diff options
Diffstat (limited to 'indra/llmessage')
84 files changed, 33442 insertions, 33506 deletions
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index e44309476b..5322139304 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -3,7 +3,6 @@ project(llmessage) include(00-Common) -include(GoogleMock) include(LLAddBuildTest) include(LLCommon) include(LLCoreHttp) @@ -11,7 +10,6 @@ include(LLAddBuildTest) include(Python) include(Tut) include(Python) -include(JsonCpp) set(llmessage_SOURCE_FILES llassetstorage.cpp diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 734b7a8a63..13fda24e62 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llassetstorage.cpp * @brief Implementation of the base asset storage system. * * $LicenseInfo:firstyear=2001&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$ */ @@ -74,18 +74,18 @@ namespace return false; } -// Rider: This is the general case of the operator declared above. The code compares the callback -// passed into the LLAssetStorage functions to determine if there are duplicated requests for an -// asset. Unfortunately std::function does not provide a direct way to compare two variables so -// we define the operator here. -// XCode is not very happy with the variadic temples in use below so we will just define the specific +// Rider: This is the general case of the operator declared above. The code compares the callback +// passed into the LLAssetStorage functions to determine if there are duplicated requests for an +// asset. Unfortunately std::function does not provide a direct way to compare two variables so +// we define the operator here. +// XCode is not very happy with the variadic temples in use below so we will just define the specific // case of comparing two LLGetAssetCallback objects since that is all we really use. -// +// // template<typename T, typename... U> // bool operator == (const std::function<T(U...)> &a, const std::function <T(U...)> &b) // { // typedef T(fnType)(U...); -// +// // auto fnPtrA = a.target<T(*)(U...)>(); // auto fnPtrB = b.target<T(*)(U...)>(); // if (fnPtrA && fnPtrB) @@ -112,8 +112,8 @@ LLAssetInfo::LLAssetInfo( void ) LLAssetInfo::LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id, LLAssetType::EType type, const char* name, const char* desc ) - : mUuid( object_id ), - mCreatorID( creator_id ), + : mUuid( object_id ), + mCreatorID( creator_id ), mType( type ) { setName( name ); @@ -198,14 +198,14 @@ LLBaseDownloadRequest::LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetTy mDownCallback(), mUserData(NULL), mHost(), - mIsTemp(FALSE), - mIsPriority(FALSE), - mDataSentInFirstPacket(FALSE), - mDataIsInCache(FALSE) + mIsTemp(false), + mIsPriority(false), + mDataSentInFirstPacket(false), + mDataIsInCache(false) { // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been // running a message system loop. - mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); + mTime = LLMessageSystem::getMessageTimeSeconds(true); } // virtual @@ -228,8 +228,8 @@ LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type : LLBaseDownloadRequest(uuid, type), mUpCallback(), mInfoCallback( NULL ), - mIsLocal(FALSE), - mIsUserWaiting(FALSE), + mIsLocal(false), + mIsUserWaiting(false), mTimeout(LL_ASSET_STORAGE_TIMEOUT), mBytesFetched(0) { @@ -344,7 +344,7 @@ void LLAssetStorage::_init(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host) { - mShutDown = FALSE; + mShutDown = false; mMessageSys = msg; mXferManager = xfer; @@ -354,9 +354,9 @@ void LLAssetStorage::_init(LLMessageSystem *msg, LLAssetStorage::~LLAssetStorage() { - mShutDown = TRUE; - - _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE); + mShutDown = true; + + _cleanupRequests(true, LL_ERR_CIRCUIT_GONE); if (gMessageSystem) { @@ -372,16 +372,16 @@ LLAssetStorage::~LLAssetStorage() void LLAssetStorage::setUpstream(const LLHost &upstream_host) { LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL; - + mUpstreamHost = upstream_host; } void LLAssetStorage::checkForTimeouts() { - _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT); + _cleanupRequests(false, LL_ERR_TCP_TIMEOUT); } -void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) +void LLAssetStorage::_cleanupRequests(bool all, S32 error) { F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); @@ -398,7 +398,7 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) // if all is true, we want to clean up everything // otherwise just check for timed out requests // EXCEPT for upload timeouts - if (all + if (all || ((RT_DOWNLOAD == rt) && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime))) { @@ -406,7 +406,7 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) << (all ? "aborted" : "timed out") << " for " << tmp->getUUID() << "." << LLAssetType::lookup(tmp->getType()) << LL_ENDL; - + timed_out.push_front(tmp); iter = requests->erase(curiter); } @@ -436,7 +436,7 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) } -BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type) +bool LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type) { return LLFileSystem::getExists(uuid, type); } @@ -450,7 +450,7 @@ bool LLAssetStorage::findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetTyp llassert(callback != NULL); } - BOOL exists = LLFileSystem::getExists(uuid, type); + bool exists = LLFileSystem::getExists(uuid, type); if (exists) { LLFileSystem file(uuid, type); @@ -477,12 +477,12 @@ bool LLAssetStorage::findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetTyp // GET routines /////////////////////////////////////////////////////////////////////////// -// IW - uuid is passed by value to avoid side effects, please don't re-add & +// IW - uuid is passed by value to avoid side effects, please don't re-add & void LLAssetStorage::getAssetData(const LLUUID uuid, - LLAssetType::EType type, + LLAssetType::EType type, LLAssetStorage::LLGetAssetCallback callback, - void *user_data, - BOOL is_priority) + void *user_data, + bool is_priority) { LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; @@ -523,7 +523,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, return; } - BOOL exists = LLFileSystem::getExists(uuid, type); + bool exists = LLFileSystem::getExists(uuid, type); LLFileSystem file(uuid, type); U32 size = exists ? file.getSize() : 0; @@ -546,9 +546,9 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; file.remove(); } - - BOOL duplicate = FALSE; - + + bool duplicate = false; + // check to see if there's a pending download of this uuid already for (request_list_t::iterator iter = mPendingDownloads.begin(); iter != mPendingDownloads.end(); ++iter ) @@ -563,19 +563,19 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, << "." << LLAssetType::lookup(type) << LL_ENDL; return; } - + // this is a duplicate request // queue the request, but don't actually ask for it again - duplicate = TRUE; + duplicate = true; } } if (duplicate) { - LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid + LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid << "." << LLAssetType::lookup(type) << LL_ENDL; } - - _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); + + _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); } } @@ -645,7 +645,7 @@ void LLAssetStorage::downloadCompleteCallback( // Inefficient since we're doing a find through a list that may have thousands of elements. // This is due for refactoring; we will probably change mPendingDownloads into a set. - request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), + request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), gAssetStorage->mPendingDownloads.end(), req); @@ -668,7 +668,7 @@ void LLAssetStorage::downloadCompleteCallback( if (vfile.getSize() <= 0) { LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset " << callback_id << LL_ENDL; - + result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; vfile.remove(); } @@ -693,14 +693,14 @@ void LLAssetStorage::downloadCompleteCallback( void LLAssetStorage::getEstateAsset( const LLHost &object_sim, - const LLUUID &agent_id, + const LLUUID &agent_id, const LLUUID &session_id, - const LLUUID &asset_id, - LLAssetType::EType atype, + const LLUUID &asset_id, + LLAssetType::EType atype, EstateAssetType etype, - LLGetAssetCallback callback, - void *user_data, - BOOL is_priority) + LLGetAssetCallback callback, + void *user_data, + bool is_priority) { LL_DEBUGS() << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << LL_ENDL; @@ -723,8 +723,8 @@ void LLAssetStorage::getEstateAsset( { return; } - - BOOL exists = LLFileSystem::getExists(asset_id, atype); + + bool exists = LLFileSystem::getExists(asset_id, atype); LLFileSystem file(asset_id, atype); U32 size = exists ? file.getSize() : 0; @@ -836,21 +836,21 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( } void LLAssetStorage::getInvItemAsset( - const LLHost &object_sim, - const LLUUID &agent_id, + const LLHost &object_sim, + const LLUUID &agent_id, const LLUUID &session_id, const LLUUID &owner_id, - const LLUUID &task_id, + const LLUUID &task_id, const LLUUID &item_id, - const LLUUID &asset_id, + const LLUUID &asset_id, LLAssetType::EType atype, - LLGetAssetCallback callback, - void *user_data, - BOOL is_priority) + LLGetAssetCallback callback, + void *user_data, + bool is_priority) { LL_DEBUGS() << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << LL_ENDL; - bool exists = false; + bool exists = false; U32 size = 0; if(asset_id.notNull()) @@ -910,7 +910,7 @@ void LLAssetStorage::getInvItemAsset( spi.setAsset(asset_id, atype); LL_DEBUGS("ViewerAsset") << "requesting inv item id " << item_id << " asset_id " << asset_id << " type " << LLAssetType::lookup(atype) << LL_ENDL; - + // Set our destination file, and the completion callback. LLTransferTargetParamsVFile tpvf; tpvf.setAsset(asset_id, atype); @@ -984,9 +984,9 @@ void LLAssetStorage::downloadInvItemCompleteCallback( // static void LLAssetStorage::uploadCompleteCallback( - const LLUUID& uuid, - void *user_data, - S32 result, + const LLUUID& uuid, + void *user_data, + S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed) { if (!gAssetStorage) @@ -995,12 +995,12 @@ void LLAssetStorage::uploadCompleteCallback( return; } LLAssetRequest *req = (LLAssetRequest *)user_data; - BOOL success = TRUE; + bool success = true; if (result) { LL_WARNS("AssetStorage") << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << LL_ENDL; - success = FALSE; + success = false; } // we're done grabbing the file, tell the client @@ -1020,7 +1020,7 @@ void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_dat LLUUID uuid; S8 asset_type_s8; LLAssetType::EType asset_type; - BOOL success = FALSE; + bool success = false; msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid); msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8); @@ -1030,7 +1030,7 @@ void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_dat this_ptr->_callUploadCallbacks(uuid, asset_type, success, LLExtStat::NONE); } -void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status ) +void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, bool success, LLExtStat ext_status ) { // SJB: We process the callbacks in reverse order, I do not know if this is important, // but I didn't want to mess with it. @@ -1190,7 +1190,7 @@ const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_ LLAssetType::EType asset_type, const LLUUID& asset_id) { - if (requests) + if (requests) { // Search the requests list for the asset. request_list_t::const_iterator iter = requests->begin(); @@ -1213,7 +1213,7 @@ LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requ LLAssetType::EType asset_type, const LLUUID& asset_id) { - if (requests) + if (requests) { // Search the requests list for the asset. request_list_t::iterator iter = requests->begin(); @@ -1296,7 +1296,7 @@ bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* re delete req; return true; } - + return false; } @@ -1340,15 +1340,15 @@ const char* LLAssetStorage::getErrorString(S32 status) } } -void LLAssetStorage::getAssetData(const LLUUID uuid, - LLAssetType::EType type, - void (*callback)(const char*, - const LLUUID&, - void *, - S32, - LLExtStat), - void *user_data, - BOOL is_priority) +void LLAssetStorage::getAssetData(const LLUUID uuid, + LLAssetType::EType type, + void (*callback)(const char*, + const LLUUID&, + void *, + S32, + LLExtStat), + void *user_data, + bool is_priority) { // check for duplicates here, since we're about to fool the normal duplicate checker for (request_list_t::iterator iter = mPendingDownloads.begin(); @@ -1358,7 +1358,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, auto cbptr = tmp->mDownCallback.target<void(*)(const LLUUID &, LLAssetType::EType, void *, S32, LLExtStat)>(); - if (type == tmp->getType() && + if (type == tmp->getType() && uuid == tmp->getUUID() && (cbptr && (*cbptr == legacyGetDataCallback)) && callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && @@ -1369,8 +1369,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, return; } } - - + + LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; legacy->mDownCallback = callback; @@ -1381,17 +1381,17 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, } // static -void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, +void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, LLAssetType::EType type, - void *user_data, - S32 status, + void *user_data, + S32 status, LLExtStat ext_status) { LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; std::string filename; // Check if the asset is marked toxic, and don't load bad stuff - BOOL toxic = gAssetStorage->isAssetToxic( uuid ); + bool toxic = gAssetStorage->isAssetToxic( uuid ); if ( !status && !toxic ) @@ -1403,7 +1403,7 @@ void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, uuid.toString(uuid_str); filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); - LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ if (fp) { const S32 buf_size = 65536; @@ -1458,7 +1458,7 @@ void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::ET std::string filename(in_filename); if (filename.empty()) filename = ll_safe_string(file); - + // Create revised message - new_message = "in_message :: file:line" std::stringstream new_message; new_message << in_message << " :: " << filename << ":" << line; @@ -1489,9 +1489,9 @@ void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::ET // Check if an asset is in the toxic map. If it is, the entry is updated -BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) +bool LLAssetStorage::isAssetToxic( const LLUUID& uuid ) { - BOOL is_toxic = FALSE; + bool is_toxic = false; if ( !uuid.isNull() ) { @@ -1499,7 +1499,7 @@ BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) if ( iter != mToxicAssetMap.end() ) { // Found toxic asset (*iter).second = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; - is_toxic = TRUE; + is_toxic = true; } } return is_toxic; @@ -1509,7 +1509,7 @@ BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) // Clean the toxic asset list, remove old entries -void LLAssetStorage::flushOldToxicAssets( BOOL force_it ) +void LLAssetStorage::flushOldToxicAssets( bool force_it ) { // Scan and look for old entries U64 now = LLFrameTimer::getTotalTime(); @@ -1531,7 +1531,7 @@ void LLAssetStorage::flushOldToxicAssets( BOOL force_it ) // Add an item to the toxic asset map void LLAssetStorage::markAssetToxic( const LLUUID& uuid ) -{ +{ if ( !uuid.isNull() ) { // Set the value to the current time. Creates a new entry if needed diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index 8a22f3f031..6b6d4a3ae7 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -1,431 +1,431 @@ -/** - * @file llassetstorage.h - * @brief definition of LLAssetStorage class which allows simple - * up/downloads of uuid,type asets - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLASSETSTORAGE_H -#define LL_LLASSETSTORAGE_H -#include <string> -#include <functional> - -#include "lluuid.h" -#include "lltimer.h" -#include "llnamevalue.h" -#include "llhost.h" -#include "lltransfermanager.h" // For LLTSCode enum -#include "llassettype.h" -#include "llstring.h" -#include "llextendedstatus.h" -#include "llxfer.h" - -// Forward declarations -class LLMessageSystem; -class LLXferManager; -class LLAssetStorage; -class LLSD; - -// anything that takes longer than this to download will abort. -// HTTP Uploads also timeout if they take longer than this. -const F32Minutes LL_ASSET_STORAGE_TIMEOUT(5); - - -// Specific error codes -const int LL_ERR_ASSET_REQUEST_FAILED = -1; -//const int LL_ERR_ASSET_REQUEST_INVALID = -2; -const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; -const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; -const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5; -const int LL_ERR_PRICE_MISMATCH = -23018; - -// *TODO: these typedefs are passed into the cache via a legacy C function pointer -// future project would be to convert these to C++ callables (std::function<>) so that -// we can use bind and remove the userData parameter. -// -typedef std::function<void(const LLUUID &asset_id, LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status)> LLGetAssetCallback; -typedef std::function<void(const LLUUID &asset_id, void *user_data, S32 status, LLExtStat ext_status)> LLStoreAssetCallback; - - -class LLAssetInfo -{ -protected: - std::string mDescription; - std::string mName; - -public: - LLUUID mUuid; - LLTransactionID mTransactionID; - LLUUID mCreatorID; - LLAssetType::EType mType; - - LLAssetInfo( void ); - LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id, - LLAssetType::EType type, const char* name, const char* desc ); - LLAssetInfo( const LLNameValue& nv ); - - const std::string& getName( void ) const { return mName; } - const std::string& getDescription( void ) const { return mDescription; } - void setName( const std::string& name ); - void setDescription( const std::string& desc ); - - // Assets (aka potential inventory items) can be applied to an - // object in the world. We'll store that as a string name value - // pair where the name encodes part of asset info, and the value - // the rest. LLAssetInfo objects will be responsible for parsing - // the meaning out froman LLNameValue object. See the inventory - // design docs for details. - void setFromNameValue( const LLNameValue& nv ); -}; - - -class LLBaseDownloadRequest -{ -public: - LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetType::EType at); - virtual ~LLBaseDownloadRequest(); - - LLUUID getUUID() const { return mUUID; } - LLAssetType::EType getType() const { return mType; } - - void setUUID(const LLUUID& id) { mUUID = id; } - void setType(LLAssetType::EType type) { mType = type; } - - virtual LLBaseDownloadRequest* getCopy(); - -protected: - LLUUID mUUID; - LLAssetType::EType mType; - -public: - LLGetAssetCallback mDownCallback; - - void *mUserData; - LLHost mHost; - BOOL mIsTemp; - F64Seconds mTime; // Message system time - BOOL mIsPriority; - BOOL mDataSentInFirstPacket; - BOOL mDataIsInCache; -}; - -class LLAssetRequest : public LLBaseDownloadRequest -{ -public: - LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType at); - virtual ~LLAssetRequest(); - - void setTimeout(F64Seconds timeout) { mTimeout = timeout; } - - virtual LLBaseDownloadRequest* getCopy(); - - LLStoreAssetCallback mUpCallback; -// void (*mUpCallback)(const LLUUID&, void *, S32, LLExtStat); - void (*mInfoCallback)(LLAssetInfo *, void *, S32); - - BOOL mIsLocal; - BOOL mIsUserWaiting; // We don't want to try forever if a user is waiting for a result. - F64Seconds mTimeout; // Amount of time before timing out. - LLUUID mRequestingAgentID; // Only valid for uploads from an agent - F64 mBytesFetched; - - virtual LLSD getTerseDetails() const; - virtual LLSD getFullDetails() const; -}; - -template <class T> -struct ll_asset_request_equal : public std::equal_to<T> -{ - bool operator()(const T& x, const T& y) const - { - return ( x->getType() == y->getType() - && x->getUUID() == y->getUUID() ); - } -}; - - -class LLInvItemRequest : public LLBaseDownloadRequest -{ -public: - LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType at); - virtual ~LLInvItemRequest(); - - virtual LLBaseDownloadRequest* getCopy(); -}; - -class LLEstateAssetRequest : public LLBaseDownloadRequest -{ -public: - LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType at, EstateAssetType et); - virtual ~LLEstateAssetRequest(); - - LLAssetType::EType getAType() const { return mType; } - - virtual LLBaseDownloadRequest* getCopy(); - -protected: - EstateAssetType mEstateAssetType; -}; - - -// Map of known bad assets -typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t; - - - -class LLAssetStorage -{ -public: - typedef ::LLStoreAssetCallback LLStoreAssetCallback; - typedef ::LLGetAssetCallback LLGetAssetCallback; - - enum ERequestType - { - RT_INVALID = -1, - RT_DOWNLOAD = 0, - RT_UPLOAD = 1, - RT_LOCALUPLOAD = 2, - RT_COUNT = 3 - }; - -protected: - BOOL mShutDown; - LLHost mUpstreamHost; - - LLMessageSystem *mMessageSys; - LLXferManager *mXferManager; - - - typedef std::list<LLAssetRequest*> request_list_t; - request_list_t mPendingDownloads; - request_list_t mPendingUploads; - request_list_t mPendingLocalUploads; - - // Map of toxic assets - these caused problems when recently rezzed, so avoid them - toxic_asset_map_t mToxicAssetMap; // Objects in this list are known to cause problems and are not loaded - -public: - LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host); - - LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer); - virtual ~LLAssetStorage(); - - void setUpstream(const LLHost &upstream_host); - - BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); - - // public interface methods - // note that your callback may get called BEFORE the function returns - void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); - - /* - * TransactionID version - * Viewer needs the store_local - */ - virtual void storeAssetData( - const LLTransactionID& tid, - LLAssetType::EType atype, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file = false, - bool is_priority = false, - bool store_local = false, - bool user_waiting= false, - F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) = 0; - - virtual void logAssetStorageInfo() = 0; - - virtual void checkForTimeouts(); - - void getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, - const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype, - LLGetAssetCallback callback, void *user_data, BOOL is_priority); - - void getInvItemAsset(const LLHost &object_sim, - const LLUUID &agent_id, const LLUUID &session_id, - const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id, - const LLUUID &asset_id, LLAssetType::EType atype, - LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); // Get a particular inventory item. - - // Check if an asset is in the toxic map. If it is, the entry is updated - BOOL isAssetToxic( const LLUUID& uuid ); - - // Clean the toxic asset list, remove old entries - void flushOldToxicAssets( BOOL force_it ); - - // Add an item to the toxic asset map - void markAssetToxic( const LLUUID& uuid ); - -protected: - bool findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, - LLGetAssetCallback callback, void *user_data); - - LLSD getPendingDetailsImpl(const request_list_t* requests, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const; - - LLSD getPendingRequestImpl(const request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const; - - bool deletePendingRequestImpl(request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id); - -public: - static const LLAssetRequest* findRequest(const request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id); - static LLAssetRequest* findRequest(request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id); - - request_list_t* getRequestList(ERequestType rt); - const request_list_t* getRequestList(ERequestType rt) const; - static std::string getRequestName(ERequestType rt); - - S32 getNumPendingDownloads() const; - S32 getNumPendingUploads() const; - S32 getNumPendingLocalUploads(); - S32 getNumPending(ERequestType rt) const; - - LLSD getPendingDetails(ERequestType rt, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const; - - LLSD getPendingRequest(ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const; - - bool deletePendingRequest(ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id); - - - static void removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type, - const LLUUID& callback_id, LLAssetType::EType callback_type, - S32 result_code, LLExtStat ext_status); - - // download process callbacks - static void downloadCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, LLExtStat ext_status); - static void downloadEstateAssetCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, LLExtStat ext_status); - static void downloadInvItemCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, LLExtStat ext_status); - - // upload process callbacks - static void uploadCompleteCallback(const LLUUID&, void *user_data, S32 result, LLExtStat ext_status); - static void processUploadComplete(LLMessageSystem *msg, void **this_handle); - - // debugging - static const char* getErrorString( S32 status ); - - // deprecated file-based methods - // Not overriden - void getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority = FALSE); - - /* - * TransactionID version - */ - virtual void storeAssetData( - const std::string& filename, - const LLTransactionID &transaction_id, - LLAssetType::EType type, - LLStoreAssetCallback callback, - void *user_data, - bool temp_file = false, - bool is_priority = false, - bool user_waiting = false, - F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0; - - static void legacyGetDataCallback(const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status); - static void legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status); - - // add extra methods to handle metadata - -protected: - void _cleanupRequests(BOOL all, S32 error); - void _callUploadCallbacks(const LLUUID &uuid, const LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status); - - virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, - void *user_data, BOOL duplicate, - BOOL is_priority) = 0; - -private: - void _init(LLMessageSystem *msg, - LLXferManager *xfer, - const LLHost &upstream_host); - -protected: - enum EMetricResult - { - // Static valued enums for #dw readability - please copy this - // declaration to them on updates -- source in llassetstorage.h - MR_INVALID = -1, // Makes no sense - MR_OKAY = 0, // Success - no metric normally - MR_ZERO_SIZE = 1, // Zero size asset - MR_BAD_FUNCTION = 2, // Tried to use a virtual base (PROGRAMMER ERROR) - MR_FILE_NONEXIST = 3, // Old format store call - source file does not exist - MR_NO_FILENAME = 4, // Old format store call - source filename is NULL/0-length - MR_NO_UPSTREAM = 5, // Upstream provider is missing - MR_CACHE_CORRUPTION = 6 // cache is corrupt - too-large or mismatched stated/returned sizes - }; - - static class LLMetrics *metric_recipient; - - static void reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const std::string& filename, - const LLUUID& agent_id, S32 asset_size, EMetricResult result, - const char* file, const S32 line, const std::string& message ); -public: - static void setMetricRecipient( LLMetrics *recip ) - { - metric_recipient = recip; - } -}; - -//////////////////////////////////////////////////////////////////////// -// Wrappers to replicate deprecated API -//////////////////////////////////////////////////////////////////////// - -class LLLegacyAssetRequest -{ -public: - void (*mDownCallback)(const char *, const LLUUID&, void *, S32, LLExtStat); - LLStoreAssetCallback mUpCallback; - - void *mUserData; -}; - -extern LLAssetStorage *gAssetStorage; -extern const LLUUID CATEGORIZE_LOST_AND_FOUND_ID; -#endif +/**
+ * @file llassetstorage.h
+ * @brief definition of LLAssetStorage class which allows simple
+ * up/downloads of uuid,type asets
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLASSETSTORAGE_H
+#define LL_LLASSETSTORAGE_H
+#include <string>
+#include <functional>
+
+#include "lluuid.h"
+#include "lltimer.h"
+#include "llnamevalue.h"
+#include "llhost.h"
+#include "lltransfermanager.h" // For LLTSCode enum
+#include "llassettype.h"
+#include "llstring.h"
+#include "llextendedstatus.h"
+#include "llxfer.h"
+
+// Forward declarations
+class LLMessageSystem;
+class LLXferManager;
+class LLAssetStorage;
+class LLSD;
+
+// anything that takes longer than this to download will abort.
+// HTTP Uploads also timeout if they take longer than this.
+const F32Minutes LL_ASSET_STORAGE_TIMEOUT(5);
+
+
+// Specific error codes
+const int LL_ERR_ASSET_REQUEST_FAILED = -1;
+//const int LL_ERR_ASSET_REQUEST_INVALID = -2;
+const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3;
+const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4;
+const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5;
+const int LL_ERR_PRICE_MISMATCH = -23018;
+
+// *TODO: these typedefs are passed into the cache via a legacy C function pointer
+// future project would be to convert these to C++ callables (std::function<>) so that
+// we can use bind and remove the userData parameter.
+//
+typedef std::function<void(const LLUUID &asset_id, LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status)> LLGetAssetCallback;
+typedef std::function<void(const LLUUID &asset_id, void *user_data, S32 status, LLExtStat ext_status)> LLStoreAssetCallback;
+
+
+class LLAssetInfo
+{
+protected:
+ std::string mDescription;
+ std::string mName;
+
+public:
+ LLUUID mUuid;
+ LLTransactionID mTransactionID;
+ LLUUID mCreatorID;
+ LLAssetType::EType mType;
+
+ LLAssetInfo( void );
+ LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id,
+ LLAssetType::EType type, const char* name, const char* desc );
+ LLAssetInfo( const LLNameValue& nv );
+
+ const std::string& getName( void ) const { return mName; }
+ const std::string& getDescription( void ) const { return mDescription; }
+ void setName( const std::string& name );
+ void setDescription( const std::string& desc );
+
+ // Assets (aka potential inventory items) can be applied to an
+ // object in the world. We'll store that as a string name value
+ // pair where the name encodes part of asset info, and the value
+ // the rest. LLAssetInfo objects will be responsible for parsing
+ // the meaning out froman LLNameValue object. See the inventory
+ // design docs for details.
+ void setFromNameValue( const LLNameValue& nv );
+};
+
+
+class LLBaseDownloadRequest
+{
+public:
+ LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetType::EType at);
+ virtual ~LLBaseDownloadRequest();
+
+ LLUUID getUUID() const { return mUUID; }
+ LLAssetType::EType getType() const { return mType; }
+
+ void setUUID(const LLUUID& id) { mUUID = id; }
+ void setType(LLAssetType::EType type) { mType = type; }
+
+ virtual LLBaseDownloadRequest* getCopy();
+
+protected:
+ LLUUID mUUID;
+ LLAssetType::EType mType;
+
+public:
+ LLGetAssetCallback mDownCallback;
+
+ void *mUserData;
+ LLHost mHost;
+ bool mIsTemp;
+ F64Seconds mTime; // Message system time
+ bool mIsPriority;
+ bool mDataSentInFirstPacket;
+ bool mDataIsInCache;
+};
+
+class LLAssetRequest : public LLBaseDownloadRequest
+{
+public:
+ LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType at);
+ virtual ~LLAssetRequest();
+
+ void setTimeout(F64Seconds timeout) { mTimeout = timeout; }
+
+ virtual LLBaseDownloadRequest* getCopy();
+
+ LLStoreAssetCallback mUpCallback;
+// void (*mUpCallback)(const LLUUID&, void *, S32, LLExtStat);
+ void (*mInfoCallback)(LLAssetInfo *, void *, S32);
+
+ bool mIsLocal;
+ bool mIsUserWaiting; // We don't want to try forever if a user is waiting for a result.
+ F64Seconds mTimeout; // Amount of time before timing out.
+ LLUUID mRequestingAgentID; // Only valid for uploads from an agent
+ F64 mBytesFetched;
+
+ virtual LLSD getTerseDetails() const;
+ virtual LLSD getFullDetails() const;
+};
+
+template <class T>
+struct ll_asset_request_equal : public std::equal_to<T>
+{
+ bool operator()(const T& x, const T& y) const
+ {
+ return ( x->getType() == y->getType()
+ && x->getUUID() == y->getUUID() );
+ }
+};
+
+
+class LLInvItemRequest : public LLBaseDownloadRequest
+{
+public:
+ LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType at);
+ virtual ~LLInvItemRequest();
+
+ virtual LLBaseDownloadRequest* getCopy();
+};
+
+class LLEstateAssetRequest : public LLBaseDownloadRequest
+{
+public:
+ LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType at, EstateAssetType et);
+ virtual ~LLEstateAssetRequest();
+
+ LLAssetType::EType getAType() const { return mType; }
+
+ virtual LLBaseDownloadRequest* getCopy();
+
+protected:
+ EstateAssetType mEstateAssetType;
+};
+
+
+// Map of known bad assets
+typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t;
+
+
+
+class LLAssetStorage
+{
+public:
+ typedef ::LLStoreAssetCallback LLStoreAssetCallback;
+ typedef ::LLGetAssetCallback LLGetAssetCallback;
+
+ enum ERequestType
+ {
+ RT_INVALID = -1,
+ RT_DOWNLOAD = 0,
+ RT_UPLOAD = 1,
+ RT_LOCALUPLOAD = 2,
+ RT_COUNT = 3
+ };
+
+protected:
+ bool mShutDown;
+ LLHost mUpstreamHost;
+
+ LLMessageSystem *mMessageSys;
+ LLXferManager *mXferManager;
+
+
+ typedef std::list<LLAssetRequest*> request_list_t;
+ request_list_t mPendingDownloads;
+ request_list_t mPendingUploads;
+ request_list_t mPendingLocalUploads;
+
+ // Map of toxic assets - these caused problems when recently rezzed, so avoid them
+ toxic_asset_map_t mToxicAssetMap; // Objects in this list are known to cause problems and are not loaded
+
+public:
+ LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host);
+
+ LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer);
+ virtual ~LLAssetStorage();
+
+ void setUpstream(const LLHost &upstream_host);
+
+ bool hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type);
+
+ // public interface methods
+ // note that your callback may get called BEFORE the function returns
+ void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, bool is_priority = false);
+
+ /*
+ * TransactionID version
+ * Viewer needs the store_local
+ */
+ virtual void storeAssetData(
+ const LLTransactionID& tid,
+ LLAssetType::EType atype,
+ LLStoreAssetCallback callback,
+ void* user_data,
+ bool temp_file = false,
+ bool is_priority = false,
+ bool store_local = false,
+ bool user_waiting= false,
+ F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) = 0;
+
+ virtual void logAssetStorageInfo() = 0;
+
+ virtual void checkForTimeouts();
+
+ void getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
+ const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype,
+ LLGetAssetCallback callback, void *user_data, bool is_priority);
+
+ void getInvItemAsset(const LLHost &object_sim,
+ const LLUUID &agent_id, const LLUUID &session_id,
+ const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id,
+ const LLUUID &asset_id, LLAssetType::EType atype,
+ LLGetAssetCallback cb, void *user_data, bool is_priority = false); // Get a particular inventory item.
+
+ // Check if an asset is in the toxic map. If it is, the entry is updated
+ bool isAssetToxic( const LLUUID& uuid );
+
+ // Clean the toxic asset list, remove old entries
+ void flushOldToxicAssets( bool force_it );
+
+ // Add an item to the toxic asset map
+ void markAssetToxic( const LLUUID& uuid );
+
+protected:
+ bool findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type,
+ LLGetAssetCallback callback, void *user_data);
+
+ LLSD getPendingDetailsImpl(const request_list_t* requests,
+ LLAssetType::EType asset_type,
+ const std::string& detail_prefix) const;
+
+ LLSD getPendingRequestImpl(const request_list_t* requests,
+ LLAssetType::EType asset_type,
+ const LLUUID& asset_id) const;
+
+ bool deletePendingRequestImpl(request_list_t* requests,
+ LLAssetType::EType asset_type,
+ const LLUUID& asset_id);
+
+public:
+ static const LLAssetRequest* findRequest(const request_list_t* requests,
+ LLAssetType::EType asset_type,
+ const LLUUID& asset_id);
+ static LLAssetRequest* findRequest(request_list_t* requests,
+ LLAssetType::EType asset_type,
+ const LLUUID& asset_id);
+
+ request_list_t* getRequestList(ERequestType rt);
+ const request_list_t* getRequestList(ERequestType rt) const;
+ static std::string getRequestName(ERequestType rt);
+
+ S32 getNumPendingDownloads() const;
+ S32 getNumPendingUploads() const;
+ S32 getNumPendingLocalUploads();
+ S32 getNumPending(ERequestType rt) const;
+
+ LLSD getPendingDetails(ERequestType rt,
+ LLAssetType::EType asset_type,
+ const std::string& detail_prefix) const;
+
+ LLSD getPendingRequest(ERequestType rt,
+ LLAssetType::EType asset_type,
+ const LLUUID& asset_id) const;
+
+ bool deletePendingRequest(ERequestType rt,
+ LLAssetType::EType asset_type,
+ const LLUUID& asset_id);
+
+
+ static void removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type,
+ const LLUUID& callback_id, LLAssetType::EType callback_type,
+ S32 result_code, LLExtStat ext_status);
+
+ // download process callbacks
+ static void downloadCompleteCallback(
+ S32 result,
+ const LLUUID& file_id,
+ LLAssetType::EType file_type,
+ LLBaseDownloadRequest* user_data, LLExtStat ext_status);
+ static void downloadEstateAssetCompleteCallback(
+ S32 result,
+ const LLUUID& file_id,
+ LLAssetType::EType file_type,
+ LLBaseDownloadRequest* user_data, LLExtStat ext_status);
+ static void downloadInvItemCompleteCallback(
+ S32 result,
+ const LLUUID& file_id,
+ LLAssetType::EType file_type,
+ LLBaseDownloadRequest* user_data, LLExtStat ext_status);
+
+ // upload process callbacks
+ static void uploadCompleteCallback(const LLUUID&, void *user_data, S32 result, LLExtStat ext_status);
+ static void processUploadComplete(LLMessageSystem *msg, void **this_handle);
+
+ // debugging
+ static const char* getErrorString( S32 status );
+
+ // deprecated file-based methods
+ // Not overriden
+ void getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, bool is_priority = false);
+
+ /*
+ * TransactionID version
+ */
+ virtual void storeAssetData(
+ const std::string& filename,
+ const LLTransactionID &transaction_id,
+ LLAssetType::EType type,
+ LLStoreAssetCallback callback,
+ void *user_data,
+ bool temp_file = false,
+ bool is_priority = false,
+ bool user_waiting = false,
+ F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0;
+
+ static void legacyGetDataCallback(const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status);
+ static void legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status);
+
+ // add extra methods to handle metadata
+
+protected:
+ void _cleanupRequests(bool all, S32 error);
+ void _callUploadCallbacks(const LLUUID &uuid, const LLAssetType::EType asset_type, bool success, LLExtStat ext_status);
+
+ virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback,
+ void *user_data, bool duplicate,
+ bool is_priority) = 0;
+
+private:
+ void _init(LLMessageSystem *msg,
+ LLXferManager *xfer,
+ const LLHost &upstream_host);
+
+protected:
+ enum EMetricResult
+ {
+ // Static valued enums for #dw readability - please copy this
+ // declaration to them on updates -- source in llassetstorage.h
+ MR_INVALID = -1, // Makes no sense
+ MR_OKAY = 0, // Success - no metric normally
+ MR_ZERO_SIZE = 1, // Zero size asset
+ MR_BAD_FUNCTION = 2, // Tried to use a virtual base (PROGRAMMER ERROR)
+ MR_FILE_NONEXIST = 3, // Old format store call - source file does not exist
+ MR_NO_FILENAME = 4, // Old format store call - source filename is NULL/0-length
+ MR_NO_UPSTREAM = 5, // Upstream provider is missing
+ MR_CACHE_CORRUPTION = 6 // cache is corrupt - too-large or mismatched stated/returned sizes
+ };
+
+ static class LLMetrics *metric_recipient;
+
+ static void reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const std::string& filename,
+ const LLUUID& agent_id, S32 asset_size, EMetricResult result,
+ const char* file, const S32 line, const std::string& message );
+public:
+ static void setMetricRecipient( LLMetrics *recip )
+ {
+ metric_recipient = recip;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////
+// Wrappers to replicate deprecated API
+////////////////////////////////////////////////////////////////////////
+
+class LLLegacyAssetRequest
+{
+public:
+ void (*mDownCallback)(const char *, const LLUUID&, void *, S32, LLExtStat);
+ LLStoreAssetCallback mUpCallback;
+
+ void *mUserData;
+};
+
+extern LLAssetStorage *gAssetStorage;
+extern const LLUUID CATEGORIZE_LOST_AND_FOUND_ID;
+#endif
diff --git a/indra/llmessage/llblowfishcipher.h b/indra/llmessage/llblowfishcipher.h index 2343882cee..59d6f159c5 100644 --- a/indra/llmessage/llblowfishcipher.h +++ b/indra/llmessage/llblowfishcipher.h @@ -1,57 +1,57 @@ -/** - * @file llblowfishcipher.h - * @brief A symmetric block cipher, designed in 1993 by Bruce Schneier. - * We use it because it has an 8 byte block size, allowing encryption of - * two UUIDs and a timestamp (16x2 + 4 = 36 bytes) with only 40 bytes of - * output. AES has a block size of 32 bytes, so this would require 64 bytes. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LLBLOWFISHCIPHER_H -#define LLBLOWFISHCIPHER_H - -#include "llcipher.h" - - -class LLBlowfishCipher : public LLCipher -{ -public: - // Secret may be up to 56 bytes in length per Blowfish spec. - LLBlowfishCipher(const U8* secret, size_t secret_size); - virtual ~LLBlowfishCipher(); - - // See llcipher.h for documentation. - /*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); - /*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); - /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const; - -#ifdef _DEBUG - static BOOL testHarness(); -#endif - -private: - U8* mSecret; - size_t mSecretSize; -}; - -#endif // LL_LLCRYPTO_H +/**
+ * @file llblowfishcipher.h
+ * @brief A symmetric block cipher, designed in 1993 by Bruce Schneier.
+ * We use it because it has an 8 byte block size, allowing encryption of
+ * two UUIDs and a timestamp (16x2 + 4 = 36 bytes) with only 40 bytes of
+ * output. AES has a block size of 32 bytes, so this would require 64 bytes.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#ifndef LLBLOWFISHCIPHER_H
+#define LLBLOWFISHCIPHER_H
+
+#include "llcipher.h"
+
+
+class LLBlowfishCipher : public LLCipher
+{
+public:
+ // Secret may be up to 56 bytes in length per Blowfish spec.
+ LLBlowfishCipher(const U8* secret, size_t secret_size);
+ virtual ~LLBlowfishCipher();
+
+ // See llcipher.h for documentation.
+ /*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
+ /*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
+ /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const;
+
+#ifdef _DEBUG
+ static bool testHarness();
+#endif
+
+private:
+ U8* mSecret;
+ size_t mSecretSize;
+};
+
+#endif // LL_LLCRYPTO_H
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index d5b967a8e9..cb654f5a30 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -1,1021 +1,1021 @@ -/** - * @file llcachename.cpp - * @brief A hierarchical cache of first and last names queried based on UUID. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#include "linden_common.h" - -#include "llcachename.h" - -// linden library includes -#include "lldbstrings.h" -#include "llframetimer.h" -#include "llhost.h" -#include "llrand.h" -#include "llsdserialize.h" -#include "lluuid.h" -#include "message.h" - -#include <boost/regex.hpp> - -// llsd serialization constants -static const std::string AGENTS("agents"); -static const std::string GROUPS("groups"); -static const std::string CTIME("ctime"); -static const std::string FIRST("first"); -static const std::string LAST("last"); -static const std::string NAME("name"); - -// We track name requests in flight for up to this long. -// We won't re-request a name during this time -const U32 PENDING_TIMEOUT_SECS = 5 * 60; - -// Globals -LLCacheName* gCacheName = NULL; -std::map<std::string, std::string> LLCacheName::sCacheName; - -/// --------------------------------------------------------------------------- -/// class LLCacheNameEntry -/// --------------------------------------------------------------------------- - -class LLCacheNameEntry -{ -public: - LLCacheNameEntry(); - -public: - bool mIsGroup; - U32 mCreateTime; // unix time_t - // IDEVO TODO collapse names to one field, which will eliminate - // many string compares on "Resident" - std::string mFirstName; - std::string mLastName; - std::string mGroupName; -}; - -LLCacheNameEntry::LLCacheNameEntry() - : mIsGroup(false), - mCreateTime(0) -{ -} - - -class PendingReply -{ -public: - LLUUID mID; - LLCacheNameSignal mSignal; - LLHost mHost; - - PendingReply(const LLUUID& id, const LLHost& host) - : mID(id), mHost(host) - { - } - - boost::signals2::connection setCallback(const LLCacheNameCallback& cb) - { - return mSignal.connect(cb); - } - - void done() { mID.setNull(); } - bool isDone() const { return mID.isNull() != FALSE; } -}; - -class ReplySender -{ -public: - ReplySender(LLMessageSystem* msg); - ~ReplySender(); - - void send(const LLUUID& id, - const LLCacheNameEntry& entry, const LLHost& host); - -private: - void flush(); - - LLMessageSystem* mMsg; - bool mPending; - bool mCurrIsGroup; - LLHost mCurrHost; -}; - -ReplySender::ReplySender(LLMessageSystem* msg) - : mMsg(msg), mPending(false), mCurrIsGroup(false) -{ } - -ReplySender::~ReplySender() -{ - flush(); -} - -void ReplySender::send(const LLUUID& id, - const LLCacheNameEntry& entry, const LLHost& host) -{ - if (mPending) - { - if (mCurrIsGroup != entry.mIsGroup - || mCurrHost != host) - { - flush(); - } - } - - if (!mPending) - { - mPending = true; - mCurrIsGroup = entry.mIsGroup; - mCurrHost = host; - - if(mCurrIsGroup) - mMsg->newMessageFast(_PREHASH_UUIDGroupNameReply); - else - mMsg->newMessageFast(_PREHASH_UUIDNameReply); - } - - mMsg->nextBlockFast(_PREHASH_UUIDNameBlock); - mMsg->addUUIDFast(_PREHASH_ID, id); - if(mCurrIsGroup) - { - mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName); - } - else - { - mMsg->addStringFast(_PREHASH_FirstName, entry.mFirstName); - mMsg->addStringFast(_PREHASH_LastName, entry.mLastName); - } - - if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock)) - { - flush(); - } -} - -void ReplySender::flush() -{ - if (mPending) - { - mMsg->sendReliable(mCurrHost); - mPending = false; - } -} - - -typedef std::set<LLUUID> AskQueue; -typedef std::list<PendingReply*> ReplyQueue; -typedef std::map<LLUUID,U32> PendingQueue; -typedef std::map<LLUUID, LLCacheNameEntry*> Cache; -typedef std::map<std::string, LLUUID> ReverseCache; - -class LLCacheName::Impl -{ -public: - LLMessageSystem* mMsg; - LLHost mUpstreamHost; - - Cache mCache; - // the map of UUIDs to names - ReverseCache mReverseCache; - // map of names to UUIDs - - AskQueue mAskNameQueue; - AskQueue mAskGroupQueue; - // UUIDs to ask our upstream host about - - PendingQueue mPendingQueue; - // UUIDs that have been requested but are not in cache yet. - - ReplyQueue mReplyQueue; - // requests awaiting replies from us - - LLCacheNameSignal mSignal; - - LLFrameTimer mProcessTimer; - - Impl(LLMessageSystem* msg); - ~Impl(); - - BOOL getName(const LLUUID& id, std::string& first, std::string& last); - - boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback); - void addPending(const LLUUID& id, const LLHost& host); - - void processPendingAsks(); - void processPendingReplies(); - void sendRequest(const char* msg_name, const AskQueue& queue); - bool isRequestPending(const LLUUID& id); - - // Message system callbacks. - void processUUIDRequest(LLMessageSystem* msg, bool isGroup); - void processUUIDReply(LLMessageSystem* msg, bool isGroup); - - static void handleUUIDNameRequest(LLMessageSystem* msg, void** userdata); - static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata); - static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata); - static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata); -}; - - -/// -------------------------------------------------------------------------- -/// class LLCacheName -/// --------------------------------------------------------------------------- - -LLCacheName::LLCacheName(LLMessageSystem* msg) - : impl(* new Impl(msg)) - { } - -LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host) - : impl(* new Impl(msg)) -{ - sCacheName["waiting"] = "(Loading...)"; - sCacheName["nobody"] = "(nobody)"; - sCacheName["none"] = "(none)"; - setUpstream(upstream_host); -} - -LLCacheName::~LLCacheName() -{ - delete &impl; -} - -LLCacheName::Impl::Impl(LLMessageSystem* msg) - : mMsg(msg), mUpstreamHost(LLHost()) -{ - mMsg->setHandlerFuncFast( - _PREHASH_UUIDNameRequest, handleUUIDNameRequest, (void**)this); - mMsg->setHandlerFuncFast( - _PREHASH_UUIDNameReply, handleUUIDNameReply, (void**)this); - mMsg->setHandlerFuncFast( - _PREHASH_UUIDGroupNameRequest, handleUUIDGroupNameRequest, (void**)this); - mMsg->setHandlerFuncFast( - _PREHASH_UUIDGroupNameReply, handleUUIDGroupNameReply, (void**)this); -} - - -LLCacheName::Impl::~Impl() -{ - for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); - mCache.clear(); - for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer()); - mReplyQueue.clear(); -} - -boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback) -{ - PendingReply* reply = new PendingReply(id, LLHost()); - boost::signals2::connection res = reply->setCallback(callback); - mReplyQueue.push_back(reply); - return res; -} - -void LLCacheName::Impl::addPending(const LLUUID& id, const LLHost& host) -{ - PendingReply* reply = new PendingReply(id, host); - mReplyQueue.push_back(reply); -} - -void LLCacheName::setUpstream(const LLHost& upstream_host) -{ - impl.mUpstreamHost = upstream_host; -} - -boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& callback) -{ - return impl.mSignal.connect(callback); -} - -bool LLCacheName::importFile(std::istream& istr) -{ - LLSD data; - if(LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(data, istr)) - { - return false; - } - - // We'll expire entries more than a week old - U32 now = (U32)time(NULL); - const U32 SECS_PER_DAY = 60 * 60 * 24; - U32 delete_before_time = now - (7 * SECS_PER_DAY); - - // iterate over the agents - S32 count = 0; - LLSD agents = data[AGENTS]; - LLSD::map_iterator iter = agents.beginMap(); - LLSD::map_iterator end = agents.endMap(); - for( ; iter != end; ++iter) - { - LLUUID id((*iter).first); - LLSD agent = (*iter).second; - U32 ctime = (U32)agent[CTIME].asInteger(); - if(ctime < delete_before_time) continue; - - LLCacheNameEntry* entry = new LLCacheNameEntry(); - entry->mIsGroup = false; - entry->mCreateTime = ctime; - entry->mFirstName = agent[FIRST].asString(); - entry->mLastName = agent[LAST].asString(); - impl.mCache[id] = entry; - std::string fullname = buildFullName(entry->mFirstName, entry->mLastName); - impl.mReverseCache[fullname] = id; - - ++count; - } - LL_INFOS() << "LLCacheName loaded " << count << " agent names" << LL_ENDL; - - count = 0; - LLSD groups = data[GROUPS]; - iter = groups.beginMap(); - end = groups.endMap(); - for( ; iter != end; ++iter) - { - LLUUID id((*iter).first); - LLSD group = (*iter).second; - U32 ctime = (U32)group[CTIME].asInteger(); - if(ctime < delete_before_time) continue; - - LLCacheNameEntry* entry = new LLCacheNameEntry(); - entry->mIsGroup = true; - entry->mCreateTime = ctime; - entry->mGroupName = group[NAME].asString(); - impl.mCache[id] = entry; - impl.mReverseCache[entry->mGroupName] = id; - ++count; - } - LL_INFOS() << "LLCacheName loaded " << count << " group names" << LL_ENDL; - return true; -} - -void LLCacheName::exportFile(std::ostream& ostr) -{ - LLSD data; - Cache::iterator iter = impl.mCache.begin(); - Cache::iterator end = impl.mCache.end(); - for( ; iter != end; ++iter) - { - // 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('?'))) - { - continue; - } - - // store it - LLUUID id = iter->first; - std::string id_str = id.asString(); - // IDEVO TODO: Should we store SLIDs with last name "Resident" or not? - if(!entry->mFirstName.empty() && !entry->mLastName.empty()) - { - 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); -} - - -BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last) -{ - if(id.isNull()) - { - first = sCacheName["nobody"]; - last.clear(); - return TRUE; - } - - LLCacheNameEntry* entry = get_ptr_in_map(mCache, id ); - if (entry) - { - first = entry->mFirstName; - last = entry->mLastName; - return TRUE; - } - else - { - first = sCacheName["waiting"]; - last.clear(); - if (!isRequestPending(id)) - { - mAskNameQueue.insert(id); - } - return FALSE; - } - -} - -// static -void LLCacheName::localizeCacheName(std::string key, std::string value) -{ - if (key!="" && value!= "" ) - sCacheName[key]=value; - else - LL_WARNS()<< " Error localizing cache key " << key << " To "<< value<<LL_ENDL; -} - -BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname) -{ - std::string first_name, last_name; - BOOL res = impl.getName(id, first_name, last_name); - fullname = buildFullName(first_name, last_name); - return res; -} - - - -BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) -{ - if(id.isNull()) - { - group = sCacheName["none"]; - return TRUE; - } - - LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id); - if (entry && entry->mGroupName.empty()) - { - // COUNTER-HACK to combat James' HACK in exportFile()... - // this group name was loaded from a name cache that did not - // bother to save the group name ==> we must ask for it - LL_DEBUGS() << "LLCacheName queuing HACK group request: " << id << LL_ENDL; - entry = NULL; - } - - if (entry) - { - group = entry->mGroupName; - return TRUE; - } - else - { - group = sCacheName["waiting"]; - if (!impl.isRequestPending(id)) - { - impl.mAskGroupQueue.insert(id); - } - return FALSE; - } -} - -BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id) -{ - std::string full_name = buildFullName(first, last); - return getUUID(full_name, id); -} - -BOOL LLCacheName::getUUID(const std::string& full_name, LLUUID& id) -{ - ReverseCache::iterator iter = impl.mReverseCache.find(full_name); - if (iter != impl.mReverseCache.end()) - { - id = iter->second; - return TRUE; - } - else - { - return FALSE; - } -} - -//static -std::string LLCacheName::buildFullName(const std::string& first, const std::string& last) -{ - std::string fullname = first; - if (!last.empty() - && last != "Resident") - { - fullname += ' '; - fullname += last; - } - return fullname; -} - -//static -std::string LLCacheName::cleanFullName(const std::string& full_name) -{ - return full_name.substr(0, full_name.find(" Resident")); -} - -//static -// Transform hard-coded name provided by server to a more legible username -std::string LLCacheName::buildUsername(const std::string& full_name) -{ - // rare, but handle hard-coded error names returned from server - if (full_name == "(\?\?\?) (\?\?\?)") - { - return "(\?\?\?)"; - } - - std::string::size_type index = full_name.find(' '); - - if (index != std::string::npos) - { - std::string username; - username = full_name.substr(0, index); - std::string lastname = full_name.substr(index+1); - - if (lastname != "Resident") - { - username = username + "." + lastname; - } - - LLStringUtil::toLower(username); - return username; - } - - // if the input wasn't a correctly formatted legacy name, just return it - // cleaned up from a potential terminal "Resident" - std::string clean_name = cleanFullName(full_name); - LLStringUtil::toLower(clean_name); - return clean_name; -} - -//static -std::string LLCacheName::buildLegacyName(const std::string& complete_name) -{ - //boost::regexp was showing up in the crashreporter, so doing - //painfully manual parsing using substr. LF - S32 open_paren = complete_name.rfind(" ("); - S32 close_paren = complete_name.rfind(')'); - - if (open_paren != std::string::npos && - close_paren == complete_name.length()-1) - { - S32 length = close_paren - open_paren - 2; - std::string legacy_name = complete_name.substr(open_paren+2, length); - - if (legacy_name.length() > 0) - { - std::string cap_letter = legacy_name.substr(0, 1); - LLStringUtil::toUpper(cap_letter); - legacy_name = cap_letter + legacy_name.substr(1); - - S32 separator = legacy_name.find('.'); - - if (separator != std::string::npos) - { - std::string last_name = legacy_name.substr(separator+1); - legacy_name = legacy_name.substr(0, separator); - - if (last_name.length() > 0) - { - cap_letter = last_name.substr(0, 1); - LLStringUtil::toUpper(cap_letter); - legacy_name = legacy_name + " " + cap_letter + last_name.substr(1); - } - } - - return legacy_name; - } - } - - return complete_name; -} - -// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer. -// The reason it is a slot is so that the legacy get() function below can bind an old callback -// and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior -// doesn't get lost. As a result, we have to bind the slot to a signal to call it, even when -// we call it immediately. -Steve -// NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the -// potential need for any parsing should any code need to handle first and last name independently. -boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback) -{ - boost::signals2::connection res; - - if(id.isNull()) - { - LLCacheNameSignal signal; - signal.connect(callback); - signal(id, sCacheName["nobody"], is_group); - return res; - } - - LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); - if (entry) - { - LLCacheNameSignal signal; - signal.connect(callback); - // id found in map therefore we can call the callback immediately. - if (entry->mIsGroup) - { - signal(id, entry->mGroupName, entry->mIsGroup); - } - else - { - std::string fullname = - buildFullName(entry->mFirstName, entry->mLastName); - signal(id, fullname, entry->mIsGroup); - } - } - else - { - // id not found in map so we must queue the callback call until available. - if (!impl.isRequestPending(id)) - { - if (is_group) - { - impl.mAskGroupQueue.insert(id); - } - else - { - impl.mAskNameQueue.insert(id); - } - } - res = impl.addPending(id, callback); - } - return res; -} - -boost::signals2::connection LLCacheName::getGroup(const LLUUID& group_id, - const LLCacheNameCallback& callback) -{ - return get(group_id, true, callback); -} - -boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data) -{ - return get(id, is_group, boost::bind(callback, _1, _2, _3, user_data)); -} - -void LLCacheName::processPending() -{ - const F32 SECS_BETWEEN_PROCESS = 0.1f; - if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS)) - { - return; - } - - if(!impl.mUpstreamHost.isOk()) - { - LL_DEBUGS() << "LLCacheName::processPending() - bad upstream host." - << LL_ENDL; - return; - } - - impl.processPendingAsks(); - impl.processPendingReplies(); -} - -void LLCacheName::deleteEntriesOlderThan(S32 secs) -{ - U32 now = (U32)time(NULL); - U32 expire_time = now - secs; - for(Cache::iterator iter = impl.mCache.begin(); iter != impl.mCache.end(); ) - { - Cache::iterator curiter = iter++; - LLCacheNameEntry* entry = curiter->second; - if (entry->mCreateTime < expire_time) - { - delete entry; - impl.mCache.erase(curiter); - } - } - - // These are pending requests that we never heard back from. - U32 pending_expire_time = now - PENDING_TIMEOUT_SECS; - for(PendingQueue::iterator p_iter = impl.mPendingQueue.begin(); - p_iter != impl.mPendingQueue.end(); ) - { - PendingQueue::iterator p_curitor = p_iter++; - - if (p_curitor->second < pending_expire_time) - { - impl.mPendingQueue.erase(p_curitor); - } - } -} - - -void LLCacheName::dump() -{ - for (Cache::iterator iter = impl.mCache.begin(), - end = impl.mCache.end(); - iter != end; iter++) - { - LLCacheNameEntry* entry = iter->second; - if (entry->mIsGroup) - { - LL_INFOS() - << iter->first << " = (group) " - << entry->mGroupName - << " @ " << entry->mCreateTime - << LL_ENDL; - } - else - { - LL_INFOS() - << iter->first << " = " - << buildFullName(entry->mFirstName, entry->mLastName) - << " @ " << entry->mCreateTime - << LL_ENDL; - } - } -} - -void LLCacheName::dumpStats() -{ - LL_INFOS() << "Queue sizes: " - << " Cache=" << impl.mCache.size() - << " AskName=" << impl.mAskNameQueue.size() - << " AskGroup=" << impl.mAskGroupQueue.size() - << " Pending=" << impl.mPendingQueue.size() - << " Reply=" << impl.mReplyQueue.size() -// << " Observers=" << impl.mSignal.size() - << LL_ENDL; -} - -void LLCacheName::clear() -{ - for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer()); - impl.mCache.clear(); -} - -//static -std::string LLCacheName::getDefaultName() -{ - return sCacheName["waiting"]; -} - -//static -std::string LLCacheName::getDefaultLastName() -{ - return "Resident"; -} - -void LLCacheName::Impl::processPendingAsks() -{ - sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue); - sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue); - mAskNameQueue.clear(); - mAskGroupQueue.clear(); -} - -void LLCacheName::Impl::processPendingReplies() -{ - // First call all the callbacks, because they might send messages. - for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it) - { - PendingReply* reply = *it; - LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID); - if(!entry) continue; - - if (!entry->mIsGroup) - { - std::string fullname = - LLCacheName::buildFullName(entry->mFirstName, entry->mLastName); - (reply->mSignal)(reply->mID, fullname, false); - } - else - { - (reply->mSignal)(reply->mID, entry->mGroupName, true); - } - } - - // Forward on all replies, if needed. - ReplySender sender(mMsg); - for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it) - { - PendingReply* reply = *it; - LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID); - if(!entry) continue; - - if (reply->mHost.isOk()) - { - sender.send(reply->mID, *entry, reply->mHost); - } - - reply->done(); - } - - for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ) - { - ReplyQueue::iterator curit = it++; - PendingReply* reply = *curit; - if (reply->isDone()) - { - delete reply; - mReplyQueue.erase(curit); - } - } -} - - -void LLCacheName::Impl::sendRequest( - const char* msg_name, - const AskQueue& queue) -{ - if(queue.empty()) - { - return; - } - - bool start_new_message = true; - AskQueue::const_iterator it = queue.begin(); - AskQueue::const_iterator end = queue.end(); - for(; it != end; ++it) - { - if(start_new_message) - { - start_new_message = false; - mMsg->newMessageFast(msg_name); - } - mMsg->nextBlockFast(_PREHASH_UUIDNameBlock); - mMsg->addUUIDFast(_PREHASH_ID, (*it)); - - if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock)) - { - start_new_message = true; - mMsg->sendReliable(mUpstreamHost); - } - } - if(!start_new_message) - { - mMsg->sendReliable(mUpstreamHost); - } -} - -bool LLCacheName::Impl::isRequestPending(const LLUUID& id) -{ - U32 now = (U32)time(NULL); - U32 expire_time = now - PENDING_TIMEOUT_SECS; - - PendingQueue::iterator iter = mPendingQueue.find(id); - - if (iter == mPendingQueue.end() - || (iter->second < expire_time) ) - { - mPendingQueue[id] = now; - return false; - } - - return true; -} - -void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup) -{ - // You should only get this message if the cache is at the simulator - // level, hence having an upstream provider. - if (!mUpstreamHost.isOk()) - { - LL_WARNS() << "LLCacheName - got UUID name/group request, but no upstream provider!" << LL_ENDL; - return; - } - - LLHost fromHost = msg->getSender(); - ReplySender sender(msg); - - S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock); - for(S32 i = 0; i < count; ++i) - { - LLUUID id; - msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i); - LLCacheNameEntry* entry = get_ptr_in_map(mCache, id); - if(entry) - { - if (isGroup != entry->mIsGroup) - { - LL_WARNS() << "LLCacheName - Asked for " - << (isGroup ? "group" : "user") << " name, " - << "but found " - << (entry->mIsGroup ? "group" : "user") - << ": " << id << LL_ENDL; - } - 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); - } - else - { - mAskNameQueue.insert(id); - } - } - - addPending(id, fromHost); - } - } -} - - - -void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup) -{ - S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock); - for(S32 i = 0; i < count; ++i) - { - LLUUID id; - msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i); - LLCacheNameEntry* entry = get_ptr_in_map(mCache, id); - if (!entry) - { - entry = new LLCacheNameEntry; - mCache[id] = entry; - } - - 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); - } - else - { // is group - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, entry->mGroupName, i); - LLStringFn::replace_ascii_controlchars(entry->mGroupName, LL_UNKNOWN_CHAR); - } - - if (!isGroup) - { - // NOTE: Very occasionally the server sends down a full name - // in the first name field with an empty last name, for example, - // first = "Ladanie1 Resident", last = "". - // I cannot reproduce this, nor can I find a bug in the server code. - // Ensure "Resident" does not appear via cleanFullName, because - // buildFullName only checks last name. JC - std::string full_name; - if (entry->mLastName.empty()) - { - full_name = cleanFullName(entry->mFirstName); - - //fix what we are putting in the cache - entry->mFirstName = full_name; - entry->mLastName = "Resident"; - } - else - { - full_name = LLCacheName::buildFullName(entry->mFirstName, entry->mLastName); - } - mSignal(id, full_name, false); - mReverseCache[full_name] = id; - } - else - { - mSignal(id, entry->mGroupName, true); - mReverseCache[entry->mGroupName] = id; - } - } -} - - - -// static call back functions - -void LLCacheName::Impl::handleUUIDNameReply(LLMessageSystem* msg, void** userData) -{ - ((LLCacheName::Impl*)userData)->processUUIDReply(msg, false); -} - -void LLCacheName::Impl::handleUUIDNameRequest(LLMessageSystem* msg, void** userData) -{ - ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, false); -} - -void LLCacheName::Impl::handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userData) -{ - ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, true); -} - -void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** userData) -{ - ((LLCacheName::Impl*)userData)->processUUIDReply(msg, true); -} +/**
+ * @file llcachename.cpp
+ * @brief A hierarchical cache of first and last names queried based on UUID.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "linden_common.h"
+
+#include "llcachename.h"
+
+// linden library includes
+#include "lldbstrings.h"
+#include "llframetimer.h"
+#include "llhost.h"
+#include "llrand.h"
+#include "llsdserialize.h"
+#include "lluuid.h"
+#include "message.h"
+
+#include <boost/regex.hpp>
+
+// llsd serialization constants
+static const std::string AGENTS("agents");
+static const std::string GROUPS("groups");
+static const std::string CTIME("ctime");
+static const std::string FIRST("first");
+static const std::string LAST("last");
+static const std::string NAME("name");
+
+// We track name requests in flight for up to this long.
+// We won't re-request a name during this time
+const U32 PENDING_TIMEOUT_SECS = 5 * 60;
+
+// Globals
+LLCacheName* gCacheName = NULL;
+std::map<std::string, std::string> LLCacheName::sCacheName;
+
+/// ---------------------------------------------------------------------------
+/// class LLCacheNameEntry
+/// ---------------------------------------------------------------------------
+
+class LLCacheNameEntry
+{
+public:
+ LLCacheNameEntry();
+
+public:
+ bool mIsGroup;
+ U32 mCreateTime; // unix time_t
+ // IDEVO TODO collapse names to one field, which will eliminate
+ // many string compares on "Resident"
+ std::string mFirstName;
+ std::string mLastName;
+ std::string mGroupName;
+};
+
+LLCacheNameEntry::LLCacheNameEntry()
+ : mIsGroup(false),
+ mCreateTime(0)
+{
+}
+
+
+class PendingReply
+{
+public:
+ LLUUID mID;
+ LLCacheNameSignal mSignal;
+ LLHost mHost;
+
+ PendingReply(const LLUUID& id, const LLHost& host)
+ : mID(id), mHost(host)
+ {
+ }
+
+ boost::signals2::connection setCallback(const LLCacheNameCallback& cb)
+ {
+ return mSignal.connect(cb);
+ }
+
+ void done() { mID.setNull(); }
+ bool isDone() const { return mID.isNull(); }
+};
+
+class ReplySender
+{
+public:
+ ReplySender(LLMessageSystem* msg);
+ ~ReplySender();
+
+ void send(const LLUUID& id,
+ const LLCacheNameEntry& entry, const LLHost& host);
+
+private:
+ void flush();
+
+ LLMessageSystem* mMsg;
+ bool mPending;
+ bool mCurrIsGroup;
+ LLHost mCurrHost;
+};
+
+ReplySender::ReplySender(LLMessageSystem* msg)
+ : mMsg(msg), mPending(false), mCurrIsGroup(false)
+{ }
+
+ReplySender::~ReplySender()
+{
+ flush();
+}
+
+void ReplySender::send(const LLUUID& id,
+ const LLCacheNameEntry& entry, const LLHost& host)
+{
+ if (mPending)
+ {
+ if (mCurrIsGroup != entry.mIsGroup
+ || mCurrHost != host)
+ {
+ flush();
+ }
+ }
+
+ if (!mPending)
+ {
+ mPending = true;
+ mCurrIsGroup = entry.mIsGroup;
+ mCurrHost = host;
+
+ if(mCurrIsGroup)
+ mMsg->newMessageFast(_PREHASH_UUIDGroupNameReply);
+ else
+ mMsg->newMessageFast(_PREHASH_UUIDNameReply);
+ }
+
+ mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
+ mMsg->addUUIDFast(_PREHASH_ID, id);
+ if(mCurrIsGroup)
+ {
+ mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName);
+ }
+ else
+ {
+ mMsg->addStringFast(_PREHASH_FirstName, entry.mFirstName);
+ mMsg->addStringFast(_PREHASH_LastName, entry.mLastName);
+ }
+
+ if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
+ {
+ flush();
+ }
+}
+
+void ReplySender::flush()
+{
+ if (mPending)
+ {
+ mMsg->sendReliable(mCurrHost);
+ mPending = false;
+ }
+}
+
+
+typedef std::set<LLUUID> AskQueue;
+typedef std::list<PendingReply*> ReplyQueue;
+typedef std::map<LLUUID,U32> PendingQueue;
+typedef std::map<LLUUID, LLCacheNameEntry*> Cache;
+typedef std::map<std::string, LLUUID> ReverseCache;
+
+class LLCacheName::Impl
+{
+public:
+ LLMessageSystem* mMsg;
+ LLHost mUpstreamHost;
+
+ Cache mCache;
+ // the map of UUIDs to names
+ ReverseCache mReverseCache;
+ // map of names to UUIDs
+
+ AskQueue mAskNameQueue;
+ AskQueue mAskGroupQueue;
+ // UUIDs to ask our upstream host about
+
+ PendingQueue mPendingQueue;
+ // UUIDs that have been requested but are not in cache yet.
+
+ ReplyQueue mReplyQueue;
+ // requests awaiting replies from us
+
+ LLCacheNameSignal mSignal;
+
+ LLFrameTimer mProcessTimer;
+
+ Impl(LLMessageSystem* msg);
+ ~Impl();
+
+ bool getName(const LLUUID& id, std::string& first, std::string& last);
+
+ boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback);
+ void addPending(const LLUUID& id, const LLHost& host);
+
+ void processPendingAsks();
+ void processPendingReplies();
+ void sendRequest(const char* msg_name, const AskQueue& queue);
+ bool isRequestPending(const LLUUID& id);
+
+ // Message system callbacks.
+ void processUUIDRequest(LLMessageSystem* msg, bool isGroup);
+ void processUUIDReply(LLMessageSystem* msg, bool isGroup);
+
+ static void handleUUIDNameRequest(LLMessageSystem* msg, void** userdata);
+ static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata);
+ static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata);
+ static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata);
+};
+
+
+/// --------------------------------------------------------------------------
+/// class LLCacheName
+/// ---------------------------------------------------------------------------
+
+LLCacheName::LLCacheName(LLMessageSystem* msg)
+ : impl(* new Impl(msg))
+ { }
+
+LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host)
+ : impl(* new Impl(msg))
+{
+ sCacheName["waiting"] = "(Loading...)";
+ sCacheName["nobody"] = "(nobody)";
+ sCacheName["none"] = "(none)";
+ setUpstream(upstream_host);
+}
+
+LLCacheName::~LLCacheName()
+{
+ delete &impl;
+}
+
+LLCacheName::Impl::Impl(LLMessageSystem* msg)
+ : mMsg(msg), mUpstreamHost(LLHost())
+{
+ mMsg->setHandlerFuncFast(
+ _PREHASH_UUIDNameRequest, handleUUIDNameRequest, (void**)this);
+ mMsg->setHandlerFuncFast(
+ _PREHASH_UUIDNameReply, handleUUIDNameReply, (void**)this);
+ mMsg->setHandlerFuncFast(
+ _PREHASH_UUIDGroupNameRequest, handleUUIDGroupNameRequest, (void**)this);
+ mMsg->setHandlerFuncFast(
+ _PREHASH_UUIDGroupNameReply, handleUUIDGroupNameReply, (void**)this);
+}
+
+
+LLCacheName::Impl::~Impl()
+{
+ for_each(mCache.begin(), mCache.end(), DeletePairedPointer());
+ mCache.clear();
+ for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer());
+ mReplyQueue.clear();
+}
+
+boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback)
+{
+ PendingReply* reply = new PendingReply(id, LLHost());
+ boost::signals2::connection res = reply->setCallback(callback);
+ mReplyQueue.push_back(reply);
+ return res;
+}
+
+void LLCacheName::Impl::addPending(const LLUUID& id, const LLHost& host)
+{
+ PendingReply* reply = new PendingReply(id, host);
+ mReplyQueue.push_back(reply);
+}
+
+void LLCacheName::setUpstream(const LLHost& upstream_host)
+{
+ impl.mUpstreamHost = upstream_host;
+}
+
+boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& callback)
+{
+ return impl.mSignal.connect(callback);
+}
+
+bool LLCacheName::importFile(std::istream& istr)
+{
+ LLSD data;
+ if(LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(data, istr))
+ {
+ return false;
+ }
+
+ // We'll expire entries more than a week old
+ U32 now = (U32)time(NULL);
+ const U32 SECS_PER_DAY = 60 * 60 * 24;
+ U32 delete_before_time = now - (7 * SECS_PER_DAY);
+
+ // iterate over the agents
+ S32 count = 0;
+ LLSD agents = data[AGENTS];
+ LLSD::map_iterator iter = agents.beginMap();
+ LLSD::map_iterator end = agents.endMap();
+ for( ; iter != end; ++iter)
+ {
+ LLUUID id((*iter).first);
+ LLSD agent = (*iter).second;
+ U32 ctime = (U32)agent[CTIME].asInteger();
+ if(ctime < delete_before_time) continue;
+
+ LLCacheNameEntry* entry = new LLCacheNameEntry();
+ entry->mIsGroup = false;
+ entry->mCreateTime = ctime;
+ entry->mFirstName = agent[FIRST].asString();
+ entry->mLastName = agent[LAST].asString();
+ impl.mCache[id] = entry;
+ std::string fullname = buildFullName(entry->mFirstName, entry->mLastName);
+ impl.mReverseCache[fullname] = id;
+
+ ++count;
+ }
+ LL_INFOS() << "LLCacheName loaded " << count << " agent names" << LL_ENDL;
+
+ count = 0;
+ LLSD groups = data[GROUPS];
+ iter = groups.beginMap();
+ end = groups.endMap();
+ for( ; iter != end; ++iter)
+ {
+ LLUUID id((*iter).first);
+ LLSD group = (*iter).second;
+ U32 ctime = (U32)group[CTIME].asInteger();
+ if(ctime < delete_before_time) continue;
+
+ LLCacheNameEntry* entry = new LLCacheNameEntry();
+ entry->mIsGroup = true;
+ entry->mCreateTime = ctime;
+ entry->mGroupName = group[NAME].asString();
+ impl.mCache[id] = entry;
+ impl.mReverseCache[entry->mGroupName] = id;
+ ++count;
+ }
+ LL_INFOS() << "LLCacheName loaded " << count << " group names" << LL_ENDL;
+ return true;
+}
+
+void LLCacheName::exportFile(std::ostream& ostr)
+{
+ LLSD data;
+ Cache::iterator iter = impl.mCache.begin();
+ Cache::iterator end = impl.mCache.end();
+ for( ; iter != end; ++iter)
+ {
+ // 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('?')))
+ {
+ continue;
+ }
+
+ // store it
+ LLUUID id = iter->first;
+ std::string id_str = id.asString();
+ // IDEVO TODO: Should we store SLIDs with last name "Resident" or not?
+ if(!entry->mFirstName.empty() && !entry->mLastName.empty())
+ {
+ 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);
+}
+
+
+bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last)
+{
+ if(id.isNull())
+ {
+ first = sCacheName["nobody"];
+ last.clear();
+ return true;
+ }
+
+ LLCacheNameEntry* entry = get_ptr_in_map(mCache, id );
+ if (entry)
+ {
+ first = entry->mFirstName;
+ last = entry->mLastName;
+ return true;
+ }
+ else
+ {
+ first = sCacheName["waiting"];
+ last.clear();
+ if (!isRequestPending(id))
+ {
+ mAskNameQueue.insert(id);
+ }
+ return false;
+ }
+
+}
+
+// static
+void LLCacheName::localizeCacheName(std::string key, std::string value)
+{
+ if (key!="" && value!= "" )
+ sCacheName[key]=value;
+ else
+ LL_WARNS()<< " Error localizing cache key " << key << " To "<< value<<LL_ENDL;
+}
+
+bool LLCacheName::getFullName(const LLUUID& id, std::string& fullname)
+{
+ std::string first_name, last_name;
+ bool res = impl.getName(id, first_name, last_name);
+ fullname = buildFullName(first_name, last_name);
+ return res;
+}
+
+
+
+bool LLCacheName::getGroupName(const LLUUID& id, std::string& group)
+{
+ if(id.isNull())
+ {
+ group = sCacheName["none"];
+ return true;
+ }
+
+ LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id);
+ if (entry && entry->mGroupName.empty())
+ {
+ // COUNTER-HACK to combat James' HACK in exportFile()...
+ // this group name was loaded from a name cache that did not
+ // bother to save the group name ==> we must ask for it
+ LL_DEBUGS() << "LLCacheName queuing HACK group request: " << id << LL_ENDL;
+ entry = NULL;
+ }
+
+ if (entry)
+ {
+ group = entry->mGroupName;
+ return true;
+ }
+ else
+ {
+ group = sCacheName["waiting"];
+ if (!impl.isRequestPending(id))
+ {
+ impl.mAskGroupQueue.insert(id);
+ }
+ return false;
+ }
+}
+
+bool LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id)
+{
+ std::string full_name = buildFullName(first, last);
+ return getUUID(full_name, id);
+}
+
+bool LLCacheName::getUUID(const std::string& full_name, LLUUID& id)
+{
+ ReverseCache::iterator iter = impl.mReverseCache.find(full_name);
+ if (iter != impl.mReverseCache.end())
+ {
+ id = iter->second;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//static
+std::string LLCacheName::buildFullName(const std::string& first, const std::string& last)
+{
+ std::string fullname = first;
+ if (!last.empty()
+ && last != "Resident")
+ {
+ fullname += ' ';
+ fullname += last;
+ }
+ return fullname;
+}
+
+//static
+std::string LLCacheName::cleanFullName(const std::string& full_name)
+{
+ return full_name.substr(0, full_name.find(" Resident"));
+}
+
+//static
+// Transform hard-coded name provided by server to a more legible username
+std::string LLCacheName::buildUsername(const std::string& full_name)
+{
+ // rare, but handle hard-coded error names returned from server
+ if (full_name == "(\?\?\?) (\?\?\?)")
+ {
+ return "(\?\?\?)";
+ }
+
+ std::string::size_type index = full_name.find(' ');
+
+ if (index != std::string::npos)
+ {
+ std::string username;
+ username = full_name.substr(0, index);
+ std::string lastname = full_name.substr(index+1);
+
+ if (lastname != "Resident")
+ {
+ username = username + "." + lastname;
+ }
+
+ LLStringUtil::toLower(username);
+ return username;
+ }
+
+ // if the input wasn't a correctly formatted legacy name, just return it
+ // cleaned up from a potential terminal "Resident"
+ std::string clean_name = cleanFullName(full_name);
+ LLStringUtil::toLower(clean_name);
+ return clean_name;
+}
+
+//static
+std::string LLCacheName::buildLegacyName(const std::string& complete_name)
+{
+ //boost::regexp was showing up in the crashreporter, so doing
+ //painfully manual parsing using substr. LF
+ S32 open_paren = complete_name.rfind(" (");
+ S32 close_paren = complete_name.rfind(')');
+
+ if (open_paren != std::string::npos &&
+ close_paren == complete_name.length()-1)
+ {
+ S32 length = close_paren - open_paren - 2;
+ std::string legacy_name = complete_name.substr(open_paren+2, length);
+
+ if (legacy_name.length() > 0)
+ {
+ std::string cap_letter = legacy_name.substr(0, 1);
+ LLStringUtil::toUpper(cap_letter);
+ legacy_name = cap_letter + legacy_name.substr(1);
+
+ S32 separator = legacy_name.find('.');
+
+ if (separator != std::string::npos)
+ {
+ std::string last_name = legacy_name.substr(separator+1);
+ legacy_name = legacy_name.substr(0, separator);
+
+ if (last_name.length() > 0)
+ {
+ cap_letter = last_name.substr(0, 1);
+ LLStringUtil::toUpper(cap_letter);
+ legacy_name = legacy_name + " " + cap_letter + last_name.substr(1);
+ }
+ }
+
+ return legacy_name;
+ }
+ }
+
+ return complete_name;
+}
+
+// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer.
+// The reason it is a slot is so that the legacy get() function below can bind an old callback
+// and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior
+// doesn't get lost. As a result, we have to bind the slot to a signal to call it, even when
+// we call it immediately. -Steve
+// NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the
+// potential need for any parsing should any code need to handle first and last name independently.
+boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)
+{
+ boost::signals2::connection res;
+
+ if(id.isNull())
+ {
+ LLCacheNameSignal signal;
+ signal.connect(callback);
+ signal(id, sCacheName["nobody"], is_group);
+ return res;
+ }
+
+ LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
+ if (entry)
+ {
+ LLCacheNameSignal signal;
+ signal.connect(callback);
+ // id found in map therefore we can call the callback immediately.
+ if (entry->mIsGroup)
+ {
+ signal(id, entry->mGroupName, entry->mIsGroup);
+ }
+ else
+ {
+ std::string fullname =
+ buildFullName(entry->mFirstName, entry->mLastName);
+ signal(id, fullname, entry->mIsGroup);
+ }
+ }
+ else
+ {
+ // id not found in map so we must queue the callback call until available.
+ if (!impl.isRequestPending(id))
+ {
+ if (is_group)
+ {
+ impl.mAskGroupQueue.insert(id);
+ }
+ else
+ {
+ impl.mAskNameQueue.insert(id);
+ }
+ }
+ res = impl.addPending(id, callback);
+ }
+ return res;
+}
+
+boost::signals2::connection LLCacheName::getGroup(const LLUUID& group_id,
+ const LLCacheNameCallback& callback)
+{
+ return get(group_id, true, callback);
+}
+
+boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data)
+{
+ return get(id, is_group, boost::bind(callback, _1, _2, _3, user_data));
+}
+
+void LLCacheName::processPending()
+{
+ const F32 SECS_BETWEEN_PROCESS = 0.1f;
+ if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS))
+ {
+ return;
+ }
+
+ if(!impl.mUpstreamHost.isOk())
+ {
+ LL_DEBUGS() << "LLCacheName::processPending() - bad upstream host."
+ << LL_ENDL;
+ return;
+ }
+
+ impl.processPendingAsks();
+ impl.processPendingReplies();
+}
+
+void LLCacheName::deleteEntriesOlderThan(S32 secs)
+{
+ U32 now = (U32)time(NULL);
+ U32 expire_time = now - secs;
+ for(Cache::iterator iter = impl.mCache.begin(); iter != impl.mCache.end(); )
+ {
+ Cache::iterator curiter = iter++;
+ LLCacheNameEntry* entry = curiter->second;
+ if (entry->mCreateTime < expire_time)
+ {
+ delete entry;
+ impl.mCache.erase(curiter);
+ }
+ }
+
+ // These are pending requests that we never heard back from.
+ U32 pending_expire_time = now - PENDING_TIMEOUT_SECS;
+ for(PendingQueue::iterator p_iter = impl.mPendingQueue.begin();
+ p_iter != impl.mPendingQueue.end(); )
+ {
+ PendingQueue::iterator p_curitor = p_iter++;
+
+ if (p_curitor->second < pending_expire_time)
+ {
+ impl.mPendingQueue.erase(p_curitor);
+ }
+ }
+}
+
+
+void LLCacheName::dump()
+{
+ for (Cache::iterator iter = impl.mCache.begin(),
+ end = impl.mCache.end();
+ iter != end; iter++)
+ {
+ LLCacheNameEntry* entry = iter->second;
+ if (entry->mIsGroup)
+ {
+ LL_INFOS()
+ << iter->first << " = (group) "
+ << entry->mGroupName
+ << " @ " << entry->mCreateTime
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS()
+ << iter->first << " = "
+ << buildFullName(entry->mFirstName, entry->mLastName)
+ << " @ " << entry->mCreateTime
+ << LL_ENDL;
+ }
+ }
+}
+
+void LLCacheName::dumpStats()
+{
+ LL_INFOS() << "Queue sizes: "
+ << " Cache=" << impl.mCache.size()
+ << " AskName=" << impl.mAskNameQueue.size()
+ << " AskGroup=" << impl.mAskGroupQueue.size()
+ << " Pending=" << impl.mPendingQueue.size()
+ << " Reply=" << impl.mReplyQueue.size()
+// << " Observers=" << impl.mSignal.size()
+ << LL_ENDL;
+}
+
+void LLCacheName::clear()
+{
+ for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer());
+ impl.mCache.clear();
+}
+
+//static
+std::string LLCacheName::getDefaultName()
+{
+ return sCacheName["waiting"];
+}
+
+//static
+std::string LLCacheName::getDefaultLastName()
+{
+ return "Resident";
+}
+
+void LLCacheName::Impl::processPendingAsks()
+{
+ sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue);
+ sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue);
+ mAskNameQueue.clear();
+ mAskGroupQueue.clear();
+}
+
+void LLCacheName::Impl::processPendingReplies()
+{
+ // First call all the callbacks, because they might send messages.
+ for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it)
+ {
+ PendingReply* reply = *it;
+ LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID);
+ if(!entry) continue;
+
+ if (!entry->mIsGroup)
+ {
+ std::string fullname =
+ LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
+ (reply->mSignal)(reply->mID, fullname, false);
+ }
+ else
+ {
+ (reply->mSignal)(reply->mID, entry->mGroupName, true);
+ }
+ }
+
+ // Forward on all replies, if needed.
+ ReplySender sender(mMsg);
+ for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it)
+ {
+ PendingReply* reply = *it;
+ LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID);
+ if(!entry) continue;
+
+ if (reply->mHost.isOk())
+ {
+ sender.send(reply->mID, *entry, reply->mHost);
+ }
+
+ reply->done();
+ }
+
+ for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); )
+ {
+ ReplyQueue::iterator curit = it++;
+ PendingReply* reply = *curit;
+ if (reply->isDone())
+ {
+ delete reply;
+ mReplyQueue.erase(curit);
+ }
+ }
+}
+
+
+void LLCacheName::Impl::sendRequest(
+ const char* msg_name,
+ const AskQueue& queue)
+{
+ if(queue.empty())
+ {
+ return;
+ }
+
+ bool start_new_message = true;
+ AskQueue::const_iterator it = queue.begin();
+ AskQueue::const_iterator end = queue.end();
+ for(; it != end; ++it)
+ {
+ if(start_new_message)
+ {
+ start_new_message = false;
+ mMsg->newMessageFast(msg_name);
+ }
+ mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
+ mMsg->addUUIDFast(_PREHASH_ID, (*it));
+
+ if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
+ {
+ start_new_message = true;
+ mMsg->sendReliable(mUpstreamHost);
+ }
+ }
+ if(!start_new_message)
+ {
+ mMsg->sendReliable(mUpstreamHost);
+ }
+}
+
+bool LLCacheName::Impl::isRequestPending(const LLUUID& id)
+{
+ U32 now = (U32)time(NULL);
+ U32 expire_time = now - PENDING_TIMEOUT_SECS;
+
+ PendingQueue::iterator iter = mPendingQueue.find(id);
+
+ if (iter == mPendingQueue.end()
+ || (iter->second < expire_time) )
+ {
+ mPendingQueue[id] = now;
+ return false;
+ }
+
+ return true;
+}
+
+void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup)
+{
+ // You should only get this message if the cache is at the simulator
+ // level, hence having an upstream provider.
+ if (!mUpstreamHost.isOk())
+ {
+ LL_WARNS() << "LLCacheName - got UUID name/group request, but no upstream provider!" << LL_ENDL;
+ return;
+ }
+
+ LLHost fromHost = msg->getSender();
+ ReplySender sender(msg);
+
+ S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
+ for(S32 i = 0; i < count; ++i)
+ {
+ LLUUID id;
+ msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
+ LLCacheNameEntry* entry = get_ptr_in_map(mCache, id);
+ if(entry)
+ {
+ if (isGroup != entry->mIsGroup)
+ {
+ LL_WARNS() << "LLCacheName - Asked for "
+ << (isGroup ? "group" : "user") << " name, "
+ << "but found "
+ << (entry->mIsGroup ? "group" : "user")
+ << ": " << id << LL_ENDL;
+ }
+ 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);
+ }
+ else
+ {
+ mAskNameQueue.insert(id);
+ }
+ }
+
+ addPending(id, fromHost);
+ }
+ }
+}
+
+
+
+void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
+{
+ S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
+ for(S32 i = 0; i < count; ++i)
+ {
+ LLUUID id;
+ msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
+ LLCacheNameEntry* entry = get_ptr_in_map(mCache, id);
+ if (!entry)
+ {
+ entry = new LLCacheNameEntry;
+ mCache[id] = entry;
+ }
+
+ 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);
+ }
+ else
+ { // is group
+ msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, entry->mGroupName, i);
+ LLStringFn::replace_ascii_controlchars(entry->mGroupName, LL_UNKNOWN_CHAR);
+ }
+
+ if (!isGroup)
+ {
+ // NOTE: Very occasionally the server sends down a full name
+ // in the first name field with an empty last name, for example,
+ // first = "Ladanie1 Resident", last = "".
+ // I cannot reproduce this, nor can I find a bug in the server code.
+ // Ensure "Resident" does not appear via cleanFullName, because
+ // buildFullName only checks last name. JC
+ std::string full_name;
+ if (entry->mLastName.empty())
+ {
+ full_name = cleanFullName(entry->mFirstName);
+
+ //fix what we are putting in the cache
+ entry->mFirstName = full_name;
+ entry->mLastName = "Resident";
+ }
+ else
+ {
+ full_name = LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
+ }
+ mSignal(id, full_name, false);
+ mReverseCache[full_name] = id;
+ }
+ else
+ {
+ mSignal(id, entry->mGroupName, true);
+ mReverseCache[entry->mGroupName] = id;
+ }
+ }
+}
+
+
+
+// static call back functions
+
+void LLCacheName::Impl::handleUUIDNameReply(LLMessageSystem* msg, void** userData)
+{
+ ((LLCacheName::Impl*)userData)->processUUIDReply(msg, false);
+}
+
+void LLCacheName::Impl::handleUUIDNameRequest(LLMessageSystem* msg, void** userData)
+{
+ ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, false);
+}
+
+void LLCacheName::Impl::handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userData)
+{
+ ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, true);
+}
+
+void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** userData)
+{
+ ((LLCacheName::Impl*)userData)->processUUIDReply(msg, true);
+}
diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index 401f52a579..958f91d3c0 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -1,148 +1,148 @@ -/** - * @file llcachename.h - * @brief A cache of names from UUIDs. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#ifndef LL_LLCACHENAME_H -#define LL_LLCACHENAME_H - -#include <boost/bind.hpp> -#include <boost/signals2.hpp> - -class LLMessageSystem; -class LLHost; -class LLUUID; - - -typedef boost::signals2::signal<void (const LLUUID& id, - const std::string& name, - bool is_group)> LLCacheNameSignal; -typedef LLCacheNameSignal::slot_type LLCacheNameCallback; - -// Old callback with user data for compatibility -typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*); - -// Here's the theory: -// If you request a name that isn't in the cache, it returns "waiting" -// and requests the data. After the data arrives, you get that on -// subsequent calls. -// If the data hasn't been updated in an hour, it requests it again, -// but keeps giving you the old value until new data arrives. -// If you haven't requested the data in an hour, it releases it. -class LLCacheName -{ -public: - LLCacheName(LLMessageSystem* msg); - LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host); - ~LLCacheName(); - - // registers the upstream host - // for viewers, this is the currently connected simulator - // for simulators, this is the data server - void setUpstream(const LLHost& upstream_host); - - boost::signals2::connection addObserver(const LLCacheNameCallback& callback); - - // storing cache on disk; for viewer, in name.cache - bool importFile(std::istream& istr); - void exportFile(std::ostream& ostr); - - // If available, copies name ("bobsmith123" or "James Linden") into string - // If not available, copies the string "waiting". - // Returns TRUE iff available. - BOOL getFullName(const LLUUID& id, std::string& full_name); - - // Reverse lookup of UUID from name - BOOL getUUID(const std::string& first, const std::string& last, LLUUID& id); - BOOL getUUID(const std::string& fullname, LLUUID& id); - - // IDEVO Temporary code - // Clean up new-style "bobsmith123 Resident" names to "bobsmith123" for display - static std::string buildFullName(const std::string& first, const std::string& last); - - // Clean up legacy "bobsmith123 Resident" to "bobsmith123" - // If name does not contain "Resident" returns it unchanged. - static std::string cleanFullName(const std::string& full_name); - - // Converts a standard legacy name to a username - // "bobsmith123 Resident" -> "bobsmith" - // "Random Linden" -> "random.linden" - static std::string buildUsername(const std::string& name); - - // Converts a complete display name to a legacy name - // if possible, otherwise returns the input - // "Alias (random.linden)" -> "Random Linden" - // "Something random" -> "Something random" - static std::string buildLegacyName(const std::string& name); - - // If available, this method copies the group name into the string - // provided. The caller must allocate at least - // DB_GROUP_NAME_BUF_SIZE characters. If not available, this - // method copies the string "waiting". Returns TRUE iff available. - BOOL getGroupName(const LLUUID& id, std::string& group); - - // Call the callback with the group or avatar name. - // 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. - boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback); - - // Convenience method for looking up a group name, so you can - // tell the difference between avatar lookup and group lookup - // in global searches - boost::signals2::connection getGroup(const LLUUID& group_id, const LLCacheNameCallback& callback); - - // LEGACY - boost::signals2::connection get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data); - // This method needs to be called from time to time to send out - // requests. - void processPending(); - - // Expire entries created more than "secs" seconds ago. - void deleteEntriesOlderThan(S32 secs); - - // Debugging - void dump(); // Dumps the contents of the cache - void dumpStats(); // Dumps the sizes of the cache and associated queues. - void clear(); // Deletes all entries from the cache - - static std::string getDefaultName(); - - // Returns "Resident", the default last name for SLID-based accounts - // that have no last name. - static std::string getDefaultLastName(); - - static void localizeCacheName(std::string key, std::string value); - static std::map<std::string, std::string> sCacheName; -private: - - class Impl; - Impl& impl; -}; - - - -extern LLCacheName* gCacheName; - -#endif +/**
+ * @file llcachename.h
+ * @brief A cache of names from UUIDs.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLCACHENAME_H
+#define LL_LLCACHENAME_H
+
+#include <boost/bind.hpp>
+#include <boost/signals2.hpp>
+
+class LLMessageSystem;
+class LLHost;
+class LLUUID;
+
+
+typedef boost::signals2::signal<void (const LLUUID& id,
+ const std::string& name,
+ bool is_group)> LLCacheNameSignal;
+typedef LLCacheNameSignal::slot_type LLCacheNameCallback;
+
+// Old callback with user data for compatibility
+typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*);
+
+// Here's the theory:
+// If you request a name that isn't in the cache, it returns "waiting"
+// and requests the data. After the data arrives, you get that on
+// subsequent calls.
+// If the data hasn't been updated in an hour, it requests it again,
+// but keeps giving you the old value until new data arrives.
+// If you haven't requested the data in an hour, it releases it.
+class LLCacheName
+{
+public:
+ LLCacheName(LLMessageSystem* msg);
+ LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host);
+ ~LLCacheName();
+
+ // registers the upstream host
+ // for viewers, this is the currently connected simulator
+ // for simulators, this is the data server
+ void setUpstream(const LLHost& upstream_host);
+
+ boost::signals2::connection addObserver(const LLCacheNameCallback& callback);
+
+ // storing cache on disk; for viewer, in name.cache
+ bool importFile(std::istream& istr);
+ void exportFile(std::ostream& ostr);
+
+ // If available, copies name ("bobsmith123" or "James Linden") into string
+ // If not available, copies the string "waiting".
+ // Returns true if available.
+ bool getFullName(const LLUUID& id, std::string& full_name);
+
+ // Reverse lookup of UUID from name
+ bool getUUID(const std::string& first, const std::string& last, LLUUID& id);
+ bool getUUID(const std::string& fullname, LLUUID& id);
+
+ // IDEVO Temporary code
+ // Clean up new-style "bobsmith123 Resident" names to "bobsmith123" for display
+ static std::string buildFullName(const std::string& first, const std::string& last);
+
+ // Clean up legacy "bobsmith123 Resident" to "bobsmith123"
+ // If name does not contain "Resident" returns it unchanged.
+ static std::string cleanFullName(const std::string& full_name);
+
+ // Converts a standard legacy name to a username
+ // "bobsmith123 Resident" -> "bobsmith"
+ // "Random Linden" -> "random.linden"
+ static std::string buildUsername(const std::string& name);
+
+ // Converts a complete display name to a legacy name
+ // if possible, otherwise returns the input
+ // "Alias (random.linden)" -> "Random Linden"
+ // "Something random" -> "Something random"
+ static std::string buildLegacyName(const std::string& name);
+
+ // If available, this method copies the group name into the string
+ // provided. The caller must allocate at least
+ // DB_GROUP_NAME_BUF_SIZE characters. If not available, this
+ // method copies the string "waiting". Returns true if available.
+ bool getGroupName(const LLUUID& id, std::string& group);
+
+ // Call the callback with the group or avatar name.
+ // 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.
+ boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback);
+
+ // Convenience method for looking up a group name, so you can
+ // tell the difference between avatar lookup and group lookup
+ // in global searches
+ boost::signals2::connection getGroup(const LLUUID& group_id, const LLCacheNameCallback& callback);
+
+ // LEGACY
+ boost::signals2::connection get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data);
+ // This method needs to be called from time to time to send out
+ // requests.
+ void processPending();
+
+ // Expire entries created more than "secs" seconds ago.
+ void deleteEntriesOlderThan(S32 secs);
+
+ // Debugging
+ void dump(); // Dumps the contents of the cache
+ void dumpStats(); // Dumps the sizes of the cache and associated queues.
+ void clear(); // Deletes all entries from the cache
+
+ static std::string getDefaultName();
+
+ // Returns "Resident", the default last name for SLID-based accounts
+ // that have no last name.
+ static std::string getDefaultLastName();
+
+ static void localizeCacheName(std::string key, std::string value);
+ static std::map<std::string, std::string> sCacheName;
+private:
+
+ class Impl;
+ Impl& impl;
+};
+
+
+
+extern LLCacheName* gCacheName;
+
+#endif
diff --git a/indra/llmessage/llcipher.h b/indra/llmessage/llcipher.h index 4bbc6466a9..cbd5d5bde1 100644 --- a/indra/llmessage/llcipher.h +++ b/indra/llmessage/llcipher.h @@ -1,56 +1,56 @@ -/** - * @file llcipher.h - * @brief Abstract base class for encryption ciphers. - * - * $LicenseInfo:firstyear=2003&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$ - */ - -#ifndef LLCIPHER_H -#define LLCIPHER_H - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLCipher -// -// Abstract base class for a cipher object. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLCipher -{ -public: - virtual ~LLCipher() {} - - // encrypt src and place result into dst. returns TRUE if - // Returns number of bytes written into dst, or 0 on error. - virtual U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) = 0; - - // decrypt src and place result into dst. - // Returns number of bytes written into dst, or 0 on error. - virtual U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) = 0; - - // returns the minimum amount of space required to encrypt for a - // unencrypted source buffer of length len. - // *NOTE: This is estimated space and you should check the return value - // of the encrypt function. - virtual U32 requiredEncryptionSpace(U32 src_len) const = 0 ; -}; - -#endif +/**
+ * @file llcipher.h
+ * @brief Abstract base class for encryption ciphers.
+ *
+ * $LicenseInfo:firstyear=2003&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$
+ */
+
+#ifndef LLCIPHER_H
+#define LLCIPHER_H
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLCipher
+//
+// Abstract base class for a cipher object.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLCipher
+{
+public:
+ virtual ~LLCipher() {}
+
+ // encrypt src and place result into dst. returns true if
+ // Returns number of bytes written into dst, or 0 on error.
+ virtual U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) = 0;
+
+ // decrypt src and place result into dst.
+ // Returns number of bytes written into dst, or 0 on error.
+ virtual U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) = 0;
+
+ // returns the minimum amount of space required to encrypt for a
+ // unencrypted source buffer of length len.
+ // *NOTE: This is estimated space and you should check the return value
+ // of the encrypt function.
+ virtual U32 requiredEncryptionSpace(U32 src_len) const = 0 ;
+};
+
+#endif
diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index d6125fd321..bd9b3553fe 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -1,1419 +1,1419 @@ -/** - * @file llcircuit.cpp - * @brief Class to track UDP endpoints for the message system. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#include "linden_common.h" - -#if LL_WINDOWS - -#include <process.h> - -#else - -#if LL_LINUX -#include <dlfcn.h> // RTLD_LAZY -#endif -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> - -#endif - - -#if !defined(USE_CIRCUIT_LIST) -#include <algorithm> -#endif -#include <sstream> -#include <iterator> -#include <stack> - -#include "llcircuit.h" - -#include "message.h" -#include "llrand.h" -#include "llstl.h" -#include "lltransfermanager.h" -#include "llmodularmath.h" - -const S32 PING_START_BLOCK = 3; // How many pings behind we have to be to consider ourself blocked. -const S32 PING_RELEASE_BLOCK = 2; // How many pings behind we have to be to consider ourself unblocked. - -const F32Seconds TARGET_PERIOD_LENGTH(5.f); -const F32Seconds LL_DUPLICATE_SUPPRESSION_TIMEOUT(60.f); //this can be long, as time-based cleanup is - // only done when wrapping packetids, now... - -LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, - const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout) -: mHost (host), - mWrapID(0), - mPacketsOutID(0), - mPacketsInID(in_id), - mHighestPacketID(in_id), - mTimeoutCallback(NULL), - mTimeoutUserData(NULL), - mTrusted(FALSE), - mbAllowTimeout(TRUE), - mbAlive(TRUE), - mBlocked(FALSE), - mPingTime(0.0), - mLastPingSendTime(0.0), - mLastPingReceivedTime(0.0), - mNextPingSendTime(0.0), - mPingsInTransit(0), - mLastPingID(0), - mPingDelay(INITIAL_PING_VALUE_MSEC), - mPingDelayAveraged(INITIAL_PING_VALUE_MSEC), - mUnackedPacketCount(0), - mUnackedPacketBytes(0), - mLastPacketInTime(0.0), - mLocalEndPointID(), - mPacketsOut(0), - mPacketsIn(0), - mPacketsLost(0), - mBytesIn(0), - mBytesOut(0), - mLastPeriodLength(-1.f), - mBytesInLastPeriod(0), - mBytesOutLastPeriod(0), - mBytesInThisPeriod(0), - mBytesOutThisPeriod(0), - mPeakBPSIn(0.f), - mPeakBPSOut(0.f), - mPeriodTime(0.0), - mExistenceTimer(), - mAckCreationTime(0.f), - mCurrentResendCount(0), - mLastPacketGap(0), - mHeartbeatInterval(circuit_heartbeat_interval), - mHeartbeatTimeout(circuit_timeout) -{ - // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been - // running a message system loop. - F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(TRUE); - F32 distribution_offset = ll_frand(); - - mPingTime = mt_sec; - mLastPingSendTime = mt_sec + mHeartbeatInterval * distribution_offset; - mLastPingReceivedTime = mt_sec; - mNextPingSendTime = mLastPingSendTime + 0.95*mHeartbeatInterval + F32Seconds(ll_frand(0.1f*mHeartbeatInterval.value())); - mPeriodTime = mt_sec; - - mLocalEndPointID.generate(); -} - - -LLCircuitData::~LLCircuitData() -{ - LLReliablePacket *packetp = NULL; - - // Clean up all pending transfers. - gTransferManager.cleanupConnection(mHost); - - // remove all pending reliable messages on this circuit - std::vector<TPACKETID> doomed; - reliable_iter iter; - reliable_iter end = mUnackedPackets.end(); - for(iter = mUnackedPackets.begin(); iter != end; ++iter) - { - packetp = iter->second; - gMessageSystem->mFailedResendPackets++; - if(gMessageSystem->mVerboseLog) - { - doomed.push_back(packetp->mPacketID); - } - if (packetp->mCallback) - { - packetp->mCallback(packetp->mCallbackData,LL_ERR_CIRCUIT_GONE); - } - - // Update stats - mUnackedPacketCount--; - mUnackedPacketBytes -= packetp->mBufferLength; - - delete packetp; - } - - // remove all pending final retry reliable messages on this circuit - end = mFinalRetryPackets.end(); - for(iter = mFinalRetryPackets.begin(); iter != end; ++iter) - { - packetp = iter->second; - gMessageSystem->mFailedResendPackets++; - if(gMessageSystem->mVerboseLog) - { - doomed.push_back(packetp->mPacketID); - } - if (packetp->mCallback) - { - packetp->mCallback(packetp->mCallbackData,LL_ERR_CIRCUIT_GONE); - } - - // Update stats - mUnackedPacketCount--; - mUnackedPacketBytes -= packetp->mBufferLength; - - delete packetp; - } - - // log aborted reliable packets for this circuit. - if(gMessageSystem->mVerboseLog && !doomed.empty()) - { - std::ostringstream str; - std::ostream_iterator<TPACKETID> append(str, " "); - str << "MSG: -> " << mHost << "\tABORTING RELIABLE:\t"; - std::copy(doomed.begin(), doomed.end(), append); - LL_INFOS() << str.str() << LL_ENDL; - } -} - - -void LLCircuitData::ackReliablePacket(TPACKETID packet_num) -{ - reliable_iter iter; - LLReliablePacket *packetp; - - iter = mUnackedPackets.find(packet_num); - if (iter != mUnackedPackets.end()) - { - packetp = iter->second; - - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << packetp->mHost << "\tRELIABLE ACKED:\t" - << packetp->mPacketID; - LL_INFOS() << str.str() << LL_ENDL; - } - if (packetp->mCallback) - { - if (packetp->mTimeout < F32Seconds(0.f)) // negative timeout will always return timeout even for successful ack, for debugging - { - packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT); - } - else - { - packetp->mCallback(packetp->mCallbackData,LL_ERR_NOERR); - } - } - - // Update stats - mUnackedPacketCount--; - mUnackedPacketBytes -= packetp->mBufferLength; - - // Cleanup - delete packetp; - mUnackedPackets.erase(iter); - return; - } - - iter = mFinalRetryPackets.find(packet_num); - if (iter != mFinalRetryPackets.end()) - { - packetp = iter->second; - // LL_INFOS() << "Packet " << packet_num << " removed from the pending list" << LL_ENDL; - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << packetp->mHost << "\tRELIABLE ACKED:\t" - << packetp->mPacketID; - LL_INFOS() << str.str() << LL_ENDL; - } - if (packetp->mCallback) - { - if (packetp->mTimeout < F32Seconds(0.f)) // negative timeout will always return timeout even for successful ack, for debugging - { - packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT); - } - else - { - packetp->mCallback(packetp->mCallbackData,LL_ERR_NOERR); - } - } - - // Update stats - mUnackedPacketCount--; - mUnackedPacketBytes -= packetp->mBufferLength; - - // Cleanup - delete packetp; - mFinalRetryPackets.erase(iter); - } - else - { - // Couldn't find this packet on either of the unacked lists. - // maybe it's a duplicate ack? - } -} - - - -S32 LLCircuitData::resendUnackedPackets(const F64Seconds now) -{ - LLReliablePacket *packetp; - - - // - // Theoretically we should search through the list for the packet with the oldest - // packet ID, as otherwise when we WRAP we will resend reliable packets out of order. - // Since resends are ALREADY out of order, and wrapping is highly rare (16+million packets), - // I'm not going to worry about this for now - djs - // - - reliable_iter iter; - BOOL have_resend_overflow = FALSE; - for (iter = mUnackedPackets.begin(); iter != mUnackedPackets.end();) - { - packetp = iter->second; - - // Only check overflow if we haven't had one yet. - if (!have_resend_overflow) - { - have_resend_overflow = mThrottles.checkOverflow(TC_RESEND, 0); - } - - if (have_resend_overflow) - { - // We've exceeded our bandwidth for resends. - // Time to stop trying to send them. - - // If we have too many unacked packets, we need to start dropping expired ones. - if (mUnackedPacketBytes > 512000) - { - if (now > packetp->mExpirationTime) - { - // This circuit has overflowed. Do not retry. Do not pass go. - packetp->mRetries = 0; - // Remove it from this list and add it to the final list. - mUnackedPackets.erase(iter++); - mFinalRetryPackets[packetp->mPacketID] = packetp; - } - else - { - ++iter; - } - // Move on to the next unacked packet. - continue; - } - - if (mUnackedPacketBytes > 256000 && !(getPacketsOut() % 1024)) - { - // Warn if we've got a lot of resends waiting. - LL_WARNS() << mHost << " has " << mUnackedPacketBytes - << " bytes of reliable messages waiting" << LL_ENDL; - } - // Stop resending. There are less than 512000 unacked packets. - break; - } - - if (now > packetp->mExpirationTime) - { - packetp->mRetries--; - - // retry - mCurrentResendCount++; - - gMessageSystem->mResentPackets++; - - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: -> " << packetp->mHost - << "\tRESENDING RELIABLE:\t" << packetp->mPacketID; - LL_INFOS() << str.str() << LL_ENDL; - } - - packetp->mBuffer[0] |= LL_RESENT_FLAG; // tag packet id as being a resend - - gMessageSystem->mPacketRing.sendPacket(packetp->mSocket, - (char *)packetp->mBuffer, packetp->mBufferLength, - packetp->mHost); - - mThrottles.throttleOverflow(TC_RESEND, packetp->mBufferLength * 8.f); - - // The new method, retry time based on ping - if (packetp->mPingBasedRetry) - { - packetp->mExpirationTime = now + llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * getPingDelayAveraged())); - } - else - { - // custom, constant retry time - packetp->mExpirationTime = now + packetp->mTimeout; - } - - if (!packetp->mRetries) - { - // Last resend, remove it from this list and add it to the final list. - mUnackedPackets.erase(iter++); - mFinalRetryPackets[packetp->mPacketID] = packetp; - } - else - { - // Don't remove it yet, it still gets to try to resend at least once. - ++iter; - } - } - else - { - // Don't need to do anything with this packet, keep iterating. - ++iter; - } - } - - - for (iter = mFinalRetryPackets.begin(); iter != mFinalRetryPackets.end();) - { - packetp = iter->second; - if (now > packetp->mExpirationTime) - { - // fail (too many retries) - //LL_INFOS() << "Packet " << packetp->mPacketID << " removed from the pending list: exceeded retry limit" << LL_ENDL; - //if (packetp->mMessageName) - //{ - // LL_INFOS() << "Packet name " << packetp->mMessageName << LL_ENDL; - //} - gMessageSystem->mFailedResendPackets++; - - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: -> " << packetp->mHost << "\tABORTING RELIABLE:\t" - << packetp->mPacketID; - LL_INFOS() << str.str() << LL_ENDL; - } - - if (packetp->mCallback) - { - packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT); - } - - // Update stats - mUnackedPacketCount--; - mUnackedPacketBytes -= packetp->mBufferLength; - - mFinalRetryPackets.erase(iter++); - delete packetp; - } - else - { - ++iter; - } - } - - return mUnackedPacketCount; -} - - -LLCircuit::LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout) -: mLastCircuit(NULL), - mHeartbeatInterval(circuit_heartbeat_interval), - mHeartbeatTimeout(circuit_timeout) -{} - -LLCircuit::~LLCircuit() -{ - // delete pointers in the map. - std::for_each(mCircuitData.begin(), - mCircuitData.end(), - llcompose1( - DeletePointerFunctor<LLCircuitData>(), - llselect2nd<circuit_data_map::value_type>())); -} - -LLCircuitData *LLCircuit::addCircuitData(const LLHost &host, TPACKETID in_id) -{ - // This should really validate if one already exists - LL_INFOS() << "LLCircuit::addCircuitData for " << host << LL_ENDL; - LLCircuitData *tempp = new LLCircuitData(host, in_id, mHeartbeatInterval, mHeartbeatTimeout); - mCircuitData.insert(circuit_data_map::value_type(host, tempp)); - mPingSet.insert(tempp); - - mLastCircuit = tempp; - return tempp; -} - -void LLCircuit::removeCircuitData(const LLHost &host) -{ - LL_INFOS() << "LLCircuit::removeCircuitData for " << host << LL_ENDL; - mLastCircuit = NULL; - circuit_data_map::iterator it = mCircuitData.find(host); - if(it != mCircuitData.end()) - { - LLCircuitData *cdp = it->second; - mCircuitData.erase(it); - - LLCircuit::ping_set_t::iterator psit = mPingSet.find(cdp); - if (psit != mPingSet.end()) - { - mPingSet.erase(psit); - } - else - { - LL_WARNS() << "Couldn't find entry for next ping in ping set!" << LL_ENDL; - } - - // Clean up from optimization maps - mUnackedCircuitMap.erase(host); - mSendAckMap.erase(host); - delete cdp; - } - - // This also has to happen AFTER we nuke the circuit, because various - // callbacks for the circuit may result in messages being sent to - // this circuit, and the setting of mLastCircuit. We don't check - // if the host matches, but we don't really care because mLastCircuit - // is an optimization, and this happens VERY rarely. - mLastCircuit = NULL; -} - -void LLCircuitData::setAlive(BOOL b_alive) -{ - if (mbAlive != b_alive) - { - mPacketsOutID = 0; - mPacketsInID = 0; - mbAlive = b_alive; - } - if (b_alive) - { - mLastPingReceivedTime = LLMessageSystem::getMessageTimeSeconds(); - mPingsInTransit = 0; - mBlocked = FALSE; - } -} - - -void LLCircuitData::setAllowTimeout(BOOL allow) -{ - mbAllowTimeout = allow; - - if (allow) - { - // resuming circuit - // make sure it's alive - setAlive(TRUE); - } -} - - -// Reset per-period counters if necessary. -void LLCircuitData::checkPeriodTime() -{ - F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); - F64Seconds period_length = mt_sec - mPeriodTime; - if ( period_length > TARGET_PERIOD_LENGTH) - { - F32 bps_in = F32Bits(mBytesInThisPeriod).value() / period_length.value(); - if (bps_in > mPeakBPSIn) - { - mPeakBPSIn = bps_in; - } - - F32 bps_out = F32Bits(mBytesOutThisPeriod).value() / period_length.value(); - if (bps_out > mPeakBPSOut) - { - mPeakBPSOut = bps_out; - } - - mBytesInLastPeriod = mBytesInThisPeriod; - mBytesOutLastPeriod = mBytesOutThisPeriod; - mBytesInThisPeriod = S32Bytes(0); - mBytesOutThisPeriod = S32Bytes(0); - mLastPeriodLength = F32Seconds::convert(period_length); - - mPeriodTime = mt_sec; - } -} - - -void LLCircuitData::addBytesIn(S32Bytes bytes) -{ - mBytesIn += bytes; - mBytesInThisPeriod += bytes; -} - - -void LLCircuitData::addBytesOut(S32Bytes bytes) -{ - mBytesOut += bytes; - mBytesOutThisPeriod += bytes; -} - - -void LLCircuitData::addReliablePacket(S32 mSocket, U8 *buf_ptr, S32 buf_len, LLReliablePacketParams *params) -{ - LLReliablePacket *packet_info; - - packet_info = new LLReliablePacket(mSocket, buf_ptr, buf_len, params); - - mUnackedPacketCount++; - mUnackedPacketBytes += packet_info->mBufferLength; - - if (params && params->mRetries) - { - mUnackedPackets[packet_info->mPacketID] = packet_info; - } - else - { - mFinalRetryPackets[packet_info->mPacketID] = packet_info; - } -} - - -void LLCircuit::resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size) -{ - F64Seconds now = LLMessageSystem::getMessageTimeSeconds(); - unacked_list_length = 0; - unacked_list_size = 0; - - LLCircuitData* circ; - circuit_data_map::iterator end = mUnackedCircuitMap.end(); - for(circuit_data_map::iterator it = mUnackedCircuitMap.begin(); it != end; ++it) - { - circ = (*it).second; - unacked_list_length += circ->resendUnackedPackets(now); - unacked_list_size += circ->getUnackedPacketBytes(); - } -} - - -BOOL LLCircuitData::isDuplicateResend(TPACKETID packetnum) -{ - return (mRecentlyReceivedReliablePackets.find(packetnum) != mRecentlyReceivedReliablePackets.end()); -} - - -void LLCircuit::dumpResends() -{ - circuit_data_map::iterator end = mCircuitData.end(); - for(circuit_data_map::iterator it = mCircuitData.begin(); it != end; ++it) - { - (*it).second->dumpResendCountAndReset(); - } -} - -LLCircuitData* LLCircuit::findCircuit(const LLHost& host) const -{ - // An optimization on finding the previously found circuit. - if (mLastCircuit && (mLastCircuit->mHost == host)) - { - return mLastCircuit; - } - - circuit_data_map::const_iterator it = mCircuitData.find(host); - if(it == mCircuitData.end()) - { - return NULL; - } - mLastCircuit = it->second; - return mLastCircuit; -} - - -BOOL LLCircuit::isCircuitAlive(const LLHost& host) const -{ - LLCircuitData *cdp = findCircuit(host); - if(cdp) - { - return cdp->mbAlive; - } - - return FALSE; -} - -void LLCircuitData::setTimeoutCallback(void (*callback_func)(const LLHost &host, void *user_data), void *user_data) -{ - mTimeoutCallback = callback_func; - mTimeoutUserData = user_data; -} - -void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) -{ - // Done as floats so we don't have to worry about running out of room - // with U32 getting poked into an S32. - F32 delta = (F32)mHighestPacketID - (F32)id; - if (delta > (0.5f*LL_MAX_OUT_PACKET_ID)) - { - // We've almost definitely wrapped, reset the mLastPacketID to be low again. - mHighestPacketID = id; - } - else if (delta < (-0.5f*LL_MAX_OUT_PACKET_ID)) - { - // This is almost definitely an old packet coming in after a wrap, ignore it. - } - else - { - mHighestPacketID = llmax(mHighestPacketID, id); - } - - // Save packet arrival time - mLastPacketInTime = LLMessageSystem::getMessageTimeSeconds(); - - // Have we received anything on this circuit yet? - if (0 == mPacketsIn) - { - // Must be first packet from unclosed circuit. - mPacketsIn++; - setPacketInID((id + 1) % LL_MAX_OUT_PACKET_ID); - - mLastPacketGap = 0; - return; - } - - mPacketsIn++; - - - // now, check to see if we've got a gap - U32 gap = 0; - if (mPacketsInID == id) - { - // nope! bump and wrap the counter, then return - mPacketsInID++; - mPacketsInID = (mPacketsInID) % LL_MAX_OUT_PACKET_ID; - } - else if (id < mWrapID) - { - // id < mWrapID will happen if the first few packets are out of order. . . - // at that point we haven't marked anything "potentially lost" and - // the out-of-order packet will cause a full wrap marking all the IDs "potentially lost" - - // do nothing - } - else - { - // we have a gap! if that id is in the map, remove it from the map, leave mCurrentCircuit->mPacketsInID - // alone - // otherwise, walk from mCurrentCircuit->mPacketsInID to id with wrapping, adding the values to the map - // and setting mPacketsInID to id + 1 % LL_MAX_OUT_PACKET_ID - - // babbage: all operands in expression are unsigned, so modular - // arithmetic will always find correct gap, regardless of wrap arounds. - const U8 width = 24; - gap = LLModularMath::subtract<width>(mPacketsInID, id); - - if (mPotentialLostPackets.find(id) != mPotentialLostPackets.end()) - { - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << mHost << "\tRECOVERING LOST:\t" << id; - LL_INFOS() << str.str() << LL_ENDL; - } - // LL_INFOS() << "removing potential lost: " << id << LL_ENDL; - mPotentialLostPackets.erase(id); - } - else if (!receive_resent) // don't freak out over out-of-order reliable resends - { - U64Microseconds time = LLMessageSystem::getMessageTimeUsecs(); - TPACKETID index = mPacketsInID; - S32 gap_count = 0; - if ((index < id) && ((id - index) < 16)) - { - while (index != id) - { - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << mHost << "\tPACKET GAP:\t" - << index; - LL_INFOS() << str.str() << LL_ENDL; - } - -// LL_INFOS() << "adding potential lost: " << index << LL_ENDL; - mPotentialLostPackets[index] = time; - index++; - index = index % LL_MAX_OUT_PACKET_ID; - gap_count++; - } - } - else - { - LL_INFOS() << "packet_out_of_order - got packet " << id << " expecting " << index << " from " << mHost << LL_ENDL; - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << mHost << "\tPACKET GAP:\t" - << id << " expected " << index; - LL_INFOS() << str.str() << LL_ENDL; - } - } - - mPacketsInID = id + 1; - mPacketsInID = (mPacketsInID) % LL_MAX_OUT_PACKET_ID; - - if (gap_count > 128) - { - LL_WARNS() << "Packet loss gap filler running amok!" << LL_ENDL; - } - else if (gap_count > 16) - { - LL_WARNS() << "Sustaining large amounts of packet loss!" << LL_ENDL; - } - - } - } - mLastPacketGap = gap; -} - - -void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys) -{ - F64Seconds cur_time = LLMessageSystem::getMessageTimeSeconds(); - S32 count = mPingSet.size(); - S32 cur = 0; - - // Only process each circuit once at most, stop processing if no circuits - while((cur < count) && !mPingSet.empty()) - { - cur++; - - LLCircuit::ping_set_t::iterator psit = mPingSet.begin(); - LLCircuitData *cdp = *psit; - - if (!cdp->mbAlive) - { - // We suspect that this case should never happen, given how - // the alive status is set. - // Skip over dead circuits, just add the ping interval and push it to the back - // Always remember to remove it from the set before changing the sorting - // key (mNextPingSendTime) - mPingSet.erase(psit); - cdp->mNextPingSendTime = cur_time + mHeartbeatInterval; - mPingSet.insert(cdp); - continue; - } - else - { - // Check to see if this needs a ping - if (cur_time < cdp->mNextPingSendTime) - { - // This circuit doesn't need a ping, break out because - // we have a sorted list, thus no more circuits need pings - break; - } - - // Update watchdog timers - if (cdp->updateWatchDogTimers(msgsys)) - { - // Randomize our pings a bit by doing some up to 5% early or late - F64Seconds dt = 0.95f*mHeartbeatInterval + F32Seconds(ll_frand(0.1f*mHeartbeatInterval.value())); - - // Remove it, and reinsert it with the new next ping time. - // Always remove before changing the sorting key. - mPingSet.erase(psit); - cdp->mNextPingSendTime = cur_time + dt; - mPingSet.insert(cdp); - - // Update our throttles - cdp->mThrottles.dynamicAdjust(); - - // Update some stats, this is not terribly important - cdp->checkPeriodTime(); - } - else - { - // This mPingSet.erase isn't necessary, because removing the circuit will - // remove the ping set. - //mPingSet.erase(psit); - removeCircuitData(cdp->mHost); - } - } - } -} - - -BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) -{ - F64Seconds cur_time = LLMessageSystem::getMessageTimeSeconds(); - mLastPingSendTime = cur_time; - - if (!checkCircuitTimeout()) - { - // Pass this back to the calling LLCircuit, this circuit needs to be cleaned up. - return FALSE; - } - - // WARNING! - // Duplicate suppression can FAIL if packets are delivered out of - // order, although it's EXTREMELY unlikely. It would require - // that the ping get delivered out of order enough that the ACK - // for the packet that it was out of order with was received BEFORE - // the ping was sent. - - // Find the current oldest reliable packetID - // This is to handle the case if we actually manage to wrap our - // packet IDs - the oldest will actually have a higher packet ID - // than the current. - BOOL wrapped = FALSE; - reliable_iter iter; - iter = mUnackedPackets.upper_bound(getPacketOutID()); - if (iter == mUnackedPackets.end()) - { - // Nothing AFTER this one, so we want the lowest packet ID - // then. - iter = mUnackedPackets.begin(); - wrapped = TRUE; - } - - TPACKETID packet_id = 0; - - // Check against the "final" packets - BOOL wrapped_final = FALSE; - reliable_iter iter_final; - iter_final = mFinalRetryPackets.upper_bound(getPacketOutID()); - if (iter_final == mFinalRetryPackets.end()) - { - iter_final = mFinalRetryPackets.begin(); - wrapped_final = TRUE; - } - - //LL_INFOS() << mHost << " - unacked count " << mUnackedPackets.size() << LL_ENDL; - //LL_INFOS() << mHost << " - final count " << mFinalRetryPackets.size() << LL_ENDL; - if (wrapped != wrapped_final) - { - // One of the "unacked" or "final" lists hasn't wrapped. Whichever one - // hasn't has the oldest packet. - if (!wrapped) - { - // Hasn't wrapped, so the one on the - // unacked packet list is older - packet_id = iter->first; - //LL_INFOS() << mHost << ": nowrapped unacked" << LL_ENDL; - } - else - { - packet_id = iter_final->first; - //LL_INFOS() << mHost << ": nowrapped final" << LL_ENDL; - } - } - else - { - // They both wrapped, we can just use the minimum of the two. - if ((iter == mUnackedPackets.end()) && (iter_final == mFinalRetryPackets.end())) - { - // Wow! No unacked packets at all! - // Send the ID of the last packet we sent out. - // This will flush all of the destination's - // unacked packets, theoretically. - //LL_INFOS() << mHost << ": No unacked!" << LL_ENDL; - packet_id = getPacketOutID(); - } - else - { - BOOL had_unacked = FALSE; - if (iter != mUnackedPackets.end()) - { - // Unacked list has the lowest so far - packet_id = iter->first; - had_unacked = TRUE; - //LL_INFOS() << mHost << ": Unacked" << LL_ENDL; - } - - if (iter_final != mFinalRetryPackets.end()) - { - // Use the lowest of the unacked list and the final list - if (had_unacked) - { - // Both had a packet, use the lowest. - packet_id = llmin(packet_id, iter_final->first); - //LL_INFOS() << mHost << ": Min of unacked/final" << LL_ENDL; - } - else - { - // Only the final had a packet, use it. - packet_id = iter_final->first; - //LL_INFOS() << mHost << ": Final!" << LL_ENDL; - } - } - } - } - - // Send off the another ping. - pingTimerStart(); - msgsys->newMessageFast(_PREHASH_StartPingCheck); - msgsys->nextBlock(_PREHASH_PingID); - msgsys->addU8Fast(_PREHASH_PingID, nextPingID()); - msgsys->addU32Fast(_PREHASH_OldestUnacked, packet_id); - msgsys->sendMessage(mHost); - - // Also do lost packet accounting. - // Check to see if anything on our lost list is old enough to - // be considered lost - - LLCircuitData::packet_time_map::iterator it; - U64Microseconds timeout = llmin(LL_MAX_LOST_TIMEOUT, F32Seconds(getPingDelayAveraged()) * LL_LOST_TIMEOUT_FACTOR); - - U64Microseconds mt_usec = LLMessageSystem::getMessageTimeUsecs(); - for (it = mPotentialLostPackets.begin(); it != mPotentialLostPackets.end(); ) - { - U64Microseconds delta_t_usec = mt_usec - (*it).second; - if (delta_t_usec > timeout) - { - // let's call this one a loss! - mPacketsLost++; - gMessageSystem->mDroppedPackets++; - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << mHost << "\tLOST PACKET:\t" - << (*it).first; - LL_INFOS() << str.str() << LL_ENDL; - } - mPotentialLostPackets.erase(it++); - } - else - { - ++it; - } - } - - return TRUE; -} - - -void LLCircuitData::clearDuplicateList(TPACKETID oldest_id) -{ - // purge old data from the duplicate suppression queue - - // we want to KEEP all x where oldest_id <= x <= last incoming packet, and delete everything else. - - //LL_INFOS() << mHost << ": clearing before oldest " << oldest_id << LL_ENDL; - //LL_INFOS() << "Recent list before: " << mRecentlyReceivedReliablePackets.size() << LL_ENDL; - if (oldest_id < mHighestPacketID) - { - // Clean up everything with a packet ID less than oldest_id. - packet_time_map::iterator pit_start; - packet_time_map::iterator pit_end; - pit_start = mRecentlyReceivedReliablePackets.begin(); - pit_end = mRecentlyReceivedReliablePackets.lower_bound(oldest_id); - mRecentlyReceivedReliablePackets.erase(pit_start, pit_end); - } - - // Do timeout checks on everything with an ID > mHighestPacketID. - // This should be empty except for wrapping IDs. Thus, this should be - // highly rare. - U64Microseconds mt_usec = LLMessageSystem::getMessageTimeUsecs(); - - packet_time_map::iterator pit; - for(pit = mRecentlyReceivedReliablePackets.upper_bound(mHighestPacketID); - pit != mRecentlyReceivedReliablePackets.end(); ) - { - // Validate that the packet ID seems far enough away - if ((pit->first - mHighestPacketID) < 100) - { - LL_WARNS() << "Probably incorrectly timing out non-wrapped packets!" << LL_ENDL; - } - U64Microseconds delta_t_usec = mt_usec - (*pit).second; - F64Seconds delta_t_sec = delta_t_usec; - if (delta_t_sec > LL_DUPLICATE_SUPPRESSION_TIMEOUT) - { - // enough time has elapsed we're not likely to get a duplicate on this one - LL_INFOS() << "Clearing " << pit->first << " from recent list" << LL_ENDL; - mRecentlyReceivedReliablePackets.erase(pit++); - } - else - { - ++pit; - } - } - //LL_INFOS() << "Recent list after: " << mRecentlyReceivedReliablePackets.size() << LL_ENDL; -} - -BOOL LLCircuitData::checkCircuitTimeout() -{ - F64Seconds time_since_last_ping = LLMessageSystem::getMessageTimeSeconds() - mLastPingReceivedTime; - - // Nota Bene: This needs to be turned off if you are debugging multiple simulators - if (time_since_last_ping > mHeartbeatTimeout) - { - LL_WARNS() << "LLCircuitData::checkCircuitTimeout for " << mHost << " last ping " << time_since_last_ping << " seconds ago." <<LL_ENDL; - setAlive(FALSE); - if (mTimeoutCallback) - { - LL_WARNS() << "LLCircuitData::checkCircuitTimeout for " << mHost << " calling callback." << LL_ENDL; - mTimeoutCallback(mHost, mTimeoutUserData); - } - if (!isAlive()) - { - // The callback didn't try and resurrect the circuit. We should kill it. - LL_WARNS() << "LLCircuitData::checkCircuitTimeout for " << mHost << " still dead, dropping." << LL_ENDL; - return FALSE; - } - } - - return TRUE; -} - -// Call this method when a reliable message comes in - this will -// correctly place the packet in the correct list to be acked later. -BOOL LLCircuitData::collectRAck(TPACKETID packet_num) -{ - if (mAcks.empty()) - { - // First extra ack, we need to add ourselves to the list of circuits that need to send acks - gMessageSystem->mCircuitInfo.mSendAckMap[mHost] = this; - } - - mAcks.push_back(packet_num); - if (mAckCreationTime == 0) - { - mAckCreationTime = getAgeInSeconds(); - } - return TRUE; -} - -// this method is called during the message system processAcks() to -// send out any acks that did not get sent already. -void LLCircuit::sendAcks(F32 collect_time) -{ - collect_time = llclamp(collect_time, 0.f, LL_COLLECT_ACK_TIME_MAX); - LLCircuitData* cd; - circuit_data_map::iterator it = mSendAckMap.begin(); - while (it != mSendAckMap.end()) - { - circuit_data_map::iterator cur_it = it++; - cd = (*cur_it).second; - S32 count = (S32)cd->mAcks.size(); - F32 age = cd->getAgeInSeconds() - cd->mAckCreationTime; - if (age > collect_time || count == 0) - { - if (count>0) - { - // send the packet acks - S32 acks_this_packet = 0; - for(S32 i = 0; i < count; ++i) - { - if(acks_this_packet == 0) - { - gMessageSystem->newMessageFast(_PREHASH_PacketAck); - } - gMessageSystem->nextBlockFast(_PREHASH_Packets); - gMessageSystem->addU32Fast(_PREHASH_ID, cd->mAcks[i]); - ++acks_this_packet; - if(acks_this_packet > 250) - { - gMessageSystem->sendMessage(cd->mHost); - acks_this_packet = 0; - } - } - if(acks_this_packet > 0) - { - gMessageSystem->sendMessage(cd->mHost); - } - - if(gMessageSystem->mVerboseLog) - { - std::ostringstream str; - str << "MSG: -> " << cd->mHost << "\tPACKET ACKS:\t"; - std::ostream_iterator<TPACKETID> append(str, " "); - std::copy(cd->mAcks.begin(), cd->mAcks.end(), append); - LL_INFOS() << str.str() << LL_ENDL; - } - - // empty out the acks list - cd->mAcks.clear(); - cd->mAckCreationTime = 0.f; - } - // remove data map - mSendAckMap.erase(cur_it); - } - } -} - - -std::ostream& operator<<(std::ostream& s, LLCircuitData& circuit) -{ - F32 age = circuit.mExistenceTimer.getElapsedTimeF32(); - - using namespace std; - s << "Circuit " << circuit.mHost << " " - << circuit.mRemoteID << " " - << (circuit.mbAlive ? "Alive" : "Not Alive") << " " - << (circuit.mbAllowTimeout ? "Timeout Allowed" : "Timeout Not Allowed") - << endl; - - s << " Packets Lost: " << circuit.mPacketsLost - << " Measured Ping: " << circuit.mPingDelay - << " Averaged Ping: " << circuit.mPingDelayAveraged - << endl; - - s << "Global In/Out " << S32(age) << " sec" - << " KBytes: " << circuit.mBytesIn.valueInUnits<LLUnits::Kilobytes>() << "/" << circuit.mBytesOut.valueInUnits<LLUnits::Kilobytes>() - << " Kbps: " - << S32(circuit.mBytesIn.valueInUnits<LLUnits::Kilobits>() / circuit.mExistenceTimer.getElapsedTimeF32().value()) - << "/" - << S32(circuit.mBytesOut.valueInUnits<LLUnits::Kilobits>() / circuit.mExistenceTimer.getElapsedTimeF32().value()) - << " Packets: " << circuit.mPacketsIn << "/" << circuit.mPacketsOut - << endl; - - s << "Recent In/Out " << circuit.mLastPeriodLength - << " KBytes: " - << circuit.mBytesInLastPeriod.valueInUnits<LLUnits::Kilobytes>() - << "/" - << circuit.mBytesOutLastPeriod.valueInUnits<LLUnits::Kilobytes>() - << " Kbps: " - << (S32)(circuit.mBytesInLastPeriod.valueInUnits<LLUnits::Kilobits>() / circuit.mLastPeriodLength.value()) - << "/" - << (S32)(circuit.mBytesOutLastPeriod.valueInUnits<LLUnits::Kilobits>() / circuit.mLastPeriodLength.value()) - << " Peak kbps: " - << S32(circuit.mPeakBPSIn / 1024.f) - << "/" - << S32(circuit.mPeakBPSOut / 1024.f) - << endl; - - return s; -} - -void LLCircuitData::getInfo(LLSD& info) const -{ - info["Host"] = mHost.getIPandPort(); - info["Alive"] = mbAlive; - info["Age"] = mExistenceTimer.getElapsedTimeF32(); -} - -void LLCircuitData::dumpResendCountAndReset() -{ - if (mCurrentResendCount) - { - LL_INFOS() << "Circuit: " << mHost << " resent " << mCurrentResendCount << " packets" << LL_ENDL; - mCurrentResendCount = 0; - } -} - -std::ostream& operator<<(std::ostream& s, LLCircuit &circuit) -{ - s << "Circuit Info:" << std::endl; - LLCircuit::circuit_data_map::iterator end = circuit.mCircuitData.end(); - LLCircuit::circuit_data_map::iterator it; - for(it = circuit.mCircuitData.begin(); it != end; ++it) - { - s << *((*it).second) << std::endl; - } - return s; -} - -void LLCircuit::getInfo(LLSD& info) const -{ - LLCircuit::circuit_data_map::const_iterator end = mCircuitData.end(); - LLCircuit::circuit_data_map::const_iterator it; - LLSD circuit_info; - for(it = mCircuitData.begin(); it != end; ++it) - { - (*it).second->getInfo(circuit_info); - info["Circuits"].append(circuit_info); - } -} - -void LLCircuit::getCircuitRange( - const LLHost& key, - LLCircuit::circuit_data_map::iterator& first, - LLCircuit::circuit_data_map::iterator& end) -{ - end = mCircuitData.end(); - first = mCircuitData.upper_bound(key); -} - -TPACKETID LLCircuitData::nextPacketOutID() -{ - mPacketsOut++; - - TPACKETID id; - - id = (mPacketsOutID + 1) % LL_MAX_OUT_PACKET_ID; - - if (id < mPacketsOutID) - { - // we just wrapped on a circuit, reset the wrap ID to zero - mWrapID = 0; - } - mPacketsOutID = id; - return id; -} - - -void LLCircuitData::setPacketInID(TPACKETID id) -{ - id = id % LL_MAX_OUT_PACKET_ID; - mPacketsInID = id; - mRecentlyReceivedReliablePackets.clear(); - - mWrapID = id; -} - - -void LLCircuitData::pingTimerStop(const U8 ping_id) -{ - F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); - - // Nota Bene: no averaging of ping times until we get a feel for how this works - F64Seconds time = mt_secs - mPingTime; - if (time == F32Seconds(0.0)) - { - // Ack, we got our ping response on the same frame! Sigh, let's get a real time otherwise - // all of our ping calculations will be skewed. - mt_secs = LLMessageSystem::getMessageTimeSeconds(TRUE); - } - mLastPingReceivedTime = mt_secs; - - // If ping is longer than 1 second, we'll get sequence deltas in the ping. - // Approximate by assuming each ping counts for 1 second (slightly low, probably) - S32 delta_ping = (S32)mLastPingID - (S32) ping_id; - if (delta_ping < 0) - { - delta_ping += 256; - } - - U32Milliseconds msec = delta_ping*mHeartbeatInterval + time; - setPingDelay(msec); - - mPingsInTransit = delta_ping; - if (mBlocked && (mPingsInTransit <= PING_RELEASE_BLOCK)) - { - mBlocked = FALSE; - } -} - - -void LLCircuitData::pingTimerStart() -{ - mPingTime = LLMessageSystem::getMessageTimeSeconds(); - mPingsInTransit++; - - if (!mBlocked && (mPingsInTransit > PING_START_BLOCK)) - { - mBlocked = TRUE; - } -} - - -U32 LLCircuitData::getPacketsIn() const -{ - return mPacketsIn; -} - - -S32Bytes LLCircuitData::getBytesIn() const -{ - return mBytesIn; -} - - -S32Bytes LLCircuitData::getBytesOut() const -{ - return mBytesOut; -} - - -U32 LLCircuitData::getPacketsOut() const -{ - return mPacketsOut; -} - - -TPACKETID LLCircuitData::getPacketOutID() const -{ - return mPacketsOutID; -} - - -U32 LLCircuitData::getPacketsLost() const -{ - return mPacketsLost; -} - - -BOOL LLCircuitData::isAlive() const -{ - return mbAlive; -} - - -BOOL LLCircuitData::isBlocked() const -{ - return mBlocked; -} - - -BOOL LLCircuitData::getAllowTimeout() const -{ - return mbAllowTimeout; -} - - -U32Milliseconds LLCircuitData::getPingDelay() const -{ - return mPingDelay; -} - - -F32Milliseconds LLCircuitData::getPingInTransitTime() -{ - // This may be inaccurate in the case of a circuit that was "dead" and then revived, - // but only until the first round trip ping is sent - djs - F32Milliseconds time_since_ping_was_sent(0); - - if (mPingsInTransit) - { - time_since_ping_was_sent = F32Milliseconds::convert(((mPingsInTransit*mHeartbeatInterval - F32Seconds(1)) - + (LLMessageSystem::getMessageTimeSeconds() - mPingTime))); - } - - return time_since_ping_was_sent; -} - - -void LLCircuitData::setPingDelay(U32Milliseconds ping) -{ - mPingDelay = ping; - mPingDelayAveraged = llmax((F32Milliseconds)ping, getPingDelayAveraged()); - mPingDelayAveraged = ((1.f - LL_AVERAGED_PING_ALPHA) * mPingDelayAveraged) - + (LL_AVERAGED_PING_ALPHA * (F32Milliseconds) ping); - mPingDelayAveraged = llclamp(mPingDelayAveraged, - LL_AVERAGED_PING_MIN, - LL_AVERAGED_PING_MAX); -} - - -F32Milliseconds LLCircuitData::getPingDelayAveraged() -{ - return llmin(llmax(getPingInTransitTime(), mPingDelayAveraged), LL_AVERAGED_PING_MAX); -} - - -BOOL LLCircuitData::getTrusted() const -{ - return mTrusted; -} - - -void LLCircuitData::setTrusted(BOOL t) -{ - mTrusted = t; -} - -F32 LLCircuitData::getAgeInSeconds() const -{ - return mExistenceTimer.getElapsedTimeF32(); -} +/**
+ * @file llcircuit.cpp
+ * @brief Class to track UDP endpoints for the message system.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "linden_common.h"
+
+#if LL_WINDOWS
+
+#include <process.h>
+
+#else
+
+#if LL_LINUX
+#include <dlfcn.h> // RTLD_LAZY
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#endif
+
+
+#if !defined(USE_CIRCUIT_LIST)
+#include <algorithm>
+#endif
+#include <sstream>
+#include <iterator>
+#include <stack>
+
+#include "llcircuit.h"
+
+#include "message.h"
+#include "llrand.h"
+#include "llstl.h"
+#include "lltransfermanager.h"
+#include "llmodularmath.h"
+
+const S32 PING_START_BLOCK = 3; // How many pings behind we have to be to consider ourself blocked.
+const S32 PING_RELEASE_BLOCK = 2; // How many pings behind we have to be to consider ourself unblocked.
+
+const F32Seconds TARGET_PERIOD_LENGTH(5.f);
+const F32Seconds LL_DUPLICATE_SUPPRESSION_TIMEOUT(60.f); //this can be long, as time-based cleanup is
+ // only done when wrapping packetids, now...
+
+LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id,
+ const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout)
+: mHost (host),
+ mWrapID(0),
+ mPacketsOutID(0),
+ mPacketsInID(in_id),
+ mHighestPacketID(in_id),
+ mTimeoutCallback(NULL),
+ mTimeoutUserData(NULL),
+ mTrusted(false),
+ mbAllowTimeout(true),
+ mbAlive(true),
+ mBlocked(false),
+ mPingTime(0.0),
+ mLastPingSendTime(0.0),
+ mLastPingReceivedTime(0.0),
+ mNextPingSendTime(0.0),
+ mPingsInTransit(0),
+ mLastPingID(0),
+ mPingDelay(INITIAL_PING_VALUE_MSEC),
+ mPingDelayAveraged(INITIAL_PING_VALUE_MSEC),
+ mUnackedPacketCount(0),
+ mUnackedPacketBytes(0),
+ mLastPacketInTime(0.0),
+ mLocalEndPointID(),
+ mPacketsOut(0),
+ mPacketsIn(0),
+ mPacketsLost(0),
+ mBytesIn(0),
+ mBytesOut(0),
+ mLastPeriodLength(-1.f),
+ mBytesInLastPeriod(0),
+ mBytesOutLastPeriod(0),
+ mBytesInThisPeriod(0),
+ mBytesOutThisPeriod(0),
+ mPeakBPSIn(0.f),
+ mPeakBPSOut(0.f),
+ mPeriodTime(0.0),
+ mExistenceTimer(),
+ mAckCreationTime(0.f),
+ mCurrentResendCount(0),
+ mLastPacketGap(0),
+ mHeartbeatInterval(circuit_heartbeat_interval),
+ mHeartbeatTimeout(circuit_timeout)
+{
+ // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been
+ // running a message system loop.
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(true);
+ F32 distribution_offset = ll_frand();
+
+ mPingTime = mt_sec;
+ mLastPingSendTime = mt_sec + mHeartbeatInterval * distribution_offset;
+ mLastPingReceivedTime = mt_sec;
+ mNextPingSendTime = mLastPingSendTime + 0.95*mHeartbeatInterval + F32Seconds(ll_frand(0.1f*mHeartbeatInterval.value()));
+ mPeriodTime = mt_sec;
+
+ mLocalEndPointID.generate();
+}
+
+
+LLCircuitData::~LLCircuitData()
+{
+ LLReliablePacket *packetp = NULL;
+
+ // Clean up all pending transfers.
+ gTransferManager.cleanupConnection(mHost);
+
+ // remove all pending reliable messages on this circuit
+ std::vector<TPACKETID> doomed;
+ reliable_iter iter;
+ reliable_iter end = mUnackedPackets.end();
+ for(iter = mUnackedPackets.begin(); iter != end; ++iter)
+ {
+ packetp = iter->second;
+ gMessageSystem->mFailedResendPackets++;
+ if(gMessageSystem->mVerboseLog)
+ {
+ doomed.push_back(packetp->mPacketID);
+ }
+ if (packetp->mCallback)
+ {
+ packetp->mCallback(packetp->mCallbackData,LL_ERR_CIRCUIT_GONE);
+ }
+
+ // Update stats
+ mUnackedPacketCount--;
+ mUnackedPacketBytes -= packetp->mBufferLength;
+
+ delete packetp;
+ }
+
+ // remove all pending final retry reliable messages on this circuit
+ end = mFinalRetryPackets.end();
+ for(iter = mFinalRetryPackets.begin(); iter != end; ++iter)
+ {
+ packetp = iter->second;
+ gMessageSystem->mFailedResendPackets++;
+ if(gMessageSystem->mVerboseLog)
+ {
+ doomed.push_back(packetp->mPacketID);
+ }
+ if (packetp->mCallback)
+ {
+ packetp->mCallback(packetp->mCallbackData,LL_ERR_CIRCUIT_GONE);
+ }
+
+ // Update stats
+ mUnackedPacketCount--;
+ mUnackedPacketBytes -= packetp->mBufferLength;
+
+ delete packetp;
+ }
+
+ // log aborted reliable packets for this circuit.
+ if(gMessageSystem->mVerboseLog && !doomed.empty())
+ {
+ std::ostringstream str;
+ std::ostream_iterator<TPACKETID> append(str, " ");
+ str << "MSG: -> " << mHost << "\tABORTING RELIABLE:\t";
+ std::copy(doomed.begin(), doomed.end(), append);
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+}
+
+
+void LLCircuitData::ackReliablePacket(TPACKETID packet_num)
+{
+ reliable_iter iter;
+ LLReliablePacket *packetp;
+
+ iter = mUnackedPackets.find(packet_num);
+ if (iter != mUnackedPackets.end())
+ {
+ packetp = iter->second;
+
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << packetp->mHost << "\tRELIABLE ACKED:\t"
+ << packetp->mPacketID;
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+ if (packetp->mCallback)
+ {
+ if (packetp->mTimeout < F32Seconds(0.f)) // negative timeout will always return timeout even for successful ack, for debugging
+ {
+ packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT);
+ }
+ else
+ {
+ packetp->mCallback(packetp->mCallbackData,LL_ERR_NOERR);
+ }
+ }
+
+ // Update stats
+ mUnackedPacketCount--;
+ mUnackedPacketBytes -= packetp->mBufferLength;
+
+ // Cleanup
+ delete packetp;
+ mUnackedPackets.erase(iter);
+ return;
+ }
+
+ iter = mFinalRetryPackets.find(packet_num);
+ if (iter != mFinalRetryPackets.end())
+ {
+ packetp = iter->second;
+ // LL_INFOS() << "Packet " << packet_num << " removed from the pending list" << LL_ENDL;
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << packetp->mHost << "\tRELIABLE ACKED:\t"
+ << packetp->mPacketID;
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+ if (packetp->mCallback)
+ {
+ if (packetp->mTimeout < F32Seconds(0.f)) // negative timeout will always return timeout even for successful ack, for debugging
+ {
+ packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT);
+ }
+ else
+ {
+ packetp->mCallback(packetp->mCallbackData,LL_ERR_NOERR);
+ }
+ }
+
+ // Update stats
+ mUnackedPacketCount--;
+ mUnackedPacketBytes -= packetp->mBufferLength;
+
+ // Cleanup
+ delete packetp;
+ mFinalRetryPackets.erase(iter);
+ }
+ else
+ {
+ // Couldn't find this packet on either of the unacked lists.
+ // maybe it's a duplicate ack?
+ }
+}
+
+
+
+S32 LLCircuitData::resendUnackedPackets(const F64Seconds now)
+{
+ LLReliablePacket *packetp;
+
+
+ //
+ // Theoretically we should search through the list for the packet with the oldest
+ // packet ID, as otherwise when we WRAP we will resend reliable packets out of order.
+ // Since resends are ALREADY out of order, and wrapping is highly rare (16+million packets),
+ // I'm not going to worry about this for now - djs
+ //
+
+ reliable_iter iter;
+ bool have_resend_overflow = false;
+ for (iter = mUnackedPackets.begin(); iter != mUnackedPackets.end();)
+ {
+ packetp = iter->second;
+
+ // Only check overflow if we haven't had one yet.
+ if (!have_resend_overflow)
+ {
+ have_resend_overflow = mThrottles.checkOverflow(TC_RESEND, 0);
+ }
+
+ if (have_resend_overflow)
+ {
+ // We've exceeded our bandwidth for resends.
+ // Time to stop trying to send them.
+
+ // If we have too many unacked packets, we need to start dropping expired ones.
+ if (mUnackedPacketBytes > 512000)
+ {
+ if (now > packetp->mExpirationTime)
+ {
+ // This circuit has overflowed. Do not retry. Do not pass go.
+ packetp->mRetries = 0;
+ // Remove it from this list and add it to the final list.
+ mUnackedPackets.erase(iter++);
+ mFinalRetryPackets[packetp->mPacketID] = packetp;
+ }
+ else
+ {
+ ++iter;
+ }
+ // Move on to the next unacked packet.
+ continue;
+ }
+
+ if (mUnackedPacketBytes > 256000 && !(getPacketsOut() % 1024))
+ {
+ // Warn if we've got a lot of resends waiting.
+ LL_WARNS() << mHost << " has " << mUnackedPacketBytes
+ << " bytes of reliable messages waiting" << LL_ENDL;
+ }
+ // Stop resending. There are less than 512000 unacked packets.
+ break;
+ }
+
+ if (now > packetp->mExpirationTime)
+ {
+ packetp->mRetries--;
+
+ // retry
+ mCurrentResendCount++;
+
+ gMessageSystem->mResentPackets++;
+
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: -> " << packetp->mHost
+ << "\tRESENDING RELIABLE:\t" << packetp->mPacketID;
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+
+ packetp->mBuffer[0] |= LL_RESENT_FLAG; // tag packet id as being a resend
+
+ gMessageSystem->mPacketRing.sendPacket(packetp->mSocket,
+ (char *)packetp->mBuffer, packetp->mBufferLength,
+ packetp->mHost);
+
+ mThrottles.throttleOverflow(TC_RESEND, packetp->mBufferLength * 8.f);
+
+ // The new method, retry time based on ping
+ if (packetp->mPingBasedRetry)
+ {
+ packetp->mExpirationTime = now + llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * getPingDelayAveraged()));
+ }
+ else
+ {
+ // custom, constant retry time
+ packetp->mExpirationTime = now + packetp->mTimeout;
+ }
+
+ if (!packetp->mRetries)
+ {
+ // Last resend, remove it from this list and add it to the final list.
+ mUnackedPackets.erase(iter++);
+ mFinalRetryPackets[packetp->mPacketID] = packetp;
+ }
+ else
+ {
+ // Don't remove it yet, it still gets to try to resend at least once.
+ ++iter;
+ }
+ }
+ else
+ {
+ // Don't need to do anything with this packet, keep iterating.
+ ++iter;
+ }
+ }
+
+
+ for (iter = mFinalRetryPackets.begin(); iter != mFinalRetryPackets.end();)
+ {
+ packetp = iter->second;
+ if (now > packetp->mExpirationTime)
+ {
+ // fail (too many retries)
+ //LL_INFOS() << "Packet " << packetp->mPacketID << " removed from the pending list: exceeded retry limit" << LL_ENDL;
+ //if (packetp->mMessageName)
+ //{
+ // LL_INFOS() << "Packet name " << packetp->mMessageName << LL_ENDL;
+ //}
+ gMessageSystem->mFailedResendPackets++;
+
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: -> " << packetp->mHost << "\tABORTING RELIABLE:\t"
+ << packetp->mPacketID;
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+
+ if (packetp->mCallback)
+ {
+ packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT);
+ }
+
+ // Update stats
+ mUnackedPacketCount--;
+ mUnackedPacketBytes -= packetp->mBufferLength;
+
+ mFinalRetryPackets.erase(iter++);
+ delete packetp;
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+
+ return mUnackedPacketCount;
+}
+
+
+LLCircuit::LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout)
+: mLastCircuit(NULL),
+ mHeartbeatInterval(circuit_heartbeat_interval),
+ mHeartbeatTimeout(circuit_timeout)
+{}
+
+LLCircuit::~LLCircuit()
+{
+ // delete pointers in the map.
+ std::for_each(mCircuitData.begin(),
+ mCircuitData.end(),
+ llcompose1(
+ DeletePointerFunctor<LLCircuitData>(),
+ llselect2nd<circuit_data_map::value_type>()));
+}
+
+LLCircuitData *LLCircuit::addCircuitData(const LLHost &host, TPACKETID in_id)
+{
+ // This should really validate if one already exists
+ LL_INFOS() << "LLCircuit::addCircuitData for " << host << LL_ENDL;
+ LLCircuitData *tempp = new LLCircuitData(host, in_id, mHeartbeatInterval, mHeartbeatTimeout);
+ mCircuitData.insert(circuit_data_map::value_type(host, tempp));
+ mPingSet.insert(tempp);
+
+ mLastCircuit = tempp;
+ return tempp;
+}
+
+void LLCircuit::removeCircuitData(const LLHost &host)
+{
+ LL_INFOS() << "LLCircuit::removeCircuitData for " << host << LL_ENDL;
+ mLastCircuit = NULL;
+ circuit_data_map::iterator it = mCircuitData.find(host);
+ if(it != mCircuitData.end())
+ {
+ LLCircuitData *cdp = it->second;
+ mCircuitData.erase(it);
+
+ LLCircuit::ping_set_t::iterator psit = mPingSet.find(cdp);
+ if (psit != mPingSet.end())
+ {
+ mPingSet.erase(psit);
+ }
+ else
+ {
+ LL_WARNS() << "Couldn't find entry for next ping in ping set!" << LL_ENDL;
+ }
+
+ // Clean up from optimization maps
+ mUnackedCircuitMap.erase(host);
+ mSendAckMap.erase(host);
+ delete cdp;
+ }
+
+ // This also has to happen AFTER we nuke the circuit, because various
+ // callbacks for the circuit may result in messages being sent to
+ // this circuit, and the setting of mLastCircuit. We don't check
+ // if the host matches, but we don't really care because mLastCircuit
+ // is an optimization, and this happens VERY rarely.
+ mLastCircuit = NULL;
+}
+
+void LLCircuitData::setAlive(bool b_alive)
+{
+ if (mbAlive != b_alive)
+ {
+ mPacketsOutID = 0;
+ mPacketsInID = 0;
+ mbAlive = b_alive;
+ }
+ if (b_alive)
+ {
+ mLastPingReceivedTime = LLMessageSystem::getMessageTimeSeconds();
+ mPingsInTransit = 0;
+ mBlocked = false;
+ }
+}
+
+
+void LLCircuitData::setAllowTimeout(bool allow)
+{
+ mbAllowTimeout = allow;
+
+ if (allow)
+ {
+ // resuming circuit
+ // make sure it's alive
+ setAlive(true);
+ }
+}
+
+
+// Reset per-period counters if necessary.
+void LLCircuitData::checkPeriodTime()
+{
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+ F64Seconds period_length = mt_sec - mPeriodTime;
+ if ( period_length > TARGET_PERIOD_LENGTH)
+ {
+ F32 bps_in = F32Bits(mBytesInThisPeriod).value() / period_length.value();
+ if (bps_in > mPeakBPSIn)
+ {
+ mPeakBPSIn = bps_in;
+ }
+
+ F32 bps_out = F32Bits(mBytesOutThisPeriod).value() / period_length.value();
+ if (bps_out > mPeakBPSOut)
+ {
+ mPeakBPSOut = bps_out;
+ }
+
+ mBytesInLastPeriod = mBytesInThisPeriod;
+ mBytesOutLastPeriod = mBytesOutThisPeriod;
+ mBytesInThisPeriod = S32Bytes(0);
+ mBytesOutThisPeriod = S32Bytes(0);
+ mLastPeriodLength = F32Seconds::convert(period_length);
+
+ mPeriodTime = mt_sec;
+ }
+}
+
+
+void LLCircuitData::addBytesIn(S32Bytes bytes)
+{
+ mBytesIn += bytes;
+ mBytesInThisPeriod += bytes;
+}
+
+
+void LLCircuitData::addBytesOut(S32Bytes bytes)
+{
+ mBytesOut += bytes;
+ mBytesOutThisPeriod += bytes;
+}
+
+
+void LLCircuitData::addReliablePacket(S32 mSocket, U8 *buf_ptr, S32 buf_len, LLReliablePacketParams *params)
+{
+ LLReliablePacket *packet_info;
+
+ packet_info = new LLReliablePacket(mSocket, buf_ptr, buf_len, params);
+
+ mUnackedPacketCount++;
+ mUnackedPacketBytes += packet_info->mBufferLength;
+
+ if (params && params->mRetries)
+ {
+ mUnackedPackets[packet_info->mPacketID] = packet_info;
+ }
+ else
+ {
+ mFinalRetryPackets[packet_info->mPacketID] = packet_info;
+ }
+}
+
+
+void LLCircuit::resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size)
+{
+ F64Seconds now = LLMessageSystem::getMessageTimeSeconds();
+ unacked_list_length = 0;
+ unacked_list_size = 0;
+
+ LLCircuitData* circ;
+ circuit_data_map::iterator end = mUnackedCircuitMap.end();
+ for(circuit_data_map::iterator it = mUnackedCircuitMap.begin(); it != end; ++it)
+ {
+ circ = (*it).second;
+ unacked_list_length += circ->resendUnackedPackets(now);
+ unacked_list_size += circ->getUnackedPacketBytes();
+ }
+}
+
+
+bool LLCircuitData::isDuplicateResend(TPACKETID packetnum)
+{
+ return (mRecentlyReceivedReliablePackets.find(packetnum) != mRecentlyReceivedReliablePackets.end());
+}
+
+
+void LLCircuit::dumpResends()
+{
+ circuit_data_map::iterator end = mCircuitData.end();
+ for(circuit_data_map::iterator it = mCircuitData.begin(); it != end; ++it)
+ {
+ (*it).second->dumpResendCountAndReset();
+ }
+}
+
+LLCircuitData* LLCircuit::findCircuit(const LLHost& host) const
+{
+ // An optimization on finding the previously found circuit.
+ if (mLastCircuit && (mLastCircuit->mHost == host))
+ {
+ return mLastCircuit;
+ }
+
+ circuit_data_map::const_iterator it = mCircuitData.find(host);
+ if(it == mCircuitData.end())
+ {
+ return NULL;
+ }
+ mLastCircuit = it->second;
+ return mLastCircuit;
+}
+
+
+bool LLCircuit::isCircuitAlive(const LLHost& host) const
+{
+ LLCircuitData *cdp = findCircuit(host);
+ if(cdp)
+ {
+ return cdp->mbAlive;
+ }
+
+ return false;
+}
+
+void LLCircuitData::setTimeoutCallback(void (*callback_func)(const LLHost &host, void *user_data), void *user_data)
+{
+ mTimeoutCallback = callback_func;
+ mTimeoutUserData = user_data;
+}
+
+void LLCircuitData::checkPacketInID(TPACKETID id, bool receive_resent)
+{
+ // Done as floats so we don't have to worry about running out of room
+ // with U32 getting poked into an S32.
+ F32 delta = (F32)mHighestPacketID - (F32)id;
+ if (delta > (0.5f*LL_MAX_OUT_PACKET_ID))
+ {
+ // We've almost definitely wrapped, reset the mLastPacketID to be low again.
+ mHighestPacketID = id;
+ }
+ else if (delta < (-0.5f*LL_MAX_OUT_PACKET_ID))
+ {
+ // This is almost definitely an old packet coming in after a wrap, ignore it.
+ }
+ else
+ {
+ mHighestPacketID = llmax(mHighestPacketID, id);
+ }
+
+ // Save packet arrival time
+ mLastPacketInTime = LLMessageSystem::getMessageTimeSeconds();
+
+ // Have we received anything on this circuit yet?
+ if (0 == mPacketsIn)
+ {
+ // Must be first packet from unclosed circuit.
+ mPacketsIn++;
+ setPacketInID((id + 1) % LL_MAX_OUT_PACKET_ID);
+
+ mLastPacketGap = 0;
+ return;
+ }
+
+ mPacketsIn++;
+
+
+ // now, check to see if we've got a gap
+ U32 gap = 0;
+ if (mPacketsInID == id)
+ {
+ // nope! bump and wrap the counter, then return
+ mPacketsInID++;
+ mPacketsInID = (mPacketsInID) % LL_MAX_OUT_PACKET_ID;
+ }
+ else if (id < mWrapID)
+ {
+ // id < mWrapID will happen if the first few packets are out of order. . .
+ // at that point we haven't marked anything "potentially lost" and
+ // the out-of-order packet will cause a full wrap marking all the IDs "potentially lost"
+
+ // do nothing
+ }
+ else
+ {
+ // we have a gap! if that id is in the map, remove it from the map, leave mCurrentCircuit->mPacketsInID
+ // alone
+ // otherwise, walk from mCurrentCircuit->mPacketsInID to id with wrapping, adding the values to the map
+ // and setting mPacketsInID to id + 1 % LL_MAX_OUT_PACKET_ID
+
+ // babbage: all operands in expression are unsigned, so modular
+ // arithmetic will always find correct gap, regardless of wrap arounds.
+ const U8 width = 24;
+ gap = LLModularMath::subtract<width>(mPacketsInID, id);
+
+ if (mPotentialLostPackets.find(id) != mPotentialLostPackets.end())
+ {
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << mHost << "\tRECOVERING LOST:\t" << id;
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+ // LL_INFOS() << "removing potential lost: " << id << LL_ENDL;
+ mPotentialLostPackets.erase(id);
+ }
+ else if (!receive_resent) // don't freak out over out-of-order reliable resends
+ {
+ U64Microseconds time = LLMessageSystem::getMessageTimeUsecs();
+ TPACKETID index = mPacketsInID;
+ S32 gap_count = 0;
+ if ((index < id) && ((id - index) < 16))
+ {
+ while (index != id)
+ {
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << mHost << "\tPACKET GAP:\t"
+ << index;
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+
+// LL_INFOS() << "adding potential lost: " << index << LL_ENDL;
+ mPotentialLostPackets[index] = time;
+ index++;
+ index = index % LL_MAX_OUT_PACKET_ID;
+ gap_count++;
+ }
+ }
+ else
+ {
+ LL_INFOS() << "packet_out_of_order - got packet " << id << " expecting " << index << " from " << mHost << LL_ENDL;
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << mHost << "\tPACKET GAP:\t"
+ << id << " expected " << index;
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+ }
+
+ mPacketsInID = id + 1;
+ mPacketsInID = (mPacketsInID) % LL_MAX_OUT_PACKET_ID;
+
+ if (gap_count > 128)
+ {
+ LL_WARNS() << "Packet loss gap filler running amok!" << LL_ENDL;
+ }
+ else if (gap_count > 16)
+ {
+ LL_WARNS() << "Sustaining large amounts of packet loss!" << LL_ENDL;
+ }
+
+ }
+ }
+ mLastPacketGap = gap;
+}
+
+
+void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys)
+{
+ F64Seconds cur_time = LLMessageSystem::getMessageTimeSeconds();
+ S32 count = mPingSet.size();
+ S32 cur = 0;
+
+ // Only process each circuit once at most, stop processing if no circuits
+ while((cur < count) && !mPingSet.empty())
+ {
+ cur++;
+
+ LLCircuit::ping_set_t::iterator psit = mPingSet.begin();
+ LLCircuitData *cdp = *psit;
+
+ if (!cdp->mbAlive)
+ {
+ // We suspect that this case should never happen, given how
+ // the alive status is set.
+ // Skip over dead circuits, just add the ping interval and push it to the back
+ // Always remember to remove it from the set before changing the sorting
+ // key (mNextPingSendTime)
+ mPingSet.erase(psit);
+ cdp->mNextPingSendTime = cur_time + mHeartbeatInterval;
+ mPingSet.insert(cdp);
+ continue;
+ }
+ else
+ {
+ // Check to see if this needs a ping
+ if (cur_time < cdp->mNextPingSendTime)
+ {
+ // This circuit doesn't need a ping, break out because
+ // we have a sorted list, thus no more circuits need pings
+ break;
+ }
+
+ // Update watchdog timers
+ if (cdp->updateWatchDogTimers(msgsys))
+ {
+ // Randomize our pings a bit by doing some up to 5% early or late
+ F64Seconds dt = 0.95f*mHeartbeatInterval + F32Seconds(ll_frand(0.1f*mHeartbeatInterval.value()));
+
+ // Remove it, and reinsert it with the new next ping time.
+ // Always remove before changing the sorting key.
+ mPingSet.erase(psit);
+ cdp->mNextPingSendTime = cur_time + dt;
+ mPingSet.insert(cdp);
+
+ // Update our throttles
+ cdp->mThrottles.dynamicAdjust();
+
+ // Update some stats, this is not terribly important
+ cdp->checkPeriodTime();
+ }
+ else
+ {
+ // This mPingSet.erase isn't necessary, because removing the circuit will
+ // remove the ping set.
+ //mPingSet.erase(psit);
+ removeCircuitData(cdp->mHost);
+ }
+ }
+ }
+}
+
+
+bool LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys)
+{
+ F64Seconds cur_time = LLMessageSystem::getMessageTimeSeconds();
+ mLastPingSendTime = cur_time;
+
+ if (!checkCircuitTimeout())
+ {
+ // Pass this back to the calling LLCircuit, this circuit needs to be cleaned up.
+ return false;
+ }
+
+ // WARNING!
+ // Duplicate suppression can FAIL if packets are delivered out of
+ // order, although it's EXTREMELY unlikely. It would require
+ // that the ping get delivered out of order enough that the ACK
+ // for the packet that it was out of order with was received BEFORE
+ // the ping was sent.
+
+ // Find the current oldest reliable packetID
+ // This is to handle the case if we actually manage to wrap our
+ // packet IDs - the oldest will actually have a higher packet ID
+ // than the current.
+ bool wrapped = false;
+ reliable_iter iter;
+ iter = mUnackedPackets.upper_bound(getPacketOutID());
+ if (iter == mUnackedPackets.end())
+ {
+ // Nothing AFTER this one, so we want the lowest packet ID
+ // then.
+ iter = mUnackedPackets.begin();
+ wrapped = true;
+ }
+
+ TPACKETID packet_id = 0;
+
+ // Check against the "final" packets
+ bool wrapped_final = false;
+ reliable_iter iter_final;
+ iter_final = mFinalRetryPackets.upper_bound(getPacketOutID());
+ if (iter_final == mFinalRetryPackets.end())
+ {
+ iter_final = mFinalRetryPackets.begin();
+ wrapped_final = true;
+ }
+
+ //LL_INFOS() << mHost << " - unacked count " << mUnackedPackets.size() << LL_ENDL;
+ //LL_INFOS() << mHost << " - final count " << mFinalRetryPackets.size() << LL_ENDL;
+ if (wrapped != wrapped_final)
+ {
+ // One of the "unacked" or "final" lists hasn't wrapped. Whichever one
+ // hasn't has the oldest packet.
+ if (!wrapped)
+ {
+ // Hasn't wrapped, so the one on the
+ // unacked packet list is older
+ packet_id = iter->first;
+ //LL_INFOS() << mHost << ": nowrapped unacked" << LL_ENDL;
+ }
+ else
+ {
+ packet_id = iter_final->first;
+ //LL_INFOS() << mHost << ": nowrapped final" << LL_ENDL;
+ }
+ }
+ else
+ {
+ // They both wrapped, we can just use the minimum of the two.
+ if ((iter == mUnackedPackets.end()) && (iter_final == mFinalRetryPackets.end()))
+ {
+ // Wow! No unacked packets at all!
+ // Send the ID of the last packet we sent out.
+ // This will flush all of the destination's
+ // unacked packets, theoretically.
+ //LL_INFOS() << mHost << ": No unacked!" << LL_ENDL;
+ packet_id = getPacketOutID();
+ }
+ else
+ {
+ bool had_unacked = false;
+ if (iter != mUnackedPackets.end())
+ {
+ // Unacked list has the lowest so far
+ packet_id = iter->first;
+ had_unacked = true;
+ //LL_INFOS() << mHost << ": Unacked" << LL_ENDL;
+ }
+
+ if (iter_final != mFinalRetryPackets.end())
+ {
+ // Use the lowest of the unacked list and the final list
+ if (had_unacked)
+ {
+ // Both had a packet, use the lowest.
+ packet_id = llmin(packet_id, iter_final->first);
+ //LL_INFOS() << mHost << ": Min of unacked/final" << LL_ENDL;
+ }
+ else
+ {
+ // Only the final had a packet, use it.
+ packet_id = iter_final->first;
+ //LL_INFOS() << mHost << ": Final!" << LL_ENDL;
+ }
+ }
+ }
+ }
+
+ // Send off the another ping.
+ pingTimerStart();
+ msgsys->newMessageFast(_PREHASH_StartPingCheck);
+ msgsys->nextBlock(_PREHASH_PingID);
+ msgsys->addU8Fast(_PREHASH_PingID, nextPingID());
+ msgsys->addU32Fast(_PREHASH_OldestUnacked, packet_id);
+ msgsys->sendMessage(mHost);
+
+ // Also do lost packet accounting.
+ // Check to see if anything on our lost list is old enough to
+ // be considered lost
+
+ LLCircuitData::packet_time_map::iterator it;
+ U64Microseconds timeout = llmin(LL_MAX_LOST_TIMEOUT, F32Seconds(getPingDelayAveraged()) * LL_LOST_TIMEOUT_FACTOR);
+
+ U64Microseconds mt_usec = LLMessageSystem::getMessageTimeUsecs();
+ for (it = mPotentialLostPackets.begin(); it != mPotentialLostPackets.end(); )
+ {
+ U64Microseconds delta_t_usec = mt_usec - (*it).second;
+ if (delta_t_usec > timeout)
+ {
+ // let's call this one a loss!
+ mPacketsLost++;
+ gMessageSystem->mDroppedPackets++;
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << mHost << "\tLOST PACKET:\t"
+ << (*it).first;
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+ mPotentialLostPackets.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ return true;
+}
+
+
+void LLCircuitData::clearDuplicateList(TPACKETID oldest_id)
+{
+ // purge old data from the duplicate suppression queue
+
+ // we want to KEEP all x where oldest_id <= x <= last incoming packet, and delete everything else.
+
+ //LL_INFOS() << mHost << ": clearing before oldest " << oldest_id << LL_ENDL;
+ //LL_INFOS() << "Recent list before: " << mRecentlyReceivedReliablePackets.size() << LL_ENDL;
+ if (oldest_id < mHighestPacketID)
+ {
+ // Clean up everything with a packet ID less than oldest_id.
+ packet_time_map::iterator pit_start;
+ packet_time_map::iterator pit_end;
+ pit_start = mRecentlyReceivedReliablePackets.begin();
+ pit_end = mRecentlyReceivedReliablePackets.lower_bound(oldest_id);
+ mRecentlyReceivedReliablePackets.erase(pit_start, pit_end);
+ }
+
+ // Do timeout checks on everything with an ID > mHighestPacketID.
+ // This should be empty except for wrapping IDs. Thus, this should be
+ // highly rare.
+ U64Microseconds mt_usec = LLMessageSystem::getMessageTimeUsecs();
+
+ packet_time_map::iterator pit;
+ for(pit = mRecentlyReceivedReliablePackets.upper_bound(mHighestPacketID);
+ pit != mRecentlyReceivedReliablePackets.end(); )
+ {
+ // Validate that the packet ID seems far enough away
+ if ((pit->first - mHighestPacketID) < 100)
+ {
+ LL_WARNS() << "Probably incorrectly timing out non-wrapped packets!" << LL_ENDL;
+ }
+ U64Microseconds delta_t_usec = mt_usec - (*pit).second;
+ F64Seconds delta_t_sec = delta_t_usec;
+ if (delta_t_sec > LL_DUPLICATE_SUPPRESSION_TIMEOUT)
+ {
+ // enough time has elapsed we're not likely to get a duplicate on this one
+ LL_INFOS() << "Clearing " << pit->first << " from recent list" << LL_ENDL;
+ mRecentlyReceivedReliablePackets.erase(pit++);
+ }
+ else
+ {
+ ++pit;
+ }
+ }
+ //LL_INFOS() << "Recent list after: " << mRecentlyReceivedReliablePackets.size() << LL_ENDL;
+}
+
+bool LLCircuitData::checkCircuitTimeout()
+{
+ F64Seconds time_since_last_ping = LLMessageSystem::getMessageTimeSeconds() - mLastPingReceivedTime;
+
+ // Nota Bene: This needs to be turned off if you are debugging multiple simulators
+ if (time_since_last_ping > mHeartbeatTimeout)
+ {
+ LL_WARNS() << "LLCircuitData::checkCircuitTimeout for " << mHost << " last ping " << time_since_last_ping << " seconds ago." <<LL_ENDL;
+ setAlive(false);
+ if (mTimeoutCallback)
+ {
+ LL_WARNS() << "LLCircuitData::checkCircuitTimeout for " << mHost << " calling callback." << LL_ENDL;
+ mTimeoutCallback(mHost, mTimeoutUserData);
+ }
+ if (!isAlive())
+ {
+ // The callback didn't try and resurrect the circuit. We should kill it.
+ LL_WARNS() << "LLCircuitData::checkCircuitTimeout for " << mHost << " still dead, dropping." << LL_ENDL;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Call this method when a reliable message comes in - this will
+// correctly place the packet in the correct list to be acked later.
+bool LLCircuitData::collectRAck(TPACKETID packet_num)
+{
+ if (mAcks.empty())
+ {
+ // First extra ack, we need to add ourselves to the list of circuits that need to send acks
+ gMessageSystem->mCircuitInfo.mSendAckMap[mHost] = this;
+ }
+
+ mAcks.push_back(packet_num);
+ if (mAckCreationTime == 0)
+ {
+ mAckCreationTime = getAgeInSeconds();
+ }
+ return true;
+}
+
+// this method is called during the message system processAcks() to
+// send out any acks that did not get sent already.
+void LLCircuit::sendAcks(F32 collect_time)
+{
+ collect_time = llclamp(collect_time, 0.f, LL_COLLECT_ACK_TIME_MAX);
+ LLCircuitData* cd;
+ circuit_data_map::iterator it = mSendAckMap.begin();
+ while (it != mSendAckMap.end())
+ {
+ circuit_data_map::iterator cur_it = it++;
+ cd = (*cur_it).second;
+ S32 count = (S32)cd->mAcks.size();
+ F32 age = cd->getAgeInSeconds() - cd->mAckCreationTime;
+ if (age > collect_time || count == 0)
+ {
+ if (count>0)
+ {
+ // send the packet acks
+ S32 acks_this_packet = 0;
+ for(S32 i = 0; i < count; ++i)
+ {
+ if(acks_this_packet == 0)
+ {
+ gMessageSystem->newMessageFast(_PREHASH_PacketAck);
+ }
+ gMessageSystem->nextBlockFast(_PREHASH_Packets);
+ gMessageSystem->addU32Fast(_PREHASH_ID, cd->mAcks[i]);
+ ++acks_this_packet;
+ if(acks_this_packet > 250)
+ {
+ gMessageSystem->sendMessage(cd->mHost);
+ acks_this_packet = 0;
+ }
+ }
+ if(acks_this_packet > 0)
+ {
+ gMessageSystem->sendMessage(cd->mHost);
+ }
+
+ if(gMessageSystem->mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: -> " << cd->mHost << "\tPACKET ACKS:\t";
+ std::ostream_iterator<TPACKETID> append(str, " ");
+ std::copy(cd->mAcks.begin(), cd->mAcks.end(), append);
+ LL_INFOS() << str.str() << LL_ENDL;
+ }
+
+ // empty out the acks list
+ cd->mAcks.clear();
+ cd->mAckCreationTime = 0.f;
+ }
+ // remove data map
+ mSendAckMap.erase(cur_it);
+ }
+ }
+}
+
+
+std::ostream& operator<<(std::ostream& s, LLCircuitData& circuit)
+{
+ F32 age = circuit.mExistenceTimer.getElapsedTimeF32();
+
+ using namespace std;
+ s << "Circuit " << circuit.mHost << " "
+ << circuit.mRemoteID << " "
+ << (circuit.mbAlive ? "Alive" : "Not Alive") << " "
+ << (circuit.mbAllowTimeout ? "Timeout Allowed" : "Timeout Not Allowed")
+ << endl;
+
+ s << " Packets Lost: " << circuit.mPacketsLost
+ << " Measured Ping: " << circuit.mPingDelay
+ << " Averaged Ping: " << circuit.mPingDelayAveraged
+ << endl;
+
+ s << "Global In/Out " << S32(age) << " sec"
+ << " KBytes: " << circuit.mBytesIn.valueInUnits<LLUnits::Kilobytes>() << "/" << circuit.mBytesOut.valueInUnits<LLUnits::Kilobytes>()
+ << " Kbps: "
+ << S32(circuit.mBytesIn.valueInUnits<LLUnits::Kilobits>() / circuit.mExistenceTimer.getElapsedTimeF32().value())
+ << "/"
+ << S32(circuit.mBytesOut.valueInUnits<LLUnits::Kilobits>() / circuit.mExistenceTimer.getElapsedTimeF32().value())
+ << " Packets: " << circuit.mPacketsIn << "/" << circuit.mPacketsOut
+ << endl;
+
+ s << "Recent In/Out " << circuit.mLastPeriodLength
+ << " KBytes: "
+ << circuit.mBytesInLastPeriod.valueInUnits<LLUnits::Kilobytes>()
+ << "/"
+ << circuit.mBytesOutLastPeriod.valueInUnits<LLUnits::Kilobytes>()
+ << " Kbps: "
+ << (S32)(circuit.mBytesInLastPeriod.valueInUnits<LLUnits::Kilobits>() / circuit.mLastPeriodLength.value())
+ << "/"
+ << (S32)(circuit.mBytesOutLastPeriod.valueInUnits<LLUnits::Kilobits>() / circuit.mLastPeriodLength.value())
+ << " Peak kbps: "
+ << S32(circuit.mPeakBPSIn / 1024.f)
+ << "/"
+ << S32(circuit.mPeakBPSOut / 1024.f)
+ << endl;
+
+ return s;
+}
+
+void LLCircuitData::getInfo(LLSD& info) const
+{
+ info["Host"] = mHost.getIPandPort();
+ info["Alive"] = mbAlive;
+ info["Age"] = mExistenceTimer.getElapsedTimeF32();
+}
+
+void LLCircuitData::dumpResendCountAndReset()
+{
+ if (mCurrentResendCount)
+ {
+ LL_INFOS() << "Circuit: " << mHost << " resent " << mCurrentResendCount << " packets" << LL_ENDL;
+ mCurrentResendCount = 0;
+ }
+}
+
+std::ostream& operator<<(std::ostream& s, LLCircuit &circuit)
+{
+ s << "Circuit Info:" << std::endl;
+ LLCircuit::circuit_data_map::iterator end = circuit.mCircuitData.end();
+ LLCircuit::circuit_data_map::iterator it;
+ for(it = circuit.mCircuitData.begin(); it != end; ++it)
+ {
+ s << *((*it).second) << std::endl;
+ }
+ return s;
+}
+
+void LLCircuit::getInfo(LLSD& info) const
+{
+ LLCircuit::circuit_data_map::const_iterator end = mCircuitData.end();
+ LLCircuit::circuit_data_map::const_iterator it;
+ LLSD circuit_info;
+ for(it = mCircuitData.begin(); it != end; ++it)
+ {
+ (*it).second->getInfo(circuit_info);
+ info["Circuits"].append(circuit_info);
+ }
+}
+
+void LLCircuit::getCircuitRange(
+ const LLHost& key,
+ LLCircuit::circuit_data_map::iterator& first,
+ LLCircuit::circuit_data_map::iterator& end)
+{
+ end = mCircuitData.end();
+ first = mCircuitData.upper_bound(key);
+}
+
+TPACKETID LLCircuitData::nextPacketOutID()
+{
+ mPacketsOut++;
+
+ TPACKETID id;
+
+ id = (mPacketsOutID + 1) % LL_MAX_OUT_PACKET_ID;
+
+ if (id < mPacketsOutID)
+ {
+ // we just wrapped on a circuit, reset the wrap ID to zero
+ mWrapID = 0;
+ }
+ mPacketsOutID = id;
+ return id;
+}
+
+
+void LLCircuitData::setPacketInID(TPACKETID id)
+{
+ id = id % LL_MAX_OUT_PACKET_ID;
+ mPacketsInID = id;
+ mRecentlyReceivedReliablePackets.clear();
+
+ mWrapID = id;
+}
+
+
+void LLCircuitData::pingTimerStop(const U8 ping_id)
+{
+ F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds();
+
+ // Nota Bene: no averaging of ping times until we get a feel for how this works
+ F64Seconds time = mt_secs - mPingTime;
+ if (time == F32Seconds(0.0))
+ {
+ // Ack, we got our ping response on the same frame! Sigh, let's get a real time otherwise
+ // all of our ping calculations will be skewed.
+ mt_secs = LLMessageSystem::getMessageTimeSeconds(true);
+ }
+ mLastPingReceivedTime = mt_secs;
+
+ // If ping is longer than 1 second, we'll get sequence deltas in the ping.
+ // Approximate by assuming each ping counts for 1 second (slightly low, probably)
+ S32 delta_ping = (S32)mLastPingID - (S32) ping_id;
+ if (delta_ping < 0)
+ {
+ delta_ping += 256;
+ }
+
+ U32Milliseconds msec = delta_ping*mHeartbeatInterval + time;
+ setPingDelay(msec);
+
+ mPingsInTransit = delta_ping;
+ if (mBlocked && (mPingsInTransit <= PING_RELEASE_BLOCK))
+ {
+ mBlocked = false;
+ }
+}
+
+
+void LLCircuitData::pingTimerStart()
+{
+ mPingTime = LLMessageSystem::getMessageTimeSeconds();
+ mPingsInTransit++;
+
+ if (!mBlocked && (mPingsInTransit > PING_START_BLOCK))
+ {
+ mBlocked = true;
+ }
+}
+
+
+U32 LLCircuitData::getPacketsIn() const
+{
+ return mPacketsIn;
+}
+
+
+S32Bytes LLCircuitData::getBytesIn() const
+{
+ return mBytesIn;
+}
+
+
+S32Bytes LLCircuitData::getBytesOut() const
+{
+ return mBytesOut;
+}
+
+
+U32 LLCircuitData::getPacketsOut() const
+{
+ return mPacketsOut;
+}
+
+
+TPACKETID LLCircuitData::getPacketOutID() const
+{
+ return mPacketsOutID;
+}
+
+
+U32 LLCircuitData::getPacketsLost() const
+{
+ return mPacketsLost;
+}
+
+
+bool LLCircuitData::isAlive() const
+{
+ return mbAlive;
+}
+
+
+bool LLCircuitData::isBlocked() const
+{
+ return mBlocked;
+}
+
+
+bool LLCircuitData::getAllowTimeout() const
+{
+ return mbAllowTimeout;
+}
+
+
+U32Milliseconds LLCircuitData::getPingDelay() const
+{
+ return mPingDelay;
+}
+
+
+F32Milliseconds LLCircuitData::getPingInTransitTime()
+{
+ // This may be inaccurate in the case of a circuit that was "dead" and then revived,
+ // but only until the first round trip ping is sent - djs
+ F32Milliseconds time_since_ping_was_sent(0);
+
+ if (mPingsInTransit)
+ {
+ time_since_ping_was_sent = F32Milliseconds::convert(((mPingsInTransit*mHeartbeatInterval - F32Seconds(1))
+ + (LLMessageSystem::getMessageTimeSeconds() - mPingTime)));
+ }
+
+ return time_since_ping_was_sent;
+}
+
+
+void LLCircuitData::setPingDelay(U32Milliseconds ping)
+{
+ mPingDelay = ping;
+ mPingDelayAveraged = llmax((F32Milliseconds)ping, getPingDelayAveraged());
+ mPingDelayAveraged = ((1.f - LL_AVERAGED_PING_ALPHA) * mPingDelayAveraged)
+ + (LL_AVERAGED_PING_ALPHA * (F32Milliseconds) ping);
+ mPingDelayAveraged = llclamp(mPingDelayAveraged,
+ LL_AVERAGED_PING_MIN,
+ LL_AVERAGED_PING_MAX);
+}
+
+
+F32Milliseconds LLCircuitData::getPingDelayAveraged()
+{
+ return llmin(llmax(getPingInTransitTime(), mPingDelayAveraged), LL_AVERAGED_PING_MAX);
+}
+
+
+bool LLCircuitData::getTrusted() const
+{
+ return mTrusted;
+}
+
+
+void LLCircuitData::setTrusted(bool t)
+{
+ mTrusted = t;
+}
+
+F32 LLCircuitData::getAgeInSeconds() const
+{
+ return mExistenceTimer.getElapsedTimeF32();
+}
diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h index 7a5a5c65f5..ba38849f70 100644 --- a/indra/llmessage/llcircuit.h +++ b/indra/llmessage/llcircuit.h @@ -1,350 +1,350 @@ -/** - * @file llcircuit.h - * @brief Provides a method for tracking network circuit information - * for the UDP message system - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLCIRCUIT_H -#define LL_LLCIRCUIT_H - -#include <map> -#include <vector> - -#include "llerror.h" - -#include "lltimer.h" -#include "net.h" -#include "llhost.h" -#include "llpacketack.h" -#include "lluuid.h" -#include "llthrottle.h" - -// -// Constants -// -const F32 LL_AVERAGED_PING_ALPHA = 0.2f; // relaxation constant on ping running average -const F32Milliseconds LL_AVERAGED_PING_MAX(2000); -const F32Milliseconds LL_AVERAGED_PING_MIN(100); // increased to avoid retransmits when a process is slow - -const U32Milliseconds INITIAL_PING_VALUE_MSEC(1000); // initial value for the ping delay, or for ping delay for an unknown circuit - -const TPACKETID LL_MAX_OUT_PACKET_ID = 0x01000000; -const int LL_ERR_CIRCUIT_GONE = -23017; -const int LL_ERR_TCP_TIMEOUT = -23016; - -// 0 - flags -// [1,4] - packetid -// 5 - data offset (after message name) -const U8 LL_PACKET_ID_SIZE = 6; - -const S32 LL_MAX_RESENT_PACKETS_PER_FRAME = 100; -const S32 LL_MAX_ACKED_PACKETS_PER_FRAME = 200; -const F32 LL_COLLECT_ACK_TIME_MAX = 2.f; - -// -// Prototypes and Predefines -// -class LLMessageSystem; -class LLEncodedDatagramService; -class LLSD; - -// -// Classes -// - - -class LLCircuitData -{ -public: - LLCircuitData(const LLHost &host, TPACKETID in_id, - const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout); - ~LLCircuitData(); - - S32 resendUnackedPackets(const F64Seconds now); - void clearDuplicateList(TPACKETID oldest_id); - - - void dumpResendCountAndReset(); // Used for tracking how many resends are being done on a circuit. - - - - // Public because stupid message system callbacks uses it. - void pingTimerStart(); - void pingTimerStop(const U8 ping_id); - void ackReliablePacket(TPACKETID packet_num); - - // remote computer information - const LLUUID& getRemoteID() const { return mRemoteID; } - const LLUUID& getRemoteSessionID() const { return mRemoteSessionID; } - void setRemoteID(const LLUUID& id) { mRemoteID = id; } - void setRemoteSessionID(const LLUUID& id) { mRemoteSessionID = id; } - - void setTrusted(BOOL t); - - // The local end point ID is used when establishing a trusted circuit. - // no matching set function for getLocalEndPointID() - // mLocalEndPointID should only ever be setup in the LLCircuitData constructor - const LLUUID& getLocalEndPointID() const { return mLocalEndPointID; } - - U32Milliseconds getPingDelay() const; - S32 getPingsInTransit() const { return mPingsInTransit; } - - // ACCESSORS - BOOL isAlive() const; - BOOL isBlocked() const; - BOOL getAllowTimeout() const; - F32Milliseconds getPingDelayAveraged(); - F32Milliseconds getPingInTransitTime(); - U32 getPacketsIn() const; - S32Bytes getBytesIn() const; - S32Bytes getBytesOut() const; - U32 getPacketsOut() const; - U32 getPacketsLost() const; - TPACKETID getPacketOutID() const; - BOOL getTrusted() const; - F32 getAgeInSeconds() const; - S32 getUnackedPacketCount() const { return mUnackedPacketCount; } - S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; } - F64Seconds getNextPingSendTime() const { return mNextPingSendTime; } - U32 getLastPacketGap() const { return mLastPacketGap; } - LLHost getHost() const { return mHost; } - F64Seconds getLastPacketInTime() const { return mLastPacketInTime; } - - LLThrottleGroup &getThrottleGroup() { return mThrottles; } - - class less - { - public: - bool operator()(const LLCircuitData* lhs, const LLCircuitData* rhs) const - { - if (lhs->getNextPingSendTime() < rhs->getNextPingSendTime()) - { - return true; - } - else if (lhs->getNextPingSendTime() > rhs->getNextPingSendTime()) - { - return false; - } - else return lhs > rhs; - } - }; - - // - // Debugging stuff (not necessary for operation) - // - void checkPeriodTime(); // Reset per-period counters if necessary. - friend std::ostream& operator<<(std::ostream& s, LLCircuitData &circuit); - void getInfo(LLSD& info) const; - - friend class LLCircuit; - friend class LLMessageSystem; - friend class LLEncodedDatagramService; - friend void crash_on_spaceserver_timeout (const LLHost &host, void *); // HACK, so it has access to setAlive() so it can send a final shutdown message. -protected: - TPACKETID nextPacketOutID(); - void setPacketInID(TPACKETID id); - void checkPacketInID(TPACKETID id, BOOL receive_resent); - void setPingDelay(U32Milliseconds ping); - BOOL checkCircuitTimeout(); // Return FALSE if the circuit is dead and should be cleaned up - - void addBytesIn(S32Bytes bytes); - void addBytesOut(S32Bytes bytes); - - U8 nextPingID() { mLastPingID++; return mLastPingID; } - - BOOL updateWatchDogTimers(LLMessageSystem *msgsys); // Return FALSE if the circuit is dead and should be cleaned up - - void addReliablePacket(S32 mSocket, U8 *buf_ptr, S32 buf_len, LLReliablePacketParams *params); - BOOL isDuplicateResend(TPACKETID packetnum); - // Call this method when a reliable message comes in - this will - // correctly place the packet in the correct list to be acked - // later. RAack = requested ack - BOOL collectRAck(TPACKETID packet_num); - - - void setTimeoutCallback(void (*callback_func)(const LLHost &host, void *user_data), void *user_data); - - - - void setAlive(BOOL b_alive); - void setAllowTimeout(BOOL allow); - -protected: - // Identification for this circuit. - LLHost mHost; - LLUUID mRemoteID; - LLUUID mRemoteSessionID; - - LLThrottleGroup mThrottles; - - TPACKETID mWrapID; - - // Current packet IDs of incoming/outgoing packets - // Used for packet sequencing/packet loss detection. - TPACKETID mPacketsOutID; - TPACKETID mPacketsInID; - TPACKETID mHighestPacketID; - - - // Callback and data to run in the case of a circuit timeout. - // Used primarily to try and reconnect to servers if they crash/die. - void (*mTimeoutCallback)(const LLHost &host, void *user_data); - void *mTimeoutUserData; - - BOOL mTrusted; // Is this circuit trusted? - BOOL mbAllowTimeout; // Machines can "pause" circuits, forcing them not to be dropped - - BOOL mbAlive; // Indicates whether a circuit is "alive", i.e. responded to pings - - BOOL mBlocked; // Blocked is true if the circuit is hosed, i.e. far behind on pings - - // Not sure what the difference between this and mLastPingSendTime is - F64Seconds mPingTime; // Time at which a ping was sent. - - F64Seconds mLastPingSendTime; // Time we last sent a ping - F64Seconds mLastPingReceivedTime; // Time we last received a ping - F64Seconds mNextPingSendTime; // Time to try and send the next ping - S32 mPingsInTransit; // Number of pings in transit - U8 mLastPingID; // ID of the last ping that we sent out - - - // Used for determining the resend time for reliable resends. - U32Milliseconds mPingDelay; // raw ping delay - F32Milliseconds mPingDelayAveraged; // averaged ping delay (fast attack/slow decay) - - typedef std::map<TPACKETID, U64Microseconds> packet_time_map; - - packet_time_map mPotentialLostPackets; - packet_time_map mRecentlyReceivedReliablePackets; - std::vector<TPACKETID> mAcks; - F32 mAckCreationTime; // first ack creation time - - typedef std::map<TPACKETID, LLReliablePacket *> reliable_map; - typedef reliable_map::iterator reliable_iter; - - reliable_map mUnackedPackets; - reliable_map mFinalRetryPackets; - - S32 mUnackedPacketCount; - S32 mUnackedPacketBytes; - - F64Seconds mLastPacketInTime; // Time of last packet arrival - - LLUUID mLocalEndPointID; - - // - // These variables are being used for statistical and debugging purpose ONLY, - // as far as I can tell. - // - - U32 mPacketsOut; - U32 mPacketsIn; - S32 mPacketsLost; - S32Bytes mBytesIn, - mBytesOut; - - F32Seconds mLastPeriodLength; - S32Bytes mBytesInLastPeriod; - S32Bytes mBytesOutLastPeriod; - S32Bytes mBytesInThisPeriod; - S32Bytes mBytesOutThisPeriod; - F32 mPeakBPSIn; // bits per second, max of all period bps - F32 mPeakBPSOut; // bits per second, max of all period bps - F64Seconds mPeriodTime; - LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers - - S32 mCurrentResendCount; // Number of resent packets since last spam - U32 mLastPacketGap; // Gap in sequence number of last packet. - - const F32Seconds mHeartbeatInterval; - const F32Seconds mHeartbeatTimeout; -}; - - -// Actually a singleton class -- the global messagesystem -// has a single LLCircuit member. -class LLCircuit -{ -public: - // CREATORS - LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout); - ~LLCircuit(); - - // ACCESSORS - LLCircuitData* findCircuit(const LLHost& host) const; - BOOL isCircuitAlive(const LLHost& host) const; - - // MANIPULATORS - LLCircuitData *addCircuitData(const LLHost &host, TPACKETID in_id); - void removeCircuitData(const LLHost &host); - - void updateWatchDogTimers(LLMessageSystem *msgsys); - void resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size); - - // this method is called during the message system processAcks() - // to send out any acks that did not get sent already. - void sendAcks(F32 collect_time); - - friend std::ostream& operator<<(std::ostream& s, LLCircuit &circuit); - void getInfo(LLSD& info) const; - - void dumpResends(); - - typedef std::map<LLHost, LLCircuitData*> circuit_data_map; - - /** - * @brief This method gets an iterator range starting after key in - * the circuit data map. - * - * @param key The the host before first. - * @param first[out] The first matching value after key. This - * value will equal end if there are no entries. - * @param end[out] The end of the iteration sequence. - */ - void getCircuitRange( - const LLHost& key, - circuit_data_map::iterator& first, - circuit_data_map::iterator& end); - - // Lists that optimize how many circuits we need to traverse a frame - // HACK - this should become protected eventually, but stupid !@$@# message system/circuit classes are jumbling things up. - circuit_data_map mUnackedCircuitMap; // Map of circuits with unacked data - circuit_data_map mSendAckMap; // Map of circuits which need to send acks -protected: - circuit_data_map mCircuitData; - - typedef std::set<LLCircuitData *, LLCircuitData::less> ping_set_t; // Circuits sorted by next ping time - - ping_set_t mPingSet; - - // This variable points to the last circuit data we found to - // optimize the many, many times we call findCircuit. This may be - // set in otherwise const methods, so it is declared mutable. - mutable LLCircuitData* mLastCircuit; - -private: - const F32Seconds mHeartbeatInterval; - const F32Seconds mHeartbeatTimeout; -}; -#endif +/**
+ * @file llcircuit.h
+ * @brief Provides a method for tracking network circuit information
+ * for the UDP message system
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLCIRCUIT_H
+#define LL_LLCIRCUIT_H
+
+#include <map>
+#include <vector>
+
+#include "llerror.h"
+
+#include "lltimer.h"
+#include "net.h"
+#include "llhost.h"
+#include "llpacketack.h"
+#include "lluuid.h"
+#include "llthrottle.h"
+
+//
+// Constants
+//
+const F32 LL_AVERAGED_PING_ALPHA = 0.2f; // relaxation constant on ping running average
+const F32Milliseconds LL_AVERAGED_PING_MAX(2000);
+const F32Milliseconds LL_AVERAGED_PING_MIN(100); // increased to avoid retransmits when a process is slow
+
+const U32Milliseconds INITIAL_PING_VALUE_MSEC(1000); // initial value for the ping delay, or for ping delay for an unknown circuit
+
+const TPACKETID LL_MAX_OUT_PACKET_ID = 0x01000000;
+const int LL_ERR_CIRCUIT_GONE = -23017;
+const int LL_ERR_TCP_TIMEOUT = -23016;
+
+// 0 - flags
+// [1,4] - packetid
+// 5 - data offset (after message name)
+const U8 LL_PACKET_ID_SIZE = 6;
+
+const S32 LL_MAX_RESENT_PACKETS_PER_FRAME = 100;
+const S32 LL_MAX_ACKED_PACKETS_PER_FRAME = 200;
+const F32 LL_COLLECT_ACK_TIME_MAX = 2.f;
+
+//
+// Prototypes and Predefines
+//
+class LLMessageSystem;
+class LLEncodedDatagramService;
+class LLSD;
+
+//
+// Classes
+//
+
+
+class LLCircuitData
+{
+public:
+ LLCircuitData(const LLHost &host, TPACKETID in_id,
+ const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout);
+ ~LLCircuitData();
+
+ S32 resendUnackedPackets(const F64Seconds now);
+ void clearDuplicateList(TPACKETID oldest_id);
+
+
+ void dumpResendCountAndReset(); // Used for tracking how many resends are being done on a circuit.
+
+
+
+ // Public because stupid message system callbacks uses it.
+ void pingTimerStart();
+ void pingTimerStop(const U8 ping_id);
+ void ackReliablePacket(TPACKETID packet_num);
+
+ // remote computer information
+ const LLUUID& getRemoteID() const { return mRemoteID; }
+ const LLUUID& getRemoteSessionID() const { return mRemoteSessionID; }
+ void setRemoteID(const LLUUID& id) { mRemoteID = id; }
+ void setRemoteSessionID(const LLUUID& id) { mRemoteSessionID = id; }
+
+ void setTrusted(bool t);
+
+ // The local end point ID is used when establishing a trusted circuit.
+ // no matching set function for getLocalEndPointID()
+ // mLocalEndPointID should only ever be setup in the LLCircuitData constructor
+ const LLUUID& getLocalEndPointID() const { return mLocalEndPointID; }
+
+ U32Milliseconds getPingDelay() const;
+ S32 getPingsInTransit() const { return mPingsInTransit; }
+
+ // ACCESSORS
+ bool isAlive() const;
+ bool isBlocked() const;
+ bool getAllowTimeout() const;
+ F32Milliseconds getPingDelayAveraged();
+ F32Milliseconds getPingInTransitTime();
+ U32 getPacketsIn() const;
+ S32Bytes getBytesIn() const;
+ S32Bytes getBytesOut() const;
+ U32 getPacketsOut() const;
+ U32 getPacketsLost() const;
+ TPACKETID getPacketOutID() const;
+ bool getTrusted() const;
+ F32 getAgeInSeconds() const;
+ S32 getUnackedPacketCount() const { return mUnackedPacketCount; }
+ S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; }
+ F64Seconds getNextPingSendTime() const { return mNextPingSendTime; }
+ U32 getLastPacketGap() const { return mLastPacketGap; }
+ LLHost getHost() const { return mHost; }
+ F64Seconds getLastPacketInTime() const { return mLastPacketInTime; }
+
+ LLThrottleGroup &getThrottleGroup() { return mThrottles; }
+
+ class less
+ {
+ public:
+ bool operator()(const LLCircuitData* lhs, const LLCircuitData* rhs) const
+ {
+ if (lhs->getNextPingSendTime() < rhs->getNextPingSendTime())
+ {
+ return true;
+ }
+ else if (lhs->getNextPingSendTime() > rhs->getNextPingSendTime())
+ {
+ return false;
+ }
+ else return lhs > rhs;
+ }
+ };
+
+ //
+ // Debugging stuff (not necessary for operation)
+ //
+ void checkPeriodTime(); // Reset per-period counters if necessary.
+ friend std::ostream& operator<<(std::ostream& s, LLCircuitData &circuit);
+ void getInfo(LLSD& info) const;
+
+ friend class LLCircuit;
+ friend class LLMessageSystem;
+ friend class LLEncodedDatagramService;
+ friend void crash_on_spaceserver_timeout (const LLHost &host, void *); // HACK, so it has access to setAlive() so it can send a final shutdown message.
+protected:
+ TPACKETID nextPacketOutID();
+ void setPacketInID(TPACKETID id);
+ void checkPacketInID(TPACKETID id, bool receive_resent);
+ void setPingDelay(U32Milliseconds ping);
+ bool checkCircuitTimeout(); // Return false if the circuit is dead and should be cleaned up
+
+ void addBytesIn(S32Bytes bytes);
+ void addBytesOut(S32Bytes bytes);
+
+ U8 nextPingID() { mLastPingID++; return mLastPingID; }
+
+ bool updateWatchDogTimers(LLMessageSystem *msgsys); // Return false if the circuit is dead and should be cleaned up
+
+ void addReliablePacket(S32 mSocket, U8 *buf_ptr, S32 buf_len, LLReliablePacketParams *params);
+ bool isDuplicateResend(TPACKETID packetnum);
+ // Call this method when a reliable message comes in - this will
+ // correctly place the packet in the correct list to be acked
+ // later. RAack = requested ack
+ bool collectRAck(TPACKETID packet_num);
+
+
+ void setTimeoutCallback(void (*callback_func)(const LLHost &host, void *user_data), void *user_data);
+
+
+
+ void setAlive(bool b_alive);
+ void setAllowTimeout(bool allow);
+
+protected:
+ // Identification for this circuit.
+ LLHost mHost;
+ LLUUID mRemoteID;
+ LLUUID mRemoteSessionID;
+
+ LLThrottleGroup mThrottles;
+
+ TPACKETID mWrapID;
+
+ // Current packet IDs of incoming/outgoing packets
+ // Used for packet sequencing/packet loss detection.
+ TPACKETID mPacketsOutID;
+ TPACKETID mPacketsInID;
+ TPACKETID mHighestPacketID;
+
+
+ // Callback and data to run in the case of a circuit timeout.
+ // Used primarily to try and reconnect to servers if they crash/die.
+ void (*mTimeoutCallback)(const LLHost &host, void *user_data);
+ void *mTimeoutUserData;
+
+ bool mTrusted; // Is this circuit trusted?
+ bool mbAllowTimeout; // Machines can "pause" circuits, forcing them not to be dropped
+
+ bool mbAlive; // Indicates whether a circuit is "alive", i.e. responded to pings
+
+ bool mBlocked; // Blocked is true if the circuit is hosed, i.e. far behind on pings
+
+ // Not sure what the difference between this and mLastPingSendTime is
+ F64Seconds mPingTime; // Time at which a ping was sent.
+
+ F64Seconds mLastPingSendTime; // Time we last sent a ping
+ F64Seconds mLastPingReceivedTime; // Time we last received a ping
+ F64Seconds mNextPingSendTime; // Time to try and send the next ping
+ S32 mPingsInTransit; // Number of pings in transit
+ U8 mLastPingID; // ID of the last ping that we sent out
+
+
+ // Used for determining the resend time for reliable resends.
+ U32Milliseconds mPingDelay; // raw ping delay
+ F32Milliseconds mPingDelayAveraged; // averaged ping delay (fast attack/slow decay)
+
+ typedef std::map<TPACKETID, U64Microseconds> packet_time_map;
+
+ packet_time_map mPotentialLostPackets;
+ packet_time_map mRecentlyReceivedReliablePackets;
+ std::vector<TPACKETID> mAcks;
+ F32 mAckCreationTime; // first ack creation time
+
+ typedef std::map<TPACKETID, LLReliablePacket *> reliable_map;
+ typedef reliable_map::iterator reliable_iter;
+
+ reliable_map mUnackedPackets;
+ reliable_map mFinalRetryPackets;
+
+ S32 mUnackedPacketCount;
+ S32 mUnackedPacketBytes;
+
+ F64Seconds mLastPacketInTime; // Time of last packet arrival
+
+ LLUUID mLocalEndPointID;
+
+ //
+ // These variables are being used for statistical and debugging purpose ONLY,
+ // as far as I can tell.
+ //
+
+ U32 mPacketsOut;
+ U32 mPacketsIn;
+ S32 mPacketsLost;
+ S32Bytes mBytesIn,
+ mBytesOut;
+
+ F32Seconds mLastPeriodLength;
+ S32Bytes mBytesInLastPeriod;
+ S32Bytes mBytesOutLastPeriod;
+ S32Bytes mBytesInThisPeriod;
+ S32Bytes mBytesOutThisPeriod;
+ F32 mPeakBPSIn; // bits per second, max of all period bps
+ F32 mPeakBPSOut; // bits per second, max of all period bps
+ F64Seconds mPeriodTime;
+ LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers
+
+ S32 mCurrentResendCount; // Number of resent packets since last spam
+ U32 mLastPacketGap; // Gap in sequence number of last packet.
+
+ const F32Seconds mHeartbeatInterval;
+ const F32Seconds mHeartbeatTimeout;
+};
+
+
+// Actually a singleton class -- the global messagesystem
+// has a single LLCircuit member.
+class LLCircuit
+{
+public:
+ // CREATORS
+ LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout);
+ ~LLCircuit();
+
+ // ACCESSORS
+ LLCircuitData* findCircuit(const LLHost& host) const;
+ bool isCircuitAlive(const LLHost& host) const;
+
+ // MANIPULATORS
+ LLCircuitData *addCircuitData(const LLHost &host, TPACKETID in_id);
+ void removeCircuitData(const LLHost &host);
+
+ void updateWatchDogTimers(LLMessageSystem *msgsys);
+ void resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size);
+
+ // this method is called during the message system processAcks()
+ // to send out any acks that did not get sent already.
+ void sendAcks(F32 collect_time);
+
+ friend std::ostream& operator<<(std::ostream& s, LLCircuit &circuit);
+ void getInfo(LLSD& info) const;
+
+ void dumpResends();
+
+ typedef std::map<LLHost, LLCircuitData*> circuit_data_map;
+
+ /**
+ * @brief This method gets an iterator range starting after key in
+ * the circuit data map.
+ *
+ * @param key The the host before first.
+ * @param first[out] The first matching value after key. This
+ * value will equal end if there are no entries.
+ * @param end[out] The end of the iteration sequence.
+ */
+ void getCircuitRange(
+ const LLHost& key,
+ circuit_data_map::iterator& first,
+ circuit_data_map::iterator& end);
+
+ // Lists that optimize how many circuits we need to traverse a frame
+ // HACK - this should become protected eventually, but stupid !@$@# message system/circuit classes are jumbling things up.
+ circuit_data_map mUnackedCircuitMap; // Map of circuits with unacked data
+ circuit_data_map mSendAckMap; // Map of circuits which need to send acks
+protected:
+ circuit_data_map mCircuitData;
+
+ typedef std::set<LLCircuitData *, LLCircuitData::less> ping_set_t; // Circuits sorted by next ping time
+
+ ping_set_t mPingSet;
+
+ // This variable points to the last circuit data we found to
+ // optimize the many, many times we call findCircuit. This may be
+ // set in otherwise const methods, so it is declared mutable.
+ mutable LLCircuitData* mLastCircuit;
+
+private:
+ const F32Seconds mHeartbeatInterval;
+ const F32Seconds mHeartbeatTimeout;
+};
+#endif
diff --git a/indra/llmessage/llclassifiedflags.cpp b/indra/llmessage/llclassifiedflags.cpp index 748b6f2355..345942955c 100644 --- a/indra/llmessage/llclassifiedflags.cpp +++ b/indra/llmessage/llclassifiedflags.cpp @@ -1,84 +1,84 @@ -/** - * @file llclassifiedflags.cpp - * @brief - * - * $LicenseInfo:firstyear=2006&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$ - */ - -//***************************************************************************** -// llclassifiedflags.cpp -// -// Some exported symbols and functions for dealing with classified flags. -// -// Copyright 2005, Linden Research, Inc -//***************************************************************************** - -#include "linden_common.h" - -#include "llclassifiedflags.h" - -ClassifiedFlags pack_classified_flags_request(BOOL auto_renew, BOOL inc_pg, BOOL inc_mature, BOOL inc_adult) -{ - U8 rv = 0; - if(inc_pg) rv |= CLASSIFIED_QUERY_INC_PG; - if(inc_mature) rv |= CLASSIFIED_QUERY_INC_MATURE; - if (inc_pg && !inc_mature) rv |= CLASSIFIED_FLAG_MATURE; - if(inc_adult) rv |= CLASSIFIED_QUERY_INC_ADULT; - if(auto_renew) rv |= CLASSIFIED_FLAG_AUTO_RENEW; - return rv; -} - -ClassifiedFlags pack_classified_flags(BOOL auto_renew, BOOL inc_pg, BOOL inc_mature, BOOL inc_adult) -{ - U8 rv = 0; - if(inc_pg) rv |= CLASSIFIED_QUERY_INC_PG; - if(inc_mature) - { - rv |= CLASSIFIED_QUERY_INC_MATURE; - rv |= CLASSIFIED_FLAG_MATURE; - } - if(inc_adult) rv |= CLASSIFIED_QUERY_INC_ADULT; - if(auto_renew) rv |= CLASSIFIED_FLAG_AUTO_RENEW; - return rv; -} - -bool is_cf_mature(ClassifiedFlags flags) -{ - return ((flags & CLASSIFIED_FLAG_MATURE) != 0) || ((flags & CLASSIFIED_QUERY_INC_MATURE) != 0); -} - -// Deprecated, but leaving commented out because someday we might -// want to let users enable/disable classifieds. JC -//bool is_cf_enabled(ClassifiedFlags flags) -//{ -// return ((flags & CLASSIFIED_FLAG_ENABLED) == CLASSIFIED_FLAG_ENABLED); -//} - -bool is_cf_update_time(ClassifiedFlags flags) -{ - return ((flags & CLASSIFIED_FLAG_UPDATE_TIME) != 0); -} - -bool is_cf_auto_renew(ClassifiedFlags flags) -{ - return ((flags & CLASSIFIED_FLAG_AUTO_RENEW) != 0); -} +/**
+ * @file llclassifiedflags.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+//*****************************************************************************
+// llclassifiedflags.cpp
+//
+// Some exported symbols and functions for dealing with classified flags.
+//
+// Copyright 2005, Linden Research, Inc
+//*****************************************************************************
+
+#include "linden_common.h"
+
+#include "llclassifiedflags.h"
+
+ClassifiedFlags pack_classified_flags_request(bool auto_renew, bool inc_pg, bool inc_mature, bool inc_adult)
+{
+ U8 rv = 0;
+ if(inc_pg) rv |= CLASSIFIED_QUERY_INC_PG;
+ if(inc_mature) rv |= CLASSIFIED_QUERY_INC_MATURE;
+ if (inc_pg && !inc_mature) rv |= CLASSIFIED_FLAG_MATURE;
+ if(inc_adult) rv |= CLASSIFIED_QUERY_INC_ADULT;
+ if(auto_renew) rv |= CLASSIFIED_FLAG_AUTO_RENEW;
+ return rv;
+}
+
+ClassifiedFlags pack_classified_flags(bool auto_renew, bool inc_pg, bool inc_mature, bool inc_adult)
+{
+ U8 rv = 0;
+ if(inc_pg) rv |= CLASSIFIED_QUERY_INC_PG;
+ if(inc_mature)
+ {
+ rv |= CLASSIFIED_QUERY_INC_MATURE;
+ rv |= CLASSIFIED_FLAG_MATURE;
+ }
+ if(inc_adult) rv |= CLASSIFIED_QUERY_INC_ADULT;
+ if(auto_renew) rv |= CLASSIFIED_FLAG_AUTO_RENEW;
+ return rv;
+}
+
+bool is_cf_mature(ClassifiedFlags flags)
+{
+ return ((flags & CLASSIFIED_FLAG_MATURE) != 0) || ((flags & CLASSIFIED_QUERY_INC_MATURE) != 0);
+}
+
+// Deprecated, but leaving commented out because someday we might
+// want to let users enable/disable classifieds. JC
+//bool is_cf_enabled(ClassifiedFlags flags)
+//{
+// return ((flags & CLASSIFIED_FLAG_ENABLED) == CLASSIFIED_FLAG_ENABLED);
+//}
+
+bool is_cf_update_time(ClassifiedFlags flags)
+{
+ return ((flags & CLASSIFIED_FLAG_UPDATE_TIME) != 0);
+}
+
+bool is_cf_auto_renew(ClassifiedFlags flags)
+{
+ return ((flags & CLASSIFIED_FLAG_AUTO_RENEW) != 0);
+}
diff --git a/indra/llmessage/llclassifiedflags.h b/indra/llmessage/llclassifiedflags.h index 9c6c268b39..126b23340f 100644 --- a/indra/llmessage/llclassifiedflags.h +++ b/indra/llmessage/llclassifiedflags.h @@ -1,62 +1,62 @@ -/** - * @file llclassifiedflags.h - * @brief Flags used in the classifieds. - * - * $LicenseInfo:firstyear=2005&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$ - */ - -#ifndef LL_LLCLASSIFIEDFLAGS_H -#define LL_LLCLASSIFIEDFLAGS_H - -typedef U8 ClassifiedFlags; - -const U8 CLASSIFIED_FLAG_NONE = 1 << 0; -const U8 CLASSIFIED_FLAG_MATURE = 1 << 1; -//const U8 CLASSIFIED_FLAG_ENABLED = 1 << 2; // see llclassifiedflags.cpp -//const U8 CLASSIFIED_FLAG_HAS_PRICE= 1 << 3; // deprecated -const U8 CLASSIFIED_FLAG_UPDATE_TIME= 1 << 4; -const U8 CLASSIFIED_FLAG_AUTO_RENEW = 1 << 5; - -const U8 CLASSIFIED_QUERY_FILTER_MATURE = 1 << 1; -//const U8 CLASSIFIED_QUERY_FILTER_ENABLED = 1 << 2; -//const U8 CLASSIFIED_QUERY_FILTER_PRICE = 1 << 3; - -// These are new with Adult-enabled viewers (1.23 and later) -const U8 CLASSIFIED_QUERY_INC_PG = 1 << 2; -const U8 CLASSIFIED_QUERY_INC_MATURE = 1 << 3; -const U8 CLASSIFIED_QUERY_INC_ADULT = 1 << 6; -const U8 CLASSIFIED_QUERY_INC_NEW_VIEWER = (CLASSIFIED_QUERY_INC_PG | CLASSIFIED_QUERY_INC_MATURE | CLASSIFIED_QUERY_INC_ADULT); - -const S32 MAX_CLASSIFIEDS = 100; - -// This function is used in AO viewers to pack old query flags into the request -// so that they can talk to old dataservers properly. When the AO servers are deployed on agni -// we can revert back to ClassifiedFlags pack_classified_flags and get rider of this one. -ClassifiedFlags pack_classified_flags_request(BOOL auto_renew, BOOL is_pg, BOOL is_mature, BOOL is_adult); - -ClassifiedFlags pack_classified_flags(BOOL auto_renew, BOOL is_pg, BOOL is_mature, BOOL is_adult); -bool is_cf_mature(ClassifiedFlags flags); -//bool is_cf_enabled(ClassifiedFlags flags); -bool is_cf_update_time(ClassifiedFlags flags); -bool is_cf_auto_renew(ClassifiedFlags flags); - -#endif +/**
+ * @file llclassifiedflags.h
+ * @brief Flags used in the classifieds.
+ *
+ * $LicenseInfo:firstyear=2005&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$
+ */
+
+#ifndef LL_LLCLASSIFIEDFLAGS_H
+#define LL_LLCLASSIFIEDFLAGS_H
+
+typedef U8 ClassifiedFlags;
+
+const U8 CLASSIFIED_FLAG_NONE = 1 << 0;
+const U8 CLASSIFIED_FLAG_MATURE = 1 << 1;
+//const U8 CLASSIFIED_FLAG_ENABLED = 1 << 2; // see llclassifiedflags.cpp
+//const U8 CLASSIFIED_FLAG_HAS_PRICE= 1 << 3; // deprecated
+const U8 CLASSIFIED_FLAG_UPDATE_TIME= 1 << 4;
+const U8 CLASSIFIED_FLAG_AUTO_RENEW = 1 << 5;
+
+const U8 CLASSIFIED_QUERY_FILTER_MATURE = 1 << 1;
+//const U8 CLASSIFIED_QUERY_FILTER_ENABLED = 1 << 2;
+//const U8 CLASSIFIED_QUERY_FILTER_PRICE = 1 << 3;
+
+// These are new with Adult-enabled viewers (1.23 and later)
+const U8 CLASSIFIED_QUERY_INC_PG = 1 << 2;
+const U8 CLASSIFIED_QUERY_INC_MATURE = 1 << 3;
+const U8 CLASSIFIED_QUERY_INC_ADULT = 1 << 6;
+const U8 CLASSIFIED_QUERY_INC_NEW_VIEWER = (CLASSIFIED_QUERY_INC_PG | CLASSIFIED_QUERY_INC_MATURE | CLASSIFIED_QUERY_INC_ADULT);
+
+const S32 MAX_CLASSIFIEDS = 100;
+
+// This function is used in AO viewers to pack old query flags into the request
+// so that they can talk to old dataservers properly. When the AO servers are deployed on agni
+// we can revert back to ClassifiedFlags pack_classified_flags and get rider of this one.
+ClassifiedFlags pack_classified_flags_request(bool auto_renew, bool is_pg, bool is_mature, bool is_adult);
+
+ClassifiedFlags pack_classified_flags(bool auto_renew, bool is_pg, bool is_mature, bool is_adult);
+bool is_cf_mature(ClassifiedFlags flags);
+//bool is_cf_enabled(ClassifiedFlags flags);
+bool is_cf_update_time(ClassifiedFlags flags);
+bool is_cf_auto_renew(ClassifiedFlags flags);
+
+#endif
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index dcc0b59d07..7619b46fed 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llcorehttputil.cpp * @date 2014-08-25 * @brief Implementation of adapter and utility classes expanding the llcorehttp interfaces. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2014&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, 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$ */ @@ -35,8 +35,7 @@ #include "llsd.h" #include "llsdjson.h" #include "llsdserialize.h" -#include "json/reader.h" // JSON -#include "json/writer.h" // JSON +#include "boost/json.hpp" // Boost.Json #include "llfilesystem.h" #include "message.h" // for getting the port @@ -49,7 +48,7 @@ namespace LLCoreHttpUtil const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; -namespace +namespace { const std::string HTTP_LOGBODY_KEY("HTTPLogBodyOnError"); @@ -88,9 +87,9 @@ void logMessageFail(std::string logAuth, std::string url, std::string message) } //========================================================================= -/// The HttpRequestPumper is a utility class. When constructed it will poll the +/// The HttpRequestPumper is a utility class. When constructed it will poll the /// supplied HttpRequest once per frame until it is destroyed. -/// +/// class HttpRequestPumper { public: @@ -262,7 +261,7 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons LLCore::HttpStatus status = response->getStatus(); if (status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_HANDLE_NOT_FOUND)) - { // A response came in for a canceled request and we have not processed the + { // A response came in for a canceled request and we have not processed the // cancel yet. Patience! return; } @@ -274,9 +273,9 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons LLCore::HttpStatus::type_enum_t errType = status.getType(); LL_INFOS() - << "Possible failure [" << status.toTerseString() << "] cannot "<< response->getRequestMethod() + << "Possible failure [" << status.toTerseString() << "] cannot "<< response->getRequestMethod() << " url '" << response->getRequestURL() - << "' because " << status.toString() + << "' because " << status.toString() << LL_ENDL; if ((errType >= 400) && (errType < 500)) { @@ -361,13 +360,13 @@ void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::str } //========================================================================= -/// The HttpCoroLLSDHandler is a specialization of the LLCore::HttpHandler for -/// interacting with coroutines. When the request is completed the response +/// The HttpCoroLLSDHandler is a specialization of the LLCore::HttpHandler for +/// interacting with coroutines. When the request is completed the response /// will be posted onto the supplied Event Pump. -/// +/// /// If the LLSD retrieved from through the HTTP connection is not in the form /// of a LLSD::map it will be returned as in an llsd["content"] element. -/// +/// /// The LLSD posted back to the coroutine will have the following additions: /// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status /// +- ["status"] - The status code associated with the HTTP call @@ -375,7 +374,7 @@ void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::str /// +- ["type"] - The LLCore::HttpStatus type associted with the HTTP call /// +- ["url"] - The URL used to make the call. /// +- ["headers"] - A map of name name value pairs with the HTTP headers. -/// +/// class HttpCoroLLSDHandler : public HttpCoroHandler { public: @@ -391,7 +390,7 @@ HttpCoroLLSDHandler::HttpCoroLLSDHandler(LLEventStream &reply): HttpCoroHandler(reply) { } - + LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) { @@ -425,7 +424,7 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: #endif if (!success) - { + { #if 1 // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); @@ -441,13 +440,13 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: status = LLCore::HttpStatus(499, "Failed to deserialize LLSD."); } #endif - // If we've gotten to this point and the result LLSD is still undefined + // If we've gotten to this point and the result LLSD is still undefined // either there was an issue deserializing the body or the response was // blank. Create an empty map to hold the result either way. result = LLSD::emptyMap(); } else if (!result.isMap()) - { // The results are not themselves a map. Move them down so that + { // The results are not themselves a map. Move them down so that // this method can return a map to the caller. // *TODO: Should it always do this? LLSD newResult = LLSD::emptyMap(); @@ -477,13 +476,13 @@ LLSD HttpCoroLLSDHandler::parseBody(LLCore::HttpResponse *response, bool &succes //======================================================================== -/// The HttpCoroRawHandler is a specialization of the LLCore::HttpHandler for -/// interacting with coroutines. -/// -/// In addition to the normal "http_results" the returned LLSD will contain +/// The HttpCoroRawHandler is a specialization of the LLCore::HttpHandler for +/// interacting with coroutines. +/// +/// In addition to the normal "http_results" the returned LLSD will contain /// an entry keyed with "raw" containing the unprocessed results of the HTTP /// call. -/// +/// class HttpCoroRawHandler : public HttpCoroHandler { public: @@ -516,9 +515,9 @@ LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:: #if 1 // This is the slower implementation. It is safe vis-a-vi the const_cast<> and modification // of a LLSD managed array but contains an extra (potentially large) copy. - // + // // *TODO: https://jira.secondlife.com/browse/MAINT-5221 - + LLSD::Binary data; data.reserve(size); bas >> std::noskipws; @@ -527,12 +526,12 @@ LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:: result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = data; #else - // This is disabled because it's dangerous. See the other case for an + // This is disabled because it's dangerous. See the other case for an // alternate implementation. // We create a new LLSD::Binary object and assign it to the result map. - // The LLSD has created it's own copy so we retrieve it asBinary and const cast + // The LLSD has created it's own copy so we retrieve it asBinary and const cast // the reference so that we can modify it. - // *TODO: This is potentially dangerous... but I am trying to avoid a potentially + // *TODO: This is potentially dangerous... but I am trying to avoid a potentially // large copy. result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = LLSD::Binary(); LLSD::Binary &data = const_cast<LLSD::Binary &>( result[HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary() ); @@ -552,13 +551,13 @@ LLSD HttpCoroRawHandler::parseBody(LLCore::HttpResponse *response, bool &success } //======================================================================== -/// The HttpCoroJSONHandler is a specialization of the LLCore::HttpHandler for -/// interacting with coroutines. -/// -/// In addition to the normal "http_results" the returned LLSD will contain -/// JSON entries will be converted into an LLSD map. All results are considered +/// The HttpCoroJSONHandler is a specialization of the LLCore::HttpHandler for +/// interacting with coroutines. +/// +/// In addition to the normal "http_results" the returned LLSD will contain +/// JSON entries will be converted into an LLSD map. All results are considered /// strings -/// +/// class HttpCoroJSONHandler : public HttpCoroHandler { public: @@ -585,15 +584,12 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: } LLCore::BufferArrayStream bas(body); - Json::Value jsonRoot; - try - { - bas >> jsonRoot; - } - catch (std::runtime_error& e) + boost::json::error_code ec; + boost::json::value jsonRoot = boost::json::parse(bas, ec); + if(ec.failed()) { // deserialization failed. Record the reason and pass back an empty map for markup. - status = LLCore::HttpStatus(499, std::string(e.what())); + status = LLCore::HttpStatus(499, std::string(ec.what())); return result; } @@ -613,13 +609,10 @@ LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &succes } LLCore::BufferArrayStream bas(body); - Json::Value jsonRoot; - try - { - bas >> jsonRoot; - } - catch (std::runtime_error&) + boost::json::error_code ec; + boost::json::value jsonRoot = boost::json::parse(bas, ec); + if (ec.failed()) { success = false; return LLSD(); @@ -699,7 +692,7 @@ LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = requestPostWithLLSD(request, mPolicyId, url, body, options, headers, @@ -737,7 +730,7 @@ LLSD HttpCoroutineAdapter::postRawAndSuspend(LLCore::HttpRequest::ptr_t request, return postAndSuspend_(request, url, rawbody, options, headers, httpHandler); } -// *TODO: This functionality could be moved into the LLCore::Http library itself +// *TODO: This functionality could be moved into the LLCore::Http library itself // by having the CURL layer read the file directly. LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request, const std::string & url, std::string fileName, @@ -766,7 +759,7 @@ LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request return postAndSuspend(request, url, fileData, options, headers); } -// *TODO: This functionality could be moved into the LLCore::Http library itself +// *TODO: This functionality could be moved into the LLCore::Http library itself // by having the CURL layer read the file directly. LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request, const std::string & url, LLUUID assetId, LLAssetType::EType assetType, @@ -783,7 +776,7 @@ LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request U8* fileBuffer; fileBuffer = new U8[fileSize]; vfile.read(fileBuffer, fileSize); - + outs.write((char*)fileBuffer, fileSize); delete[] fileBuffer; } @@ -802,12 +795,12 @@ LLSD HttpCoroutineAdapter::postJsonAndSuspend(LLCore::HttpRequest::ptr_t request { LLCore::BufferArrayStream outs(rawbody.get()); - Json::Value root = LlsdToJson(body); - Json::FastWriter writer; + auto root = LlsdToJson(body); + std::string value = boost::json::serialize(root); - LL_WARNS("Http::post") << "JSON Generates: \"" << writer.write(root) << "\"" << LL_ENDL; + LL_WARNS("Http::post") << "JSON Generates: \"" << value << "\"" << LL_ENDL; - outs << writer.write(root); + outs << value; } return postAndSuspend_(request, url, rawbody, options, headers, httpHandler); @@ -823,7 +816,7 @@ LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = request->requestPost(mPolicyId, url, rawbody.get(), options, headers, handler); @@ -861,11 +854,11 @@ LLSD HttpCoroutineAdapter::putJsonAndSuspend(LLCore::HttpRequest::ptr_t request, { LLCore::BufferArrayStream outs(rawbody.get()); - Json::Value root = LlsdToJson(body); - Json::FastWriter writer; + auto root = LlsdToJson(body); + std::string value = boost::json::serialize(root); - LL_WARNS("Http::put") << "JSON Generates: \"" << writer.write(root) << "\"" << LL_ENDL; - outs << writer.write(root); + LL_WARNS("Http::put") << "JSON Generates: \"" << value << "\"" << LL_ENDL; + outs << value; } return putAndSuspend_(request, url, rawbody, options, headers, httpHandler); @@ -880,7 +873,7 @@ LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = requestPutWithLLSD(request, mPolicyId, url, body, options, headers, @@ -907,7 +900,7 @@ LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = request->requestPut(mPolicyId, url, rawbody.get(), options, headers, handler); @@ -957,13 +950,13 @@ LLSD HttpCoroutineAdapter::getJsonAndSuspend(LLCore::HttpRequest::ptr_t request, LLSD HttpCoroutineAdapter::getAndSuspend_(LLCore::HttpRequest::ptr_t &request, const std::string & url, - LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, + LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler) { HttpRequestPumper pumper(request); checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = request->requestGet(mPolicyId, url, options, headers, handler); @@ -992,7 +985,7 @@ LLSD HttpCoroutineAdapter::deleteAndSuspend(LLCore::HttpRequest::ptr_t request, } LLSD HttpCoroutineAdapter::deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request, - const std::string & url, + const std::string & url, LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) { LLEventStream replyPump(mAdapterName + "Reply", true); @@ -1003,13 +996,13 @@ LLSD HttpCoroutineAdapter::deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t reque LLSD HttpCoroutineAdapter::deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request, - const std::string & url, LLCore::HttpOptions::ptr_t &options, + const std::string & url, LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler) { HttpRequestPumper pumper(request); checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = request->requestDelete(mPolicyId, url, options, headers, handler); @@ -1046,7 +1039,7 @@ LLSD HttpCoroutineAdapter::patchAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = requestPatchWithLLSD(request, mPolicyId, url, body, options, headers, @@ -1080,7 +1073,7 @@ LLSD HttpCoroutineAdapter::copyAndSuspend(LLCore::HttpRequest::ptr_t request, LLSD HttpCoroutineAdapter::copyAndSuspend_(LLCore::HttpRequest::ptr_t &request, - const std::string & url, + const std::string & url, LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler) { @@ -1088,9 +1081,9 @@ LLSD HttpCoroutineAdapter::copyAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. - // + // LLCore::HttpHandle hhandle = request->requestCopy(mPolicyId, url, options, headers, handler); @@ -1130,9 +1123,9 @@ LLSD HttpCoroutineAdapter::moveAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. - // + // LLCore::HttpHandle hhandle = request->requestMove(mPolicyId, url, options, headers, handler); @@ -1181,7 +1174,7 @@ void HttpCoroutineAdapter::cancelSuspendedOperation() } } -void HttpCoroutineAdapter::saveState(LLCore::HttpHandle yieldingHandle, +void HttpCoroutineAdapter::saveState(LLCore::HttpHandle yieldingHandle, LLCore::HttpRequest::ptr_t &request, HttpCoroHandler::ptr_t &handler) { mWeakRequest = request; @@ -1197,15 +1190,15 @@ void HttpCoroutineAdapter::cleanState() } /*static*/ -LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, - const std::string &url) +LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, + const std::string &url) { LLCore::HttpStatus status = request->getStatus(); LL_WARNS("CoreHTTP") << "Error posting to " << url << " Status=" << status.getStatus() << " message = " << status.getMessage() << LL_ENDL; - // Mimic the status results returned from an http error that we had - // to wait on + // Mimic the status results returned from an http error that we had + // to wait on LLSD httpresults = LLSD::emptyMap(); HttpCoroHandler::writeStatusCodes(status, url, httpresults); @@ -1235,7 +1228,7 @@ void HttpCoroutineAdapter::callbackHttpGet(const std::string &url, LLCore::HttpR /*static*/ void HttpCoroutineAdapter::messageHttpGet(const std::string &url, const std::string &success, const std::string &failure) { - completionCallback_t cbSuccess = (success.empty()) ? NULL : + completionCallback_t cbSuccess = (success.empty()) ? NULL : static_cast<completionCallback_t>(boost::bind(&logMessageSuccess, "HttpCoroutineAdapter", url, success)); completionCallback_t cbFailure = (failure.empty()) ? NULL : static_cast<completionCallback_t>(boost::bind(&logMessageFail, "HttpCoroutineAdapter", url, failure)); @@ -1260,7 +1253,7 @@ void HttpCoroutineAdapter::trivialGetCoro(std::string url, LLCore::HttpRequest:: LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (!status) - { + { if (failure) { failure(httpResults); diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 71862b9aa4..e8cd11c0a0 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -1,2180 +1,2180 @@ -/** - * @file lldatapacker.cpp - * @brief Data packer implementation. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#include "linden_common.h" - -#include "lldatapacker.h" -#include "llerror.h" - -#include "message.h" - -#include "v4color.h" -#include "v4coloru.h" -#include "v2math.h" -#include "v3math.h" -#include "v4math.h" -#include "lluuid.h" - -// *NOTE: there are functions below which use sscanf and rely on this -// particular value of DP_BUFSIZE. Search for '511' (DP_BUFSIZE - 1) -// to find them if you change this number. -const S32 DP_BUFSIZE = 512; - -static char DUMMY_BUFFER[128]; /*Flawfinder: ignore*/ - -LLDataPacker::LLDataPacker() : mPassFlags(0), mWriteEnabled(FALSE) -{ -} - -//virtual -void LLDataPacker::reset() -{ - LL_ERRS() << "Using unimplemented datapacker reset!" << LL_ENDL; -} - -//virtual -void LLDataPacker::dumpBufferToLog() -{ - LL_ERRS() << "dumpBufferToLog not implemented for this type!" << LL_ENDL; -} - -BOOL LLDataPacker::packFixed(const F32 value, const char *name, - const BOOL is_signed, const U32 int_bits, const U32 frac_bits) -{ - BOOL success = TRUE; - S32 unsigned_bits = int_bits + frac_bits; - S32 total_bits = unsigned_bits; - - if (is_signed) - { - total_bits++; - } - - S32 min_val; - U32 max_val; - if (is_signed) - { - min_val = 1 << int_bits; - min_val *= -1; - } - else - { - min_val = 0; - } - max_val = 1 << int_bits; - - // Clamp to be within range - F32 fixed_val = llclamp(value, (F32)min_val, (F32)max_val); - if (is_signed) - { - fixed_val += max_val; - } - fixed_val *= 1 << frac_bits; - - if (total_bits <= 8) - { - packU8((U8)fixed_val, name); - } - else if (total_bits <= 16) - { - packU16((U16)fixed_val, name); - } - else if (total_bits <= 31) - { - packU32((U32)fixed_val, name); - } - else - { - LL_ERRS() << "Using fixed-point packing of " << total_bits << " bits, why?!" << LL_ENDL; - } - return success; -} - -BOOL LLDataPacker::unpackFixed(F32 &value, const char *name, - const BOOL is_signed, const U32 int_bits, const U32 frac_bits) -{ - BOOL success = TRUE; - //LL_INFOS() << "unpackFixed:" << name << " int:" << int_bits << " frac:" << frac_bits << LL_ENDL; - S32 unsigned_bits = int_bits + frac_bits; - S32 total_bits = unsigned_bits; - - if (is_signed) - { - total_bits++; - } - - U32 max_val; - max_val = 1 << int_bits; - - F32 fixed_val; - if (total_bits <= 8) - { - U8 fixed_8; - success = unpackU8(fixed_8, name); - fixed_val = (F32)fixed_8; - } - else if (total_bits <= 16) - { - U16 fixed_16; - success = unpackU16(fixed_16, name); - fixed_val = (F32)fixed_16; - } - else if (total_bits <= 31) - { - U32 fixed_32; - success = unpackU32(fixed_32, name); - fixed_val = (F32)fixed_32; - } - else - { - fixed_val = 0; - LL_ERRS() << "Bad bit count: " << total_bits << LL_ENDL; - } - - //LL_INFOS() << "Fixed_val:" << fixed_val << LL_ENDL; - - fixed_val /= (F32)(1 << frac_bits); - if (is_signed) - { - fixed_val -= max_val; - } - value = fixed_val; - //LL_INFOS() << "Value: " << value << LL_ENDL; - return success; -} - -BOOL LLDataPacker::unpackU16s(U16 *values, S32 count, const char *name) -{ - for (S32 idx = 0; idx < count; ++idx) - { - if (!unpackU16(values[idx], name)) - { - LL_WARNS("DATAPACKER") << "Buffer overflow reading Unsigned 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL; - return FALSE; - } - } - return TRUE; -} - -BOOL LLDataPacker::unpackS16s(S16 *values, S32 count, const char *name) -{ - for (S32 idx = 0; idx < count; ++idx) - { - if (!unpackS16(values[idx], name)) - { - LL_WARNS("DATAPACKER") << "Buffer overflow reading Signed 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL; - return FALSE; - } - } - return TRUE; -} - -BOOL LLDataPacker::unpackF32s(F32 *values, S32 count, const char *name) -{ - for (S32 idx = 0; idx < count; ++idx) - { - if (!unpackF32(values[idx], name)) - { - LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL; - return FALSE; - } - } - return TRUE; -} - -BOOL LLDataPacker::unpackColor4Us(LLColor4U *values, S32 count, const char *name) -{ - for (S32 idx = 0; idx < count; ++idx) - { - if (!unpackColor4U(values[idx], name)) - { - LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL; - return FALSE; - } - } - return TRUE; -} - -BOOL LLDataPacker::unpackUUIDs(LLUUID *values, S32 count, const char *name) -{ - for (S32 idx = 0; idx < count; ++idx) - { - if (!unpackUUID(values[idx], name)) - { - LL_WARNS("DATAPACKER") << "Buffer overflow reading UUIDs \"" << name << "\" at index " << idx << "!" << LL_ENDL; - return FALSE; - } - } - return TRUE; -} - -//--------------------------------------------------------------------------- -// LLDataPackerBinaryBuffer implementation -//--------------------------------------------------------------------------- - -BOOL LLDataPackerBinaryBuffer::packString(const std::string& value, const char *name) -{ - S32 length = value.length()+1; - - if (!verifyLength(length, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, value.c_str(), MVT_VARIABLE, length); - } - mCurBufferp += length; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackString(std::string& value, const char *name) -{ - S32 length = (S32)strlen((char *)mCurBufferp) + 1; /*Flawfinder: ignore*/ - - if (!verifyLength(length, name)) - { - return FALSE; - } - - value = std::string((char*)mCurBufferp); // We already assume NULL termination calling strlen() - - mCurBufferp += length; - return TRUE; -} - -BOOL LLDataPackerBinaryBuffer::packBinaryData(const U8 *value, S32 size, const char *name) -{ - if (!verifyLength(size + 4, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, &size, MVT_S32, 4); - } - mCurBufferp += 4; - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, value, MVT_VARIABLE, size); - } - mCurBufferp += size; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char *name) -{ - if (!verifyLength(4, name)) - { - LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData would unpack invalid data, aborting!" << LL_ENDL; - return FALSE; - } - - htolememcpy(&size, mCurBufferp, MVT_S32, 4); - - if (size < 0) - { - LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData unpacked invalid size, aborting!" << LL_ENDL; - return FALSE; - } - - mCurBufferp += 4; - - if (!verifyLength(size, name)) - { - LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData would unpack invalid data, aborting!" << LL_ENDL; - return FALSE; - } - - htolememcpy(value, mCurBufferp, MVT_VARIABLE, size); - mCurBufferp += size; - - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::packBinaryDataFixed(const U8 *value, S32 size, const char *name) -{ - if (!verifyLength(size, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, value, MVT_VARIABLE, size); - } - mCurBufferp += size; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) -{ - if (!verifyLength(size, name)) - { - return FALSE; - } - htolememcpy(value, mCurBufferp, MVT_VARIABLE, size); - mCurBufferp += size; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::packU8(const U8 value, const char *name) -{ - if (!verifyLength(sizeof(U8), name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - *mCurBufferp = value; - } - mCurBufferp++; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackU8(U8 &value, const char *name) -{ - if (!verifyLength(sizeof(U8), name)) - { - return FALSE; - } - - value = *mCurBufferp; - mCurBufferp++; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::packU16(const U16 value, const char *name) -{ - if (!verifyLength(sizeof(U16), name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, &value, MVT_U16, 2); - } - mCurBufferp += 2; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name) -{ - if (!verifyLength(sizeof(U16), name)) - { - return FALSE; - } - - htolememcpy(&value, mCurBufferp, MVT_U16, 2); - mCurBufferp += 2; - return TRUE; -} - -BOOL LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name) -{ - BOOL success = verifyLength(sizeof(S16), name); - - if (mWriteEnabled && success) - { - htolememcpy(mCurBufferp, &value, MVT_S16, 2); - } - mCurBufferp += 2; - return success; -} - -BOOL LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name) -{ - BOOL success = verifyLength(sizeof(S16), name); - - if (success) - { - htolememcpy(&value, mCurBufferp, MVT_S16, 2); - } - mCurBufferp += 2; - return success; -} - -BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name) -{ - if (!verifyLength(sizeof(U32), name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, &value, MVT_U32, 4); - } - mCurBufferp += 4; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackU32(U32 &value, const char *name) -{ - if (!verifyLength(sizeof(U32), name)) - { - return FALSE; - } - - htolememcpy(&value, mCurBufferp, MVT_U32, 4); - mCurBufferp += 4; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::packS32(const S32 value, const char *name) -{ - if (!verifyLength(sizeof(S32), name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, &value, MVT_S32, 4); - } - mCurBufferp += 4; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackS32(S32 &value, const char *name) -{ - if(!verifyLength(sizeof(S32), name)) - { - return FALSE; - } - - htolememcpy(&value, mCurBufferp, MVT_S32, 4); - mCurBufferp += 4; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::packF32(const F32 value, const char *name) -{ - if (!verifyLength(sizeof(F32), name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, &value, MVT_F32, 4); - } - mCurBufferp += 4; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackF32(F32 &value, const char *name) -{ - if (!verifyLength(sizeof(F32), name)) - { - return FALSE; - } - - htolememcpy(&value, mCurBufferp, MVT_F32, 4); - mCurBufferp += 4; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::packColor4(const LLColor4 &value, const char *name) -{ - if (!verifyLength(16, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); - } - mCurBufferp += 16; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackColor4(LLColor4 &value, const char *name) -{ - if (!verifyLength(16, name)) - { - return FALSE; - } - - htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); - mCurBufferp += 16; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::packColor4U(const LLColor4U &value, const char *name) -{ - if (!verifyLength(4, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, value.mV, MVT_VARIABLE, 4); - } - mCurBufferp += 4; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackColor4U(LLColor4U &value, const char *name) -{ - if (!verifyLength(4, name)) - { - return FALSE; - } - - htolememcpy(value.mV, mCurBufferp, MVT_VARIABLE, 4); - mCurBufferp += 4; - return TRUE; -} - - - -BOOL LLDataPackerBinaryBuffer::packVector2(const LLVector2 &value, const char *name) -{ - if (!verifyLength(8, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, &value.mV[0], MVT_F32, 4); - htolememcpy(mCurBufferp+4, &value.mV[1], MVT_F32, 4); - } - mCurBufferp += 8; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackVector2(LLVector2 &value, const char *name) -{ - if (!verifyLength(8, name)) - { - return FALSE; - } - - htolememcpy(&value.mV[0], mCurBufferp, MVT_F32, 4); - htolememcpy(&value.mV[1], mCurBufferp+4, MVT_F32, 4); - mCurBufferp += 8; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::packVector3(const LLVector3 &value, const char *name) -{ - if (!verifyLength(12, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, value.mV, MVT_LLVector3, 12); - } - mCurBufferp += 12; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackVector3(LLVector3 &value, const char *name) -{ - if (!verifyLength(12, name)) - { - return FALSE; - } - - htolememcpy(value.mV, mCurBufferp, MVT_LLVector3, 12); - mCurBufferp += 12; - return TRUE; -} - -BOOL LLDataPackerBinaryBuffer::packVector4(const LLVector4 &value, const char *name) -{ - if (!verifyLength(16, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); - } - mCurBufferp += 16; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackVector4(LLVector4 &value, const char *name) -{ - if (!verifyLength(16, name)) - { - return FALSE; - } - - htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); - mCurBufferp += 16; - return TRUE; -} - -BOOL LLDataPackerBinaryBuffer::packUUID(const LLUUID &value, const char *name) -{ - if (!verifyLength(16, name)) - { - return FALSE; - } - - if (mWriteEnabled) - { - htolememcpy(mCurBufferp, value.mData, MVT_LLUUID, 16); - } - mCurBufferp += 16; - return TRUE; -} - - -BOOL LLDataPackerBinaryBuffer::unpackUUID(LLUUID &value, const char *name) -{ - if (!verifyLength(16, name)) - { - return FALSE; - } - - htolememcpy(value.mData, mCurBufferp, MVT_LLUUID, 16); - mCurBufferp += 16; - return TRUE; -} - -const LLDataPackerBinaryBuffer& LLDataPackerBinaryBuffer::operator=(const LLDataPackerBinaryBuffer &a) -{ - if (a.getBufferSize() > getBufferSize()) - { - // We've got problems, ack! - LL_ERRS() << "Trying to do an assignment with not enough room in the target." << LL_ENDL; - } - memcpy(mBufferp, a.mBufferp, a.getBufferSize()); /*Flawfinder: ignore*/ - return *this; -} - -void LLDataPackerBinaryBuffer::dumpBufferToLog() -{ - LL_WARNS() << "Binary Buffer Dump, size: " << mBufferSize << LL_ENDL; - char line_buffer[256]; /*Flawfinder: ignore*/ - S32 i; - S32 cur_line_pos = 0; - - S32 cur_line = 0; - for (i = 0; i < mBufferSize; i++) - { - snprintf(line_buffer + cur_line_pos*3, sizeof(line_buffer) - cur_line_pos*3, "%02x ", mBufferp[i]); /* Flawfinder: ignore */ - cur_line_pos++; - if (cur_line_pos >= 16) - { - cur_line_pos = 0; - LL_WARNS() << "Offset:" << std::hex << cur_line*16 << std::dec << " Data:" << line_buffer << LL_ENDL; - cur_line++; - } - } - if (cur_line_pos) - { - LL_WARNS() << "Offset:" << std::hex << cur_line*16 << std::dec << " Data:" << line_buffer << LL_ENDL; - } -} - -//--------------------------------------------------------------------------- -// LLDataPackerAsciiBuffer implementation -//--------------------------------------------------------------------------- -BOOL LLDataPackerAsciiBuffer::packString(const std::string& value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%s\n", value.c_str()); /* Flawfinder: ignore */ - } - else - { - numCopied = value.length() + 1; /*Flawfinder: ignore*/ - } - - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - // *NOTE: I believe we need to mark a failure bit at this point. - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packString: string truncated: " << value << LL_ENDL; - } - mCurBufferp += numCopied; - return success; -} - -BOOL LLDataPackerAsciiBuffer::unpackString(std::string& value, const char *name) -{ - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore*/ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) // NULL terminated - { - return FALSE; - } - value = valuestr; - return TRUE; -} - - -BOOL LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%010d ", size); /* Flawfinder: ignore */ - - // snprintf returns number of bytes that would have been - // written had the output not being truncated. In that case, - // it will retuen >= passed in size value. so a check needs - // to be added to detect truncation, and if there is any, only - // account for the actual number of bytes written..and not - // what could have been written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: number truncated: " << size << LL_ENDL; - } - mCurBufferp += numCopied; - - - S32 i; - BOOL bBufferFull = FALSE; - for (i = 0; i < size && !bBufferFull; i++) - { - numCopied = snprintf(mCurBufferp, getBufferSize()-getCurrentSize(), "%02x ", value[i]); /* Flawfinder: ignore */ - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: data truncated: " << LL_ENDL; - bBufferFull = TRUE; - } - mCurBufferp += numCopied; - } - - if (!bBufferFull) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(), "\n"); /* Flawfinder: ignore */ - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: newline truncated: " << LL_ENDL; - } - mCurBufferp += numCopied; - } - } - else - { - // why +10 ?? XXXCHECK - numCopied = 10 + 1; // size plus newline - numCopied += size; - if (numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - } - mCurBufferp += numCopied; - } - - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackBinaryData(U8 *value, S32 &size, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - char *cur_pos = &valuestr[0]; - sscanf(valuestr,"%010d", &size); - cur_pos += 11; - - S32 i; - for (i = 0; i < size; i++) - { - S32 val; - sscanf(cur_pos,"%02x", &val); - value[i] = val; - cur_pos += 3; - } - return success; -} - - -BOOL LLDataPackerAsciiBuffer::packBinaryDataFixed(const U8 *value, S32 size, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - - if (mWriteEnabled) - { - S32 i; - int numCopied = 0; - BOOL bBufferFull = FALSE; - for (i = 0; i < size && !bBufferFull; i++) - { - numCopied = snprintf(mCurBufferp, getBufferSize()-getCurrentSize(), "%02x ", value[i]); /* Flawfinder: ignore */ - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryDataFixed: data truncated: " << LL_ENDL; - bBufferFull = TRUE; - } - mCurBufferp += numCopied; - - } - if (!bBufferFull) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(), "\n"); /* Flawfinder: ignore */ - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryDataFixed: newline truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - } - } - else - { - int numCopied = 2 * size + 1; //hex bytes plus newline - if (numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - } - mCurBufferp += numCopied; - } - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - char *cur_pos = &valuestr[0]; - - S32 i; - for (i = 0; i < size; i++) - { - S32 val; - sscanf(cur_pos,"%02x", &val); - value[i] = val; - cur_pos += 3; - } - return success; -} - - - -BOOL LLDataPackerAsciiBuffer::packU8(const U8 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%d\n", value); /* Flawfinder: ignore */ - } - else - { - // just do the write to a temp buffer to get the length - numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */ - } - - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packU8: val truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackU8(U8 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - S32 in_val; - sscanf(valuestr,"%d", &in_val); - value = in_val; - return success; -} - -BOOL LLDataPackerAsciiBuffer::packU16(const U16 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%d\n", value); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */ - } - - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packU16: val truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - S32 in_val; - sscanf(valuestr,"%d", &in_val); - value = in_val; - return success; -} - -BOOL LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp, getBufferSize() - getCurrentSize(), "%d\n", value); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */ - } - - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if(numCopied < 0 || numCopied > getBufferSize() - getCurrentSize()) - { - numCopied = getBufferSize() - getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packS16: val truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - S32 in_val; - sscanf(valuestr, "%d", &in_val); - value = in_val; - return success; -} - -BOOL LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%u\n", value); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%u\n", value); /* Flawfinder: ignore */ - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packU32: val truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackU32(U32 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%u", &value); - return success; -} - - -BOOL LLDataPackerAsciiBuffer::packS32(const S32 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%d\n", value); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */ - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packS32: val truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackS32(S32 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%d", &value); - return success; -} - - -BOOL LLDataPackerAsciiBuffer::packF32(const F32 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f\n", value); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%f\n", value); /* Flawfinder: ignore */ - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packF32: val truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackF32(F32 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f", &value); - return success; -} - - -BOOL LLDataPackerAsciiBuffer::packColor4(const LLColor4 &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */ - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packColor4: truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackColor4(LLColor4 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]); - return success; -} - -BOOL LLDataPackerAsciiBuffer::packColor4U(const LLColor4U &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%d %d %d %d\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%d %d %d %d\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */ - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packColor4U: truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackColor4U(LLColor4U &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - S32 r, g, b, a; - - sscanf(valuestr,"%d %d %d %d", &r, &g, &b, &a); - value.mV[0] = r; - value.mV[1] = g; - value.mV[2] = b; - value.mV[3] = a; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::packVector2(const LLVector2 &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f %f\n", value.mV[0], value.mV[1]); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%f %f\n", value.mV[0], value.mV[1]); /* Flawfinder: ignore */ - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packVector2: truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackVector2(LLVector2 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f %f", &value.mV[0], &value.mV[1]); - return success; -} - - -BOOL LLDataPackerAsciiBuffer::packVector3(const LLVector3 &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f %f %f\n", value.mV[0], value.mV[1], value.mV[2]); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%f %f %f\n", value.mV[0], value.mV[1], value.mV[2]); /* Flawfinder: ignore */ - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packVector3: truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackVector3(LLVector3 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f %f %f", &value.mV[0], &value.mV[1], &value.mV[2]); - return success; -} - -BOOL LLDataPackerAsciiBuffer::packVector4(const LLVector4 &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */ - } - else - { - numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */ - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packVector4: truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackVector4(LLVector4 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]); - return success; -} - - -BOOL LLDataPackerAsciiBuffer::packUUID(const LLUUID &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - - int numCopied = 0; - if (mWriteEnabled) - { - std::string tmp_str; - value.toString(tmp_str); - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%s\n", tmp_str.c_str()); /* Flawfinder: ignore */ - } - else - { - numCopied = 64 + 1; // UUID + newline - } - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::packUUID: truncated: " << LL_ENDL; - success = FALSE; - } - mCurBufferp += numCopied; - return success; -} - - -BOOL LLDataPackerAsciiBuffer::unpackUUID(LLUUID &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - char tmp_str[64]; /* Flawfinder: ignore */ - sscanf(valuestr, "%63s", tmp_str); /* Flawfinder: ignore */ - value.set(tmp_str); - - return success; -} - -void LLDataPackerAsciiBuffer::dump() -{ - LL_INFOS() << "Buffer: " << mBufferp << LL_ENDL; -} - -void LLDataPackerAsciiBuffer::writeIndentedName(const char *name) -{ - if (mIncludeNames) - { - int numCopied = 0; - if (mWriteEnabled) - { - numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%s\t", name); /* Flawfinder: ignore */ - } - else - { - numCopied = (S32)strlen(name) + 1; /* Flawfinder: ignore */ //name + tab - } - - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) - { - numCopied = getBufferSize()-getCurrentSize(); - LL_WARNS() << "LLDataPackerAsciiBuffer::writeIndentedName: truncated: " << LL_ENDL; - } - - mCurBufferp += numCopied; - } -} - -BOOL LLDataPackerAsciiBuffer::getValueStr(const char *name, char *out_value, S32 value_len) -{ - BOOL success = TRUE; - char buffer[DP_BUFSIZE]; /* Flawfinder: ignore */ - char keyword[DP_BUFSIZE]; /* Flawfinder: ignore */ - char value[DP_BUFSIZE]; /* Flawfinder: ignore */ - - buffer[0] = '\0'; - keyword[0] = '\0'; - value[0] = '\0'; - - if (mIncludeNames) - { - // Read both the name and the value, and validate the name. - sscanf(mCurBufferp, "%511[^\n]", buffer); - // Skip the \n - mCurBufferp += (S32)strlen(buffer) + 1; /* Flawfinder: ignore */ - - sscanf(buffer, "%511s %511[^\n]", keyword, value); /* Flawfinder: ignore */ - - if (strcmp(keyword, name)) - { - LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL; - return FALSE; - } - } - else - { - // Just the value exists - sscanf(mCurBufferp, "%511[^\n]", value); - // Skip the \n - mCurBufferp += (S32)strlen(value) + 1; /* Flawfinder: ignore */ - } - - S32 in_value_len = (S32)strlen(value)+1; /* Flawfinder: ignore */ - S32 min_len = llmin(in_value_len, value_len); - memcpy(out_value, value, min_len); /* Flawfinder: ignore */ - out_value[min_len-1] = 0; - - return success; -} - -// helper function used by LLDataPackerAsciiFile -// to convert F32 into a string. This is to avoid -// << operator writing F32 value into a stream -// since it does not seem to preserve the float value -std::string convertF32ToString(F32 val) -{ - std::string str; - char buf[20]; - snprintf(buf, 20, "%f", val); - str = buf; - return str; -} - -//--------------------------------------------------------------------------- -// LLDataPackerAsciiFile implementation -//--------------------------------------------------------------------------- -BOOL LLDataPackerAsciiFile::packString(const std::string& value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%s\n", value.c_str()); - } - else if (mOutputStream) - { - *mOutputStream << value << "\n"; - } - return success; -} - -BOOL LLDataPackerAsciiFile::unpackString(std::string& value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - value = valuestr; - return success; -} - - -BOOL LLDataPackerAsciiFile::packBinaryData(const U8 *value, S32 size, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - - if (mFP) - { - fprintf(mFP, "%010d ", size); - - S32 i; - for (i = 0; i < size; i++) - { - fprintf(mFP, "%02x ", value[i]); - } - fprintf(mFP, "\n"); - } - else if (mOutputStream) - { - char buffer[32]; /* Flawfinder: ignore */ - snprintf(buffer,sizeof(buffer), "%010d ", size); /* Flawfinder: ignore */ - *mOutputStream << buffer; - - S32 i; - for (i = 0; i < size; i++) - { - snprintf(buffer, sizeof(buffer), "%02x ", value[i]); /* Flawfinder: ignore */ - *mOutputStream << buffer; - } - *mOutputStream << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackBinaryData(U8 *value, S32 &size, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore*/ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - char *cur_pos = &valuestr[0]; - sscanf(valuestr,"%010d", &size); - cur_pos += 11; - - S32 i; - for (i = 0; i < size; i++) - { - S32 val; - sscanf(cur_pos,"%02x", &val); - value[i] = val; - cur_pos += 3; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::packBinaryDataFixed(const U8 *value, S32 size, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - - if (mFP) - { - S32 i; - for (i = 0; i < size; i++) - { - fprintf(mFP, "%02x ", value[i]); - } - fprintf(mFP, "\n"); - } - else if (mOutputStream) - { - char buffer[32]; /*Flawfinder: ignore*/ - S32 i; - for (i = 0; i < size; i++) - { - snprintf(buffer, sizeof(buffer), "%02x ", value[i]); /* Flawfinder: ignore */ - *mOutputStream << buffer; - } - *mOutputStream << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore*/ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - char *cur_pos = &valuestr[0]; - - S32 i; - for (i = 0; i < size; i++) - { - S32 val; - sscanf(cur_pos,"%02x", &val); - value[i] = val; - cur_pos += 3; - } - return success; -} - - - -BOOL LLDataPackerAsciiFile::packU8(const U8 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%d\n", value); - } - else if (mOutputStream) - { - // We have to cast this to an integer because streams serialize - // bytes as bytes - not as text. - *mOutputStream << (S32)value << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackU8(U8 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - S32 in_val; - sscanf(valuestr,"%d", &in_val); - value = in_val; - return success; -} - -BOOL LLDataPackerAsciiFile::packU16(const U16 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%d\n", value); - } - else if (mOutputStream) - { - *mOutputStream <<"" << value << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - S32 in_val; - sscanf(valuestr,"%d", &in_val); - value = in_val; - return success; -} - -BOOL LLDataPackerAsciiFile::packS16(const S16 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP, "%d\n", value); - } - else if (mOutputStream) - { - *mOutputStream << "" << value << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - S32 in_val; - sscanf(valuestr, "%d", &in_val); - value = in_val; - return success; -} - -BOOL LLDataPackerAsciiFile::packU32(const U32 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%u\n", value); - } - else if (mOutputStream) - { - *mOutputStream <<"" << value << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackU32(U32 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%u", &value); - return success; -} - - -BOOL LLDataPackerAsciiFile::packS32(const S32 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%d\n", value); - } - else if (mOutputStream) - { - *mOutputStream <<"" << value << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackS32(S32 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%d", &value); - return success; -} - - -BOOL LLDataPackerAsciiFile::packF32(const F32 value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%f\n", value); - } - else if (mOutputStream) - { - *mOutputStream <<"" << convertF32ToString(value) << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackF32(F32 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f", &value); - return success; -} - - -BOOL LLDataPackerAsciiFile::packColor4(const LLColor4 &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); - } - else if (mOutputStream) - { - *mOutputStream << convertF32ToString(value.mV[0]) << " " << convertF32ToString(value.mV[1]) << " " << convertF32ToString(value.mV[2]) << " " << convertF32ToString(value.mV[3]) << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackColor4(LLColor4 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]); - return success; -} - -BOOL LLDataPackerAsciiFile::packColor4U(const LLColor4U &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%d %d %d %d\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); - } - else if (mOutputStream) - { - *mOutputStream << (S32)(value.mV[0]) << " " << (S32)(value.mV[1]) << " " << (S32)(value.mV[2]) << " " << (S32)(value.mV[3]) << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackColor4U(LLColor4U &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - S32 r, g, b, a; - - sscanf(valuestr,"%d %d %d %d", &r, &g, &b, &a); - value.mV[0] = r; - value.mV[1] = g; - value.mV[2] = b; - value.mV[3] = a; - return success; -} - - -BOOL LLDataPackerAsciiFile::packVector2(const LLVector2 &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%f %f\n", value.mV[0], value.mV[1]); - } - else if (mOutputStream) - { - *mOutputStream << convertF32ToString(value.mV[0]) << " " << convertF32ToString(value.mV[1]) << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackVector2(LLVector2 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f %f", &value.mV[0], &value.mV[1]); - return success; -} - - -BOOL LLDataPackerAsciiFile::packVector3(const LLVector3 &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%f %f %f\n", value.mV[0], value.mV[1], value.mV[2]); - } - else if (mOutputStream) - { - *mOutputStream << convertF32ToString(value.mV[0]) << " " << convertF32ToString(value.mV[1]) << " " << convertF32ToString(value.mV[2]) << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackVector3(LLVector3 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f %f %f", &value.mV[0], &value.mV[1], &value.mV[2]); - return success; -} - -BOOL LLDataPackerAsciiFile::packVector4(const LLVector4 &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - if (mFP) - { - fprintf(mFP,"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); - } - else if (mOutputStream) - { - *mOutputStream << convertF32ToString(value.mV[0]) << " " << convertF32ToString(value.mV[1]) << " " << convertF32ToString(value.mV[2]) << " " << convertF32ToString(value.mV[3]) << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackVector4(LLVector4 &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]); - return success; -} - - -BOOL LLDataPackerAsciiFile::packUUID(const LLUUID &value, const char *name) -{ - BOOL success = TRUE; - writeIndentedName(name); - std::string tmp_str; - value.toString(tmp_str); - if (mFP) - { - fprintf(mFP,"%s\n", tmp_str.c_str()); - } - else if (mOutputStream) - { - *mOutputStream <<"" << tmp_str << "\n"; - } - return success; -} - - -BOOL LLDataPackerAsciiFile::unpackUUID(LLUUID &value, const char *name) -{ - BOOL success = TRUE; - char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ - if (!getValueStr(name, valuestr, DP_BUFSIZE)) - { - return FALSE; - } - - char tmp_str[64]; /*Flawfinder: ignore */ - sscanf(valuestr,"%63s",tmp_str); /* Flawfinder: ignore */ - value.set(tmp_str); - - return success; -} - - -void LLDataPackerAsciiFile::writeIndentedName(const char *name) -{ - std::string indent_buf; - indent_buf.reserve(mIndent+1); - - S32 i; - for(i = 0; i < mIndent; i++) - { - indent_buf[i] = '\t'; - } - indent_buf[i] = 0; - if (mFP) - { - fprintf(mFP,"%s%s\t",indent_buf.c_str(), name); - } - else if (mOutputStream) - { - *mOutputStream << indent_buf << name << "\t"; - } -} - -BOOL LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 value_len) -{ - BOOL success = FALSE; - char buffer[DP_BUFSIZE]; /*Flawfinder: ignore*/ - char keyword[DP_BUFSIZE]; /*Flawfinder: ignore*/ - char value[DP_BUFSIZE]; /*Flawfinder: ignore*/ - - buffer[0] = '\0'; - keyword[0] = '\0'; - value[0] = '\0'; - - if (mFP) - { - fpos_t last_pos; - if (0 != fgetpos(mFP, &last_pos)) // 0==success for fgetpos - { - LL_WARNS() << "Data packer failed to fgetpos" << LL_ENDL; - return FALSE; - } - - if (fgets(buffer, DP_BUFSIZE, mFP) == NULL) - { - buffer[0] = '\0'; - } - - sscanf(buffer, "%511s %511[^\n]", keyword, value); /* Flawfinder: ignore */ - - if (!keyword[0]) - { - LL_WARNS() << "Data packer could not get the keyword!" << LL_ENDL; - fsetpos(mFP, &last_pos); - return FALSE; - } - if (strcmp(keyword, name)) - { - LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL; - fsetpos(mFP, &last_pos); - return FALSE; - } - - S32 in_value_len = (S32)strlen(value)+1; /*Flawfinder: ignore*/ - S32 min_len = llmin(in_value_len, value_len); - memcpy(out_value, value, min_len); /*Flawfinder: ignore*/ - out_value[min_len-1] = 0; - success = TRUE; - } - else if (mInputStream) - { - mInputStream->getline(buffer, DP_BUFSIZE); - - sscanf(buffer, "%511s %511[^\n]", keyword, value); /* Flawfinder: ignore */ - if (!keyword[0]) - { - LL_WARNS() << "Data packer could not get the keyword!" << LL_ENDL; - return FALSE; - } - if (strcmp(keyword, name)) - { - LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL; - return FALSE; - } - - S32 in_value_len = (S32)strlen(value)+1; /*Flawfinder: ignore*/ - S32 min_len = llmin(in_value_len, value_len); - memcpy(out_value, value, min_len); /*Flawfinder: ignore*/ - out_value[min_len-1] = 0; - success = TRUE; - } - - return success; -} +/**
+ * @file lldatapacker.cpp
+ * @brief Data packer implementation.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include "linden_common.h"
+
+#include "lldatapacker.h"
+#include "llerror.h"
+
+#include "message.h"
+
+#include "v4color.h"
+#include "v4coloru.h"
+#include "v2math.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "lluuid.h"
+
+// *NOTE: there are functions below which use sscanf and rely on this
+// particular value of DP_BUFSIZE. Search for '511' (DP_BUFSIZE - 1)
+// to find them if you change this number.
+const S32 DP_BUFSIZE = 512;
+
+static char DUMMY_BUFFER[128]; /*Flawfinder: ignore*/
+
+LLDataPacker::LLDataPacker() : mPassFlags(0), mWriteEnabled(false)
+{
+}
+
+//virtual
+void LLDataPacker::reset()
+{
+ LL_ERRS() << "Using unimplemented datapacker reset!" << LL_ENDL;
+}
+
+//virtual
+void LLDataPacker::dumpBufferToLog()
+{
+ LL_ERRS() << "dumpBufferToLog not implemented for this type!" << LL_ENDL;
+}
+
+bool LLDataPacker::packFixed(const F32 value, const char *name,
+ const bool is_signed, const U32 int_bits, const U32 frac_bits)
+{
+ bool success = true;
+ S32 unsigned_bits = int_bits + frac_bits;
+ S32 total_bits = unsigned_bits;
+
+ if (is_signed)
+ {
+ total_bits++;
+ }
+
+ S32 min_val;
+ U32 max_val;
+ if (is_signed)
+ {
+ min_val = 1 << int_bits;
+ min_val *= -1;
+ }
+ else
+ {
+ min_val = 0;
+ }
+ max_val = 1 << int_bits;
+
+ // Clamp to be within range
+ F32 fixed_val = llclamp(value, (F32)min_val, (F32)max_val);
+ if (is_signed)
+ {
+ fixed_val += max_val;
+ }
+ fixed_val *= 1 << frac_bits;
+
+ if (total_bits <= 8)
+ {
+ packU8((U8)fixed_val, name);
+ }
+ else if (total_bits <= 16)
+ {
+ packU16((U16)fixed_val, name);
+ }
+ else if (total_bits <= 31)
+ {
+ packU32((U32)fixed_val, name);
+ }
+ else
+ {
+ LL_ERRS() << "Using fixed-point packing of " << total_bits << " bits, why?!" << LL_ENDL;
+ }
+ return success;
+}
+
+bool LLDataPacker::unpackFixed(F32 &value, const char *name,
+ const bool is_signed, const U32 int_bits, const U32 frac_bits)
+{
+ bool success = true;
+ //LL_INFOS() << "unpackFixed:" << name << " int:" << int_bits << " frac:" << frac_bits << LL_ENDL;
+ S32 unsigned_bits = int_bits + frac_bits;
+ S32 total_bits = unsigned_bits;
+
+ if (is_signed)
+ {
+ total_bits++;
+ }
+
+ U32 max_val;
+ max_val = 1 << int_bits;
+
+ F32 fixed_val;
+ if (total_bits <= 8)
+ {
+ U8 fixed_8;
+ success = unpackU8(fixed_8, name);
+ fixed_val = (F32)fixed_8;
+ }
+ else if (total_bits <= 16)
+ {
+ U16 fixed_16;
+ success = unpackU16(fixed_16, name);
+ fixed_val = (F32)fixed_16;
+ }
+ else if (total_bits <= 31)
+ {
+ U32 fixed_32;
+ success = unpackU32(fixed_32, name);
+ fixed_val = (F32)fixed_32;
+ }
+ else
+ {
+ fixed_val = 0;
+ LL_ERRS() << "Bad bit count: " << total_bits << LL_ENDL;
+ }
+
+ //LL_INFOS() << "Fixed_val:" << fixed_val << LL_ENDL;
+
+ fixed_val /= (F32)(1 << frac_bits);
+ if (is_signed)
+ {
+ fixed_val -= max_val;
+ }
+ value = fixed_val;
+ //LL_INFOS() << "Value: " << value << LL_ENDL;
+ return success;
+}
+
+bool LLDataPacker::unpackU16s(U16 *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackU16(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading Unsigned 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LLDataPacker::unpackS16s(S16 *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackS16(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading Signed 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LLDataPacker::unpackF32s(F32 *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackF32(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LLDataPacker::unpackColor4Us(LLColor4U *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackColor4U(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LLDataPacker::unpackUUIDs(LLUUID *values, S32 count, const char *name)
+{
+ for (S32 idx = 0; idx < count; ++idx)
+ {
+ if (!unpackUUID(values[idx], name))
+ {
+ LL_WARNS("DATAPACKER") << "Buffer overflow reading UUIDs \"" << name << "\" at index " << idx << "!" << LL_ENDL;
+ return false;
+ }
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+// LLDataPackerBinaryBuffer implementation
+//---------------------------------------------------------------------------
+
+bool LLDataPackerBinaryBuffer::packString(const std::string& value, const char *name)
+{
+ S32 length = value.length()+1;
+
+ if (!verifyLength(length, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, value.c_str(), MVT_VARIABLE, length);
+ }
+ mCurBufferp += length;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackString(std::string& value, const char *name)
+{
+ S32 length = (S32)strlen((char *)mCurBufferp) + 1; /*Flawfinder: ignore*/
+
+ if (!verifyLength(length, name))
+ {
+ return false;
+ }
+
+ value = std::string((char*)mCurBufferp); // We already assume NULL termination calling strlen()
+
+ mCurBufferp += length;
+ return true;
+}
+
+bool LLDataPackerBinaryBuffer::packBinaryData(const U8 *value, S32 size, const char *name)
+{
+ if (!verifyLength(size + 4, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, &size, MVT_S32, 4);
+ }
+ mCurBufferp += 4;
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, value, MVT_VARIABLE, size);
+ }
+ mCurBufferp += size;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char *name)
+{
+ if (!verifyLength(4, name))
+ {
+ LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData would unpack invalid data, aborting!" << LL_ENDL;
+ return false;
+ }
+
+ htolememcpy(&size, mCurBufferp, MVT_S32, 4);
+
+ if (size < 0)
+ {
+ LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData unpacked invalid size, aborting!" << LL_ENDL;
+ return false;
+ }
+
+ mCurBufferp += 4;
+
+ if (!verifyLength(size, name))
+ {
+ LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData would unpack invalid data, aborting!" << LL_ENDL;
+ return false;
+ }
+
+ htolememcpy(value, mCurBufferp, MVT_VARIABLE, size);
+ mCurBufferp += size;
+
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::packBinaryDataFixed(const U8 *value, S32 size, const char *name)
+{
+ if (!verifyLength(size, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, value, MVT_VARIABLE, size);
+ }
+ mCurBufferp += size;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const char *name)
+{
+ if (!verifyLength(size, name))
+ {
+ return false;
+ }
+ htolememcpy(value, mCurBufferp, MVT_VARIABLE, size);
+ mCurBufferp += size;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::packU8(const U8 value, const char *name)
+{
+ if (!verifyLength(sizeof(U8), name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ *mCurBufferp = value;
+ }
+ mCurBufferp++;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackU8(U8 &value, const char *name)
+{
+ if (!verifyLength(sizeof(U8), name))
+ {
+ return false;
+ }
+
+ value = *mCurBufferp;
+ mCurBufferp++;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::packU16(const U16 value, const char *name)
+{
+ if (!verifyLength(sizeof(U16), name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, &value, MVT_U16, 2);
+ }
+ mCurBufferp += 2;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name)
+{
+ if (!verifyLength(sizeof(U16), name))
+ {
+ return false;
+ }
+
+ htolememcpy(&value, mCurBufferp, MVT_U16, 2);
+ mCurBufferp += 2;
+ return true;
+}
+
+bool LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name)
+{
+ bool success = verifyLength(sizeof(S16), name);
+
+ if (mWriteEnabled && success)
+ {
+ htolememcpy(mCurBufferp, &value, MVT_S16, 2);
+ }
+ mCurBufferp += 2;
+ return success;
+}
+
+bool LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name)
+{
+ bool success = verifyLength(sizeof(S16), name);
+
+ if (success)
+ {
+ htolememcpy(&value, mCurBufferp, MVT_S16, 2);
+ }
+ mCurBufferp += 2;
+ return success;
+}
+
+bool LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name)
+{
+ if (!verifyLength(sizeof(U32), name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, &value, MVT_U32, 4);
+ }
+ mCurBufferp += 4;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackU32(U32 &value, const char *name)
+{
+ if (!verifyLength(sizeof(U32), name))
+ {
+ return false;
+ }
+
+ htolememcpy(&value, mCurBufferp, MVT_U32, 4);
+ mCurBufferp += 4;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::packS32(const S32 value, const char *name)
+{
+ if (!verifyLength(sizeof(S32), name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, &value, MVT_S32, 4);
+ }
+ mCurBufferp += 4;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackS32(S32 &value, const char *name)
+{
+ if(!verifyLength(sizeof(S32), name))
+ {
+ return false;
+ }
+
+ htolememcpy(&value, mCurBufferp, MVT_S32, 4);
+ mCurBufferp += 4;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::packF32(const F32 value, const char *name)
+{
+ if (!verifyLength(sizeof(F32), name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, &value, MVT_F32, 4);
+ }
+ mCurBufferp += 4;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackF32(F32 &value, const char *name)
+{
+ if (!verifyLength(sizeof(F32), name))
+ {
+ return false;
+ }
+
+ htolememcpy(&value, mCurBufferp, MVT_F32, 4);
+ mCurBufferp += 4;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::packColor4(const LLColor4 &value, const char *name)
+{
+ if (!verifyLength(16, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16);
+ }
+ mCurBufferp += 16;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackColor4(LLColor4 &value, const char *name)
+{
+ if (!verifyLength(16, name))
+ {
+ return false;
+ }
+
+ htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16);
+ mCurBufferp += 16;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::packColor4U(const LLColor4U &value, const char *name)
+{
+ if (!verifyLength(4, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, value.mV, MVT_VARIABLE, 4);
+ }
+ mCurBufferp += 4;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackColor4U(LLColor4U &value, const char *name)
+{
+ if (!verifyLength(4, name))
+ {
+ return false;
+ }
+
+ htolememcpy(value.mV, mCurBufferp, MVT_VARIABLE, 4);
+ mCurBufferp += 4;
+ return true;
+}
+
+
+
+bool LLDataPackerBinaryBuffer::packVector2(const LLVector2 &value, const char *name)
+{
+ if (!verifyLength(8, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, &value.mV[0], MVT_F32, 4);
+ htolememcpy(mCurBufferp+4, &value.mV[1], MVT_F32, 4);
+ }
+ mCurBufferp += 8;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackVector2(LLVector2 &value, const char *name)
+{
+ if (!verifyLength(8, name))
+ {
+ return false;
+ }
+
+ htolememcpy(&value.mV[0], mCurBufferp, MVT_F32, 4);
+ htolememcpy(&value.mV[1], mCurBufferp+4, MVT_F32, 4);
+ mCurBufferp += 8;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::packVector3(const LLVector3 &value, const char *name)
+{
+ if (!verifyLength(12, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, value.mV, MVT_LLVector3, 12);
+ }
+ mCurBufferp += 12;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackVector3(LLVector3 &value, const char *name)
+{
+ if (!verifyLength(12, name))
+ {
+ return false;
+ }
+
+ htolememcpy(value.mV, mCurBufferp, MVT_LLVector3, 12);
+ mCurBufferp += 12;
+ return true;
+}
+
+bool LLDataPackerBinaryBuffer::packVector4(const LLVector4 &value, const char *name)
+{
+ if (!verifyLength(16, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16);
+ }
+ mCurBufferp += 16;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackVector4(LLVector4 &value, const char *name)
+{
+ if (!verifyLength(16, name))
+ {
+ return false;
+ }
+
+ htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16);
+ mCurBufferp += 16;
+ return true;
+}
+
+bool LLDataPackerBinaryBuffer::packUUID(const LLUUID &value, const char *name)
+{
+ if (!verifyLength(16, name))
+ {
+ return false;
+ }
+
+ if (mWriteEnabled)
+ {
+ htolememcpy(mCurBufferp, value.mData, MVT_LLUUID, 16);
+ }
+ mCurBufferp += 16;
+ return true;
+}
+
+
+bool LLDataPackerBinaryBuffer::unpackUUID(LLUUID &value, const char *name)
+{
+ if (!verifyLength(16, name))
+ {
+ return false;
+ }
+
+ htolememcpy(value.mData, mCurBufferp, MVT_LLUUID, 16);
+ mCurBufferp += 16;
+ return true;
+}
+
+const LLDataPackerBinaryBuffer& LLDataPackerBinaryBuffer::operator=(const LLDataPackerBinaryBuffer &a)
+{
+ if (a.getBufferSize() > getBufferSize())
+ {
+ // We've got problems, ack!
+ LL_ERRS() << "Trying to do an assignment with not enough room in the target." << LL_ENDL;
+ }
+ memcpy(mBufferp, a.mBufferp, a.getBufferSize()); /*Flawfinder: ignore*/
+ return *this;
+}
+
+void LLDataPackerBinaryBuffer::dumpBufferToLog()
+{
+ LL_WARNS() << "Binary Buffer Dump, size: " << mBufferSize << LL_ENDL;
+ char line_buffer[256]; /*Flawfinder: ignore*/
+ S32 i;
+ S32 cur_line_pos = 0;
+
+ S32 cur_line = 0;
+ for (i = 0; i < mBufferSize; i++)
+ {
+ snprintf(line_buffer + cur_line_pos*3, sizeof(line_buffer) - cur_line_pos*3, "%02x ", mBufferp[i]); /* Flawfinder: ignore */
+ cur_line_pos++;
+ if (cur_line_pos >= 16)
+ {
+ cur_line_pos = 0;
+ LL_WARNS() << "Offset:" << std::hex << cur_line*16 << std::dec << " Data:" << line_buffer << LL_ENDL;
+ cur_line++;
+ }
+ }
+ if (cur_line_pos)
+ {
+ LL_WARNS() << "Offset:" << std::hex << cur_line*16 << std::dec << " Data:" << line_buffer << LL_ENDL;
+ }
+}
+
+//---------------------------------------------------------------------------
+// LLDataPackerAsciiBuffer implementation
+//---------------------------------------------------------------------------
+bool LLDataPackerAsciiBuffer::packString(const std::string& value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%s\n", value.c_str()); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = value.length() + 1; /*Flawfinder: ignore*/
+ }
+
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ // *NOTE: I believe we need to mark a failure bit at this point.
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packString: string truncated: " << value << LL_ENDL;
+ }
+ mCurBufferp += numCopied;
+ return success;
+}
+
+bool LLDataPackerAsciiBuffer::unpackString(std::string& value, const char *name)
+{
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore*/
+ if (!getValueStr(name, valuestr, DP_BUFSIZE)) // NULL terminated
+ {
+ return false;
+ }
+ value = valuestr;
+ return true;
+}
+
+
+bool LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%010d ", size); /* Flawfinder: ignore */
+
+ // snprintf returns number of bytes that would have been
+ // written had the output not being truncated. In that case,
+ // it will retuen >= passed in size value. so a check needs
+ // to be added to detect truncation, and if there is any, only
+ // account for the actual number of bytes written..and not
+ // what could have been written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: number truncated: " << size << LL_ENDL;
+ }
+ mCurBufferp += numCopied;
+
+
+ S32 i;
+ bool bBufferFull = false;
+ for (i = 0; i < size && !bBufferFull; i++)
+ {
+ numCopied = snprintf(mCurBufferp, getBufferSize()-getCurrentSize(), "%02x ", value[i]); /* Flawfinder: ignore */
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: data truncated: " << LL_ENDL;
+ bBufferFull = true;
+ }
+ mCurBufferp += numCopied;
+ }
+
+ if (!bBufferFull)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(), "\n"); /* Flawfinder: ignore */
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: newline truncated: " << LL_ENDL;
+ }
+ mCurBufferp += numCopied;
+ }
+ }
+ else
+ {
+ // why +10 ?? XXXCHECK
+ numCopied = 10 + 1; // size plus newline
+ numCopied += size;
+ if (numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ }
+ mCurBufferp += numCopied;
+ }
+
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackBinaryData(U8 *value, S32 &size, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ char *cur_pos = &valuestr[0];
+ sscanf(valuestr,"%010d", &size);
+ cur_pos += 11;
+
+ S32 i;
+ for (i = 0; i < size; i++)
+ {
+ S32 val;
+ sscanf(cur_pos,"%02x", &val);
+ value[i] = val;
+ cur_pos += 3;
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::packBinaryDataFixed(const U8 *value, S32 size, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+
+ if (mWriteEnabled)
+ {
+ S32 i;
+ int numCopied = 0;
+ bool bBufferFull = false;
+ for (i = 0; i < size && !bBufferFull; i++)
+ {
+ numCopied = snprintf(mCurBufferp, getBufferSize()-getCurrentSize(), "%02x ", value[i]); /* Flawfinder: ignore */
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryDataFixed: data truncated: " << LL_ENDL;
+ bBufferFull = true;
+ }
+ mCurBufferp += numCopied;
+
+ }
+ if (!bBufferFull)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(), "\n"); /* Flawfinder: ignore */
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryDataFixed: newline truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ }
+ }
+ else
+ {
+ int numCopied = 2 * size + 1; //hex bytes plus newline
+ if (numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ }
+ mCurBufferp += numCopied;
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ char *cur_pos = &valuestr[0];
+
+ S32 i;
+ for (i = 0; i < size; i++)
+ {
+ S32 val;
+ sscanf(cur_pos,"%02x", &val);
+ value[i] = val;
+ cur_pos += 3;
+ }
+ return success;
+}
+
+
+
+bool LLDataPackerAsciiBuffer::packU8(const U8 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%d\n", value); /* Flawfinder: ignore */
+ }
+ else
+ {
+ // just do the write to a temp buffer to get the length
+ numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */
+ }
+
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packU8: val truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackU8(U8 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ S32 in_val;
+ sscanf(valuestr,"%d", &in_val);
+ value = in_val;
+ return success;
+}
+
+bool LLDataPackerAsciiBuffer::packU16(const U16 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%d\n", value); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */
+ }
+
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packU16: val truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ S32 in_val;
+ sscanf(valuestr,"%d", &in_val);
+ value = in_val;
+ return success;
+}
+
+bool LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp, getBufferSize() - getCurrentSize(), "%d\n", value); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */
+ }
+
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if(numCopied < 0 || numCopied > getBufferSize() - getCurrentSize())
+ {
+ numCopied = getBufferSize() - getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packS16: val truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ S32 in_val;
+ sscanf(valuestr, "%d", &in_val);
+ value = in_val;
+ return success;
+}
+
+bool LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%u\n", value); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%u\n", value); /* Flawfinder: ignore */
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packU32: val truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackU32(U32 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%u", &value);
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::packS32(const S32 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%d\n", value); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packS32: val truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackS32(S32 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%d", &value);
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::packF32(const F32 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f\n", value); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%f\n", value); /* Flawfinder: ignore */
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packF32: val truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackF32(F32 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f", &value);
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::packColor4(const LLColor4 &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packColor4: truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackColor4(LLColor4 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]);
+ return success;
+}
+
+bool LLDataPackerAsciiBuffer::packColor4U(const LLColor4U &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%d %d %d %d\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%d %d %d %d\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packColor4U: truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackColor4U(LLColor4U &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ S32 r, g, b, a;
+
+ sscanf(valuestr,"%d %d %d %d", &r, &g, &b, &a);
+ value.mV[0] = r;
+ value.mV[1] = g;
+ value.mV[2] = b;
+ value.mV[3] = a;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::packVector2(const LLVector2 &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f %f\n", value.mV[0], value.mV[1]); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%f %f\n", value.mV[0], value.mV[1]); /* Flawfinder: ignore */
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packVector2: truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackVector2(LLVector2 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f %f", &value.mV[0], &value.mV[1]);
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::packVector3(const LLVector3 &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f %f %f\n", value.mV[0], value.mV[1], value.mV[2]); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%f %f %f\n", value.mV[0], value.mV[1], value.mV[2]); /* Flawfinder: ignore */
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packVector3: truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackVector3(LLVector3 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f %f %f", &value.mV[0], &value.mV[1], &value.mV[2]);
+ return success;
+}
+
+bool LLDataPackerAsciiBuffer::packVector4(const LLVector4 &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = snprintf(DUMMY_BUFFER,sizeof(DUMMY_BUFFER),"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]); /* Flawfinder: ignore */
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packVector4: truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackVector4(LLVector4 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]);
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::packUUID(const LLUUID &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ std::string tmp_str;
+ value.toString(tmp_str);
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%s\n", tmp_str.c_str()); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = 64 + 1; // UUID + newline
+ }
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::packUUID: truncated: " << LL_ENDL;
+ success = false;
+ }
+ mCurBufferp += numCopied;
+ return success;
+}
+
+
+bool LLDataPackerAsciiBuffer::unpackUUID(LLUUID &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ char tmp_str[64]; /* Flawfinder: ignore */
+ sscanf(valuestr, "%63s", tmp_str); /* Flawfinder: ignore */
+ value.set(tmp_str);
+
+ return success;
+}
+
+void LLDataPackerAsciiBuffer::dump()
+{
+ LL_INFOS() << "Buffer: " << mBufferp << LL_ENDL;
+}
+
+void LLDataPackerAsciiBuffer::writeIndentedName(const char *name)
+{
+ if (mIncludeNames)
+ {
+ int numCopied = 0;
+ if (mWriteEnabled)
+ {
+ numCopied = snprintf(mCurBufferp,getBufferSize()-getCurrentSize(),"%s\t", name); /* Flawfinder: ignore */
+ }
+ else
+ {
+ numCopied = (S32)strlen(name) + 1; /* Flawfinder: ignore */ //name + tab
+ }
+
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize())
+ {
+ numCopied = getBufferSize()-getCurrentSize();
+ LL_WARNS() << "LLDataPackerAsciiBuffer::writeIndentedName: truncated: " << LL_ENDL;
+ }
+
+ mCurBufferp += numCopied;
+ }
+}
+
+bool LLDataPackerAsciiBuffer::getValueStr(const char *name, char *out_value, S32 value_len)
+{
+ bool success = true;
+ char buffer[DP_BUFSIZE]; /* Flawfinder: ignore */
+ char keyword[DP_BUFSIZE]; /* Flawfinder: ignore */
+ char value[DP_BUFSIZE]; /* Flawfinder: ignore */
+
+ buffer[0] = '\0';
+ keyword[0] = '\0';
+ value[0] = '\0';
+
+ if (mIncludeNames)
+ {
+ // Read both the name and the value, and validate the name.
+ sscanf(mCurBufferp, "%511[^\n]", buffer);
+ // Skip the \n
+ mCurBufferp += (S32)strlen(buffer) + 1; /* Flawfinder: ignore */
+
+ sscanf(buffer, "%511s %511[^\n]", keyword, value); /* Flawfinder: ignore */
+
+ if (strcmp(keyword, name))
+ {
+ LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ // Just the value exists
+ sscanf(mCurBufferp, "%511[^\n]", value);
+ // Skip the \n
+ mCurBufferp += (S32)strlen(value) + 1; /* Flawfinder: ignore */
+ }
+
+ S32 in_value_len = (S32)strlen(value)+1; /* Flawfinder: ignore */
+ S32 min_len = llmin(in_value_len, value_len);
+ memcpy(out_value, value, min_len); /* Flawfinder: ignore */
+ out_value[min_len-1] = 0;
+
+ return success;
+}
+
+// helper function used by LLDataPackerAsciiFile
+// to convert F32 into a string. This is to avoid
+// << operator writing F32 value into a stream
+// since it does not seem to preserve the float value
+std::string convertF32ToString(F32 val)
+{
+ std::string str;
+ char buf[20];
+ snprintf(buf, 20, "%f", val);
+ str = buf;
+ return str;
+}
+
+//---------------------------------------------------------------------------
+// LLDataPackerAsciiFile implementation
+//---------------------------------------------------------------------------
+bool LLDataPackerAsciiFile::packString(const std::string& value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%s\n", value.c_str());
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << value << "\n";
+ }
+ return success;
+}
+
+bool LLDataPackerAsciiFile::unpackString(std::string& value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+ value = valuestr;
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::packBinaryData(const U8 *value, S32 size, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+
+ if (mFP)
+ {
+ fprintf(mFP, "%010d ", size);
+
+ S32 i;
+ for (i = 0; i < size; i++)
+ {
+ fprintf(mFP, "%02x ", value[i]);
+ }
+ fprintf(mFP, "\n");
+ }
+ else if (mOutputStream)
+ {
+ char buffer[32]; /* Flawfinder: ignore */
+ snprintf(buffer,sizeof(buffer), "%010d ", size); /* Flawfinder: ignore */
+ *mOutputStream << buffer;
+
+ S32 i;
+ for (i = 0; i < size; i++)
+ {
+ snprintf(buffer, sizeof(buffer), "%02x ", value[i]); /* Flawfinder: ignore */
+ *mOutputStream << buffer;
+ }
+ *mOutputStream << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackBinaryData(U8 *value, S32 &size, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore*/
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ char *cur_pos = &valuestr[0];
+ sscanf(valuestr,"%010d", &size);
+ cur_pos += 11;
+
+ S32 i;
+ for (i = 0; i < size; i++)
+ {
+ S32 val;
+ sscanf(cur_pos,"%02x", &val);
+ value[i] = val;
+ cur_pos += 3;
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::packBinaryDataFixed(const U8 *value, S32 size, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+
+ if (mFP)
+ {
+ S32 i;
+ for (i = 0; i < size; i++)
+ {
+ fprintf(mFP, "%02x ", value[i]);
+ }
+ fprintf(mFP, "\n");
+ }
+ else if (mOutputStream)
+ {
+ char buffer[32]; /*Flawfinder: ignore*/
+ S32 i;
+ for (i = 0; i < size; i++)
+ {
+ snprintf(buffer, sizeof(buffer), "%02x ", value[i]); /* Flawfinder: ignore */
+ *mOutputStream << buffer;
+ }
+ *mOutputStream << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackBinaryDataFixed(U8 *value, S32 size, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore*/
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ char *cur_pos = &valuestr[0];
+
+ S32 i;
+ for (i = 0; i < size; i++)
+ {
+ S32 val;
+ sscanf(cur_pos,"%02x", &val);
+ value[i] = val;
+ cur_pos += 3;
+ }
+ return success;
+}
+
+
+
+bool LLDataPackerAsciiFile::packU8(const U8 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%d\n", value);
+ }
+ else if (mOutputStream)
+ {
+ // We have to cast this to an integer because streams serialize
+ // bytes as bytes - not as text.
+ *mOutputStream << (S32)value << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackU8(U8 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ S32 in_val;
+ sscanf(valuestr,"%d", &in_val);
+ value = in_val;
+ return success;
+}
+
+bool LLDataPackerAsciiFile::packU16(const U16 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%d\n", value);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream <<"" << value << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ S32 in_val;
+ sscanf(valuestr,"%d", &in_val);
+ value = in_val;
+ return success;
+}
+
+bool LLDataPackerAsciiFile::packS16(const S16 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP, "%d\n", value);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << "" << value << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ S32 in_val;
+ sscanf(valuestr, "%d", &in_val);
+ value = in_val;
+ return success;
+}
+
+bool LLDataPackerAsciiFile::packU32(const U32 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%u\n", value);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream <<"" << value << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackU32(U32 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%u", &value);
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::packS32(const S32 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%d\n", value);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream <<"" << value << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackS32(S32 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%d", &value);
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::packF32(const F32 value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%f\n", value);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream <<"" << convertF32ToString(value) << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackF32(F32 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f", &value);
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::packColor4(const LLColor4 &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << convertF32ToString(value.mV[0]) << " " << convertF32ToString(value.mV[1]) << " " << convertF32ToString(value.mV[2]) << " " << convertF32ToString(value.mV[3]) << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackColor4(LLColor4 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]);
+ return success;
+}
+
+bool LLDataPackerAsciiFile::packColor4U(const LLColor4U &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%d %d %d %d\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << (S32)(value.mV[0]) << " " << (S32)(value.mV[1]) << " " << (S32)(value.mV[2]) << " " << (S32)(value.mV[3]) << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackColor4U(LLColor4U &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ S32 r, g, b, a;
+
+ sscanf(valuestr,"%d %d %d %d", &r, &g, &b, &a);
+ value.mV[0] = r;
+ value.mV[1] = g;
+ value.mV[2] = b;
+ value.mV[3] = a;
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::packVector2(const LLVector2 &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%f %f\n", value.mV[0], value.mV[1]);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << convertF32ToString(value.mV[0]) << " " << convertF32ToString(value.mV[1]) << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackVector2(LLVector2 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f %f", &value.mV[0], &value.mV[1]);
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::packVector3(const LLVector3 &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%f %f %f\n", value.mV[0], value.mV[1], value.mV[2]);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << convertF32ToString(value.mV[0]) << " " << convertF32ToString(value.mV[1]) << " " << convertF32ToString(value.mV[2]) << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackVector3(LLVector3 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f %f %f", &value.mV[0], &value.mV[1], &value.mV[2]);
+ return success;
+}
+
+bool LLDataPackerAsciiFile::packVector4(const LLVector4 &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ if (mFP)
+ {
+ fprintf(mFP,"%f %f %f %f\n", value.mV[0], value.mV[1], value.mV[2], value.mV[3]);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << convertF32ToString(value.mV[0]) << " " << convertF32ToString(value.mV[1]) << " " << convertF32ToString(value.mV[2]) << " " << convertF32ToString(value.mV[3]) << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackVector4(LLVector4 &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]);
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::packUUID(const LLUUID &value, const char *name)
+{
+ bool success = true;
+ writeIndentedName(name);
+ std::string tmp_str;
+ value.toString(tmp_str);
+ if (mFP)
+ {
+ fprintf(mFP,"%s\n", tmp_str.c_str());
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream <<"" << tmp_str << "\n";
+ }
+ return success;
+}
+
+
+bool LLDataPackerAsciiFile::unpackUUID(LLUUID &value, const char *name)
+{
+ bool success = true;
+ char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
+ if (!getValueStr(name, valuestr, DP_BUFSIZE))
+ {
+ return false;
+ }
+
+ char tmp_str[64]; /*Flawfinder: ignore */
+ sscanf(valuestr,"%63s",tmp_str); /* Flawfinder: ignore */
+ value.set(tmp_str);
+
+ return success;
+}
+
+
+void LLDataPackerAsciiFile::writeIndentedName(const char *name)
+{
+ std::string indent_buf;
+ indent_buf.reserve(mIndent+1);
+
+ S32 i;
+ for(i = 0; i < mIndent; i++)
+ {
+ indent_buf[i] = '\t';
+ }
+ indent_buf[i] = 0;
+ if (mFP)
+ {
+ fprintf(mFP,"%s%s\t",indent_buf.c_str(), name);
+ }
+ else if (mOutputStream)
+ {
+ *mOutputStream << indent_buf << name << "\t";
+ }
+}
+
+bool LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 value_len)
+{
+ bool success = false;
+ char buffer[DP_BUFSIZE]; /*Flawfinder: ignore*/
+ char keyword[DP_BUFSIZE]; /*Flawfinder: ignore*/
+ char value[DP_BUFSIZE]; /*Flawfinder: ignore*/
+
+ buffer[0] = '\0';
+ keyword[0] = '\0';
+ value[0] = '\0';
+
+ if (mFP)
+ {
+ fpos_t last_pos;
+ if (0 != fgetpos(mFP, &last_pos)) // 0==success for fgetpos
+ {
+ LL_WARNS() << "Data packer failed to fgetpos" << LL_ENDL;
+ return false;
+ }
+
+ if (fgets(buffer, DP_BUFSIZE, mFP) == NULL)
+ {
+ buffer[0] = '\0';
+ }
+
+ sscanf(buffer, "%511s %511[^\n]", keyword, value); /* Flawfinder: ignore */
+
+ if (!keyword[0])
+ {
+ LL_WARNS() << "Data packer could not get the keyword!" << LL_ENDL;
+ fsetpos(mFP, &last_pos);
+ return false;
+ }
+ if (strcmp(keyword, name))
+ {
+ LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL;
+ fsetpos(mFP, &last_pos);
+ return false;
+ }
+
+ S32 in_value_len = (S32)strlen(value)+1; /*Flawfinder: ignore*/
+ S32 min_len = llmin(in_value_len, value_len);
+ memcpy(out_value, value, min_len); /*Flawfinder: ignore*/
+ out_value[min_len-1] = 0;
+ success = true;
+ }
+ else if (mInputStream)
+ {
+ mInputStream->getline(buffer, DP_BUFSIZE);
+
+ sscanf(buffer, "%511s %511[^\n]", keyword, value); /* Flawfinder: ignore */
+ if (!keyword[0])
+ {
+ LL_WARNS() << "Data packer could not get the keyword!" << LL_ENDL;
+ return false;
+ }
+ if (strcmp(keyword, name))
+ {
+ LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL;
+ return false;
+ }
+
+ S32 in_value_len = (S32)strlen(value)+1; /*Flawfinder: ignore*/
+ S32 min_len = llmin(in_value_len, value_len);
+ memcpy(out_value, value, min_len); /*Flawfinder: ignore*/
+ out_value[min_len-1] = 0;
+ success = true;
+ }
+
+ return success;
+}
diff --git a/indra/llmessage/lldatapacker.h b/indra/llmessage/lldatapacker.h index 9869326c12..5c896d28fc 100644 --- a/indra/llmessage/lldatapacker.h +++ b/indra/llmessage/lldatapacker.h @@ -1,435 +1,435 @@ -/** - * @file lldatapacker.h - * @brief Data packer declaration for tightly storing binary data. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#ifndef LL_LLDATAPACKER_H -#define LL_LLDATAPACKER_H - -class LLColor4; -class LLColor4U; -class LLVector2; -class LLVector3; -class LLVector4; -class LLUUID; - -class LLDataPacker -{ -public: - virtual ~LLDataPacker() {} - - // Not required to override, but error to call? - virtual void reset(); - virtual void dumpBufferToLog(); - - virtual BOOL hasNext() const = 0; - - virtual BOOL packString(const std::string& value, const char *name) = 0; - virtual BOOL unpackString(std::string& value, const char *name) = 0; - - virtual BOOL packBinaryData(const U8 *value, S32 size, const char *name) = 0; - virtual BOOL unpackBinaryData(U8 *value, S32 &size, const char *name) = 0; - - // Constant size binary data packing - virtual BOOL packBinaryDataFixed(const U8 *value, S32 size, const char *name) = 0; - virtual BOOL unpackBinaryDataFixed(U8 *value, S32 size, const char *name) = 0; - - virtual BOOL packU8(const U8 value, const char *name) = 0; - virtual BOOL unpackU8(U8 &value, const char *name) = 0; - - virtual BOOL packU16(const U16 value, const char *name) = 0; - virtual BOOL unpackU16(U16 &value, const char *name) = 0; - BOOL unpackU16s(U16 *value, S32 count, const char *name); - - virtual BOOL packS16(const S16 value, const char *name) = 0; - virtual BOOL unpackS16(S16 &value, const char *name) = 0; - BOOL unpackS16s(S16 *value, S32 count, const char *name); - - virtual BOOL packU32(const U32 value, const char *name) = 0; - virtual BOOL unpackU32(U32 &value, const char *name) = 0; - - virtual BOOL packS32(const S32 value, const char *name) = 0; - virtual BOOL unpackS32(S32 &value, const char *name) = 0; - - virtual BOOL packF32(const F32 value, const char *name) = 0; - virtual BOOL unpackF32(F32 &value, const char *name) = 0; - BOOL unpackF32s(F32 *values, S32 count, const char *name); - - // Packs a float into an integer, using the given size - // and picks the right U* data type to pack into. - BOOL packFixed(const F32 value, const char *name, - const BOOL is_signed, const U32 int_bits, const U32 frac_bits); - BOOL unpackFixed(F32 &value, const char *name, - const BOOL is_signed, const U32 int_bits, const U32 frac_bits); - - virtual BOOL packColor4(const LLColor4 &value, const char *name) = 0; - virtual BOOL unpackColor4(LLColor4 &value, const char *name) = 0; - - virtual BOOL packColor4U(const LLColor4U &value, const char *name) = 0; - virtual BOOL unpackColor4U(LLColor4U &value, const char *name) = 0; - BOOL unpackColor4Us(LLColor4U *values, S32 count, const char *name); - - virtual BOOL packVector2(const LLVector2 &value, const char *name) = 0; - virtual BOOL unpackVector2(LLVector2 &value, const char *name) = 0; - - virtual BOOL packVector3(const LLVector3 &value, const char *name) = 0; - virtual BOOL unpackVector3(LLVector3 &value, const char *name) = 0; - - virtual BOOL packVector4(const LLVector4 &value, const char *name) = 0; - virtual BOOL unpackVector4(LLVector4 &value, const char *name) = 0; - - virtual BOOL packUUID(const LLUUID &value, const char *name) = 0; - virtual BOOL unpackUUID(LLUUID &value, const char *name) = 0; - BOOL unpackUUIDs(LLUUID *values, S32 count, const char *name); - U32 getPassFlags() const { return mPassFlags; } - void setPassFlags(U32 flags) { mPassFlags = flags; } -protected: - LLDataPacker(); -protected: - U32 mPassFlags; - BOOL mWriteEnabled; // disable this to do things like determine filesize without actually copying data -}; - -class LLDataPackerBinaryBuffer : public LLDataPacker -{ -public: - LLDataPackerBinaryBuffer(U8 *bufferp, S32 size) - : LLDataPacker(), - mBufferp(bufferp), - mCurBufferp(bufferp), - mBufferSize(size) - { - mWriteEnabled = TRUE; - } - - LLDataPackerBinaryBuffer() - : LLDataPacker(), - mBufferp(NULL), - mCurBufferp(NULL), - mBufferSize(0) - { - } - - /*virtual*/ BOOL packString(const std::string& value, const char *name); - /*virtual*/ BOOL unpackString(std::string& value, const char *name); - - /*virtual*/ BOOL packBinaryData(const U8 *value, S32 size, const char *name); - /*virtual*/ BOOL unpackBinaryData(U8 *value, S32 &size, const char *name); - - // Constant size binary data packing - /*virtual*/ BOOL packBinaryDataFixed(const U8 *value, S32 size, const char *name); - /*virtual*/ BOOL unpackBinaryDataFixed(U8 *value, S32 size, const char *name); - - /*virtual*/ BOOL packU8(const U8 value, const char *name); - /*virtual*/ BOOL unpackU8(U8 &value, const char *name); - - /*virtual*/ BOOL packU16(const U16 value, const char *name); - /*virtual*/ BOOL unpackU16(U16 &value, const char *name); - - /*virtual*/ BOOL packS16(const S16 value, const char *name); - /*virtual*/ BOOL unpackS16(S16 &value, const char *name); - - /*virtual*/ BOOL packU32(const U32 value, const char *name); - /*virtual*/ BOOL unpackU32(U32 &value, const char *name); - - /*virtual*/ BOOL packS32(const S32 value, const char *name); - /*virtual*/ BOOL unpackS32(S32 &value, const char *name); - - /*virtual*/ BOOL packF32(const F32 value, const char *name); - /*virtual*/ BOOL unpackF32(F32 &value, const char *name); - - /*virtual*/ BOOL packColor4(const LLColor4 &value, const char *name); - /*virtual*/ BOOL unpackColor4(LLColor4 &value, const char *name); - - /*virtual*/ BOOL packColor4U(const LLColor4U &value, const char *name); - /*virtual*/ BOOL unpackColor4U(LLColor4U &value, const char *name); - - /*virtual*/ BOOL packVector2(const LLVector2 &value, const char *name); - /*virtual*/ BOOL unpackVector2(LLVector2 &value, const char *name); - - /*virtual*/ BOOL packVector3(const LLVector3 &value, const char *name); - /*virtual*/ BOOL unpackVector3(LLVector3 &value, const char *name); - - /*virtual*/ BOOL packVector4(const LLVector4 &value, const char *name); - /*virtual*/ BOOL unpackVector4(LLVector4 &value, const char *name); - - /*virtual*/ BOOL packUUID(const LLUUID &value, const char *name); - /*virtual*/ BOOL unpackUUID(LLUUID &value, const char *name); - - S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp); } - S32 getBufferSize() const { return mBufferSize; } - const U8* getBuffer() const { return mBufferp; } - void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); } - void shift(S32 offset) { reset(); mCurBufferp += offset;} - void freeBuffer() { delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = FALSE; } - void assignBuffer(U8 *bufferp, S32 size) - { - if(mBufferp && mBufferp != bufferp) - { - freeBuffer() ; - } - mBufferp = bufferp; - mCurBufferp = bufferp; - mBufferSize = size; - mWriteEnabled = TRUE; - } - const LLDataPackerBinaryBuffer& operator=(const LLDataPackerBinaryBuffer &a); - - /*virtual*/ BOOL hasNext() const { return getCurrentSize() < getBufferSize(); } - - /*virtual*/ void dumpBufferToLog(); -protected: - inline BOOL verifyLength(const S32 data_size, const char *name); - - U8 *mBufferp; - U8 *mCurBufferp; - S32 mBufferSize; -}; - -inline BOOL LLDataPackerBinaryBuffer::verifyLength(const S32 data_size, const char *name) -{ - if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size) - { - LL_WARNS() << "Buffer overflow in BinaryBuffer length verify, field name " << name << "!" << LL_ENDL; - LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL; - return FALSE; - } - - return TRUE; -} - -class LLDataPackerAsciiBuffer : public LLDataPacker -{ -public: - LLDataPackerAsciiBuffer(char* bufferp, S32 size) - { - mBufferp = bufferp; - mCurBufferp = bufferp; - mBufferSize = size; - mPassFlags = 0; - mIncludeNames = FALSE; - mWriteEnabled = TRUE; - } - - LLDataPackerAsciiBuffer() - { - mBufferp = NULL; - mCurBufferp = NULL; - mBufferSize = 0; - mPassFlags = 0; - mIncludeNames = FALSE; - mWriteEnabled = FALSE; - } - - /*virtual*/ BOOL packString(const std::string& value, const char *name); - /*virtual*/ BOOL unpackString(std::string& value, const char *name); - - /*virtual*/ BOOL packBinaryData(const U8 *value, S32 size, const char *name); - /*virtual*/ BOOL unpackBinaryData(U8 *value, S32 &size, const char *name); - - // Constant size binary data packing - /*virtual*/ BOOL packBinaryDataFixed(const U8 *value, S32 size, const char *name); - /*virtual*/ BOOL unpackBinaryDataFixed(U8 *value, S32 size, const char *name); - - /*virtual*/ BOOL packU8(const U8 value, const char *name); - /*virtual*/ BOOL unpackU8(U8 &value, const char *name); - - /*virtual*/ BOOL packU16(const U16 value, const char *name); - /*virtual*/ BOOL unpackU16(U16 &value, const char *name); - - /*virtual*/ BOOL packS16(const S16 value, const char *name); - /*virtual*/ BOOL unpackS16(S16 &value, const char *name); - - /*virtual*/ BOOL packU32(const U32 value, const char *name); - /*virtual*/ BOOL unpackU32(U32 &value, const char *name); - - /*virtual*/ BOOL packS32(const S32 value, const char *name); - /*virtual*/ BOOL unpackS32(S32 &value, const char *name); - - /*virtual*/ BOOL packF32(const F32 value, const char *name); - /*virtual*/ BOOL unpackF32(F32 &value, const char *name); - - /*virtual*/ BOOL packColor4(const LLColor4 &value, const char *name); - /*virtual*/ BOOL unpackColor4(LLColor4 &value, const char *name); - - /*virtual*/ BOOL packColor4U(const LLColor4U &value, const char *name); - /*virtual*/ BOOL unpackColor4U(LLColor4U &value, const char *name); - - /*virtual*/ BOOL packVector2(const LLVector2 &value, const char *name); - /*virtual*/ BOOL unpackVector2(LLVector2 &value, const char *name); - - /*virtual*/ BOOL packVector3(const LLVector3 &value, const char *name); - /*virtual*/ BOOL unpackVector3(LLVector3 &value, const char *name); - - /*virtual*/ BOOL packVector4(const LLVector4 &value, const char *name); - /*virtual*/ BOOL unpackVector4(LLVector4 &value, const char *name); - - /*virtual*/ BOOL packUUID(const LLUUID &value, const char *name); - /*virtual*/ BOOL unpackUUID(LLUUID &value, const char *name); - - void setIncludeNames(BOOL b) { mIncludeNames = b; } - - // Include the trailing NULL so it's always a valid string - S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp) + 1; } - - S32 getBufferSize() const { return mBufferSize; } - /*virtual*/ void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); } - - /*virtual*/ BOOL hasNext() const { return getCurrentSize() < getBufferSize(); } - - inline void freeBuffer(); - inline void assignBuffer(char* bufferp, S32 size); - void dump(); - -protected: - void writeIndentedName(const char *name); - BOOL getValueStr(const char *name, char *out_value, const S32 value_len); - -protected: - inline BOOL verifyLength(const S32 data_size, const char *name); - - char *mBufferp; - char *mCurBufferp; - S32 mBufferSize; - BOOL mIncludeNames; // useful for debugging, print the name of each field -}; - -inline void LLDataPackerAsciiBuffer::freeBuffer() -{ - delete [] mBufferp; - mBufferp = mCurBufferp = NULL; - mBufferSize = 0; - mWriteEnabled = FALSE; -} - -inline void LLDataPackerAsciiBuffer::assignBuffer(char* bufferp, S32 size) -{ - mBufferp = bufferp; - mCurBufferp = bufferp; - mBufferSize = size; - mWriteEnabled = TRUE; -} - -inline BOOL LLDataPackerAsciiBuffer::verifyLength(const S32 data_size, const char *name) -{ - if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size) - { - LL_WARNS() << "Buffer overflow in AsciiBuffer length verify, field name " << name << "!" << LL_ENDL; - LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL; - return FALSE; - } - - return TRUE; -} - -class LLDataPackerAsciiFile : public LLDataPacker -{ -public: - LLDataPackerAsciiFile(LLFILE *fp, const S32 indent = 2) - : LLDataPacker(), - mIndent(indent), - mFP(fp), - mOutputStream(NULL), - mInputStream(NULL) - { - } - - LLDataPackerAsciiFile(std::ostream& output_stream, const S32 indent = 2) - : LLDataPacker(), - mIndent(indent), - mFP(NULL), - mOutputStream(&output_stream), - mInputStream(NULL) - { - mWriteEnabled = TRUE; - } - - LLDataPackerAsciiFile(std::istream& input_stream, const S32 indent = 2) - : LLDataPacker(), - mIndent(indent), - mFP(NULL), - mOutputStream(NULL), - mInputStream(&input_stream) - { - } - - /*virtual*/ BOOL packString(const std::string& value, const char *name); - /*virtual*/ BOOL unpackString(std::string& value, const char *name); - - /*virtual*/ BOOL packBinaryData(const U8 *value, S32 size, const char *name); - /*virtual*/ BOOL unpackBinaryData(U8 *value, S32 &size, const char *name); - - /*virtual*/ BOOL packBinaryDataFixed(const U8 *value, S32 size, const char *name); - /*virtual*/ BOOL unpackBinaryDataFixed(U8 *value, S32 size, const char *name); - - /*virtual*/ BOOL packU8(const U8 value, const char *name); - /*virtual*/ BOOL unpackU8(U8 &value, const char *name); - - /*virtual*/ BOOL packU16(const U16 value, const char *name); - /*virtual*/ BOOL unpackU16(U16 &value, const char *name); - - /*virtual*/ BOOL packS16(const S16 value, const char *name); - /*virtual*/ BOOL unpackS16(S16 &value, const char *name); - - /*virtual*/ BOOL packU32(const U32 value, const char *name); - /*virtual*/ BOOL unpackU32(U32 &value, const char *name); - - /*virtual*/ BOOL packS32(const S32 value, const char *name); - /*virtual*/ BOOL unpackS32(S32 &value, const char *name); - - /*virtual*/ BOOL packF32(const F32 value, const char *name); - /*virtual*/ BOOL unpackF32(F32 &value, const char *name); - - /*virtual*/ BOOL packColor4(const LLColor4 &value, const char *name); - /*virtual*/ BOOL unpackColor4(LLColor4 &value, const char *name); - - /*virtual*/ BOOL packColor4U(const LLColor4U &value, const char *name); - /*virtual*/ BOOL unpackColor4U(LLColor4U &value, const char *name); - - /*virtual*/ BOOL packVector2(const LLVector2 &value, const char *name); - /*virtual*/ BOOL unpackVector2(LLVector2 &value, const char *name); - - /*virtual*/ BOOL packVector3(const LLVector3 &value, const char *name); - /*virtual*/ BOOL unpackVector3(LLVector3 &value, const char *name); - - /*virtual*/ BOOL packVector4(const LLVector4 &value, const char *name); - /*virtual*/ BOOL unpackVector4(LLVector4 &value, const char *name); - - /*virtual*/ BOOL packUUID(const LLUUID &value, const char *name); - /*virtual*/ BOOL unpackUUID(LLUUID &value, const char *name); -protected: - void writeIndentedName(const char *name); - BOOL getValueStr(const char *name, char *out_value, const S32 value_len); - - /*virtual*/ BOOL hasNext() const { return true; } - -protected: - S32 mIndent; - LLFILE *mFP; - std::ostream* mOutputStream; - std::istream* mInputStream; -}; - -#endif // LL_LLDATAPACKER - +/**
+ * @file lldatapacker.h
+ * @brief Data packer declaration for tightly storing binary data.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLDATAPACKER_H
+#define LL_LLDATAPACKER_H
+
+class LLColor4;
+class LLColor4U;
+class LLVector2;
+class LLVector3;
+class LLVector4;
+class LLUUID;
+
+class LLDataPacker
+{
+public:
+ virtual ~LLDataPacker() {}
+
+ // Not required to override, but error to call?
+ virtual void reset();
+ virtual void dumpBufferToLog();
+
+ virtual bool hasNext() const = 0;
+
+ virtual bool packString(const std::string& value, const char *name) = 0;
+ virtual bool unpackString(std::string& value, const char *name) = 0;
+
+ virtual bool packBinaryData(const U8 *value, S32 size, const char *name) = 0;
+ virtual bool unpackBinaryData(U8 *value, S32 &size, const char *name) = 0;
+
+ // Constant size binary data packing
+ virtual bool packBinaryDataFixed(const U8 *value, S32 size, const char *name) = 0;
+ virtual bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name) = 0;
+
+ virtual bool packU8(const U8 value, const char *name) = 0;
+ virtual bool unpackU8(U8 &value, const char *name) = 0;
+
+ virtual bool packU16(const U16 value, const char *name) = 0;
+ virtual bool unpackU16(U16 &value, const char *name) = 0;
+ bool unpackU16s(U16 *value, S32 count, const char *name);
+
+ virtual bool packS16(const S16 value, const char *name) = 0;
+ virtual bool unpackS16(S16 &value, const char *name) = 0;
+ bool unpackS16s(S16 *value, S32 count, const char *name);
+
+ virtual bool packU32(const U32 value, const char *name) = 0;
+ virtual bool unpackU32(U32 &value, const char *name) = 0;
+
+ virtual bool packS32(const S32 value, const char *name) = 0;
+ virtual bool unpackS32(S32 &value, const char *name) = 0;
+
+ virtual bool packF32(const F32 value, const char *name) = 0;
+ virtual bool unpackF32(F32 &value, const char *name) = 0;
+ bool unpackF32s(F32 *values, S32 count, const char *name);
+
+ // Packs a float into an integer, using the given size
+ // and picks the right U* data type to pack into.
+ bool packFixed(const F32 value, const char *name,
+ const bool is_signed, const U32 int_bits, const U32 frac_bits);
+ bool unpackFixed(F32 &value, const char *name,
+ const bool is_signed, const U32 int_bits, const U32 frac_bits);
+
+ virtual bool packColor4(const LLColor4 &value, const char *name) = 0;
+ virtual bool unpackColor4(LLColor4 &value, const char *name) = 0;
+
+ virtual bool packColor4U(const LLColor4U &value, const char *name) = 0;
+ virtual bool unpackColor4U(LLColor4U &value, const char *name) = 0;
+ bool unpackColor4Us(LLColor4U *values, S32 count, const char *name);
+
+ virtual bool packVector2(const LLVector2 &value, const char *name) = 0;
+ virtual bool unpackVector2(LLVector2 &value, const char *name) = 0;
+
+ virtual bool packVector3(const LLVector3 &value, const char *name) = 0;
+ virtual bool unpackVector3(LLVector3 &value, const char *name) = 0;
+
+ virtual bool packVector4(const LLVector4 &value, const char *name) = 0;
+ virtual bool unpackVector4(LLVector4 &value, const char *name) = 0;
+
+ virtual bool packUUID(const LLUUID &value, const char *name) = 0;
+ virtual bool unpackUUID(LLUUID &value, const char *name) = 0;
+ bool unpackUUIDs(LLUUID *values, S32 count, const char *name);
+ U32 getPassFlags() const { return mPassFlags; }
+ void setPassFlags(U32 flags) { mPassFlags = flags; }
+protected:
+ LLDataPacker();
+protected:
+ U32 mPassFlags;
+ bool mWriteEnabled; // disable this to do things like determine filesize without actually copying data
+};
+
+class LLDataPackerBinaryBuffer : public LLDataPacker
+{
+public:
+ LLDataPackerBinaryBuffer(U8 *bufferp, S32 size)
+ : LLDataPacker(),
+ mBufferp(bufferp),
+ mCurBufferp(bufferp),
+ mBufferSize(size)
+ {
+ mWriteEnabled = true;
+ }
+
+ LLDataPackerBinaryBuffer()
+ : LLDataPacker(),
+ mBufferp(NULL),
+ mCurBufferp(NULL),
+ mBufferSize(0)
+ {
+ }
+
+ /*virtual*/ bool packString(const std::string& value, const char *name);
+ /*virtual*/ bool unpackString(std::string& value, const char *name);
+
+ /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name);
+ /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name);
+
+ // Constant size binary data packing
+ /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name);
+ /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name);
+
+ /*virtual*/ bool packU8(const U8 value, const char *name);
+ /*virtual*/ bool unpackU8(U8 &value, const char *name);
+
+ /*virtual*/ bool packU16(const U16 value, const char *name);
+ /*virtual*/ bool unpackU16(U16 &value, const char *name);
+
+ /*virtual*/ bool packS16(const S16 value, const char *name);
+ /*virtual*/ bool unpackS16(S16 &value, const char *name);
+
+ /*virtual*/ bool packU32(const U32 value, const char *name);
+ /*virtual*/ bool unpackU32(U32 &value, const char *name);
+
+ /*virtual*/ bool packS32(const S32 value, const char *name);
+ /*virtual*/ bool unpackS32(S32 &value, const char *name);
+
+ /*virtual*/ bool packF32(const F32 value, const char *name);
+ /*virtual*/ bool unpackF32(F32 &value, const char *name);
+
+ /*virtual*/ bool packColor4(const LLColor4 &value, const char *name);
+ /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name);
+
+ /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name);
+ /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name);
+
+ /*virtual*/ bool packVector2(const LLVector2 &value, const char *name);
+ /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name);
+
+ /*virtual*/ bool packVector3(const LLVector3 &value, const char *name);
+ /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name);
+
+ /*virtual*/ bool packVector4(const LLVector4 &value, const char *name);
+ /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name);
+
+ /*virtual*/ bool packUUID(const LLUUID &value, const char *name);
+ /*virtual*/ bool unpackUUID(LLUUID &value, const char *name);
+
+ S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp); }
+ S32 getBufferSize() const { return mBufferSize; }
+ const U8* getBuffer() const { return mBufferp; }
+ void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); }
+ void shift(S32 offset) { reset(); mCurBufferp += offset;}
+ void freeBuffer() { delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = false; }
+ void assignBuffer(U8 *bufferp, S32 size)
+ {
+ if(mBufferp && mBufferp != bufferp)
+ {
+ freeBuffer() ;
+ }
+ mBufferp = bufferp;
+ mCurBufferp = bufferp;
+ mBufferSize = size;
+ mWriteEnabled = true;
+ }
+ const LLDataPackerBinaryBuffer& operator=(const LLDataPackerBinaryBuffer &a);
+
+ /*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); }
+
+ /*virtual*/ void dumpBufferToLog();
+protected:
+ inline bool verifyLength(const S32 data_size, const char *name);
+
+ U8 *mBufferp;
+ U8 *mCurBufferp;
+ S32 mBufferSize;
+};
+
+inline bool LLDataPackerBinaryBuffer::verifyLength(const S32 data_size, const char *name)
+{
+ if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size)
+ {
+ LL_WARNS() << "Buffer overflow in BinaryBuffer length verify, field name " << name << "!" << LL_ENDL;
+ LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
+
+class LLDataPackerAsciiBuffer : public LLDataPacker
+{
+public:
+ LLDataPackerAsciiBuffer(char* bufferp, S32 size)
+ {
+ mBufferp = bufferp;
+ mCurBufferp = bufferp;
+ mBufferSize = size;
+ mPassFlags = 0;
+ mIncludeNames = false;
+ mWriteEnabled = true;
+ }
+
+ LLDataPackerAsciiBuffer()
+ {
+ mBufferp = NULL;
+ mCurBufferp = NULL;
+ mBufferSize = 0;
+ mPassFlags = 0;
+ mIncludeNames = false;
+ mWriteEnabled = false;
+ }
+
+ /*virtual*/ bool packString(const std::string& value, const char *name);
+ /*virtual*/ bool unpackString(std::string& value, const char *name);
+
+ /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name);
+ /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name);
+
+ // Constant size binary data packing
+ /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name);
+ /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name);
+
+ /*virtual*/ bool packU8(const U8 value, const char *name);
+ /*virtual*/ bool unpackU8(U8 &value, const char *name);
+
+ /*virtual*/ bool packU16(const U16 value, const char *name);
+ /*virtual*/ bool unpackU16(U16 &value, const char *name);
+
+ /*virtual*/ bool packS16(const S16 value, const char *name);
+ /*virtual*/ bool unpackS16(S16 &value, const char *name);
+
+ /*virtual*/ bool packU32(const U32 value, const char *name);
+ /*virtual*/ bool unpackU32(U32 &value, const char *name);
+
+ /*virtual*/ bool packS32(const S32 value, const char *name);
+ /*virtual*/ bool unpackS32(S32 &value, const char *name);
+
+ /*virtual*/ bool packF32(const F32 value, const char *name);
+ /*virtual*/ bool unpackF32(F32 &value, const char *name);
+
+ /*virtual*/ bool packColor4(const LLColor4 &value, const char *name);
+ /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name);
+
+ /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name);
+ /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name);
+
+ /*virtual*/ bool packVector2(const LLVector2 &value, const char *name);
+ /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name);
+
+ /*virtual*/ bool packVector3(const LLVector3 &value, const char *name);
+ /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name);
+
+ /*virtual*/ bool packVector4(const LLVector4 &value, const char *name);
+ /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name);
+
+ /*virtual*/ bool packUUID(const LLUUID &value, const char *name);
+ /*virtual*/ bool unpackUUID(LLUUID &value, const char *name);
+
+ void setIncludeNames(bool b) { mIncludeNames = b; }
+
+ // Include the trailing NULL so it's always a valid string
+ S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp) + 1; }
+
+ S32 getBufferSize() const { return mBufferSize; }
+ /*virtual*/ void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); }
+
+ /*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); }
+
+ inline void freeBuffer();
+ inline void assignBuffer(char* bufferp, S32 size);
+ void dump();
+
+protected:
+ void writeIndentedName(const char *name);
+ bool getValueStr(const char *name, char *out_value, const S32 value_len);
+
+protected:
+ inline bool verifyLength(const S32 data_size, const char *name);
+
+ char *mBufferp;
+ char *mCurBufferp;
+ S32 mBufferSize;
+ bool mIncludeNames; // useful for debugging, print the name of each field
+};
+
+inline void LLDataPackerAsciiBuffer::freeBuffer()
+{
+ delete [] mBufferp;
+ mBufferp = mCurBufferp = NULL;
+ mBufferSize = 0;
+ mWriteEnabled = false;
+}
+
+inline void LLDataPackerAsciiBuffer::assignBuffer(char* bufferp, S32 size)
+{
+ mBufferp = bufferp;
+ mCurBufferp = bufferp;
+ mBufferSize = size;
+ mWriteEnabled = true;
+}
+
+inline bool LLDataPackerAsciiBuffer::verifyLength(const S32 data_size, const char *name)
+{
+ if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size)
+ {
+ LL_WARNS() << "Buffer overflow in AsciiBuffer length verify, field name " << name << "!" << LL_ENDL;
+ LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
+
+class LLDataPackerAsciiFile : public LLDataPacker
+{
+public:
+ LLDataPackerAsciiFile(LLFILE *fp, const S32 indent = 2)
+ : LLDataPacker(),
+ mIndent(indent),
+ mFP(fp),
+ mOutputStream(NULL),
+ mInputStream(NULL)
+ {
+ }
+
+ LLDataPackerAsciiFile(std::ostream& output_stream, const S32 indent = 2)
+ : LLDataPacker(),
+ mIndent(indent),
+ mFP(NULL),
+ mOutputStream(&output_stream),
+ mInputStream(NULL)
+ {
+ mWriteEnabled = true;
+ }
+
+ LLDataPackerAsciiFile(std::istream& input_stream, const S32 indent = 2)
+ : LLDataPacker(),
+ mIndent(indent),
+ mFP(NULL),
+ mOutputStream(NULL),
+ mInputStream(&input_stream)
+ {
+ }
+
+ /*virtual*/ bool packString(const std::string& value, const char *name);
+ /*virtual*/ bool unpackString(std::string& value, const char *name);
+
+ /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name);
+ /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name);
+
+ /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name);
+ /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name);
+
+ /*virtual*/ bool packU8(const U8 value, const char *name);
+ /*virtual*/ bool unpackU8(U8 &value, const char *name);
+
+ /*virtual*/ bool packU16(const U16 value, const char *name);
+ /*virtual*/ bool unpackU16(U16 &value, const char *name);
+
+ /*virtual*/ bool packS16(const S16 value, const char *name);
+ /*virtual*/ bool unpackS16(S16 &value, const char *name);
+
+ /*virtual*/ bool packU32(const U32 value, const char *name);
+ /*virtual*/ bool unpackU32(U32 &value, const char *name);
+
+ /*virtual*/ bool packS32(const S32 value, const char *name);
+ /*virtual*/ bool unpackS32(S32 &value, const char *name);
+
+ /*virtual*/ bool packF32(const F32 value, const char *name);
+ /*virtual*/ bool unpackF32(F32 &value, const char *name);
+
+ /*virtual*/ bool packColor4(const LLColor4 &value, const char *name);
+ /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name);
+
+ /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name);
+ /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name);
+
+ /*virtual*/ bool packVector2(const LLVector2 &value, const char *name);
+ /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name);
+
+ /*virtual*/ bool packVector3(const LLVector3 &value, const char *name);
+ /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name);
+
+ /*virtual*/ bool packVector4(const LLVector4 &value, const char *name);
+ /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name);
+
+ /*virtual*/ bool packUUID(const LLUUID &value, const char *name);
+ /*virtual*/ bool unpackUUID(LLUUID &value, const char *name);
+protected:
+ void writeIndentedName(const char *name);
+ bool getValueStr(const char *name, char *out_value, const S32 value_len);
+
+ /*virtual*/ bool hasNext() const { return true; }
+
+protected:
+ S32 mIndent;
+ LLFILE *mFP;
+ std::ostream* mOutputStream;
+ std::istream* mInputStream;
+};
+
+#endif // LL_LLDATAPACKER
+
diff --git a/indra/llmessage/llhost.cpp b/indra/llmessage/llhost.cpp index fe0b594d39..264d64bb50 100644 --- a/indra/llmessage/llhost.cpp +++ b/indra/llmessage/llhost.cpp @@ -1,176 +1,176 @@ -/** - * @file llhost.cpp - * @brief Encapsulates an IP address and a port. - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#include "linden_common.h" - -#include "llhost.h" - -#include "llerror.h" - -#if LL_WINDOWS - #define WIN32_LEAN_AND_MEAN - #include <winsock2.h> -#else - #include <netdb.h> - #include <netinet/in.h> // ntonl() - #include <sys/types.h> - #include <sys/socket.h> - #include <arpa/inet.h> -#endif - -LLHost::LLHost(const std::string& ip_and_port) -{ - std::string::size_type colon_index = ip_and_port.find(":"); - if (colon_index == std::string::npos) - { - mIP = ip_string_to_u32(ip_and_port.c_str()); - mPort = 0; - } - else - { - std::string ip_str(ip_and_port, 0, colon_index); - std::string port_str(ip_and_port, colon_index+1); - - mIP = ip_string_to_u32(ip_str.c_str()); - mPort = atol(port_str.c_str()); - } -} - -std::string LLHost::getString() const -{ - return llformat("%s:%u", u32_to_ip_string(mIP), mPort); -} - - -std::string LLHost::getIPandPort() const -{ - return getString(); -} - - -std::string LLHost::getIPString() const -{ - return std::string( u32_to_ip_string( mIP ) ); -} - - -std::string LLHost::getHostName() const -{ - hostent* he; - if (INVALID_HOST_IP_ADDRESS == mIP) - { - LL_WARNS() << "LLHost::getHostName() : Invalid IP address" << LL_ENDL; - return std::string(); - } - he = gethostbyaddr((char *)&mIP, sizeof(mIP), AF_INET); - if (!he) - { -#if LL_WINDOWS - LL_WARNS() << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: " - << WSAGetLastError() << LL_ENDL; -#else - LL_WARNS() << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: " - << h_errno << LL_ENDL; -#endif - return std::string(); - } - else - { - return ll_safe_string(he->h_name); - } -} - -BOOL LLHost::setHostByName(const std::string& hostname) -{ - hostent *he; - std::string local_name(hostname); - -#if LL_WINDOWS - // We may need an equivalent for Linux, but not sure - djs - LLStringUtil::toUpper(local_name); -#endif - - he = gethostbyname(local_name.c_str()); - if(!he) - { - U32 ip_address = ip_string_to_u32(hostname.c_str()); - he = gethostbyaddr((char *)&ip_address, sizeof(ip_address), AF_INET); - } - - if (he) - { - mIP = *(U32 *)he->h_addr_list[0]; - return TRUE; - } - else - { - setAddress(local_name); - - // In windows, h_errno is a macro for WSAGetLastError(), so store value here - S32 error_number = h_errno; - switch(error_number) - { - case TRY_AGAIN: // XXX how to handle this case? - LL_WARNS() << "LLHost::setAddress(): try again" << LL_ENDL; - break; - case HOST_NOT_FOUND: - case NO_ADDRESS: // NO_DATA - LL_WARNS() << "LLHost::setAddress(): host not found" << LL_ENDL; - break; - case NO_RECOVERY: - LL_WARNS() << "LLHost::setAddress(): unrecoverable error" << LL_ENDL; - break; - default: - LL_WARNS() << "LLHost::setAddress(): unknown error - " << error_number << LL_ENDL; - break; - } - return FALSE; - } -} - -LLHost& LLHost::operator=(const LLHost &rhs) -{ - if (this != &rhs) - { - set(rhs.getAddress(), rhs.getPort()); - } - return *this; -} - - -std::ostream& operator<< (std::ostream& os, const LLHost &hh) -{ - os << u32_to_ip_string(hh.mIP) << ":" << hh.mPort ; - return os; -} - - -//std::istream& operator>> (std::istream& is, LLHost &rh) -//{ -// is >> rh.mIP; -// is >> rh.mPort; -// return is; -//} +/**
+ * @file llhost.cpp
+ * @brief Encapsulates an IP address and a port.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+#include "llhost.h"
+
+#include "llerror.h"
+
+#if LL_WINDOWS
+ #define WIN32_LEAN_AND_MEAN
+ #include <winsock2.h>
+#else
+ #include <netdb.h>
+ #include <netinet/in.h> // ntonl()
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <arpa/inet.h>
+#endif
+
+LLHost::LLHost(const std::string& ip_and_port)
+{
+ std::string::size_type colon_index = ip_and_port.find(":");
+ if (colon_index == std::string::npos)
+ {
+ mIP = ip_string_to_u32(ip_and_port.c_str());
+ mPort = 0;
+ }
+ else
+ {
+ std::string ip_str(ip_and_port, 0, colon_index);
+ std::string port_str(ip_and_port, colon_index+1);
+
+ mIP = ip_string_to_u32(ip_str.c_str());
+ mPort = atol(port_str.c_str());
+ }
+}
+
+std::string LLHost::getString() const
+{
+ return llformat("%s:%u", u32_to_ip_string(mIP), mPort);
+}
+
+
+std::string LLHost::getIPandPort() const
+{
+ return getString();
+}
+
+
+std::string LLHost::getIPString() const
+{
+ return std::string( u32_to_ip_string( mIP ) );
+}
+
+
+std::string LLHost::getHostName() const
+{
+ hostent* he;
+ if (INVALID_HOST_IP_ADDRESS == mIP)
+ {
+ LL_WARNS() << "LLHost::getHostName() : Invalid IP address" << LL_ENDL;
+ return std::string();
+ }
+ he = gethostbyaddr((char *)&mIP, sizeof(mIP), AF_INET);
+ if (!he)
+ {
+#if LL_WINDOWS
+ LL_WARNS() << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: "
+ << WSAGetLastError() << LL_ENDL;
+#else
+ LL_WARNS() << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: "
+ << h_errno << LL_ENDL;
+#endif
+ return std::string();
+ }
+ else
+ {
+ return ll_safe_string(he->h_name);
+ }
+}
+
+bool LLHost::setHostByName(const std::string& hostname)
+{
+ hostent *he;
+ std::string local_name(hostname);
+
+#if LL_WINDOWS
+ // We may need an equivalent for Linux, but not sure - djs
+ LLStringUtil::toUpper(local_name);
+#endif
+
+ he = gethostbyname(local_name.c_str());
+ if(!he)
+ {
+ U32 ip_address = ip_string_to_u32(hostname.c_str());
+ he = gethostbyaddr((char *)&ip_address, sizeof(ip_address), AF_INET);
+ }
+
+ if (he)
+ {
+ mIP = *(U32 *)he->h_addr_list[0];
+ return true;
+ }
+ else
+ {
+ setAddress(local_name);
+
+ // In windows, h_errno is a macro for WSAGetLastError(), so store value here
+ S32 error_number = h_errno;
+ switch(error_number)
+ {
+ case TRY_AGAIN: // XXX how to handle this case?
+ LL_WARNS() << "LLHost::setAddress(): try again" << LL_ENDL;
+ break;
+ case HOST_NOT_FOUND:
+ case NO_ADDRESS: // NO_DATA
+ LL_WARNS() << "LLHost::setAddress(): host not found" << LL_ENDL;
+ break;
+ case NO_RECOVERY:
+ LL_WARNS() << "LLHost::setAddress(): unrecoverable error" << LL_ENDL;
+ break;
+ default:
+ LL_WARNS() << "LLHost::setAddress(): unknown error - " << error_number << LL_ENDL;
+ break;
+ }
+ return false;
+ }
+}
+
+LLHost& LLHost::operator=(const LLHost &rhs)
+{
+ if (this != &rhs)
+ {
+ set(rhs.getAddress(), rhs.getPort());
+ }
+ return *this;
+}
+
+
+std::ostream& operator<< (std::ostream& os, const LLHost &hh)
+{
+ os << u32_to_ip_string(hh.mIP) << ":" << hh.mPort ;
+ return os;
+}
+
+
+//std::istream& operator>> (std::istream& is, LLHost &rh)
+//{
+// is >> rh.mIP;
+// is >> rh.mPort;
+// return is;
+//}
diff --git a/indra/llmessage/llhost.h b/indra/llmessage/llhost.h index 613c81168f..1a3a48eede 100644 --- a/indra/llmessage/llhost.h +++ b/indra/llmessage/llhost.h @@ -1,154 +1,154 @@ -/** - * @file llhost.h - * @brief a LLHost uniquely defines a host (Simulator, Proxy or other) - * across the network - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#ifndef LL_LLHOST_H -#define LL_LLHOST_H - -#include <iostream> -#include <string> - -#include "net.h" - -const U32 INVALID_PORT = 0; -const U32 INVALID_HOST_IP_ADDRESS = 0x0; - -class LLHost { -protected: - U32 mPort; - U32 mIP; - std::string mUntrustedSimCap; -public: - - // CREATORS - LLHost() - : mPort(INVALID_PORT), - mIP(INVALID_HOST_IP_ADDRESS) - { } // STL's hash_map expect this T() - - LLHost( U32 ipv4_addr, U32 port ) - : mPort( port ) - { - mIP = ipv4_addr; - } - - LLHost( const std::string& ipv4_addr, U32 port ) - : mPort( port ) - { - mIP = ip_string_to_u32(ipv4_addr.c_str()); - } - - explicit LLHost(const U64 ip_port) - { - U32 ip = (U32)(ip_port >> 32); - U32 port = (U32)(ip_port & (U64)0xFFFFFFFF); - mIP = ip; - mPort = port; - } - - explicit LLHost(const std::string& ip_and_port); - - ~LLHost() - { } - - // MANIPULATORS - void set( U32 ip, U32 port ) { mIP = ip; mPort = port; } - void set( const std::string& ipstr, U32 port ) { mIP = ip_string_to_u32(ipstr.c_str()); mPort = port; } - void setAddress( const std::string& ipstr ) { mIP = ip_string_to_u32(ipstr.c_str()); } - void setAddress( U32 ip ) { mIP = ip; } - void setPort( U32 port ) { mPort = port; } - BOOL setHostByName(const std::string& hname); - - LLHost& operator=(const LLHost &rhs); - void invalidate() { mIP = INVALID_HOST_IP_ADDRESS; mPort = INVALID_PORT;}; - - // READERS - U32 getAddress() const { return mIP; } - U32 getPort() const { return mPort; } - bool isOk() const { return (mIP != INVALID_HOST_IP_ADDRESS) && (mPort != INVALID_PORT); } - bool isInvalid() { return (mIP == INVALID_HOST_IP_ADDRESS) || (mPort == INVALID_PORT); } - size_t hash() const { return (mIP << 16) | (mPort & 0xffff); } - std::string getString() const; - std::string getIPString() const; - std::string getHostName() const; - std::string getIPandPort() const; - - std::string getUntrustedSimulatorCap() const { return mUntrustedSimCap; } - void setUntrustedSimulatorCap(const std::string &capurl) { mUntrustedSimCap = capurl; } - - friend std::ostream& operator<< (std::ostream& os, const LLHost &hh); - - // This operator is not well defined. does it expect a - // "192.168.1.1:80" notation or "int int" format? Phoenix 2007-05-18 - //friend std::istream& operator>> (std::istream& is, LLHost &hh); - - friend bool operator==( const LLHost &lhs, const LLHost &rhs ); - friend bool operator!=( const LLHost &lhs, const LLHost &rhs ); - friend bool operator<(const LLHost &lhs, const LLHost &rhs); -}; - - -// Function Object required for STL templates using LLHost as key -class LLHostHash -{ -public: - size_t operator() (const LLHost &hh) const { return hh.hash(); } -}; - - -inline bool operator==( const LLHost &lhs, const LLHost &rhs ) -{ - return (lhs.mIP == rhs.mIP) && (lhs.mPort == rhs.mPort); -} - -inline bool operator!=( const LLHost &lhs, const LLHost &rhs ) -{ - return (lhs.mIP != rhs.mIP) || (lhs.mPort != rhs.mPort); -} - -inline bool operator<(const LLHost &lhs, const LLHost &rhs) -{ - if (lhs.mIP < rhs.mIP) - { - return true; - } - if (lhs.mIP > rhs.mIP) - { - return false; - } - - if (lhs.mPort < rhs.mPort) - { - return true; - } - else - { - return false; - } -} - - -#endif // LL_LLHOST_H +/**
+ * @file llhost.h
+ * @brief a LLHost uniquely defines a host (Simulator, Proxy or other)
+ * across the network
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#ifndef LL_LLHOST_H
+#define LL_LLHOST_H
+
+#include <iostream>
+#include <string>
+
+#include "net.h"
+
+const U32 INVALID_PORT = 0;
+const U32 INVALID_HOST_IP_ADDRESS = 0x0;
+
+class LLHost {
+protected:
+ U32 mPort;
+ U32 mIP;
+ std::string mUntrustedSimCap;
+public:
+
+ // CREATORS
+ LLHost()
+ : mPort(INVALID_PORT),
+ mIP(INVALID_HOST_IP_ADDRESS)
+ { } // STL's hash_map expect this T()
+
+ LLHost( U32 ipv4_addr, U32 port )
+ : mPort( port )
+ {
+ mIP = ipv4_addr;
+ }
+
+ LLHost( const std::string& ipv4_addr, U32 port )
+ : mPort( port )
+ {
+ mIP = ip_string_to_u32(ipv4_addr.c_str());
+ }
+
+ explicit LLHost(const U64 ip_port)
+ {
+ U32 ip = (U32)(ip_port >> 32);
+ U32 port = (U32)(ip_port & (U64)0xFFFFFFFF);
+ mIP = ip;
+ mPort = port;
+ }
+
+ explicit LLHost(const std::string& ip_and_port);
+
+ ~LLHost()
+ { }
+
+ // MANIPULATORS
+ void set( U32 ip, U32 port ) { mIP = ip; mPort = port; }
+ void set( const std::string& ipstr, U32 port ) { mIP = ip_string_to_u32(ipstr.c_str()); mPort = port; }
+ void setAddress( const std::string& ipstr ) { mIP = ip_string_to_u32(ipstr.c_str()); }
+ void setAddress( U32 ip ) { mIP = ip; }
+ void setPort( U32 port ) { mPort = port; }
+ bool setHostByName(const std::string& hname);
+
+ LLHost& operator=(const LLHost &rhs);
+ void invalidate() { mIP = INVALID_HOST_IP_ADDRESS; mPort = INVALID_PORT;};
+
+ // READERS
+ U32 getAddress() const { return mIP; }
+ U32 getPort() const { return mPort; }
+ bool isOk() const { return (mIP != INVALID_HOST_IP_ADDRESS) && (mPort != INVALID_PORT); }
+ bool isInvalid() { return (mIP == INVALID_HOST_IP_ADDRESS) || (mPort == INVALID_PORT); }
+ size_t hash() const { return (mIP << 16) | (mPort & 0xffff); }
+ std::string getString() const;
+ std::string getIPString() const;
+ std::string getHostName() const;
+ std::string getIPandPort() const;
+
+ std::string getUntrustedSimulatorCap() const { return mUntrustedSimCap; }
+ void setUntrustedSimulatorCap(const std::string &capurl) { mUntrustedSimCap = capurl; }
+
+ friend std::ostream& operator<< (std::ostream& os, const LLHost &hh);
+
+ // This operator is not well defined. does it expect a
+ // "192.168.1.1:80" notation or "int int" format? Phoenix 2007-05-18
+ //friend std::istream& operator>> (std::istream& is, LLHost &hh);
+
+ friend bool operator==( const LLHost &lhs, const LLHost &rhs );
+ friend bool operator!=( const LLHost &lhs, const LLHost &rhs );
+ friend bool operator<(const LLHost &lhs, const LLHost &rhs);
+};
+
+
+// Function Object required for STL templates using LLHost as key
+class LLHostHash
+{
+public:
+ size_t operator() (const LLHost &hh) const { return hh.hash(); }
+};
+
+
+inline bool operator==( const LLHost &lhs, const LLHost &rhs )
+{
+ return (lhs.mIP == rhs.mIP) && (lhs.mPort == rhs.mPort);
+}
+
+inline bool operator!=( const LLHost &lhs, const LLHost &rhs )
+{
+ return (lhs.mIP != rhs.mIP) || (lhs.mPort != rhs.mPort);
+}
+
+inline bool operator<(const LLHost &lhs, const LLHost &rhs)
+{
+ if (lhs.mIP < rhs.mIP)
+ {
+ return true;
+ }
+ if (lhs.mIP > rhs.mIP)
+ {
+ return false;
+ }
+
+ if (lhs.mPort < rhs.mPort)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+#endif // LL_LLHOST_H
diff --git a/indra/llmessage/llinstantmessage.cpp b/indra/llmessage/llinstantmessage.cpp index 8708552122..0563613cfa 100644 --- a/indra/llmessage/llinstantmessage.cpp +++ b/indra/llmessage/llinstantmessage.cpp @@ -1,164 +1,164 @@ -/** - * @file llinstantmessage.cpp - * @author Phoenix - * @date 2005-08-29 - * @brief Constants and functions used in IM. - * - * $LicenseInfo:firstyear=2005&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$ - */ - -#include "linden_common.h" - -#include "lldbstrings.h" -#include "llinstantmessage.h" -#include "llhost.h" -#include "lluuid.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "llsdutil_math.h" -#include "llpointer.h" -#include "message.h" - -#include "message.h" - -const U8 IM_ONLINE = 0; -const U8 IM_OFFLINE = 1; - -const char EMPTY_BINARY_BUCKET[] = ""; -const S32 EMPTY_BINARY_BUCKET_SIZE = 1; -const U32 NO_TIMESTAMP = 0; -const std::string SYSTEM_FROM("Second Life"); -const std::string INTERACTIVE_SYSTEM_FROM("F387446C-37C4-45f2-A438-D99CBDBB563B"); -const S32 IM_TTL = 1; - - -void pack_instant_message( - LLMessageSystem* msg, - const LLUUID& from_id, - BOOL from_group, - const LLUUID& session_id, - const LLUUID& to_id, - const std::string& name, - const std::string& message, - U8 offline, - EInstantMessage dialog, - const LLUUID& id, - U32 parent_estate_id, - const LLUUID& region_id, - const LLVector3& position, - U32 timestamp, - const U8* binary_bucket, - S32 binary_bucket_size) -{ - LL_DEBUGS() << "pack_instant_message()" << LL_ENDL; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - pack_instant_message_block( - msg, - from_id, - from_group, - session_id, - to_id, - name, - message, - offline, - dialog, - id, - parent_estate_id, - region_id, - position, - timestamp, - binary_bucket, - binary_bucket_size); -} - -void pack_instant_message_block( - LLMessageSystem* msg, - const LLUUID& from_id, - BOOL from_group, - const LLUUID& session_id, - const LLUUID& to_id, - const std::string& name, - const std::string& message, - U8 offline, - EInstantMessage dialog, - const LLUUID& id, - U32 parent_estate_id, - const LLUUID& region_id, - const LLVector3& position, - U32 timestamp, - const U8* binary_bucket, - S32 binary_bucket_size) -{ - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, from_id); - msg->addUUIDFast(_PREHASH_SessionID, session_id); - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, from_group); - msg->addUUIDFast(_PREHASH_ToAgentID, to_id); - msg->addU32Fast(_PREHASH_ParentEstateID, parent_estate_id); - msg->addUUIDFast(_PREHASH_RegionID, region_id); - msg->addVector3Fast(_PREHASH_Position, position); - msg->addU8Fast(_PREHASH_Offline, offline); - msg->addU8Fast(_PREHASH_Dialog, (U8) dialog); - msg->addUUIDFast(_PREHASH_ID, id); - msg->addU32Fast(_PREHASH_Timestamp, timestamp); - msg->addStringFast(_PREHASH_FromAgentName, name); - S32 bytes_left = MTUBYTES; - if(!message.empty()) - { - char buffer[MTUBYTES]; - int num_written = snprintf(buffer, MTUBYTES, "%s", message.c_str()); /* Flawfinder: ignore */ - // snprintf returns number of bytes that would have been written - // had the output not being truncated. In that case, it will - // return either -1 or value >= passed in size value . So a check needs to be added - // to detect truncation, and if there is any, only account for the - // actual number of bytes written..and not what could have been - // written. - if (num_written < 0 || num_written >= MTUBYTES) - { - num_written = MTUBYTES - 1; - LL_WARNS() << "pack_instant_message_block: message truncated: " << message << LL_ENDL; - } - - bytes_left -= num_written; - bytes_left = llmax(0, bytes_left); - msg->addStringFast(_PREHASH_Message, buffer); - } - else - { - msg->addStringFast(_PREHASH_Message, NULL); - } - const U8* bb; - if(binary_bucket) - { - bb = binary_bucket; - binary_bucket_size = llmin(bytes_left, binary_bucket_size); - } - else - { - bb = (const U8*)EMPTY_BINARY_BUCKET; - binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE; - } - msg->addBinaryDataFast(_PREHASH_BinaryBucket, bb, binary_bucket_size); -} - - +/**
+ * @file llinstantmessage.cpp
+ * @author Phoenix
+ * @date 2005-08-29
+ * @brief Constants and functions used in IM.
+ *
+ * $LicenseInfo:firstyear=2005&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$
+ */
+
+#include "linden_common.h"
+
+#include "lldbstrings.h"
+#include "llinstantmessage.h"
+#include "llhost.h"
+#include "lluuid.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "llsdutil_math.h"
+#include "llpointer.h"
+#include "message.h"
+
+#include "message.h"
+
+const U8 IM_ONLINE = 0;
+const U8 IM_OFFLINE = 1;
+
+const char EMPTY_BINARY_BUCKET[] = "";
+const S32 EMPTY_BINARY_BUCKET_SIZE = 1;
+const U32 NO_TIMESTAMP = 0;
+const std::string SYSTEM_FROM("Second Life");
+const std::string INTERACTIVE_SYSTEM_FROM("F387446C-37C4-45f2-A438-D99CBDBB563B");
+const S32 IM_TTL = 1;
+
+
+void pack_instant_message(
+ LLMessageSystem* msg,
+ const LLUUID& from_id,
+ bool from_group,
+ const LLUUID& session_id,
+ const LLUUID& to_id,
+ const std::string& name,
+ const std::string& message,
+ U8 offline,
+ EInstantMessage dialog,
+ const LLUUID& id,
+ U32 parent_estate_id,
+ const LLUUID& region_id,
+ const LLVector3& position,
+ U32 timestamp,
+ const U8* binary_bucket,
+ S32 binary_bucket_size)
+{
+ LL_DEBUGS() << "pack_instant_message()" << LL_ENDL;
+ msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
+ pack_instant_message_block(
+ msg,
+ from_id,
+ from_group,
+ session_id,
+ to_id,
+ name,
+ message,
+ offline,
+ dialog,
+ id,
+ parent_estate_id,
+ region_id,
+ position,
+ timestamp,
+ binary_bucket,
+ binary_bucket_size);
+}
+
+void pack_instant_message_block(
+ LLMessageSystem* msg,
+ const LLUUID& from_id,
+ bool from_group,
+ const LLUUID& session_id,
+ const LLUUID& to_id,
+ const std::string& name,
+ const std::string& message,
+ U8 offline,
+ EInstantMessage dialog,
+ const LLUUID& id,
+ U32 parent_estate_id,
+ const LLUUID& region_id,
+ const LLVector3& position,
+ U32 timestamp,
+ const U8* binary_bucket,
+ S32 binary_bucket_size)
+{
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, from_id);
+ msg->addUUIDFast(_PREHASH_SessionID, session_id);
+ msg->nextBlockFast(_PREHASH_MessageBlock);
+ msg->addBOOLFast(_PREHASH_FromGroup, from_group);
+ msg->addUUIDFast(_PREHASH_ToAgentID, to_id);
+ msg->addU32Fast(_PREHASH_ParentEstateID, parent_estate_id);
+ msg->addUUIDFast(_PREHASH_RegionID, region_id);
+ msg->addVector3Fast(_PREHASH_Position, position);
+ msg->addU8Fast(_PREHASH_Offline, offline);
+ msg->addU8Fast(_PREHASH_Dialog, (U8) dialog);
+ msg->addUUIDFast(_PREHASH_ID, id);
+ msg->addU32Fast(_PREHASH_Timestamp, timestamp);
+ msg->addStringFast(_PREHASH_FromAgentName, name);
+ S32 bytes_left = MTUBYTES;
+ if(!message.empty())
+ {
+ char buffer[MTUBYTES];
+ int num_written = snprintf(buffer, MTUBYTES, "%s", message.c_str()); /* Flawfinder: ignore */
+ // snprintf returns number of bytes that would have been written
+ // had the output not being truncated. In that case, it will
+ // return either -1 or value >= passed in size value . So a check needs to be added
+ // to detect truncation, and if there is any, only account for the
+ // actual number of bytes written..and not what could have been
+ // written.
+ if (num_written < 0 || num_written >= MTUBYTES)
+ {
+ num_written = MTUBYTES - 1;
+ LL_WARNS() << "pack_instant_message_block: message truncated: " << message << LL_ENDL;
+ }
+
+ bytes_left -= num_written;
+ bytes_left = llmax(0, bytes_left);
+ msg->addStringFast(_PREHASH_Message, buffer);
+ }
+ else
+ {
+ msg->addStringFast(_PREHASH_Message, NULL);
+ }
+ const U8* bb;
+ if(binary_bucket)
+ {
+ bb = binary_bucket;
+ binary_bucket_size = llmin(bytes_left, binary_bucket_size);
+ }
+ else
+ {
+ bb = (const U8*)EMPTY_BINARY_BUCKET;
+ binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE;
+ }
+ msg->addBinaryDataFast(_PREHASH_BinaryBucket, bb, binary_bucket_size);
+}
+
+
diff --git a/indra/llmessage/llinstantmessage.h b/indra/llmessage/llinstantmessage.h index feb07c6b0f..d1f5eef548 100644 --- a/indra/llmessage/llinstantmessage.h +++ b/indra/llmessage/llinstantmessage.h @@ -1,218 +1,218 @@ -/** - * @file llinstantmessage.h - * @brief Constants and declarations used by instant messages. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#ifndef LL_LLINSTANTMESSAGE_H -#define LL_LLINSTANTMESSAGE_H - -#include "llhost.h" -#include "lluuid.h" -#include "llsd.h" -#include "llrefcount.h" -#include "llpointer.h" -#include "v3math.h" - -class LLMessageSystem; - -// The ImprovedInstantMessage only supports 8 bits in the "Dialog" -// field, so don't go past the byte boundary -enum EInstantMessage -{ - // default. ID is meaningless, nothing in the binary bucket. - IM_NOTHING_SPECIAL = 0, - - // pops a messagebox with a single OK button - IM_MESSAGEBOX = 1, - - // pops a countdown messagebox with a single OK button - // IM_MESSAGEBOX_COUNTDOWN = 2, - - // You've been invited to join a group. - // ID is the group id. - - // The binary bucket contains a null terminated string - // representation of the officer/member status and join cost for - // the invitee. (bug # 7672) The format is 1 byte for - // officer/member (O for officer, M for member), and as many bytes - // as necessary for cost. - IM_GROUP_INVITATION = 3, - - // Inventory offer. - // ID is the transaction id - // Binary bucket is a list of inventory uuid and type. - IM_INVENTORY_OFFERED = 4, - IM_INVENTORY_ACCEPTED = 5, - IM_INVENTORY_DECLINED = 6, - - // Group vote - // Name is name of person who called vote. - // ID is vote ID used for internal tracking - // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 - IM_GROUP_VOTE = 7, - - // Group message - // This means that the message is meant for everyone in the - // agent's group. This will result in a database query to find all - // participants and start an im session. - IM_GROUP_MESSAGE_DEPRECATED = 8, - - // Task inventory offer. - // ID is the transaction id - // Binary bucket is a (mostly) complete packed inventory item - IM_TASK_INVENTORY_OFFERED = 9, - IM_TASK_INVENTORY_ACCEPTED = 10, - IM_TASK_INVENTORY_DECLINED = 11, - - // Copied as pending, type LL_NOTHING_SPECIAL, for new users - // used by offline tools - IM_NEW_USER_DEFAULT = 12, - - // - // session based messaging - the way that people usually actually - // communicate with each other. - // - - // Invite users to a session. - IM_SESSION_INVITE = 13, - - IM_SESSION_P2P_INVITE = 14, - - // start a session with your gruop - IM_SESSION_GROUP_START = 15, - - // start a session without a calling card (finder or objects) - IM_SESSION_CONFERENCE_START = 16, - - // send a message to a session. - IM_SESSION_SEND = 17, - - // leave a session - IM_SESSION_LEAVE = 18, - - // an instant message from an object - for differentiation on the - // viewer, since you can't IM an object yet. - IM_FROM_TASK = 19, - - // sent an IM to a do not disturb user, this is the auto response - IM_DO_NOT_DISTURB_AUTO_RESPONSE = 20, - - // Shows the message in the console and chat history - IM_CONSOLE_AND_CHAT_HISTORY = 21, - - // IM Types used for luring your friends - IM_LURE_USER = 22, - IM_LURE_ACCEPTED = 23, - IM_LURE_DECLINED = 24, - IM_GODLIKE_LURE_USER = 25, - IM_TELEPORT_REQUEST = 26, - - // IM that notifie of a new group election. - // Name is name of person who called vote. - // ID is election ID used for internal tracking - IM_GROUP_ELECTION_DEPRECATED = 27, - - // IM to tell the user to go to an URL. Put a text message in the - // message field, and put the url with a trailing \0 in the binary - // bucket. - IM_GOTO_URL = 28, - - // a message generated by a script which we don't want to - // be sent through e-mail. Similar to IM_FROM_TASK, but - // it is shown as an alert on the viewer. - IM_FROM_TASK_AS_ALERT = 31, - - // IM from group officer to all group members. - IM_GROUP_NOTICE = 32, - IM_GROUP_NOTICE_INVENTORY_ACCEPTED = 33, - IM_GROUP_NOTICE_INVENTORY_DECLINED = 34, - - IM_GROUP_INVITATION_ACCEPT = 35, - IM_GROUP_INVITATION_DECLINE = 36, - - IM_GROUP_NOTICE_REQUESTED = 37, - - IM_FRIENDSHIP_OFFERED = 38, - IM_FRIENDSHIP_ACCEPTED = 39, - IM_FRIENDSHIP_DECLINED_DEPRECATED = 40, - - IM_TYPING_START = 41, - IM_TYPING_STOP = 42, - - IM_COUNT -}; - - -extern const U8 IM_ONLINE; -extern const U8 IM_OFFLINE; - -extern const char EMPTY_BINARY_BUCKET[]; -extern const S32 EMPTY_BINARY_BUCKET_SIZE; - -extern const U32 NO_TIMESTAMP; -extern const std::string SYSTEM_FROM; -extern const std::string INTERACTIVE_SYSTEM_FROM; - -// Number of retry attempts on sending the im. -extern const S32 IM_TTL; - -void pack_instant_message( - LLMessageSystem* msgsystem, - const LLUUID& from_id, - BOOL from_group, - const LLUUID& session_id, - const LLUUID& to_id, - const std::string& name, - const std::string& message, - U8 offline = IM_ONLINE, - EInstantMessage dialog = IM_NOTHING_SPECIAL, - const LLUUID& id = LLUUID::null, - U32 parent_estate_id = 0, - const LLUUID& region_id = LLUUID::null, - const LLVector3& position = LLVector3::zero, - U32 timestamp = NO_TIMESTAMP, - const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET, - S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE); - -void pack_instant_message_block( - LLMessageSystem* msgsystem, - const LLUUID& from_id, - BOOL from_group, - const LLUUID& session_id, - const LLUUID& to_id, - const std::string& name, - const std::string& message, - U8 offline = IM_ONLINE, - EInstantMessage dialog = IM_NOTHING_SPECIAL, - const LLUUID& id = LLUUID::null, - U32 parent_estate_id = 0, - const LLUUID& region_id = LLUUID::null, - const LLVector3& position = LLVector3::zero, - U32 timestamp = NO_TIMESTAMP, - const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET, - S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE); - - -#endif // LL_LLINSTANTMESSAGE_H - +/**
+ * @file llinstantmessage.h
+ * @brief Constants and declarations used by instant messages.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLINSTANTMESSAGE_H
+#define LL_LLINSTANTMESSAGE_H
+
+#include "llhost.h"
+#include "lluuid.h"
+#include "llsd.h"
+#include "llrefcount.h"
+#include "llpointer.h"
+#include "v3math.h"
+
+class LLMessageSystem;
+
+// The ImprovedInstantMessage only supports 8 bits in the "Dialog"
+// field, so don't go past the byte boundary
+enum EInstantMessage
+{
+ // default. ID is meaningless, nothing in the binary bucket.
+ IM_NOTHING_SPECIAL = 0,
+
+ // pops a messagebox with a single OK button
+ IM_MESSAGEBOX = 1,
+
+ // pops a countdown messagebox with a single OK button
+ // IM_MESSAGEBOX_COUNTDOWN = 2,
+
+ // You've been invited to join a group.
+ // ID is the group id.
+
+ // The binary bucket contains a null terminated string
+ // representation of the officer/member status and join cost for
+ // the invitee. (bug # 7672) The format is 1 byte for
+ // officer/member (O for officer, M for member), and as many bytes
+ // as necessary for cost.
+ IM_GROUP_INVITATION = 3,
+
+ // Inventory offer.
+ // ID is the transaction id
+ // Binary bucket is a list of inventory uuid and type.
+ IM_INVENTORY_OFFERED = 4,
+ IM_INVENTORY_ACCEPTED = 5,
+ IM_INVENTORY_DECLINED = 6,
+
+ // Group vote
+ // Name is name of person who called vote.
+ // ID is vote ID used for internal tracking
+ // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856
+ IM_GROUP_VOTE = 7,
+
+ // Group message
+ // This means that the message is meant for everyone in the
+ // agent's group. This will result in a database query to find all
+ // participants and start an im session.
+ IM_GROUP_MESSAGE_DEPRECATED = 8,
+
+ // Task inventory offer.
+ // ID is the transaction id
+ // Binary bucket is a (mostly) complete packed inventory item
+ IM_TASK_INVENTORY_OFFERED = 9,
+ IM_TASK_INVENTORY_ACCEPTED = 10,
+ IM_TASK_INVENTORY_DECLINED = 11,
+
+ // Copied as pending, type LL_NOTHING_SPECIAL, for new users
+ // used by offline tools
+ IM_NEW_USER_DEFAULT = 12,
+
+ //
+ // session based messaging - the way that people usually actually
+ // communicate with each other.
+ //
+
+ // Invite users to a session.
+ IM_SESSION_INVITE = 13,
+
+ IM_SESSION_P2P_INVITE = 14,
+
+ // start a session with your gruop
+ IM_SESSION_GROUP_START = 15,
+
+ // start a session without a calling card (finder or objects)
+ IM_SESSION_CONFERENCE_START = 16,
+
+ // send a message to a session.
+ IM_SESSION_SEND = 17,
+
+ // leave a session
+ IM_SESSION_LEAVE = 18,
+
+ // an instant message from an object - for differentiation on the
+ // viewer, since you can't IM an object yet.
+ IM_FROM_TASK = 19,
+
+ // sent an IM to a do not disturb user, this is the auto response
+ IM_DO_NOT_DISTURB_AUTO_RESPONSE = 20,
+
+ // Shows the message in the console and chat history
+ IM_CONSOLE_AND_CHAT_HISTORY = 21,
+
+ // IM Types used for luring your friends
+ IM_LURE_USER = 22,
+ IM_LURE_ACCEPTED = 23,
+ IM_LURE_DECLINED = 24,
+ IM_GODLIKE_LURE_USER = 25,
+ IM_TELEPORT_REQUEST = 26,
+
+ // IM that notifie of a new group election.
+ // Name is name of person who called vote.
+ // ID is election ID used for internal tracking
+ IM_GROUP_ELECTION_DEPRECATED = 27,
+
+ // IM to tell the user to go to an URL. Put a text message in the
+ // message field, and put the url with a trailing \0 in the binary
+ // bucket.
+ IM_GOTO_URL = 28,
+
+ // a message generated by a script which we don't want to
+ // be sent through e-mail. Similar to IM_FROM_TASK, but
+ // it is shown as an alert on the viewer.
+ IM_FROM_TASK_AS_ALERT = 31,
+
+ // IM from group officer to all group members.
+ IM_GROUP_NOTICE = 32,
+ IM_GROUP_NOTICE_INVENTORY_ACCEPTED = 33,
+ IM_GROUP_NOTICE_INVENTORY_DECLINED = 34,
+
+ IM_GROUP_INVITATION_ACCEPT = 35,
+ IM_GROUP_INVITATION_DECLINE = 36,
+
+ IM_GROUP_NOTICE_REQUESTED = 37,
+
+ IM_FRIENDSHIP_OFFERED = 38,
+ IM_FRIENDSHIP_ACCEPTED = 39,
+ IM_FRIENDSHIP_DECLINED_DEPRECATED = 40,
+
+ IM_TYPING_START = 41,
+ IM_TYPING_STOP = 42,
+
+ IM_COUNT
+};
+
+
+extern const U8 IM_ONLINE;
+extern const U8 IM_OFFLINE;
+
+extern const char EMPTY_BINARY_BUCKET[];
+extern const S32 EMPTY_BINARY_BUCKET_SIZE;
+
+extern const U32 NO_TIMESTAMP;
+extern const std::string SYSTEM_FROM;
+extern const std::string INTERACTIVE_SYSTEM_FROM;
+
+// Number of retry attempts on sending the im.
+extern const S32 IM_TTL;
+
+void pack_instant_message(
+ LLMessageSystem* msgsystem,
+ const LLUUID& from_id,
+ bool from_group,
+ const LLUUID& session_id,
+ const LLUUID& to_id,
+ const std::string& name,
+ const std::string& message,
+ U8 offline = IM_ONLINE,
+ EInstantMessage dialog = IM_NOTHING_SPECIAL,
+ const LLUUID& id = LLUUID::null,
+ U32 parent_estate_id = 0,
+ const LLUUID& region_id = LLUUID::null,
+ const LLVector3& position = LLVector3::zero,
+ U32 timestamp = NO_TIMESTAMP,
+ const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET,
+ S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE);
+
+void pack_instant_message_block(
+ LLMessageSystem* msgsystem,
+ const LLUUID& from_id,
+ bool from_group,
+ const LLUUID& session_id,
+ const LLUUID& to_id,
+ const std::string& name,
+ const std::string& message,
+ U8 offline = IM_ONLINE,
+ EInstantMessage dialog = IM_NOTHING_SPECIAL,
+ const LLUUID& id = LLUUID::null,
+ U32 parent_estate_id = 0,
+ const LLUUID& region_id = LLUUID::null,
+ const LLVector3& position = LLVector3::zero,
+ U32 timestamp = NO_TIMESTAMP,
+ const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET,
+ S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE);
+
+
+#endif // LL_LLINSTANTMESSAGE_H
+
diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 4e5cf8ed48..fe01f2d4a4 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -1,396 +1,396 @@ -/** - * @file llmail.cpp - * @brief smtp helper functions. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "llmail.h" - -// APR on Windows needs full windows headers -#include "llwin32headers.h" -#include <string> -#include <sstream> - -#include "apr_pools.h" -#include "apr_network_io.h" - -#include "llapr.h" -#include "llbase32.h" // IM-to-email address -#include "llblowfishcipher.h" -#include "llerror.h" -#include "llhost.h" -#include "llsd.h" -#include "llstring.h" -#include "lluuid.h" -#include "net.h" - -// -// constants -// -const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096; - -static bool gMailEnabled = true; -static apr_pool_t* gMailPool; -static apr_sockaddr_t* gSockAddr; -static apr_socket_t* gMailSocket; - -bool connect_smtp(); -void disconnect_smtp(); - -//#if LL_WINDOWS -//SOCKADDR_IN gMailDstAddr, gMailSrcAddr, gMailLclAddr; -//#else -//struct sockaddr_in gMailDstAddr, gMailSrcAddr, gMailLclAddr; -//#endif - -// Define this for a super-spammy mail mode. -//#define LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND 1 - -bool connect_smtp() -{ - // Prepare an soket to talk smtp - apr_status_t status; - status = apr_socket_create( - &gMailSocket, - gSockAddr->sa.sin.sin_family, - SOCK_STREAM, - APR_PROTO_TCP, - gMailPool); - if(ll_apr_warn_status(status)) return false; - status = apr_socket_connect(gMailSocket, gSockAddr); - if(ll_apr_warn_status(status)) - { - status = apr_socket_close(gMailSocket); - ll_apr_warn_status(status); - return false; - } - return true; -} - -void disconnect_smtp() -{ - if(gMailSocket) - { - apr_status_t status = apr_socket_close(gMailSocket); - ll_apr_warn_status(status); - gMailSocket = NULL; - } -} - -// Returns TRUE on success. -// message should NOT be SMTP escaped. -// static -BOOL LLMail::send( - const char* from_name, - const char* from_address, - const char* to_name, - const char* to_address, - const char* subject, - const char* message, - const LLSD& headers) -{ - std::string header = buildSMTPTransaction( - from_name, - from_address, - to_name, - to_address, - subject, - headers); - if(header.empty()) - { - return FALSE; - } - - std::string message_str; - if(message) - { - message_str = message; - } - bool rv = send(header, message_str, to_address, from_address); - if(rv) return TRUE; - return FALSE; -} - -// static -void LLMail::init(const std::string& hostname, apr_pool_t* pool) -{ - gMailSocket = NULL; - if(hostname.empty() || !pool) - { - gMailPool = NULL; - gSockAddr = NULL; - } - else - { - gMailPool = pool; - - // collect all the information into a socaddr sturcture. the - // documentation is a bit unclear, but I either have to - // specify APR_UNSPEC or not specify any flags. I am not sure - // which option is better. - apr_status_t status = apr_sockaddr_info_get( - &gSockAddr, - hostname.c_str(), - APR_UNSPEC, - 25, - APR_IPV4_ADDR_OK, - gMailPool); - ll_apr_warn_status(status); - } -} - -// static -void LLMail::enable(bool mail_enabled) -{ - gMailEnabled = mail_enabled; -} - -// Test a subject line for RFC2822 compliance. -static bool valid_subject_chars(const char *subject) -{ - for (; *subject != '\0'; subject++) - { - unsigned char c = *subject; - - if (c == '\xa' || c == '\xd' || c > '\x7f') - { - return false; - } - } - - return true; -} - -// static -std::string LLMail::buildSMTPTransaction( - const char* from_name, - const char* from_address, - const char* to_name, - const char* to_address, - const char* subject, - const LLSD& headers) -{ - if(!from_address || !to_address) - { - LL_INFOS() << "send_mail build_smtp_transaction reject: missing to and/or" - << " from address." << LL_ENDL; - return std::string(); - } - if(!valid_subject_chars(subject)) - { - LL_INFOS() << "send_mail build_smtp_transaction reject: bad subject header: " - << "to=<" << to_address - << ">, from=<" << from_address << ">" - << LL_ENDL; - return std::string(); - } - std::ostringstream from_fmt; - if(from_name && from_name[0]) - { - // "My Name" <myaddress@example.com> - from_fmt << "\"" << from_name << "\" <" << from_address << ">"; - } - else - { - // <myaddress@example.com> - from_fmt << "<" << from_address << ">"; - } - std::ostringstream to_fmt; - if(to_name && to_name[0]) - { - to_fmt << "\"" << to_name << "\" <" << to_address << ">"; - } - else - { - to_fmt << "<" << to_address << ">"; - } - std::ostringstream header; - header - << "HELO lindenlab.com\r\n" - << "MAIL FROM:<" << from_address << ">\r\n" - << "RCPT TO:<" << to_address << ">\r\n" - << "DATA\r\n" - << "From: " << from_fmt.str() << "\r\n" - << "To: " << to_fmt.str() << "\r\n" - << "Subject: " << subject << "\r\n"; - - if(headers.isMap()) - { - LLSD::map_const_iterator iter = headers.beginMap(); - LLSD::map_const_iterator end = headers.endMap(); - for(; iter != end; ++iter) - { - header << (*iter).first << ": " << ((*iter).second).asString() - << "\r\n"; - } - } - - header << "\r\n"; - return header.str(); -} - -// static -bool LLMail::send( - const std::string& header, - const std::string& raw_message, - const char* from_address, - const char* to_address) -{ - if(!from_address || !to_address) - { - LL_INFOS() << "send_mail reject: missing to and/or from address." - << LL_ENDL; - return false; - } - - // remove any "." SMTP commands to prevent injection (DEV-35777) - // we don't need to worry about "\r\n.\r\n" because of the - // "\n" --> "\n\n" conversion going into rfc2822_msg below - std::string message = raw_message; - std::string bad_string = "\n.\n"; - std::string good_string = "\n..\n"; - while (1) - { - int index = message.find(bad_string); - if (index == std::string::npos) break; - message.replace(index, bad_string.size(), good_string); - } - - // convert all "\n" into "\r\n" - std::ostringstream rfc2822_msg; - for(U32 i = 0; i < message.size(); ++i) - { - switch(message[i]) - { - case '\0': - break; - case '\n': - // *NOTE: this is kinda busted if we're fed \r\n - rfc2822_msg << "\r\n"; - break; - default: - rfc2822_msg << message[i]; - break; - } - } - - if(!gMailEnabled) - { - LL_INFOS() << "send_mail reject: mail system is disabled: to=<" - << to_address << ">, from=<" << from_address - << ">" << LL_ENDL; - // Any future interface to SMTP should return this as an - // error. --mark - return true; - } - if(!gSockAddr) - { - LL_WARNS() << "send_mail reject: mail system not initialized: to=<" - << to_address << ">, from=<" << from_address - << ">" << LL_ENDL; - return false; - } - - if(!connect_smtp()) - { - LL_WARNS() << "send_mail reject: SMTP connect failure: to=<" - << to_address << ">, from=<" << from_address - << ">" << LL_ENDL; - return false; - } - - std::ostringstream smtp_fmt; - smtp_fmt << header << rfc2822_msg.str() << "\r\n" << ".\r\n" << "QUIT\r\n"; - std::string smtp_transaction = smtp_fmt.str(); - size_t original_size = smtp_transaction.size(); - apr_size_t send_size = original_size; - apr_status_t status = apr_socket_send( - gMailSocket, - smtp_transaction.c_str(), - (apr_size_t*)&send_size); - disconnect_smtp(); - if(ll_apr_warn_status(status)) - { - LL_WARNS() << "send_mail socket failure: unable to write " - << "to=<" << to_address - << ">, from=<" << from_address << ">" - << ", bytes=" << original_size - << ", sent=" << send_size << LL_ENDL; - return false; - } - if(send_size >= LL_MAX_KNOWN_GOOD_MAIL_SIZE) - { - LL_WARNS() << "send_mail message has been shown to fail in testing " - << "when sending messages larger than " << LL_MAX_KNOWN_GOOD_MAIL_SIZE - << " bytes. The next log about success is potentially a lie." << LL_ENDL; - } - LL_DEBUGS() << "send_mail success: " - << "to=<" << to_address - << ">, from=<" << from_address << ">" - << ", bytes=" << original_size - << ", sent=" << send_size << LL_ENDL; - -#if LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND - LL_INFOS() << rfc2822_msg.str() << LL_ENDL; -#endif - return true; -} - - -// static -std::string LLMail::encryptIMEmailAddress(const LLUUID& from_agent_id, - const LLUUID& to_agent_id, - U32 time, - const U8* secret, - size_t secret_size) -{ -#if LL_WINDOWS - return "blowfish-not-supported-on-windows"; -#else - size_t data_size = 4 + UUID_BYTES + UUID_BYTES; - // Convert input data into a binary blob - std::vector<U8> data; - data.resize(data_size); - // *NOTE: This may suffer from endian issues. Could be htolememcpy. - memcpy(&data[0], &time, 4); - memcpy(&data[4], &from_agent_id.mData[0], UUID_BYTES); - memcpy(&data[4 + UUID_BYTES], &to_agent_id.mData[0], UUID_BYTES); - - // Encrypt the blob - LLBlowfishCipher cipher(secret, secret_size); - size_t encrypted_size = cipher.requiredEncryptionSpace(data.size()); - U8* encrypted = new U8[encrypted_size]; - cipher.encrypt(&data[0], data_size, encrypted, encrypted_size); - - std::string address = LLBase32::encode(encrypted, encrypted_size); - - // Make it more pretty for humans. - LLStringUtil::toLower(address); - - delete [] encrypted; - - return address; -#endif -} +/**
+ * @file llmail.cpp
+ * @brief smtp helper functions.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llmail.h"
+
+// APR on Windows needs full windows headers
+#include "llwin32headers.h"
+#include <string>
+#include <sstream>
+
+#include "apr_pools.h"
+#include "apr_network_io.h"
+
+#include "llapr.h"
+#include "llbase32.h" // IM-to-email address
+#include "llblowfishcipher.h"
+#include "llerror.h"
+#include "llhost.h"
+#include "llsd.h"
+#include "llstring.h"
+#include "lluuid.h"
+#include "net.h"
+
+//
+// constants
+//
+const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
+
+static bool gMailEnabled = true;
+static apr_pool_t* gMailPool;
+static apr_sockaddr_t* gSockAddr;
+static apr_socket_t* gMailSocket;
+
+bool connect_smtp();
+void disconnect_smtp();
+
+//#if LL_WINDOWS
+//SOCKADDR_IN gMailDstAddr, gMailSrcAddr, gMailLclAddr;
+//#else
+//struct sockaddr_in gMailDstAddr, gMailSrcAddr, gMailLclAddr;
+//#endif
+
+// Define this for a super-spammy mail mode.
+//#define LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND 1
+
+bool connect_smtp()
+{
+ // Prepare an soket to talk smtp
+ apr_status_t status;
+ status = apr_socket_create(
+ &gMailSocket,
+ gSockAddr->sa.sin.sin_family,
+ SOCK_STREAM,
+ APR_PROTO_TCP,
+ gMailPool);
+ if(ll_apr_warn_status(status)) return false;
+ status = apr_socket_connect(gMailSocket, gSockAddr);
+ if(ll_apr_warn_status(status))
+ {
+ status = apr_socket_close(gMailSocket);
+ ll_apr_warn_status(status);
+ return false;
+ }
+ return true;
+}
+
+void disconnect_smtp()
+{
+ if(gMailSocket)
+ {
+ apr_status_t status = apr_socket_close(gMailSocket);
+ ll_apr_warn_status(status);
+ gMailSocket = NULL;
+ }
+}
+
+// Returns true on success.
+// message should NOT be SMTP escaped.
+// static
+bool LLMail::send(
+ const char* from_name,
+ const char* from_address,
+ const char* to_name,
+ const char* to_address,
+ const char* subject,
+ const char* message,
+ const LLSD& headers)
+{
+ std::string header = buildSMTPTransaction(
+ from_name,
+ from_address,
+ to_name,
+ to_address,
+ subject,
+ headers);
+ if(header.empty())
+ {
+ return false;
+ }
+
+ std::string message_str;
+ if(message)
+ {
+ message_str = message;
+ }
+ bool rv = send(header, message_str, to_address, from_address);
+ if(rv) return true;
+ return false;
+}
+
+// static
+void LLMail::init(const std::string& hostname, apr_pool_t* pool)
+{
+ gMailSocket = NULL;
+ if(hostname.empty() || !pool)
+ {
+ gMailPool = NULL;
+ gSockAddr = NULL;
+ }
+ else
+ {
+ gMailPool = pool;
+
+ // collect all the information into a socaddr sturcture. the
+ // documentation is a bit unclear, but I either have to
+ // specify APR_UNSPEC or not specify any flags. I am not sure
+ // which option is better.
+ apr_status_t status = apr_sockaddr_info_get(
+ &gSockAddr,
+ hostname.c_str(),
+ APR_UNSPEC,
+ 25,
+ APR_IPV4_ADDR_OK,
+ gMailPool);
+ ll_apr_warn_status(status);
+ }
+}
+
+// static
+void LLMail::enable(bool mail_enabled)
+{
+ gMailEnabled = mail_enabled;
+}
+
+// Test a subject line for RFC2822 compliance.
+static bool valid_subject_chars(const char *subject)
+{
+ for (; *subject != '\0'; subject++)
+ {
+ unsigned char c = *subject;
+
+ if (c == '\xa' || c == '\xd' || c > '\x7f')
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// static
+std::string LLMail::buildSMTPTransaction(
+ const char* from_name,
+ const char* from_address,
+ const char* to_name,
+ const char* to_address,
+ const char* subject,
+ const LLSD& headers)
+{
+ if(!from_address || !to_address)
+ {
+ LL_INFOS() << "send_mail build_smtp_transaction reject: missing to and/or"
+ << " from address." << LL_ENDL;
+ return std::string();
+ }
+ if(!valid_subject_chars(subject))
+ {
+ LL_INFOS() << "send_mail build_smtp_transaction reject: bad subject header: "
+ << "to=<" << to_address
+ << ">, from=<" << from_address << ">"
+ << LL_ENDL;
+ return std::string();
+ }
+ std::ostringstream from_fmt;
+ if(from_name && from_name[0])
+ {
+ // "My Name" <myaddress@example.com>
+ from_fmt << "\"" << from_name << "\" <" << from_address << ">";
+ }
+ else
+ {
+ // <myaddress@example.com>
+ from_fmt << "<" << from_address << ">";
+ }
+ std::ostringstream to_fmt;
+ if(to_name && to_name[0])
+ {
+ to_fmt << "\"" << to_name << "\" <" << to_address << ">";
+ }
+ else
+ {
+ to_fmt << "<" << to_address << ">";
+ }
+ std::ostringstream header;
+ header
+ << "HELO lindenlab.com\r\n"
+ << "MAIL FROM:<" << from_address << ">\r\n"
+ << "RCPT TO:<" << to_address << ">\r\n"
+ << "DATA\r\n"
+ << "From: " << from_fmt.str() << "\r\n"
+ << "To: " << to_fmt.str() << "\r\n"
+ << "Subject: " << subject << "\r\n";
+
+ if(headers.isMap())
+ {
+ LLSD::map_const_iterator iter = headers.beginMap();
+ LLSD::map_const_iterator end = headers.endMap();
+ for(; iter != end; ++iter)
+ {
+ header << (*iter).first << ": " << ((*iter).second).asString()
+ << "\r\n";
+ }
+ }
+
+ header << "\r\n";
+ return header.str();
+}
+
+// static
+bool LLMail::send(
+ const std::string& header,
+ const std::string& raw_message,
+ const char* from_address,
+ const char* to_address)
+{
+ if(!from_address || !to_address)
+ {
+ LL_INFOS() << "send_mail reject: missing to and/or from address."
+ << LL_ENDL;
+ return false;
+ }
+
+ // remove any "." SMTP commands to prevent injection (DEV-35777)
+ // we don't need to worry about "\r\n.\r\n" because of the
+ // "\n" --> "\n\n" conversion going into rfc2822_msg below
+ std::string message = raw_message;
+ std::string bad_string = "\n.\n";
+ std::string good_string = "\n..\n";
+ while (1)
+ {
+ int index = message.find(bad_string);
+ if (index == std::string::npos) break;
+ message.replace(index, bad_string.size(), good_string);
+ }
+
+ // convert all "\n" into "\r\n"
+ std::ostringstream rfc2822_msg;
+ for(U32 i = 0; i < message.size(); ++i)
+ {
+ switch(message[i])
+ {
+ case '\0':
+ break;
+ case '\n':
+ // *NOTE: this is kinda busted if we're fed \r\n
+ rfc2822_msg << "\r\n";
+ break;
+ default:
+ rfc2822_msg << message[i];
+ break;
+ }
+ }
+
+ if(!gMailEnabled)
+ {
+ LL_INFOS() << "send_mail reject: mail system is disabled: to=<"
+ << to_address << ">, from=<" << from_address
+ << ">" << LL_ENDL;
+ // Any future interface to SMTP should return this as an
+ // error. --mark
+ return true;
+ }
+ if(!gSockAddr)
+ {
+ LL_WARNS() << "send_mail reject: mail system not initialized: to=<"
+ << to_address << ">, from=<" << from_address
+ << ">" << LL_ENDL;
+ return false;
+ }
+
+ if(!connect_smtp())
+ {
+ LL_WARNS() << "send_mail reject: SMTP connect failure: to=<"
+ << to_address << ">, from=<" << from_address
+ << ">" << LL_ENDL;
+ return false;
+ }
+
+ std::ostringstream smtp_fmt;
+ smtp_fmt << header << rfc2822_msg.str() << "\r\n" << ".\r\n" << "QUIT\r\n";
+ std::string smtp_transaction = smtp_fmt.str();
+ size_t original_size = smtp_transaction.size();
+ apr_size_t send_size = original_size;
+ apr_status_t status = apr_socket_send(
+ gMailSocket,
+ smtp_transaction.c_str(),
+ (apr_size_t*)&send_size);
+ disconnect_smtp();
+ if(ll_apr_warn_status(status))
+ {
+ LL_WARNS() << "send_mail socket failure: unable to write "
+ << "to=<" << to_address
+ << ">, from=<" << from_address << ">"
+ << ", bytes=" << original_size
+ << ", sent=" << send_size << LL_ENDL;
+ return false;
+ }
+ if(send_size >= LL_MAX_KNOWN_GOOD_MAIL_SIZE)
+ {
+ LL_WARNS() << "send_mail message has been shown to fail in testing "
+ << "when sending messages larger than " << LL_MAX_KNOWN_GOOD_MAIL_SIZE
+ << " bytes. The next log about success is potentially a lie." << LL_ENDL;
+ }
+ LL_DEBUGS() << "send_mail success: "
+ << "to=<" << to_address
+ << ">, from=<" << from_address << ">"
+ << ", bytes=" << original_size
+ << ", sent=" << send_size << LL_ENDL;
+
+#if LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND
+ LL_INFOS() << rfc2822_msg.str() << LL_ENDL;
+#endif
+ return true;
+}
+
+
+// static
+std::string LLMail::encryptIMEmailAddress(const LLUUID& from_agent_id,
+ const LLUUID& to_agent_id,
+ U32 time,
+ const U8* secret,
+ size_t secret_size)
+{
+#if LL_WINDOWS
+ return "blowfish-not-supported-on-windows";
+#else
+ size_t data_size = 4 + UUID_BYTES + UUID_BYTES;
+ // Convert input data into a binary blob
+ std::vector<U8> data;
+ data.resize(data_size);
+ // *NOTE: This may suffer from endian issues. Could be htolememcpy.
+ memcpy(&data[0], &time, 4);
+ memcpy(&data[4], &from_agent_id.mData[0], UUID_BYTES);
+ memcpy(&data[4 + UUID_BYTES], &to_agent_id.mData[0], UUID_BYTES);
+
+ // Encrypt the blob
+ LLBlowfishCipher cipher(secret, secret_size);
+ size_t encrypted_size = cipher.requiredEncryptionSpace(data.size());
+ U8* encrypted = new U8[encrypted_size];
+ cipher.encrypt(&data[0], data_size, encrypted, encrypted_size);
+
+ std::string address = LLBase32::encode(encrypted, encrypted_size);
+
+ // Make it more pretty for humans.
+ LLStringUtil::toLower(address);
+
+ delete [] encrypted;
+
+ return address;
+#endif
+}
diff --git a/indra/llmessage/llmail.h b/indra/llmessage/llmail.h index f437eb4db8..1523e7b5c6 100644 --- a/indra/llmessage/llmail.h +++ b/indra/llmessage/llmail.h @@ -1,130 +1,130 @@ -/** - * @file llmail.h - * @brief smtp helper functions. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLMAIL_H -#define LL_LLMAIL_H - -typedef struct apr_pool_t apr_pool_t; - -#include "llsd.h" - -class LLMail -{ -public: - // if hostname is NULL, then the host is resolved as 'mail' - static void init(const std::string& hostname, apr_pool_t* pool); - - // Allow all email transmission to be disabled/enabled. - static void enable(bool mail_enabled); - - /** - * @brief send an email - * @param from_name The name of the email sender - * @param from_address The email address for the sender - * @param to_name The name of the email recipient - * @param to_address The email recipient address - * @param subject The subject of the email - * @param headers optional X-Foo headers in an llsd map. - * @return Returns TRUE if the call succeeds, FALSE otherwise. - * - * Results in: - * From: "from_name" <from_address> - * To: "to_name" <to_address> - * Subject: subject - * - * message - */ - static BOOL send( - const char* from_name, - const char* from_address, - const char* to_name, - const char* to_address, - const char* subject, - const char* message, - const LLSD& headers = LLSD()); - - /** - * @brief build the complete smtp transaction & header for use in an - * mail. - * - * @param from_name The name of the email sender - * @param from_address The email address for the sender - * @param to_name The name of the email recipient - * @param to_address The email recipient address - * @param subject The subject of the email - * @param headers optional X-Foo headers in an llsd map. - * @return Returns the complete SMTP transaction mail header. - */ - static std::string buildSMTPTransaction( - const char* from_name, - const char* from_address, - const char* to_name, - const char* to_address, - const char* subject, - const LLSD& headers = LLSD()); - - /** - * @brief send an email with header and body. - * - * @param header The email header. Use build_mail_header(). - * @param message The unescaped email message. - * @param from_address Used for debugging - * @param to_address Used for debugging - * @return Returns true if the message could be sent. - */ - static bool send( - const std::string& header, - const std::string& message, - const char* from_address, - const char* to_address); - - // IM-to-email sessions use a "session id" based on an encrypted - // combination of from agent_id, to agent_id, and timestamp. When - // a user replies to an email we use the from_id to determine the - // sender's name and the to_id to route the message. The address - // is encrypted to prevent users from building addresses to spoof - // IMs from other users. The timestamps allow the "sessions" to - // expire, in case one of the sessions is stolen/hijacked. - // - // indra/tools/mailglue is responsible for parsing the inbound mail. - // - // secret: binary blob passed to blowfish, max length 56 bytes - // secret_size: length of blob, in bytes - // - // Returns: "base64" encoded email local-part, with _ and - as the - // non-alphanumeric characters. This allows better compatibility - // with email systems than the default / and + extra chars. JC - static std::string encryptIMEmailAddress( - const LLUUID& from_agent_id, - const LLUUID& to_agent_id, - U32 time, - const U8* secret, - size_t secret_size); -}; - -extern const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE; - -#endif +/**
+ * @file llmail.h
+ * @brief smtp helper functions.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLMAIL_H
+#define LL_LLMAIL_H
+
+typedef struct apr_pool_t apr_pool_t;
+
+#include "llsd.h"
+
+class LLMail
+{
+public:
+ // if hostname is NULL, then the host is resolved as 'mail'
+ static void init(const std::string& hostname, apr_pool_t* pool);
+
+ // Allow all email transmission to be disabled/enabled.
+ static void enable(bool mail_enabled);
+
+ /**
+ * @brief send an email
+ * @param from_name The name of the email sender
+ * @param from_address The email address for the sender
+ * @param to_name The name of the email recipient
+ * @param to_address The email recipient address
+ * @param subject The subject of the email
+ * @param headers optional X-Foo headers in an llsd map.
+ * @return Returns true if the call succeeds, false otherwise.
+ *
+ * Results in:
+ * From: "from_name" <from_address>
+ * To: "to_name" <to_address>
+ * Subject: subject
+ *
+ * message
+ */
+ static bool send(
+ const char* from_name,
+ const char* from_address,
+ const char* to_name,
+ const char* to_address,
+ const char* subject,
+ const char* message,
+ const LLSD& headers = LLSD());
+
+ /**
+ * @brief build the complete smtp transaction & header for use in an
+ * mail.
+ *
+ * @param from_name The name of the email sender
+ * @param from_address The email address for the sender
+ * @param to_name The name of the email recipient
+ * @param to_address The email recipient address
+ * @param subject The subject of the email
+ * @param headers optional X-Foo headers in an llsd map.
+ * @return Returns the complete SMTP transaction mail header.
+ */
+ static std::string buildSMTPTransaction(
+ const char* from_name,
+ const char* from_address,
+ const char* to_name,
+ const char* to_address,
+ const char* subject,
+ const LLSD& headers = LLSD());
+
+ /**
+ * @brief send an email with header and body.
+ *
+ * @param header The email header. Use build_mail_header().
+ * @param message The unescaped email message.
+ * @param from_address Used for debugging
+ * @param to_address Used for debugging
+ * @return Returns true if the message could be sent.
+ */
+ static bool send(
+ const std::string& header,
+ const std::string& message,
+ const char* from_address,
+ const char* to_address);
+
+ // IM-to-email sessions use a "session id" based on an encrypted
+ // combination of from agent_id, to agent_id, and timestamp. When
+ // a user replies to an email we use the from_id to determine the
+ // sender's name and the to_id to route the message. The address
+ // is encrypted to prevent users from building addresses to spoof
+ // IMs from other users. The timestamps allow the "sessions" to
+ // expire, in case one of the sessions is stolen/hijacked.
+ //
+ // indra/tools/mailglue is responsible for parsing the inbound mail.
+ //
+ // secret: binary blob passed to blowfish, max length 56 bytes
+ // secret_size: length of blob, in bytes
+ //
+ // Returns: "base64" encoded email local-part, with _ and - as the
+ // non-alphanumeric characters. This allows better compatibility
+ // with email systems than the default / and + extra chars. JC
+ static std::string encryptIMEmailAddress(
+ const LLUUID& from_agent_id,
+ const LLUUID& to_agent_id,
+ U32 time,
+ const U8* secret,
+ size_t secret_size);
+};
+
+extern const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE;
+
+#endif
diff --git a/indra/llmessage/llmessagebuilder.h b/indra/llmessage/llmessagebuilder.h index b35e973192..2acb47c238 100644 --- a/indra/llmessage/llmessagebuilder.h +++ b/indra/llmessage/llmessagebuilder.h @@ -1,101 +1,101 @@ -/** - * @file llmessagebuilder.h - * @brief Declaration of LLMessageBuilder class. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLMESSAGEBUILDER_H -#define LL_LLMESSAGEBUILDER_H - -#include <string> - -#include "stdtypes.h" - -class LLMsgData; -class LLQuaternion; -class LLSD; -class LLUUID; -class LLVector3; -class LLVector3d; -class LLVector4; - -class LLMessageBuilder -{ -public: - - //CLASS_LOG_TYPE(LLMessageBuilder); - - virtual ~LLMessageBuilder(); - virtual void newMessage(const char* name) = 0; - - virtual void nextBlock(const char* blockname) = 0; - virtual BOOL removeLastBlock() = 0; // TODO: babbage: remove this horror - - /** All add* methods expect pointers to canonical strings. */ - virtual void addBinaryData( - const char* varname, - const void* data, - S32 size) = 0; - virtual void addBOOL(const char* varname, BOOL b) = 0; - virtual void addS8(const char* varname, S8 s) = 0; - virtual void addU8(const char* varname, U8 u) = 0; - virtual void addS16(const char* varname, S16 i) = 0; - virtual void addU16(const char* varname, U16 i) = 0; - virtual void addF32(const char* varname, F32 f) = 0; - virtual void addS32(const char* varname, S32 s) = 0; - virtual void addU32(const char* varname, U32 u) = 0; - virtual void addU64(const char* varname, U64 lu) = 0; - virtual void addF64(const char* varname, F64 d) = 0; - virtual void addVector3(const char* varname, const LLVector3& vec) = 0; - virtual void addVector4(const char* varname, const LLVector4& vec) = 0; - virtual void addVector3d(const char* varname, const LLVector3d& vec) = 0; - virtual void addQuat(const char* varname, const LLQuaternion& quat) = 0; - virtual void addUUID(const char* varname, const LLUUID& uuid) = 0; - virtual void addIPAddr(const char* varname, const U32 ip) = 0; - virtual void addIPPort(const char* varname, const U16 port) = 0; - virtual void addString(const char* varname, const char* s) = 0; - virtual void addString(const char* varname, const std::string& s) = 0; - - virtual BOOL isMessageFull(const char* blockname) const = 0; - virtual void compressMessage(U8*& buf_ptr, U32& buffer_length) = 0; - virtual S32 getMessageSize() = 0; - - virtual BOOL isBuilt() const = 0; - virtual BOOL isClear() const = 0; - virtual U32 buildMessage( - U8* buffer, - U32 buffer_size, - U8 offset_to_data) = 0; - /**< Return built message size */ - virtual void clearMessage() = 0; - - // TODO: babbage: remove this horror - virtual void setBuilt(BOOL b) = 0; - - virtual const char* getMessageName() const = 0; - - virtual void copyFromMessageData(const LLMsgData& data) = 0; - virtual void copyFromLLSD(const LLSD& data) = 0; -}; - -#endif // LL_LLMESSAGEBUILDER_H +/**
+ * @file llmessagebuilder.h
+ * @brief Declaration of LLMessageBuilder class.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#ifndef LL_LLMESSAGEBUILDER_H
+#define LL_LLMESSAGEBUILDER_H
+
+#include <string>
+
+#include "stdtypes.h"
+
+class LLMsgData;
+class LLQuaternion;
+class LLSD;
+class LLUUID;
+class LLVector3;
+class LLVector3d;
+class LLVector4;
+
+class LLMessageBuilder
+{
+public:
+
+ //CLASS_LOG_TYPE(LLMessageBuilder);
+
+ virtual ~LLMessageBuilder();
+ virtual void newMessage(const char* name) = 0;
+
+ virtual void nextBlock(const char* blockname) = 0;
+ virtual bool removeLastBlock() = 0; // TODO: babbage: remove this horror
+
+ /** All add* methods expect pointers to canonical strings. */
+ virtual void addBinaryData(
+ const char* varname,
+ const void* data,
+ S32 size) = 0;
+ virtual void addBOOL(const char* varname, bool b) = 0;
+ virtual void addS8(const char* varname, S8 s) = 0;
+ virtual void addU8(const char* varname, U8 u) = 0;
+ virtual void addS16(const char* varname, S16 i) = 0;
+ virtual void addU16(const char* varname, U16 i) = 0;
+ virtual void addF32(const char* varname, F32 f) = 0;
+ virtual void addS32(const char* varname, S32 s) = 0;
+ virtual void addU32(const char* varname, U32 u) = 0;
+ virtual void addU64(const char* varname, U64 lu) = 0;
+ virtual void addF64(const char* varname, F64 d) = 0;
+ virtual void addVector3(const char* varname, const LLVector3& vec) = 0;
+ virtual void addVector4(const char* varname, const LLVector4& vec) = 0;
+ virtual void addVector3d(const char* varname, const LLVector3d& vec) = 0;
+ virtual void addQuat(const char* varname, const LLQuaternion& quat) = 0;
+ virtual void addUUID(const char* varname, const LLUUID& uuid) = 0;
+ virtual void addIPAddr(const char* varname, const U32 ip) = 0;
+ virtual void addIPPort(const char* varname, const U16 port) = 0;
+ virtual void addString(const char* varname, const char* s) = 0;
+ virtual void addString(const char* varname, const std::string& s) = 0;
+
+ virtual bool isMessageFull(const char* blockname) const = 0;
+ virtual void compressMessage(U8*& buf_ptr, U32& buffer_length) = 0;
+ virtual S32 getMessageSize() = 0;
+
+ virtual bool isBuilt() const = 0;
+ virtual bool isClear() const = 0;
+ virtual U32 buildMessage(
+ U8* buffer,
+ U32 buffer_size,
+ U8 offset_to_data) = 0;
+ /**< Return built message size */
+ virtual void clearMessage() = 0;
+
+ // TODO: babbage: remove this horror
+ virtual void setBuilt(bool b) = 0;
+
+ virtual const char* getMessageName() const = 0;
+
+ virtual void copyFromMessageData(const LLMsgData& data) = 0;
+ virtual void copyFromLLSD(const LLSD& data) = 0;
+};
+
+#endif // LL_LLMESSAGEBUILDER_H
diff --git a/indra/llmessage/llmessagereader.cpp b/indra/llmessage/llmessagereader.cpp index bed8655cf7..80c4379549 100644 --- a/indra/llmessage/llmessagereader.cpp +++ b/indra/llmessage/llmessagereader.cpp @@ -1,62 +1,62 @@ -/** - * @file llmessagereader.cpp - * @brief LLMessageReader class implementation - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "linden_common.h" -#include "llmessagereader.h" - -static BOOL sTimeDecodes = FALSE; - -static F32 sTimeDecodesSpamThreshold = 0.05f; - -//virtual -LLMessageReader::~LLMessageReader() -{ - // even abstract base classes need a concrete destructor -} - -//static -void LLMessageReader::setTimeDecodes(BOOL b) -{ - sTimeDecodes = b; -} - -//static -void LLMessageReader::setTimeDecodesSpamThreshold(F32 seconds) -{ - sTimeDecodesSpamThreshold = seconds; -} - -//static -BOOL LLMessageReader::getTimeDecodes() -{ - return sTimeDecodes; -} - -//static -F32 LLMessageReader::getTimeDecodesSpamThreshold() -{ - return sTimeDecodesSpamThreshold; -} +/**
+ * @file llmessagereader.cpp
+ * @brief LLMessageReader class implementation
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+#include "llmessagereader.h"
+
+static bool sTimeDecodes = false;
+
+static F32 sTimeDecodesSpamThreshold = 0.05f;
+
+//virtual
+LLMessageReader::~LLMessageReader()
+{
+ // even abstract base classes need a concrete destructor
+}
+
+//static
+void LLMessageReader::setTimeDecodes(bool b)
+{
+ sTimeDecodes = b;
+}
+
+//static
+void LLMessageReader::setTimeDecodesSpamThreshold(F32 seconds)
+{
+ sTimeDecodesSpamThreshold = seconds;
+}
+
+//static
+bool LLMessageReader::getTimeDecodes()
+{
+ return sTimeDecodes;
+}
+
+//static
+F32 LLMessageReader::getTimeDecodesSpamThreshold()
+{
+ return sTimeDecodesSpamThreshold;
+}
diff --git a/indra/llmessage/llmessagereader.h b/indra/llmessage/llmessagereader.h index f4d5a4ce83..42d8906e16 100644 --- a/indra/llmessage/llmessagereader.h +++ b/indra/llmessage/llmessagereader.h @@ -1,93 +1,94 @@ -/** - * @file llmessagereader.h - * @brief Declaration of LLMessageReader class. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLMESSAGEREADER_H -#define LL_LLMESSAGEREADER_H - -#include "stdtypes.h" - -class LLHost; -class LLMessageBuilder; -class LLMsgData; -class LLQuaternion; -class LLUUID; -class LLVector3; -class LLVector3d; -class LLVector4; - -// Error return values for getSize() functions -const S32 LL_BLOCK_NOT_IN_MESSAGE = -1; -const S32 LL_VARIABLE_NOT_IN_BLOCK = -2; -const S32 LL_MESSAGE_ERROR = -3; - - -class LLMessageReader -{ - public: - - virtual ~LLMessageReader(); - - /** All get* methods expect pointers to canonical strings. */ - virtual void getBinaryData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX) = 0; - virtual void getBOOL(const char *block, const char *var, BOOL &data, S32 blocknum = 0) = 0; - virtual void getS8(const char *block, const char *var, S8 &data, S32 blocknum = 0) = 0; - virtual void getU8(const char *block, const char *var, U8 &data, S32 blocknum = 0) = 0; - virtual void getS16(const char *block, const char *var, S16 &data, S32 blocknum = 0) = 0; - virtual void getU16(const char *block, const char *var, U16 &data, S32 blocknum = 0) = 0; - virtual void getS32(const char *block, const char *var, S32 &data, S32 blocknum = 0) = 0; - virtual void getF32(const char *block, const char *var, F32 &data, S32 blocknum = 0) = 0; - virtual void getU32(const char *block, const char *var, U32 &data, S32 blocknum = 0) = 0; - virtual void getU64(const char *block, const char *var, U64 &data, S32 blocknum = 0) = 0; - virtual void getF64(const char *block, const char *var, F64 &data, S32 blocknum = 0) = 0; - virtual void getVector3(const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0) = 0; - virtual void getVector4(const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0) = 0; - virtual void getVector3d(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0) = 0; - virtual void getQuat(const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0) = 0; - virtual void getUUID(const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0) = 0; - virtual void getIPAddr(const char *block, const char *var, U32 &ip, S32 blocknum = 0) = 0; - virtual void getIPPort(const char *block, const char *var, U16 &port, S32 blocknum = 0) = 0; - virtual void getString(const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0) = 0; - virtual void getString(const char *block, const char *var, std::string& outstr, S32 blocknum = 0) = 0; - - virtual S32 getNumberOfBlocks(const char *blockname) = 0; - virtual S32 getSize(const char *blockname, const char *varname) = 0; - virtual S32 getSize(const char *blockname, S32 blocknum, const char *varname) = 0; - - virtual void clearMessage() = 0; - - /** Returns pointer to canonical (prehashed) string. */ - virtual const char* getMessageName() const = 0; - virtual S32 getMessageSize() const = 0; - - virtual void copyToBuilder(LLMessageBuilder&) const = 0; - - static void setTimeDecodes(BOOL b); - static BOOL getTimeDecodes(); - static void setTimeDecodesSpamThreshold(F32 seconds); - static F32 getTimeDecodesSpamThreshold(); -}; - -#endif // LL_LLMESSAGEREADER_H +/**
+ * @file llmessagereader.h
+ * @brief Declaration of LLMessageReader class.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#ifndef LL_LLMESSAGEREADER_H
+#define LL_LLMESSAGEREADER_H
+
+#include "stdtypes.h"
+
+class LLHost;
+class LLMessageBuilder;
+class LLMsgData;
+class LLQuaternion;
+class LLUUID;
+class LLVector3;
+class LLVector3d;
+class LLVector4;
+
+// Error return values for getSize() functions
+const S32 LL_BLOCK_NOT_IN_MESSAGE = -1;
+const S32 LL_VARIABLE_NOT_IN_BLOCK = -2;
+const S32 LL_MESSAGE_ERROR = -3;
+
+
+class LLMessageReader
+{
+ public:
+
+ virtual ~LLMessageReader();
+
+ /** All get* methods expect pointers to canonical strings. */
+ virtual void getBinaryData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX) = 0;
+ virtual void getBOOL(const char *block, const char *var, bool &data, S32 blocknum = 0) = 0;
+ virtual void getS8(const char *block, const char *var, S8 &data, S32 blocknum = 0) = 0;
+ virtual void getU8(const char *block, const char *var, U8 &data, S32 blocknum = 0) = 0;
+ virtual void getS16(const char *block, const char *var, S16 &data, S32 blocknum = 0) = 0;
+ virtual void getU16(const char *block, const char *var, U16 &data, S32 blocknum = 0) = 0;
+ virtual void getS32(const char *block, const char *var, S32 &data, S32 blocknum = 0) = 0;
+ virtual void getF32(const char *block, const char *var, F32 &data, S32 blocknum = 0) = 0;
+ virtual void getU32(const char *block, const char *var, U32 &data, S32 blocknum = 0) = 0;
+ virtual void getU64(const char *block, const char *var, U64 &data, S32 blocknum = 0) = 0;
+ virtual void getF64(const char *block, const char *var, F64 &data, S32 blocknum = 0) = 0;
+ virtual void getVector3(const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0) = 0;
+ virtual void getVector4(const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0) = 0;
+ virtual void getVector3d(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0) = 0;
+ virtual void getQuat(const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0) = 0;
+ virtual void getUUID(const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0) = 0;
+ virtual void getIPAddr(const char *block, const char *var, U32 &ip, S32 blocknum = 0) = 0;
+ virtual void getIPPort(const char *block, const char *var, U16 &port, S32 blocknum = 0) = 0;
+ virtual void getString(const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0) = 0;
+ virtual void getString(const char *block, const char *var, std::string& outstr, S32 blocknum = 0) = 0;
+
+ virtual S32 getNumberOfBlocks(const char *blockname) = 0;
+ virtual S32 getSize(const char *blockname, const char *varname) = 0;
+ virtual S32 getSize(const char *blockname, S32 blocknum, const char *varname) = 0;
+
+ virtual void clearMessage() = 0;
+
+ /** Returns pointer to canonical (prehashed) string. */
+ virtual const char* getMessageName() const = 0;
+ virtual S32 getMessageSize() const = 0;
+
+ virtual void copyToBuilder(LLMessageBuilder&) const = 0;
+
+
+ static void setTimeDecodes(bool b);
+ static bool getTimeDecodes();
+ static void setTimeDecodesSpamThreshold(F32 seconds);
+ static F32 getTimeDecodesSpamThreshold();
+};
+
+#endif // LL_LLMESSAGEREADER_H
diff --git a/indra/llmessage/llmessagetemplate.h b/indra/llmessage/llmessagetemplate.h index 91d143b11e..454bae7238 100644 --- a/indra/llmessage/llmessagetemplate.h +++ b/indra/llmessage/llmessagetemplate.h @@ -1,421 +1,421 @@ -/** - * @file llmessagetemplate.h - * @brief Declaration of the message template classes. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLMESSAGETEMPLATE_H -#define LL_LLMESSAGETEMPLATE_H - -#include "message.h" // TODO: babbage: Remove... -#include "llstl.h" -#include "llindexedvector.h" - -class LLMsgVarData -{ -public: - LLMsgVarData() : mName(NULL), mSize(-1), mDataSize(-1), mData(NULL), mType(MVT_U8) - { - } - - LLMsgVarData(const char *name, EMsgVariableType type) : mSize(-1), mDataSize(-1), mData(NULL), mType(type) - { - mName = (char *)name; - } - - ~LLMsgVarData() - { - // copy constructor just copies the mData pointer, so only delete mData explicitly - } - - void deleteData() - { - delete[] mData; - mData = NULL; - } - - void addData(const void *indata, S32 size, EMsgVariableType type, S32 data_size = -1); - - char *getName() const { return mName; } - S32 getSize() const { return mSize; } - void *getData() { return (void*)mData; } - const void *getData() const { return (const void*)mData; } - S32 getDataSize() const { return mDataSize; } - EMsgVariableType getType() const { return mType; } - -protected: - char *mName; - S32 mSize; - S32 mDataSize; - - U8 *mData; - EMsgVariableType mType; -}; - -class LLMsgBlkData -{ -public: - LLMsgBlkData(const char *name, S32 blocknum) : mBlockNumber(blocknum), mTotalSize(-1) - { - mName = (char *)name; - } - - ~LLMsgBlkData() - { - for (msg_var_data_map_t::iterator iter = mMemberVarData.begin(); - iter != mMemberVarData.end(); iter++) - { - iter->deleteData(); - } - } - - void addVariable(const char *name, EMsgVariableType type) - { - LLMsgVarData tmp(name,type); - mMemberVarData[name] = tmp; - } - - void addData(char *name, const void *data, S32 size, EMsgVariableType type, S32 data_size = -1) - { - LLMsgVarData* temp = &mMemberVarData[name]; // creates a new entry if one doesn't exist - temp->addData(data, size, type, data_size); - } - - S32 mBlockNumber; - typedef LLIndexedVector<LLMsgVarData, const char *, 8> msg_var_data_map_t; - msg_var_data_map_t mMemberVarData; - char *mName; - S32 mTotalSize; -}; - -class LLMsgData -{ -public: - LLMsgData(const char *name) : mTotalSize(-1) - { - mName = (char *)name; - } - ~LLMsgData() - { - for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePairedPointer()); - mMemberBlocks.clear(); - } - - void addBlock(LLMsgBlkData *blockp) - { - mMemberBlocks[blockp->mName] = blockp; - } - - void addDataFast(char *blockname, char *varname, const void *data, S32 size, EMsgVariableType type, S32 data_size = -1); - -public: - typedef std::map<char*, LLMsgBlkData*> msg_blk_data_map_t; - msg_blk_data_map_t mMemberBlocks; - char *mName; - S32 mTotalSize; -}; - -// LLMessage* classes store the template of messages -class LLMessageVariable -{ -public: - LLMessageVariable() : mName(NULL), mType(MVT_NULL), mSize(-1) - { - } - - LLMessageVariable(char *name) : mType(MVT_NULL), mSize(-1) - { - mName = name; - } - - LLMessageVariable(const char *name, const EMsgVariableType type, const S32 size) : mType(type), mSize(size) - { - mName = LLMessageStringTable::getInstance()->getString(name); - } - - ~LLMessageVariable() {} - - friend std::ostream& operator<<(std::ostream& s, LLMessageVariable &msg); - - EMsgVariableType getType() const { return mType; } - S32 getSize() const { return mSize; } - char *getName() const { return mName; } -protected: - char *mName; - EMsgVariableType mType; - S32 mSize; -}; - - -typedef enum e_message_block_type -{ - MBT_NULL, - MBT_SINGLE, - MBT_MULTIPLE, - MBT_VARIABLE, - MBT_EOF -} EMsgBlockType; - -class LLMessageBlock -{ -public: - LLMessageBlock(const char *name, EMsgBlockType type, S32 number = 1) : mType(type), mNumber(number), mTotalSize(0) - { - mName = LLMessageStringTable::getInstance()->getString(name); - } - - ~LLMessageBlock() - { - for_each(mMemberVariables.begin(), mMemberVariables.end(), DeletePointer()); - } - - void addVariable(char *name, const EMsgVariableType type, const S32 size) - { - LLMessageVariable** varp = &mMemberVariables[name]; - if (*varp != NULL) - { - LL_ERRS() << name << " has already been used as a variable name!" << LL_ENDL; - } - *varp = new LLMessageVariable(name, type, size); - if (((*varp)->getType() != MVT_VARIABLE) - &&(mTotalSize != -1)) - { - mTotalSize += (*varp)->getSize(); - } - else - { - mTotalSize = -1; - } - } - - EMsgVariableType getVariableType(char *name) - { - return (mMemberVariables[name])->getType(); - } - - S32 getVariableSize(char *name) - { - return (mMemberVariables[name])->getSize(); - } - - const LLMessageVariable* getVariable(char* name) const - { - message_variable_map_t::const_iterator iter = mMemberVariables.find(name); - return iter != mMemberVariables.end()? *iter : NULL; - } - - friend std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg); - - typedef LLIndexedVector<LLMessageVariable*, const char *, 8> message_variable_map_t; - message_variable_map_t mMemberVariables; - char *mName; - EMsgBlockType mType; - S32 mNumber; - S32 mTotalSize; -}; - - -enum EMsgFrequency -{ - MFT_NULL = 0, // value is size of message number in bytes - MFT_HIGH = 1, - MFT_MEDIUM = 2, - MFT_LOW = 4 -}; - -typedef enum e_message_trust -{ - MT_TRUST, - MT_NOTRUST -} EMsgTrust; - -enum EMsgEncoding -{ - ME_UNENCODED, - ME_ZEROCODED -}; - -enum EMsgDeprecation -{ - MD_NOTDEPRECATED, - MD_UDPDEPRECATED, - MD_UDPBLACKLISTED, - MD_DEPRECATED -}; - - -class LLMessageTemplate -{ -public: - LLMessageTemplate(const char *name, U32 message_number, EMsgFrequency freq) - : - //mMemberBlocks(), - mName(NULL), - mFrequency(freq), - mTrust(MT_NOTRUST), - mEncoding(ME_ZEROCODED), - mDeprecation(MD_NOTDEPRECATED), - mMessageNumber(message_number), - mTotalSize(0), - mReceiveCount(0), - mReceiveBytes(0), - mReceiveInvalid(0), - mDecodeTimeThisFrame(0.f), - mTotalDecoded(0), - mTotalDecodeTime(0.f), - mMaxDecodeTimePerMsg(0.f), - mBanFromTrusted(false), - mBanFromUntrusted(false), - mHandlerFunc(NULL), - mUserData(NULL) - { - mName = LLMessageStringTable::getInstance()->getString(name); - } - - ~LLMessageTemplate() - { - for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePointer()); - } - - void addBlock(LLMessageBlock *blockp) - { - LLMessageBlock** member_blockp = &mMemberBlocks[blockp->mName]; - if (*member_blockp != NULL) - { - LL_ERRS() << "Block " << blockp->mName - << "has already been used as a block name!" << LL_ENDL; - } - *member_blockp = blockp; - if ( (mTotalSize != -1) - &&(blockp->mTotalSize != -1) - &&( (blockp->mType == MBT_SINGLE) - ||(blockp->mType == MBT_MULTIPLE))) - { - mTotalSize += blockp->mNumber*blockp->mTotalSize; - } - else - { - mTotalSize = -1; - } - } - - LLMessageBlock *getBlock(char *name) - { - return mMemberBlocks[name]; - } - - // Trusted messages can only be recieved on trusted circuits. - void setTrust(EMsgTrust t) - { - mTrust = t; - } - - EMsgTrust getTrust(void) const - { - return mTrust; - } - - // controls for how the message should be encoded - void setEncoding(EMsgEncoding e) - { - mEncoding = e; - } - EMsgEncoding getEncoding() const - { - return mEncoding; - } - - void setDeprecation(EMsgDeprecation d) - { - mDeprecation = d; - } - - EMsgDeprecation getDeprecation() const - { - return mDeprecation; - } - - void setHandlerFunc(void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data) - { - mHandlerFunc = handler_func; - mUserData = user_data; - } - - BOOL callHandlerFunc(LLMessageSystem *msgsystem) const - { - if (mHandlerFunc) - { - mHandlerFunc(msgsystem, mUserData); - return TRUE; - } - return FALSE; - } - - bool isUdpBanned() const - { - return mDeprecation == MD_UDPBLACKLISTED; - } - - void banUdp(); - - bool isBanned(bool trustedSource) const - { - return trustedSource ? mBanFromTrusted : mBanFromUntrusted; - } - - friend std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg); - - const LLMessageBlock* getBlock(char* name) const - { - message_block_map_t::const_iterator iter = mMemberBlocks.find(name); - return iter != mMemberBlocks.end()? *iter : NULL; - } - -public: - typedef LLIndexedVector<LLMessageBlock*, char*, 8> message_block_map_t; - message_block_map_t mMemberBlocks; - char *mName; - EMsgFrequency mFrequency; - EMsgTrust mTrust; - EMsgEncoding mEncoding; - EMsgDeprecation mDeprecation; - U32 mMessageNumber; - S32 mTotalSize; - U32 mReceiveCount; // how many of this template have been received since last reset - U32 mReceiveBytes; // How many bytes received - U32 mReceiveInvalid; // How many "invalid" packets - F32 mDecodeTimeThisFrame; // Total seconds spent decoding this frame - U32 mTotalDecoded; // Total messages successfully decoded - F32 mTotalDecodeTime; // Total time successfully decoding messages - F32 mMaxDecodeTimePerMsg; - - bool mBanFromTrusted; - bool mBanFromUntrusted; - -private: - // message handler function (this is set by each application) - void (*mHandlerFunc)(LLMessageSystem *msgsystem, void **user_data); - void **mUserData; -}; - -#endif // LL_LLMESSAGETEMPLATE_H +/**
+ * @file llmessagetemplate.h
+ * @brief Declaration of the message template classes.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#ifndef LL_LLMESSAGETEMPLATE_H
+#define LL_LLMESSAGETEMPLATE_H
+
+#include "message.h" // TODO: babbage: Remove...
+#include "llstl.h"
+#include "llindexedvector.h"
+
+class LLMsgVarData
+{
+public:
+ LLMsgVarData() : mName(NULL), mSize(-1), mDataSize(-1), mData(NULL), mType(MVT_U8)
+ {
+ }
+
+ LLMsgVarData(const char *name, EMsgVariableType type) : mSize(-1), mDataSize(-1), mData(NULL), mType(type)
+ {
+ mName = (char *)name;
+ }
+
+ ~LLMsgVarData()
+ {
+ // copy constructor just copies the mData pointer, so only delete mData explicitly
+ }
+
+ void deleteData()
+ {
+ delete[] mData;
+ mData = NULL;
+ }
+
+ void addData(const void *indata, S32 size, EMsgVariableType type, S32 data_size = -1);
+
+ char *getName() const { return mName; }
+ S32 getSize() const { return mSize; }
+ void *getData() { return (void*)mData; }
+ const void *getData() const { return (const void*)mData; }
+ S32 getDataSize() const { return mDataSize; }
+ EMsgVariableType getType() const { return mType; }
+
+protected:
+ char *mName;
+ S32 mSize;
+ S32 mDataSize;
+
+ U8 *mData;
+ EMsgVariableType mType;
+};
+
+class LLMsgBlkData
+{
+public:
+ LLMsgBlkData(const char *name, S32 blocknum) : mBlockNumber(blocknum), mTotalSize(-1)
+ {
+ mName = (char *)name;
+ }
+
+ ~LLMsgBlkData()
+ {
+ for (msg_var_data_map_t::iterator iter = mMemberVarData.begin();
+ iter != mMemberVarData.end(); iter++)
+ {
+ iter->deleteData();
+ }
+ }
+
+ void addVariable(const char *name, EMsgVariableType type)
+ {
+ LLMsgVarData tmp(name,type);
+ mMemberVarData[name] = tmp;
+ }
+
+ void addData(char *name, const void *data, S32 size, EMsgVariableType type, S32 data_size = -1)
+ {
+ LLMsgVarData* temp = &mMemberVarData[name]; // creates a new entry if one doesn't exist
+ temp->addData(data, size, type, data_size);
+ }
+
+ S32 mBlockNumber;
+ typedef LLIndexedVector<LLMsgVarData, const char *, 8> msg_var_data_map_t;
+ msg_var_data_map_t mMemberVarData;
+ char *mName;
+ S32 mTotalSize;
+};
+
+class LLMsgData
+{
+public:
+ LLMsgData(const char *name) : mTotalSize(-1)
+ {
+ mName = (char *)name;
+ }
+ ~LLMsgData()
+ {
+ for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePairedPointer());
+ mMemberBlocks.clear();
+ }
+
+ void addBlock(LLMsgBlkData *blockp)
+ {
+ mMemberBlocks[blockp->mName] = blockp;
+ }
+
+ void addDataFast(char *blockname, char *varname, const void *data, S32 size, EMsgVariableType type, S32 data_size = -1);
+
+public:
+ typedef std::map<char*, LLMsgBlkData*> msg_blk_data_map_t;
+ msg_blk_data_map_t mMemberBlocks;
+ char *mName;
+ S32 mTotalSize;
+};
+
+// LLMessage* classes store the template of messages
+class LLMessageVariable
+{
+public:
+ LLMessageVariable() : mName(NULL), mType(MVT_NULL), mSize(-1)
+ {
+ }
+
+ LLMessageVariable(char *name) : mType(MVT_NULL), mSize(-1)
+ {
+ mName = name;
+ }
+
+ LLMessageVariable(const char *name, const EMsgVariableType type, const S32 size) : mType(type), mSize(size)
+ {
+ mName = LLMessageStringTable::getInstance()->getString(name);
+ }
+
+ ~LLMessageVariable() {}
+
+ friend std::ostream& operator<<(std::ostream& s, LLMessageVariable &msg);
+
+ EMsgVariableType getType() const { return mType; }
+ S32 getSize() const { return mSize; }
+ char *getName() const { return mName; }
+protected:
+ char *mName;
+ EMsgVariableType mType;
+ S32 mSize;
+};
+
+
+typedef enum e_message_block_type
+{
+ MBT_NULL,
+ MBT_SINGLE,
+ MBT_MULTIPLE,
+ MBT_VARIABLE,
+ MBT_EOF
+} EMsgBlockType;
+
+class LLMessageBlock
+{
+public:
+ LLMessageBlock(const char *name, EMsgBlockType type, S32 number = 1) : mType(type), mNumber(number), mTotalSize(0)
+ {
+ mName = LLMessageStringTable::getInstance()->getString(name);
+ }
+
+ ~LLMessageBlock()
+ {
+ for_each(mMemberVariables.begin(), mMemberVariables.end(), DeletePointer());
+ }
+
+ void addVariable(char *name, const EMsgVariableType type, const S32 size)
+ {
+ LLMessageVariable** varp = &mMemberVariables[name];
+ if (*varp != NULL)
+ {
+ LL_ERRS() << name << " has already been used as a variable name!" << LL_ENDL;
+ }
+ *varp = new LLMessageVariable(name, type, size);
+ if (((*varp)->getType() != MVT_VARIABLE)
+ &&(mTotalSize != -1))
+ {
+ mTotalSize += (*varp)->getSize();
+ }
+ else
+ {
+ mTotalSize = -1;
+ }
+ }
+
+ EMsgVariableType getVariableType(char *name)
+ {
+ return (mMemberVariables[name])->getType();
+ }
+
+ S32 getVariableSize(char *name)
+ {
+ return (mMemberVariables[name])->getSize();
+ }
+
+ const LLMessageVariable* getVariable(char* name) const
+ {
+ message_variable_map_t::const_iterator iter = mMemberVariables.find(name);
+ return iter != mMemberVariables.end()? *iter : NULL;
+ }
+
+ friend std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg);
+
+ typedef LLIndexedVector<LLMessageVariable*, const char *, 8> message_variable_map_t;
+ message_variable_map_t mMemberVariables;
+ char *mName;
+ EMsgBlockType mType;
+ S32 mNumber;
+ S32 mTotalSize;
+};
+
+
+enum EMsgFrequency
+{
+ MFT_NULL = 0, // value is size of message number in bytes
+ MFT_HIGH = 1,
+ MFT_MEDIUM = 2,
+ MFT_LOW = 4
+};
+
+typedef enum e_message_trust
+{
+ MT_TRUST,
+ MT_NOTRUST
+} EMsgTrust;
+
+enum EMsgEncoding
+{
+ ME_UNENCODED,
+ ME_ZEROCODED
+};
+
+enum EMsgDeprecation
+{
+ MD_NOTDEPRECATED,
+ MD_UDPDEPRECATED,
+ MD_UDPBLACKLISTED,
+ MD_DEPRECATED
+};
+
+
+class LLMessageTemplate
+{
+public:
+ LLMessageTemplate(const char *name, U32 message_number, EMsgFrequency freq)
+ :
+ //mMemberBlocks(),
+ mName(NULL),
+ mFrequency(freq),
+ mTrust(MT_NOTRUST),
+ mEncoding(ME_ZEROCODED),
+ mDeprecation(MD_NOTDEPRECATED),
+ mMessageNumber(message_number),
+ mTotalSize(0),
+ mReceiveCount(0),
+ mReceiveBytes(0),
+ mReceiveInvalid(0),
+ mDecodeTimeThisFrame(0.f),
+ mTotalDecoded(0),
+ mTotalDecodeTime(0.f),
+ mMaxDecodeTimePerMsg(0.f),
+ mBanFromTrusted(false),
+ mBanFromUntrusted(false),
+ mHandlerFunc(NULL),
+ mUserData(NULL)
+ {
+ mName = LLMessageStringTable::getInstance()->getString(name);
+ }
+
+ ~LLMessageTemplate()
+ {
+ for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePointer());
+ }
+
+ void addBlock(LLMessageBlock *blockp)
+ {
+ LLMessageBlock** member_blockp = &mMemberBlocks[blockp->mName];
+ if (*member_blockp != NULL)
+ {
+ LL_ERRS() << "Block " << blockp->mName
+ << "has already been used as a block name!" << LL_ENDL;
+ }
+ *member_blockp = blockp;
+ if ( (mTotalSize != -1)
+ &&(blockp->mTotalSize != -1)
+ &&( (blockp->mType == MBT_SINGLE)
+ ||(blockp->mType == MBT_MULTIPLE)))
+ {
+ mTotalSize += blockp->mNumber*blockp->mTotalSize;
+ }
+ else
+ {
+ mTotalSize = -1;
+ }
+ }
+
+ LLMessageBlock *getBlock(char *name)
+ {
+ return mMemberBlocks[name];
+ }
+
+ // Trusted messages can only be recieved on trusted circuits.
+ void setTrust(EMsgTrust t)
+ {
+ mTrust = t;
+ }
+
+ EMsgTrust getTrust(void) const
+ {
+ return mTrust;
+ }
+
+ // controls for how the message should be encoded
+ void setEncoding(EMsgEncoding e)
+ {
+ mEncoding = e;
+ }
+ EMsgEncoding getEncoding() const
+ {
+ return mEncoding;
+ }
+
+ void setDeprecation(EMsgDeprecation d)
+ {
+ mDeprecation = d;
+ }
+
+ EMsgDeprecation getDeprecation() const
+ {
+ return mDeprecation;
+ }
+
+ void setHandlerFunc(void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data)
+ {
+ mHandlerFunc = handler_func;
+ mUserData = user_data;
+ }
+
+ bool callHandlerFunc(LLMessageSystem *msgsystem) const
+ {
+ if (mHandlerFunc)
+ {
+ mHandlerFunc(msgsystem, mUserData);
+ return true;
+ }
+ return false;
+ }
+
+ bool isUdpBanned() const
+ {
+ return mDeprecation == MD_UDPBLACKLISTED;
+ }
+
+ void banUdp();
+
+ bool isBanned(bool trustedSource) const
+ {
+ return trustedSource ? mBanFromTrusted : mBanFromUntrusted;
+ }
+
+ friend std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg);
+
+ const LLMessageBlock* getBlock(char* name) const
+ {
+ message_block_map_t::const_iterator iter = mMemberBlocks.find(name);
+ return iter != mMemberBlocks.end()? *iter : NULL;
+ }
+
+public:
+ typedef LLIndexedVector<LLMessageBlock*, char*, 8> message_block_map_t;
+ message_block_map_t mMemberBlocks;
+ char *mName;
+ EMsgFrequency mFrequency;
+ EMsgTrust mTrust;
+ EMsgEncoding mEncoding;
+ EMsgDeprecation mDeprecation;
+ U32 mMessageNumber;
+ S32 mTotalSize;
+ U32 mReceiveCount; // how many of this template have been received since last reset
+ U32 mReceiveBytes; // How many bytes received
+ U32 mReceiveInvalid; // How many "invalid" packets
+ F32 mDecodeTimeThisFrame; // Total seconds spent decoding this frame
+ U32 mTotalDecoded; // Total messages successfully decoded
+ F32 mTotalDecodeTime; // Total time successfully decoding messages
+ F32 mMaxDecodeTimePerMsg;
+
+ bool mBanFromTrusted;
+ bool mBanFromUntrusted;
+
+private:
+ // message handler function (this is set by each application)
+ void (*mHandlerFunc)(LLMessageSystem *msgsystem, void **user_data);
+ void **mUserData;
+};
+
+#endif // LL_LLMESSAGETEMPLATE_H
diff --git a/indra/llmessage/llmessagetemplateparser.cpp b/indra/llmessage/llmessagetemplateparser.cpp index 4fb9257e90..274ec3e273 100644 --- a/indra/llmessage/llmessagetemplateparser.cpp +++ b/indra/llmessage/llmessagetemplateparser.cpp @@ -1,761 +1,761 @@ -/** - * @file llmessagetemplateparser.cpp - * @brief LLMessageTemplateParser implementation - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "linden_common.h" -#include "llmessagetemplateparser.h" -#include <boost/tokenizer.hpp> - - -// What follows is a bunch of C functions to do validation. - -// Lets support a small subset of regular expressions here -// Syntax is a string made up of: -// a - checks against alphanumeric ([A-Za-z0-9]) -// c - checks against character ([A-Za-z]) -// f - checks against first variable character ([A-Za-z_]) -// v - checks against variable ([A-Za-z0-9_]) -// s - checks against sign of integer ([-0-9]) -// d - checks against integer digit ([0-9]) -// * - repeat last check - -// checks 'a' -BOOL b_return_alphanumeric_ok(char c) -{ - if ( ( (c < 'A') - ||(c > 'Z')) - &&( (c < 'a') - ||(c > 'z')) - &&( (c < '0') - ||(c > '9'))) - { - return FALSE; - } - return TRUE; -} - -// checks 'c' -BOOL b_return_character_ok(char c) -{ - if ( ( (c < 'A') - ||(c > 'Z')) - &&( (c < 'a') - ||(c > 'z'))) - { - return FALSE; - } - return TRUE; -} - -// checks 'f' -BOOL b_return_first_variable_ok(char c) -{ - if ( ( (c < 'A') - ||(c > 'Z')) - &&( (c < 'a') - ||(c > 'z')) - &&(c != '_')) - { - return FALSE; - } - return TRUE; -} - -// checks 'v' -BOOL b_return_variable_ok(char c) -{ - if ( ( (c < 'A') - ||(c > 'Z')) - &&( (c < 'a') - ||(c > 'z')) - &&( (c < '0') - ||(c > '9')) - &&(c != '_')) - { - return FALSE; - } - return TRUE; -} - -// checks 's' -BOOL b_return_signed_integer_ok(char c) -{ - if ( ( (c < '0') - ||(c > '9')) - &&(c != '-')) - { - return FALSE; - } - return TRUE; -} - -// checks 'd' -BOOL b_return_integer_ok(char c) -{ - if ( (c < '0') - ||(c > '9')) - { - return FALSE; - } - return TRUE; -} - -BOOL (*gParseCheckCharacters[])(char c) = -{ - b_return_alphanumeric_ok, - b_return_character_ok, - b_return_first_variable_ok, - b_return_variable_ok, - b_return_signed_integer_ok, - b_return_integer_ok -}; - -S32 get_checker_number(char checker) -{ - switch(checker) - { - case 'a': - return 0; - case 'c': - return 1; - case 'f': - return 2; - case 'v': - return 3; - case 's': - return 4; - case 'd': - return 5; - case '*': - return 9999; - default: - return -1; - } -} - -// check token based on passed simplified regular expression -BOOL b_check_token(const char *token, const char *regexp) -{ - S32 tptr, rptr = 0; - S32 current_checker, next_checker = 0; - - current_checker = get_checker_number(regexp[rptr++]); - - if (current_checker == -1) - { - LL_ERRS() << "Invalid regular expression value!" << LL_ENDL; - return FALSE; - } - - if (current_checker == 9999) - { - LL_ERRS() << "Regular expression can't start with *!" << LL_ENDL; - return FALSE; - } - - for (tptr = 0; token[tptr]; tptr++) - { - if (current_checker == -1) - { - LL_ERRS() << "Input exceeds regular expression!\nDid you forget a *?" << LL_ENDL; - return FALSE; - } - - if (!gParseCheckCharacters[current_checker](token[tptr])) - { - return FALSE; - } - if (next_checker != 9999) - { - next_checker = get_checker_number(regexp[rptr++]); - if (next_checker != 9999) - { - current_checker = next_checker; - } - } - } - return TRUE; -} - -// C variable can be made up of upper or lower case letters, underscores, or numbers, but can't start with a number -BOOL b_variable_ok(const char *token) -{ - if (!b_check_token(token, "fv*")) - { - LL_WARNS() << "Token '" << token << "' isn't a variable!" << LL_ENDL; - return FALSE; - } - return TRUE; -} - -// An integer is made up of the digits 0-9 and may be preceded by a '-' -BOOL b_integer_ok(const char *token) -{ - if (!b_check_token(token, "sd*")) - { - LL_WARNS() << "Token isn't an integer!" << LL_ENDL; - return FALSE; - } - return TRUE; -} - -// An integer is made up of the digits 0-9 -BOOL b_positive_integer_ok(const char *token) -{ - if (!b_check_token(token, "d*")) - { - LL_WARNS() << "Token isn't an integer!" << LL_ENDL; - return FALSE; - } - return TRUE; -} - - -// Done with C functions, here's the tokenizer. - -typedef boost::tokenizer< boost::char_separator<char> > tokenizer; - -LLTemplateTokenizer::LLTemplateTokenizer(const std::string & contents) : mStarted(false), mTokens() -{ - boost::char_separator<char> newline("\r\n", "", boost::keep_empty_tokens); - boost::char_separator<char> spaces(" \t"); - U32 line_counter = 1; - - tokenizer line_tokens(contents, newline); - for(tokenizer::iterator line_iter = line_tokens.begin(); - line_iter != line_tokens.end(); - ++line_iter, ++line_counter) - { - tokenizer word_tokens(*line_iter, spaces); - for(tokenizer::iterator word_iter = word_tokens.begin(); - word_iter != word_tokens.end(); - ++word_iter) - { - if((*word_iter)[0] == '/') - { - break; // skip to end of line on comments - } - positioned_token pt;// = new positioned_token(); - pt.str = std::string(*word_iter); - pt.line = line_counter; - mTokens.push_back(pt); - } - } - mCurrent = mTokens.begin(); -} -void LLTemplateTokenizer::inc() -{ - if(atEOF()) - { - error("trying to increment token of EOF"); - } - else if(mStarted) - { - ++mCurrent; - } - else - { - mStarted = true; - mCurrent = mTokens.begin(); - } -} -void LLTemplateTokenizer::dec() -{ - if(mCurrent == mTokens.begin()) - { - if(mStarted) - { - mStarted = false; - } - else - { - error("trying to decrement past beginning of file"); - } - } - else - { - mCurrent--; - } -} - -std::string LLTemplateTokenizer::get() const -{ - if(atEOF()) - { - error("trying to get EOF"); - } - return mCurrent->str; -} - -U32 LLTemplateTokenizer::line() const -{ - if(atEOF()) - { - return 0; - } - return mCurrent->line; -} - -bool LLTemplateTokenizer::atEOF() const -{ - return mCurrent == mTokens.end(); -} - -std::string LLTemplateTokenizer::next() -{ - inc(); - return get(); -} - -bool LLTemplateTokenizer::want(const std::string & token) -{ - if(atEOF()) return false; - inc(); - if(atEOF()) return false; - if(get() != token) - { - dec(); // back up a step - return false; - } - return true; -} - -bool LLTemplateTokenizer::wantEOF() -{ - // see if the next token is EOF - if(atEOF()) return true; - inc(); - if(!atEOF()) - { - dec(); // back up a step - return false; - } - return true; -} - -void LLTemplateTokenizer::error(std::string message) const -{ - if(atEOF()) - { - LL_ERRS() << "Unexpected end of file: " << message << LL_ENDL; - } - else - { - LL_ERRS() << "Problem parsing message template at line " - << line() << ", with token '" << get() << "' : " - << message << LL_ENDL; - } -} - - -// Done with tokenizer, next is the parser. - -LLTemplateParser::LLTemplateParser(LLTemplateTokenizer & tokens): - mVersion(0.f), - mMessages() -{ - // the version number should be the first thing in the file - if (tokens.want("version")) - { - // version number - std::string vers_string = tokens.next(); - mVersion = (F32)atof(vers_string.c_str()); - - LL_INFOS() << "### Message template version " << mVersion << " ###" << LL_ENDL; - } - else - { - LL_ERRS() << "Version must be first in the message template, found " - << tokens.next() << LL_ENDL; - } - - while(LLMessageTemplate * templatep = parseMessage(tokens)) - { - if (templatep->getDeprecation() != MD_DEPRECATED) - { - mMessages.push_back(templatep); - } - else - { - delete templatep; - } - } - - if(!tokens.wantEOF()) - { - LL_ERRS() << "Expected end of template or a message, instead found: " - << tokens.next() << " at " << tokens.line() << LL_ENDL; - } -} - -F32 LLTemplateParser::getVersion() const -{ - return mVersion; -} - -LLTemplateParser::message_iterator LLTemplateParser::getMessagesBegin() const -{ - return mMessages.begin(); -} - -LLTemplateParser::message_iterator LLTemplateParser::getMessagesEnd() const -{ - return mMessages.end(); -} - - -// static -LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens) -{ - LLMessageTemplate *templatep = NULL; - if(!tokens.want("{")) - { - return NULL; - } - - // name first - std::string template_name = tokens.next(); - - // is name a legit C variable name - if (!b_variable_ok(template_name.c_str())) - { - LL_ERRS() << "Not legit variable name: " << template_name << " at " << tokens.line() << LL_ENDL; - } - - // ok, now get Frequency ("High", "Medium", or "Low") - EMsgFrequency frequency = MFT_LOW; - std::string freq_string = tokens.next(); - if (freq_string == "High") - { - frequency = MFT_HIGH; - } - else if (freq_string == "Medium") - { - frequency = MFT_MEDIUM; - } - else if (freq_string == "Low" || freq_string == "Fixed") - { - frequency = MFT_LOW; - } - else - { - LL_ERRS() << "Expected frequency, got " << freq_string << " at " << tokens.line() << LL_ENDL; - } - - // TODO more explicit checking here pls - U32 message_number = strtoul(tokens.next().c_str(),NULL,0); - - switch (frequency) { - case MFT_HIGH: - break; - case MFT_MEDIUM: - message_number = (255 << 8) | message_number; - break; - case MFT_LOW: - message_number = (255 << 24) | (255 << 16) | message_number; - break; - default: - LL_ERRS() << "Unknown frequency enum: " << frequency << LL_ENDL; - } - - templatep = new LLMessageTemplate( - template_name.c_str(), - message_number, - frequency); - - // Now get trust ("Trusted", "NotTrusted") - std::string trust = tokens.next(); - if (trust == "Trusted") - { - templatep->setTrust(MT_TRUST); - } - else if (trust == "NotTrusted") - { - templatep->setTrust(MT_NOTRUST); - } - else - { - LL_ERRS() << "Bad trust " << trust << " at " << tokens.line() << LL_ENDL; - } - - // get encoding - std::string encoding = tokens.next(); - if(encoding == "Unencoded") - { - templatep->setEncoding(ME_UNENCODED); - } - else if(encoding == "Zerocoded") - { - templatep->setEncoding(ME_ZEROCODED); - } - else - { - LL_ERRS() << "Bad encoding " << encoding << " at " << tokens.line() << LL_ENDL; - } - - // get deprecation - if(tokens.want("Deprecated")) - { - templatep->setDeprecation(MD_DEPRECATED); - } - else if (tokens.want("UDPDeprecated")) - { - templatep->setDeprecation(MD_UDPDEPRECATED); - } - else if (tokens.want("UDPBlackListed")) - { - templatep->setDeprecation(MD_UDPBLACKLISTED); - } - else if (tokens.want("NotDeprecated")) - { - // this is the default value, but it can't hurt to set it twice - templatep->setDeprecation(MD_NOTDEPRECATED); - } - else { - // It's probably a brace, let's just start block processing - } - - while(LLMessageBlock * blockp = parseBlock(tokens)) - { - templatep->addBlock(blockp); - } - - if(!tokens.want("}")) - { - LL_ERRS() << "Expecting closing } for message " << template_name - << " at " << tokens.line() << LL_ENDL; - } - return templatep; -} - -// static -LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens) -{ - LLMessageBlock * blockp = NULL; - - if(!tokens.want("{")) - { - return NULL; - } - - // name first - std::string block_name = tokens.next(); - - // is name a legit C variable name - if (!b_variable_ok(block_name.c_str())) - { - LL_ERRS() << "not a legal block name: " << block_name - << " at " << tokens.line() << LL_ENDL; - } - - // now, block type ("Single", "Multiple", or "Variable") - std::string block_type = tokens.next(); - // which one is it? - if (block_type == "Single") - { - // ok, we can create a block - blockp = new LLMessageBlock(block_name.c_str(), MBT_SINGLE); - } - else if (block_type == "Multiple") - { - // need to get the number of repeats - std::string repeats = tokens.next(); - - // is it a legal integer - if (!b_positive_integer_ok(repeats.c_str())) - { - LL_ERRS() << "not a legal integer for block multiple count: " - << repeats << " at " << tokens.line() << LL_ENDL; - } - - // ok, we can create a block - blockp = new LLMessageBlock(block_name.c_str(), - MBT_MULTIPLE, - atoi(repeats.c_str())); - } - else if (block_type == "Variable") - { - // ok, we can create a block - blockp = new LLMessageBlock(block_name.c_str(), MBT_VARIABLE); - } - else - { - LL_ERRS() << "bad block type: " << block_type - << " at " << tokens.line() << LL_ENDL; - } - - - while(LLMessageVariable * varp = parseVariable(tokens)) - { - blockp->addVariable(varp->getName(), - varp->getType(), - varp->getSize()); - delete varp; - } - - if(!tokens.want("}")) - { - LL_ERRS() << "Expecting closing } for block " << block_name - << " at " << tokens.line() << LL_ENDL; - } - return blockp; - -} - -// static -LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens) -{ - LLMessageVariable * varp = NULL; - if(!tokens.want("{")) - { - return NULL; - } - - std::string var_name = tokens.next(); - - if (!b_variable_ok(var_name.c_str())) - { - LL_ERRS() << "Not a legit variable name: " << var_name - << " at " << tokens.line() << LL_ENDL; - } - - std::string var_type = tokens.next(); - - if (var_type == "U8") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_U8, 1); - } - else if (var_type == "U16") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_U16, 2); - } - else if (var_type == "U32") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_U32, 4); - } - else if (var_type == "U64") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_U64, 8); - } - else if (var_type == "S8") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_S8, 1); - } - else if (var_type == "S16") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_S16, 2); - } - else if (var_type == "S32") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_S32, 4); - } - else if (var_type == "S64") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_S64, 8); - } - else if (var_type == "F32") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_F32, 4); - } - else if (var_type == "F64") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_F64, 8); - } - else if (var_type == "LLVector3") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3, 12); - } - else if (var_type == "LLVector3d") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3d, 24); - } - else if (var_type == "LLVector4") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector4, 16); - } - else if (var_type == "LLQuaternion") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_LLQuaternion, 12); - } - else if (var_type == "LLUUID") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_LLUUID, 16); - } - else if (var_type == "BOOL") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_BOOL, 1); - } - else if (var_type == "IPADDR") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_IP_ADDR, 4); - } - else if (var_type == "IPPORT") - { - varp = new LLMessageVariable(var_name.c_str(), MVT_IP_PORT, 2); - } - else if (var_type == "Fixed" || var_type == "Variable") - { - std::string variable_size = tokens.next(); - - if (!b_positive_integer_ok(variable_size.c_str())) - { - LL_ERRS() << "not a legal integer variable size: " << variable_size - << " at " << tokens.line() << LL_ENDL; - } - - EMsgVariableType type_enum; - if(var_type == "Variable") - { - type_enum = MVT_VARIABLE; - } - else if(var_type == "Fixed") - { - type_enum = MVT_FIXED; - } - else - { - type_enum = MVT_FIXED; // removes a warning - LL_ERRS() << "bad variable type: " << var_type - << " at " << tokens.line() << LL_ENDL; - } - - varp = new LLMessageVariable( - var_name.c_str(), - type_enum, - atoi(variable_size.c_str())); - } - else - { - LL_ERRS() << "bad variable type:" << var_type - << " at " << tokens.line() << LL_ENDL; - } - - if(!tokens.want("}")) - { - LL_ERRS() << "Expecting closing } for variable " << var_name - << " at " << tokens.line() << LL_ENDL; - } - return varp; -} +/**
+ * @file llmessagetemplateparser.cpp
+ * @brief LLMessageTemplateParser implementation
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+#include "llmessagetemplateparser.h"
+#include <boost/tokenizer.hpp>
+
+
+// What follows is a bunch of C functions to do validation.
+
+// Lets support a small subset of regular expressions here
+// Syntax is a string made up of:
+// a - checks against alphanumeric ([A-Za-z0-9])
+// c - checks against character ([A-Za-z])
+// f - checks against first variable character ([A-Za-z_])
+// v - checks against variable ([A-Za-z0-9_])
+// s - checks against sign of integer ([-0-9])
+// d - checks against integer digit ([0-9])
+// * - repeat last check
+
+// checks 'a'
+bool b_return_alphanumeric_ok(char c)
+{
+ if ( ( (c < 'A')
+ ||(c > 'Z'))
+ &&( (c < 'a')
+ ||(c > 'z'))
+ &&( (c < '0')
+ ||(c > '9')))
+ {
+ return false;
+ }
+ return true;
+}
+
+// checks 'c'
+bool b_return_character_ok(char c)
+{
+ if ( ( (c < 'A')
+ ||(c > 'Z'))
+ &&( (c < 'a')
+ ||(c > 'z')))
+ {
+ return false;
+ }
+ return true;
+}
+
+// checks 'f'
+bool b_return_first_variable_ok(char c)
+{
+ if ( ( (c < 'A')
+ ||(c > 'Z'))
+ &&( (c < 'a')
+ ||(c > 'z'))
+ &&(c != '_'))
+ {
+ return false;
+ }
+ return true;
+}
+
+// checks 'v'
+bool b_return_variable_ok(char c)
+{
+ if ( ( (c < 'A')
+ ||(c > 'Z'))
+ &&( (c < 'a')
+ ||(c > 'z'))
+ &&( (c < '0')
+ ||(c > '9'))
+ &&(c != '_'))
+ {
+ return false;
+ }
+ return true;
+}
+
+// checks 's'
+bool b_return_signed_integer_ok(char c)
+{
+ if ( ( (c < '0')
+ ||(c > '9'))
+ &&(c != '-'))
+ {
+ return false;
+ }
+ return true;
+}
+
+// checks 'd'
+bool b_return_integer_ok(char c)
+{
+ if ( (c < '0')
+ ||(c > '9'))
+ {
+ return false;
+ }
+ return true;
+}
+
+bool (*gParseCheckCharacters[])(char c) =
+{
+ b_return_alphanumeric_ok,
+ b_return_character_ok,
+ b_return_first_variable_ok,
+ b_return_variable_ok,
+ b_return_signed_integer_ok,
+ b_return_integer_ok
+};
+
+S32 get_checker_number(char checker)
+{
+ switch(checker)
+ {
+ case 'a':
+ return 0;
+ case 'c':
+ return 1;
+ case 'f':
+ return 2;
+ case 'v':
+ return 3;
+ case 's':
+ return 4;
+ case 'd':
+ return 5;
+ case '*':
+ return 9999;
+ default:
+ return -1;
+ }
+}
+
+// check token based on passed simplified regular expression
+bool b_check_token(const char *token, const char *regexp)
+{
+ S32 tptr, rptr = 0;
+ S32 current_checker, next_checker = 0;
+
+ current_checker = get_checker_number(regexp[rptr++]);
+
+ if (current_checker == -1)
+ {
+ LL_ERRS() << "Invalid regular expression value!" << LL_ENDL;
+ return false;
+ }
+
+ if (current_checker == 9999)
+ {
+ LL_ERRS() << "Regular expression can't start with *!" << LL_ENDL;
+ return false;
+ }
+
+ for (tptr = 0; token[tptr]; tptr++)
+ {
+ if (current_checker == -1)
+ {
+ LL_ERRS() << "Input exceeds regular expression!\nDid you forget a *?" << LL_ENDL;
+ return false;
+ }
+
+ if (!gParseCheckCharacters[current_checker](token[tptr]))
+ {
+ return false;
+ }
+ if (next_checker != 9999)
+ {
+ next_checker = get_checker_number(regexp[rptr++]);
+ if (next_checker != 9999)
+ {
+ current_checker = next_checker;
+ }
+ }
+ }
+ return true;
+}
+
+// C variable can be made up of upper or lower case letters, underscores, or numbers, but can't start with a number
+bool b_variable_ok(const char *token)
+{
+ if (!b_check_token(token, "fv*"))
+ {
+ LL_WARNS() << "Token '" << token << "' isn't a variable!" << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+// An integer is made up of the digits 0-9 and may be preceded by a '-'
+bool b_integer_ok(const char *token)
+{
+ if (!b_check_token(token, "sd*"))
+ {
+ LL_WARNS() << "Token isn't an integer!" << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+// An integer is made up of the digits 0-9
+bool b_positive_integer_ok(const char *token)
+{
+ if (!b_check_token(token, "d*"))
+ {
+ LL_WARNS() << "Token isn't an integer!" << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+
+// Done with C functions, here's the tokenizer.
+
+typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
+
+LLTemplateTokenizer::LLTemplateTokenizer(const std::string & contents) : mStarted(false), mTokens()
+{
+ boost::char_separator<char> newline("\r\n", "", boost::keep_empty_tokens);
+ boost::char_separator<char> spaces(" \t");
+ U32 line_counter = 1;
+
+ tokenizer line_tokens(contents, newline);
+ for(tokenizer::iterator line_iter = line_tokens.begin();
+ line_iter != line_tokens.end();
+ ++line_iter, ++line_counter)
+ {
+ tokenizer word_tokens(*line_iter, spaces);
+ for(tokenizer::iterator word_iter = word_tokens.begin();
+ word_iter != word_tokens.end();
+ ++word_iter)
+ {
+ if((*word_iter)[0] == '/')
+ {
+ break; // skip to end of line on comments
+ }
+ positioned_token pt;// = new positioned_token();
+ pt.str = std::string(*word_iter);
+ pt.line = line_counter;
+ mTokens.push_back(pt);
+ }
+ }
+ mCurrent = mTokens.begin();
+}
+void LLTemplateTokenizer::inc()
+{
+ if(atEOF())
+ {
+ error("trying to increment token of EOF");
+ }
+ else if(mStarted)
+ {
+ ++mCurrent;
+ }
+ else
+ {
+ mStarted = true;
+ mCurrent = mTokens.begin();
+ }
+}
+void LLTemplateTokenizer::dec()
+{
+ if(mCurrent == mTokens.begin())
+ {
+ if(mStarted)
+ {
+ mStarted = false;
+ }
+ else
+ {
+ error("trying to decrement past beginning of file");
+ }
+ }
+ else
+ {
+ mCurrent--;
+ }
+}
+
+std::string LLTemplateTokenizer::get() const
+{
+ if(atEOF())
+ {
+ error("trying to get EOF");
+ }
+ return mCurrent->str;
+}
+
+U32 LLTemplateTokenizer::line() const
+{
+ if(atEOF())
+ {
+ return 0;
+ }
+ return mCurrent->line;
+}
+
+bool LLTemplateTokenizer::atEOF() const
+{
+ return mCurrent == mTokens.end();
+}
+
+std::string LLTemplateTokenizer::next()
+{
+ inc();
+ return get();
+}
+
+bool LLTemplateTokenizer::want(const std::string & token)
+{
+ if(atEOF()) return false;
+ inc();
+ if(atEOF()) return false;
+ if(get() != token)
+ {
+ dec(); // back up a step
+ return false;
+ }
+ return true;
+}
+
+bool LLTemplateTokenizer::wantEOF()
+{
+ // see if the next token is EOF
+ if(atEOF()) return true;
+ inc();
+ if(!atEOF())
+ {
+ dec(); // back up a step
+ return false;
+ }
+ return true;
+}
+
+void LLTemplateTokenizer::error(std::string message) const
+{
+ if(atEOF())
+ {
+ LL_ERRS() << "Unexpected end of file: " << message << LL_ENDL;
+ }
+ else
+ {
+ LL_ERRS() << "Problem parsing message template at line "
+ << line() << ", with token '" << get() << "' : "
+ << message << LL_ENDL;
+ }
+}
+
+
+// Done with tokenizer, next is the parser.
+
+LLTemplateParser::LLTemplateParser(LLTemplateTokenizer & tokens):
+ mVersion(0.f),
+ mMessages()
+{
+ // the version number should be the first thing in the file
+ if (tokens.want("version"))
+ {
+ // version number
+ std::string vers_string = tokens.next();
+ mVersion = (F32)atof(vers_string.c_str());
+
+ LL_INFOS() << "### Message template version " << mVersion << " ###" << LL_ENDL;
+ }
+ else
+ {
+ LL_ERRS() << "Version must be first in the message template, found "
+ << tokens.next() << LL_ENDL;
+ }
+
+ while(LLMessageTemplate * templatep = parseMessage(tokens))
+ {
+ if (templatep->getDeprecation() != MD_DEPRECATED)
+ {
+ mMessages.push_back(templatep);
+ }
+ else
+ {
+ delete templatep;
+ }
+ }
+
+ if(!tokens.wantEOF())
+ {
+ LL_ERRS() << "Expected end of template or a message, instead found: "
+ << tokens.next() << " at " << tokens.line() << LL_ENDL;
+ }
+}
+
+F32 LLTemplateParser::getVersion() const
+{
+ return mVersion;
+}
+
+LLTemplateParser::message_iterator LLTemplateParser::getMessagesBegin() const
+{
+ return mMessages.begin();
+}
+
+LLTemplateParser::message_iterator LLTemplateParser::getMessagesEnd() const
+{
+ return mMessages.end();
+}
+
+
+// static
+LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens)
+{
+ LLMessageTemplate *templatep = NULL;
+ if(!tokens.want("{"))
+ {
+ return NULL;
+ }
+
+ // name first
+ std::string template_name = tokens.next();
+
+ // is name a legit C variable name
+ if (!b_variable_ok(template_name.c_str()))
+ {
+ LL_ERRS() << "Not legit variable name: " << template_name << " at " << tokens.line() << LL_ENDL;
+ }
+
+ // ok, now get Frequency ("High", "Medium", or "Low")
+ EMsgFrequency frequency = MFT_LOW;
+ std::string freq_string = tokens.next();
+ if (freq_string == "High")
+ {
+ frequency = MFT_HIGH;
+ }
+ else if (freq_string == "Medium")
+ {
+ frequency = MFT_MEDIUM;
+ }
+ else if (freq_string == "Low" || freq_string == "Fixed")
+ {
+ frequency = MFT_LOW;
+ }
+ else
+ {
+ LL_ERRS() << "Expected frequency, got " << freq_string << " at " << tokens.line() << LL_ENDL;
+ }
+
+ // TODO more explicit checking here pls
+ U32 message_number = strtoul(tokens.next().c_str(),NULL,0);
+
+ switch (frequency) {
+ case MFT_HIGH:
+ break;
+ case MFT_MEDIUM:
+ message_number = (255 << 8) | message_number;
+ break;
+ case MFT_LOW:
+ message_number = (255 << 24) | (255 << 16) | message_number;
+ break;
+ default:
+ LL_ERRS() << "Unknown frequency enum: " << frequency << LL_ENDL;
+ }
+
+ templatep = new LLMessageTemplate(
+ template_name.c_str(),
+ message_number,
+ frequency);
+
+ // Now get trust ("Trusted", "NotTrusted")
+ std::string trust = tokens.next();
+ if (trust == "Trusted")
+ {
+ templatep->setTrust(MT_TRUST);
+ }
+ else if (trust == "NotTrusted")
+ {
+ templatep->setTrust(MT_NOTRUST);
+ }
+ else
+ {
+ LL_ERRS() << "Bad trust " << trust << " at " << tokens.line() << LL_ENDL;
+ }
+
+ // get encoding
+ std::string encoding = tokens.next();
+ if(encoding == "Unencoded")
+ {
+ templatep->setEncoding(ME_UNENCODED);
+ }
+ else if(encoding == "Zerocoded")
+ {
+ templatep->setEncoding(ME_ZEROCODED);
+ }
+ else
+ {
+ LL_ERRS() << "Bad encoding " << encoding << " at " << tokens.line() << LL_ENDL;
+ }
+
+ // get deprecation
+ if(tokens.want("Deprecated"))
+ {
+ templatep->setDeprecation(MD_DEPRECATED);
+ }
+ else if (tokens.want("UDPDeprecated"))
+ {
+ templatep->setDeprecation(MD_UDPDEPRECATED);
+ }
+ else if (tokens.want("UDPBlackListed"))
+ {
+ templatep->setDeprecation(MD_UDPBLACKLISTED);
+ }
+ else if (tokens.want("NotDeprecated"))
+ {
+ // this is the default value, but it can't hurt to set it twice
+ templatep->setDeprecation(MD_NOTDEPRECATED);
+ }
+ else {
+ // It's probably a brace, let's just start block processing
+ }
+
+ while(LLMessageBlock * blockp = parseBlock(tokens))
+ {
+ templatep->addBlock(blockp);
+ }
+
+ if(!tokens.want("}"))
+ {
+ LL_ERRS() << "Expecting closing } for message " << template_name
+ << " at " << tokens.line() << LL_ENDL;
+ }
+ return templatep;
+}
+
+// static
+LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens)
+{
+ LLMessageBlock * blockp = NULL;
+
+ if(!tokens.want("{"))
+ {
+ return NULL;
+ }
+
+ // name first
+ std::string block_name = tokens.next();
+
+ // is name a legit C variable name
+ if (!b_variable_ok(block_name.c_str()))
+ {
+ LL_ERRS() << "not a legal block name: " << block_name
+ << " at " << tokens.line() << LL_ENDL;
+ }
+
+ // now, block type ("Single", "Multiple", or "Variable")
+ std::string block_type = tokens.next();
+ // which one is it?
+ if (block_type == "Single")
+ {
+ // ok, we can create a block
+ blockp = new LLMessageBlock(block_name.c_str(), MBT_SINGLE);
+ }
+ else if (block_type == "Multiple")
+ {
+ // need to get the number of repeats
+ std::string repeats = tokens.next();
+
+ // is it a legal integer
+ if (!b_positive_integer_ok(repeats.c_str()))
+ {
+ LL_ERRS() << "not a legal integer for block multiple count: "
+ << repeats << " at " << tokens.line() << LL_ENDL;
+ }
+
+ // ok, we can create a block
+ blockp = new LLMessageBlock(block_name.c_str(),
+ MBT_MULTIPLE,
+ atoi(repeats.c_str()));
+ }
+ else if (block_type == "Variable")
+ {
+ // ok, we can create a block
+ blockp = new LLMessageBlock(block_name.c_str(), MBT_VARIABLE);
+ }
+ else
+ {
+ LL_ERRS() << "bad block type: " << block_type
+ << " at " << tokens.line() << LL_ENDL;
+ }
+
+
+ while(LLMessageVariable * varp = parseVariable(tokens))
+ {
+ blockp->addVariable(varp->getName(),
+ varp->getType(),
+ varp->getSize());
+ delete varp;
+ }
+
+ if(!tokens.want("}"))
+ {
+ LL_ERRS() << "Expecting closing } for block " << block_name
+ << " at " << tokens.line() << LL_ENDL;
+ }
+ return blockp;
+
+}
+
+// static
+LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens)
+{
+ LLMessageVariable * varp = NULL;
+ if(!tokens.want("{"))
+ {
+ return NULL;
+ }
+
+ std::string var_name = tokens.next();
+
+ if (!b_variable_ok(var_name.c_str()))
+ {
+ LL_ERRS() << "Not a legit variable name: " << var_name
+ << " at " << tokens.line() << LL_ENDL;
+ }
+
+ std::string var_type = tokens.next();
+
+ if (var_type == "U8")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_U8, 1);
+ }
+ else if (var_type == "U16")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_U16, 2);
+ }
+ else if (var_type == "U32")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_U32, 4);
+ }
+ else if (var_type == "U64")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_U64, 8);
+ }
+ else if (var_type == "S8")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_S8, 1);
+ }
+ else if (var_type == "S16")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_S16, 2);
+ }
+ else if (var_type == "S32")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_S32, 4);
+ }
+ else if (var_type == "S64")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_S64, 8);
+ }
+ else if (var_type == "F32")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_F32, 4);
+ }
+ else if (var_type == "F64")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_F64, 8);
+ }
+ else if (var_type == "LLVector3")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3, 12);
+ }
+ else if (var_type == "LLVector3d")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3d, 24);
+ }
+ else if (var_type == "LLVector4")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector4, 16);
+ }
+ else if (var_type == "LLQuaternion")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_LLQuaternion, 12);
+ }
+ else if (var_type == "LLUUID")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_LLUUID, 16);
+ }
+ else if (var_type == "BOOL")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_BOOL, 1);
+ }
+ else if (var_type == "IPADDR")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_IP_ADDR, 4);
+ }
+ else if (var_type == "IPPORT")
+ {
+ varp = new LLMessageVariable(var_name.c_str(), MVT_IP_PORT, 2);
+ }
+ else if (var_type == "Fixed" || var_type == "Variable")
+ {
+ std::string variable_size = tokens.next();
+
+ if (!b_positive_integer_ok(variable_size.c_str()))
+ {
+ LL_ERRS() << "not a legal integer variable size: " << variable_size
+ << " at " << tokens.line() << LL_ENDL;
+ }
+
+ EMsgVariableType type_enum;
+ if(var_type == "Variable")
+ {
+ type_enum = MVT_VARIABLE;
+ }
+ else if(var_type == "Fixed")
+ {
+ type_enum = MVT_FIXED;
+ }
+ else
+ {
+ type_enum = MVT_FIXED; // removes a warning
+ LL_ERRS() << "bad variable type: " << var_type
+ << " at " << tokens.line() << LL_ENDL;
+ }
+
+ varp = new LLMessageVariable(
+ var_name.c_str(),
+ type_enum,
+ atoi(variable_size.c_str()));
+ }
+ else
+ {
+ LL_ERRS() << "bad variable type:" << var_type
+ << " at " << tokens.line() << LL_ENDL;
+ }
+
+ if(!tokens.want("}"))
+ {
+ LL_ERRS() << "Expecting closing } for variable " << var_name
+ << " at " << tokens.line() << LL_ENDL;
+ }
+ return varp;
+}
diff --git a/indra/llmessage/llmessagethrottle.cpp b/indra/llmessage/llmessagethrottle.cpp index ef4f3702fc..77af27e404 100644 --- a/indra/llmessage/llmessagethrottle.cpp +++ b/indra/llmessage/llmessagethrottle.cpp @@ -1,153 +1,153 @@ -/** - * @file llmessagethrottle.cpp - * @brief LLMessageThrottle class used for throttling messages. - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#include "linden_common.h" - -#include "llhash.h" - -#include "llmessagethrottle.h" -#include "llframetimer.h" - -// This is used for the stl search_n function. -bool eq_message_throttle_entry(LLMessageThrottleEntry a, LLMessageThrottleEntry b) - { return a.getHash() == b.getHash(); } - -const U64 SEC_TO_USEC = 1000000; - -// How long (in microseconds) each type of message stays in its throttle list. -const U64 MAX_MESSAGE_AGE[MTC_EOF] = -{ - 10 * SEC_TO_USEC, // MTC_VIEWER_ALERT - 10 * SEC_TO_USEC // MTC_AGENT_ALERT -}; - -LLMessageThrottle::LLMessageThrottle() -{ -} - -LLMessageThrottle::~LLMessageThrottle() -{ -} - -void LLMessageThrottle::pruneEntries() -{ - // Go through each message category, and prune entries older than max age. - S32 cat; - for (cat = 0; cat < MTC_EOF; cat++) - { - message_list_t* message_list = &(mMessageList[cat]); - - // Use a reverse iterator, since entries on the back will be the oldest. - message_list_reverse_iterator_t r_iterator = message_list->rbegin(); - message_list_reverse_iterator_t r_last = message_list->rend(); - - // Look for the first entry younger than the maximum age. - F32 max_age = (F32)MAX_MESSAGE_AGE[cat]; - BOOL found = FALSE; - while (r_iterator != r_last && !found) - { - if ( LLFrameTimer::getTotalTime() - (*r_iterator).getEntryTime() < max_age ) - { - // We found a young enough entry. - found = TRUE; - - // Did we find at least one entry to remove? - if (r_iterator != message_list->rbegin()) - { - // Yes, remove it. - message_list->erase(r_iterator.base(), message_list->end()); - } - } - else - { - r_iterator++; - } - } - - // If we didn't find any entries young enough to keep, remove them all. - if (!found) - { - message_list->clear(); - } - } -} - -BOOL LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg) -{ - message_list_t* message_list = &(mMessageList[MTC_VIEWER_ALERT]); - - // Concatenate from,to,mesg into one string. - std::ostringstream full_mesg; - full_mesg << to << mesg; - - // Create an entry for this message. - size_t hash = llhash(full_mesg.str().c_str()); - LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); - - // Check if this message is already in the list. - message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), - 1, entry, eq_message_throttle_entry); - if (found == message_list->end()) - { - // This message was not found. Add it to the list. - message_list->push_front(entry); - return TRUE; - } - else - { - // This message was already in the list. - return FALSE; - } -} - -BOOL LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, const std::string& mesg) -{ - message_list_t* message_list = &(mMessageList[MTC_AGENT_ALERT]); - - // Concatenate from,to,mesg into one string. - std::ostringstream full_mesg; - full_mesg << agent << task << mesg; - - // Create an entry for this message. - size_t hash = llhash(full_mesg.str().c_str()); - LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); - - // Check if this message is already in the list. - message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), - 1, entry, eq_message_throttle_entry); - if (found == message_list->end()) - { - // This message was not found. Add it to the list. - message_list->push_front(entry); - return TRUE; - } - else - { - // This message was already in the list. - return FALSE; - } -} - +/**
+ * @file llmessagethrottle.cpp
+ * @brief LLMessageThrottle class used for throttling messages.
+ *
+ * $LicenseInfo:firstyear=2004&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$
+ */
+
+#include "linden_common.h"
+
+#include "llhash.h"
+
+#include "llmessagethrottle.h"
+#include "llframetimer.h"
+
+// This is used for the stl search_n function.
+bool eq_message_throttle_entry(LLMessageThrottleEntry a, LLMessageThrottleEntry b)
+ { return a.getHash() == b.getHash(); }
+
+const U64 SEC_TO_USEC = 1000000;
+
+// How long (in microseconds) each type of message stays in its throttle list.
+const U64 MAX_MESSAGE_AGE[MTC_EOF] =
+{
+ 10 * SEC_TO_USEC, // MTC_VIEWER_ALERT
+ 10 * SEC_TO_USEC // MTC_AGENT_ALERT
+};
+
+LLMessageThrottle::LLMessageThrottle()
+{
+}
+
+LLMessageThrottle::~LLMessageThrottle()
+{
+}
+
+void LLMessageThrottle::pruneEntries()
+{
+ // Go through each message category, and prune entries older than max age.
+ S32 cat;
+ for (cat = 0; cat < MTC_EOF; cat++)
+ {
+ message_list_t* message_list = &(mMessageList[cat]);
+
+ // Use a reverse iterator, since entries on the back will be the oldest.
+ message_list_reverse_iterator_t r_iterator = message_list->rbegin();
+ message_list_reverse_iterator_t r_last = message_list->rend();
+
+ // Look for the first entry younger than the maximum age.
+ F32 max_age = (F32)MAX_MESSAGE_AGE[cat];
+ bool found = false;
+ while (r_iterator != r_last && !found)
+ {
+ if ( LLFrameTimer::getTotalTime() - (*r_iterator).getEntryTime() < max_age )
+ {
+ // We found a young enough entry.
+ found = true;
+
+ // Did we find at least one entry to remove?
+ if (r_iterator != message_list->rbegin())
+ {
+ // Yes, remove it.
+ message_list->erase(r_iterator.base(), message_list->end());
+ }
+ }
+ else
+ {
+ r_iterator++;
+ }
+ }
+
+ // If we didn't find any entries young enough to keep, remove them all.
+ if (!found)
+ {
+ message_list->clear();
+ }
+ }
+}
+
+bool LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg)
+{
+ message_list_t* message_list = &(mMessageList[MTC_VIEWER_ALERT]);
+
+ // Concatenate from,to,mesg into one string.
+ std::ostringstream full_mesg;
+ full_mesg << to << mesg;
+
+ // Create an entry for this message.
+ size_t hash = llhash(full_mesg.str().c_str());
+ LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime());
+
+ // Check if this message is already in the list.
+ message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(),
+ 1, entry, eq_message_throttle_entry);
+ if (found == message_list->end())
+ {
+ // This message was not found. Add it to the list.
+ message_list->push_front(entry);
+ return true;
+ }
+ else
+ {
+ // This message was already in the list.
+ return false;
+ }
+}
+
+bool LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, const std::string& mesg)
+{
+ message_list_t* message_list = &(mMessageList[MTC_AGENT_ALERT]);
+
+ // Concatenate from,to,mesg into one string.
+ std::ostringstream full_mesg;
+ full_mesg << agent << task << mesg;
+
+ // Create an entry for this message.
+ size_t hash = llhash(full_mesg.str().c_str());
+ LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime());
+
+ // Check if this message is already in the list.
+ message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(),
+ 1, entry, eq_message_throttle_entry);
+ if (found == message_list->end())
+ {
+ // This message was not found. Add it to the list.
+ message_list->push_front(entry);
+ return true;
+ }
+ else
+ {
+ // This message was already in the list.
+ return false;
+ }
+}
+
diff --git a/indra/llmessage/llmessagethrottle.h b/indra/llmessage/llmessagethrottle.h index 8a96a6b589..9597fbccdf 100644 --- a/indra/llmessage/llmessagethrottle.h +++ b/indra/llmessage/llmessagethrottle.h @@ -1,80 +1,80 @@ -/** - * @file llmessagethrottle.h - * @brief LLMessageThrottle class used for throttling messages. - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#ifndef LL_LLMESSAGETHROTTLE_H -#define LL_LLMESSAGETHROTTLE_H - -#include <deque> - -#include "linden_common.h" -#include "lluuid.h" - -typedef enum e_message_throttle_categories -{ - MTC_VIEWER_ALERT, - MTC_AGENT_ALERT, - MTC_EOF -} EMessageThrottleCats; - -class LLMessageThrottleEntry -{ -public: - LLMessageThrottleEntry(const size_t hash, const U64 entry_time) - : mHash(hash), mEntryTime(entry_time) {} - - size_t getHash() const { return mHash; } - U64 getEntryTime() const { return mEntryTime; } -protected: - size_t mHash; - U64 mEntryTime; -}; - - -class LLMessageThrottle -{ -public: - LLMessageThrottle(); - ~LLMessageThrottle(); - - BOOL addViewerAlert (const LLUUID& to, const std::string& mesg); - BOOL addAgentAlert (const LLUUID& agent, const LLUUID& task, const std::string& mesg); - - void pruneEntries(); - -protected: - typedef std::deque<LLMessageThrottleEntry> message_list_t; - typedef std::deque<LLMessageThrottleEntry>::iterator message_list_iterator_t; - typedef std::deque<LLMessageThrottleEntry>::reverse_iterator message_list_reverse_iterator_t; - typedef std::deque<LLMessageThrottleEntry>::const_iterator message_list_const_iterator_t; - typedef std::deque<LLMessageThrottleEntry>::const_reverse_iterator message_list_const_reverse_iterator_t; - message_list_t mMessageList[MTC_EOF]; -}; - -extern LLMessageThrottle gMessageThrottle; - -#endif - - +/**
+ * @file llmessagethrottle.h
+ * @brief LLMessageThrottle class used for throttling messages.
+ *
+ * $LicenseInfo:firstyear=2004&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$
+ */
+
+#ifndef LL_LLMESSAGETHROTTLE_H
+#define LL_LLMESSAGETHROTTLE_H
+
+#include <deque>
+
+#include "linden_common.h"
+#include "lluuid.h"
+
+typedef enum e_message_throttle_categories
+{
+ MTC_VIEWER_ALERT,
+ MTC_AGENT_ALERT,
+ MTC_EOF
+} EMessageThrottleCats;
+
+class LLMessageThrottleEntry
+{
+public:
+ LLMessageThrottleEntry(const size_t hash, const U64 entry_time)
+ : mHash(hash), mEntryTime(entry_time) {}
+
+ size_t getHash() const { return mHash; }
+ U64 getEntryTime() const { return mEntryTime; }
+protected:
+ size_t mHash;
+ U64 mEntryTime;
+};
+
+
+class LLMessageThrottle
+{
+public:
+ LLMessageThrottle();
+ ~LLMessageThrottle();
+
+ bool addViewerAlert (const LLUUID& to, const std::string& mesg);
+ bool addAgentAlert (const LLUUID& agent, const LLUUID& task, const std::string& mesg);
+
+ void pruneEntries();
+
+protected:
+ typedef std::deque<LLMessageThrottleEntry> message_list_t;
+ typedef std::deque<LLMessageThrottleEntry>::iterator message_list_iterator_t;
+ typedef std::deque<LLMessageThrottleEntry>::reverse_iterator message_list_reverse_iterator_t;
+ typedef std::deque<LLMessageThrottleEntry>::const_iterator message_list_const_iterator_t;
+ typedef std::deque<LLMessageThrottleEntry>::const_reverse_iterator message_list_const_reverse_iterator_t;
+ message_list_t mMessageList[MTC_EOF];
+};
+
+extern LLMessageThrottle gMessageThrottle;
+
+#endif
+
+
diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp index c275f4ef00..5254091481 100644 --- a/indra/llmessage/llnamevalue.cpp +++ b/indra/llmessage/llnamevalue.cpp @@ -1,970 +1,970 @@ -/** - * @file llnamevalue.cpp - * @brief class for defining name value pairs. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -// Examples: -// AvatarCharacter STRING RW DSV male1 - -#include "linden_common.h" - -#include "llnamevalue.h" - -#include "u64.h" -#include "llstring.h" -#include "llstringtable.h" - -// Anonymous enumeration to provide constants in this file. -// *NOTE: These values may be used in sscanf statements below as their -// value-1, so search for '2047' if you cange NV_BUFFER_LEN or '63' if -// you change U64_BUFFER_LEN. -enum -{ - NV_BUFFER_LEN = 2048, - U64_BUFFER_LEN = 64 -}; - -LLStringTable gNVNameTable(256); - -char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH] = /*Flawfinder: Ignore*/ -{ - "NULL", - "STRING", - "F32", - "S32", - "VEC3", - "U32", - "CAMERA", // Deprecated, but leaving in case removing completely would cause problems - "ASSET", - "U64" -}; - -char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH] = /*Flawfinder: Ignore*/ -{ - "NULL", - "R", // read only - "RW" // read write -}; - -char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH] = /*Flawfinder: Ignore*/ -{ - "NULL", - "S", // "Sim", formerly SIM - "DS", // "Data Sim" formerly SIM_SPACE - "SV", // "Sim Viewer" formerly SIM_VIEWER - "DSV" // "Data Sim Viewer", formerly SIM_SPACE_VIEWER -}; /*Flawfinder: Ignore*/ - - -// -// Class -// - -LLNameValue::LLNameValue() -{ - baseInit(); -} - -void LLNameValue::baseInit() -{ - mNVNameTable = &gNVNameTable; - - mName = NULL; - mNameValueReference.string = NULL; - - mType = NVT_NULL; - mStringType = NameValueTypeStrings[NVT_NULL]; - - mClass = NVC_NULL; - mStringClass = NameValueClassStrings[NVC_NULL]; - - mSendto = NVS_NULL; - mStringSendto = NameValueSendtoStrings[NVS_NULL]; -} - -void LLNameValue::init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto) -{ - mNVNameTable = &gNVNameTable; - - mName = mNVNameTable->addString(name); - - // Nota Bene: Whatever global structure manages this should have these in the name table already! - mStringType = mNVNameTable->addString(type); - if (!strcmp(mStringType, "STRING")) - { - S32 string_length = (S32)strlen(data); /*Flawfinder: Ignore*/ - mType = NVT_STRING; - - delete[] mNameValueReference.string; - - // two options here. . . data can either look like foo or "foo" - // WRONG! - this is a poorly implemented and incomplete escape - // mechanism. For example, using this scheme, there is no way - // to tell an intentional double quotes from a zero length - // string. This needs to excised. Phoenix - //if (strchr(data, '\"')) - //{ - // string_length -= 2; - // mNameValueReference.string = new char[string_length + 1];; - // strncpy(mNameValueReference.string, data + 1, string_length); - //} - //else - //{ - mNameValueReference.string = new char[string_length + 1];; - strncpy(mNameValueReference.string, data, string_length); /*Flawfinder: Ignore*/ - //} - mNameValueReference.string[string_length] = 0; - } - else if (!strcmp(mStringType, "F32")) - { - mType = NVT_F32; - mNameValueReference.f32 = new F32((F32)atof(data)); - } - else if (!strcmp(mStringType, "S32")) - { - mType = NVT_S32; - mNameValueReference.s32 = new S32(atoi(data)); - } - else if (!strcmp(mStringType, "U64")) - { - mType = NVT_U64; - mNameValueReference.u64 = new U64(str_to_U64(ll_safe_string(data))); - } - else if (!strcmp(mStringType, "VEC3")) - { - mType = NVT_VEC3; - F32 t1, t2, t3; - - // two options here. . . data can either look like 0, 1, 2 or <0, 1, 2> - - if (strchr(data, '<')) - { - sscanf(data, "<%f, %f, %f>", &t1, &t2, &t3); - } - else - { - sscanf(data, "%f, %f, %f", &t1, &t2, &t3); - } - - // finite checks - if (!llfinite(t1) || !llfinite(t2) || !llfinite(t3)) - { - t1 = 0.f; - t2 = 0.f; - t3 = 0.f; - } - - mNameValueReference.vec3 = new LLVector3(t1, t2, t3); - } - else if (!strcmp(mStringType, "U32")) - { - mType = NVT_U32; - mNameValueReference.u32 = new U32(atoi(data)); - } - else if(!strcmp(mStringType, (const char*)NameValueTypeStrings[NVT_ASSET])) - { - // assets are treated like strings, except that the name has - // meaning to an LLAssetInfo object - S32 string_length = (S32)strlen(data); /*Flawfinder: Ignore*/ - mType = NVT_ASSET; - - // two options here. . . data can either look like foo or "foo" - // WRONG! - this is a poorly implemented and incomplete escape - // mechanism. For example, using this scheme, there is no way - // to tell an intentional double quotes from a zero length - // string. This needs to excised. Phoenix - //if (strchr(data, '\"')) - //{ - // string_length -= 2; - // mNameValueReference.string = new char[string_length + 1];; - // strncpy(mNameValueReference.string, data + 1, string_length); - //} - //else - //{ - mNameValueReference.string = new char[string_length + 1];; - strncpy(mNameValueReference.string, data, string_length); /*Flawfinder: Ignore*/ - //} - mNameValueReference.string[string_length] = 0; - } - else - { - LL_WARNS() << "Unknown name value type string " << mStringType << " for " << mName << LL_ENDL; - mType = NVT_NULL; - } - - - // Nota Bene: Whatever global structure manages this should have these in the name table already! - if (!strcmp(nvclass, "R") || - !strcmp(nvclass, "READ_ONLY")) // legacy - { - mClass = NVC_READ_ONLY; - mStringClass = mNVNameTable->addString("R"); - } - else if (!strcmp(nvclass, "RW") || - !strcmp(nvclass, "READ_WRITE")) // legacy - { - mClass = NVC_READ_WRITE; - mStringClass = mNVNameTable->addString("RW"); - } - else - { - // assume it's bad - mClass = NVC_NULL; - mStringClass = mNVNameTable->addString(nvclass); - } - - // Initialize the sendto variable - if (!strcmp(nvsendto, "S") || - !strcmp(nvsendto, "SIM")) // legacy - { - mSendto = NVS_SIM; - mStringSendto = mNVNameTable->addString("S"); - } - else if (!strcmp(nvsendto, "DS") || - !strcmp(nvsendto, "SIM_SPACE")) // legacy - { - mSendto = NVS_DATA_SIM; - mStringSendto = mNVNameTable->addString("DS"); - } - else if (!strcmp(nvsendto, "SV") || - !strcmp(nvsendto, "SIM_VIEWER")) // legacy - { - mSendto = NVS_SIM_VIEWER; - mStringSendto = mNVNameTable->addString("SV"); - } - else if (!strcmp(nvsendto, "DSV") || - !strcmp(nvsendto, "SIM_SPACE_VIEWER")) // legacy - { - mSendto = NVS_DATA_SIM_VIEWER; - mStringSendto = mNVNameTable->addString("DSV"); - } - else - { - LL_WARNS() << "LLNameValue::init() - unknown sendto field " - << nvsendto << " for NV " << mName << LL_ENDL; - mSendto = NVS_NULL; - mStringSendto = mNVNameTable->addString("S"); - } - -} - - -LLNameValue::LLNameValue(const char *name, const char *data, const char *type, const char *nvclass) -{ - baseInit(); - // if not specified, send to simulator only - init(name, data, type, nvclass, "SIM"); -} - - -LLNameValue::LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto) -{ - baseInit(); - init(name, data, type, nvclass, nvsendto); -} - - - -// Initialize without any initial data. -LLNameValue::LLNameValue(const char *name, const char *type, const char *nvclass) -{ - baseInit(); - mName = mNVNameTable->addString(name); - - // Nota Bene: Whatever global structure manages this should have these in the name table already! - mStringType = mNVNameTable->addString(type); - if (!strcmp(mStringType, "STRING")) - { - mType = NVT_STRING; - mNameValueReference.string = NULL; - } - else if (!strcmp(mStringType, "F32")) - { - mType = NVT_F32; - mNameValueReference.f32 = NULL; - } - else if (!strcmp(mStringType, "S32")) - { - mType = NVT_S32; - mNameValueReference.s32 = NULL; - } - else if (!strcmp(mStringType, "VEC3")) - { - mType = NVT_VEC3; - mNameValueReference.vec3 = NULL; - } - else if (!strcmp(mStringType, "U32")) - { - mType = NVT_U32; - mNameValueReference.u32 = NULL; - } - else if (!strcmp(mStringType, "U64")) - { - mType = NVT_U64; - mNameValueReference.u64 = NULL; - } - else if(!strcmp(mStringType, (const char*)NameValueTypeStrings[NVT_ASSET])) - { - mType = NVT_ASSET; - mNameValueReference.string = NULL; - } - else - { - mType = NVT_NULL; - LL_INFOS() << "Unknown name-value type " << mStringType << LL_ENDL; - } - - // Nota Bene: Whatever global structure manages this should have these in the name table already! - mStringClass = mNVNameTable->addString(nvclass); - if (!strcmp(mStringClass, "READ_ONLY")) - { - mClass = NVC_READ_ONLY; - } - else if (!strcmp(mStringClass, "READ_WRITE")) - { - mClass = NVC_READ_WRITE; - } - else - { - mClass = NVC_NULL; - } - - // Initialize the sendto variable - mStringSendto = mNVNameTable->addString("SIM"); - mSendto = NVS_SIM; -} - - -// data is in the format: -// "NameValueName Type Class Data" -LLNameValue::LLNameValue(const char *data) -{ - baseInit(); - static char name[NV_BUFFER_LEN]; /*Flawfinder: ignore*/ - static char type[NV_BUFFER_LEN]; /*Flawfinder: ignore*/ - static char nvclass[NV_BUFFER_LEN]; /*Flawfinder: ignore*/ - static char nvsendto[NV_BUFFER_LEN]; /*Flawfinder: ignore*/ - static char nvdata[NV_BUFFER_LEN]; /*Flawfinder: ignore*/ - - S32 i; - - S32 character_count = 0; - S32 length = 0; - - // go to first non-whitespace character - while (1) - { - if ( (*(data + character_count) == ' ') - ||(*(data + character_count) == '\n') - ||(*(data + character_count) == '\t') - ||(*(data + character_count) == '\r')) - { - character_count++; - } - else - { - break; - } - } - - // read in the name - sscanf((data + character_count), "%2047s", name); /*Flawfinder: ignore*/ - - // bump past it and add null terminator - length = (S32)strlen(name); /* Flawfinder: ignore */ - name[length] = 0; - character_count += length; - - // go to the next non-whitespace character - while (1) - { - if ( (*(data + character_count) == ' ') - ||(*(data + character_count) == '\n') - ||(*(data + character_count) == '\t') - ||(*(data + character_count) == '\r')) - { - character_count++; - } - else - { - break; - } - } - - // read in the type - sscanf((data + character_count), "%2047s", type); /*Flawfinder: ignore*/ - - // bump past it and add null terminator - length = (S32)strlen(type); /* Flawfinder: ignore */ - type[length] = 0; - character_count += length; - - // go to the next non-whitespace character - while (1) - { - if ( (*(data + character_count) == ' ') - ||(*(data + character_count) == '\n') - ||(*(data + character_count) == '\t') - ||(*(data + character_count) == '\r')) - { - character_count++; - } - else - { - break; - } - } - - // do we have a type argument? - for (i = NVC_READ_ONLY; i < NVC_EOF; i++) - { - if (!strncmp(NameValueClassStrings[i], data + character_count, strlen(NameValueClassStrings[i]))) /* Flawfinder: ignore */ - { - break; - } - } - - if (i != NVC_EOF) - { - // yes we do! - // read in the class - sscanf((data + character_count), "%2047s", nvclass); /*Flawfinder: ignore*/ - - // bump past it and add null terminator - length = (S32)strlen(nvclass); /* Flawfinder: ignore */ - nvclass[length] = 0; - character_count += length; - - // go to the next non-whitespace character - while (1) - { - if ( (*(data + character_count) == ' ') - ||(*(data + character_count) == '\n') - ||(*(data + character_count) == '\t') - ||(*(data + character_count) == '\r')) - { - character_count++; - } - else - { - break; - } - } - } - else - { - // no type argument given, default to read-write - strncpy(nvclass, "READ_WRITE", sizeof(nvclass) -1); /* Flawfinder: ignore */ - nvclass[sizeof(nvclass) -1] = '\0'; - } - - // Do we have a sendto argument? - for (i = NVS_SIM; i < NVS_EOF; i++) - { - if (!strncmp(NameValueSendtoStrings[i], data + character_count, strlen(NameValueSendtoStrings[i]))) /* Flawfinder: ignore */ - { - break; - } - } - - if (i != NVS_EOF) - { - // found a sendto argument - sscanf((data + character_count), "%2047s", nvsendto); /*Flawfinder: ignore*/ - - // add null terminator - length = (S32)strlen(nvsendto); /* Flawfinder: ignore */ - nvsendto[length] = 0; - character_count += length; - - // seek to next non-whitespace characer - while (1) - { - if ( (*(data + character_count) == ' ') - ||(*(data + character_count) == '\n') - ||(*(data + character_count) == '\t') - ||(*(data + character_count) == '\r')) - { - character_count++; - } - else - { - break; - } - } - } - else - { - // no sendto argument given, default to sim only - strncpy(nvsendto, "SIM", sizeof(nvsendto) -1); /* Flawfinder: ignore */ - nvsendto[sizeof(nvsendto) -1] ='\0'; - } - - - // copy the rest character by character into data - length = 0; - - while ( (*(nvdata + length++) = *(data + character_count++)) ) - ; - - init(name, nvdata, type, nvclass, nvsendto); -} - - -LLNameValue::~LLNameValue() -{ - mNVNameTable->removeString(mName); - mName = NULL; - - switch(mType) - { - case NVT_STRING: - case NVT_ASSET: - delete [] mNameValueReference.string; - mNameValueReference.string = NULL; - break; - case NVT_F32: - delete mNameValueReference.f32; - mNameValueReference.string = NULL; - break; - case NVT_S32: - delete mNameValueReference.s32; - mNameValueReference.string = NULL; - break; - case NVT_VEC3: - delete mNameValueReference.vec3; - mNameValueReference.string = NULL; - break; - case NVT_U32: - delete mNameValueReference.u32; - mNameValueReference.u32 = NULL; - break; - case NVT_U64: - delete mNameValueReference.u64; - mNameValueReference.u64 = NULL; - break; - default: - break; - } - - delete[] mNameValueReference.string; - mNameValueReference.string = NULL; -} - -char *LLNameValue::getString() -{ - if (mType == NVT_STRING) - { - return mNameValueReference.string; - } - else - { - LL_ERRS() << mName << " not a string!" << LL_ENDL; - return NULL; - } -} - -const char *LLNameValue::getAsset() const -{ - if (mType == NVT_ASSET) - { - return mNameValueReference.string; - } - else - { - LL_ERRS() << mName << " not an asset!" << LL_ENDL; - return NULL; - } -} - -F32 *LLNameValue::getF32() -{ - if (mType == NVT_F32) - { - return mNameValueReference.f32; - } - else - { - LL_ERRS() << mName << " not a F32!" << LL_ENDL; - return NULL; - } -} - -S32 *LLNameValue::getS32() -{ - if (mType == NVT_S32) - { - return mNameValueReference.s32; - } - else - { - LL_ERRS() << mName << " not a S32!" << LL_ENDL; - return NULL; - } -} - -U32 *LLNameValue::getU32() -{ - if (mType == NVT_U32) - { - return mNameValueReference.u32; - } - else - { - LL_ERRS() << mName << " not a U32!" << LL_ENDL; - return NULL; - } -} - -U64 *LLNameValue::getU64() -{ - if (mType == NVT_U64) - { - return mNameValueReference.u64; - } - else - { - LL_ERRS() << mName << " not a U64!" << LL_ENDL; - return NULL; - } -} - -void LLNameValue::getVec3(LLVector3 &vec) -{ - if (mType == NVT_VEC3) - { - vec = *mNameValueReference.vec3; - } - else - { - LL_ERRS() << mName << " not a Vec3!" << LL_ENDL; - } -} - -LLVector3 *LLNameValue::getVec3() -{ - if (mType == NVT_VEC3) - { - return (mNameValueReference.vec3); - } - else - { - LL_ERRS() << mName << " not a Vec3!" << LL_ENDL; - return NULL; - } -} - - -BOOL LLNameValue::sendToData() const -{ - return (mSendto == NVS_DATA_SIM || mSendto == NVS_DATA_SIM_VIEWER); -} - - -BOOL LLNameValue::sendToViewer() const -{ - return (mSendto == NVS_SIM_VIEWER || mSendto == NVS_DATA_SIM_VIEWER); -} - - -LLNameValue &LLNameValue::operator=(const LLNameValue &a) -{ - if (mType != a.mType) - { - return *this; - } - if (mClass == NVC_READ_ONLY) - return *this; - - switch(a.mType) - { - case NVT_STRING: - case NVT_ASSET: - if (mNameValueReference.string) - delete [] mNameValueReference.string; - - mNameValueReference.string = new char [strlen(a.mNameValueReference.string) + 1]; /* Flawfinder: ignore */ - if(mNameValueReference.string != NULL) - { - strcpy(mNameValueReference.string, a.mNameValueReference.string); /* Flawfinder: ignore */ - } - break; - case NVT_F32: - *mNameValueReference.f32 = *a.mNameValueReference.f32; - break; - case NVT_S32: - *mNameValueReference.s32 = *a.mNameValueReference.s32; - break; - case NVT_VEC3: - *mNameValueReference.vec3 = *a.mNameValueReference.vec3; - break; - case NVT_U32: - *mNameValueReference.u32 = *a.mNameValueReference.u32; - break; - case NVT_U64: - *mNameValueReference.u64 = *a.mNameValueReference.u64; - break; - default: - LL_ERRS() << "Unknown Name value type " << (U32)a.mType << LL_ENDL; - break; - } - - return *this; -} - -void LLNameValue::setString(const char *a) -{ - if (mClass == NVC_READ_ONLY) - return; - - switch(mType) - { - case NVT_STRING: - if (a) - { - if (mNameValueReference.string) - { - delete [] mNameValueReference.string; - } - - mNameValueReference.string = new char [strlen(a) + 1]; /* Flawfinder: ignore */ - if(mNameValueReference.string != NULL) - { - strcpy(mNameValueReference.string, a); /* Flawfinder: ignore */ - } - } - else - { - if (mNameValueReference.string) - delete [] mNameValueReference.string; - - mNameValueReference.string = new char [1]; - mNameValueReference.string[0] = 0; - } - break; - default: - break; - } - - return; -} - - -void LLNameValue::setAsset(const char *a) -{ - if (mClass == NVC_READ_ONLY) - return; - - switch(mType) - { - case NVT_ASSET: - if (a) - { - if (mNameValueReference.string) - { - delete [] mNameValueReference.string; - } - mNameValueReference.string = new char [strlen(a) + 1]; /* Flawfinder: ignore */ - if(mNameValueReference.string != NULL) - { - strcpy(mNameValueReference.string, a); /* Flawfinder: ignore */ - } - } - else - { - if (mNameValueReference.string) - delete [] mNameValueReference.string; - - mNameValueReference.string = new char [1]; - mNameValueReference.string[0] = 0; - } - break; - default: - break; - } -} - - -void LLNameValue::setF32(const F32 a) -{ - if (mClass == NVC_READ_ONLY) - return; - - switch(mType) - { - case NVT_F32: - *mNameValueReference.f32 = a; - break; - default: - break; - } - - return; -} - - -void LLNameValue::setS32(const S32 a) -{ - if (mClass == NVC_READ_ONLY) - return; - - switch(mType) - { - case NVT_S32: - *mNameValueReference.s32 = a; - break; - case NVT_U32: - *mNameValueReference.u32 = a; - break; - case NVT_F32: - *mNameValueReference.f32 = (F32)a; - break; - default: - break; - } - - return; -} - - -void LLNameValue::setU32(const U32 a) -{ - if (mClass == NVC_READ_ONLY) - return; - - switch(mType) - { - case NVT_S32: - *mNameValueReference.s32 = a; - break; - case NVT_U32: - *mNameValueReference.u32 = a; - break; - case NVT_F32: - *mNameValueReference.f32 = (F32)a; - break; - default: - LL_ERRS() << "NameValue: Trying to set U32 into a " << mStringType << ", unknown conversion" << LL_ENDL; - break; - } - return; -} - - -void LLNameValue::setVec3(const LLVector3 &a) -{ - if (mClass == NVC_READ_ONLY) - return; - - switch(mType) - { - case NVT_VEC3: - *mNameValueReference.vec3 = a; - break; - default: - LL_ERRS() << "NameValue: Trying to set LLVector3 into a " << mStringType << ", unknown conversion" << LL_ENDL; - break; - } - return; -} - - -std::string LLNameValue::printNameValue() const -{ - std::string buffer; - buffer = llformat("%s %s %s %s ", mName, mStringType, mStringClass, mStringSendto); - buffer += printData(); -// LL_INFOS() << "Name Value Length: " << buffer.size() + 1 << LL_ENDL; - return buffer; -} - -std::string LLNameValue::printData() const -{ - std::string buffer; - switch(mType) - { - case NVT_STRING: - case NVT_ASSET: - buffer = mNameValueReference.string; - break; - case NVT_F32: - buffer = llformat("%f", *mNameValueReference.f32); - break; - case NVT_S32: - buffer = llformat("%d", *mNameValueReference.s32); - break; - case NVT_U32: - buffer = llformat("%u", *mNameValueReference.u32); - break; - case NVT_U64: - { - char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */ - U64_to_str(*mNameValueReference.u64, u64_string, sizeof(u64_string)); - buffer = u64_string; - } - break; - case NVT_VEC3: - buffer = llformat( "%f, %f, %f", mNameValueReference.vec3->mV[VX], mNameValueReference.vec3->mV[VY], mNameValueReference.vec3->mV[VZ]); - break; - default: - LL_ERRS() << "Trying to print unknown NameValue type " << mStringType << LL_ENDL; - break; - } - return buffer; -} - -std::ostream& operator<<(std::ostream& s, const LLNameValue &a) -{ - switch(a.mType) - { - case NVT_STRING: - case NVT_ASSET: - s << a.mNameValueReference.string; - break; - case NVT_F32: - s << (*a.mNameValueReference.f32); - break; - case NVT_S32: - s << *(a.mNameValueReference.s32); - break; - case NVT_U32: - s << *(a.mNameValueReference.u32); - break; - case NVT_U64: - { - char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */ - U64_to_str(*a.mNameValueReference.u64, u64_string, sizeof(u64_string)); - s << u64_string; - } - break; - case NVT_VEC3: - s << *(a.mNameValueReference.vec3); - break; - default: - LL_ERRS() << "Trying to print unknown NameValue type " << a.mStringType << LL_ENDL; - break; - } - return s; -} - +/**
+ * @file llnamevalue.cpp
+ * @brief class for defining name value pairs.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+// Examples:
+// AvatarCharacter STRING RW DSV male1
+
+#include "linden_common.h"
+
+#include "llnamevalue.h"
+
+#include "u64.h"
+#include "llstring.h"
+#include "llstringtable.h"
+
+// Anonymous enumeration to provide constants in this file.
+// *NOTE: These values may be used in sscanf statements below as their
+// value-1, so search for '2047' if you cange NV_BUFFER_LEN or '63' if
+// you change U64_BUFFER_LEN.
+enum
+{
+ NV_BUFFER_LEN = 2048,
+ U64_BUFFER_LEN = 64
+};
+
+LLStringTable gNVNameTable(256);
+
+char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH] = /*Flawfinder: Ignore*/
+{
+ "NULL",
+ "STRING",
+ "F32",
+ "S32",
+ "VEC3",
+ "U32",
+ "CAMERA", // Deprecated, but leaving in case removing completely would cause problems
+ "ASSET",
+ "U64"
+};
+
+char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH] = /*Flawfinder: Ignore*/
+{
+ "NULL",
+ "R", // read only
+ "RW" // read write
+};
+
+char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH] = /*Flawfinder: Ignore*/
+{
+ "NULL",
+ "S", // "Sim", formerly SIM
+ "DS", // "Data Sim" formerly SIM_SPACE
+ "SV", // "Sim Viewer" formerly SIM_VIEWER
+ "DSV" // "Data Sim Viewer", formerly SIM_SPACE_VIEWER
+}; /*Flawfinder: Ignore*/
+
+
+//
+// Class
+//
+
+LLNameValue::LLNameValue()
+{
+ baseInit();
+}
+
+void LLNameValue::baseInit()
+{
+ mNVNameTable = &gNVNameTable;
+
+ mName = NULL;
+ mNameValueReference.string = NULL;
+
+ mType = NVT_NULL;
+ mStringType = NameValueTypeStrings[NVT_NULL];
+
+ mClass = NVC_NULL;
+ mStringClass = NameValueClassStrings[NVC_NULL];
+
+ mSendto = NVS_NULL;
+ mStringSendto = NameValueSendtoStrings[NVS_NULL];
+}
+
+void LLNameValue::init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto)
+{
+ mNVNameTable = &gNVNameTable;
+
+ mName = mNVNameTable->addString(name);
+
+ // Nota Bene: Whatever global structure manages this should have these in the name table already!
+ mStringType = mNVNameTable->addString(type);
+ if (!strcmp(mStringType, "STRING"))
+ {
+ S32 string_length = (S32)strlen(data); /*Flawfinder: Ignore*/
+ mType = NVT_STRING;
+
+ delete[] mNameValueReference.string;
+
+ // two options here. . . data can either look like foo or "foo"
+ // WRONG! - this is a poorly implemented and incomplete escape
+ // mechanism. For example, using this scheme, there is no way
+ // to tell an intentional double quotes from a zero length
+ // string. This needs to excised. Phoenix
+ //if (strchr(data, '\"'))
+ //{
+ // string_length -= 2;
+ // mNameValueReference.string = new char[string_length + 1];;
+ // strncpy(mNameValueReference.string, data + 1, string_length);
+ //}
+ //else
+ //{
+ mNameValueReference.string = new char[string_length + 1];;
+ strncpy(mNameValueReference.string, data, string_length); /*Flawfinder: Ignore*/
+ //}
+ mNameValueReference.string[string_length] = 0;
+ }
+ else if (!strcmp(mStringType, "F32"))
+ {
+ mType = NVT_F32;
+ mNameValueReference.f32 = new F32((F32)atof(data));
+ }
+ else if (!strcmp(mStringType, "S32"))
+ {
+ mType = NVT_S32;
+ mNameValueReference.s32 = new S32(atoi(data));
+ }
+ else if (!strcmp(mStringType, "U64"))
+ {
+ mType = NVT_U64;
+ mNameValueReference.u64 = new U64(str_to_U64(ll_safe_string(data)));
+ }
+ else if (!strcmp(mStringType, "VEC3"))
+ {
+ mType = NVT_VEC3;
+ F32 t1, t2, t3;
+
+ // two options here. . . data can either look like 0, 1, 2 or <0, 1, 2>
+
+ if (strchr(data, '<'))
+ {
+ sscanf(data, "<%f, %f, %f>", &t1, &t2, &t3);
+ }
+ else
+ {
+ sscanf(data, "%f, %f, %f", &t1, &t2, &t3);
+ }
+
+ // finite checks
+ if (!llfinite(t1) || !llfinite(t2) || !llfinite(t3))
+ {
+ t1 = 0.f;
+ t2 = 0.f;
+ t3 = 0.f;
+ }
+
+ mNameValueReference.vec3 = new LLVector3(t1, t2, t3);
+ }
+ else if (!strcmp(mStringType, "U32"))
+ {
+ mType = NVT_U32;
+ mNameValueReference.u32 = new U32(atoi(data));
+ }
+ else if(!strcmp(mStringType, (const char*)NameValueTypeStrings[NVT_ASSET]))
+ {
+ // assets are treated like strings, except that the name has
+ // meaning to an LLAssetInfo object
+ S32 string_length = (S32)strlen(data); /*Flawfinder: Ignore*/
+ mType = NVT_ASSET;
+
+ // two options here. . . data can either look like foo or "foo"
+ // WRONG! - this is a poorly implemented and incomplete escape
+ // mechanism. For example, using this scheme, there is no way
+ // to tell an intentional double quotes from a zero length
+ // string. This needs to excised. Phoenix
+ //if (strchr(data, '\"'))
+ //{
+ // string_length -= 2;
+ // mNameValueReference.string = new char[string_length + 1];;
+ // strncpy(mNameValueReference.string, data + 1, string_length);
+ //}
+ //else
+ //{
+ mNameValueReference.string = new char[string_length + 1];;
+ strncpy(mNameValueReference.string, data, string_length); /*Flawfinder: Ignore*/
+ //}
+ mNameValueReference.string[string_length] = 0;
+ }
+ else
+ {
+ LL_WARNS() << "Unknown name value type string " << mStringType << " for " << mName << LL_ENDL;
+ mType = NVT_NULL;
+ }
+
+
+ // Nota Bene: Whatever global structure manages this should have these in the name table already!
+ if (!strcmp(nvclass, "R") ||
+ !strcmp(nvclass, "READ_ONLY")) // legacy
+ {
+ mClass = NVC_READ_ONLY;
+ mStringClass = mNVNameTable->addString("R");
+ }
+ else if (!strcmp(nvclass, "RW") ||
+ !strcmp(nvclass, "READ_WRITE")) // legacy
+ {
+ mClass = NVC_READ_WRITE;
+ mStringClass = mNVNameTable->addString("RW");
+ }
+ else
+ {
+ // assume it's bad
+ mClass = NVC_NULL;
+ mStringClass = mNVNameTable->addString(nvclass);
+ }
+
+ // Initialize the sendto variable
+ if (!strcmp(nvsendto, "S") ||
+ !strcmp(nvsendto, "SIM")) // legacy
+ {
+ mSendto = NVS_SIM;
+ mStringSendto = mNVNameTable->addString("S");
+ }
+ else if (!strcmp(nvsendto, "DS") ||
+ !strcmp(nvsendto, "SIM_SPACE")) // legacy
+ {
+ mSendto = NVS_DATA_SIM;
+ mStringSendto = mNVNameTable->addString("DS");
+ }
+ else if (!strcmp(nvsendto, "SV") ||
+ !strcmp(nvsendto, "SIM_VIEWER")) // legacy
+ {
+ mSendto = NVS_SIM_VIEWER;
+ mStringSendto = mNVNameTable->addString("SV");
+ }
+ else if (!strcmp(nvsendto, "DSV") ||
+ !strcmp(nvsendto, "SIM_SPACE_VIEWER")) // legacy
+ {
+ mSendto = NVS_DATA_SIM_VIEWER;
+ mStringSendto = mNVNameTable->addString("DSV");
+ }
+ else
+ {
+ LL_WARNS() << "LLNameValue::init() - unknown sendto field "
+ << nvsendto << " for NV " << mName << LL_ENDL;
+ mSendto = NVS_NULL;
+ mStringSendto = mNVNameTable->addString("S");
+ }
+
+}
+
+
+LLNameValue::LLNameValue(const char *name, const char *data, const char *type, const char *nvclass)
+{
+ baseInit();
+ // if not specified, send to simulator only
+ init(name, data, type, nvclass, "SIM");
+}
+
+
+LLNameValue::LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto)
+{
+ baseInit();
+ init(name, data, type, nvclass, nvsendto);
+}
+
+
+
+// Initialize without any initial data.
+LLNameValue::LLNameValue(const char *name, const char *type, const char *nvclass)
+{
+ baseInit();
+ mName = mNVNameTable->addString(name);
+
+ // Nota Bene: Whatever global structure manages this should have these in the name table already!
+ mStringType = mNVNameTable->addString(type);
+ if (!strcmp(mStringType, "STRING"))
+ {
+ mType = NVT_STRING;
+ mNameValueReference.string = NULL;
+ }
+ else if (!strcmp(mStringType, "F32"))
+ {
+ mType = NVT_F32;
+ mNameValueReference.f32 = NULL;
+ }
+ else if (!strcmp(mStringType, "S32"))
+ {
+ mType = NVT_S32;
+ mNameValueReference.s32 = NULL;
+ }
+ else if (!strcmp(mStringType, "VEC3"))
+ {
+ mType = NVT_VEC3;
+ mNameValueReference.vec3 = NULL;
+ }
+ else if (!strcmp(mStringType, "U32"))
+ {
+ mType = NVT_U32;
+ mNameValueReference.u32 = NULL;
+ }
+ else if (!strcmp(mStringType, "U64"))
+ {
+ mType = NVT_U64;
+ mNameValueReference.u64 = NULL;
+ }
+ else if(!strcmp(mStringType, (const char*)NameValueTypeStrings[NVT_ASSET]))
+ {
+ mType = NVT_ASSET;
+ mNameValueReference.string = NULL;
+ }
+ else
+ {
+ mType = NVT_NULL;
+ LL_INFOS() << "Unknown name-value type " << mStringType << LL_ENDL;
+ }
+
+ // Nota Bene: Whatever global structure manages this should have these in the name table already!
+ mStringClass = mNVNameTable->addString(nvclass);
+ if (!strcmp(mStringClass, "READ_ONLY"))
+ {
+ mClass = NVC_READ_ONLY;
+ }
+ else if (!strcmp(mStringClass, "READ_WRITE"))
+ {
+ mClass = NVC_READ_WRITE;
+ }
+ else
+ {
+ mClass = NVC_NULL;
+ }
+
+ // Initialize the sendto variable
+ mStringSendto = mNVNameTable->addString("SIM");
+ mSendto = NVS_SIM;
+}
+
+
+// data is in the format:
+// "NameValueName Type Class Data"
+LLNameValue::LLNameValue(const char *data)
+{
+ baseInit();
+ static char name[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
+ static char type[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
+ static char nvclass[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
+ static char nvsendto[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
+ static char nvdata[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
+
+ S32 i;
+
+ S32 character_count = 0;
+ S32 length = 0;
+
+ // go to first non-whitespace character
+ while (1)
+ {
+ if ( (*(data + character_count) == ' ')
+ ||(*(data + character_count) == '\n')
+ ||(*(data + character_count) == '\t')
+ ||(*(data + character_count) == '\r'))
+ {
+ character_count++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // read in the name
+ sscanf((data + character_count), "%2047s", name); /*Flawfinder: ignore*/
+
+ // bump past it and add null terminator
+ length = (S32)strlen(name); /* Flawfinder: ignore */
+ name[length] = 0;
+ character_count += length;
+
+ // go to the next non-whitespace character
+ while (1)
+ {
+ if ( (*(data + character_count) == ' ')
+ ||(*(data + character_count) == '\n')
+ ||(*(data + character_count) == '\t')
+ ||(*(data + character_count) == '\r'))
+ {
+ character_count++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // read in the type
+ sscanf((data + character_count), "%2047s", type); /*Flawfinder: ignore*/
+
+ // bump past it and add null terminator
+ length = (S32)strlen(type); /* Flawfinder: ignore */
+ type[length] = 0;
+ character_count += length;
+
+ // go to the next non-whitespace character
+ while (1)
+ {
+ if ( (*(data + character_count) == ' ')
+ ||(*(data + character_count) == '\n')
+ ||(*(data + character_count) == '\t')
+ ||(*(data + character_count) == '\r'))
+ {
+ character_count++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // do we have a type argument?
+ for (i = NVC_READ_ONLY; i < NVC_EOF; i++)
+ {
+ if (!strncmp(NameValueClassStrings[i], data + character_count, strlen(NameValueClassStrings[i]))) /* Flawfinder: ignore */
+ {
+ break;
+ }
+ }
+
+ if (i != NVC_EOF)
+ {
+ // yes we do!
+ // read in the class
+ sscanf((data + character_count), "%2047s", nvclass); /*Flawfinder: ignore*/
+
+ // bump past it and add null terminator
+ length = (S32)strlen(nvclass); /* Flawfinder: ignore */
+ nvclass[length] = 0;
+ character_count += length;
+
+ // go to the next non-whitespace character
+ while (1)
+ {
+ if ( (*(data + character_count) == ' ')
+ ||(*(data + character_count) == '\n')
+ ||(*(data + character_count) == '\t')
+ ||(*(data + character_count) == '\r'))
+ {
+ character_count++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ // no type argument given, default to read-write
+ strncpy(nvclass, "READ_WRITE", sizeof(nvclass) -1); /* Flawfinder: ignore */
+ nvclass[sizeof(nvclass) -1] = '\0';
+ }
+
+ // Do we have a sendto argument?
+ for (i = NVS_SIM; i < NVS_EOF; i++)
+ {
+ if (!strncmp(NameValueSendtoStrings[i], data + character_count, strlen(NameValueSendtoStrings[i]))) /* Flawfinder: ignore */
+ {
+ break;
+ }
+ }
+
+ if (i != NVS_EOF)
+ {
+ // found a sendto argument
+ sscanf((data + character_count), "%2047s", nvsendto); /*Flawfinder: ignore*/
+
+ // add null terminator
+ length = (S32)strlen(nvsendto); /* Flawfinder: ignore */
+ nvsendto[length] = 0;
+ character_count += length;
+
+ // seek to next non-whitespace characer
+ while (1)
+ {
+ if ( (*(data + character_count) == ' ')
+ ||(*(data + character_count) == '\n')
+ ||(*(data + character_count) == '\t')
+ ||(*(data + character_count) == '\r'))
+ {
+ character_count++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ // no sendto argument given, default to sim only
+ strncpy(nvsendto, "SIM", sizeof(nvsendto) -1); /* Flawfinder: ignore */
+ nvsendto[sizeof(nvsendto) -1] ='\0';
+ }
+
+
+ // copy the rest character by character into data
+ length = 0;
+
+ while ( (*(nvdata + length++) = *(data + character_count++)) )
+ ;
+
+ init(name, nvdata, type, nvclass, nvsendto);
+}
+
+
+LLNameValue::~LLNameValue()
+{
+ mNVNameTable->removeString(mName);
+ mName = NULL;
+
+ switch(mType)
+ {
+ case NVT_STRING:
+ case NVT_ASSET:
+ delete [] mNameValueReference.string;
+ mNameValueReference.string = NULL;
+ break;
+ case NVT_F32:
+ delete mNameValueReference.f32;
+ mNameValueReference.string = NULL;
+ break;
+ case NVT_S32:
+ delete mNameValueReference.s32;
+ mNameValueReference.string = NULL;
+ break;
+ case NVT_VEC3:
+ delete mNameValueReference.vec3;
+ mNameValueReference.string = NULL;
+ break;
+ case NVT_U32:
+ delete mNameValueReference.u32;
+ mNameValueReference.u32 = NULL;
+ break;
+ case NVT_U64:
+ delete mNameValueReference.u64;
+ mNameValueReference.u64 = NULL;
+ break;
+ default:
+ break;
+ }
+
+ delete[] mNameValueReference.string;
+ mNameValueReference.string = NULL;
+}
+
+char *LLNameValue::getString()
+{
+ if (mType == NVT_STRING)
+ {
+ return mNameValueReference.string;
+ }
+ else
+ {
+ LL_ERRS() << mName << " not a string!" << LL_ENDL;
+ return NULL;
+ }
+}
+
+const char *LLNameValue::getAsset() const
+{
+ if (mType == NVT_ASSET)
+ {
+ return mNameValueReference.string;
+ }
+ else
+ {
+ LL_ERRS() << mName << " not an asset!" << LL_ENDL;
+ return NULL;
+ }
+}
+
+F32 *LLNameValue::getF32()
+{
+ if (mType == NVT_F32)
+ {
+ return mNameValueReference.f32;
+ }
+ else
+ {
+ LL_ERRS() << mName << " not a F32!" << LL_ENDL;
+ return NULL;
+ }
+}
+
+S32 *LLNameValue::getS32()
+{
+ if (mType == NVT_S32)
+ {
+ return mNameValueReference.s32;
+ }
+ else
+ {
+ LL_ERRS() << mName << " not a S32!" << LL_ENDL;
+ return NULL;
+ }
+}
+
+U32 *LLNameValue::getU32()
+{
+ if (mType == NVT_U32)
+ {
+ return mNameValueReference.u32;
+ }
+ else
+ {
+ LL_ERRS() << mName << " not a U32!" << LL_ENDL;
+ return NULL;
+ }
+}
+
+U64 *LLNameValue::getU64()
+{
+ if (mType == NVT_U64)
+ {
+ return mNameValueReference.u64;
+ }
+ else
+ {
+ LL_ERRS() << mName << " not a U64!" << LL_ENDL;
+ return NULL;
+ }
+}
+
+void LLNameValue::getVec3(LLVector3 &vec)
+{
+ if (mType == NVT_VEC3)
+ {
+ vec = *mNameValueReference.vec3;
+ }
+ else
+ {
+ LL_ERRS() << mName << " not a Vec3!" << LL_ENDL;
+ }
+}
+
+LLVector3 *LLNameValue::getVec3()
+{
+ if (mType == NVT_VEC3)
+ {
+ return (mNameValueReference.vec3);
+ }
+ else
+ {
+ LL_ERRS() << mName << " not a Vec3!" << LL_ENDL;
+ return NULL;
+ }
+}
+
+
+bool LLNameValue::sendToData() const
+{
+ return (mSendto == NVS_DATA_SIM || mSendto == NVS_DATA_SIM_VIEWER);
+}
+
+
+bool LLNameValue::sendToViewer() const
+{
+ return (mSendto == NVS_SIM_VIEWER || mSendto == NVS_DATA_SIM_VIEWER);
+}
+
+
+LLNameValue &LLNameValue::operator=(const LLNameValue &a)
+{
+ if (mType != a.mType)
+ {
+ return *this;
+ }
+ if (mClass == NVC_READ_ONLY)
+ return *this;
+
+ switch(a.mType)
+ {
+ case NVT_STRING:
+ case NVT_ASSET:
+ if (mNameValueReference.string)
+ delete [] mNameValueReference.string;
+
+ mNameValueReference.string = new char [strlen(a.mNameValueReference.string) + 1]; /* Flawfinder: ignore */
+ if(mNameValueReference.string != NULL)
+ {
+ strcpy(mNameValueReference.string, a.mNameValueReference.string); /* Flawfinder: ignore */
+ }
+ break;
+ case NVT_F32:
+ *mNameValueReference.f32 = *a.mNameValueReference.f32;
+ break;
+ case NVT_S32:
+ *mNameValueReference.s32 = *a.mNameValueReference.s32;
+ break;
+ case NVT_VEC3:
+ *mNameValueReference.vec3 = *a.mNameValueReference.vec3;
+ break;
+ case NVT_U32:
+ *mNameValueReference.u32 = *a.mNameValueReference.u32;
+ break;
+ case NVT_U64:
+ *mNameValueReference.u64 = *a.mNameValueReference.u64;
+ break;
+ default:
+ LL_ERRS() << "Unknown Name value type " << (U32)a.mType << LL_ENDL;
+ break;
+ }
+
+ return *this;
+}
+
+void LLNameValue::setString(const char *a)
+{
+ if (mClass == NVC_READ_ONLY)
+ return;
+
+ switch(mType)
+ {
+ case NVT_STRING:
+ if (a)
+ {
+ if (mNameValueReference.string)
+ {
+ delete [] mNameValueReference.string;
+ }
+
+ mNameValueReference.string = new char [strlen(a) + 1]; /* Flawfinder: ignore */
+ if(mNameValueReference.string != NULL)
+ {
+ strcpy(mNameValueReference.string, a); /* Flawfinder: ignore */
+ }
+ }
+ else
+ {
+ if (mNameValueReference.string)
+ delete [] mNameValueReference.string;
+
+ mNameValueReference.string = new char [1];
+ mNameValueReference.string[0] = 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+void LLNameValue::setAsset(const char *a)
+{
+ if (mClass == NVC_READ_ONLY)
+ return;
+
+ switch(mType)
+ {
+ case NVT_ASSET:
+ if (a)
+ {
+ if (mNameValueReference.string)
+ {
+ delete [] mNameValueReference.string;
+ }
+ mNameValueReference.string = new char [strlen(a) + 1]; /* Flawfinder: ignore */
+ if(mNameValueReference.string != NULL)
+ {
+ strcpy(mNameValueReference.string, a); /* Flawfinder: ignore */
+ }
+ }
+ else
+ {
+ if (mNameValueReference.string)
+ delete [] mNameValueReference.string;
+
+ mNameValueReference.string = new char [1];
+ mNameValueReference.string[0] = 0;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+void LLNameValue::setF32(const F32 a)
+{
+ if (mClass == NVC_READ_ONLY)
+ return;
+
+ switch(mType)
+ {
+ case NVT_F32:
+ *mNameValueReference.f32 = a;
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+void LLNameValue::setS32(const S32 a)
+{
+ if (mClass == NVC_READ_ONLY)
+ return;
+
+ switch(mType)
+ {
+ case NVT_S32:
+ *mNameValueReference.s32 = a;
+ break;
+ case NVT_U32:
+ *mNameValueReference.u32 = a;
+ break;
+ case NVT_F32:
+ *mNameValueReference.f32 = (F32)a;
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+void LLNameValue::setU32(const U32 a)
+{
+ if (mClass == NVC_READ_ONLY)
+ return;
+
+ switch(mType)
+ {
+ case NVT_S32:
+ *mNameValueReference.s32 = a;
+ break;
+ case NVT_U32:
+ *mNameValueReference.u32 = a;
+ break;
+ case NVT_F32:
+ *mNameValueReference.f32 = (F32)a;
+ break;
+ default:
+ LL_ERRS() << "NameValue: Trying to set U32 into a " << mStringType << ", unknown conversion" << LL_ENDL;
+ break;
+ }
+ return;
+}
+
+
+void LLNameValue::setVec3(const LLVector3 &a)
+{
+ if (mClass == NVC_READ_ONLY)
+ return;
+
+ switch(mType)
+ {
+ case NVT_VEC3:
+ *mNameValueReference.vec3 = a;
+ break;
+ default:
+ LL_ERRS() << "NameValue: Trying to set LLVector3 into a " << mStringType << ", unknown conversion" << LL_ENDL;
+ break;
+ }
+ return;
+}
+
+
+std::string LLNameValue::printNameValue() const
+{
+ std::string buffer;
+ buffer = llformat("%s %s %s %s ", mName, mStringType, mStringClass, mStringSendto);
+ buffer += printData();
+// LL_INFOS() << "Name Value Length: " << buffer.size() + 1 << LL_ENDL;
+ return buffer;
+}
+
+std::string LLNameValue::printData() const
+{
+ std::string buffer;
+ switch(mType)
+ {
+ case NVT_STRING:
+ case NVT_ASSET:
+ buffer = mNameValueReference.string;
+ break;
+ case NVT_F32:
+ buffer = llformat("%f", *mNameValueReference.f32);
+ break;
+ case NVT_S32:
+ buffer = llformat("%d", *mNameValueReference.s32);
+ break;
+ case NVT_U32:
+ buffer = llformat("%u", *mNameValueReference.u32);
+ break;
+ case NVT_U64:
+ {
+ char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */
+ U64_to_str(*mNameValueReference.u64, u64_string, sizeof(u64_string));
+ buffer = u64_string;
+ }
+ break;
+ case NVT_VEC3:
+ buffer = llformat( "%f, %f, %f", mNameValueReference.vec3->mV[VX], mNameValueReference.vec3->mV[VY], mNameValueReference.vec3->mV[VZ]);
+ break;
+ default:
+ LL_ERRS() << "Trying to print unknown NameValue type " << mStringType << LL_ENDL;
+ break;
+ }
+ return buffer;
+}
+
+std::ostream& operator<<(std::ostream& s, const LLNameValue &a)
+{
+ switch(a.mType)
+ {
+ case NVT_STRING:
+ case NVT_ASSET:
+ s << a.mNameValueReference.string;
+ break;
+ case NVT_F32:
+ s << (*a.mNameValueReference.f32);
+ break;
+ case NVT_S32:
+ s << *(a.mNameValueReference.s32);
+ break;
+ case NVT_U32:
+ s << *(a.mNameValueReference.u32);
+ break;
+ case NVT_U64:
+ {
+ char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */
+ U64_to_str(*a.mNameValueReference.u64, u64_string, sizeof(u64_string));
+ s << u64_string;
+ }
+ break;
+ case NVT_VEC3:
+ s << *(a.mNameValueReference.vec3);
+ break;
+ default:
+ LL_ERRS() << "Trying to print unknown NameValue type " << a.mStringType << LL_ENDL;
+ break;
+ }
+ return s;
+}
+
diff --git a/indra/llmessage/llnamevalue.h b/indra/llmessage/llnamevalue.h index 4016c268d2..6876c6020d 100644 --- a/indra/llmessage/llnamevalue.h +++ b/indra/llmessage/llnamevalue.h @@ -1,183 +1,183 @@ -/** - * @file llnamevalue.h - * @brief class for defining name value pairs. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLNAMEVALUE_H -#define LL_LLNAMEVALUE_H - -// As of January 2008, I believe we only use the following name-value -// pairs. This is hard to prove because they are initialized from -// strings. JC -// -// FirstName STRING -// LastName STRING -// AttachPt U32 -// AttachmentItemId STRING -// Title STRING -// AttachmentOffset VEC3 -// AttachmentOrientation VEC3 -// SitObject STRING -// SitPosition VEC3 - -#include "llstringtable.h" -#include "llmath.h" -#include "v3math.h" -#include "lldbstrings.h" - -class LLNameValue; -class LLStringTable; - -typedef enum e_name_value_types -{ - NVT_NULL, - NVT_STRING, - NVT_F32, - NVT_S32, - NVT_VEC3, - NVT_U32, - NVT_CAMERA, // Deprecated, but leaving in case removing this will cause problems - NVT_ASSET, - NVT_U64, - NVT_EOF -} ENameValueType; - -typedef enum e_name_value_class -{ - NVC_NULL, - NVC_READ_ONLY, - NVC_READ_WRITE, - NVC_EOF -} ENameValueClass; - -typedef enum e_name_value_sento -{ - NVS_NULL, - NVS_SIM, - NVS_DATA_SIM, - NVS_SIM_VIEWER, - NVS_DATA_SIM_VIEWER, - NVS_EOF -} ENameValueSendto; - - -// NameValues can always be "printed" into a buffer of this length. -const U32 NAME_VALUE_BUF_SIZE = 1024; - - -const U32 NAME_VALUE_TYPE_STRING_LENGTH = 8; -const U32 NAME_VALUE_CLASS_STRING_LENGTH = 16; -const U32 NAME_VALUE_SENDTO_STRING_LENGTH = 18; -const U32 NAME_VALUE_DATA_SIZE = - NAME_VALUE_BUF_SIZE - - ( DB_NV_NAME_BUF_SIZE + - NAME_VALUE_TYPE_STRING_LENGTH + - NAME_VALUE_CLASS_STRING_LENGTH + - NAME_VALUE_SENDTO_STRING_LENGTH ); - - -extern char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH]; /* Flawfinder: Ignore */ -extern char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH]; /* Flawfinder: Ignore */ -extern char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH]; /* Flawfinder: Ignore */ - -typedef union u_name_value_reference -{ - char *string; - F32 *f32; - S32 *s32; - LLVector3 *vec3; - U32 *u32; - U64 *u64; -} UNameValueReference; - - -class LLNameValue -{ -public: - void baseInit(); - void init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto ); - - LLNameValue(); - LLNameValue(const char *data); - LLNameValue(const char *name, const char *type, const char *nvclass ); - LLNameValue(const char *name, const char *data, const char *type, const char *nvclass ); - LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto ); - - ~LLNameValue(); - - char *getString(); - const char *getAsset() const; - F32 *getF32(); - S32 *getS32(); - void getVec3(LLVector3 &vec); - LLVector3 *getVec3(); - U32 *getU32(); - U64 *getU64(); - - const char *getType() const { return mStringType; } - const char *getClass() const { return mStringClass; } - const char *getSendto() const { return mStringSendto; } - - BOOL sendToData() const; - BOOL sendToViewer() const; - - void callCallback(); - std::string printNameValue() const; - std::string printData() const; - - ENameValueType getTypeEnum() const { return mType; } - ENameValueClass getClassEnum() const { return mClass; } - ENameValueSendto getSendtoEnum() const { return mSendto; } - - LLNameValue &operator=(const LLNameValue &a); - void setString(const char *a); - void setAsset(const char *a); - void setF32(const F32 a); - void setS32(const S32 a); - void setVec3(const LLVector3 &a); - void setU32(const U32 a); - - friend std::ostream& operator<<(std::ostream& s, const LLNameValue &a); - -private: - void printNameValue(std::ostream& s); - -public: - char *mName; - - char *mStringType; - ENameValueType mType; - char *mStringClass; - ENameValueClass mClass; - char *mStringSendto; - ENameValueSendto mSendto; - - UNameValueReference mNameValueReference; - LLStringTable *mNVNameTable; -}; - -extern LLStringTable gNVNameTable; - - -#endif +/**
+ * @file llnamevalue.h
+ * @brief class for defining name value pairs.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLNAMEVALUE_H
+#define LL_LLNAMEVALUE_H
+
+// As of January 2008, I believe we only use the following name-value
+// pairs. This is hard to prove because they are initialized from
+// strings. JC
+//
+// FirstName STRING
+// LastName STRING
+// AttachPt U32
+// AttachmentItemId STRING
+// Title STRING
+// AttachmentOffset VEC3
+// AttachmentOrientation VEC3
+// SitObject STRING
+// SitPosition VEC3
+
+#include "llstringtable.h"
+#include "llmath.h"
+#include "v3math.h"
+#include "lldbstrings.h"
+
+class LLNameValue;
+class LLStringTable;
+
+typedef enum e_name_value_types
+{
+ NVT_NULL,
+ NVT_STRING,
+ NVT_F32,
+ NVT_S32,
+ NVT_VEC3,
+ NVT_U32,
+ NVT_CAMERA, // Deprecated, but leaving in case removing this will cause problems
+ NVT_ASSET,
+ NVT_U64,
+ NVT_EOF
+} ENameValueType;
+
+typedef enum e_name_value_class
+{
+ NVC_NULL,
+ NVC_READ_ONLY,
+ NVC_READ_WRITE,
+ NVC_EOF
+} ENameValueClass;
+
+typedef enum e_name_value_sento
+{
+ NVS_NULL,
+ NVS_SIM,
+ NVS_DATA_SIM,
+ NVS_SIM_VIEWER,
+ NVS_DATA_SIM_VIEWER,
+ NVS_EOF
+} ENameValueSendto;
+
+
+// NameValues can always be "printed" into a buffer of this length.
+const U32 NAME_VALUE_BUF_SIZE = 1024;
+
+
+const U32 NAME_VALUE_TYPE_STRING_LENGTH = 8;
+const U32 NAME_VALUE_CLASS_STRING_LENGTH = 16;
+const U32 NAME_VALUE_SENDTO_STRING_LENGTH = 18;
+const U32 NAME_VALUE_DATA_SIZE =
+ NAME_VALUE_BUF_SIZE -
+ ( DB_NV_NAME_BUF_SIZE +
+ NAME_VALUE_TYPE_STRING_LENGTH +
+ NAME_VALUE_CLASS_STRING_LENGTH +
+ NAME_VALUE_SENDTO_STRING_LENGTH );
+
+
+extern char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH]; /* Flawfinder: Ignore */
+extern char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH]; /* Flawfinder: Ignore */
+extern char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH]; /* Flawfinder: Ignore */
+
+typedef union u_name_value_reference
+{
+ char *string;
+ F32 *f32;
+ S32 *s32;
+ LLVector3 *vec3;
+ U32 *u32;
+ U64 *u64;
+} UNameValueReference;
+
+
+class LLNameValue
+{
+public:
+ void baseInit();
+ void init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto );
+
+ LLNameValue();
+ LLNameValue(const char *data);
+ LLNameValue(const char *name, const char *type, const char *nvclass );
+ LLNameValue(const char *name, const char *data, const char *type, const char *nvclass );
+ LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto );
+
+ ~LLNameValue();
+
+ char *getString();
+ const char *getAsset() const;
+ F32 *getF32();
+ S32 *getS32();
+ void getVec3(LLVector3 &vec);
+ LLVector3 *getVec3();
+ U32 *getU32();
+ U64 *getU64();
+
+ const char *getType() const { return mStringType; }
+ const char *getClass() const { return mStringClass; }
+ const char *getSendto() const { return mStringSendto; }
+
+ bool sendToData() const;
+ bool sendToViewer() const;
+
+ void callCallback();
+ std::string printNameValue() const;
+ std::string printData() const;
+
+ ENameValueType getTypeEnum() const { return mType; }
+ ENameValueClass getClassEnum() const { return mClass; }
+ ENameValueSendto getSendtoEnum() const { return mSendto; }
+
+ LLNameValue &operator=(const LLNameValue &a);
+ void setString(const char *a);
+ void setAsset(const char *a);
+ void setF32(const F32 a);
+ void setS32(const S32 a);
+ void setVec3(const LLVector3 &a);
+ void setU32(const U32 a);
+
+ friend std::ostream& operator<<(std::ostream& s, const LLNameValue &a);
+
+private:
+ void printNameValue(std::ostream& s);
+
+public:
+ char *mName;
+
+ char *mStringType;
+ ENameValueType mType;
+ char *mStringClass;
+ ENameValueClass mClass;
+ char *mStringSendto;
+ ENameValueSendto mSendto;
+
+ UNameValueReference mNameValueReference;
+ LLStringTable *mNVNameTable;
+};
+
+extern LLStringTable gNVNameTable;
+
+
+#endif
diff --git a/indra/llmessage/llpacketack.cpp b/indra/llmessage/llpacketack.cpp index 98302111ca..19d21bf5d0 100644 --- a/indra/llmessage/llpacketack.cpp +++ b/indra/llmessage/llpacketack.cpp @@ -1,82 +1,82 @@ -/** - * @file llpacketack.cpp - * @author Phoenix - * @date 2007-05-09 - * @brief Implementation of the LLReliablePacket. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "linden_common.h" -#include "llpacketack.h" - -#if !LL_WINDOWS -#include <netinet/in.h> -#else -#include "winsock2.h" -#endif - -#include "message.h" - -LLReliablePacket::LLReliablePacket( - S32 socket, - U8* buf_ptr, - S32 buf_len, - LLReliablePacketParams* params) : - mBuffer(NULL), - mBufferLength(0) -{ - if (params) - { - mHost = params->mHost; - mRetries = params->mRetries; - mPingBasedRetry = params->mPingBasedRetry; - mTimeout = F32Seconds(params->mTimeout); - mCallback = params->mCallback; - mCallbackData = params->mCallbackData; - mMessageName = params->mMessageName; - } - else - { - mRetries = 0; - mPingBasedRetry = TRUE; - mTimeout = F32Seconds(0.f); - mCallback = NULL; - mCallbackData = NULL; - mMessageName = NULL; - } - - mExpirationTime = (F64Seconds)totalTime() + mTimeout; - mPacketID = ntohl(*((U32*)(&buf_ptr[PHL_PACKET_ID]))); - - mSocket = socket; - if (mRetries) - { - mBuffer = new U8[buf_len]; - if (mBuffer != NULL) - { - memcpy(mBuffer,buf_ptr,buf_len); /*Flawfinder: ignore*/ - mBufferLength = buf_len; - } - - } -} +/**
+ * @file llpacketack.cpp
+ * @author Phoenix
+ * @date 2007-05-09
+ * @brief Implementation of the LLReliablePacket.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+#include "llpacketack.h"
+
+#if !LL_WINDOWS
+#include <netinet/in.h>
+#else
+#include "winsock2.h"
+#endif
+
+#include "message.h"
+
+LLReliablePacket::LLReliablePacket(
+ S32 socket,
+ U8* buf_ptr,
+ S32 buf_len,
+ LLReliablePacketParams* params) :
+ mBuffer(NULL),
+ mBufferLength(0)
+{
+ if (params)
+ {
+ mHost = params->mHost;
+ mRetries = params->mRetries;
+ mPingBasedRetry = params->mPingBasedRetry;
+ mTimeout = F32Seconds(params->mTimeout);
+ mCallback = params->mCallback;
+ mCallbackData = params->mCallbackData;
+ mMessageName = params->mMessageName;
+ }
+ else
+ {
+ mRetries = 0;
+ mPingBasedRetry = true;
+ mTimeout = F32Seconds(0.f);
+ mCallback = NULL;
+ mCallbackData = NULL;
+ mMessageName = NULL;
+ }
+
+ mExpirationTime = (F64Seconds)totalTime() + mTimeout;
+ mPacketID = ntohl(*((U32*)(&buf_ptr[PHL_PACKET_ID])));
+
+ mSocket = socket;
+ if (mRetries)
+ {
+ mBuffer = new U8[buf_len];
+ if (mBuffer != NULL)
+ {
+ memcpy(mBuffer,buf_ptr,buf_len); /*Flawfinder: ignore*/
+ mBufferLength = buf_len;
+ }
+
+ }
+}
diff --git a/indra/llmessage/llpacketack.h b/indra/llmessage/llpacketack.h index b60861eac7..c359ec2c0e 100644 --- a/indra/llmessage/llpacketack.h +++ b/indra/llmessage/llpacketack.h @@ -1,116 +1,116 @@ -/** - * @file llpacketack.h - * @brief Reliable UDP helpers for the message system. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLPACKETACK_H -#define LL_LLPACKETACK_H - -#include "llhost.h" -#include "llunits.h" - -class LLReliablePacketParams -{ -public: - LLHost mHost; - S32 mRetries; - BOOL mPingBasedRetry; - F32Seconds mTimeout; - void (*mCallback)(void **,S32); - void** mCallbackData; - char* mMessageName; - -public: - LLReliablePacketParams() - { - clear(); - }; - - ~LLReliablePacketParams() { }; - - void clear() - { - mHost.invalidate(); - mRetries = 0; - mPingBasedRetry = TRUE; - mTimeout = F32Seconds(0.f); - mCallback = NULL; - mCallbackData = NULL; - mMessageName = NULL; - }; - - void set( - const LLHost& host, - S32 retries, - BOOL ping_based_retry, - F32Seconds timeout, - void (*callback)(void**,S32), - void** callback_data, char* name) - { - mHost = host; - mRetries = retries; - mPingBasedRetry = ping_based_retry; - mTimeout = timeout; - mCallback = callback; - mCallbackData = callback_data; - mMessageName = name; - }; -}; - -class LLReliablePacket -{ -public: - LLReliablePacket( - S32 socket, - U8* buf_ptr, - S32 buf_len, - LLReliablePacketParams* params); - ~LLReliablePacket() - { - mCallback = NULL; - delete [] mBuffer; - mBuffer = NULL; - }; - - friend class LLCircuitData; -protected: - S32 mSocket; - LLHost mHost; - S32 mRetries; - BOOL mPingBasedRetry; - F32Seconds mTimeout; - void (*mCallback)(void**,S32); - void** mCallbackData; - char* mMessageName; - - U8* mBuffer; - S32 mBufferLength; - - TPACKETID mPacketID; - - F64Seconds mExpirationTime; -}; - -#endif - +/**
+ * @file llpacketack.h
+ * @brief Reliable UDP helpers for the message system.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLPACKETACK_H
+#define LL_LLPACKETACK_H
+
+#include "llhost.h"
+#include "llunits.h"
+
+class LLReliablePacketParams
+{
+public:
+ LLHost mHost;
+ S32 mRetries;
+ bool mPingBasedRetry;
+ F32Seconds mTimeout;
+ void (*mCallback)(void **,S32);
+ void** mCallbackData;
+ char* mMessageName;
+
+public:
+ LLReliablePacketParams()
+ {
+ clear();
+ };
+
+ ~LLReliablePacketParams() { };
+
+ void clear()
+ {
+ mHost.invalidate();
+ mRetries = 0;
+ mPingBasedRetry = true;
+ mTimeout = F32Seconds(0.f);
+ mCallback = NULL;
+ mCallbackData = NULL;
+ mMessageName = NULL;
+ };
+
+ void set(
+ const LLHost& host,
+ S32 retries,
+ bool ping_based_retry,
+ F32Seconds timeout,
+ void (*callback)(void**,S32),
+ void** callback_data, char* name)
+ {
+ mHost = host;
+ mRetries = retries;
+ mPingBasedRetry = ping_based_retry;
+ mTimeout = timeout;
+ mCallback = callback;
+ mCallbackData = callback_data;
+ mMessageName = name;
+ };
+};
+
+class LLReliablePacket
+{
+public:
+ LLReliablePacket(
+ S32 socket,
+ U8* buf_ptr,
+ S32 buf_len,
+ LLReliablePacketParams* params);
+ ~LLReliablePacket()
+ {
+ mCallback = NULL;
+ delete [] mBuffer;
+ mBuffer = NULL;
+ };
+
+ friend class LLCircuitData;
+protected:
+ S32 mSocket;
+ LLHost mHost;
+ S32 mRetries;
+ bool mPingBasedRetry;
+ F32Seconds mTimeout;
+ void (*mCallback)(void**,S32);
+ void** mCallbackData;
+ char* mMessageName;
+
+ U8* mBuffer;
+ S32 mBufferLength;
+
+ TPACKETID mPacketID;
+
+ F64Seconds mExpirationTime;
+};
+
+#endif
+
diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 122f7a8b5b..8f96554939 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -1,371 +1,371 @@ -/** - * @file llpacketring.cpp - * @brief implementation of LLPacketRing class for a packet. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "llpacketring.h" - -#if LL_WINDOWS - #include <winsock2.h> -#else - #include <sys/socket.h> - #include <netinet/in.h> -#endif - -// linden library includes -#include "llerror.h" -#include "lltimer.h" -#include "llproxy.h" -#include "llrand.h" -#include "message.h" -#include "u64.h" - -/////////////////////////////////////////////////////////// -LLPacketRing::LLPacketRing () : - mUseInThrottle(FALSE), - mUseOutThrottle(FALSE), - mInThrottle(256000.f), - mOutThrottle(64000.f), - mActualBitsIn(0), - mActualBitsOut(0), - mMaxBufferLength(64000), - mInBufferLength(0), - mOutBufferLength(0), - mDropPercentage(0.0f), - mPacketsToDrop(0x0) -{ -} - -/////////////////////////////////////////////////////////// -LLPacketRing::~LLPacketRing () -{ - cleanup(); -} - -/////////////////////////////////////////////////////////// -void LLPacketRing::cleanup () -{ - LLPacketBuffer *packetp; - - while (!mReceiveQueue.empty()) - { - packetp = mReceiveQueue.front(); - delete packetp; - mReceiveQueue.pop(); - } - - while (!mSendQueue.empty()) - { - packetp = mSendQueue.front(); - delete packetp; - mSendQueue.pop(); - } -} - -/////////////////////////////////////////////////////////// -void LLPacketRing::dropPackets (U32 num_to_drop) -{ - mPacketsToDrop += num_to_drop; -} - -/////////////////////////////////////////////////////////// -void LLPacketRing::setDropPercentage (F32 percent_to_drop) -{ - mDropPercentage = percent_to_drop; -} - -void LLPacketRing::setUseInThrottle(const BOOL use_throttle) -{ - mUseInThrottle = use_throttle; -} - -void LLPacketRing::setUseOutThrottle(const BOOL use_throttle) -{ - mUseOutThrottle = use_throttle; -} - -void LLPacketRing::setInBandwidth(const F32 bps) -{ - mInThrottle.setRate(bps); -} - -void LLPacketRing::setOutBandwidth(const F32 bps) -{ - mOutThrottle.setRate(bps); -} -/////////////////////////////////////////////////////////// -S32 LLPacketRing::receiveFromRing (S32 socket, char *datap) -{ - - if (mInThrottle.checkOverflow(0)) - { - // We don't have enough bandwidth, don't give them a packet. - return 0; - } - - LLPacketBuffer *packetp = NULL; - if (mReceiveQueue.empty()) - { - // No packets on the queue, don't give them any. - return 0; - } - - S32 packet_size = 0; - packetp = mReceiveQueue.front(); - mReceiveQueue.pop(); - packet_size = packetp->getSize(); - if (packetp->getData() != NULL) - { - memcpy(datap, packetp->getData(), packet_size); /*Flawfinder: ignore*/ - } - // need to set sender IP/port!! - mLastSender = packetp->getHost(); - mLastReceivingIF = packetp->getReceivingInterface(); - delete packetp; - - this->mInBufferLength -= packet_size; - - // Adjust the throttle - mInThrottle.throttleOverflow(packet_size * 8.f); - return packet_size; -} - -/////////////////////////////////////////////////////////// -S32 LLPacketRing::receivePacket (S32 socket, char *datap) -{ - S32 packet_size = 0; - - // If using the throttle, simulate a limited size input buffer. - if (mUseInThrottle) - { - BOOL done = FALSE; - - // push any current net packet (if any) onto delay ring - while (!done) - { - LLPacketBuffer *packetp; - packetp = new LLPacketBuffer(socket); - - if (packetp->getSize()) - { - mActualBitsIn += packetp->getSize() * 8; - - // Fake packet loss - if (mDropPercentage && (ll_frand(100.f) < mDropPercentage)) - { - mPacketsToDrop++; - } - - if (mPacketsToDrop) - { - delete packetp; - packetp = NULL; - packet_size = 0; - mPacketsToDrop--; - } - } - - // If we faked packet loss, then we don't have a packet - // to use for buffer overflow testing - if (packetp) - { - if (mInBufferLength + packetp->getSize() > mMaxBufferLength) - { - // Toss it. - LL_WARNS() << "Throwing away packet, overflowing buffer" << LL_ENDL; - delete packetp; - packetp = NULL; - } - else if (packetp->getSize()) - { - mReceiveQueue.push(packetp); - mInBufferLength += packetp->getSize(); - } - else - { - delete packetp; - packetp = NULL; - done = true; - } - } - else - { - // No packetp, keep going? - no packetp == faked packet loss - } - } - - // Now, grab data off of the receive queue according to our - // throttled bandwidth settings. - packet_size = receiveFromRing(socket, datap); - } - else - { - // no delay, pull straight from net - if (LLProxy::isSOCKSProxyEnabled()) - { - U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; - packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer))); - - if (packet_size > SOCKS_HEADER_SIZE) - { - // *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6) - memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE); - proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer)); - mLastSender.setAddress(header->addr); - mLastSender.setPort(ntohs(header->port)); - - packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size - } - else - { - packet_size = 0; - } - } - else - { - packet_size = receive_packet(socket, datap); - mLastSender = ::get_sender(); - } - - mLastReceivingIF = ::get_receiving_interface(); - - if (packet_size) // did we actually get a packet? - { - if (mDropPercentage && (ll_frand(100.f) < mDropPercentage)) - { - mPacketsToDrop++; - } - - if (mPacketsToDrop) - { - packet_size = 0; - mPacketsToDrop--; - } - } - } - - return packet_size; -} - -BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host) -{ - BOOL status = TRUE; - if (!mUseOutThrottle) - { - return sendPacketImpl(h_socket, send_buffer, buf_size, host ); - } - else - { - mActualBitsOut += buf_size * 8; - LLPacketBuffer *packetp = NULL; - // See if we've got enough throttle to send a packet. - while (!mOutThrottle.checkOverflow(0.f)) - { - // While we have enough bandwidth, send a packet from the queue or the current packet - - S32 packet_size = 0; - if (!mSendQueue.empty()) - { - // Send a packet off of the queue - LLPacketBuffer *packetp = mSendQueue.front(); - mSendQueue.pop(); - - mOutBufferLength -= packetp->getSize(); - packet_size = packetp->getSize(); - - status = sendPacketImpl(h_socket, packetp->getData(), packet_size, packetp->getHost()); - - delete packetp; - // Update the throttle - mOutThrottle.throttleOverflow(packet_size * 8.f); - } - else - { - // If the queue's empty, we can just send this packet right away. - status = sendPacketImpl(h_socket, send_buffer, buf_size, host ); - packet_size = buf_size; - - // Update the throttle - mOutThrottle.throttleOverflow(packet_size * 8.f); - - // This was the packet we're sending now, there are no other packets - // that we need to send - return status; - } - - } - - // We haven't sent the incoming packet, add it to the queue - if (mOutBufferLength + buf_size > mMaxBufferLength) - { - // Nuke this packet, we overflowed the buffer. - // Toss it. - LL_WARNS() << "Throwing away outbound packet, overflowing buffer" << LL_ENDL; - } - else - { - static LLTimer queue_timer; - if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f) - { - // Add it to the queue - LL_INFOS() << "Outbound packet queue " << mOutBufferLength << " bytes" << LL_ENDL; - queue_timer.reset(); - } - packetp = new LLPacketBuffer(host, send_buffer, buf_size); - - mOutBufferLength += packetp->getSize(); - mSendQueue.push(packetp); - } - } - - return status; -} - -BOOL LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host) -{ - - if (!LLProxy::isSOCKSProxyEnabled()) - { - return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort()); - } - - char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; - - proxywrap_t *socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer)); - socks_header->rsv = 0; - socks_header->addr = host.getAddress(); - socks_header->port = htons(host.getPort()); - socks_header->atype = ADDRESS_IPV4; - socks_header->frag = 0; - - memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size); - - return send_packet( h_socket, - headered_send_buffer, - buf_size + SOCKS_HEADER_SIZE, - LLProxy::getInstance()->getUDPProxy().getAddress(), - LLProxy::getInstance()->getUDPProxy().getPort()); -} +/**
+ * @file llpacketring.cpp
+ * @brief implementation of LLPacketRing class for a packet.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llpacketring.h"
+
+#if LL_WINDOWS
+ #include <winsock2.h>
+#else
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+#endif
+
+// linden library includes
+#include "llerror.h"
+#include "lltimer.h"
+#include "llproxy.h"
+#include "llrand.h"
+#include "message.h"
+#include "u64.h"
+
+///////////////////////////////////////////////////////////
+LLPacketRing::LLPacketRing () :
+ mUseInThrottle(false),
+ mUseOutThrottle(false),
+ mInThrottle(256000.f),
+ mOutThrottle(64000.f),
+ mActualBitsIn(0),
+ mActualBitsOut(0),
+ mMaxBufferLength(64000),
+ mInBufferLength(0),
+ mOutBufferLength(0),
+ mDropPercentage(0.0f),
+ mPacketsToDrop(0x0)
+{
+}
+
+///////////////////////////////////////////////////////////
+LLPacketRing::~LLPacketRing ()
+{
+ cleanup();
+}
+
+///////////////////////////////////////////////////////////
+void LLPacketRing::cleanup ()
+{
+ LLPacketBuffer *packetp;
+
+ while (!mReceiveQueue.empty())
+ {
+ packetp = mReceiveQueue.front();
+ delete packetp;
+ mReceiveQueue.pop();
+ }
+
+ while (!mSendQueue.empty())
+ {
+ packetp = mSendQueue.front();
+ delete packetp;
+ mSendQueue.pop();
+ }
+}
+
+///////////////////////////////////////////////////////////
+void LLPacketRing::dropPackets (U32 num_to_drop)
+{
+ mPacketsToDrop += num_to_drop;
+}
+
+///////////////////////////////////////////////////////////
+void LLPacketRing::setDropPercentage (F32 percent_to_drop)
+{
+ mDropPercentage = percent_to_drop;
+}
+
+void LLPacketRing::setUseInThrottle(const bool use_throttle)
+{
+ mUseInThrottle = use_throttle;
+}
+
+void LLPacketRing::setUseOutThrottle(const bool use_throttle)
+{
+ mUseOutThrottle = use_throttle;
+}
+
+void LLPacketRing::setInBandwidth(const F32 bps)
+{
+ mInThrottle.setRate(bps);
+}
+
+void LLPacketRing::setOutBandwidth(const F32 bps)
+{
+ mOutThrottle.setRate(bps);
+}
+///////////////////////////////////////////////////////////
+S32 LLPacketRing::receiveFromRing (S32 socket, char *datap)
+{
+
+ if (mInThrottle.checkOverflow(0))
+ {
+ // We don't have enough bandwidth, don't give them a packet.
+ return 0;
+ }
+
+ LLPacketBuffer *packetp = NULL;
+ if (mReceiveQueue.empty())
+ {
+ // No packets on the queue, don't give them any.
+ return 0;
+ }
+
+ S32 packet_size = 0;
+ packetp = mReceiveQueue.front();
+ mReceiveQueue.pop();
+ packet_size = packetp->getSize();
+ if (packetp->getData() != NULL)
+ {
+ memcpy(datap, packetp->getData(), packet_size); /*Flawfinder: ignore*/
+ }
+ // need to set sender IP/port!!
+ mLastSender = packetp->getHost();
+ mLastReceivingIF = packetp->getReceivingInterface();
+ delete packetp;
+
+ this->mInBufferLength -= packet_size;
+
+ // Adjust the throttle
+ mInThrottle.throttleOverflow(packet_size * 8.f);
+ return packet_size;
+}
+
+///////////////////////////////////////////////////////////
+S32 LLPacketRing::receivePacket (S32 socket, char *datap)
+{
+ S32 packet_size = 0;
+
+ // If using the throttle, simulate a limited size input buffer.
+ if (mUseInThrottle)
+ {
+ bool done = false;
+
+ // push any current net packet (if any) onto delay ring
+ while (!done)
+ {
+ LLPacketBuffer *packetp;
+ packetp = new LLPacketBuffer(socket);
+
+ if (packetp->getSize())
+ {
+ mActualBitsIn += packetp->getSize() * 8;
+
+ // Fake packet loss
+ if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
+ {
+ mPacketsToDrop++;
+ }
+
+ if (mPacketsToDrop)
+ {
+ delete packetp;
+ packetp = NULL;
+ packet_size = 0;
+ mPacketsToDrop--;
+ }
+ }
+
+ // If we faked packet loss, then we don't have a packet
+ // to use for buffer overflow testing
+ if (packetp)
+ {
+ if (mInBufferLength + packetp->getSize() > mMaxBufferLength)
+ {
+ // Toss it.
+ LL_WARNS() << "Throwing away packet, overflowing buffer" << LL_ENDL;
+ delete packetp;
+ packetp = NULL;
+ }
+ else if (packetp->getSize())
+ {
+ mReceiveQueue.push(packetp);
+ mInBufferLength += packetp->getSize();
+ }
+ else
+ {
+ delete packetp;
+ packetp = NULL;
+ done = true;
+ }
+ }
+ else
+ {
+ // No packetp, keep going? - no packetp == faked packet loss
+ }
+ }
+
+ // Now, grab data off of the receive queue according to our
+ // throttled bandwidth settings.
+ packet_size = receiveFromRing(socket, datap);
+ }
+ else
+ {
+ // no delay, pull straight from net
+ if (LLProxy::isSOCKSProxyEnabled())
+ {
+ U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
+ packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer)));
+
+ if (packet_size > SOCKS_HEADER_SIZE)
+ {
+ // *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
+ memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE);
+ proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
+ mLastSender.setAddress(header->addr);
+ mLastSender.setPort(ntohs(header->port));
+
+ packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
+ }
+ else
+ {
+ packet_size = 0;
+ }
+ }
+ else
+ {
+ packet_size = receive_packet(socket, datap);
+ mLastSender = ::get_sender();
+ }
+
+ mLastReceivingIF = ::get_receiving_interface();
+
+ if (packet_size) // did we actually get a packet?
+ {
+ if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
+ {
+ mPacketsToDrop++;
+ }
+
+ if (mPacketsToDrop)
+ {
+ packet_size = 0;
+ mPacketsToDrop--;
+ }
+ }
+ }
+
+ return packet_size;
+}
+
+bool LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host)
+{
+ bool status = true;
+ if (!mUseOutThrottle)
+ {
+ return sendPacketImpl(h_socket, send_buffer, buf_size, host );
+ }
+ else
+ {
+ mActualBitsOut += buf_size * 8;
+ LLPacketBuffer *packetp = NULL;
+ // See if we've got enough throttle to send a packet.
+ while (!mOutThrottle.checkOverflow(0.f))
+ {
+ // While we have enough bandwidth, send a packet from the queue or the current packet
+
+ S32 packet_size = 0;
+ if (!mSendQueue.empty())
+ {
+ // Send a packet off of the queue
+ LLPacketBuffer *packetp = mSendQueue.front();
+ mSendQueue.pop();
+
+ mOutBufferLength -= packetp->getSize();
+ packet_size = packetp->getSize();
+
+ status = sendPacketImpl(h_socket, packetp->getData(), packet_size, packetp->getHost());
+
+ delete packetp;
+ // Update the throttle
+ mOutThrottle.throttleOverflow(packet_size * 8.f);
+ }
+ else
+ {
+ // If the queue's empty, we can just send this packet right away.
+ status = sendPacketImpl(h_socket, send_buffer, buf_size, host );
+ packet_size = buf_size;
+
+ // Update the throttle
+ mOutThrottle.throttleOverflow(packet_size * 8.f);
+
+ // This was the packet we're sending now, there are no other packets
+ // that we need to send
+ return status;
+ }
+
+ }
+
+ // We haven't sent the incoming packet, add it to the queue
+ if (mOutBufferLength + buf_size > mMaxBufferLength)
+ {
+ // Nuke this packet, we overflowed the buffer.
+ // Toss it.
+ LL_WARNS() << "Throwing away outbound packet, overflowing buffer" << LL_ENDL;
+ }
+ else
+ {
+ static LLTimer queue_timer;
+ if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f)
+ {
+ // Add it to the queue
+ LL_INFOS() << "Outbound packet queue " << mOutBufferLength << " bytes" << LL_ENDL;
+ queue_timer.reset();
+ }
+ packetp = new LLPacketBuffer(host, send_buffer, buf_size);
+
+ mOutBufferLength += packetp->getSize();
+ mSendQueue.push(packetp);
+ }
+ }
+
+ return status;
+}
+
+bool LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
+{
+
+ if (!LLProxy::isSOCKSProxyEnabled())
+ {
+ return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
+ }
+
+ char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
+
+ proxywrap_t *socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer));
+ socks_header->rsv = 0;
+ socks_header->addr = host.getAddress();
+ socks_header->port = htons(host.getPort());
+ socks_header->atype = ADDRESS_IPV4;
+ socks_header->frag = 0;
+
+ memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size);
+
+ return send_packet( h_socket,
+ headered_send_buffer,
+ buf_size + SOCKS_HEADER_SIZE,
+ LLProxy::getInstance()->getUDPProxy().getAddress(),
+ LLProxy::getInstance()->getUDPProxy().getPort());
+}
diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index 4f90112412..64f9f937af 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -1,101 +1,101 @@ -/** - * @file llpacketring.h - * @brief definition of LLPacketRing class for implementing a resend, - * drop, or delay in packet transmissions - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLPACKETRING_H -#define LL_LLPACKETRING_H - -#include <queue> - -#include "llhost.h" -#include "llpacketbuffer.h" -#include "llproxy.h" -#include "llthrottle.h" -#include "net.h" - -class LLPacketRing -{ -public: - LLPacketRing(); - ~LLPacketRing(); - - void cleanup(); - - void dropPackets(U32); - void setDropPercentage (F32 percent_to_drop); - void setUseInThrottle(const BOOL use_throttle); - void setUseOutThrottle(const BOOL use_throttle); - void setInBandwidth(const F32 bps); - void setOutBandwidth(const F32 bps); - S32 receivePacket (S32 socket, char *datap); - S32 receiveFromRing (S32 socket, char *datap); - - BOOL sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host); - - inline LLHost getLastSender(); - inline LLHost getLastReceivingInterface(); - - S32 getAndResetActualInBits() { S32 bits = mActualBitsIn; mActualBitsIn = 0; return bits;} - S32 getAndResetActualOutBits() { S32 bits = mActualBitsOut; mActualBitsOut = 0; return bits;} -protected: - BOOL mUseInThrottle; - BOOL mUseOutThrottle; - - // For simulating a lower-bandwidth connection - BPS - LLThrottle mInThrottle; - LLThrottle mOutThrottle; - - S32 mActualBitsIn; - S32 mActualBitsOut; - S32 mMaxBufferLength; // How much data can we queue up before dropping data. - S32 mInBufferLength; // Current incoming buffer length - S32 mOutBufferLength; // Current outgoing buffer length - - F32 mDropPercentage; // % of packets to drop - U32 mPacketsToDrop; // drop next n packets - - std::queue<LLPacketBuffer *> mReceiveQueue; - std::queue<LLPacketBuffer *> mSendQueue; - - LLHost mLastSender; - LLHost mLastReceivingIF; - -private: - BOOL sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host); -}; - - -inline LLHost LLPacketRing::getLastSender() -{ - return mLastSender; -} - -inline LLHost LLPacketRing::getLastReceivingInterface() -{ - return mLastReceivingIF; -} - -#endif +/**
+ * @file llpacketring.h
+ * @brief definition of LLPacketRing class for implementing a resend,
+ * drop, or delay in packet transmissions
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLPACKETRING_H
+#define LL_LLPACKETRING_H
+
+#include <queue>
+
+#include "llhost.h"
+#include "llpacketbuffer.h"
+#include "llproxy.h"
+#include "llthrottle.h"
+#include "net.h"
+
+class LLPacketRing
+{
+public:
+ LLPacketRing();
+ ~LLPacketRing();
+
+ void cleanup();
+
+ void dropPackets(U32);
+ void setDropPercentage (F32 percent_to_drop);
+ void setUseInThrottle(const bool use_throttle);
+ void setUseOutThrottle(const bool use_throttle);
+ void setInBandwidth(const F32 bps);
+ void setOutBandwidth(const F32 bps);
+ S32 receivePacket (S32 socket, char *datap);
+ S32 receiveFromRing (S32 socket, char *datap);
+
+ bool sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host);
+
+ inline LLHost getLastSender();
+ inline LLHost getLastReceivingInterface();
+
+ S32 getAndResetActualInBits() { S32 bits = mActualBitsIn; mActualBitsIn = 0; return bits;}
+ S32 getAndResetActualOutBits() { S32 bits = mActualBitsOut; mActualBitsOut = 0; return bits;}
+protected:
+ bool mUseInThrottle;
+ bool mUseOutThrottle;
+
+ // For simulating a lower-bandwidth connection - BPS
+ LLThrottle mInThrottle;
+ LLThrottle mOutThrottle;
+
+ S32 mActualBitsIn;
+ S32 mActualBitsOut;
+ S32 mMaxBufferLength; // How much data can we queue up before dropping data.
+ S32 mInBufferLength; // Current incoming buffer length
+ S32 mOutBufferLength; // Current outgoing buffer length
+
+ F32 mDropPercentage; // % of packets to drop
+ U32 mPacketsToDrop; // drop next n packets
+
+ std::queue<LLPacketBuffer *> mReceiveQueue;
+ std::queue<LLPacketBuffer *> mSendQueue;
+
+ LLHost mLastSender;
+ LLHost mLastReceivingIF;
+
+private:
+ bool sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
+};
+
+
+inline LLHost LLPacketRing::getLastSender()
+{
+ return mLastSender;
+}
+
+inline LLHost LLPacketRing::getLastReceivingInterface()
+{
+ return mLastReceivingIF;
+}
+
+#endif
diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp index 320b61b905..afbc74b847 100644 --- a/indra/llmessage/llpartdata.cpp +++ b/indra/llmessage/llpartdata.cpp @@ -1,419 +1,419 @@ -/** - * @file llpartdata.cpp - * @brief Particle system data packing - * - * $LicenseInfo:firstyear=2003&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$ - */ - -#include "linden_common.h" - -#include "llpartdata.h" -#include "message.h" - -#include "lldatapacker.h" -#include "v4coloru.h" - -#include "llsdutil.h" -#include "llsdutil_math.h" - - - -const S32 PS_PART_DATA_GLOW_SIZE = 2; -const S32 PS_PART_DATA_BLEND_SIZE = 2; -const S32 PS_LEGACY_PART_DATA_BLOCK_SIZE = 4 + 2 + 4 + 4 + 2 + 2; //18 -const S32 PS_SYS_DATA_BLOCK_SIZE = 68; -const S32 PS_MAX_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE+ - PS_LEGACY_PART_DATA_BLOCK_SIZE + - PS_PART_DATA_BLEND_SIZE + - PS_PART_DATA_GLOW_SIZE+ - 8; //two S32 size fields - -const S32 PS_LEGACY_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE + PS_LEGACY_PART_DATA_BLOCK_SIZE; - -const F32 MAX_PART_SCALE = 4.f; - -bool LLPartData::hasGlow() const -{ - return mStartGlow > 0.f || mEndGlow > 0.f; -} - -bool LLPartData::hasBlendFunc() const -{ - return mBlendFuncSource != LLPartData::LL_PART_BF_SOURCE_ALPHA || mBlendFuncDest != LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; -} - -S32 LLPartData::getSize() const -{ - S32 size = PS_LEGACY_PART_DATA_BLOCK_SIZE; - if (hasGlow()) size += PS_PART_DATA_GLOW_SIZE; - if (hasBlendFunc()) size += PS_PART_DATA_BLEND_SIZE; - - return size; -} - - -BOOL LLPartData::unpackLegacy(LLDataPacker &dp) -{ - LLColor4U coloru; - - dp.unpackU32(mFlags, "pdflags"); - dp.unpackFixed(mMaxAge, "pdmaxage", FALSE, 8, 8); - - dp.unpackColor4U(coloru, "pdstartcolor"); - mStartColor.setVec(coloru); - dp.unpackColor4U(coloru, "pdendcolor"); - mEndColor.setVec(coloru); - dp.unpackFixed(mStartScale.mV[0], "pdstartscalex", FALSE, 3, 5); - dp.unpackFixed(mStartScale.mV[1], "pdstartscaley", FALSE, 3, 5); - dp.unpackFixed(mEndScale.mV[0], "pdendscalex", FALSE, 3, 5); - dp.unpackFixed(mEndScale.mV[1], "pdendscaley", FALSE, 3, 5); - - mStartGlow = 0.f; - mEndGlow = 0.f; - mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA; - mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; - - return TRUE; -} - -BOOL LLPartData::unpack(LLDataPacker &dp) -{ - S32 size = 0; - dp.unpackS32(size, "partsize"); - - unpackLegacy(dp); - size -= PS_LEGACY_PART_DATA_BLOCK_SIZE; - - if (mFlags & LL_PART_DATA_GLOW) - { - if (size < PS_PART_DATA_GLOW_SIZE) return FALSE; - - U8 tmp_glow = 0; - dp.unpackU8(tmp_glow,"pdstartglow"); - mStartGlow = tmp_glow / 255.f; - dp.unpackU8(tmp_glow,"pdendglow"); - mEndGlow = tmp_glow / 255.f; - - size -= PS_PART_DATA_GLOW_SIZE; - } - else - { - mStartGlow = 0.f; - mEndGlow = 0.f; - } - - if (mFlags & LL_PART_DATA_BLEND) - { - if (size < PS_PART_DATA_BLEND_SIZE) return FALSE; - dp.unpackU8(mBlendFuncSource,"pdblendsource"); - dp.unpackU8(mBlendFuncDest,"pdblenddest"); - size -= PS_PART_DATA_BLEND_SIZE; - } - else - { - mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA; - mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; - } - - if (size > 0) - { //leftover bytes, unrecognized parameters - U8 feh = 0; - while (size > 0) - { //read remaining bytes in block - dp.unpackU8(feh, "whippang"); - size--; - } - - //this particle system won't display properly, better to not show anything - return FALSE; - } - - - return TRUE; -} - -void LLPartData::setFlags(const U32 flags) -{ - mFlags = flags; -} - - -void LLPartData::setMaxAge(const F32 max_age) -{ - mMaxAge = llclamp(max_age, 0.f, 30.f); -} - - -void LLPartData::setStartScale(const F32 xs, const F32 ys) -{ - mStartScale.mV[VX] = llmin(xs, MAX_PART_SCALE); - mStartScale.mV[VY] = llmin(ys, MAX_PART_SCALE); -} - - -void LLPartData::setEndScale(const F32 xs, const F32 ys) -{ - mEndScale.mV[VX] = llmin(xs, MAX_PART_SCALE); - mEndScale.mV[VY] = llmin(ys, MAX_PART_SCALE); -} - - -void LLPartData::setStartColor(const LLVector3 &rgb) -{ - mStartColor.setVec(rgb.mV[0], rgb.mV[1], rgb.mV[2]); -} - - -void LLPartData::setEndColor(const LLVector3 &rgb) -{ - mEndColor.setVec(rgb.mV[0], rgb.mV[1], rgb.mV[2]); -} - -void LLPartData::setStartAlpha(const F32 alpha) -{ - mStartColor.mV[3] = alpha; -} -void LLPartData::setEndAlpha(const F32 alpha) -{ - mEndColor.mV[3] = alpha; -} - -// static -bool LLPartData::validBlendFunc(S32 func) -{ - if (func >= 0 - && func < LL_PART_BF_COUNT - && func != UNSUPPORTED_DEST_ALPHA - && func != UNSUPPORTED_ONE_MINUS_DEST_ALPHA) - { - return true; - } - return false; -} - -LLPartSysData::LLPartSysData() -{ - mCRC = 0; - mFlags = 0; - - mPartData.mFlags = 0; - mPartData.mStartColor = LLColor4(1.f, 1.f, 1.f, 1.f); - mPartData.mEndColor = LLColor4(1.f, 1.f, 1.f, 1.f); - mPartData.mStartScale = LLVector2(1.f, 1.f); - mPartData.mEndScale = LLVector2(1.f, 1.f); - mPartData.mMaxAge = 10.0; - mPartData.mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA; - mPartData.mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; - mPartData.mStartGlow = 0.f; - mPartData.mEndGlow = 0.f; - - mMaxAge = 0.0; - mStartAge = 0.0; - mPattern = LL_PART_SRC_PATTERN_DROP; // Pattern for particle velocity - mInnerAngle = 0.0; // Inner angle of PATTERN_ANGLE_* - mOuterAngle = 0.0; // Outer angle of PATTERN_ANGLE_* - mBurstRate = 0.1f; // How often to do a burst of particles - mBurstPartCount = 1; // How many particles in a burst - mBurstSpeedMin = 1.f; // Minimum particle velocity - mBurstSpeedMax = 1.f; // Maximum particle velocity - mBurstRadius = 0.f; - - mNumParticles = 0; -} - -BOOL LLPartSysData::unpackSystem(LLDataPacker &dp) -{ - dp.unpackU32(mCRC, "pscrc"); - dp.unpackU32(mFlags, "psflags"); - dp.unpackU8(mPattern, "pspattern"); - dp.unpackFixed(mMaxAge, "psmaxage", FALSE, 8, 8); - dp.unpackFixed(mStartAge, "psstartage", FALSE, 8, 8); - dp.unpackFixed(mInnerAngle, "psinnerangle", FALSE, 3, 5); - dp.unpackFixed(mOuterAngle, "psouterangle", FALSE, 3, 5); - dp.unpackFixed(mBurstRate, "psburstrate", FALSE, 8, 8); - mBurstRate = llmax(0.01f, mBurstRate); - dp.unpackFixed(mBurstRadius, "psburstradius", FALSE, 8, 8); - dp.unpackFixed(mBurstSpeedMin, "psburstspeedmin", FALSE, 8, 8); - dp.unpackFixed(mBurstSpeedMax, "psburstspeedmax", FALSE, 8, 8); - dp.unpackU8(mBurstPartCount, "psburstpartcount"); - - dp.unpackFixed(mAngularVelocity.mV[0], "psangvelx", TRUE, 8, 7); - dp.unpackFixed(mAngularVelocity.mV[1], "psangvely", TRUE, 8, 7); - dp.unpackFixed(mAngularVelocity.mV[2], "psangvelz", TRUE, 8, 7); - - dp.unpackFixed(mPartAccel.mV[0], "psaccelx", TRUE, 8, 7); - dp.unpackFixed(mPartAccel.mV[1], "psaccely", TRUE, 8, 7); - dp.unpackFixed(mPartAccel.mV[2], "psaccelz", TRUE, 8, 7); - - dp.unpackUUID(mPartImageID, "psuuid"); - dp.unpackUUID(mTargetUUID, "pstargetuuid"); - return TRUE; -} - -BOOL LLPartSysData::unpackLegacy(LLDataPacker &dp) -{ - unpackSystem(dp); - mPartData.unpackLegacy(dp); - - return TRUE; -} - -BOOL LLPartSysData::unpack(LLDataPacker &dp) -{ - // syssize is currently unused. Adding now when modifying the 'version to make extensible in the future - S32 size = 0; - dp.unpackS32(size, "syssize"); - - if (size != PS_SYS_DATA_BLOCK_SIZE) - { //unexpected size, this viewer doesn't know how to parse this particle system - - //skip to LLPartData block - U8 feh = 0; - - for (U32 i = 0; i < size; ++i) - { - dp.unpackU8(feh, "whippang"); - } - - dp.unpackS32(size, "partsize"); - //skip LLPartData block - for (U32 i = 0; i < size; ++i) - { - dp.unpackU8(feh, "whippang"); - } - return FALSE; - } - - unpackSystem(dp); - - return mPartData.unpack(dp); -} - -std::ostream& operator<<(std::ostream& s, const LLPartSysData &data) -{ - s << "Flags: " << std::hex << data.mFlags; - s << "Pattern: " << std::hex << (U32) data.mPattern << "\n"; - s << "Source Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n"; - s << "Particle Age: " << data.mPartData.mMaxAge << "\n"; - s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n"; - s << "Burst Rate: " << data.mBurstRate << "\n"; - s << "Burst Radius: " << data.mBurstRadius << "\n"; - s << "Burst Speed: [" << data.mBurstSpeedMin << ", " << data.mBurstSpeedMax << "]\n"; - s << "Burst Part Count: " << std::hex << (U32) data.mBurstPartCount << "\n"; - s << "Angular Velocity: " << data.mAngularVelocity << "\n"; - s << "Accel: " << data.mPartAccel; - return s; -} - -BOOL LLPartSysData::isNullPS(const S32 block_num) -{ - U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE]; - U32 crc; - - S32 size; - // Check size of block - size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock"); - - if (!size) - { - return TRUE; - } - - if (size > PS_MAX_DATA_BLOCK_SIZE) - { - //size is too big, newer particle version unsupported - return TRUE; - } - - gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); - - LLDataPackerBinaryBuffer dp(ps_data_block, size); - if (size > PS_LEGACY_DATA_BLOCK_SIZE) - { - // non legacy systems pack a size before the CRC - S32 tmp = 0; - dp.unpackS32(tmp, "syssize"); - - if (tmp > PS_SYS_DATA_BLOCK_SIZE) - { //unknown system data block size, don't know how to parse it, treat as NULL - return TRUE; - } - } - - dp.unpackU32(crc, "crc"); - - if (crc == 0) - { - return TRUE; - } - return FALSE; -} - -BOOL LLPartSysData::unpackBlock(const S32 block_num) -{ - U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE]; - - // Check size of block - S32 size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock"); - - if (size > PS_MAX_DATA_BLOCK_SIZE) - { - // Larger packets are newer and unsupported - return FALSE; - } - - // Get from message - gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); - - LLDataPackerBinaryBuffer dp(ps_data_block, size); - - if (size == PS_LEGACY_DATA_BLOCK_SIZE) - { - return unpackLegacy(dp); - } - else - { - return unpack(dp); - } -} - -bool LLPartSysData::isLegacyCompatible() const -{ - return !mPartData.hasGlow() && !mPartData.hasBlendFunc(); -} - -void LLPartSysData::clampSourceParticleRate() -{ - F32 particle_rate = 0; - particle_rate = mBurstPartCount/mBurstRate; - if (particle_rate > 256.f) - { - mBurstPartCount = llfloor(((F32)mBurstPartCount)*(256.f/particle_rate)); - } -} - -void LLPartSysData::setPartAccel(const LLVector3 &accel) -{ - mPartAccel.mV[VX] = llclamp(accel.mV[VX], -100.f, 100.f); - mPartAccel.mV[VY] = llclamp(accel.mV[VY], -100.f, 100.f); - mPartAccel.mV[VZ] = llclamp(accel.mV[VZ], -100.f, 100.f); -} +/**
+ * @file llpartdata.cpp
+ * @brief Particle system data packing
+ *
+ * $LicenseInfo:firstyear=2003&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$
+ */
+
+#include "linden_common.h"
+
+#include "llpartdata.h"
+#include "message.h"
+
+#include "lldatapacker.h"
+#include "v4coloru.h"
+
+#include "llsdutil.h"
+#include "llsdutil_math.h"
+
+
+
+const S32 PS_PART_DATA_GLOW_SIZE = 2;
+const S32 PS_PART_DATA_BLEND_SIZE = 2;
+const S32 PS_LEGACY_PART_DATA_BLOCK_SIZE = 4 + 2 + 4 + 4 + 2 + 2; //18
+const S32 PS_SYS_DATA_BLOCK_SIZE = 68;
+const S32 PS_MAX_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE+
+ PS_LEGACY_PART_DATA_BLOCK_SIZE +
+ PS_PART_DATA_BLEND_SIZE +
+ PS_PART_DATA_GLOW_SIZE+
+ 8; //two S32 size fields
+
+const S32 PS_LEGACY_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE + PS_LEGACY_PART_DATA_BLOCK_SIZE;
+
+const F32 MAX_PART_SCALE = 4.f;
+
+bool LLPartData::hasGlow() const
+{
+ return mStartGlow > 0.f || mEndGlow > 0.f;
+}
+
+bool LLPartData::hasBlendFunc() const
+{
+ return mBlendFuncSource != LLPartData::LL_PART_BF_SOURCE_ALPHA || mBlendFuncDest != LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
+}
+
+S32 LLPartData::getSize() const
+{
+ S32 size = PS_LEGACY_PART_DATA_BLOCK_SIZE;
+ if (hasGlow()) size += PS_PART_DATA_GLOW_SIZE;
+ if (hasBlendFunc()) size += PS_PART_DATA_BLEND_SIZE;
+
+ return size;
+}
+
+
+bool LLPartData::unpackLegacy(LLDataPacker &dp)
+{
+ LLColor4U coloru;
+
+ dp.unpackU32(mFlags, "pdflags");
+ dp.unpackFixed(mMaxAge, "pdmaxage", false, 8, 8);
+
+ dp.unpackColor4U(coloru, "pdstartcolor");
+ mStartColor.setVec(coloru);
+ dp.unpackColor4U(coloru, "pdendcolor");
+ mEndColor.setVec(coloru);
+ dp.unpackFixed(mStartScale.mV[0], "pdstartscalex", false, 3, 5);
+ dp.unpackFixed(mStartScale.mV[1], "pdstartscaley", false, 3, 5);
+ dp.unpackFixed(mEndScale.mV[0], "pdendscalex", false, 3, 5);
+ dp.unpackFixed(mEndScale.mV[1], "pdendscaley", false, 3, 5);
+
+ mStartGlow = 0.f;
+ mEndGlow = 0.f;
+ mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA;
+ mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
+
+ return true;
+}
+
+bool LLPartData::unpack(LLDataPacker &dp)
+{
+ S32 size = 0;
+ dp.unpackS32(size, "partsize");
+
+ unpackLegacy(dp);
+ size -= PS_LEGACY_PART_DATA_BLOCK_SIZE;
+
+ if (mFlags & LL_PART_DATA_GLOW)
+ {
+ if (size < PS_PART_DATA_GLOW_SIZE) return false;
+
+ U8 tmp_glow = 0;
+ dp.unpackU8(tmp_glow,"pdstartglow");
+ mStartGlow = tmp_glow / 255.f;
+ dp.unpackU8(tmp_glow,"pdendglow");
+ mEndGlow = tmp_glow / 255.f;
+
+ size -= PS_PART_DATA_GLOW_SIZE;
+ }
+ else
+ {
+ mStartGlow = 0.f;
+ mEndGlow = 0.f;
+ }
+
+ if (mFlags & LL_PART_DATA_BLEND)
+ {
+ if (size < PS_PART_DATA_BLEND_SIZE) return false;
+ dp.unpackU8(mBlendFuncSource,"pdblendsource");
+ dp.unpackU8(mBlendFuncDest,"pdblenddest");
+ size -= PS_PART_DATA_BLEND_SIZE;
+ }
+ else
+ {
+ mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA;
+ mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
+ }
+
+ if (size > 0)
+ { //leftover bytes, unrecognized parameters
+ U8 feh = 0;
+ while (size > 0)
+ { //read remaining bytes in block
+ dp.unpackU8(feh, "whippang");
+ size--;
+ }
+
+ //this particle system won't display properly, better to not show anything
+ return false;
+ }
+
+
+ return true;
+}
+
+void LLPartData::setFlags(const U32 flags)
+{
+ mFlags = flags;
+}
+
+
+void LLPartData::setMaxAge(const F32 max_age)
+{
+ mMaxAge = llclamp(max_age, 0.f, 30.f);
+}
+
+
+void LLPartData::setStartScale(const F32 xs, const F32 ys)
+{
+ mStartScale.mV[VX] = llmin(xs, MAX_PART_SCALE);
+ mStartScale.mV[VY] = llmin(ys, MAX_PART_SCALE);
+}
+
+
+void LLPartData::setEndScale(const F32 xs, const F32 ys)
+{
+ mEndScale.mV[VX] = llmin(xs, MAX_PART_SCALE);
+ mEndScale.mV[VY] = llmin(ys, MAX_PART_SCALE);
+}
+
+
+void LLPartData::setStartColor(const LLVector3 &rgb)
+{
+ mStartColor.setVec(rgb.mV[0], rgb.mV[1], rgb.mV[2]);
+}
+
+
+void LLPartData::setEndColor(const LLVector3 &rgb)
+{
+ mEndColor.setVec(rgb.mV[0], rgb.mV[1], rgb.mV[2]);
+}
+
+void LLPartData::setStartAlpha(const F32 alpha)
+{
+ mStartColor.mV[3] = alpha;
+}
+void LLPartData::setEndAlpha(const F32 alpha)
+{
+ mEndColor.mV[3] = alpha;
+}
+
+// static
+bool LLPartData::validBlendFunc(S32 func)
+{
+ if (func >= 0
+ && func < LL_PART_BF_COUNT
+ && func != UNSUPPORTED_DEST_ALPHA
+ && func != UNSUPPORTED_ONE_MINUS_DEST_ALPHA)
+ {
+ return true;
+ }
+ return false;
+}
+
+LLPartSysData::LLPartSysData()
+{
+ mCRC = 0;
+ mFlags = 0;
+
+ mPartData.mFlags = 0;
+ mPartData.mStartColor = LLColor4(1.f, 1.f, 1.f, 1.f);
+ mPartData.mEndColor = LLColor4(1.f, 1.f, 1.f, 1.f);
+ mPartData.mStartScale = LLVector2(1.f, 1.f);
+ mPartData.mEndScale = LLVector2(1.f, 1.f);
+ mPartData.mMaxAge = 10.0;
+ mPartData.mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA;
+ mPartData.mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
+ mPartData.mStartGlow = 0.f;
+ mPartData.mEndGlow = 0.f;
+
+ mMaxAge = 0.0;
+ mStartAge = 0.0;
+ mPattern = LL_PART_SRC_PATTERN_DROP; // Pattern for particle velocity
+ mInnerAngle = 0.0; // Inner angle of PATTERN_ANGLE_*
+ mOuterAngle = 0.0; // Outer angle of PATTERN_ANGLE_*
+ mBurstRate = 0.1f; // How often to do a burst of particles
+ mBurstPartCount = 1; // How many particles in a burst
+ mBurstSpeedMin = 1.f; // Minimum particle velocity
+ mBurstSpeedMax = 1.f; // Maximum particle velocity
+ mBurstRadius = 0.f;
+
+ mNumParticles = 0;
+}
+
+bool LLPartSysData::unpackSystem(LLDataPacker &dp)
+{
+ dp.unpackU32(mCRC, "pscrc");
+ dp.unpackU32(mFlags, "psflags");
+ dp.unpackU8(mPattern, "pspattern");
+ dp.unpackFixed(mMaxAge, "psmaxage", false, 8, 8);
+ dp.unpackFixed(mStartAge, "psstartage", false, 8, 8);
+ dp.unpackFixed(mInnerAngle, "psinnerangle", false, 3, 5);
+ dp.unpackFixed(mOuterAngle, "psouterangle", false, 3, 5);
+ dp.unpackFixed(mBurstRate, "psburstrate", false, 8, 8);
+ mBurstRate = llmax(0.01f, mBurstRate);
+ dp.unpackFixed(mBurstRadius, "psburstradius", false, 8, 8);
+ dp.unpackFixed(mBurstSpeedMin, "psburstspeedmin", false, 8, 8);
+ dp.unpackFixed(mBurstSpeedMax, "psburstspeedmax", false, 8, 8);
+ dp.unpackU8(mBurstPartCount, "psburstpartcount");
+
+ dp.unpackFixed(mAngularVelocity.mV[0], "psangvelx", true, 8, 7);
+ dp.unpackFixed(mAngularVelocity.mV[1], "psangvely", true, 8, 7);
+ dp.unpackFixed(mAngularVelocity.mV[2], "psangvelz", true, 8, 7);
+
+ dp.unpackFixed(mPartAccel.mV[0], "psaccelx", true, 8, 7);
+ dp.unpackFixed(mPartAccel.mV[1], "psaccely", true, 8, 7);
+ dp.unpackFixed(mPartAccel.mV[2], "psaccelz", true, 8, 7);
+
+ dp.unpackUUID(mPartImageID, "psuuid");
+ dp.unpackUUID(mTargetUUID, "pstargetuuid");
+ return true;
+}
+
+bool LLPartSysData::unpackLegacy(LLDataPacker &dp)
+{
+ unpackSystem(dp);
+ mPartData.unpackLegacy(dp);
+
+ return true;
+}
+
+bool LLPartSysData::unpack(LLDataPacker &dp)
+{
+ // syssize is currently unused. Adding now when modifying the 'version to make extensible in the future
+ S32 size = 0;
+ dp.unpackS32(size, "syssize");
+
+ if (size != PS_SYS_DATA_BLOCK_SIZE)
+ { //unexpected size, this viewer doesn't know how to parse this particle system
+
+ //skip to LLPartData block
+ U8 feh = 0;
+
+ for (U32 i = 0; i < size; ++i)
+ {
+ dp.unpackU8(feh, "whippang");
+ }
+
+ dp.unpackS32(size, "partsize");
+ //skip LLPartData block
+ for (U32 i = 0; i < size; ++i)
+ {
+ dp.unpackU8(feh, "whippang");
+ }
+ return false;
+ }
+
+ unpackSystem(dp);
+
+ return mPartData.unpack(dp);
+}
+
+std::ostream& operator<<(std::ostream& s, const LLPartSysData &data)
+{
+ s << "Flags: " << std::hex << data.mFlags;
+ s << "Pattern: " << std::hex << (U32) data.mPattern << "\n";
+ s << "Source Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n";
+ s << "Particle Age: " << data.mPartData.mMaxAge << "\n";
+ s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n";
+ s << "Burst Rate: " << data.mBurstRate << "\n";
+ s << "Burst Radius: " << data.mBurstRadius << "\n";
+ s << "Burst Speed: [" << data.mBurstSpeedMin << ", " << data.mBurstSpeedMax << "]\n";
+ s << "Burst Part Count: " << std::hex << (U32) data.mBurstPartCount << "\n";
+ s << "Angular Velocity: " << data.mAngularVelocity << "\n";
+ s << "Accel: " << data.mPartAccel;
+ return s;
+}
+
+bool LLPartSysData::isNullPS(const S32 block_num)
+{
+ U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE];
+ U32 crc;
+
+ S32 size;
+ // Check size of block
+ size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock");
+
+ if (!size)
+ {
+ return true;
+ }
+
+ if (size > PS_MAX_DATA_BLOCK_SIZE)
+ {
+ //size is too big, newer particle version unsupported
+ return true;
+ }
+
+ gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE);
+
+ LLDataPackerBinaryBuffer dp(ps_data_block, size);
+ if (size > PS_LEGACY_DATA_BLOCK_SIZE)
+ {
+ // non legacy systems pack a size before the CRC
+ S32 tmp = 0;
+ dp.unpackS32(tmp, "syssize");
+
+ if (tmp > PS_SYS_DATA_BLOCK_SIZE)
+ { //unknown system data block size, don't know how to parse it, treat as NULL
+ return true;
+ }
+ }
+
+ dp.unpackU32(crc, "crc");
+
+ if (crc == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool LLPartSysData::unpackBlock(const S32 block_num)
+{
+ U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE];
+
+ // Check size of block
+ S32 size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock");
+
+ if (size > PS_MAX_DATA_BLOCK_SIZE)
+ {
+ // Larger packets are newer and unsupported
+ return false;
+ }
+
+ // Get from message
+ gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE);
+
+ LLDataPackerBinaryBuffer dp(ps_data_block, size);
+
+ if (size == PS_LEGACY_DATA_BLOCK_SIZE)
+ {
+ return unpackLegacy(dp);
+ }
+ else
+ {
+ return unpack(dp);
+ }
+}
+
+bool LLPartSysData::isLegacyCompatible() const
+{
+ return !mPartData.hasGlow() && !mPartData.hasBlendFunc();
+}
+
+void LLPartSysData::clampSourceParticleRate()
+{
+ F32 particle_rate = 0;
+ particle_rate = mBurstPartCount/mBurstRate;
+ if (particle_rate > 256.f)
+ {
+ mBurstPartCount = llfloor(((F32)mBurstPartCount)*(256.f/particle_rate));
+ }
+}
+
+void LLPartSysData::setPartAccel(const LLVector3 &accel)
+{
+ mPartAccel.mV[VX] = llclamp(accel.mV[VX], -100.f, 100.f);
+ mPartAccel.mV[VY] = llclamp(accel.mV[VY], -100.f, 100.f);
+ mPartAccel.mV[VZ] = llclamp(accel.mV[VZ], -100.f, 100.f);
+}
diff --git a/indra/llmessage/llpartdata.h b/indra/llmessage/llpartdata.h index 35602dc949..70c425b0a5 100644 --- a/indra/llmessage/llpartdata.h +++ b/indra/llmessage/llpartdata.h @@ -1,279 +1,279 @@ -/** - * @file llpartdata.h - * @brief Particle system data packing - * - * $LicenseInfo:firstyear=2003&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$ - */ - -#ifndef LL_LLPARTDATA_H -#define LL_LLPARTDATA_H - -#include "lluuid.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v2math.h" -#include "v4color.h" - -class LLMessageSystem; -class LLDataPacker; - -const S32 PS_CUR_VERSION = 18; - -// -// These constants are used by the script code, not by the particle system itself -// - -enum LLPSScriptFlags -{ - // Flags for the different parameters of individual particles - LLPS_PART_FLAGS, - LLPS_PART_START_COLOR, - LLPS_PART_START_ALPHA, - LLPS_PART_END_COLOR, - LLPS_PART_END_ALPHA, - LLPS_PART_START_SCALE, - LLPS_PART_END_SCALE, - LLPS_PART_MAX_AGE, - - // Flags for the different parameters of the particle source - LLPS_SRC_ACCEL, - LLPS_SRC_PATTERN, - LLPS_SRC_INNERANGLE, - LLPS_SRC_OUTERANGLE, - LLPS_SRC_TEXTURE, - LLPS_SRC_BURST_RATE, - LLPS_SRC_BURST_DURATION, - LLPS_SRC_BURST_PART_COUNT, - LLPS_SRC_BURST_RADIUS, - LLPS_SRC_BURST_SPEED_MIN, - LLPS_SRC_BURST_SPEED_MAX, - LLPS_SRC_MAX_AGE, - LLPS_SRC_TARGET_UUID, - LLPS_SRC_OMEGA, - LLPS_SRC_ANGLE_BEGIN, - LLPS_SRC_ANGLE_END, - - LLPS_PART_BLEND_FUNC_SOURCE, - LLPS_PART_BLEND_FUNC_DEST, - LLPS_PART_START_GLOW, - LLPS_PART_END_GLOW -}; - - -class LLPartData -{ -public: - LLPartData() : - mFlags(0), - mMaxAge(0.f), - mParameter(0.f) - { - } - BOOL unpackLegacy(LLDataPacker &dp); - BOOL unpack(LLDataPacker &dp); - - BOOL pack(LLDataPacker &dp); - - bool hasGlow() const; - bool hasBlendFunc() const; - - // Masks for the different particle flags - enum - { - LL_PART_INTERP_COLOR_MASK = 0x01, - LL_PART_INTERP_SCALE_MASK = 0x02, - LL_PART_BOUNCE_MASK = 0x04, - LL_PART_WIND_MASK = 0x08, - LL_PART_FOLLOW_SRC_MASK = 0x10, // Follows source, no rotation following (expensive!) - LL_PART_FOLLOW_VELOCITY_MASK = 0x20, // Particles orient themselves with velocity - LL_PART_TARGET_POS_MASK = 0x40, - LL_PART_TARGET_LINEAR_MASK = 0x80, // Particle uses a direct linear interpolation - LL_PART_EMISSIVE_MASK = 0x100, // Particle is "emissive", instead of being lit - LL_PART_BEAM_MASK = 0x200, // Particle is a "beam" connecting source and target - LL_PART_RIBBON_MASK = 0x400, // Particles are joined together into one continuous triangle strip - - // Not implemented yet! - //LL_PART_RANDOM_ACCEL_MASK = 0x100, // Particles have random acceleration - //LL_PART_RANDOM_VEL_MASK = 0x200, // Particles have random velocity shifts" - //LL_PART_TRAIL_MASK = 0x400, // Particles have historical "trails" - - //sYSTEM SET FLAGS - LL_PART_DATA_GLOW = 0x10000, - LL_PART_DATA_BLEND = 0x20000, - - // Viewer side use only! - LL_PART_HUD = 0x40000000, - LL_PART_DEAD_MASK = 0x80000000, - }; - - enum - { - LL_PART_BF_ONE = 0, - LL_PART_BF_ZERO = 1, - LL_PART_BF_DEST_COLOR = 2, - LL_PART_BF_SOURCE_COLOR = 3, - LL_PART_BF_ONE_MINUS_DEST_COLOR = 4, - LL_PART_BF_ONE_MINUS_SOURCE_COLOR = 5, - UNSUPPORTED_DEST_ALPHA = 6, - LL_PART_BF_SOURCE_ALPHA = 7, - UNSUPPORTED_ONE_MINUS_DEST_ALPHA = 8, - LL_PART_BF_ONE_MINUS_SOURCE_ALPHA = 9, - LL_PART_BF_COUNT = 10 - }; - - static bool validBlendFunc(S32 func); - - void setFlags(const U32 flags); - void setMaxAge(const F32 max_age); - void setStartScale(const F32 xs, F32 ys); - void setEndScale(const F32 xs, F32 ys); - void setStartColor(const LLVector3 &rgb); - void setEndColor(const LLVector3 &rgb); - void setStartAlpha(const F32 alpha); - void setEndAlpha(const F32 alpha); - - - friend class LLPartSysData; - friend class LLViewerPartSourceScript; - -private: - S32 getSize() const; - - // These are public because I'm really lazy... -public: - U32 mFlags; // Particle state/interpolators in effect - F32 mMaxAge; // Maximum age of the particle - LLColor4 mStartColor; // Start color - LLColor4 mEndColor; // End color - LLVector2 mStartScale; // Start scale - LLVector2 mEndScale; // End scale - - LLVector3 mPosOffset; // Offset from source if using FOLLOW_SOURCE - F32 mParameter; // A single floating point parameter - - F32 mStartGlow; - F32 mEndGlow; - - U8 mBlendFuncSource; - U8 mBlendFuncDest; -}; - - -class LLPartSysData -{ -public: - LLPartSysData(); - - BOOL unpack(LLDataPacker &dp); - BOOL unpackLegacy(LLDataPacker &dp); - BOOL unpackBlock(const S32 block_num); - - static BOOL isNullPS(const S32 block_num); // Returns FALSE if this is a "NULL" particle system (i.e. no system) - - bool isLegacyCompatible() const; - - // Different masks for effects on the source - enum - { - LL_PART_SRC_OBJ_REL_MASK = 0x01, // Accel and velocity for particles relative object rotation - LL_PART_USE_NEW_ANGLE = 0x02, // Particles uses new 'correct' angle parameters. - }; - - // The different patterns for how particles are created - enum - { - LL_PART_SRC_PATTERN_DROP = 0x01, - LL_PART_SRC_PATTERN_EXPLODE = 0x02, - // Not implemented fully yet - LL_PART_SRC_PATTERN_ANGLE = 0x04, - LL_PART_SRC_PATTERN_ANGLE_CONE = 0x08, - LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY = 0x10, - }; - - - void setBurstSpeedMin(const F32 spd) { mBurstSpeedMin = llclamp(spd, -100.f, 100.f); } - void setBurstSpeedMax(const F32 spd) { mBurstSpeedMax = llclamp(spd, -100.f, 100.f); } - void setBurstRadius(const F32 rad) { mBurstRadius = llclamp(rad, 0.f, 50.f); } - void setPartAccel(const LLVector3 &accel); - void setUseNewAngle() { mFlags |= LL_PART_USE_NEW_ANGLE; } - void unsetUseNewAngle() { mFlags &= ~LL_PART_USE_NEW_ANGLE; } - - // Since the actual particle creation rate is - // a combination of multiple parameters, we - // need to clamp it using a separate method instead of an accessor. - void clampSourceParticleRate(); - - friend std::ostream& operator<<(std::ostream& s, const LLPartSysData &data); // Stream a - - S32 getdataBlockSize() const; - -private: - BOOL unpackSystem(LLDataPacker &dp); - -public: - // Public because I'm lazy.... - - // - // There are two kinds of data for the particle system - // 1. Parameters which specify parameters of the source (mSource*) - // 2. Parameters which specify parameters of the particles generated by the source (mPart*) - // - - U32 mCRC; - U32 mFlags; - - U8 mPattern; // Pattern for particle velocity/output - F32 mInnerAngle; // Inner angle for PATTERN_ANGLE - F32 mOuterAngle; // Outer angle for PATTERN_ANGLE - LLVector3 mAngularVelocity; // Angular velocity for emission axis (for PATTERN_ANGLE) - - F32 mBurstRate; // How often to do a burst of particles - U8 mBurstPartCount; // How many particles in a burst - F32 mBurstRadius; - F32 mBurstSpeedMin; // Minimum particle velocity - F32 mBurstSpeedMax; // Maximum particle velocity - - F32 mMaxAge; // Maximum lifetime of this particle source - - LLUUID mTargetUUID; // Target UUID for the particle system - - F32 mStartAge; // Age at which to start the particle system (for an update after the - // particle system has started) - - - // - // These are actually particle properties, but can be mutated by the source, - // so are stored here instead - // - LLVector3 mPartAccel; - LLUUID mPartImageID; - - // - // The "template" partdata where we actually store the non-mutable particle parameters - // - LLPartData mPartData; - -protected: - S32 mNumParticles; // Number of particles generated -}; - -#endif // LL_LLPARTDATA_H +/**
+ * @file llpartdata.h
+ * @brief Particle system data packing
+ *
+ * $LicenseInfo:firstyear=2003&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$
+ */
+
+#ifndef LL_LLPARTDATA_H
+#define LL_LLPARTDATA_H
+
+#include "lluuid.h"
+#include "v3math.h"
+#include "v3dmath.h"
+#include "v2math.h"
+#include "v4color.h"
+
+class LLMessageSystem;
+class LLDataPacker;
+
+const S32 PS_CUR_VERSION = 18;
+
+//
+// These constants are used by the script code, not by the particle system itself
+//
+
+enum LLPSScriptFlags
+{
+ // Flags for the different parameters of individual particles
+ LLPS_PART_FLAGS,
+ LLPS_PART_START_COLOR,
+ LLPS_PART_START_ALPHA,
+ LLPS_PART_END_COLOR,
+ LLPS_PART_END_ALPHA,
+ LLPS_PART_START_SCALE,
+ LLPS_PART_END_SCALE,
+ LLPS_PART_MAX_AGE,
+
+ // Flags for the different parameters of the particle source
+ LLPS_SRC_ACCEL,
+ LLPS_SRC_PATTERN,
+ LLPS_SRC_INNERANGLE,
+ LLPS_SRC_OUTERANGLE,
+ LLPS_SRC_TEXTURE,
+ LLPS_SRC_BURST_RATE,
+ LLPS_SRC_BURST_DURATION,
+ LLPS_SRC_BURST_PART_COUNT,
+ LLPS_SRC_BURST_RADIUS,
+ LLPS_SRC_BURST_SPEED_MIN,
+ LLPS_SRC_BURST_SPEED_MAX,
+ LLPS_SRC_MAX_AGE,
+ LLPS_SRC_TARGET_UUID,
+ LLPS_SRC_OMEGA,
+ LLPS_SRC_ANGLE_BEGIN,
+ LLPS_SRC_ANGLE_END,
+
+ LLPS_PART_BLEND_FUNC_SOURCE,
+ LLPS_PART_BLEND_FUNC_DEST,
+ LLPS_PART_START_GLOW,
+ LLPS_PART_END_GLOW
+};
+
+
+class LLPartData
+{
+public:
+ LLPartData() :
+ mFlags(0),
+ mMaxAge(0.f),
+ mParameter(0.f)
+ {
+ }
+ bool unpackLegacy(LLDataPacker &dp);
+ bool unpack(LLDataPacker &dp);
+
+ bool pack(LLDataPacker &dp);
+
+ bool hasGlow() const;
+ bool hasBlendFunc() const;
+
+ // Masks for the different particle flags
+ enum
+ {
+ LL_PART_INTERP_COLOR_MASK = 0x01,
+ LL_PART_INTERP_SCALE_MASK = 0x02,
+ LL_PART_BOUNCE_MASK = 0x04,
+ LL_PART_WIND_MASK = 0x08,
+ LL_PART_FOLLOW_SRC_MASK = 0x10, // Follows source, no rotation following (expensive!)
+ LL_PART_FOLLOW_VELOCITY_MASK = 0x20, // Particles orient themselves with velocity
+ LL_PART_TARGET_POS_MASK = 0x40,
+ LL_PART_TARGET_LINEAR_MASK = 0x80, // Particle uses a direct linear interpolation
+ LL_PART_EMISSIVE_MASK = 0x100, // Particle is "emissive", instead of being lit
+ LL_PART_BEAM_MASK = 0x200, // Particle is a "beam" connecting source and target
+ LL_PART_RIBBON_MASK = 0x400, // Particles are joined together into one continuous triangle strip
+
+ // Not implemented yet!
+ //LL_PART_RANDOM_ACCEL_MASK = 0x100, // Particles have random acceleration
+ //LL_PART_RANDOM_VEL_MASK = 0x200, // Particles have random velocity shifts"
+ //LL_PART_TRAIL_MASK = 0x400, // Particles have historical "trails"
+
+ //sYSTEM SET FLAGS
+ LL_PART_DATA_GLOW = 0x10000,
+ LL_PART_DATA_BLEND = 0x20000,
+
+ // Viewer side use only!
+ LL_PART_HUD = 0x40000000,
+ LL_PART_DEAD_MASK = 0x80000000,
+ };
+
+ enum
+ {
+ LL_PART_BF_ONE = 0,
+ LL_PART_BF_ZERO = 1,
+ LL_PART_BF_DEST_COLOR = 2,
+ LL_PART_BF_SOURCE_COLOR = 3,
+ LL_PART_BF_ONE_MINUS_DEST_COLOR = 4,
+ LL_PART_BF_ONE_MINUS_SOURCE_COLOR = 5,
+ UNSUPPORTED_DEST_ALPHA = 6,
+ LL_PART_BF_SOURCE_ALPHA = 7,
+ UNSUPPORTED_ONE_MINUS_DEST_ALPHA = 8,
+ LL_PART_BF_ONE_MINUS_SOURCE_ALPHA = 9,
+ LL_PART_BF_COUNT = 10
+ };
+
+ static bool validBlendFunc(S32 func);
+
+ void setFlags(const U32 flags);
+ void setMaxAge(const F32 max_age);
+ void setStartScale(const F32 xs, F32 ys);
+ void setEndScale(const F32 xs, F32 ys);
+ void setStartColor(const LLVector3 &rgb);
+ void setEndColor(const LLVector3 &rgb);
+ void setStartAlpha(const F32 alpha);
+ void setEndAlpha(const F32 alpha);
+
+
+ friend class LLPartSysData;
+ friend class LLViewerPartSourceScript;
+
+private:
+ S32 getSize() const;
+
+ // These are public because I'm really lazy...
+public:
+ U32 mFlags; // Particle state/interpolators in effect
+ F32 mMaxAge; // Maximum age of the particle
+ LLColor4 mStartColor; // Start color
+ LLColor4 mEndColor; // End color
+ LLVector2 mStartScale; // Start scale
+ LLVector2 mEndScale; // End scale
+
+ LLVector3 mPosOffset; // Offset from source if using FOLLOW_SOURCE
+ F32 mParameter; // A single floating point parameter
+
+ F32 mStartGlow;
+ F32 mEndGlow;
+
+ U8 mBlendFuncSource;
+ U8 mBlendFuncDest;
+};
+
+
+class LLPartSysData
+{
+public:
+ LLPartSysData();
+
+ bool unpack(LLDataPacker &dp);
+ bool unpackLegacy(LLDataPacker &dp);
+ bool unpackBlock(const S32 block_num);
+
+ static bool isNullPS(const S32 block_num); // Returns false if this is a "NULL" particle system (i.e. no system)
+
+ bool isLegacyCompatible() const;
+
+ // Different masks for effects on the source
+ enum
+ {
+ LL_PART_SRC_OBJ_REL_MASK = 0x01, // Accel and velocity for particles relative object rotation
+ LL_PART_USE_NEW_ANGLE = 0x02, // Particles uses new 'correct' angle parameters.
+ };
+
+ // The different patterns for how particles are created
+ enum
+ {
+ LL_PART_SRC_PATTERN_DROP = 0x01,
+ LL_PART_SRC_PATTERN_EXPLODE = 0x02,
+ // Not implemented fully yet
+ LL_PART_SRC_PATTERN_ANGLE = 0x04,
+ LL_PART_SRC_PATTERN_ANGLE_CONE = 0x08,
+ LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY = 0x10,
+ };
+
+
+ void setBurstSpeedMin(const F32 spd) { mBurstSpeedMin = llclamp(spd, -100.f, 100.f); }
+ void setBurstSpeedMax(const F32 spd) { mBurstSpeedMax = llclamp(spd, -100.f, 100.f); }
+ void setBurstRadius(const F32 rad) { mBurstRadius = llclamp(rad, 0.f, 50.f); }
+ void setPartAccel(const LLVector3 &accel);
+ void setUseNewAngle() { mFlags |= LL_PART_USE_NEW_ANGLE; }
+ void unsetUseNewAngle() { mFlags &= ~LL_PART_USE_NEW_ANGLE; }
+
+ // Since the actual particle creation rate is
+ // a combination of multiple parameters, we
+ // need to clamp it using a separate method instead of an accessor.
+ void clampSourceParticleRate();
+
+ friend std::ostream& operator<<(std::ostream& s, const LLPartSysData &data); // Stream a
+
+ S32 getdataBlockSize() const;
+
+private:
+ bool unpackSystem(LLDataPacker &dp);
+
+public:
+ // Public because I'm lazy....
+
+ //
+ // There are two kinds of data for the particle system
+ // 1. Parameters which specify parameters of the source (mSource*)
+ // 2. Parameters which specify parameters of the particles generated by the source (mPart*)
+ //
+
+ U32 mCRC;
+ U32 mFlags;
+
+ U8 mPattern; // Pattern for particle velocity/output
+ F32 mInnerAngle; // Inner angle for PATTERN_ANGLE
+ F32 mOuterAngle; // Outer angle for PATTERN_ANGLE
+ LLVector3 mAngularVelocity; // Angular velocity for emission axis (for PATTERN_ANGLE)
+
+ F32 mBurstRate; // How often to do a burst of particles
+ U8 mBurstPartCount; // How many particles in a burst
+ F32 mBurstRadius;
+ F32 mBurstSpeedMin; // Minimum particle velocity
+ F32 mBurstSpeedMax; // Maximum particle velocity
+
+ F32 mMaxAge; // Maximum lifetime of this particle source
+
+ LLUUID mTargetUUID; // Target UUID for the particle system
+
+ F32 mStartAge; // Age at which to start the particle system (for an update after the
+ // particle system has started)
+
+
+ //
+ // These are actually particle properties, but can be mutated by the source,
+ // so are stored here instead
+ //
+ LLVector3 mPartAccel;
+ LLUUID mPartImageID;
+
+ //
+ // The "template" partdata where we actually store the non-mutable particle parameters
+ //
+ LLPartData mPartData;
+
+protected:
+ S32 mNumParticles; // Number of particles generated
+};
+
+#endif // LL_LLPARTDATA_H
diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index ec0d7fe4e4..646f8aa2ca 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -1,1146 +1,1150 @@ -/** - * @file llpumpio.cpp - * @author Phoenix - * @date 2004-11-21 - * @brief Implementation of the i/o pump and related functions. - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#include "linden_common.h" -#include "llpumpio.h" - -#include <map> -#include <set> -#include "apr_poll.h" - -#include "llapr.h" -#include "llfasttimer.h" -#include "llstl.h" - -// These should not be enabled in production, but they can be -// intensely useful during development for finding certain kinds of -// bugs. -#if LL_LINUX -//#define LL_DEBUG_PIPE_TYPE_IN_PUMP 1 -//#define LL_DEBUG_POLL_FILE_DESCRIPTORS 1 -#if LL_DEBUG_POLL_FILE_DESCRIPTORS -#include "apr_portable.h" -#endif -#endif - -#if LL_DEBUG_PIPE_TYPE_IN_PUMP -#include <typeinfo> -#endif - -// constants for poll timeout. if we are threading, we want to have a -// longer poll timeout. -static const S32 DEFAULT_POLL_TIMEOUT = 0; - -// The default (and fallback) expiration time for chains -const F32 DEFAULT_CHAIN_EXPIRY_SECS = 30.0f; -extern const F32 SHORT_CHAIN_EXPIRY_SECS = 1.0f; -extern const F32 NEVER_CHAIN_EXPIRY_SECS = 0.0f; - -// sorta spammy debug modes. -//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_IN_ON_ERROR 1 -//#define LL_DEBUG_PROCESS_LINK 1 -//#define LL_DEBUG_PROCESS_RETURN_VALUE 1 - -// Super spammy debug mode. -//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_IN 1 -//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT 1 - -// -// local functions -// -void ll_debug_poll_fd(const char* msg, const apr_pollfd_t* poll) -{ -#if LL_DEBUG_POLL_FILE_DESCRIPTORS - if(!poll) - { - LL_DEBUGS() << "Poll -- " << (msg?msg:"") << ": no pollfd." << LL_ENDL; - return; - } - if(poll->desc.s) - { - apr_os_sock_t os_sock; - if(APR_SUCCESS == apr_os_sock_get(&os_sock, poll->desc.s)) - { - LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " on fd " << os_sock - << " at " << poll->desc.s << LL_ENDL; - } - else - { - LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " no fd " - << " at " << poll->desc.s << LL_ENDL; - } - } - else if(poll->desc.f) - { - apr_os_file_t os_file; - if(APR_SUCCESS == apr_os_file_get(&os_file, poll->desc.f)) - { - LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " on fd " << os_file - << " at " << poll->desc.f << LL_ENDL; - } - else - { - LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " no fd " - << " at " << poll->desc.f << LL_ENDL; - } - } - else - { - LL_DEBUGS() << "Poll -- " << (msg?msg:"") << ": no descriptor." << LL_ENDL; - } -#endif -} - -/** - * @class - */ -class LLChainSleeper : public LLRunnable -{ -public: - static LLRunner::run_ptr_t build(LLPumpIO* pump, S32 key) - { - return LLRunner::run_ptr_t(new LLChainSleeper(pump, key)); - } - - virtual void run(LLRunner* runner, S64 handle) - { - mPump->clearLock(mKey); - } - -protected: - LLChainSleeper(LLPumpIO* pump, S32 key) : mPump(pump), mKey(key) {} - LLPumpIO* mPump; - S32 mKey; -}; - - -/** - * @struct ll_delete_apr_pollset_fd_client_data - * @brief This is a simple helper class to clean up our client data. - */ -struct ll_delete_apr_pollset_fd_client_data -{ - typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t; - void operator()(const pipe_conditional_t& conditional) - { - S32* client_id = (S32*)conditional.second.client_data; - delete client_id; - } -}; - -/** - * LLPumpIO - */ -LLPumpIO::LLPumpIO(apr_pool_t* pool) : - mState(LLPumpIO::NORMAL), - mRebuildPollset(false), - mPollset(NULL), - mPollsetClientID(0), - mNextLock(0), - mPool(NULL), - mCurrentPool(NULL), - mCurrentPoolReallocCount(0), - mCurrentChain(mRunningChains.end()) -{ - mCurrentChain = mRunningChains.end(); - - initialize(pool); -} - -LLPumpIO::~LLPumpIO() -{ - cleanup(); -} - -bool LLPumpIO::prime(apr_pool_t* pool) -{ - cleanup(); - initialize(pool); - return ((pool == NULL) ? false : true); -} - -bool LLPumpIO::addChain(const chain_t& chain, F32 timeout, bool has_curl_request) -{ - if(chain.empty()) return false; - - LLChainInfo info; - info.mHasCurlRequest = has_curl_request; - info.setTimeoutSeconds(timeout); - info.mData = LLIOPipe::buffer_ptr_t(new LLBufferArray); - info.mData->setThreaded(has_curl_request); - LLLinkInfo link; -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - LL_DEBUGS() << "LLPumpIO::addChain() " << chain[0] << " '" - << typeid(*(chain[0])).name() << "'" << LL_ENDL; -#else - LL_DEBUGS() << "LLPumpIO::addChain() " << chain[0] <<LL_ENDL; -#endif - chain_t::const_iterator it = chain.begin(); - chain_t::const_iterator end = chain.end(); - for(; it != end; ++it) - { - link.mPipe = (*it); - link.mChannels = info.mData->nextChannel(); - info.mChainLinks.push_back(link); - } - mPendingChains.push_back(info); - return true; -} - -bool LLPumpIO::addChain( - const LLPumpIO::links_t& links, - LLIOPipe::buffer_ptr_t data, - LLSD context, - F32 timeout) -{ - - // remember that if the caller is providing a full link - // description, we need to have that description matched to a - // particular buffer. - if(!data) return false; - if(links.empty()) return false; - -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - LL_DEBUGS() << "LLPumpIO::addChain() " << links[0].mPipe << " '" - << typeid(*(links[0].mPipe)).name() << "'" << LL_ENDL; -#else - LL_DEBUGS() << "LLPumpIO::addChain() " << links[0].mPipe << LL_ENDL; -#endif - LLChainInfo info; - info.setTimeoutSeconds(timeout); - info.mChainLinks = links; - info.mData = data; - info.mContext = context; - mPendingChains.push_back(info); - return true; -} - -bool LLPumpIO::setTimeoutSeconds(F32 timeout) -{ - // If no chain is running, return failure. - if(mRunningChains.end() == mCurrentChain) - { - return false; - } - (*mCurrentChain).setTimeoutSeconds(timeout); - return true; -} - -void LLPumpIO::adjustTimeoutSeconds(F32 delta) -{ - // Ensure a chain is running - if(mRunningChains.end() != mCurrentChain) - { - (*mCurrentChain).adjustTimeoutSeconds(delta); - } -} - -static std::string events_2_string(apr_int16_t events) -{ - std::ostringstream ostr; - if(events & APR_POLLIN) - { - ostr << "read,"; - } - if(events & APR_POLLPRI) - { - ostr << "priority,"; - } - if(events & APR_POLLOUT) - { - ostr << "write,"; - } - if(events & APR_POLLERR) - { - ostr << "error,"; - } - if(events & APR_POLLHUP) - { - ostr << "hangup,"; - } - if(events & APR_POLLNVAL) - { - ostr << "invalid,"; - } - return chop_tail_copy(ostr.str(), 1); -} - -bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll) -{ - if(!pipe) return false; - ll_debug_poll_fd("Set conditional", poll); - - LL_DEBUGS() << "Setting conditionals (" << (poll ? events_2_string(poll->reqevents) :"null") - << ") " -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - << "on pipe " << typeid(*pipe).name() -#endif - << " at " << pipe << LL_ENDL; - - // remove any matching poll file descriptors for this pipe. - LLIOPipe::ptr_t pipe_ptr(pipe); - LLChainInfo::conditionals_t::iterator it; - it = (*mCurrentChain).mDescriptors.begin(); - while(it != (*mCurrentChain).mDescriptors.end()) - { - LLChainInfo::pipe_conditional_t& value = (*it); - if(pipe_ptr == value.first) - { - ll_delete_apr_pollset_fd_client_data()(value); - it = (*mCurrentChain).mDescriptors.erase(it); - mRebuildPollset = true; - } - else - { - ++it; - } - } - - if(!poll) - { - mRebuildPollset = true; - return true; - } - LLChainInfo::pipe_conditional_t value; - value.first = pipe_ptr; - value.second = *poll; - value.second.rtnevents = 0; - if(!poll->p) - { - // each fd needs a pool to work with, so if one was - // not specified, use this pool. - // *FIX: Should it always be this pool? - value.second.p = mPool; - } - value.second.client_data = new S32(++mPollsetClientID); - (*mCurrentChain).mDescriptors.push_back(value); - mRebuildPollset = true; - return true; -} - -S32 LLPumpIO::setLock() -{ - // *NOTE: I do not think it is necessary to acquire a mutex here - // since this should only be called during the pump(), and should - // only change the running chain. Any other use of this method is - // incorrect usage. If it becomes necessary to acquire a lock - // here, be sure to lock here and call a protected method to get - // the lock, and sleepChain() should probably acquire the same - // lock while and calling the same protected implementation to - // lock the runner at the same time. - - // If no chain is running, return failure. - if(mRunningChains.end() == mCurrentChain) - { - return 0; - } - - // deal with wrap. - if(++mNextLock <= 0) - { - mNextLock = 1; - } - - // set the lock - (*mCurrentChain).mLock = mNextLock; - return mNextLock; -} - -void LLPumpIO::clearLock(S32 key) -{ - // We need to lock it here since we do not want to be iterating - // over the chains twice. We can safely call process() while this - // is happening since we should not be erasing a locked pipe, and - // therefore won't be treading into deleted memory. I think we can - // also clear the lock on the chain safely since the pump only - // reads that value. - mClearLocks.insert(key); -} - -bool LLPumpIO::sleepChain(F64 seconds) -{ - // Much like the call to setLock(), this should only be called - // from one chain during processing, so there is no need to - // acquire a mutex. - if(seconds <= 0.0) return false; - S32 key = setLock(); - if(!key) return false; - LLRunner::run_handle_t handle = mRunner.addRunnable( - LLChainSleeper::build(this, key), - LLRunner::RUN_IN, - seconds); - if(0 == handle) return false; - return true; -} - -bool LLPumpIO::copyCurrentLinkInfo(links_t& links) const -{ - if(mRunningChains.end() == mCurrentChain) - { - return false; - } - std::copy( - (*mCurrentChain).mChainLinks.begin(), - (*mCurrentChain).mChainLinks.end(), - std::back_insert_iterator<links_t>(links)); - return true; -} - -void LLPumpIO::pump() -{ - pump(DEFAULT_POLL_TIMEOUT); -} - -LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain) -{ - std::for_each( - (*run_chain).mDescriptors.begin(), - (*run_chain).mDescriptors.end(), - ll_delete_apr_pollset_fd_client_data()); - return mRunningChains.erase(run_chain); -} - -//timeout is in microseconds -void LLPumpIO::pump(const S32& poll_timeout) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - //LL_INFOS() << "LLPumpIO::pump()" << LL_ENDL; - - // Run any pending runners. - mRunner.run(); - - // We need to move all of the pending heads over to the running - // chains. - PUMP_DEBUG; - if(true) - { - // bail if this pump is paused. - if(PAUSING == mState) - { - mState = PAUSED; - } - if(PAUSED == mState) - { - return; - } - - PUMP_DEBUG; - // Move the pending chains over to the running chaings - if(!mPendingChains.empty()) - { - PUMP_DEBUG; - //LL_DEBUGS() << "Pushing " << mPendingChains.size() << "." << LL_ENDL; - std::copy( - mPendingChains.begin(), - mPendingChains.end(), - std::back_insert_iterator<running_chains_t>(mRunningChains)); - mPendingChains.clear(); - PUMP_DEBUG; - } - - // Clear any locks. This needs to be done here so that we do - // not clash during a call to clearLock(). - if(!mClearLocks.empty()) - { - PUMP_DEBUG; - running_chains_t::iterator it = mRunningChains.begin(); - running_chains_t::iterator end = mRunningChains.end(); - std::set<S32>::iterator not_cleared = mClearLocks.end(); - for(; it != end; ++it) - { - if((*it).mLock && mClearLocks.find((*it).mLock) != not_cleared) - { - (*it).mLock = 0; - } - } - PUMP_DEBUG; - mClearLocks.clear(); - } - } - - PUMP_DEBUG; - // rebuild the pollset if necessary - if(mRebuildPollset) - { - PUMP_DEBUG; - rebuildPollset(); - mRebuildPollset = false; - } - - // Poll based on the last known pollset - // *TODO: may want to pass in a poll timeout so it works correctly - // in single and multi threaded processes. - PUMP_DEBUG; - typedef std::map<S32, S32> signal_client_t; - signal_client_t signalled_client; - const apr_pollfd_t* poll_fd = NULL; - if(mPollset) - { - PUMP_DEBUG; - //LL_INFOS() << "polling" << LL_ENDL; - S32 count = 0; - S32 client_id = 0; - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd); - } - PUMP_DEBUG; - for(S32 ii = 0; ii < count; ++ii) - { - ll_debug_poll_fd("Signalled pipe", &poll_fd[ii]); - client_id = *((S32*)poll_fd[ii].client_data); - signalled_client[client_id] = ii; - } - PUMP_DEBUG; - } - - PUMP_DEBUG; - // set up for a check to see if each one was signalled - signal_client_t::iterator not_signalled = signalled_client.end(); - - // Process everything as appropriate - //LL_DEBUGS() << "Running chain count: " << mRunningChains.size() << LL_ENDL; - running_chains_t::iterator run_chain = mRunningChains.begin(); - bool process_this_chain = false; - while( run_chain != mRunningChains.end() ) - { - PUMP_DEBUG; - if((*run_chain).mInit - && (*run_chain).mTimer.getStarted() - && (*run_chain).mTimer.hasExpired()) - { - PUMP_DEBUG; - if(handleChainError(*run_chain, LLIOPipe::STATUS_EXPIRED)) - { - // the pipe probably handled the error. If the handler - // forgot to reset the expiration then we need to do - // that here. - if((*run_chain).mTimer.getStarted() - && (*run_chain).mTimer.hasExpired()) - { - PUMP_DEBUG; - LL_INFOS() << "Error handler forgot to reset timeout. " - << "Resetting to " << DEFAULT_CHAIN_EXPIRY_SECS - << " seconds." << LL_ENDL; - (*run_chain).setTimeoutSeconds(DEFAULT_CHAIN_EXPIRY_SECS); - } - } - else - { - PUMP_DEBUG; - // it timed out and no one handled it, so we need to - // retire the chain -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - LL_DEBUGS() << "Removing chain " - << (*run_chain).mChainLinks[0].mPipe - << " '" - << typeid(*((*run_chain).mChainLinks[0].mPipe)).name() - << "' because it timed out." << LL_ENDL; -#else -// LL_DEBUGS() << "Removing chain " -// << (*run_chain).mChainLinks[0].mPipe -// << " because we reached the end." << LL_ENDL; -#endif - run_chain = removeRunningChain(run_chain); - continue; - } - } - else if(isChainExpired(*run_chain)) - { - run_chain = removeRunningChain(run_chain); - continue; - } - - PUMP_DEBUG; - if((*run_chain).mLock) - { - ++run_chain; - continue; - } - PUMP_DEBUG; - mCurrentChain = run_chain; - - if((*run_chain).mDescriptors.empty()) - { - // if there are no conditionals, just process this chain. - process_this_chain = true; - //LL_DEBUGS() << "no conditionals - processing" << LL_ENDL; - } - else - { - PUMP_DEBUG; - //LL_DEBUGS() << "checking conditionals" << LL_ENDL; - // Check if this run chain was signalled. If any file - // descriptor is ready for something, then go ahead and - // process this chian. - process_this_chain = false; - if(!signalled_client.empty()) - { - PUMP_DEBUG; - LLChainInfo::conditionals_t::iterator it; - it = (*run_chain).mDescriptors.begin(); - LLChainInfo::conditionals_t::iterator end; - end = (*run_chain).mDescriptors.end(); - S32 client_id = 0; - signal_client_t::iterator signal; - for(; it != end; ++it) - { - PUMP_DEBUG; - client_id = *((S32*)((*it).second.client_data)); - signal = signalled_client.find(client_id); - if (signal == not_signalled) continue; - static const apr_int16_t POLL_CHAIN_ERROR = - APR_POLLHUP | APR_POLLNVAL | APR_POLLERR; - const apr_pollfd_t* poll = &(poll_fd[(*signal).second]); - if(poll->rtnevents & POLL_CHAIN_ERROR) - { - // Potential eror condition has been - // returned. If HUP was one of them, we pass - // that as the error even though there may be - // more. If there are in fact more errors, - // we'll just wait for that detection until - // the next pump() cycle to catch it so that - // the logic here gets no more strained than - // it already is. - LLIOPipe::EStatus error_status; - if(poll->rtnevents & APR_POLLHUP) - error_status = LLIOPipe::STATUS_LOST_CONNECTION; - else - error_status = LLIOPipe::STATUS_ERROR; - if(handleChainError(*run_chain, error_status)) break; - ll_debug_poll_fd("Removing pipe", poll); - LL_WARNS() << "Removing pipe " - << (*run_chain).mChainLinks[0].mPipe - << " '" -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - << typeid( - *((*run_chain).mChainLinks[0].mPipe)).name() -#endif - << "' because: " - << events_2_string(poll->rtnevents) - << LL_ENDL; - (*run_chain).mHead = (*run_chain).mChainLinks.end(); - break; - } - - // at least 1 fd got signalled, and there were no - // errors. That means we process this chain. - process_this_chain = true; - break; - } - } - } - if(process_this_chain) - { - PUMP_DEBUG; - if(!((*run_chain).mInit)) - { - (*run_chain).mHead = (*run_chain).mChainLinks.begin(); - (*run_chain).mInit = true; - } - PUMP_DEBUG; - processChain(*run_chain); - } - - PUMP_DEBUG; - if((*run_chain).mHead == (*run_chain).mChainLinks.end()) - { -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - LL_DEBUGS() << "Removing chain " << (*run_chain).mChainLinks[0].mPipe - << " '" - << typeid(*((*run_chain).mChainLinks[0].mPipe)).name() - << "' because we reached the end." << LL_ENDL; -#else -// LL_DEBUGS() << "Removing chain " << (*run_chain).mChainLinks[0].mPipe -// << " because we reached the end." << LL_ENDL; -#endif - - PUMP_DEBUG; - // This chain is done. Clean up any allocated memory and - // erase the chain info. - run_chain = removeRunningChain(run_chain); - - // *NOTE: may not always need to rebuild the pollset. - mRebuildPollset = true; - } - else - { - PUMP_DEBUG; - // this chain needs more processing - just go to the next - // chain. - ++run_chain; - } - } - - PUMP_DEBUG; - // null out the chain - mCurrentChain = mRunningChains.end(); - END_PUMP_DEBUG; -} - -bool LLPumpIO::respond(LLIOPipe* pipe) -{ - if(NULL == pipe) return false; - - LLChainInfo info; - LLLinkInfo link; - link.mPipe = pipe; - info.mChainLinks.push_back(link); - mPendingCallbacks.push_back(info); - return true; -} - -bool LLPumpIO::respond( - const links_t& links, - LLIOPipe::buffer_ptr_t data, - LLSD context) -{ - // if the caller is providing a full link description, we need to - // have that description matched to a particular buffer. - if(!data) return false; - if(links.empty()) return false; - - // Add the callback response - LLChainInfo info; - info.mChainLinks = links; - info.mData = data; - info.mContext = context; - mPendingCallbacks.push_back(info); - return true; -} - -void LLPumpIO::callback() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - //LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL; - if(true) - { - std::copy( - mPendingCallbacks.begin(), - mPendingCallbacks.end(), - std::back_insert_iterator<callbacks_t>(mCallbacks)); - mPendingCallbacks.clear(); - } - if(!mCallbacks.empty()) - { - callbacks_t::iterator it = mCallbacks.begin(); - callbacks_t::iterator end = mCallbacks.end(); - for(; it != end; ++it) - { - // it's always the first and last time for respone chains - (*it).mHead = (*it).mChainLinks.begin(); - (*it).mInit = true; - (*it).mEOS = true; - processChain(*it); - } - mCallbacks.clear(); - } -} - -void LLPumpIO::control(LLPumpIO::EControl op) -{ - switch(op) - { - case PAUSE: - mState = PAUSING; - break; - case RESUME: - mState = NORMAL; - break; - default: - // no-op - break; - } -} - -void LLPumpIO::initialize(apr_pool_t* pool) -{ - if(!pool) return; - mPool = pool; -} - -void LLPumpIO::cleanup() -{ - if(mPollset) - { -// LL_DEBUGS() << "cleaning up pollset" << LL_ENDL; - apr_pollset_destroy(mPollset); - mPollset = NULL; - } - if(mCurrentPool) - { - apr_pool_destroy(mCurrentPool); - mCurrentPool = NULL; - } - mPool = NULL; -} - -void LLPumpIO::rebuildPollset() -{ -// LL_DEBUGS() << "LLPumpIO::rebuildPollset()" << LL_ENDL; - if(mPollset) - { - //LL_DEBUGS() << "destroying pollset" << LL_ENDL; - apr_pollset_destroy(mPollset); - mPollset = NULL; - } - U32 size = 0; - running_chains_t::iterator run_it = mRunningChains.begin(); - running_chains_t::iterator run_end = mRunningChains.end(); - for(; run_it != run_end; ++run_it) - { - size += (*run_it).mDescriptors.size(); - } - //LL_DEBUGS() << "found " << size << " descriptors." << LL_ENDL; - if(size) - { - // Recycle the memory pool - const S32 POLLSET_POOL_RECYCLE_COUNT = 100; - if(mCurrentPool - && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT))) - { - apr_pool_destroy(mCurrentPool); - mCurrentPool = NULL; - mCurrentPoolReallocCount = 0; - } - if(!mCurrentPool) - { - apr_status_t status = apr_pool_create(&mCurrentPool, mPool); - (void)ll_apr_warn_status(status); - } - - // add all of the file descriptors - run_it = mRunningChains.begin(); - LLChainInfo::conditionals_t::iterator fd_it; - LLChainInfo::conditionals_t::iterator fd_end; - apr_pollset_create(&mPollset, size, mCurrentPool, 0); - for(; run_it != run_end; ++run_it) - { - fd_it = (*run_it).mDescriptors.begin(); - fd_end = (*run_it).mDescriptors.end(); - for(; fd_it != fd_end; ++fd_it) - { - apr_pollset_add(mPollset, &((*fd_it).second)); - } - } - } -} - -void LLPumpIO::processChain(LLChainInfo& chain) -{ - PUMP_DEBUG; - LLIOPipe::EStatus status = LLIOPipe::STATUS_OK; - links_t::iterator it = chain.mHead; - links_t::iterator end = chain.mChainLinks.end(); - bool need_process_signaled = false; - bool keep_going = true; - do - { -#if LL_DEBUG_PROCESS_LINK -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - LL_INFOS() << "Processing " << typeid(*((*it).mPipe)).name() << "." - << LL_ENDL; -#else - LL_INFOS() << "Processing link " << (*it).mPipe << "." << LL_ENDL; -#endif -#endif -#if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN - if(chain.mData) - { - char* buf = NULL; - S32 bytes = chain.mData->countAfter((*it).mChannels.in(), NULL); - if(bytes) - { - buf = new char[bytes + 1]; - chain.mData->readAfter( - (*it).mChannels.in(), - NULL, - (U8*)buf, - bytes); - buf[bytes] = '\0'; - LL_INFOS() << "CHANNEL IN(" << (*it).mChannels.in() << "): " - << buf << LL_ENDL; - delete[] buf; - buf = NULL; - } - else - { - LL_INFOS() << "CHANNEL IN(" << (*it).mChannels.in()<< "): (null)" - << LL_ENDL; - } - } -#endif - PUMP_DEBUG; - status = (*it).mPipe->process( - (*it).mChannels, - chain.mData, - chain.mEOS, - chain.mContext, - this); -#if LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT - if(chain.mData) - { - char* buf = NULL; - S32 bytes = chain.mData->countAfter((*it).mChannels.out(), NULL); - if(bytes) - { - buf = new char[bytes + 1]; - chain.mData->readAfter( - (*it).mChannels.out(), - NULL, - (U8*)buf, - bytes); - buf[bytes] = '\0'; - LL_INFOS() << "CHANNEL OUT(" << (*it).mChannels.out()<< "): " - << buf << LL_ENDL; - delete[] buf; - buf = NULL; - } - else - { - LL_INFOS() << "CHANNEL OUT(" << (*it).mChannels.out()<< "): (null)" - << LL_ENDL; - } - } -#endif - -#if LL_DEBUG_PROCESS_RETURN_VALUE - // Only bother with the success codes - error codes are logged - // below. - if(LLIOPipe::isSuccess(status)) - { - LL_INFOS() << "Pipe returned: '" -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - << typeid(*((*it).mPipe)).name() << "':'" -#endif - << LLIOPipe::lookupStatusString(status) << "'" << LL_ENDL; - } -#endif - - PUMP_DEBUG; - switch(status) - { - case LLIOPipe::STATUS_OK: - // no-op - break; - case LLIOPipe::STATUS_STOP: - PUMP_DEBUG; - status = LLIOPipe::STATUS_OK; - chain.mHead = end; - keep_going = false; - break; - case LLIOPipe::STATUS_DONE: - PUMP_DEBUG; - status = LLIOPipe::STATUS_OK; - chain.mHead = (it + 1); - chain.mEOS = true; - break; - case LLIOPipe::STATUS_BREAK: - PUMP_DEBUG; - status = LLIOPipe::STATUS_OK; - keep_going = false; - break; - case LLIOPipe::STATUS_NEED_PROCESS: - PUMP_DEBUG; - status = LLIOPipe::STATUS_OK; - if(!need_process_signaled) - { - need_process_signaled = true; - chain.mHead = it; - } - break; - default: - PUMP_DEBUG; - if(LLIOPipe::isError(status)) - { - LL_INFOS() << "Pump generated pipe err: '" -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - << typeid(*((*it).mPipe)).name() << "':'" -#endif - << LLIOPipe::lookupStatusString(status) - << "'" << LL_ENDL; -#if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN_ON_ERROR - if(chain.mData) - { - char* buf = NULL; - S32 bytes = chain.mData->countAfter( - (*it).mChannels.in(), - NULL); - if(bytes) - { - buf = new char[bytes + 1]; - chain.mData->readAfter( - (*it).mChannels.in(), - NULL, - (U8*)buf, - bytes); - buf[bytes] = '\0'; - LL_INFOS() << "Input After Error: " << buf << LL_ENDL; - delete[] buf; - buf = NULL; - } - else - { - LL_INFOS() << "Input After Error: (null)" << LL_ENDL; - } - } - else - { - LL_INFOS() << "Input After Error: (null)" << LL_ENDL; - } -#endif - keep_going = false; - chain.mHead = it; - if(!handleChainError(chain, status)) - { - chain.mHead = end; - } - } - else - { - LL_INFOS() << "Unhandled status code: " << status << ":" - << LLIOPipe::lookupStatusString(status) << LL_ENDL; - } - break; - } - PUMP_DEBUG; - } while(keep_going && (++it != end)); - PUMP_DEBUG; -} - -bool LLPumpIO::isChainExpired(LLChainInfo& chain) -{ - if(!chain.mHasCurlRequest) - { - return false ; - } - - for(links_t::iterator iter = chain.mChainLinks.begin(); iter != chain.mChainLinks.end(); ++iter) - { - if(!(*iter).mPipe->isValid()) - { - return true ; - } - } - - return false ; -} - -bool LLPumpIO::handleChainError( - LLChainInfo& chain, - LLIOPipe::EStatus error) -{ - links_t::reverse_iterator rit; - if(chain.mHead == chain.mChainLinks.end()) - { - rit = links_t::reverse_iterator(chain.mHead); - } - else - { - rit = links_t::reverse_iterator(chain.mHead + 1); - } - - links_t::reverse_iterator rend = chain.mChainLinks.rend(); - bool handled = false; - bool keep_going = true; - do - { -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - LL_DEBUGS() << "Passing error to " << typeid(*((*rit).mPipe)).name() - << "." << LL_ENDL; -#endif - error = (*rit).mPipe->handleError(error, this); - switch(error) - { - case LLIOPipe::STATUS_OK: - handled = true; - chain.mHead = rit.base(); - break; - case LLIOPipe::STATUS_STOP: - case LLIOPipe::STATUS_DONE: - case LLIOPipe::STATUS_BREAK: - case LLIOPipe::STATUS_NEED_PROCESS: -#if LL_DEBUG_PIPE_TYPE_IN_PUMP - LL_DEBUGS() << "Pipe " << typeid(*((*rit).mPipe)).name() - << " returned code to stop error handler." << LL_ENDL; -#endif - keep_going = false; - break; - case LLIOPipe::STATUS_EXPIRED: - keep_going = false; - break ; - default: - if(LLIOPipe::isSuccess(error)) - { - LL_INFOS() << "Unhandled status code: " << error << ":" - << LLIOPipe::lookupStatusString(error) << LL_ENDL; - error = LLIOPipe::STATUS_ERROR; - keep_going = false; - } - break; - } - } while(keep_going && !handled && (++rit != rend)); - return handled; -} - -/** - * LLPumpIO::LLChainInfo - */ - -LLPumpIO::LLChainInfo::LLChainInfo() : - mInit(false), - mLock(0), - mEOS(false), - mHasCurlRequest(false) -{ - mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS); -} - -void LLPumpIO::LLChainInfo::setTimeoutSeconds(F32 timeout) -{ - if(timeout > 0.0f) - { - mTimer.start(); - mTimer.reset(); - mTimer.setTimerExpirySec(timeout); - } - else - { - mTimer.stop(); - } -} - -void LLPumpIO::LLChainInfo::adjustTimeoutSeconds(F32 delta) -{ - if(mTimer.getStarted()) - { - F64 expiry = mTimer.expiresAt(); - expiry += delta; - mTimer.setExpiryAt(expiry); - } -} +/**
+ * @file llpumpio.cpp
+ * @author Phoenix
+ * @date 2004-11-21
+ * @brief Implementation of the i/o pump and related functions.
+ *
+ * $LicenseInfo:firstyear=2004&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$
+ */
+
+#include "linden_common.h"
+#include "llpumpio.h"
+
+#include <map>
+#include <set>
+#include "apr_poll.h"
+
+#include "llapr.h"
+#include "llfasttimer.h"
+#include "llstl.h"
+
+// These should not be enabled in production, but they can be
+// intensely useful during development for finding certain kinds of
+// bugs.
+#if LL_LINUX
+//#define LL_DEBUG_PIPE_TYPE_IN_PUMP 1
+//#define LL_DEBUG_POLL_FILE_DESCRIPTORS 1
+#if LL_DEBUG_POLL_FILE_DESCRIPTORS
+#include "apr_portable.h"
+#endif
+#endif
+
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+#include <typeinfo>
+#endif
+
+// constants for poll timeout. if we are threading, we want to have a
+// longer poll timeout.
+static const S32 DEFAULT_POLL_TIMEOUT = 0;
+
+// The default (and fallback) expiration time for chains
+const F32 DEFAULT_CHAIN_EXPIRY_SECS = 30.0f;
+extern const F32 SHORT_CHAIN_EXPIRY_SECS = 1.0f;
+extern const F32 NEVER_CHAIN_EXPIRY_SECS = 0.0f;
+
+// sorta spammy debug modes.
+//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_IN_ON_ERROR 1
+//#define LL_DEBUG_PROCESS_LINK 1
+//#define LL_DEBUG_PROCESS_RETURN_VALUE 1
+
+// Super spammy debug mode.
+//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_IN 1
+//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT 1
+
+//
+// local functions
+//
+void ll_debug_poll_fd(const char* msg, const apr_pollfd_t* poll)
+{
+#if LL_DEBUG_POLL_FILE_DESCRIPTORS
+ if(!poll)
+ {
+ LL_DEBUGS() << "Poll -- " << (msg?msg:"") << ": no pollfd." << LL_ENDL;
+ return;
+ }
+ if(poll->desc.s)
+ {
+ apr_os_sock_t os_sock;
+ if(APR_SUCCESS == apr_os_sock_get(&os_sock, poll->desc.s))
+ {
+ LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " on fd " << os_sock
+ << " at " << poll->desc.s << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " no fd "
+ << " at " << poll->desc.s << LL_ENDL;
+ }
+ }
+ else if(poll->desc.f)
+ {
+ apr_os_file_t os_file;
+ if(APR_SUCCESS == apr_os_file_get(&os_file, poll->desc.f))
+ {
+ LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " on fd " << os_file
+ << " at " << poll->desc.f << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " no fd "
+ << " at " << poll->desc.f << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_DEBUGS() << "Poll -- " << (msg?msg:"") << ": no descriptor." << LL_ENDL;
+ }
+#endif
+}
+
+/**
+ * @class
+ */
+class LLChainSleeper : public LLRunnable
+{
+public:
+ static LLRunner::run_ptr_t build(LLPumpIO* pump, S32 key)
+ {
+ return LLRunner::run_ptr_t(new LLChainSleeper(pump, key));
+ }
+
+ virtual void run(LLRunner* runner, S64 handle)
+ {
+ mPump->clearLock(mKey);
+ }
+
+protected:
+ LLChainSleeper(LLPumpIO* pump, S32 key) : mPump(pump), mKey(key) {}
+ LLPumpIO* mPump;
+ S32 mKey;
+};
+
+
+/**
+ * @struct ll_delete_apr_pollset_fd_client_data
+ * @brief This is a simple helper class to clean up our client data.
+ */
+struct ll_delete_apr_pollset_fd_client_data
+{
+ typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t;
+ void operator()(const pipe_conditional_t& conditional)
+ {
+ S32* client_id = (S32*)conditional.second.client_data;
+ delete client_id;
+ }
+};
+
+/**
+ * LLPumpIO
+ */
+LLPumpIO::LLPumpIO(apr_pool_t* pool) :
+ mState(LLPumpIO::NORMAL),
+ mRebuildPollset(false),
+ mPollset(NULL),
+ mPollsetClientID(0),
+ mNextLock(0),
+ mPool(NULL),
+ mCurrentPool(NULL),
+ mCurrentPoolReallocCount(0),
+ mCurrentChain(mRunningChains.end())
+{
+ mCurrentChain = mRunningChains.end();
+
+ initialize(pool);
+}
+
+LLPumpIO::~LLPumpIO()
+{
+ cleanup();
+}
+
+bool LLPumpIO::prime(apr_pool_t* pool)
+{
+ cleanup();
+ initialize(pool);
+ return pool != nullptr;
+}
+
+bool LLPumpIO::addChain(const chain_t& chain, F32 timeout, bool has_curl_request)
+{
+ if (chain.empty())
+ return false;
+
+ LLChainInfo info;
+ info.mHasCurlRequest = has_curl_request;
+ info.setTimeoutSeconds(timeout);
+ info.mData = LLIOPipe::buffer_ptr_t(new LLBufferArray);
+ info.mData->setThreaded(has_curl_request);
+ LLLinkInfo link;
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ LL_DEBUGS() << "LLPumpIO::addChain() " << chain[0] << " '"
+ << typeid(*(chain[0])).name() << "'" << LL_ENDL;
+#else
+ LL_DEBUGS() << "LLPumpIO::addChain() " << chain[0] <<LL_ENDL;
+#endif
+ chain_t::const_iterator it = chain.begin();
+ chain_t::const_iterator end = chain.end();
+ for(; it != end; ++it)
+ {
+ link.mPipe = (*it);
+ link.mChannels = info.mData->nextChannel();
+ info.mChainLinks.push_back(link);
+ }
+ mPendingChains.push_back(info);
+ return true;
+}
+
+bool LLPumpIO::addChain(
+ const LLPumpIO::links_t& links,
+ LLIOPipe::buffer_ptr_t data,
+ LLSD context,
+ F32 timeout)
+{
+ // remember that if the caller is providing a full link
+ // description, we need to have that description matched to a
+ // particular buffer.
+ if (!data)
+ return false;
+ if (links.empty())
+ return false;
+
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ LL_DEBUGS() << "LLPumpIO::addChain() " << links[0].mPipe << " '"
+ << typeid(*(links[0].mPipe)).name() << "'" << LL_ENDL;
+#else
+ LL_DEBUGS() << "LLPumpIO::addChain() " << links[0].mPipe << LL_ENDL;
+#endif
+ LLChainInfo info;
+ info.setTimeoutSeconds(timeout);
+ info.mChainLinks = links;
+ info.mData = data;
+ info.mContext = context;
+ mPendingChains.push_back(info);
+ return true;
+}
+
+bool LLPumpIO::setTimeoutSeconds(F32 timeout)
+{
+ // If no chain is running, return failure.
+ if (mRunningChains.end() == mCurrentChain)
+ {
+ return false;
+ }
+
+ (*mCurrentChain).setTimeoutSeconds(timeout);
+ return true;
+}
+
+void LLPumpIO::adjustTimeoutSeconds(F32 delta)
+{
+ // Ensure a chain is running
+ if (mRunningChains.end() != mCurrentChain)
+ {
+ (*mCurrentChain).adjustTimeoutSeconds(delta);
+ }
+}
+
+static std::string events_2_string(apr_int16_t events)
+{
+ std::ostringstream ostr;
+ if (events & APR_POLLIN)
+ {
+ ostr << "read,";
+ }
+ if (events & APR_POLLPRI)
+ {
+ ostr << "priority,";
+ }
+ if (events & APR_POLLOUT)
+ {
+ ostr << "write,";
+ }
+ if (events & APR_POLLERR)
+ {
+ ostr << "error,";
+ }
+ if (events & APR_POLLHUP)
+ {
+ ostr << "hangup,";
+ }
+ if (events & APR_POLLNVAL)
+ {
+ ostr << "invalid,";
+ }
+ return chop_tail_copy(ostr.str(), 1);
+}
+
+bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll)
+{
+ if (!pipe)
+ return false;
+ ll_debug_poll_fd("Set conditional", poll);
+
+ LL_DEBUGS() << "Setting conditionals (" << (poll ? events_2_string(poll->reqevents) :"null")
+ << ") "
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ << "on pipe " << typeid(*pipe).name()
+#endif
+ << " at " << pipe << LL_ENDL;
+
+ // remove any matching poll file descriptors for this pipe.
+ LLIOPipe::ptr_t pipe_ptr(pipe);
+ LLChainInfo::conditionals_t::iterator it;
+ it = (*mCurrentChain).mDescriptors.begin();
+ while(it != (*mCurrentChain).mDescriptors.end())
+ {
+ LLChainInfo::pipe_conditional_t& value = (*it);
+ if(pipe_ptr == value.first)
+ {
+ ll_delete_apr_pollset_fd_client_data()(value);
+ it = (*mCurrentChain).mDescriptors.erase(it);
+ mRebuildPollset = true;
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ if(!poll)
+ {
+ mRebuildPollset = true;
+ return true;
+ }
+ LLChainInfo::pipe_conditional_t value;
+ value.first = pipe_ptr;
+ value.second = *poll;
+ value.second.rtnevents = 0;
+ if(!poll->p)
+ {
+ // each fd needs a pool to work with, so if one was
+ // not specified, use this pool.
+ // *FIX: Should it always be this pool?
+ value.second.p = mPool;
+ }
+ value.second.client_data = new S32(++mPollsetClientID);
+ (*mCurrentChain).mDescriptors.push_back(value);
+ mRebuildPollset = true;
+ return true;
+}
+
+S32 LLPumpIO::setLock()
+{
+ // *NOTE: I do not think it is necessary to acquire a mutex here
+ // since this should only be called during the pump(), and should
+ // only change the running chain. Any other use of this method is
+ // incorrect usage. If it becomes necessary to acquire a lock
+ // here, be sure to lock here and call a protected method to get
+ // the lock, and sleepChain() should probably acquire the same
+ // lock while and calling the same protected implementation to
+ // lock the runner at the same time.
+
+ // If no chain is running, return failure.
+ if(mRunningChains.end() == mCurrentChain)
+ {
+ return 0;
+ }
+
+ // deal with wrap.
+ if(++mNextLock <= 0)
+ {
+ mNextLock = 1;
+ }
+
+ // set the lock
+ (*mCurrentChain).mLock = mNextLock;
+ return mNextLock;
+}
+
+void LLPumpIO::clearLock(S32 key)
+{
+ // We need to lock it here since we do not want to be iterating
+ // over the chains twice. We can safely call process() while this
+ // is happening since we should not be erasing a locked pipe, and
+ // therefore won't be treading into deleted memory. I think we can
+ // also clear the lock on the chain safely since the pump only
+ // reads that value.
+ mClearLocks.insert(key);
+}
+
+bool LLPumpIO::sleepChain(F64 seconds)
+{
+ // Much like the call to setLock(), this should only be called
+ // from one chain during processing, so there is no need to
+ // acquire a mutex.
+ if(seconds <= 0.0) return false;
+ S32 key = setLock();
+ if(!key) return false;
+ LLRunner::run_handle_t handle = mRunner.addRunnable(
+ LLChainSleeper::build(this, key),
+ LLRunner::RUN_IN,
+ seconds);
+ if(0 == handle) return false;
+ return true;
+}
+
+bool LLPumpIO::copyCurrentLinkInfo(links_t& links) const
+{
+ if(mRunningChains.end() == mCurrentChain)
+ {
+ return false;
+ }
+ std::copy(
+ (*mCurrentChain).mChainLinks.begin(),
+ (*mCurrentChain).mChainLinks.end(),
+ std::back_insert_iterator<links_t>(links));
+ return true;
+}
+
+void LLPumpIO::pump()
+{
+ pump(DEFAULT_POLL_TIMEOUT);
+}
+
+LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain)
+{
+ std::for_each(
+ (*run_chain).mDescriptors.begin(),
+ (*run_chain).mDescriptors.end(),
+ ll_delete_apr_pollset_fd_client_data());
+ return mRunningChains.erase(run_chain);
+}
+
+//timeout is in microseconds
+void LLPumpIO::pump(const S32& poll_timeout)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+ //LL_INFOS() << "LLPumpIO::pump()" << LL_ENDL;
+
+ // Run any pending runners.
+ mRunner.run();
+
+ // We need to move all of the pending heads over to the running
+ // chains.
+ PUMP_DEBUG;
+ if(true)
+ {
+ // bail if this pump is paused.
+ if(PAUSING == mState)
+ {
+ mState = PAUSED;
+ }
+ if(PAUSED == mState)
+ {
+ return;
+ }
+
+ PUMP_DEBUG;
+ // Move the pending chains over to the running chaings
+ if(!mPendingChains.empty())
+ {
+ PUMP_DEBUG;
+ //LL_DEBUGS() << "Pushing " << mPendingChains.size() << "." << LL_ENDL;
+ std::copy(
+ mPendingChains.begin(),
+ mPendingChains.end(),
+ std::back_insert_iterator<running_chains_t>(mRunningChains));
+ mPendingChains.clear();
+ PUMP_DEBUG;
+ }
+
+ // Clear any locks. This needs to be done here so that we do
+ // not clash during a call to clearLock().
+ if(!mClearLocks.empty())
+ {
+ PUMP_DEBUG;
+ running_chains_t::iterator it = mRunningChains.begin();
+ running_chains_t::iterator end = mRunningChains.end();
+ std::set<S32>::iterator not_cleared = mClearLocks.end();
+ for(; it != end; ++it)
+ {
+ if((*it).mLock && mClearLocks.find((*it).mLock) != not_cleared)
+ {
+ (*it).mLock = 0;
+ }
+ }
+ PUMP_DEBUG;
+ mClearLocks.clear();
+ }
+ }
+
+ PUMP_DEBUG;
+ // rebuild the pollset if necessary
+ if(mRebuildPollset)
+ {
+ PUMP_DEBUG;
+ rebuildPollset();
+ mRebuildPollset = false;
+ }
+
+ // Poll based on the last known pollset
+ // *TODO: may want to pass in a poll timeout so it works correctly
+ // in single and multi threaded processes.
+ PUMP_DEBUG;
+ typedef std::map<S32, S32> signal_client_t;
+ signal_client_t signalled_client;
+ const apr_pollfd_t* poll_fd = NULL;
+ if(mPollset)
+ {
+ PUMP_DEBUG;
+ //LL_INFOS() << "polling" << LL_ENDL;
+ S32 count = 0;
+ S32 client_id = 0;
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+ apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd);
+ }
+ PUMP_DEBUG;
+ for(S32 ii = 0; ii < count; ++ii)
+ {
+ ll_debug_poll_fd("Signalled pipe", &poll_fd[ii]);
+ client_id = *((S32*)poll_fd[ii].client_data);
+ signalled_client[client_id] = ii;
+ }
+ PUMP_DEBUG;
+ }
+
+ PUMP_DEBUG;
+ // set up for a check to see if each one was signalled
+ signal_client_t::iterator not_signalled = signalled_client.end();
+
+ // Process everything as appropriate
+ //LL_DEBUGS() << "Running chain count: " << mRunningChains.size() << LL_ENDL;
+ running_chains_t::iterator run_chain = mRunningChains.begin();
+ bool process_this_chain = false;
+ while( run_chain != mRunningChains.end() )
+ {
+ PUMP_DEBUG;
+ if((*run_chain).mInit
+ && (*run_chain).mTimer.getStarted()
+ && (*run_chain).mTimer.hasExpired())
+ {
+ PUMP_DEBUG;
+ if(handleChainError(*run_chain, LLIOPipe::STATUS_EXPIRED))
+ {
+ // the pipe probably handled the error. If the handler
+ // forgot to reset the expiration then we need to do
+ // that here.
+ if((*run_chain).mTimer.getStarted()
+ && (*run_chain).mTimer.hasExpired())
+ {
+ PUMP_DEBUG;
+ LL_INFOS() << "Error handler forgot to reset timeout. "
+ << "Resetting to " << DEFAULT_CHAIN_EXPIRY_SECS
+ << " seconds." << LL_ENDL;
+ (*run_chain).setTimeoutSeconds(DEFAULT_CHAIN_EXPIRY_SECS);
+ }
+ }
+ else
+ {
+ PUMP_DEBUG;
+ // it timed out and no one handled it, so we need to
+ // retire the chain
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ LL_DEBUGS() << "Removing chain "
+ << (*run_chain).mChainLinks[0].mPipe
+ << " '"
+ << typeid(*((*run_chain).mChainLinks[0].mPipe)).name()
+ << "' because it timed out." << LL_ENDL;
+#else
+// LL_DEBUGS() << "Removing chain "
+// << (*run_chain).mChainLinks[0].mPipe
+// << " because we reached the end." << LL_ENDL;
+#endif
+ run_chain = removeRunningChain(run_chain);
+ continue;
+ }
+ }
+ else if(isChainExpired(*run_chain))
+ {
+ run_chain = removeRunningChain(run_chain);
+ continue;
+ }
+
+ PUMP_DEBUG;
+ if((*run_chain).mLock)
+ {
+ ++run_chain;
+ continue;
+ }
+ PUMP_DEBUG;
+ mCurrentChain = run_chain;
+
+ if((*run_chain).mDescriptors.empty())
+ {
+ // if there are no conditionals, just process this chain.
+ process_this_chain = true;
+ //LL_DEBUGS() << "no conditionals - processing" << LL_ENDL;
+ }
+ else
+ {
+ PUMP_DEBUG;
+ //LL_DEBUGS() << "checking conditionals" << LL_ENDL;
+ // Check if this run chain was signalled. If any file
+ // descriptor is ready for something, then go ahead and
+ // process this chian.
+ process_this_chain = false;
+ if(!signalled_client.empty())
+ {
+ PUMP_DEBUG;
+ LLChainInfo::conditionals_t::iterator it;
+ it = (*run_chain).mDescriptors.begin();
+ LLChainInfo::conditionals_t::iterator end;
+ end = (*run_chain).mDescriptors.end();
+ S32 client_id = 0;
+ signal_client_t::iterator signal;
+ for(; it != end; ++it)
+ {
+ PUMP_DEBUG;
+ client_id = *((S32*)((*it).second.client_data));
+ signal = signalled_client.find(client_id);
+ if (signal == not_signalled) continue;
+ static const apr_int16_t POLL_CHAIN_ERROR =
+ APR_POLLHUP | APR_POLLNVAL | APR_POLLERR;
+ const apr_pollfd_t* poll = &(poll_fd[(*signal).second]);
+ if(poll->rtnevents & POLL_CHAIN_ERROR)
+ {
+ // Potential eror condition has been
+ // returned. If HUP was one of them, we pass
+ // that as the error even though there may be
+ // more. If there are in fact more errors,
+ // we'll just wait for that detection until
+ // the next pump() cycle to catch it so that
+ // the logic here gets no more strained than
+ // it already is.
+ LLIOPipe::EStatus error_status;
+ if(poll->rtnevents & APR_POLLHUP)
+ error_status = LLIOPipe::STATUS_LOST_CONNECTION;
+ else
+ error_status = LLIOPipe::STATUS_ERROR;
+ if(handleChainError(*run_chain, error_status)) break;
+ ll_debug_poll_fd("Removing pipe", poll);
+ LL_WARNS() << "Removing pipe "
+ << (*run_chain).mChainLinks[0].mPipe
+ << " '"
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ << typeid(
+ *((*run_chain).mChainLinks[0].mPipe)).name()
+#endif
+ << "' because: "
+ << events_2_string(poll->rtnevents)
+ << LL_ENDL;
+ (*run_chain).mHead = (*run_chain).mChainLinks.end();
+ break;
+ }
+
+ // at least 1 fd got signalled, and there were no
+ // errors. That means we process this chain.
+ process_this_chain = true;
+ break;
+ }
+ }
+ }
+ if(process_this_chain)
+ {
+ PUMP_DEBUG;
+ if(!((*run_chain).mInit))
+ {
+ (*run_chain).mHead = (*run_chain).mChainLinks.begin();
+ (*run_chain).mInit = true;
+ }
+ PUMP_DEBUG;
+ processChain(*run_chain);
+ }
+
+ PUMP_DEBUG;
+ if((*run_chain).mHead == (*run_chain).mChainLinks.end())
+ {
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ LL_DEBUGS() << "Removing chain " << (*run_chain).mChainLinks[0].mPipe
+ << " '"
+ << typeid(*((*run_chain).mChainLinks[0].mPipe)).name()
+ << "' because we reached the end." << LL_ENDL;
+#else
+// LL_DEBUGS() << "Removing chain " << (*run_chain).mChainLinks[0].mPipe
+// << " because we reached the end." << LL_ENDL;
+#endif
+
+ PUMP_DEBUG;
+ // This chain is done. Clean up any allocated memory and
+ // erase the chain info.
+ run_chain = removeRunningChain(run_chain);
+
+ // *NOTE: may not always need to rebuild the pollset.
+ mRebuildPollset = true;
+ }
+ else
+ {
+ PUMP_DEBUG;
+ // this chain needs more processing - just go to the next
+ // chain.
+ ++run_chain;
+ }
+ }
+
+ PUMP_DEBUG;
+ // null out the chain
+ mCurrentChain = mRunningChains.end();
+ END_PUMP_DEBUG;
+}
+
+bool LLPumpIO::respond(LLIOPipe* pipe)
+{
+ if(NULL == pipe) return false;
+
+ LLChainInfo info;
+ LLLinkInfo link;
+ link.mPipe = pipe;
+ info.mChainLinks.push_back(link);
+ mPendingCallbacks.push_back(info);
+ return true;
+}
+
+bool LLPumpIO::respond(
+ const links_t& links,
+ LLIOPipe::buffer_ptr_t data,
+ LLSD context)
+{
+ // if the caller is providing a full link description, we need to
+ // have that description matched to a particular buffer.
+ if(!data) return false;
+ if(links.empty()) return false;
+
+ // Add the callback response
+ LLChainInfo info;
+ info.mChainLinks = links;
+ info.mData = data;
+ info.mContext = context;
+ mPendingCallbacks.push_back(info);
+ return true;
+}
+
+void LLPumpIO::callback()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+ //LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL;
+ if(true)
+ {
+ std::copy(
+ mPendingCallbacks.begin(),
+ mPendingCallbacks.end(),
+ std::back_insert_iterator<callbacks_t>(mCallbacks));
+ mPendingCallbacks.clear();
+ }
+ if(!mCallbacks.empty())
+ {
+ callbacks_t::iterator it = mCallbacks.begin();
+ callbacks_t::iterator end = mCallbacks.end();
+ for(; it != end; ++it)
+ {
+ // it's always the first and last time for respone chains
+ (*it).mHead = (*it).mChainLinks.begin();
+ (*it).mInit = true;
+ (*it).mEOS = true;
+ processChain(*it);
+ }
+ mCallbacks.clear();
+ }
+}
+
+void LLPumpIO::control(LLPumpIO::EControl op)
+{
+ switch(op)
+ {
+ case PAUSE:
+ mState = PAUSING;
+ break;
+ case RESUME:
+ mState = NORMAL;
+ break;
+ default:
+ // no-op
+ break;
+ }
+}
+
+void LLPumpIO::initialize(apr_pool_t* pool)
+{
+ if(!pool) return;
+ mPool = pool;
+}
+
+void LLPumpIO::cleanup()
+{
+ if(mPollset)
+ {
+// LL_DEBUGS() << "cleaning up pollset" << LL_ENDL;
+ apr_pollset_destroy(mPollset);
+ mPollset = NULL;
+ }
+ if(mCurrentPool)
+ {
+ apr_pool_destroy(mCurrentPool);
+ mCurrentPool = NULL;
+ }
+ mPool = NULL;
+}
+
+void LLPumpIO::rebuildPollset()
+{
+// LL_DEBUGS() << "LLPumpIO::rebuildPollset()" << LL_ENDL;
+ if(mPollset)
+ {
+ //LL_DEBUGS() << "destroying pollset" << LL_ENDL;
+ apr_pollset_destroy(mPollset);
+ mPollset = NULL;
+ }
+ U32 size = 0;
+ running_chains_t::iterator run_it = mRunningChains.begin();
+ running_chains_t::iterator run_end = mRunningChains.end();
+ for(; run_it != run_end; ++run_it)
+ {
+ size += (*run_it).mDescriptors.size();
+ }
+ //LL_DEBUGS() << "found " << size << " descriptors." << LL_ENDL;
+ if(size)
+ {
+ // Recycle the memory pool
+ const S32 POLLSET_POOL_RECYCLE_COUNT = 100;
+ if(mCurrentPool
+ && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT)))
+ {
+ apr_pool_destroy(mCurrentPool);
+ mCurrentPool = NULL;
+ mCurrentPoolReallocCount = 0;
+ }
+ if(!mCurrentPool)
+ {
+ apr_status_t status = apr_pool_create(&mCurrentPool, mPool);
+ (void)ll_apr_warn_status(status);
+ }
+
+ // add all of the file descriptors
+ run_it = mRunningChains.begin();
+ LLChainInfo::conditionals_t::iterator fd_it;
+ LLChainInfo::conditionals_t::iterator fd_end;
+ apr_pollset_create(&mPollset, size, mCurrentPool, 0);
+ for(; run_it != run_end; ++run_it)
+ {
+ fd_it = (*run_it).mDescriptors.begin();
+ fd_end = (*run_it).mDescriptors.end();
+ for(; fd_it != fd_end; ++fd_it)
+ {
+ apr_pollset_add(mPollset, &((*fd_it).second));
+ }
+ }
+ }
+}
+
+void LLPumpIO::processChain(LLChainInfo& chain)
+{
+ PUMP_DEBUG;
+ LLIOPipe::EStatus status = LLIOPipe::STATUS_OK;
+ links_t::iterator it = chain.mHead;
+ links_t::iterator end = chain.mChainLinks.end();
+ bool need_process_signaled = false;
+ bool keep_going = true;
+ do
+ {
+#if LL_DEBUG_PROCESS_LINK
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ LL_INFOS() << "Processing " << typeid(*((*it).mPipe)).name() << "."
+ << LL_ENDL;
+#else
+ LL_INFOS() << "Processing link " << (*it).mPipe << "." << LL_ENDL;
+#endif
+#endif
+#if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN
+ if(chain.mData)
+ {
+ char* buf = NULL;
+ S32 bytes = chain.mData->countAfter((*it).mChannels.in(), NULL);
+ if(bytes)
+ {
+ buf = new char[bytes + 1];
+ chain.mData->readAfter(
+ (*it).mChannels.in(),
+ NULL,
+ (U8*)buf,
+ bytes);
+ buf[bytes] = '\0';
+ LL_INFOS() << "CHANNEL IN(" << (*it).mChannels.in() << "): "
+ << buf << LL_ENDL;
+ delete[] buf;
+ buf = NULL;
+ }
+ else
+ {
+ LL_INFOS() << "CHANNEL IN(" << (*it).mChannels.in()<< "): (null)"
+ << LL_ENDL;
+ }
+ }
+#endif
+ PUMP_DEBUG;
+ status = (*it).mPipe->process(
+ (*it).mChannels,
+ chain.mData,
+ chain.mEOS,
+ chain.mContext,
+ this);
+#if LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT
+ if(chain.mData)
+ {
+ char* buf = NULL;
+ S32 bytes = chain.mData->countAfter((*it).mChannels.out(), NULL);
+ if(bytes)
+ {
+ buf = new char[bytes + 1];
+ chain.mData->readAfter(
+ (*it).mChannels.out(),
+ NULL,
+ (U8*)buf,
+ bytes);
+ buf[bytes] = '\0';
+ LL_INFOS() << "CHANNEL OUT(" << (*it).mChannels.out()<< "): "
+ << buf << LL_ENDL;
+ delete[] buf;
+ buf = NULL;
+ }
+ else
+ {
+ LL_INFOS() << "CHANNEL OUT(" << (*it).mChannels.out()<< "): (null)"
+ << LL_ENDL;
+ }
+ }
+#endif
+
+#if LL_DEBUG_PROCESS_RETURN_VALUE
+ // Only bother with the success codes - error codes are logged
+ // below.
+ if(LLIOPipe::isSuccess(status))
+ {
+ LL_INFOS() << "Pipe returned: '"
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ << typeid(*((*it).mPipe)).name() << "':'"
+#endif
+ << LLIOPipe::lookupStatusString(status) << "'" << LL_ENDL;
+ }
+#endif
+
+ PUMP_DEBUG;
+ switch(status)
+ {
+ case LLIOPipe::STATUS_OK:
+ // no-op
+ break;
+ case LLIOPipe::STATUS_STOP:
+ PUMP_DEBUG;
+ status = LLIOPipe::STATUS_OK;
+ chain.mHead = end;
+ keep_going = false;
+ break;
+ case LLIOPipe::STATUS_DONE:
+ PUMP_DEBUG;
+ status = LLIOPipe::STATUS_OK;
+ chain.mHead = (it + 1);
+ chain.mEOS = true;
+ break;
+ case LLIOPipe::STATUS_BREAK:
+ PUMP_DEBUG;
+ status = LLIOPipe::STATUS_OK;
+ keep_going = false;
+ break;
+ case LLIOPipe::STATUS_NEED_PROCESS:
+ PUMP_DEBUG;
+ status = LLIOPipe::STATUS_OK;
+ if(!need_process_signaled)
+ {
+ need_process_signaled = true;
+ chain.mHead = it;
+ }
+ break;
+ default:
+ PUMP_DEBUG;
+ if(LLIOPipe::isError(status))
+ {
+ LL_INFOS() << "Pump generated pipe err: '"
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ << typeid(*((*it).mPipe)).name() << "':'"
+#endif
+ << LLIOPipe::lookupStatusString(status)
+ << "'" << LL_ENDL;
+#if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN_ON_ERROR
+ if(chain.mData)
+ {
+ char* buf = NULL;
+ S32 bytes = chain.mData->countAfter(
+ (*it).mChannels.in(),
+ NULL);
+ if(bytes)
+ {
+ buf = new char[bytes + 1];
+ chain.mData->readAfter(
+ (*it).mChannels.in(),
+ NULL,
+ (U8*)buf,
+ bytes);
+ buf[bytes] = '\0';
+ LL_INFOS() << "Input After Error: " << buf << LL_ENDL;
+ delete[] buf;
+ buf = NULL;
+ }
+ else
+ {
+ LL_INFOS() << "Input After Error: (null)" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_INFOS() << "Input After Error: (null)" << LL_ENDL;
+ }
+#endif
+ keep_going = false;
+ chain.mHead = it;
+ if(!handleChainError(chain, status))
+ {
+ chain.mHead = end;
+ }
+ }
+ else
+ {
+ LL_INFOS() << "Unhandled status code: " << status << ":"
+ << LLIOPipe::lookupStatusString(status) << LL_ENDL;
+ }
+ break;
+ }
+ PUMP_DEBUG;
+ } while(keep_going && (++it != end));
+ PUMP_DEBUG;
+}
+
+bool LLPumpIO::isChainExpired(LLChainInfo& chain)
+{
+ if(!chain.mHasCurlRequest)
+ {
+ return false ;
+ }
+
+ for(links_t::iterator iter = chain.mChainLinks.begin(); iter != chain.mChainLinks.end(); ++iter)
+ {
+ if(!(*iter).mPipe->isValid())
+ {
+ return true ;
+ }
+ }
+
+ return false ;
+}
+
+bool LLPumpIO::handleChainError(
+ LLChainInfo& chain,
+ LLIOPipe::EStatus error)
+{
+ links_t::reverse_iterator rit;
+ if(chain.mHead == chain.mChainLinks.end())
+ {
+ rit = links_t::reverse_iterator(chain.mHead);
+ }
+ else
+ {
+ rit = links_t::reverse_iterator(chain.mHead + 1);
+ }
+
+ links_t::reverse_iterator rend = chain.mChainLinks.rend();
+ bool handled = false;
+ bool keep_going = true;
+ do
+ {
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ LL_DEBUGS() << "Passing error to " << typeid(*((*rit).mPipe)).name()
+ << "." << LL_ENDL;
+#endif
+ error = (*rit).mPipe->handleError(error, this);
+ switch(error)
+ {
+ case LLIOPipe::STATUS_OK:
+ handled = true;
+ chain.mHead = rit.base();
+ break;
+ case LLIOPipe::STATUS_STOP:
+ case LLIOPipe::STATUS_DONE:
+ case LLIOPipe::STATUS_BREAK:
+ case LLIOPipe::STATUS_NEED_PROCESS:
+#if LL_DEBUG_PIPE_TYPE_IN_PUMP
+ LL_DEBUGS() << "Pipe " << typeid(*((*rit).mPipe)).name()
+ << " returned code to stop error handler." << LL_ENDL;
+#endif
+ keep_going = false;
+ break;
+ case LLIOPipe::STATUS_EXPIRED:
+ keep_going = false;
+ break ;
+ default:
+ if(LLIOPipe::isSuccess(error))
+ {
+ LL_INFOS() << "Unhandled status code: " << error << ":"
+ << LLIOPipe::lookupStatusString(error) << LL_ENDL;
+ error = LLIOPipe::STATUS_ERROR;
+ keep_going = false;
+ }
+ break;
+ }
+ } while(keep_going && !handled && (++rit != rend));
+ return handled;
+}
+
+/**
+ * LLPumpIO::LLChainInfo
+ */
+
+LLPumpIO::LLChainInfo::LLChainInfo() :
+ mInit(false),
+ mLock(0),
+ mEOS(false),
+ mHasCurlRequest(false)
+{
+ mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS);
+}
+
+void LLPumpIO::LLChainInfo::setTimeoutSeconds(F32 timeout)
+{
+ if(timeout > 0.0f)
+ {
+ mTimer.start();
+ mTimer.reset();
+ mTimer.setTimerExpirySec(timeout);
+ }
+ else
+ {
+ mTimer.stop();
+ }
+}
+
+void LLPumpIO::LLChainInfo::adjustTimeoutSeconds(F32 delta)
+{
+ if(mTimer.getStarted())
+ {
+ F64 expiry = mTimer.expiresAt();
+ expiry += delta;
+ mTimer.setExpiryAt(expiry);
+ }
+}
diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 71a7672337..835bccfb14 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -1,206 +1,211 @@ -/** - * @file llregionflags.h - * @brief Flags that are sent in the statistics message region_flags field. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#ifndef LL_LLREGIONFLAGS_H -#define LL_LLREGIONFLAGS_H - -// Can you be hurt here? Should health be on? -const U64 REGION_FLAGS_ALLOW_DAMAGE = (1 << 0); - -// Can you make landmarks here? -const U64 REGION_FLAGS_ALLOW_LANDMARK = (1 << 1); - -// Do we reset the home position when someone teleports away from here? -const U64 REGION_FLAGS_ALLOW_SET_HOME = (1 << 2); - -// Do we reset the home position when someone teleports away from here? -const U64 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3); - -// Does the sun move? -const U64 REGION_FLAGS_SUN_FIXED = (1 << 4); - -// Does the estate owner allow private parcels? -const U64 REGION_FLAGS_ALLOW_ACCESS_OVERRIDE = (1 << 5); - -// Can't change the terrain heightfield, even on owned parcels, -// but can plant trees and grass. -const U64 REGION_FLAGS_BLOCK_TERRAFORM = (1 << 6); - -// Can't release, sell, or buy land. -const U64 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7); - -// All content wiped once per night -const U64 REGION_FLAGS_SANDBOX = (1 << 8); - -const U64 REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE = (1 << 9); - -const U64 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies -const U64 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13); -const U64 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics -const U64 REGION_FLAGS_EXTERNALLY_VISIBLE = (1 << 15); -const U64 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT = (1 << 16); -const U64 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT = (1 << 17); -const U64 REGION_FLAGS_BLOCK_DWELL = (1 << 18); - -// Is flight allowed? -const U64 REGION_FLAGS_BLOCK_FLY = (1 << 19); - -// Is direct teleport (p2p) allowed? -const U64 REGION_FLAGS_ALLOW_DIRECT_TELEPORT = (1 << 20); - -// Is there an administrative override on scripts in the region at the -// moment. This is the similar skip scripts, except this flag is -// presisted in the database on an estate level. -const U64 REGION_FLAGS_ESTATE_SKIP_SCRIPTS = (1 << 21); - -const U64 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1 << 22); - -const U64 REGION_FLAGS_DENY_ANONYMOUS = (1 << 23); - -const U64 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1 << 26); - -const U64 REGION_FLAGS_BLOCK_FLYOVER = (1 << 27); - -const U64 REGION_FLAGS_ALLOW_VOICE = (1 << 28); - -const U64 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29); -const U64 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30); - -const U64 REGION_FLAGS_DENY_BOTS = (1 << 31); - -const U64 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK | - REGION_FLAGS_ALLOW_SET_HOME | - REGION_FLAGS_ALLOW_PARCEL_CHANGES | - REGION_FLAGS_ALLOW_VOICE; - - -const U64 REGION_FLAGS_PRELUDE_SET = REGION_FLAGS_RESET_HOME_ON_TELEPORT; -const U64 REGION_FLAGS_PRELUDE_UNSET = REGION_FLAGS_ALLOW_LANDMARK - | REGION_FLAGS_ALLOW_SET_HOME; - -const U64 REGION_FLAGS_ESTATE_MASK = REGION_FLAGS_EXTERNALLY_VISIBLE - | REGION_FLAGS_SUN_FIXED - | REGION_FLAGS_DENY_ANONYMOUS - | REGION_FLAGS_DENY_AGEUNVERIFIED; - -inline BOOL is_prelude( U64 flags ) -{ - // definition of prelude does not depend on fixed-sun - return 0 == (flags & REGION_FLAGS_PRELUDE_UNSET) - && 0 != (flags & REGION_FLAGS_PRELUDE_SET); -} - -inline U64 set_prelude_flags(U64 flags) -{ - // also set the sun-fixed flag - return ((flags & ~REGION_FLAGS_PRELUDE_UNSET) - | (REGION_FLAGS_PRELUDE_SET | REGION_FLAGS_SUN_FIXED)); -} - -inline U64 unset_prelude_flags(U64 flags) -{ - // also unset the fixed-sun flag - return ((flags | REGION_FLAGS_PRELUDE_UNSET) - & ~(REGION_FLAGS_PRELUDE_SET | REGION_FLAGS_SUN_FIXED)); -} - -// Region protocols -const U64 REGION_PROTOCOLS_AGENT_APPEARANCE_SERVICE = (1 << 0); - -// estate constants. Need to match first few etries in indra.estate table. -const U32 ESTATE_ALL = 0; // will not match in db, reserved key for logic -const U32 ESTATE_MAINLAND = 1; -const U32 ESTATE_ORIENTATION = 2; -const U32 ESTATE_INTERNAL = 3; -const U32 ESTATE_SHOWCASE = 4; -const U32 ESTATE_TEEN = 5; -const U32 ESTATE_LAST_LINDEN = 5; // last linden owned/managed estate - -// for EstateOwnerRequest, setaccess message -const U32 ESTATE_ACCESS_ALLOWED_AGENTS = 1 << 0; -const U32 ESTATE_ACCESS_ALLOWED_GROUPS = 1 << 1; -const U32 ESTATE_ACCESS_BANNED_AGENTS = 1 << 2; -const U32 ESTATE_ACCESS_MANAGERS = 1 << 3; - -//maximum number of access list entries we can fit in one packet -const S32 ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET = 63; - -// for reply to "getinfo", don't need to forward to all sims in estate -const U32 ESTATE_ACCESS_SEND_TO_AGENT_ONLY = 1 << 4; - -const U32 ESTATE_ACCESS_ALL = ESTATE_ACCESS_ALLOWED_AGENTS - | ESTATE_ACCESS_ALLOWED_GROUPS - | ESTATE_ACCESS_BANNED_AGENTS - | ESTATE_ACCESS_MANAGERS; - -// for EstateOwnerRequest, estateaccessdelta, estateexperiencedelta messages -const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1U << 0; -const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1U << 1; - -const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1U << 2; -const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1U << 3; -const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1U << 4; -const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1U << 5; -const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1U << 6; -const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1U << 7; -const U32 ESTATE_ACCESS_MANAGER_ADD = 1U << 8; -const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9; -const U32 ESTATE_ACCESS_NO_REPLY = 1U << 10; -const U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11; - -const S32 ESTATE_MAX_MANAGERS = 20; -const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access -const S32 ESTATE_MAX_BANNED_IDS = 750; // max for banned -const S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET; - -// 'Sim Wide Delete' flags -const U32 SWD_OTHERS_LAND_ONLY = (1 << 0); -const U32 SWD_ALWAYS_RETURN_OBJECTS = (1 << 1); -const U32 SWD_SCRIPTED_ONLY = (1 << 2); - -// Controls experience key validity in the estate -const U32 EXPERIENCE_KEY_TYPE_NONE = 0; -const U32 EXPERIENCE_KEY_TYPE_BLOCKED = 1; -const U32 EXPERIENCE_KEY_TYPE_ALLOWED = 2; -const U32 EXPERIENCE_KEY_TYPE_TRUSTED = 3; - -const U32 EXPERIENCE_KEY_TYPE_FIRST = EXPERIENCE_KEY_TYPE_BLOCKED; -const U32 EXPERIENCE_KEY_TYPE_LAST = EXPERIENCE_KEY_TYPE_TRUSTED; - -// -const U32 ESTATE_EXPERIENCE_TRUSTED_ADD = 1U << 2; -const U32 ESTATE_EXPERIENCE_TRUSTED_REMOVE = 1U << 3; -const U32 ESTATE_EXPERIENCE_ALLOWED_ADD = 1U << 4; -const U32 ESTATE_EXPERIENCE_ALLOWED_REMOVE = 1U << 5; -const U32 ESTATE_EXPERIENCE_BLOCKED_ADD = 1U << 6; -const U32 ESTATE_EXPERIENCE_BLOCKED_REMOVE = 1U << 7; - -const S32 ESTATE_MAX_EXPERIENCE_IDS = 8; - - -#endif - - +/**
+ * @file llregionflags.h
+ * @brief Flags that are sent in the statistics message region_flags field.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLREGIONFLAGS_H
+#define LL_LLREGIONFLAGS_H
+
+// Can you be hurt here? Should health be on?
+const U64 REGION_FLAGS_ALLOW_DAMAGE = (1 << 0);
+
+// Can you make landmarks here?
+const U64 REGION_FLAGS_ALLOW_LANDMARK = (1 << 1);
+
+// Do we reset the home position when someone teleports away from here?
+const U64 REGION_FLAGS_ALLOW_SET_HOME = (1 << 2);
+
+// Do we reset the home position when someone teleports away from here?
+const U64 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3);
+
+// Does the sun move?
+const U64 REGION_FLAGS_SUN_FIXED = (1 << 4);
+
+// Does the estate owner allow private parcels?
+const U64 REGION_FLAGS_ALLOW_ACCESS_OVERRIDE = (1 << 5);
+
+// Can't change the terrain heightfield, even on owned parcels,
+// but can plant trees and grass.
+const U64 REGION_FLAGS_BLOCK_TERRAFORM = (1 << 6);
+
+// Can't release, sell, or buy land.
+const U64 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7);
+
+// All content wiped once per night
+const U64 REGION_FLAGS_SANDBOX = (1 << 8);
+
+const U64 REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE = (1 << 9);
+
+const U64 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies
+const U64 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13);
+const U64 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics
+const U64 REGION_FLAGS_EXTERNALLY_VISIBLE = (1 << 15);
+const U64 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT = (1 << 16);
+const U64 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT = (1 << 17);
+const U64 REGION_FLAGS_BLOCK_DWELL = (1 << 18);
+
+// Is flight allowed?
+const U64 REGION_FLAGS_BLOCK_FLY = (1 << 19);
+
+// Is direct teleport (p2p) allowed?
+const U64 REGION_FLAGS_ALLOW_DIRECT_TELEPORT = (1 << 20);
+
+// Is there an administrative override on scripts in the region at the
+// moment. This is the similar skip scripts, except this flag is
+// presisted in the database on an estate level.
+const U64 REGION_FLAGS_ESTATE_SKIP_SCRIPTS = (1 << 21);
+
+const U64 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1 << 22);
+
+const U64 REGION_FLAGS_DENY_ANONYMOUS = (1 << 23);
+
+const U64 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1 << 26);
+
+const U64 REGION_FLAGS_BLOCK_FLYOVER = (1 << 27);
+
+const U64 REGION_FLAGS_ALLOW_VOICE = (1 << 28);
+
+const U64 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29);
+const U64 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30);
+
+const U64 REGION_FLAGS_DENY_BOTS = (1 << 31);
+
+const U64 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK |
+ REGION_FLAGS_ALLOW_SET_HOME |
+ REGION_FLAGS_ALLOW_PARCEL_CHANGES |
+ REGION_FLAGS_ALLOW_VOICE;
+
+
+const U64 REGION_FLAGS_PRELUDE_SET = REGION_FLAGS_RESET_HOME_ON_TELEPORT;
+const U64 REGION_FLAGS_PRELUDE_UNSET = REGION_FLAGS_ALLOW_LANDMARK
+ | REGION_FLAGS_ALLOW_SET_HOME;
+
+const U64 REGION_FLAGS_ESTATE_MASK = REGION_FLAGS_EXTERNALLY_VISIBLE
+ | REGION_FLAGS_SUN_FIXED
+ | REGION_FLAGS_DENY_ANONYMOUS
+ | REGION_FLAGS_DENY_AGEUNVERIFIED;
+
+inline bool is_flag_set(U64 flags, U64 flag)
+{
+ return (flags & flag) != 0;
+}
+
+inline bool is_prelude( U64 flags )
+{
+ // definition of prelude does not depend on fixed-sun
+ return !is_flag_set(flags, REGION_FLAGS_PRELUDE_UNSET) &&
+ is_flag_set(flags, REGION_FLAGS_PRELUDE_SET);
+}
+
+inline U64 set_prelude_flags(U64 flags)
+{
+ // also set the sun-fixed flag
+ return ((flags & ~REGION_FLAGS_PRELUDE_UNSET)
+ | (REGION_FLAGS_PRELUDE_SET | REGION_FLAGS_SUN_FIXED));
+}
+
+inline U64 unset_prelude_flags(U64 flags)
+{
+ // also unset the fixed-sun flag
+ return ((flags | REGION_FLAGS_PRELUDE_UNSET)
+ & ~(REGION_FLAGS_PRELUDE_SET | REGION_FLAGS_SUN_FIXED));
+}
+
+// Region protocols
+const U64 REGION_PROTOCOLS_AGENT_APPEARANCE_SERVICE = (1 << 0);
+
+// estate constants. Need to match first few etries in indra.estate table.
+const U32 ESTATE_ALL = 0; // will not match in db, reserved key for logic
+const U32 ESTATE_MAINLAND = 1;
+const U32 ESTATE_ORIENTATION = 2;
+const U32 ESTATE_INTERNAL = 3;
+const U32 ESTATE_SHOWCASE = 4;
+const U32 ESTATE_TEEN = 5;
+const U32 ESTATE_LAST_LINDEN = 5; // last linden owned/managed estate
+
+// for EstateOwnerRequest, setaccess message
+const U32 ESTATE_ACCESS_ALLOWED_AGENTS = 1 << 0;
+const U32 ESTATE_ACCESS_ALLOWED_GROUPS = 1 << 1;
+const U32 ESTATE_ACCESS_BANNED_AGENTS = 1 << 2;
+const U32 ESTATE_ACCESS_MANAGERS = 1 << 3;
+
+//maximum number of access list entries we can fit in one packet
+const S32 ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET = 63;
+
+// for reply to "getinfo", don't need to forward to all sims in estate
+const U32 ESTATE_ACCESS_SEND_TO_AGENT_ONLY = 1 << 4;
+
+const U32 ESTATE_ACCESS_ALL = ESTATE_ACCESS_ALLOWED_AGENTS
+ | ESTATE_ACCESS_ALLOWED_GROUPS
+ | ESTATE_ACCESS_BANNED_AGENTS
+ | ESTATE_ACCESS_MANAGERS;
+
+// for EstateOwnerRequest, estateaccessdelta, estateexperiencedelta messages
+const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1U << 0;
+const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1U << 1;
+
+const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1U << 2;
+const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1U << 3;
+const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1U << 4;
+const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1U << 5;
+const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1U << 6;
+const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1U << 7;
+const U32 ESTATE_ACCESS_MANAGER_ADD = 1U << 8;
+const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9;
+const U32 ESTATE_ACCESS_NO_REPLY = 1U << 10;
+const U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11;
+
+const S32 ESTATE_MAX_MANAGERS = 20;
+const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access
+const S32 ESTATE_MAX_BANNED_IDS = 750; // max for banned
+const S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET;
+
+// 'Sim Wide Delete' flags
+const U32 SWD_OTHERS_LAND_ONLY = (1 << 0);
+const U32 SWD_ALWAYS_RETURN_OBJECTS = (1 << 1);
+const U32 SWD_SCRIPTED_ONLY = (1 << 2);
+
+// Controls experience key validity in the estate
+const U32 EXPERIENCE_KEY_TYPE_NONE = 0;
+const U32 EXPERIENCE_KEY_TYPE_BLOCKED = 1;
+const U32 EXPERIENCE_KEY_TYPE_ALLOWED = 2;
+const U32 EXPERIENCE_KEY_TYPE_TRUSTED = 3;
+
+const U32 EXPERIENCE_KEY_TYPE_FIRST = EXPERIENCE_KEY_TYPE_BLOCKED;
+const U32 EXPERIENCE_KEY_TYPE_LAST = EXPERIENCE_KEY_TYPE_TRUSTED;
+
+//
+const U32 ESTATE_EXPERIENCE_TRUSTED_ADD = 1U << 2;
+const U32 ESTATE_EXPERIENCE_TRUSTED_REMOVE = 1U << 3;
+const U32 ESTATE_EXPERIENCE_ALLOWED_ADD = 1U << 4;
+const U32 ESTATE_EXPERIENCE_ALLOWED_REMOVE = 1U << 5;
+const U32 ESTATE_EXPERIENCE_BLOCKED_ADD = 1U << 6;
+const U32 ESTATE_EXPERIENCE_BLOCKED_REMOVE = 1U << 7;
+
+const S32 ESTATE_MAX_EXPERIENCE_IDS = 8;
+
+
+#endif
+
+
diff --git a/indra/llmessage/llregionhandle.h b/indra/llmessage/llregionhandle.h index 9982a8260e..f732cdcce5 100644 --- a/indra/llmessage/llregionhandle.h +++ b/indra/llmessage/llregionhandle.h @@ -1,126 +1,126 @@ -/** - * @file llregionhandle.h - * @brief Routines for converting positions to/from region handles. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#ifndef LL_LLREGIONHANDLE_H -#define LL_LLREGIONHANDLE_H - -#include "indra_constants.h" -#include "v3math.h" -#include "v3dmath.h" - -inline U64 to_region_handle(const U32 x_origin, const U32 y_origin) -{ - U64 region_handle; - region_handle = ((U64)x_origin) << 32; - region_handle |= (U64) y_origin; - return region_handle; -} - -inline U64 to_region_handle(const LLVector3d& pos_global) -{ - U32 global_x = (U32)pos_global.mdV[VX]; - global_x -= global_x % 256; - - U32 global_y = (U32)pos_global.mdV[VY]; - global_y -= global_y % 256; - - return to_region_handle(global_x, global_y); -} - -inline U64 to_region_handle_global(const F32 x_global, const F32 y_global) -{ - // Round down to the nearest origin - U32 x_origin = (U32)x_global; - x_origin -= x_origin % REGION_WIDTH_U32; - U32 y_origin = (U32)y_global; - y_origin -= y_origin % REGION_WIDTH_U32; - U64 region_handle; - region_handle = ((U64)x_origin) << 32; - region_handle |= (U64) y_origin; - return region_handle; -} - -inline BOOL to_region_handle(const F32 x_pos, const F32 y_pos, U64 *region_handle) -{ - U32 x_int, y_int; - if (x_pos < 0.f) - { -// LL_WARNS() << "to_region_handle:Clamping negative x position " << x_pos << " to zero!" << LL_ENDL; - return FALSE; - } - else - { - x_int = (U32)ll_round(x_pos); - } - if (y_pos < 0.f) - { -// LL_WARNS() << "to_region_handle:Clamping negative y position " << y_pos << " to zero!" << LL_ENDL; - return FALSE; - } - else - { - y_int = (U32)ll_round(y_pos); - } - *region_handle = to_region_handle(x_int, y_int); - return TRUE; -} - -// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos -inline void from_region_handle(const U64 ®ion_handle, F32 *x_pos, F32 *y_pos) -{ - *x_pos = (F32)((U32)(region_handle >> 32)); - *y_pos = (F32)((U32)(region_handle & 0xFFFFFFFF)); -} - -// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos -inline void from_region_handle(const U64 ®ion_handle, U32 *x_pos, U32 *y_pos) -{ - *x_pos = ((U32)(region_handle >> 32)); - *y_pos = ((U32)(region_handle & 0xFFFFFFFF)); -} - -// return the word-frame XY location of sim's SouthWest corner in LLVector3d -inline LLVector3d from_region_handle(const U64 ®ion_handle) -{ - return LLVector3d(((U32)(region_handle >> 32)), (U32)(region_handle & 0xFFFFFFFF), 0.f); -} - -// grid-based region handle encoding. pass in a grid position -// (eg: 1000,1000) and this will return the region handle. -inline U64 grid_to_region_handle(const U32 grid_x, const U32 grid_y) -{ - return to_region_handle(grid_x * REGION_WIDTH_UNITS, - grid_y * REGION_WIDTH_UNITS); -} - -inline void grid_from_region_handle(const U64& region_handle, U32* grid_x, U32* grid_y) -{ - from_region_handle(region_handle, grid_x, grid_y); - *grid_x /= REGION_WIDTH_UNITS; - *grid_y /= REGION_WIDTH_UNITS; -} - -#endif +/**
+ * @file llregionhandle.h
+ * @brief Routines for converting positions to/from region handles.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLREGIONHANDLE_H
+#define LL_LLREGIONHANDLE_H
+
+#include "indra_constants.h"
+#include "v3math.h"
+#include "v3dmath.h"
+
+inline U64 to_region_handle(const U32 x_origin, const U32 y_origin)
+{
+ U64 region_handle;
+ region_handle = ((U64)x_origin) << 32;
+ region_handle |= (U64) y_origin;
+ return region_handle;
+}
+
+inline U64 to_region_handle(const LLVector3d& pos_global)
+{
+ U32 global_x = (U32)pos_global.mdV[VX];
+ global_x -= global_x % 256;
+
+ U32 global_y = (U32)pos_global.mdV[VY];
+ global_y -= global_y % 256;
+
+ return to_region_handle(global_x, global_y);
+}
+
+inline U64 to_region_handle_global(const F32 x_global, const F32 y_global)
+{
+ // Round down to the nearest origin
+ U32 x_origin = (U32)x_global;
+ x_origin -= x_origin % REGION_WIDTH_U32;
+ U32 y_origin = (U32)y_global;
+ y_origin -= y_origin % REGION_WIDTH_U32;
+ U64 region_handle;
+ region_handle = ((U64)x_origin) << 32;
+ region_handle |= (U64) y_origin;
+ return region_handle;
+}
+
+inline bool to_region_handle(const F32 x_pos, const F32 y_pos, U64 *region_handle)
+{
+ U32 x_int, y_int;
+ if (x_pos < 0.f)
+ {
+// LL_WARNS() << "to_region_handle:Clamping negative x position " << x_pos << " to zero!" << LL_ENDL;
+ return false;
+ }
+ else
+ {
+ x_int = (U32)ll_round(x_pos);
+ }
+ if (y_pos < 0.f)
+ {
+// LL_WARNS() << "to_region_handle:Clamping negative y position " << y_pos << " to zero!" << LL_ENDL;
+ return false;
+ }
+ else
+ {
+ y_int = (U32)ll_round(y_pos);
+ }
+ *region_handle = to_region_handle(x_int, y_int);
+ return true;
+}
+
+// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos
+inline void from_region_handle(const U64 ®ion_handle, F32 *x_pos, F32 *y_pos)
+{
+ *x_pos = (F32)((U32)(region_handle >> 32));
+ *y_pos = (F32)((U32)(region_handle & 0xFFFFFFFF));
+}
+
+// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos
+inline void from_region_handle(const U64 ®ion_handle, U32 *x_pos, U32 *y_pos)
+{
+ *x_pos = ((U32)(region_handle >> 32));
+ *y_pos = ((U32)(region_handle & 0xFFFFFFFF));
+}
+
+// return the word-frame XY location of sim's SouthWest corner in LLVector3d
+inline LLVector3d from_region_handle(const U64 ®ion_handle)
+{
+ return LLVector3d(((U32)(region_handle >> 32)), (U32)(region_handle & 0xFFFFFFFF), 0.f);
+}
+
+// grid-based region handle encoding. pass in a grid position
+// (eg: 1000,1000) and this will return the region handle.
+inline U64 grid_to_region_handle(const U32 grid_x, const U32 grid_y)
+{
+ return to_region_handle(grid_x * REGION_WIDTH_UNITS,
+ grid_y * REGION_WIDTH_UNITS);
+}
+
+inline void grid_from_region_handle(const U64& region_handle, U32* grid_x, U32* grid_y)
+{
+ from_region_handle(region_handle, grid_x, grid_y);
+ *grid_x /= REGION_WIDTH_UNITS;
+ *grid_y /= REGION_WIDTH_UNITS;
+}
+
+#endif
diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp index 4c678b235b..3f4553fcee 100644 --- a/indra/llmessage/llsdmessagebuilder.cpp +++ b/indra/llmessage/llsdmessagebuilder.cpp @@ -1,424 +1,424 @@ -/** - * @file llsdmessagebuilder.cpp - * @brief LLSDMessageBuilder class implementation. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "linden_common.h" - -#include "llsdmessagebuilder.h" - -#include "llmessagetemplate.h" -#include "llmath.h" -#include "llquaternion.h" -#include "llsdutil.h" -#include "llsdutil_math.h" -#include "llsdserialize.h" -#include "u64.h" -#include "v3dmath.h" -#include "v3math.h" -#include "v4math.h" - -LLSDMessageBuilder::LLSDMessageBuilder() : - mCurrentMessage(LLSD::emptyMap()), - mCurrentBlock(NULL), - mCurrentMessageName(""), - mCurrentBlockName(""), - mbSBuilt(FALSE), - mbSClear(TRUE) -{ -} - -//virtual -LLSDMessageBuilder::~LLSDMessageBuilder() -{ -} - - -// virtual -void LLSDMessageBuilder::newMessage(const char* name) -{ - mbSBuilt = FALSE; - mbSClear = FALSE; - - mCurrentMessage = LLSD::emptyMap(); - mCurrentMessageName = (char*)name; -} - -// virtual -void LLSDMessageBuilder::clearMessage() -{ - mbSBuilt = FALSE; - mbSClear = TRUE; - - mCurrentMessage = LLSD::emptyMap(); - mCurrentMessageName = ""; -} - -// virtual -void LLSDMessageBuilder::nextBlock(const char* blockname) -{ - LLSD& block = mCurrentMessage[blockname]; - if(block.isUndefined()) - { - block[0] = LLSD::emptyMap(); - mCurrentBlock = &(block[0]); - } - else if(block.isArray()) - { - block[block.size()] = LLSD::emptyMap(); - mCurrentBlock = &(block[block.size() - 1]); - } - else - { - LL_ERRS() << "existing block not array" << LL_ENDL; - } -} - -// TODO: Remove this horror... -BOOL LLSDMessageBuilder::removeLastBlock() -{ - /* TODO: finish implementing this */ - return FALSE; -} - -void LLSDMessageBuilder::addBinaryData( - const char* varname, - const void* data, - S32 size) -{ - std::vector<U8> v; - v.resize(size); - memcpy(&(v[0]), reinterpret_cast<const U8*>(data), size); - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addS8(const char* varname, S8 v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addU8(const char* varname, U8 v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addS16(const char* varname, S16 v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addU16(const char* varname, U16 v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addF32(const char* varname, F32 v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addS32(const char* varname, S32 v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addU32(const char* varname, U32 v) -{ - (*mCurrentBlock)[varname] = ll_sd_from_U32(v); -} - -void LLSDMessageBuilder::addU64(const char* varname, U64 v) -{ - (*mCurrentBlock)[varname] = ll_sd_from_U64(v); -} - -void LLSDMessageBuilder::addF64(const char* varname, F64 v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addIPAddr(const char* varname, U32 v) -{ - (*mCurrentBlock)[varname] = ll_sd_from_ipaddr(v); -} - -void LLSDMessageBuilder::addIPPort(const char* varname, U16 v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::addBOOL(const char* varname, BOOL v) -{ - (*mCurrentBlock)[varname] = (v == TRUE); -} - -void LLSDMessageBuilder::addString(const char* varname, const char* v) -{ - if (v) - (*mCurrentBlock)[varname] = v; /* Flawfinder: ignore */ - else - (*mCurrentBlock)[varname] = ""; -} - -void LLSDMessageBuilder::addString(const char* varname, const std::string& v) -{ - if (v.size()) - (*mCurrentBlock)[varname] = v; - else - (*mCurrentBlock)[varname] = ""; -} - -void LLSDMessageBuilder::addVector3(const char* varname, const LLVector3& v) -{ - (*mCurrentBlock)[varname] = ll_sd_from_vector3(v); -} - -void LLSDMessageBuilder::addVector4(const char* varname, const LLVector4& v) -{ - (*mCurrentBlock)[varname] = ll_sd_from_vector4(v); -} - -void LLSDMessageBuilder::addVector3d(const char* varname, const LLVector3d& v) -{ - (*mCurrentBlock)[varname] = ll_sd_from_vector3d(v); -} - -void LLSDMessageBuilder::addQuat(const char* varname, const LLQuaternion& v) -{ - (*mCurrentBlock)[varname] = ll_sd_from_quaternion(v); -} - -void LLSDMessageBuilder::addUUID(const char* varname, const LLUUID& v) -{ - (*mCurrentBlock)[varname] = v; -} - -void LLSDMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length) -{ -} - -BOOL LLSDMessageBuilder::isMessageFull(const char* blockname) const -{ - return FALSE; -} - -U32 LLSDMessageBuilder::buildMessage(U8*, U32, U8) -{ - return 0; -} - -void LLSDMessageBuilder::copyFromMessageData(const LLMsgData& data) -{ - // copy the blocks - // counting variables used to encode multiple block info - S32 block_count = 0; - char* block_name = NULL; - - // loop through msg blocks to loop through variables, totalling up size - // data and filling the new (send) message - LLMsgData::msg_blk_data_map_t::const_iterator iter = - data.mMemberBlocks.begin(); - LLMsgData::msg_blk_data_map_t::const_iterator end = - data.mMemberBlocks.end(); - for(; iter != end; ++iter) - { - const LLMsgBlkData* mbci = iter->second; - if(!mbci) continue; - - // do we need to encode a block code? - if (block_count == 0) - { - block_count = mbci->mBlockNumber; - block_name = (char*)mbci->mName; - } - - // counting down mutliple blocks - block_count--; - - nextBlock(block_name); - - // now loop through the variables - LLMsgBlkData::msg_var_data_map_t::const_iterator dit = mbci->mMemberVarData.begin(); - LLMsgBlkData::msg_var_data_map_t::const_iterator dend = mbci->mMemberVarData.end(); - - for(; dit != dend; ++dit) - { - const LLMsgVarData& mvci = *dit; - const char* varname = mvci.getName(); - - switch(mvci.getType()) - { - case MVT_FIXED: - addBinaryData(varname, mvci.getData(), mvci.getSize()); - break; - - case MVT_VARIABLE: - { - const char end = ((const char*)mvci.getData())[mvci.getSize()-1]; // Ensure null terminated - if (mvci.getDataSize() == 1 && end == 0) - { - addString(varname, (const char*)mvci.getData()); - } - else - { - addBinaryData(varname, mvci.getData(), mvci.getSize()); - } - break; - } - - case MVT_U8: - addU8(varname, *(U8*)mvci.getData()); - break; - - case MVT_U16: - addU16(varname, *(U16*)mvci.getData()); - break; - - case MVT_U32: - addU32(varname, *(U32*)mvci.getData()); - break; - - case MVT_U64: - addU64(varname, *(U64*)mvci.getData()); - break; - - case MVT_S8: - addS8(varname, *(S8*)mvci.getData()); - break; - - case MVT_S16: - addS16(varname, *(S16*)mvci.getData()); - break; - - case MVT_S32: - addS32(varname, *(S32*)mvci.getData()); - break; - - // S64 not supported in LLSD so we just truncate it - case MVT_S64: - addS32(varname, (S32)*(S64*)mvci.getData()); - break; - - case MVT_F32: - addF32(varname, *(F32*)mvci.getData()); - break; - - case MVT_F64: - addF64(varname, *(F64*)mvci.getData()); - break; - - case MVT_LLVector3: - addVector3(varname, *(LLVector3*)mvci.getData()); - break; - - case MVT_LLVector3d: - addVector3d(varname, *(LLVector3d*)mvci.getData()); - break; - - case MVT_LLVector4: - addVector4(varname, *(LLVector4*)mvci.getData()); - break; - - case MVT_LLQuaternion: - { - LLVector3 v = *(LLVector3*)mvci.getData(); - LLQuaternion q; - q.unpackFromVector3(v); - addQuat(varname, q); - break; - } - - case MVT_LLUUID: - addUUID(varname, *(LLUUID*)mvci.getData()); - break; - - case MVT_BOOL: - addBOOL(varname, *(BOOL*)mvci.getData()); - break; - - case MVT_IP_ADDR: - addIPAddr(varname, *(U32*)mvci.getData()); - break; - - case MVT_IP_PORT: - addIPPort(varname, *(U16*)mvci.getData()); - break; - - case MVT_U16Vec3: - //treated as an array of 6 bytes - addBinaryData(varname, mvci.getData(), 6); - break; - - case MVT_U16Quat: - //treated as an array of 8 bytes - addBinaryData(varname, mvci.getData(), 8); - break; - - case MVT_S16Array: - addBinaryData(varname, mvci.getData(), mvci.getSize()); - break; - - default: - LL_WARNS() << "Unknown type in conversion of message to LLSD" << LL_ENDL; - break; - } - } - } -} - -//virtual -void LLSDMessageBuilder::copyFromLLSD(const LLSD& msg) -{ - mCurrentMessage = msg; - LL_DEBUGS() << LLSDNotationStreamer(mCurrentMessage) << LL_ENDL; -} - -const LLSD& LLSDMessageBuilder::getMessage() const -{ - return mCurrentMessage; -} - -//virtual -void LLSDMessageBuilder::setBuilt(BOOL b) { mbSBuilt = b; } - -//virtual -BOOL LLSDMessageBuilder::isBuilt() const {return mbSBuilt;} - -//virtual -BOOL LLSDMessageBuilder::isClear() const {return mbSClear;} - -//virtual -S32 LLSDMessageBuilder::getMessageSize() -{ - // babbage: size is unknown as message stored as LLSD. - // return non-zero if pending data, as send can be skipped for 0 size. - // return 1 to encourage senders checking size against splitting message. - return mCurrentMessage.size()? 1 : 0; -} - -//virtual -const char* LLSDMessageBuilder::getMessageName() const -{ - return mCurrentMessageName.c_str(); -} +/**
+ * @file llsdmessagebuilder.cpp
+ * @brief LLSDMessageBuilder class implementation.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+
+#include "llsdmessagebuilder.h"
+
+#include "llmessagetemplate.h"
+#include "llmath.h"
+#include "llquaternion.h"
+#include "llsdutil.h"
+#include "llsdutil_math.h"
+#include "llsdserialize.h"
+#include "u64.h"
+#include "v3dmath.h"
+#include "v3math.h"
+#include "v4math.h"
+
+LLSDMessageBuilder::LLSDMessageBuilder() :
+ mCurrentMessage(LLSD::emptyMap()),
+ mCurrentBlock(NULL),
+ mCurrentMessageName(""),
+ mCurrentBlockName(""),
+ mbSBuilt(false),
+ mbSClear(true)
+{
+}
+
+//virtual
+LLSDMessageBuilder::~LLSDMessageBuilder()
+{
+}
+
+
+// virtual
+void LLSDMessageBuilder::newMessage(const char* name)
+{
+ mbSBuilt = false;
+ mbSClear = false;
+
+ mCurrentMessage = LLSD::emptyMap();
+ mCurrentMessageName = (char*)name;
+}
+
+// virtual
+void LLSDMessageBuilder::clearMessage()
+{
+ mbSBuilt = false;
+ mbSClear = true;
+
+ mCurrentMessage = LLSD::emptyMap();
+ mCurrentMessageName = "";
+}
+
+// virtual
+void LLSDMessageBuilder::nextBlock(const char* blockname)
+{
+ LLSD& block = mCurrentMessage[blockname];
+ if(block.isUndefined())
+ {
+ block[0] = LLSD::emptyMap();
+ mCurrentBlock = &(block[0]);
+ }
+ else if(block.isArray())
+ {
+ block[block.size()] = LLSD::emptyMap();
+ mCurrentBlock = &(block[block.size() - 1]);
+ }
+ else
+ {
+ LL_ERRS() << "existing block not array" << LL_ENDL;
+ }
+}
+
+// TODO: Remove this horror...
+bool LLSDMessageBuilder::removeLastBlock()
+{
+ /* TODO: finish implementing this */
+ return false;
+}
+
+void LLSDMessageBuilder::addBinaryData(
+ const char* varname,
+ const void* data,
+ S32 size)
+{
+ std::vector<U8> v;
+ v.resize(size);
+ memcpy(&(v[0]), reinterpret_cast<const U8*>(data), size);
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addS8(const char* varname, S8 v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addU8(const char* varname, U8 v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addS16(const char* varname, S16 v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addU16(const char* varname, U16 v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addF32(const char* varname, F32 v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addS32(const char* varname, S32 v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addU32(const char* varname, U32 v)
+{
+ (*mCurrentBlock)[varname] = ll_sd_from_U32(v);
+}
+
+void LLSDMessageBuilder::addU64(const char* varname, U64 v)
+{
+ (*mCurrentBlock)[varname] = ll_sd_from_U64(v);
+}
+
+void LLSDMessageBuilder::addF64(const char* varname, F64 v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addIPAddr(const char* varname, U32 v)
+{
+ (*mCurrentBlock)[varname] = ll_sd_from_ipaddr(v);
+}
+
+void LLSDMessageBuilder::addIPPort(const char* varname, U16 v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addBOOL(const char* varname, bool v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::addString(const char* varname, const char* v)
+{
+ if (v)
+ (*mCurrentBlock)[varname] = v; /* Flawfinder: ignore */
+ else
+ (*mCurrentBlock)[varname] = "";
+}
+
+void LLSDMessageBuilder::addString(const char* varname, const std::string& v)
+{
+ if (v.size())
+ (*mCurrentBlock)[varname] = v;
+ else
+ (*mCurrentBlock)[varname] = "";
+}
+
+void LLSDMessageBuilder::addVector3(const char* varname, const LLVector3& v)
+{
+ (*mCurrentBlock)[varname] = ll_sd_from_vector3(v);
+}
+
+void LLSDMessageBuilder::addVector4(const char* varname, const LLVector4& v)
+{
+ (*mCurrentBlock)[varname] = ll_sd_from_vector4(v);
+}
+
+void LLSDMessageBuilder::addVector3d(const char* varname, const LLVector3d& v)
+{
+ (*mCurrentBlock)[varname] = ll_sd_from_vector3d(v);
+}
+
+void LLSDMessageBuilder::addQuat(const char* varname, const LLQuaternion& v)
+{
+ (*mCurrentBlock)[varname] = ll_sd_from_quaternion(v);
+}
+
+void LLSDMessageBuilder::addUUID(const char* varname, const LLUUID& v)
+{
+ (*mCurrentBlock)[varname] = v;
+}
+
+void LLSDMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length)
+{
+}
+
+bool LLSDMessageBuilder::isMessageFull(const char* blockname) const
+{
+ return false;
+}
+
+U32 LLSDMessageBuilder::buildMessage(U8*, U32, U8)
+{
+ return 0;
+}
+
+void LLSDMessageBuilder::copyFromMessageData(const LLMsgData& data)
+{
+ // copy the blocks
+ // counting variables used to encode multiple block info
+ S32 block_count = 0;
+ char* block_name = NULL;
+
+ // loop through msg blocks to loop through variables, totalling up size
+ // data and filling the new (send) message
+ LLMsgData::msg_blk_data_map_t::const_iterator iter =
+ data.mMemberBlocks.begin();
+ LLMsgData::msg_blk_data_map_t::const_iterator end =
+ data.mMemberBlocks.end();
+ for(; iter != end; ++iter)
+ {
+ const LLMsgBlkData* mbci = iter->second;
+ if(!mbci) continue;
+
+ // do we need to encode a block code?
+ if (block_count == 0)
+ {
+ block_count = mbci->mBlockNumber;
+ block_name = (char*)mbci->mName;
+ }
+
+ // counting down mutliple blocks
+ block_count--;
+
+ nextBlock(block_name);
+
+ // now loop through the variables
+ LLMsgBlkData::msg_var_data_map_t::const_iterator dit = mbci->mMemberVarData.begin();
+ LLMsgBlkData::msg_var_data_map_t::const_iterator dend = mbci->mMemberVarData.end();
+
+ for(; dit != dend; ++dit)
+ {
+ const LLMsgVarData& mvci = *dit;
+ const char* varname = mvci.getName();
+
+ switch(mvci.getType())
+ {
+ case MVT_FIXED:
+ addBinaryData(varname, mvci.getData(), mvci.getSize());
+ break;
+
+ case MVT_VARIABLE:
+ {
+ const char end = ((const char*)mvci.getData())[mvci.getSize()-1]; // Ensure null terminated
+ if (mvci.getDataSize() == 1 && end == 0)
+ {
+ addString(varname, (const char*)mvci.getData());
+ }
+ else
+ {
+ addBinaryData(varname, mvci.getData(), mvci.getSize());
+ }
+ break;
+ }
+
+ case MVT_U8:
+ addU8(varname, *(U8*)mvci.getData());
+ break;
+
+ case MVT_U16:
+ addU16(varname, *(U16*)mvci.getData());
+ break;
+
+ case MVT_U32:
+ addU32(varname, *(U32*)mvci.getData());
+ break;
+
+ case MVT_U64:
+ addU64(varname, *(U64*)mvci.getData());
+ break;
+
+ case MVT_S8:
+ addS8(varname, *(S8*)mvci.getData());
+ break;
+
+ case MVT_S16:
+ addS16(varname, *(S16*)mvci.getData());
+ break;
+
+ case MVT_S32:
+ addS32(varname, *(S32*)mvci.getData());
+ break;
+
+ // S64 not supported in LLSD so we just truncate it
+ case MVT_S64:
+ addS32(varname, (S32)*(S64*)mvci.getData());
+ break;
+
+ case MVT_F32:
+ addF32(varname, *(F32*)mvci.getData());
+ break;
+
+ case MVT_F64:
+ addF64(varname, *(F64*)mvci.getData());
+ break;
+
+ case MVT_LLVector3:
+ addVector3(varname, *(LLVector3*)mvci.getData());
+ break;
+
+ case MVT_LLVector3d:
+ addVector3d(varname, *(LLVector3d*)mvci.getData());
+ break;
+
+ case MVT_LLVector4:
+ addVector4(varname, *(LLVector4*)mvci.getData());
+ break;
+
+ case MVT_LLQuaternion:
+ {
+ LLVector3 v = *(LLVector3*)mvci.getData();
+ LLQuaternion q;
+ q.unpackFromVector3(v);
+ addQuat(varname, q);
+ break;
+ }
+
+ case MVT_LLUUID:
+ addUUID(varname, *(LLUUID*)mvci.getData());
+ break;
+
+ case MVT_BOOL:
+ addBOOL(varname, *(bool*)mvci.getData());
+ break;
+
+ case MVT_IP_ADDR:
+ addIPAddr(varname, *(U32*)mvci.getData());
+ break;
+
+ case MVT_IP_PORT:
+ addIPPort(varname, *(U16*)mvci.getData());
+ break;
+
+ case MVT_U16Vec3:
+ //treated as an array of 6 bytes
+ addBinaryData(varname, mvci.getData(), 6);
+ break;
+
+ case MVT_U16Quat:
+ //treated as an array of 8 bytes
+ addBinaryData(varname, mvci.getData(), 8);
+ break;
+
+ case MVT_S16Array:
+ addBinaryData(varname, mvci.getData(), mvci.getSize());
+ break;
+
+ default:
+ LL_WARNS() << "Unknown type in conversion of message to LLSD" << LL_ENDL;
+ break;
+ }
+ }
+ }
+}
+
+//virtual
+void LLSDMessageBuilder::copyFromLLSD(const LLSD& msg)
+{
+ mCurrentMessage = msg;
+ LL_DEBUGS() << LLSDNotationStreamer(mCurrentMessage) << LL_ENDL;
+}
+
+const LLSD& LLSDMessageBuilder::getMessage() const
+{
+ return mCurrentMessage;
+}
+
+//virtual
+void LLSDMessageBuilder::setBuilt(bool b) { mbSBuilt = b; }
+
+//virtual
+bool LLSDMessageBuilder::isBuilt() const {return mbSBuilt;}
+
+//virtual
+bool LLSDMessageBuilder::isClear() const {return mbSClear;}
+
+//virtual
+S32 LLSDMessageBuilder::getMessageSize()
+{
+ // babbage: size is unknown as message stored as LLSD.
+ // return non-zero if pending data, as send can be skipped for 0 size.
+ // return 1 to encourage senders checking size against splitting message.
+ return mCurrentMessage.size()? 1 : 0;
+}
+
+//virtual
+const char* LLSDMessageBuilder::getMessageName() const
+{
+ return mCurrentMessageName.c_str();
+}
diff --git a/indra/llmessage/llsdmessagebuilder.h b/indra/llmessage/llsdmessagebuilder.h index 82c70202ee..8eac962ba0 100644 --- a/indra/llmessage/llsdmessagebuilder.h +++ b/indra/llmessage/llsdmessagebuilder.h @@ -1,126 +1,126 @@ -/** - * @file llsdmessagebuilder.h - * @brief Declaration of LLSDMessageBuilder class. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLSDMESSAGEBUILDER_H -#define LL_LLSDMESSAGEBUILDER_H - -#include <map> - -#include "llmessagebuilder.h" -#include "llmsgvariabletype.h" -#include "llsd.h" - -class LLMessageTemplate; -class LLMsgData; - -class LLSDMessageBuilder : public LLMessageBuilder -{ -public: - - //CLASS_LOG_TYPE(LLSDMessageBuilder); - - LLSDMessageBuilder(); - virtual ~LLSDMessageBuilder(); - - virtual void newMessage(const char* name); - - virtual void nextBlock(const char* blockname); - virtual BOOL removeLastBlock(); // TODO: babbage: remove this horror... - - /** All add* methods expect pointers to canonical varname strings. */ - virtual void addBinaryData( - const char* varname, - const void* data, - S32 size); - virtual void addBOOL(const char* varname, BOOL b); - virtual void addS8(const char* varname, S8 s); - virtual void addU8(const char* varname, U8 u); - virtual void addS16(const char* varname, S16 i); - virtual void addU16(const char* varname, U16 i); - virtual void addF32(const char* varname, F32 f); - virtual void addS32(const char* varname, S32 s); - virtual void addU32(const char* varname, U32 u); - virtual void addU64(const char* varname, U64 lu); - virtual void addF64(const char* varname, F64 d); - virtual void addVector3(const char* varname, const LLVector3& vec); - virtual void addVector4(const char* varname, const LLVector4& vec); - virtual void addVector3d(const char* varname, const LLVector3d& vec); - virtual void addQuat(const char* varname, const LLQuaternion& quat); - virtual void addUUID(const char* varname, const LLUUID& uuid); - virtual void addIPAddr(const char* varname, const U32 ip); - virtual void addIPPort(const char* varname, const U16 port); - virtual void addString(const char* varname, const char* s); - virtual void addString(const char* varname, const std::string& s); - - virtual BOOL isMessageFull(const char* blockname) const; - virtual void compressMessage(U8*& buf_ptr, U32& buffer_length); - - virtual BOOL isBuilt() const; - virtual BOOL isClear() const; - virtual U32 buildMessage(U8* buffer, U32 buffer_size, U8 offset_to_data); - /**< Null implementation which returns 0. */ - - virtual void clearMessage(); - - // TODO: babbage: remove this horror. - virtual void setBuilt(BOOL b); - - virtual S32 getMessageSize(); - virtual const char* getMessageName() const; - - virtual void copyFromMessageData(const LLMsgData& data); - - virtual void copyFromLLSD(const LLSD& msg); - - const LLSD& getMessage() const; -private: - - /* mCurrentMessage is of the following format: - mCurrentMessage = { 'block_name1' : [ { 'block1_field1' : 'b1f1_data', - 'block1_field2' : 'b1f2_data', - ... - 'block1_fieldn' : 'b1fn_data'}, - { 'block2_field1' : 'b2f1_data', - 'block2_field2' : 'b2f2_data', - ... - 'block2_fieldn' : 'b2fn_data'}, - ... - { 'blockm_field1' : 'bmf1_data', - 'blockm_field2' : 'bmf2_data', - ... - 'blockm_fieldn' : 'bmfn_data'} ], - 'block_name2' : ..., - ... - 'block_namem' } */ - LLSD mCurrentMessage; - LLSD* mCurrentBlock; - std::string mCurrentMessageName; - std::string mCurrentBlockName; - BOOL mbSBuilt; - BOOL mbSClear; -}; - -#endif // LL_LLSDMESSAGEBUILDER_H +/**
+ * @file llsdmessagebuilder.h
+ * @brief Declaration of LLSDMessageBuilder class.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#ifndef LL_LLSDMESSAGEBUILDER_H
+#define LL_LLSDMESSAGEBUILDER_H
+
+#include <map>
+
+#include "llmessagebuilder.h"
+#include "llmsgvariabletype.h"
+#include "llsd.h"
+
+class LLMessageTemplate;
+class LLMsgData;
+
+class LLSDMessageBuilder : public LLMessageBuilder
+{
+public:
+
+ //CLASS_LOG_TYPE(LLSDMessageBuilder);
+
+ LLSDMessageBuilder();
+ virtual ~LLSDMessageBuilder();
+
+ virtual void newMessage(const char* name);
+
+ virtual void nextBlock(const char* blockname);
+ virtual bool removeLastBlock(); // TODO: babbage: remove this horror...
+
+ /** All add* methods expect pointers to canonical varname strings. */
+ virtual void addBinaryData(
+ const char* varname,
+ const void* data,
+ S32 size);
+ virtual void addBOOL(const char* varname, bool b);
+ virtual void addS8(const char* varname, S8 s);
+ virtual void addU8(const char* varname, U8 u);
+ virtual void addS16(const char* varname, S16 i);
+ virtual void addU16(const char* varname, U16 i);
+ virtual void addF32(const char* varname, F32 f);
+ virtual void addS32(const char* varname, S32 s);
+ virtual void addU32(const char* varname, U32 u);
+ virtual void addU64(const char* varname, U64 lu);
+ virtual void addF64(const char* varname, F64 d);
+ virtual void addVector3(const char* varname, const LLVector3& vec);
+ virtual void addVector4(const char* varname, const LLVector4& vec);
+ virtual void addVector3d(const char* varname, const LLVector3d& vec);
+ virtual void addQuat(const char* varname, const LLQuaternion& quat);
+ virtual void addUUID(const char* varname, const LLUUID& uuid);
+ virtual void addIPAddr(const char* varname, const U32 ip);
+ virtual void addIPPort(const char* varname, const U16 port);
+ virtual void addString(const char* varname, const char* s);
+ virtual void addString(const char* varname, const std::string& s);
+
+ virtual bool isMessageFull(const char* blockname) const;
+ virtual void compressMessage(U8*& buf_ptr, U32& buffer_length);
+
+ virtual bool isBuilt() const;
+ virtual bool isClear() const;
+ virtual U32 buildMessage(U8* buffer, U32 buffer_size, U8 offset_to_data);
+ /**< Null implementation which returns 0. */
+
+ virtual void clearMessage();
+
+ // TODO: babbage: remove this horror.
+ virtual void setBuilt(bool b);
+
+ virtual S32 getMessageSize();
+ virtual const char* getMessageName() const;
+
+ virtual void copyFromMessageData(const LLMsgData& data);
+
+ virtual void copyFromLLSD(const LLSD& msg);
+
+ const LLSD& getMessage() const;
+private:
+
+ /* mCurrentMessage is of the following format:
+ mCurrentMessage = { 'block_name1' : [ { 'block1_field1' : 'b1f1_data',
+ 'block1_field2' : 'b1f2_data',
+ ...
+ 'block1_fieldn' : 'b1fn_data'},
+ { 'block2_field1' : 'b2f1_data',
+ 'block2_field2' : 'b2f2_data',
+ ...
+ 'block2_fieldn' : 'b2fn_data'},
+ ...
+ { 'blockm_field1' : 'bmf1_data',
+ 'blockm_field2' : 'bmf2_data',
+ ...
+ 'blockm_fieldn' : 'bmfn_data'} ],
+ 'block_name2' : ...,
+ ...
+ 'block_namem' } */
+ LLSD mCurrentMessage;
+ LLSD* mCurrentBlock;
+ std::string mCurrentMessageName;
+ std::string mCurrentBlockName;
+ bool mbSBuilt;
+ bool mbSClear;
+};
+
+#endif // LL_LLSDMESSAGEBUILDER_H
diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp index 00d962357b..c0e8f634b2 100644 --- a/indra/llmessage/llsdmessagereader.cpp +++ b/indra/llmessage/llsdmessagereader.cpp @@ -1,344 +1,344 @@ -/** - * @file llsdmessagereader.cpp - * @brief LLSDMessageReader class implementation. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "linden_common.h" - -#include "llsdmessagereader.h" - -#include "llmessagebuilder.h" -#include "llsdmessagebuilder.h" -#include "llsdutil.h" - -#include "llsdutil_math.h" -#include "v3math.h" -#include "v4math.h" -#include "v3dmath.h" -#include "v2math.h" -#include "llquaternion.h" -#include "v4color.h" - -LLSDMessageReader::LLSDMessageReader() : - mMessageName(NULL) -{ -} - -//virtual -LLSDMessageReader::~LLSDMessageReader() -{ -} - - -LLSD getLLSD(const LLSD& input, const char* block, const char* var, S32 blocknum) -{ - // babbage: log error to LL_ERRS() if variable not found to mimic - // LLTemplateMessageReader::getData behaviour - if(NULL == block) - { - LL_ERRS() << "NULL block name" << LL_ENDL; - return LLSD(); - } - if(NULL == var) - { - LL_ERRS() << "NULL var name" << LL_ENDL; - return LLSD(); - } - if(! input[block].isArray()) - { - // NOTE: babbage: need to return default for missing blocks to allow - // backwards/forwards compatibility - handlers must cope with default - // values. - LL_WARNS() << "block " << block << " not found" << LL_ENDL; - return LLSD(); - } - - LLSD result = input[block][blocknum][var]; - if(result.isUndefined()) - { - // NOTE: babbage: need to return default for missing vars to allow - // backwards/forwards compatibility - handlers must cope with default - // values. - LL_WARNS() << "var " << var << " not found" << LL_ENDL; - } - return result; -} - -//virtual -void LLSDMessageReader::getBinaryData(const char *block, const char *var, - void *datap, S32 size, S32 blocknum, - S32 max_size) -{ - std::vector<U8> data = getLLSD(mMessage, block, var, blocknum); - S32 data_size = (S32)data.size(); - - if (size && data_size != size) - { - return; - } - - if (max_size < data_size) - { - data_size = max_size; - } - - // Calls to memcpy will fail if data_size is not positive. - // Phoenix 2009-02-27 - if(data_size <= 0) - { - return; - } - memcpy(datap, &(data[0]), data_size); -} - -//virtual -void LLSDMessageReader::getBOOL(const char *block, const char *var, - BOOL &data, - S32 blocknum) -{ - data = getLLSD(mMessage, block, var, blocknum); -} - -//virtual -void LLSDMessageReader::getS8(const char *block, const char *var, S8 &data, - S32 blocknum) -{ - data = getLLSD(mMessage, block, var, blocknum).asInteger(); -} - -//virtual -void LLSDMessageReader::getU8(const char *block, const char *var, U8 &data, - S32 blocknum) -{ - data = getLLSD(mMessage, block, var, blocknum).asInteger(); -} - -//virtual -void LLSDMessageReader::getS16(const char *block, const char *var, S16 &data, - S32 blocknum) -{ - data = getLLSD(mMessage, block, var, blocknum).asInteger(); -} - -//virtual -void LLSDMessageReader::getU16(const char *block, const char *var, U16 &data, - S32 blocknum) -{ - data = getLLSD(mMessage, block, var, blocknum).asInteger(); -} - -//virtual -void LLSDMessageReader::getS32(const char *block, const char *var, S32 &data, - S32 blocknum) -{ - data = getLLSD(mMessage, block, var, blocknum); -} - -//virtual -void LLSDMessageReader::getF32(const char *block, const char *var, F32 &data, - S32 blocknum) -{ - data = (F32)getLLSD(mMessage, block, var, blocknum).asReal(); -} - -//virtual -void LLSDMessageReader::getU32(const char *block, const char *var, U32 &data, - S32 blocknum) -{ - data = ll_U32_from_sd(getLLSD(mMessage, block, var, blocknum)); -} - -//virtual -void LLSDMessageReader::getU64(const char *block, const char *var, - U64 &data, S32 blocknum) -{ - data = ll_U64_from_sd(getLLSD(mMessage, block, var, blocknum)); -} - -//virtual -void LLSDMessageReader::getF64(const char *block, const char *var, - F64 &data, S32 blocknum) -{ - data = getLLSD(mMessage, block, var, blocknum); -} - -//virtual -void LLSDMessageReader::getVector3(const char *block, const char *var, - LLVector3 &vec, S32 blocknum) -{ - vec = ll_vector3_from_sd(getLLSD(mMessage, block, var, blocknum)); -} - -//virtual -void LLSDMessageReader::getVector4(const char *block, const char *var, - LLVector4 &vec, S32 blocknum) -{ - vec = ll_vector4_from_sd(getLLSD(mMessage, block, var, blocknum)); -} - -//virtual -void LLSDMessageReader::getVector3d(const char *block, const char *var, - LLVector3d &vec, S32 blocknum) -{ - vec = ll_vector3d_from_sd(getLLSD(mMessage, block, var, blocknum)); -} - -//virtual -void LLSDMessageReader::getQuat(const char *block, const char *var, - LLQuaternion &q, S32 blocknum) -{ - q = ll_quaternion_from_sd(getLLSD(mMessage, block, var, blocknum)); -} - -//virtual -void LLSDMessageReader::getUUID(const char *block, const char *var, - LLUUID &uuid, S32 blocknum) -{ - uuid = getLLSD(mMessage, block, var, blocknum); -} - -//virtual -void LLSDMessageReader::getIPAddr(const char *block, const char *var, - U32 &ip, S32 blocknum) -{ - ip = ll_ipaddr_from_sd(getLLSD(mMessage, block, var, blocknum)); -} - -//virtual -void LLSDMessageReader::getIPPort(const char *block, const char *var, - U16 &port, S32 blocknum) -{ - port = getLLSD(mMessage, block, var, blocknum).asInteger(); -} - -//virtual -void LLSDMessageReader::getString(const char *block, const char *var, - S32 buffer_size, char *buffer, S32 blocknum) -{ - if(buffer_size <= 0) - { - LL_WARNS() << "buffer_size <= 0" << LL_ENDL; - return; - } - std::string data = getLLSD(mMessage, block, var, blocknum); - S32 data_size = data.size(); - if (data_size >= buffer_size) - { - data_size = buffer_size - 1; - } - memcpy(buffer, data.data(), data_size); - buffer[data_size] = '\0'; -} - -//virtual -void LLSDMessageReader::getString(const char *block, const char *var, - std::string& outstr, S32 blocknum) -{ - outstr = getLLSD(mMessage, block, var, blocknum).asString(); -} - -//virtual -S32 LLSDMessageReader::getNumberOfBlocks(const char *blockname) -{ - return mMessage[blockname].size(); -} - -S32 getElementSize(const LLSD& llsd) -{ - LLSD::Type type = llsd.type(); - switch(type) - { - case LLSD::TypeBoolean: - return sizeof(bool); - case LLSD::TypeInteger: - return sizeof(S32); - case LLSD::TypeReal: - return sizeof(F64); - case LLSD::TypeString: - return llsd.size(); - case LLSD::TypeUUID: - return sizeof(LLUUID); - case LLSD::TypeDate: - return sizeof(LLDate); - case LLSD::TypeURI: - return sizeof(LLURI); - case LLSD::TypeBinary: - { - std::vector<U8> data = llsd; - return data.size() * sizeof(U8); - } - case LLSD::TypeMap: - case LLSD::TypeArray: - case LLSD::TypeUndefined: - default: // TypeLLSDTypeEnd, TypeLLSDNumTypes, etc. - return 0; - } - //return 0; -} - -//virtual -//Mainly used to find size of binary block of data -S32 LLSDMessageReader::getSize(const char *blockname, const char *varname) -{ - return getElementSize(mMessage[blockname][0][varname]); -} - - -//virtual -S32 LLSDMessageReader::getSize(const char *blockname, S32 blocknum, - const char *varname) -{ - return getElementSize(mMessage[blockname][blocknum][varname]); -} - -//virtual -void LLSDMessageReader::clearMessage() -{ - mMessage = LLSD(); -} - -//virtual -const char* LLSDMessageReader::getMessageName() const -{ - return mMessageName; -} - -// virtual -S32 LLSDMessageReader::getMessageSize() const -{ - return 0; -} - -//virtual -void LLSDMessageReader::copyToBuilder(LLMessageBuilder& builder) const -{ - builder.copyFromLLSD(mMessage); -} - -void LLSDMessageReader::setMessage(const char* name, const LLSD& message) -{ - mMessageName = name; - // TODO: Validate - mMessage = message; -} +/**
+ * @file llsdmessagereader.cpp
+ * @brief LLSDMessageReader class implementation.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+
+#include "llsdmessagereader.h"
+
+#include "llmessagebuilder.h"
+#include "llsdmessagebuilder.h"
+#include "llsdutil.h"
+
+#include "llsdutil_math.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "v3dmath.h"
+#include "v2math.h"
+#include "llquaternion.h"
+#include "v4color.h"
+
+LLSDMessageReader::LLSDMessageReader() :
+ mMessageName(NULL)
+{
+}
+
+//virtual
+LLSDMessageReader::~LLSDMessageReader()
+{
+}
+
+
+LLSD getLLSD(const LLSD& input, const char* block, const char* var, S32 blocknum)
+{
+ // babbage: log error to LL_ERRS() if variable not found to mimic
+ // LLTemplateMessageReader::getData behaviour
+ if(NULL == block)
+ {
+ LL_ERRS() << "NULL block name" << LL_ENDL;
+ return LLSD();
+ }
+ if(NULL == var)
+ {
+ LL_ERRS() << "NULL var name" << LL_ENDL;
+ return LLSD();
+ }
+ if(! input[block].isArray())
+ {
+ // NOTE: babbage: need to return default for missing blocks to allow
+ // backwards/forwards compatibility - handlers must cope with default
+ // values.
+ LL_WARNS() << "block " << block << " not found" << LL_ENDL;
+ return LLSD();
+ }
+
+ LLSD result = input[block][blocknum][var];
+ if(result.isUndefined())
+ {
+ // NOTE: babbage: need to return default for missing vars to allow
+ // backwards/forwards compatibility - handlers must cope with default
+ // values.
+ LL_WARNS() << "var " << var << " not found" << LL_ENDL;
+ }
+ return result;
+}
+
+//virtual
+void LLSDMessageReader::getBinaryData(const char *block, const char *var,
+ void *datap, S32 size, S32 blocknum,
+ S32 max_size)
+{
+ std::vector<U8> data = getLLSD(mMessage, block, var, blocknum);
+ S32 data_size = (S32)data.size();
+
+ if (size && data_size != size)
+ {
+ return;
+ }
+
+ if (max_size < data_size)
+ {
+ data_size = max_size;
+ }
+
+ // Calls to memcpy will fail if data_size is not positive.
+ // Phoenix 2009-02-27
+ if(data_size <= 0)
+ {
+ return;
+ }
+ memcpy(datap, &(data[0]), data_size);
+}
+
+//virtual
+void LLSDMessageReader::getBOOL(const char *block, const char *var,
+ bool &data,
+ S32 blocknum)
+{
+ data = getLLSD(mMessage, block, var, blocknum);
+}
+
+//virtual
+void LLSDMessageReader::getS8(const char *block, const char *var, S8 &data,
+ S32 blocknum)
+{
+ data = getLLSD(mMessage, block, var, blocknum).asInteger();
+}
+
+//virtual
+void LLSDMessageReader::getU8(const char *block, const char *var, U8 &data,
+ S32 blocknum)
+{
+ data = getLLSD(mMessage, block, var, blocknum).asInteger();
+}
+
+//virtual
+void LLSDMessageReader::getS16(const char *block, const char *var, S16 &data,
+ S32 blocknum)
+{
+ data = getLLSD(mMessage, block, var, blocknum).asInteger();
+}
+
+//virtual
+void LLSDMessageReader::getU16(const char *block, const char *var, U16 &data,
+ S32 blocknum)
+{
+ data = getLLSD(mMessage, block, var, blocknum).asInteger();
+}
+
+//virtual
+void LLSDMessageReader::getS32(const char *block, const char *var, S32 &data,
+ S32 blocknum)
+{
+ data = getLLSD(mMessage, block, var, blocknum);
+}
+
+//virtual
+void LLSDMessageReader::getF32(const char *block, const char *var, F32 &data,
+ S32 blocknum)
+{
+ data = (F32)getLLSD(mMessage, block, var, blocknum).asReal();
+}
+
+//virtual
+void LLSDMessageReader::getU32(const char *block, const char *var, U32 &data,
+ S32 blocknum)
+{
+ data = ll_U32_from_sd(getLLSD(mMessage, block, var, blocknum));
+}
+
+//virtual
+void LLSDMessageReader::getU64(const char *block, const char *var,
+ U64 &data, S32 blocknum)
+{
+ data = ll_U64_from_sd(getLLSD(mMessage, block, var, blocknum));
+}
+
+//virtual
+void LLSDMessageReader::getF64(const char *block, const char *var,
+ F64 &data, S32 blocknum)
+{
+ data = getLLSD(mMessage, block, var, blocknum);
+}
+
+//virtual
+void LLSDMessageReader::getVector3(const char *block, const char *var,
+ LLVector3 &vec, S32 blocknum)
+{
+ vec = ll_vector3_from_sd(getLLSD(mMessage, block, var, blocknum));
+}
+
+//virtual
+void LLSDMessageReader::getVector4(const char *block, const char *var,
+ LLVector4 &vec, S32 blocknum)
+{
+ vec = ll_vector4_from_sd(getLLSD(mMessage, block, var, blocknum));
+}
+
+//virtual
+void LLSDMessageReader::getVector3d(const char *block, const char *var,
+ LLVector3d &vec, S32 blocknum)
+{
+ vec = ll_vector3d_from_sd(getLLSD(mMessage, block, var, blocknum));
+}
+
+//virtual
+void LLSDMessageReader::getQuat(const char *block, const char *var,
+ LLQuaternion &q, S32 blocknum)
+{
+ q = ll_quaternion_from_sd(getLLSD(mMessage, block, var, blocknum));
+}
+
+//virtual
+void LLSDMessageReader::getUUID(const char *block, const char *var,
+ LLUUID &uuid, S32 blocknum)
+{
+ uuid = getLLSD(mMessage, block, var, blocknum);
+}
+
+//virtual
+void LLSDMessageReader::getIPAddr(const char *block, const char *var,
+ U32 &ip, S32 blocknum)
+{
+ ip = ll_ipaddr_from_sd(getLLSD(mMessage, block, var, blocknum));
+}
+
+//virtual
+void LLSDMessageReader::getIPPort(const char *block, const char *var,
+ U16 &port, S32 blocknum)
+{
+ port = getLLSD(mMessage, block, var, blocknum).asInteger();
+}
+
+//virtual
+void LLSDMessageReader::getString(const char *block, const char *var,
+ S32 buffer_size, char *buffer, S32 blocknum)
+{
+ if(buffer_size <= 0)
+ {
+ LL_WARNS() << "buffer_size <= 0" << LL_ENDL;
+ return;
+ }
+ std::string data = getLLSD(mMessage, block, var, blocknum);
+ S32 data_size = data.size();
+ if (data_size >= buffer_size)
+ {
+ data_size = buffer_size - 1;
+ }
+ memcpy(buffer, data.data(), data_size);
+ buffer[data_size] = '\0';
+}
+
+//virtual
+void LLSDMessageReader::getString(const char *block, const char *var,
+ std::string& outstr, S32 blocknum)
+{
+ outstr = getLLSD(mMessage, block, var, blocknum).asString();
+}
+
+//virtual
+S32 LLSDMessageReader::getNumberOfBlocks(const char *blockname)
+{
+ return mMessage[blockname].size();
+}
+
+S32 getElementSize(const LLSD& llsd)
+{
+ LLSD::Type type = llsd.type();
+ switch(type)
+ {
+ case LLSD::TypeBoolean:
+ return sizeof(bool);
+ case LLSD::TypeInteger:
+ return sizeof(S32);
+ case LLSD::TypeReal:
+ return sizeof(F64);
+ case LLSD::TypeString:
+ return llsd.size();
+ case LLSD::TypeUUID:
+ return sizeof(LLUUID);
+ case LLSD::TypeDate:
+ return sizeof(LLDate);
+ case LLSD::TypeURI:
+ return sizeof(LLURI);
+ case LLSD::TypeBinary:
+ {
+ std::vector<U8> data = llsd;
+ return data.size() * sizeof(U8);
+ }
+ case LLSD::TypeMap:
+ case LLSD::TypeArray:
+ case LLSD::TypeUndefined:
+ default: // TypeLLSDTypeEnd, TypeLLSDNumTypes, etc.
+ return 0;
+ }
+ //return 0;
+}
+
+//virtual
+//Mainly used to find size of binary block of data
+S32 LLSDMessageReader::getSize(const char *blockname, const char *varname)
+{
+ return getElementSize(mMessage[blockname][0][varname]);
+}
+
+
+//virtual
+S32 LLSDMessageReader::getSize(const char *blockname, S32 blocknum,
+ const char *varname)
+{
+ return getElementSize(mMessage[blockname][blocknum][varname]);
+}
+
+//virtual
+void LLSDMessageReader::clearMessage()
+{
+ mMessage = LLSD();
+}
+
+//virtual
+const char* LLSDMessageReader::getMessageName() const
+{
+ return mMessageName;
+}
+
+// virtual
+S32 LLSDMessageReader::getMessageSize() const
+{
+ return 0;
+}
+
+//virtual
+void LLSDMessageReader::copyToBuilder(LLMessageBuilder& builder) const
+{
+ builder.copyFromLLSD(mMessage);
+}
+
+void LLSDMessageReader::setMessage(const char* name, const LLSD& message)
+{
+ mMessageName = name;
+ // TODO: Validate
+ mMessage = message;
+}
diff --git a/indra/llmessage/llsdmessagereader.h b/indra/llmessage/llsdmessagereader.h index 8f84c679ba..510730c115 100644 --- a/indra/llmessage/llsdmessagereader.h +++ b/indra/llmessage/llsdmessagereader.h @@ -1,108 +1,108 @@ -/** - * @file llsdmessagereader.h - * @brief LLSDMessageReader class Declaration - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLSDMESSAGEREADER_H -#define LL_LLSDMESSAGEREADER_H - -#include "llmessagereader.h" -#include "llsd.h" - -#include <map> - -class LLMessageTemplate; -class LLMsgData; - -class LLSDMessageReader : public LLMessageReader -{ -public: - - LLSDMessageReader(); - virtual ~LLSDMessageReader(); - - /** All get* methods expect pointers to canonical strings. */ - virtual void getBinaryData(const char *block, const char *var, - void *datap, S32 size, S32 blocknum = 0, - S32 max_size = S32_MAX); - virtual void getBOOL(const char *block, const char *var, BOOL &data, - S32 blocknum = 0); - virtual void getS8(const char *block, const char *var, S8 &data, - S32 blocknum = 0); - virtual void getU8(const char *block, const char *var, U8 &data, - S32 blocknum = 0); - virtual void getS16(const char *block, const char *var, S16 &data, - S32 blocknum = 0); - virtual void getU16(const char *block, const char *var, U16 &data, - S32 blocknum = 0); - virtual void getS32(const char *block, const char *var, S32 &data, - S32 blocknum = 0); - virtual void getF32(const char *block, const char *var, F32 &data, - S32 blocknum = 0); - virtual void getU32(const char *block, const char *var, U32 &data, - S32 blocknum = 0); - virtual void getU64(const char *block, const char *var, U64 &data, - S32 blocknum = 0); - virtual void getF64(const char *block, const char *var, F64 &data, - S32 blocknum = 0); - virtual void getVector3(const char *block, const char *var, - LLVector3 &vec, S32 blocknum = 0); - virtual void getVector4(const char *block, const char *var, - LLVector4 &vec, S32 blocknum = 0); - virtual void getVector3d(const char *block, const char *var, - LLVector3d &vec, S32 blocknum = 0); - virtual void getQuat(const char *block, const char *var, LLQuaternion &q, - S32 blocknum = 0); - virtual void getUUID(const char *block, const char *var, LLUUID &uuid, - S32 blocknum = 0); - virtual void getIPAddr(const char *block, const char *var, U32 &ip, - S32 blocknum = 0); - virtual void getIPPort(const char *block, const char *var, U16 &port, - S32 blocknum = 0); - virtual void getString(const char *block, const char *var, - S32 buffer_size, char *buffer, S32 blocknum = 0); - virtual void getString(const char *block, const char *var, std::string& outstr, - S32 blocknum = 0); - - virtual S32 getNumberOfBlocks(const char *blockname); - virtual S32 getSize(const char *blockname, const char *varname); - virtual S32 getSize(const char *blockname, S32 blocknum, - const char *varname); - - virtual void clearMessage(); - - virtual const char* getMessageName() const; - virtual S32 getMessageSize() const; - - virtual void copyToBuilder(LLMessageBuilder&) const; - - /** Expects a pointer to a canonical name string */ - void setMessage(const char* name, const LLSD& msg); - -private: - const char* mMessageName; // Canonical (prehashed) string. - LLSD mMessage; -}; - -#endif // LL_LLSDMESSAGEREADER_H +/**
+ * @file llsdmessagereader.h
+ * @brief LLSDMessageReader class Declaration
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#ifndef LL_LLSDMESSAGEREADER_H
+#define LL_LLSDMESSAGEREADER_H
+
+#include "llmessagereader.h"
+#include "llsd.h"
+
+#include <map>
+
+class LLMessageTemplate;
+class LLMsgData;
+
+class LLSDMessageReader : public LLMessageReader
+{
+public:
+
+ LLSDMessageReader();
+ virtual ~LLSDMessageReader();
+
+ /** All get* methods expect pointers to canonical strings. */
+ virtual void getBinaryData(const char *block, const char *var,
+ void *datap, S32 size, S32 blocknum = 0,
+ S32 max_size = S32_MAX);
+ virtual void getBOOL(const char *block, const char *var, bool &data,
+ S32 blocknum = 0);
+ virtual void getS8(const char *block, const char *var, S8 &data,
+ S32 blocknum = 0);
+ virtual void getU8(const char *block, const char *var, U8 &data,
+ S32 blocknum = 0);
+ virtual void getS16(const char *block, const char *var, S16 &data,
+ S32 blocknum = 0);
+ virtual void getU16(const char *block, const char *var, U16 &data,
+ S32 blocknum = 0);
+ virtual void getS32(const char *block, const char *var, S32 &data,
+ S32 blocknum = 0);
+ virtual void getF32(const char *block, const char *var, F32 &data,
+ S32 blocknum = 0);
+ virtual void getU32(const char *block, const char *var, U32 &data,
+ S32 blocknum = 0);
+ virtual void getU64(const char *block, const char *var, U64 &data,
+ S32 blocknum = 0);
+ virtual void getF64(const char *block, const char *var, F64 &data,
+ S32 blocknum = 0);
+ virtual void getVector3(const char *block, const char *var,
+ LLVector3 &vec, S32 blocknum = 0);
+ virtual void getVector4(const char *block, const char *var,
+ LLVector4 &vec, S32 blocknum = 0);
+ virtual void getVector3d(const char *block, const char *var,
+ LLVector3d &vec, S32 blocknum = 0);
+ virtual void getQuat(const char *block, const char *var, LLQuaternion &q,
+ S32 blocknum = 0);
+ virtual void getUUID(const char *block, const char *var, LLUUID &uuid,
+ S32 blocknum = 0);
+ virtual void getIPAddr(const char *block, const char *var, U32 &ip,
+ S32 blocknum = 0);
+ virtual void getIPPort(const char *block, const char *var, U16 &port,
+ S32 blocknum = 0);
+ virtual void getString(const char *block, const char *var,
+ S32 buffer_size, char *buffer, S32 blocknum = 0);
+ virtual void getString(const char *block, const char *var, std::string& outstr,
+ S32 blocknum = 0);
+
+ virtual S32 getNumberOfBlocks(const char *blockname);
+ virtual S32 getSize(const char *blockname, const char *varname);
+ virtual S32 getSize(const char *blockname, S32 blocknum,
+ const char *varname);
+
+ virtual void clearMessage();
+
+ virtual const char* getMessageName() const;
+ virtual S32 getMessageSize() const;
+
+ virtual void copyToBuilder(LLMessageBuilder&) const;
+
+ /** Expects a pointer to a canonical name string */
+ void setMessage(const char* name, const LLSD& msg);
+
+private:
+ const char* mMessageName; // Canonical (prehashed) string.
+ LLSD mMessage;
+};
+
+#endif // LL_LLSDMESSAGEREADER_H
diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index be5dcadb28..57ffba9705 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -1,895 +1,893 @@ -/** - * @file lltemplatemessagebuilder.cpp - * @brief LLTemplateMessageBuilder class implementation. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "linden_common.h" - -#include "lltemplatemessagebuilder.h" - -#include "llmessagetemplate.h" -#include "llmath.h" -#include "llquaternion.h" -#include "u64.h" -#include "v3dmath.h" -#include "v3math.h" -#include "v4math.h" - -LLTemplateMessageBuilder::LLTemplateMessageBuilder(const message_template_name_map_t& name_template_map) : - mCurrentSMessageData(NULL), - mCurrentSMessageTemplate(NULL), - mCurrentSDataBlock(NULL), - mCurrentSMessageName(NULL), - mCurrentSBlockName(NULL), - mbSBuilt(FALSE), - mbSClear(TRUE), - mCurrentSendTotal(0), - mMessageTemplates(name_template_map) -{ -} - -//virtual -LLTemplateMessageBuilder::~LLTemplateMessageBuilder() -{ - delete mCurrentSMessageData; - mCurrentSMessageData = NULL; -} - -// virtual -void LLTemplateMessageBuilder::newMessage(const char *name) -{ - mbSBuilt = FALSE; - mbSClear = FALSE; - - mCurrentSendTotal = 0; - - delete mCurrentSMessageData; - mCurrentSMessageData = NULL; - - char* namep = (char*)name; - if (mMessageTemplates.count(namep) > 0) - { - mCurrentSMessageTemplate = mMessageTemplates.find(name)->second; - mCurrentSMessageData = new LLMsgData(namep); - mCurrentSMessageName = namep; - mCurrentSDataBlock = NULL; - mCurrentSBlockName = NULL; - - // add at one of each block - const LLMessageTemplate* msg_template = mMessageTemplates.find(name)->second; - - if (msg_template->getDeprecation() != MD_NOTDEPRECATED) - { - LL_WARNS() << "Sending deprecated message " << namep << LL_ENDL; - } - - LLMessageTemplate::message_block_map_t::const_iterator iter; - for(iter = msg_template->mMemberBlocks.begin(); - iter != msg_template->mMemberBlocks.end(); - ++iter) - { - LLMessageBlock* ci = *iter; - LLMsgBlkData* tblockp = new LLMsgBlkData(ci->mName, 0); - mCurrentSMessageData->addBlock(tblockp); - } - } - else - { - LL_ERRS() << "newMessage - Message " << name << " not registered" << LL_ENDL; - } -} - -// virtual -void LLTemplateMessageBuilder::clearMessage() -{ - mbSBuilt = FALSE; - mbSClear = TRUE; - - mCurrentSendTotal = 0; - - mCurrentSMessageTemplate = NULL; - - delete mCurrentSMessageData; - mCurrentSMessageData = NULL; - - mCurrentSMessageName = NULL; - mCurrentSDataBlock = NULL; - mCurrentSBlockName = NULL; -} - -// virtual -void LLTemplateMessageBuilder::nextBlock(const char* blockname) -{ - char *bnamep = (char *)blockname; - - if (!mCurrentSMessageTemplate) - { - LL_ERRS() << "newMessage not called prior to setBlock" << LL_ENDL; - return; - } - - // now, does this block exist? - const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep); - if (!template_data) - { - LL_ERRS() << "LLTemplateMessageBuilder::nextBlock " << bnamep - << " not a block in " << mCurrentSMessageTemplate->mName << LL_ENDL; - return; - } - - // ok, have we already set this block? - LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[bnamep]; - if (block_data->mBlockNumber == 0) - { - // nope! set this as the current block - block_data->mBlockNumber = 1; - mCurrentSDataBlock = block_data; - mCurrentSBlockName = bnamep; - - // add placeholders for each of the variables - for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin(); - iter != template_data->mMemberVariables.end(); iter++) - { - LLMessageVariable& ci = **iter; - mCurrentSDataBlock->addVariable(ci.getName(), ci.getType()); - } - return; - } - else - { - // already have this block. . . - // are we supposed to have a new one? - - // if the block is type MBT_SINGLE this is bad! - if (template_data->mType == MBT_SINGLE) - { - LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called multiple times" - << " for " << bnamep << " but is type MBT_SINGLE" << LL_ENDL; - return; - } - - - // if the block is type MBT_MULTIPLE then we need a known number, - // make sure that we're not exceeding it - if ( (template_data->mType == MBT_MULTIPLE) - &&(mCurrentSDataBlock->mBlockNumber == template_data->mNumber)) - { - LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called " - << mCurrentSDataBlock->mBlockNumber << " times for " << bnamep - << " exceeding " << template_data->mNumber - << " specified in type MBT_MULTIPLE." << LL_ENDL; - return; - } - - // ok, we can make a new one - // modify the name to avoid name collision by adding number to end - S32 count = block_data->mBlockNumber; - - // incrememt base name's count - block_data->mBlockNumber++; - - if (block_data->mBlockNumber > MAX_BLOCKS) - { - LL_ERRS() << "Trying to pack too many blocks into MBT_VARIABLE type " - << "(limited to " << MAX_BLOCKS << ")" << LL_ENDL; - } - - // create new name - // Nota Bene: if things are working correctly, - // mCurrentMessageData->mMemberBlocks[blockname]->mBlockNumber == - // mCurrentDataBlock->mBlockNumber + 1 - - char *nbnamep = bnamep + count; - - mCurrentSDataBlock = new LLMsgBlkData(bnamep, count); - mCurrentSDataBlock->mName = nbnamep; - mCurrentSMessageData->mMemberBlocks[nbnamep] = mCurrentSDataBlock; - - // add placeholders for each of the variables - for (LLMessageBlock::message_variable_map_t::const_iterator - iter = template_data->mMemberVariables.begin(), - end = template_data->mMemberVariables.end(); - iter != end; iter++) - { - LLMessageVariable& ci = **iter; - mCurrentSDataBlock->addVariable(ci.getName(), ci.getType()); - } - return; - } -} - -// TODO: Remove this horror... -BOOL LLTemplateMessageBuilder::removeLastBlock() -{ - if (mCurrentSBlockName) - { - if ( (mCurrentSMessageData) - &&(mCurrentSMessageTemplate)) - { - if (mCurrentSMessageData->mMemberBlocks[mCurrentSBlockName]->mBlockNumber >= 1) - { - // At least one block for the current block name. - - // Store the current block name for future reference. - char *block_name = mCurrentSBlockName; - - // Decrement the sent total by the size of the - // data in the message block that we're currently building. - - const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName); - - for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin(); - iter != template_data->mMemberVariables.end(); iter++) - { - LLMessageVariable& ci = **iter; - mCurrentSendTotal -= ci.getSize(); - } - - - // Now we want to find the block that we're blowing away. - - // Get the number of blocks. - LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[block_name]; - S32 num_blocks = block_data->mBlockNumber; - - // Use the same (suspect?) algorithm that's used to generate - // the names in the nextBlock method to find it. - char *block_getting_whacked = block_name + num_blocks - 1; - LLMsgBlkData* whacked_data = mCurrentSMessageData->mMemberBlocks[block_getting_whacked]; - delete whacked_data; - mCurrentSMessageData->mMemberBlocks.erase(block_getting_whacked); - - if (num_blocks <= 1) - { - // we just blew away the last one, so return FALSE - LL_WARNS() << "not blowing away the only block of message " - << mCurrentSMessageName - << ". Block: " << block_name - << ". Number: " << num_blocks - << LL_ENDL; - return FALSE; - } - else - { - // Decrement the counter. - block_data->mBlockNumber--; - return TRUE; - } - } - } - } - return FALSE; -} - -// add data to variable in current block -void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type, S32 size) -{ - char *vnamep = (char *)varname; - - // do we have a current message? - if (!mCurrentSMessageTemplate) - { - LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL; - return; - } - - // do we have a current block? - if (!mCurrentSDataBlock) - { - LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL; - return; - } - - // kewl, add the data if it exists - const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep); - if (!var_data || !var_data->getName()) - { - LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL; - return; - } - - // ok, it seems ok. . . are we the correct size? - if (var_data->getType() == MVT_VARIABLE) - { - // Variable 1 can only store 255 bytes, make sure our data is smaller - if ((var_data->getSize() == 1) && - (size > 255)) - { - LL_WARNS() << "Field " << varname << " is a Variable 1 but program " - << "attempted to stuff more than 255 bytes in " - << "(" << size << "). Clamping size and truncating data." << LL_ENDL; - size = 255; - char *truncate = (char *)data; - truncate[254] = 0; // array size is 255 but the last element index is 254 - } - - // no correct size for MVT_VARIABLE, instead we need to tell how many bytes the size will be encoded as - mCurrentSDataBlock->addData(vnamep, data, size, type, var_data->getSize()); - mCurrentSendTotal += size; - } - else - { - if (size != var_data->getSize()) - { - LL_ERRS() << varname << " is type MVT_FIXED but request size " << size << " doesn't match template size " - << var_data->getSize() << LL_ENDL; - return; - } - // alright, smash it in - mCurrentSDataBlock->addData(vnamep, data, size, type); - mCurrentSendTotal += size; - } -} - -// add data to variable in current block - fails if variable isn't MVT_FIXED -void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type) -{ - char *vnamep = (char *)varname; - - // do we have a current message? - if (!mCurrentSMessageTemplate) - { - LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL; - return; - } - - // do we have a current block? - if (!mCurrentSDataBlock) - { - LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL; - return; - } - - // kewl, add the data if it exists - const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep); - if (!var_data->getName()) - { - LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL; - return; - } - - // ok, it seems ok. . . are we MVT_VARIABLE? - if (var_data->getType() == MVT_VARIABLE) - { - // nope - LL_ERRS() << vnamep << " is type MVT_VARIABLE. Call using addData(name, data, size)" << LL_ENDL; - return; - } - else - { - mCurrentSDataBlock->addData(vnamep, data, var_data->getSize(), type); - mCurrentSendTotal += var_data->getSize(); - } -} - -void LLTemplateMessageBuilder::addBinaryData(const char *varname, - const void *data, S32 size) -{ - addData(varname, data, MVT_FIXED, size); -} - -void LLTemplateMessageBuilder::addS8(const char *varname, S8 s) -{ - addData(varname, &s, MVT_S8, sizeof(s)); -} - -void LLTemplateMessageBuilder::addU8(const char *varname, U8 u) -{ - addData(varname, &u, MVT_U8, sizeof(u)); -} - -void LLTemplateMessageBuilder::addS16(const char *varname, S16 i) -{ - addData(varname, &i, MVT_S16, sizeof(i)); -} - -void LLTemplateMessageBuilder::addU16(const char *varname, U16 i) -{ - addData(varname, &i, MVT_U16, sizeof(i)); -} - -void LLTemplateMessageBuilder::addF32(const char *varname, F32 f) -{ - addData(varname, &f, MVT_F32, sizeof(f)); -} - -void LLTemplateMessageBuilder::addS32(const char *varname, S32 s) -{ - addData(varname, &s, MVT_S32, sizeof(s)); -} - -void LLTemplateMessageBuilder::addU32(const char *varname, U32 u) -{ - addData(varname, &u, MVT_U32, sizeof(u)); -} - -void LLTemplateMessageBuilder::addU64(const char *varname, U64 lu) -{ - addData(varname, &lu, MVT_U64, sizeof(lu)); -} - -void LLTemplateMessageBuilder::addF64(const char *varname, F64 d) -{ - addData(varname, &d, MVT_F64, sizeof(d)); -} - -void LLTemplateMessageBuilder::addIPAddr(const char *varname, U32 u) -{ - addData(varname, &u, MVT_IP_ADDR, sizeof(u)); -} - -void LLTemplateMessageBuilder::addIPPort(const char *varname, U16 u) -{ - u = htons(u); - addData(varname, &u, MVT_IP_PORT, sizeof(u)); -} - -void LLTemplateMessageBuilder::addBOOL(const char* varname, BOOL b) -{ - // Can't just cast a BOOL (actually a U32) to a U8. - // In some cases the low order bits will be zero. - U8 temp = (b != 0); - addData(varname, &temp, MVT_BOOL, sizeof(temp)); -} - -void LLTemplateMessageBuilder::addString(const char* varname, const char* s) -{ - if (s) - addData( varname, (void *)s, MVT_VARIABLE, (S32)strlen(s) + 1); /* Flawfinder: ignore */ - else - addData( varname, NULL, MVT_VARIABLE, 0); -} - -void LLTemplateMessageBuilder::addString(const char* varname, const std::string& s) -{ - if (s.size()) - addData( varname, (void *)s.c_str(), MVT_VARIABLE, (S32)(s.size()) + 1); - else - addData( varname, NULL, MVT_VARIABLE, 0); -} - -void LLTemplateMessageBuilder::addVector3(const char *varname, const LLVector3& vec) -{ - addData(varname, vec.mV, MVT_LLVector3, sizeof(vec.mV)); -} - -void LLTemplateMessageBuilder::addVector4(const char *varname, const LLVector4& vec) -{ - addData(varname, vec.mV, MVT_LLVector4, sizeof(vec.mV)); -} - -void LLTemplateMessageBuilder::addVector3d(const char *varname, const LLVector3d& vec) -{ - addData(varname, vec.mdV, MVT_LLVector3d, sizeof(vec.mdV)); -} - -void LLTemplateMessageBuilder::addQuat(const char *varname, const LLQuaternion& quat) -{ - addData(varname, quat.packToVector3().mV, MVT_LLQuaternion, sizeof(LLVector3)); -} - -void LLTemplateMessageBuilder::addUUID(const char *varname, const LLUUID& uuid) -{ - addData(varname, uuid.mData, MVT_LLUUID, sizeof(uuid.mData)); -} - -static S32 zero_code(U8 **data, U32 *data_size) -{ - // Encoded send buffer needs to be slightly larger since the zero - // coding can potentially increase the size of the send data. - static U8 encodedSendBuffer[2 * MAX_BUFFER_SIZE]; - - S32 count = *data_size; - - S32 net_gain = 0; - U8 num_zeroes = 0; - - U8 *inptr = (U8 *)*data; - U8 *outptr = (U8 *)encodedSendBuffer; - -// skip the packet id field - - for (U32 ii = 0; ii < LL_PACKET_ID_SIZE ; ++ii) - { - count--; - *outptr++ = *inptr++; - } - -// build encoded packet, keeping track of net size gain - -// sequential zero bytes are encoded as 0 [U8 count] -// with 0 0 [count] representing wrap (>256 zeroes) - - while (count--) - { - if (!(*inptr)) // in a zero count - { - if (num_zeroes) - { - if (++num_zeroes > 254) - { - *outptr++ = num_zeroes; - num_zeroes = 0; - } - net_gain--; // subseqent zeroes save one - } - else - { - *outptr++ = 0; - net_gain++; // starting a zero count adds one - num_zeroes = 1; - } - inptr++; - } - else - { - if (num_zeroes) - { - *outptr++ = num_zeroes; - num_zeroes = 0; - } - *outptr++ = *inptr++; - } - } - - if (num_zeroes) - { - *outptr++ = num_zeroes; - } - - if (net_gain < 0) - { - // TODO: babbage: reinstate stat collecting... - //mCompressedPacketsOut++; - //mUncompressedBytesOut += *data_size; - - *data = encodedSendBuffer; - *data_size += net_gain; - encodedSendBuffer[0] |= LL_ZERO_CODE_FLAG; // set the head bit to indicate zero coding - - //mCompressedBytesOut += *data_size; - - } - //mTotalBytesOut += *data_size; - - return(net_gain); -} - -void LLTemplateMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length) -{ - if(ME_ZEROCODED == mCurrentSMessageTemplate->getEncoding()) - { - zero_code(&buf_ptr, &buffer_length); - } -} - -BOOL LLTemplateMessageBuilder::isMessageFull(const char* blockname) const -{ - if(mCurrentSendTotal > MTUBYTES) - { - return TRUE; - } - if(!blockname) - { - return FALSE; - } - char* bnamep = (char*)blockname; - S32 max; - - const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep); - - switch(template_data->mType) - { - case MBT_SINGLE: - max = 1; - break; - case MBT_MULTIPLE: - max = template_data->mNumber; - break; - case MBT_VARIABLE: - default: - max = MAX_BLOCKS; - break; - } - if(mCurrentSMessageData->mMemberBlocks[bnamep]->mBlockNumber >= max) - { - return TRUE; - } - return FALSE; -} - -static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* template_data, LLMsgData* message_data) -{ - S32 result = 0; - LLMsgData::msg_blk_data_map_t::const_iterator block_iter = message_data->mMemberBlocks.find(template_data->mName); - const LLMsgBlkData* mbci = block_iter->second; - - // ok, if this is the first block of a repeating pack, set - // block_count and, if it's type MBT_VARIABLE encode a byte - // for how many there are - S32 block_count = mbci->mBlockNumber; - if (template_data->mType == MBT_VARIABLE) - { - // remember that mBlockNumber is a S32 - U8 temp_block_number = (U8)mbci->mBlockNumber; - if ((S32)(result + sizeof(U8)) < MAX_BUFFER_SIZE) - { - memcpy(&buffer[result], &temp_block_number, sizeof(U8)); - result += sizeof(U8); - } - else - { - // Just reporting error is likely not enough. Need - // to check how to abort or error out gracefully - // from this function. XXXTBD - LL_ERRS() << "buildBlock failed. Message excedding " - << "sendBuffersize." << LL_ENDL; - } - } - else if (template_data->mType == MBT_MULTIPLE) - { - if (block_count != template_data->mNumber) - { - // nope! need to fill it in all the way! - LL_ERRS() << "Block " << mbci->mName - << " is type MBT_MULTIPLE but only has data for " - << block_count << " out of its " - << template_data->mNumber << " blocks" << LL_ENDL; - } - } - - while(block_count > 0) - { - // now loop through the variables - for (LLMsgBlkData::msg_var_data_map_t::const_iterator iter = mbci->mMemberVarData.begin(); - iter != mbci->mMemberVarData.end(); iter++) - { - const LLMsgVarData& mvci = *iter; - if (mvci.getSize() == -1) - { - // oops, this variable wasn't ever set! - LL_ERRS() << "The variable " << mvci.getName() << " in block " - << mbci->mName << " of message " - << template_data->mName - << " wasn't set prior to buildMessage call" << LL_ENDL; - } - else - { - S32 data_size = mvci.getDataSize(); - if(data_size > 0) - { - // The type is MVT_VARIABLE, which means that we - // need to encode a size argument. Otherwise, - // there is no need. - S32 size = mvci.getSize(); - U8 sizeb; - U16 sizeh; - switch(data_size) - { - case 1: - sizeb = size; - htolememcpy(&buffer[result], &sizeb, MVT_U8, 1); - break; - case 2: - sizeh = size; - htolememcpy(&buffer[result], &sizeh, MVT_U16, 2); - break; - case 4: - htolememcpy(&buffer[result], &size, MVT_S32, 4); - break; - default: - LL_ERRS() << "Attempting to build variable field with unknown size of " << size << LL_ENDL; - break; - } - result += mvci.getDataSize(); - } - - // if there is any data to pack, pack it - if((mvci.getData() != NULL) && mvci.getSize()) - { - if(result + mvci.getSize() < buffer_size) - { - memcpy( - &buffer[result], - mvci.getData(), - mvci.getSize()); - result += mvci.getSize(); - } - else - { - // Just reporting error is likely not - // enough. Need to check how to abort or error - // out gracefully from this function. XXXTBD - LL_ERRS() << "buildBlock failed. " - << "Attempted to pack " - << (result + mvci.getSize()) - << " bytes into a buffer with size " - << buffer_size << "." << LL_ENDL; - } - } - } - } - - --block_count; - - if (block_iter != message_data->mMemberBlocks.end()) - { - ++block_iter; - if (block_iter != message_data->mMemberBlocks.end()) - { - mbci = block_iter->second; - } - } - } - - return result; -} - - -// make sure that all the desired data is in place and then copy the data into MAX_BUFFER_SIZEd buffer -U32 LLTemplateMessageBuilder::buildMessage( - U8* buffer, - U32 buffer_size, - U8 offset_to_data) -{ - // basic algorithm is to loop through the various pieces, building - // size and offset info if we encounter a -1 for mSize at any - // point that variable wasn't given data - - // do we have a current message? - if (!mCurrentSMessageTemplate) - { - LL_ERRS() << "newMessage not called prior to buildMessage" << LL_ENDL; - return 0; - } - - // leave room for flags, packet sequence #, and data offset - // information. - buffer[PHL_OFFSET] = offset_to_data; - U32 result = LL_PACKET_ID_SIZE; - - // encode message number and adjust total_offset - if (mCurrentSMessageTemplate->mFrequency == MFT_HIGH) - { -// old, endian-dependant way -// memcpy(&buffer[result], &mCurrentMessageTemplate->mMessageNumber, sizeof(U8)); - -// new, independant way - buffer[result] = (U8)mCurrentSMessageTemplate->mMessageNumber; - result += sizeof(U8); - } - else if (mCurrentSMessageTemplate->mFrequency == MFT_MEDIUM) - { - U8 temp = 255; - memcpy(&buffer[result], &temp, sizeof(U8)); /*Flawfinder: ignore*/ - result += sizeof(U8); - - // mask off unsightly bits - temp = mCurrentSMessageTemplate->mMessageNumber & 255; - memcpy(&buffer[result], &temp, sizeof(U8)); /*Flawfinder: ignore*/ - result += sizeof(U8); - } - else if (mCurrentSMessageTemplate->mFrequency == MFT_LOW) - { - U8 temp = 255; - U16 message_num; - memcpy(&buffer[result], &temp, sizeof(U8)); /*Flawfinder: ignore*/ - result += sizeof(U8); - memcpy(&buffer[result], &temp, sizeof(U8)); /*Flawfinder: ignore*/ - result += sizeof(U8); - - // mask off unsightly bits - message_num = mCurrentSMessageTemplate->mMessageNumber & 0xFFFF; - - // convert to network byte order - message_num = htons(message_num); - memcpy(&buffer[result], &message_num, sizeof(U16)); /*Flawfinder: ignore*/ - result += sizeof(U16); - } - else - { - LL_ERRS() << "unexpected message frequency in buildMessage" << LL_ENDL; - return 0; - } - - // fast forward through the offset and build the message - result += offset_to_data; - for(LLMessageTemplate::message_block_map_t::const_iterator - iter = mCurrentSMessageTemplate->mMemberBlocks.begin(), - end = mCurrentSMessageTemplate->mMemberBlocks.end(); - iter != end; - ++iter) - { - result += buildBlock(buffer + result, buffer_size - result, *iter, mCurrentSMessageData); - } - mbSBuilt = TRUE; - - return result; -} - -void LLTemplateMessageBuilder::copyFromMessageData(const LLMsgData& data) -{ - // copy the blocks - // counting variables used to encode multiple block info - S32 block_count = 0; - char *block_name = NULL; - - // loop through msg blocks to loop through variables, totalling up size - // data and filling the new (send) message - LLMsgData::msg_blk_data_map_t::const_iterator iter = - data.mMemberBlocks.begin(); - LLMsgData::msg_blk_data_map_t::const_iterator end = - data.mMemberBlocks.end(); - for(; iter != end; ++iter) - { - const LLMsgBlkData* mbci = iter->second; - if(!mbci) continue; - - // do we need to encode a block code? - if (block_count == 0) - { - block_count = mbci->mBlockNumber; - block_name = (char *)mbci->mName; - } - - // counting down mutliple blocks - block_count--; - - nextBlock(block_name); - - // now loop through the variables - LLMsgBlkData::msg_var_data_map_t::const_iterator dit = mbci->mMemberVarData.begin(); - LLMsgBlkData::msg_var_data_map_t::const_iterator dend = mbci->mMemberVarData.end(); - - for(; dit != dend; ++dit) - { - const LLMsgVarData& mvci = *dit; - addData(mvci.getName(), mvci.getData(), mvci.getType(), mvci.getSize()); - } - } -} - -//virtual -void LLTemplateMessageBuilder::copyFromLLSD(const LLSD&) -{ - // TODO -} - -//virtual -void LLTemplateMessageBuilder::setBuilt(BOOL b) { mbSBuilt = b; } - -//virtual -BOOL LLTemplateMessageBuilder::isBuilt() const {return mbSBuilt;} - -//virtual -BOOL LLTemplateMessageBuilder::isClear() const {return mbSClear;} - -//virtual -S32 LLTemplateMessageBuilder::getMessageSize() {return mCurrentSendTotal;} - -//virtual -const char* LLTemplateMessageBuilder::getMessageName() const -{ - return mCurrentSMessageName; -} +/**
+ * @file lltemplatemessagebuilder.cpp
+ * @brief LLTemplateMessageBuilder class implementation.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+
+#include "lltemplatemessagebuilder.h"
+
+#include "llmessagetemplate.h"
+#include "llmath.h"
+#include "llquaternion.h"
+#include "u64.h"
+#include "v3dmath.h"
+#include "v3math.h"
+#include "v4math.h"
+
+LLTemplateMessageBuilder::LLTemplateMessageBuilder(const message_template_name_map_t& name_template_map) :
+ mCurrentSMessageData(NULL),
+ mCurrentSMessageTemplate(NULL),
+ mCurrentSDataBlock(NULL),
+ mCurrentSMessageName(NULL),
+ mCurrentSBlockName(NULL),
+ mbSBuilt(false),
+ mbSClear(true),
+ mCurrentSendTotal(0),
+ mMessageTemplates(name_template_map)
+{
+}
+
+//virtual
+LLTemplateMessageBuilder::~LLTemplateMessageBuilder()
+{
+ delete mCurrentSMessageData;
+ mCurrentSMessageData = NULL;
+}
+
+// virtual
+void LLTemplateMessageBuilder::newMessage(const char *name)
+{
+ mbSBuilt = false;
+ mbSClear = false;
+
+ mCurrentSendTotal = 0;
+
+ delete mCurrentSMessageData;
+ mCurrentSMessageData = NULL;
+
+ char* namep = (char*)name;
+ if (mMessageTemplates.count(namep) > 0)
+ {
+ mCurrentSMessageTemplate = mMessageTemplates.find(name)->second;
+ mCurrentSMessageData = new LLMsgData(namep);
+ mCurrentSMessageName = namep;
+ mCurrentSDataBlock = NULL;
+ mCurrentSBlockName = NULL;
+
+ // add at one of each block
+ const LLMessageTemplate* msg_template = mMessageTemplates.find(name)->second;
+
+ if (msg_template->getDeprecation() != MD_NOTDEPRECATED)
+ {
+ LL_WARNS() << "Sending deprecated message " << namep << LL_ENDL;
+ }
+
+ LLMessageTemplate::message_block_map_t::const_iterator iter;
+ for(iter = msg_template->mMemberBlocks.begin();
+ iter != msg_template->mMemberBlocks.end();
+ ++iter)
+ {
+ LLMessageBlock* ci = *iter;
+ LLMsgBlkData* tblockp = new LLMsgBlkData(ci->mName, 0);
+ mCurrentSMessageData->addBlock(tblockp);
+ }
+ }
+ else
+ {
+ LL_ERRS() << "newMessage - Message " << name << " not registered" << LL_ENDL;
+ }
+}
+
+// virtual
+void LLTemplateMessageBuilder::clearMessage()
+{
+ mbSBuilt = false;
+ mbSClear = true;
+
+ mCurrentSendTotal = 0;
+
+ mCurrentSMessageTemplate = NULL;
+
+ delete mCurrentSMessageData;
+ mCurrentSMessageData = NULL;
+
+ mCurrentSMessageName = NULL;
+ mCurrentSDataBlock = NULL;
+ mCurrentSBlockName = NULL;
+}
+
+// virtual
+void LLTemplateMessageBuilder::nextBlock(const char* blockname)
+{
+ char *bnamep = (char *)blockname;
+
+ if (!mCurrentSMessageTemplate)
+ {
+ LL_ERRS() << "newMessage not called prior to setBlock" << LL_ENDL;
+ return;
+ }
+
+ // now, does this block exist?
+ const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep);
+ if (!template_data)
+ {
+ LL_ERRS() << "LLTemplateMessageBuilder::nextBlock " << bnamep
+ << " not a block in " << mCurrentSMessageTemplate->mName << LL_ENDL;
+ return;
+ }
+
+ // ok, have we already set this block?
+ LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[bnamep];
+ if (block_data->mBlockNumber == 0)
+ {
+ // nope! set this as the current block
+ block_data->mBlockNumber = 1;
+ mCurrentSDataBlock = block_data;
+ mCurrentSBlockName = bnamep;
+
+ // add placeholders for each of the variables
+ for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin();
+ iter != template_data->mMemberVariables.end(); iter++)
+ {
+ LLMessageVariable& ci = **iter;
+ mCurrentSDataBlock->addVariable(ci.getName(), ci.getType());
+ }
+ return;
+ }
+ else
+ {
+ // already have this block. . .
+ // are we supposed to have a new one?
+
+ // if the block is type MBT_SINGLE this is bad!
+ if (template_data->mType == MBT_SINGLE)
+ {
+ LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called multiple times"
+ << " for " << bnamep << " but is type MBT_SINGLE" << LL_ENDL;
+ return;
+ }
+
+
+ // if the block is type MBT_MULTIPLE then we need a known number,
+ // make sure that we're not exceeding it
+ if ( (template_data->mType == MBT_MULTIPLE)
+ &&(mCurrentSDataBlock->mBlockNumber == template_data->mNumber))
+ {
+ LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called "
+ << mCurrentSDataBlock->mBlockNumber << " times for " << bnamep
+ << " exceeding " << template_data->mNumber
+ << " specified in type MBT_MULTIPLE." << LL_ENDL;
+ return;
+ }
+
+ // ok, we can make a new one
+ // modify the name to avoid name collision by adding number to end
+ S32 count = block_data->mBlockNumber;
+
+ // incrememt base name's count
+ block_data->mBlockNumber++;
+
+ if (block_data->mBlockNumber > MAX_BLOCKS)
+ {
+ LL_ERRS() << "Trying to pack too many blocks into MBT_VARIABLE type "
+ << "(limited to " << MAX_BLOCKS << ")" << LL_ENDL;
+ }
+
+ // create new name
+ // Nota Bene: if things are working correctly,
+ // mCurrentMessageData->mMemberBlocks[blockname]->mBlockNumber ==
+ // mCurrentDataBlock->mBlockNumber + 1
+
+ char *nbnamep = bnamep + count;
+
+ mCurrentSDataBlock = new LLMsgBlkData(bnamep, count);
+ mCurrentSDataBlock->mName = nbnamep;
+ mCurrentSMessageData->mMemberBlocks[nbnamep] = mCurrentSDataBlock;
+
+ // add placeholders for each of the variables
+ for (LLMessageBlock::message_variable_map_t::const_iterator
+ iter = template_data->mMemberVariables.begin(),
+ end = template_data->mMemberVariables.end();
+ iter != end; iter++)
+ {
+ LLMessageVariable& ci = **iter;
+ mCurrentSDataBlock->addVariable(ci.getName(), ci.getType());
+ }
+ return;
+ }
+}
+
+// TODO: Remove this horror...
+bool LLTemplateMessageBuilder::removeLastBlock()
+{
+ if (mCurrentSBlockName)
+ {
+ if ( (mCurrentSMessageData)
+ &&(mCurrentSMessageTemplate))
+ {
+ if (mCurrentSMessageData->mMemberBlocks[mCurrentSBlockName]->mBlockNumber >= 1)
+ {
+ // At least one block for the current block name.
+
+ // Store the current block name for future reference.
+ char *block_name = mCurrentSBlockName;
+
+ // Decrement the sent total by the size of the
+ // data in the message block that we're currently building.
+
+ const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName);
+
+ for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin();
+ iter != template_data->mMemberVariables.end(); iter++)
+ {
+ LLMessageVariable& ci = **iter;
+ mCurrentSendTotal -= ci.getSize();
+ }
+
+
+ // Now we want to find the block that we're blowing away.
+
+ // Get the number of blocks.
+ LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[block_name];
+ S32 num_blocks = block_data->mBlockNumber;
+
+ // Use the same (suspect?) algorithm that's used to generate
+ // the names in the nextBlock method to find it.
+ char *block_getting_whacked = block_name + num_blocks - 1;
+ LLMsgBlkData* whacked_data = mCurrentSMessageData->mMemberBlocks[block_getting_whacked];
+ delete whacked_data;
+ mCurrentSMessageData->mMemberBlocks.erase(block_getting_whacked);
+
+ if (num_blocks <= 1)
+ {
+ // we just blew away the last one, so return false
+ LL_WARNS() << "not blowing away the only block of message "
+ << mCurrentSMessageName
+ << ". Block: " << block_name
+ << ". Number: " << num_blocks
+ << LL_ENDL;
+ return false;
+ }
+ else
+ {
+ // Decrement the counter.
+ block_data->mBlockNumber--;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+// add data to variable in current block
+void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type, S32 size)
+{
+ char *vnamep = (char *)varname;
+
+ // do we have a current message?
+ if (!mCurrentSMessageTemplate)
+ {
+ LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL;
+ return;
+ }
+
+ // do we have a current block?
+ if (!mCurrentSDataBlock)
+ {
+ LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL;
+ return;
+ }
+
+ // kewl, add the data if it exists
+ const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep);
+ if (!var_data || !var_data->getName())
+ {
+ LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL;
+ return;
+ }
+
+ // ok, it seems ok. . . are we the correct size?
+ if (var_data->getType() == MVT_VARIABLE)
+ {
+ // Variable 1 can only store 255 bytes, make sure our data is smaller
+ if ((var_data->getSize() == 1) &&
+ (size > 255))
+ {
+ LL_WARNS() << "Field " << varname << " is a Variable 1 but program "
+ << "attempted to stuff more than 255 bytes in "
+ << "(" << size << "). Clamping size and truncating data." << LL_ENDL;
+ size = 255;
+ char *truncate = (char *)data;
+ truncate[254] = 0; // array size is 255 but the last element index is 254
+ }
+
+ // no correct size for MVT_VARIABLE, instead we need to tell how many bytes the size will be encoded as
+ mCurrentSDataBlock->addData(vnamep, data, size, type, var_data->getSize());
+ mCurrentSendTotal += size;
+ }
+ else
+ {
+ if (size != var_data->getSize())
+ {
+ LL_ERRS() << varname << " is type MVT_FIXED but request size " << size << " doesn't match template size "
+ << var_data->getSize() << LL_ENDL;
+ return;
+ }
+ // alright, smash it in
+ mCurrentSDataBlock->addData(vnamep, data, size, type);
+ mCurrentSendTotal += size;
+ }
+}
+
+// add data to variable in current block - fails if variable isn't MVT_FIXED
+void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type)
+{
+ char *vnamep = (char *)varname;
+
+ // do we have a current message?
+ if (!mCurrentSMessageTemplate)
+ {
+ LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL;
+ return;
+ }
+
+ // do we have a current block?
+ if (!mCurrentSDataBlock)
+ {
+ LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL;
+ return;
+ }
+
+ // kewl, add the data if it exists
+ const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep);
+ if (!var_data->getName())
+ {
+ LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL;
+ return;
+ }
+
+ // ok, it seems ok. . . are we MVT_VARIABLE?
+ if (var_data->getType() == MVT_VARIABLE)
+ {
+ // nope
+ LL_ERRS() << vnamep << " is type MVT_VARIABLE. Call using addData(name, data, size)" << LL_ENDL;
+ return;
+ }
+ else
+ {
+ mCurrentSDataBlock->addData(vnamep, data, var_data->getSize(), type);
+ mCurrentSendTotal += var_data->getSize();
+ }
+}
+
+void LLTemplateMessageBuilder::addBinaryData(const char *varname,
+ const void *data, S32 size)
+{
+ addData(varname, data, MVT_FIXED, size);
+}
+
+void LLTemplateMessageBuilder::addS8(const char *varname, S8 s)
+{
+ addData(varname, &s, MVT_S8, sizeof(s));
+}
+
+void LLTemplateMessageBuilder::addU8(const char *varname, U8 u)
+{
+ addData(varname, &u, MVT_U8, sizeof(u));
+}
+
+void LLTemplateMessageBuilder::addS16(const char *varname, S16 i)
+{
+ addData(varname, &i, MVT_S16, sizeof(i));
+}
+
+void LLTemplateMessageBuilder::addU16(const char *varname, U16 i)
+{
+ addData(varname, &i, MVT_U16, sizeof(i));
+}
+
+void LLTemplateMessageBuilder::addF32(const char *varname, F32 f)
+{
+ addData(varname, &f, MVT_F32, sizeof(f));
+}
+
+void LLTemplateMessageBuilder::addS32(const char *varname, S32 s)
+{
+ addData(varname, &s, MVT_S32, sizeof(s));
+}
+
+void LLTemplateMessageBuilder::addU32(const char *varname, U32 u)
+{
+ addData(varname, &u, MVT_U32, sizeof(u));
+}
+
+void LLTemplateMessageBuilder::addU64(const char *varname, U64 lu)
+{
+ addData(varname, &lu, MVT_U64, sizeof(lu));
+}
+
+void LLTemplateMessageBuilder::addF64(const char *varname, F64 d)
+{
+ addData(varname, &d, MVT_F64, sizeof(d));
+}
+
+void LLTemplateMessageBuilder::addIPAddr(const char *varname, U32 u)
+{
+ addData(varname, &u, MVT_IP_ADDR, sizeof(u));
+}
+
+void LLTemplateMessageBuilder::addIPPort(const char *varname, U16 u)
+{
+ u = htons(u);
+ addData(varname, &u, MVT_IP_PORT, sizeof(u));
+}
+
+void LLTemplateMessageBuilder::addBOOL(const char* varname, bool b)
+{
+ U8 temp = (b != 0);
+ addData(varname, &temp, MVT_BOOL, sizeof(temp));
+}
+
+void LLTemplateMessageBuilder::addString(const char* varname, const char* s)
+{
+ if (s)
+ addData( varname, (void *)s, MVT_VARIABLE, (S32)strlen(s) + 1); /* Flawfinder: ignore */
+ else
+ addData( varname, NULL, MVT_VARIABLE, 0);
+}
+
+void LLTemplateMessageBuilder::addString(const char* varname, const std::string& s)
+{
+ if (s.size())
+ addData( varname, (void *)s.c_str(), MVT_VARIABLE, (S32)(s.size()) + 1);
+ else
+ addData( varname, NULL, MVT_VARIABLE, 0);
+}
+
+void LLTemplateMessageBuilder::addVector3(const char *varname, const LLVector3& vec)
+{
+ addData(varname, vec.mV, MVT_LLVector3, sizeof(vec.mV));
+}
+
+void LLTemplateMessageBuilder::addVector4(const char *varname, const LLVector4& vec)
+{
+ addData(varname, vec.mV, MVT_LLVector4, sizeof(vec.mV));
+}
+
+void LLTemplateMessageBuilder::addVector3d(const char *varname, const LLVector3d& vec)
+{
+ addData(varname, vec.mdV, MVT_LLVector3d, sizeof(vec.mdV));
+}
+
+void LLTemplateMessageBuilder::addQuat(const char *varname, const LLQuaternion& quat)
+{
+ addData(varname, quat.packToVector3().mV, MVT_LLQuaternion, sizeof(LLVector3));
+}
+
+void LLTemplateMessageBuilder::addUUID(const char *varname, const LLUUID& uuid)
+{
+ addData(varname, uuid.mData, MVT_LLUUID, sizeof(uuid.mData));
+}
+
+static S32 zero_code(U8 **data, U32 *data_size)
+{
+ // Encoded send buffer needs to be slightly larger since the zero
+ // coding can potentially increase the size of the send data.
+ static U8 encodedSendBuffer[2 * MAX_BUFFER_SIZE];
+
+ S32 count = *data_size;
+
+ S32 net_gain = 0;
+ U8 num_zeroes = 0;
+
+ U8 *inptr = (U8 *)*data;
+ U8 *outptr = (U8 *)encodedSendBuffer;
+
+// skip the packet id field
+
+ for (U32 ii = 0; ii < LL_PACKET_ID_SIZE ; ++ii)
+ {
+ count--;
+ *outptr++ = *inptr++;
+ }
+
+// build encoded packet, keeping track of net size gain
+
+// sequential zero bytes are encoded as 0 [U8 count]
+// with 0 0 [count] representing wrap (>256 zeroes)
+
+ while (count--)
+ {
+ if (!(*inptr)) // in a zero count
+ {
+ if (num_zeroes)
+ {
+ if (++num_zeroes > 254)
+ {
+ *outptr++ = num_zeroes;
+ num_zeroes = 0;
+ }
+ net_gain--; // subseqent zeroes save one
+ }
+ else
+ {
+ *outptr++ = 0;
+ net_gain++; // starting a zero count adds one
+ num_zeroes = 1;
+ }
+ inptr++;
+ }
+ else
+ {
+ if (num_zeroes)
+ {
+ *outptr++ = num_zeroes;
+ num_zeroes = 0;
+ }
+ *outptr++ = *inptr++;
+ }
+ }
+
+ if (num_zeroes)
+ {
+ *outptr++ = num_zeroes;
+ }
+
+ if (net_gain < 0)
+ {
+ // TODO: babbage: reinstate stat collecting...
+ //mCompressedPacketsOut++;
+ //mUncompressedBytesOut += *data_size;
+
+ *data = encodedSendBuffer;
+ *data_size += net_gain;
+ encodedSendBuffer[0] |= LL_ZERO_CODE_FLAG; // set the head bit to indicate zero coding
+
+ //mCompressedBytesOut += *data_size;
+
+ }
+ //mTotalBytesOut += *data_size;
+
+ return(net_gain);
+}
+
+void LLTemplateMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length)
+{
+ if(ME_ZEROCODED == mCurrentSMessageTemplate->getEncoding())
+ {
+ zero_code(&buf_ptr, &buffer_length);
+ }
+}
+
+bool LLTemplateMessageBuilder::isMessageFull(const char* blockname) const
+{
+ if(mCurrentSendTotal > MTUBYTES)
+ {
+ return true;
+ }
+ if(!blockname)
+ {
+ return false;
+ }
+ char* bnamep = (char*)blockname;
+ S32 max;
+
+ const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep);
+
+ switch(template_data->mType)
+ {
+ case MBT_SINGLE:
+ max = 1;
+ break;
+ case MBT_MULTIPLE:
+ max = template_data->mNumber;
+ break;
+ case MBT_VARIABLE:
+ default:
+ max = MAX_BLOCKS;
+ break;
+ }
+ if(mCurrentSMessageData->mMemberBlocks[bnamep]->mBlockNumber >= max)
+ {
+ return true;
+ }
+ return false;
+}
+
+static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* template_data, LLMsgData* message_data)
+{
+ S32 result = 0;
+ LLMsgData::msg_blk_data_map_t::const_iterator block_iter = message_data->mMemberBlocks.find(template_data->mName);
+ const LLMsgBlkData* mbci = block_iter->second;
+
+ // ok, if this is the first block of a repeating pack, set
+ // block_count and, if it's type MBT_VARIABLE encode a byte
+ // for how many there are
+ S32 block_count = mbci->mBlockNumber;
+ if (template_data->mType == MBT_VARIABLE)
+ {
+ // remember that mBlockNumber is a S32
+ U8 temp_block_number = (U8)mbci->mBlockNumber;
+ if ((S32)(result + sizeof(U8)) < MAX_BUFFER_SIZE)
+ {
+ memcpy(&buffer[result], &temp_block_number, sizeof(U8));
+ result += sizeof(U8);
+ }
+ else
+ {
+ // Just reporting error is likely not enough. Need
+ // to check how to abort or error out gracefully
+ // from this function. XXXTBD
+ LL_ERRS() << "buildBlock failed. Message excedding "
+ << "sendBuffersize." << LL_ENDL;
+ }
+ }
+ else if (template_data->mType == MBT_MULTIPLE)
+ {
+ if (block_count != template_data->mNumber)
+ {
+ // nope! need to fill it in all the way!
+ LL_ERRS() << "Block " << mbci->mName
+ << " is type MBT_MULTIPLE but only has data for "
+ << block_count << " out of its "
+ << template_data->mNumber << " blocks" << LL_ENDL;
+ }
+ }
+
+ while(block_count > 0)
+ {
+ // now loop through the variables
+ for (LLMsgBlkData::msg_var_data_map_t::const_iterator iter = mbci->mMemberVarData.begin();
+ iter != mbci->mMemberVarData.end(); iter++)
+ {
+ const LLMsgVarData& mvci = *iter;
+ if (mvci.getSize() == -1)
+ {
+ // oops, this variable wasn't ever set!
+ LL_ERRS() << "The variable " << mvci.getName() << " in block "
+ << mbci->mName << " of message "
+ << template_data->mName
+ << " wasn't set prior to buildMessage call" << LL_ENDL;
+ }
+ else
+ {
+ S32 data_size = mvci.getDataSize();
+ if(data_size > 0)
+ {
+ // The type is MVT_VARIABLE, which means that we
+ // need to encode a size argument. Otherwise,
+ // there is no need.
+ S32 size = mvci.getSize();
+ U8 sizeb;
+ U16 sizeh;
+ switch(data_size)
+ {
+ case 1:
+ sizeb = size;
+ htolememcpy(&buffer[result], &sizeb, MVT_U8, 1);
+ break;
+ case 2:
+ sizeh = size;
+ htolememcpy(&buffer[result], &sizeh, MVT_U16, 2);
+ break;
+ case 4:
+ htolememcpy(&buffer[result], &size, MVT_S32, 4);
+ break;
+ default:
+ LL_ERRS() << "Attempting to build variable field with unknown size of " << size << LL_ENDL;
+ break;
+ }
+ result += mvci.getDataSize();
+ }
+
+ // if there is any data to pack, pack it
+ if((mvci.getData() != NULL) && mvci.getSize())
+ {
+ if(result + mvci.getSize() < buffer_size)
+ {
+ memcpy(
+ &buffer[result],
+ mvci.getData(),
+ mvci.getSize());
+ result += mvci.getSize();
+ }
+ else
+ {
+ // Just reporting error is likely not
+ // enough. Need to check how to abort or error
+ // out gracefully from this function. XXXTBD
+ LL_ERRS() << "buildBlock failed. "
+ << "Attempted to pack "
+ << (result + mvci.getSize())
+ << " bytes into a buffer with size "
+ << buffer_size << "." << LL_ENDL;
+ }
+ }
+ }
+ }
+
+ --block_count;
+
+ if (block_iter != message_data->mMemberBlocks.end())
+ {
+ ++block_iter;
+ if (block_iter != message_data->mMemberBlocks.end())
+ {
+ mbci = block_iter->second;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+// make sure that all the desired data is in place and then copy the data into MAX_BUFFER_SIZEd buffer
+U32 LLTemplateMessageBuilder::buildMessage(
+ U8* buffer,
+ U32 buffer_size,
+ U8 offset_to_data)
+{
+ // basic algorithm is to loop through the various pieces, building
+ // size and offset info if we encounter a -1 for mSize at any
+ // point that variable wasn't given data
+
+ // do we have a current message?
+ if (!mCurrentSMessageTemplate)
+ {
+ LL_ERRS() << "newMessage not called prior to buildMessage" << LL_ENDL;
+ return 0;
+ }
+
+ // leave room for flags, packet sequence #, and data offset
+ // information.
+ buffer[PHL_OFFSET] = offset_to_data;
+ U32 result = LL_PACKET_ID_SIZE;
+
+ // encode message number and adjust total_offset
+ if (mCurrentSMessageTemplate->mFrequency == MFT_HIGH)
+ {
+// old, endian-dependant way
+// memcpy(&buffer[result], &mCurrentMessageTemplate->mMessageNumber, sizeof(U8));
+
+// new, independant way
+ buffer[result] = (U8)mCurrentSMessageTemplate->mMessageNumber;
+ result += sizeof(U8);
+ }
+ else if (mCurrentSMessageTemplate->mFrequency == MFT_MEDIUM)
+ {
+ U8 temp = 255;
+ memcpy(&buffer[result], &temp, sizeof(U8)); /*Flawfinder: ignore*/
+ result += sizeof(U8);
+
+ // mask off unsightly bits
+ temp = mCurrentSMessageTemplate->mMessageNumber & 255;
+ memcpy(&buffer[result], &temp, sizeof(U8)); /*Flawfinder: ignore*/
+ result += sizeof(U8);
+ }
+ else if (mCurrentSMessageTemplate->mFrequency == MFT_LOW)
+ {
+ U8 temp = 255;
+ U16 message_num;
+ memcpy(&buffer[result], &temp, sizeof(U8)); /*Flawfinder: ignore*/
+ result += sizeof(U8);
+ memcpy(&buffer[result], &temp, sizeof(U8)); /*Flawfinder: ignore*/
+ result += sizeof(U8);
+
+ // mask off unsightly bits
+ message_num = mCurrentSMessageTemplate->mMessageNumber & 0xFFFF;
+
+ // convert to network byte order
+ message_num = htons(message_num);
+ memcpy(&buffer[result], &message_num, sizeof(U16)); /*Flawfinder: ignore*/
+ result += sizeof(U16);
+ }
+ else
+ {
+ LL_ERRS() << "unexpected message frequency in buildMessage" << LL_ENDL;
+ return 0;
+ }
+
+ // fast forward through the offset and build the message
+ result += offset_to_data;
+ for(LLMessageTemplate::message_block_map_t::const_iterator
+ iter = mCurrentSMessageTemplate->mMemberBlocks.begin(),
+ end = mCurrentSMessageTemplate->mMemberBlocks.end();
+ iter != end;
+ ++iter)
+ {
+ result += buildBlock(buffer + result, buffer_size - result, *iter, mCurrentSMessageData);
+ }
+ mbSBuilt = true;
+
+ return result;
+}
+
+void LLTemplateMessageBuilder::copyFromMessageData(const LLMsgData& data)
+{
+ // copy the blocks
+ // counting variables used to encode multiple block info
+ S32 block_count = 0;
+ char *block_name = NULL;
+
+ // loop through msg blocks to loop through variables, totalling up size
+ // data and filling the new (send) message
+ LLMsgData::msg_blk_data_map_t::const_iterator iter =
+ data.mMemberBlocks.begin();
+ LLMsgData::msg_blk_data_map_t::const_iterator end =
+ data.mMemberBlocks.end();
+ for(; iter != end; ++iter)
+ {
+ const LLMsgBlkData* mbci = iter->second;
+ if(!mbci) continue;
+
+ // do we need to encode a block code?
+ if (block_count == 0)
+ {
+ block_count = mbci->mBlockNumber;
+ block_name = (char *)mbci->mName;
+ }
+
+ // counting down mutliple blocks
+ block_count--;
+
+ nextBlock(block_name);
+
+ // now loop through the variables
+ LLMsgBlkData::msg_var_data_map_t::const_iterator dit = mbci->mMemberVarData.begin();
+ LLMsgBlkData::msg_var_data_map_t::const_iterator dend = mbci->mMemberVarData.end();
+
+ for(; dit != dend; ++dit)
+ {
+ const LLMsgVarData& mvci = *dit;
+ addData(mvci.getName(), mvci.getData(), mvci.getType(), mvci.getSize());
+ }
+ }
+}
+
+//virtual
+void LLTemplateMessageBuilder::copyFromLLSD(const LLSD&)
+{
+ // TODO
+}
+
+//virtual
+void LLTemplateMessageBuilder::setBuilt(bool b) { mbSBuilt = b; }
+
+//virtual
+bool LLTemplateMessageBuilder::isBuilt() const {return mbSBuilt;}
+
+//virtual
+bool LLTemplateMessageBuilder::isClear() const {return mbSClear;}
+
+//virtual
+S32 LLTemplateMessageBuilder::getMessageSize() {return mCurrentSendTotal;}
+
+//virtual
+const char* LLTemplateMessageBuilder::getMessageName() const
+{
+ return mCurrentSMessageName;
+}
diff --git a/indra/llmessage/lltemplatemessagebuilder.h b/indra/llmessage/lltemplatemessagebuilder.h index f399dc8acc..bb50b0ab8a 100644 --- a/indra/llmessage/lltemplatemessagebuilder.h +++ b/indra/llmessage/lltemplatemessagebuilder.h @@ -1,115 +1,115 @@ -/** - * @file lltemplatemessagebuilder.h - * @brief Declaration of LLTemplateMessageBuilder class. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLTEMPLATEMESSAGEBUILDER_H -#define LL_LLTEMPLATEMESSAGEBUILDER_H - -#include <map> - -#include "llmessagebuilder.h" -#include "llmsgvariabletype.h" - -class LLMsgData; -class LLMessageTemplate; -class LLMsgBlkData; -class LLMessageTemplate; - -class LLTemplateMessageBuilder : public LLMessageBuilder -{ -public: - - typedef std::map<const char* , LLMessageTemplate*> message_template_name_map_t; - - LLTemplateMessageBuilder(const message_template_name_map_t&); - virtual ~LLTemplateMessageBuilder(); - - virtual void newMessage(const char* name); - - virtual void nextBlock(const char* blockname); - virtual BOOL removeLastBlock(); // TODO: babbage: remove this horror... - - /** All add* methods expect pointers to canonical varname strings. */ - virtual void addBinaryData(const char *varname, const void *data, - S32 size); - virtual void addBOOL(const char* varname, BOOL b); - virtual void addS8(const char* varname, S8 s); - virtual void addU8(const char* varname, U8 u); - virtual void addS16(const char* varname, S16 i); - virtual void addU16(const char* varname, U16 i); - virtual void addF32(const char* varname, F32 f); - virtual void addS32(const char* varname, S32 s); - virtual void addU32(const char* varname, U32 u); - virtual void addU64(const char* varname, U64 lu); - virtual void addF64(const char* varname, F64 d); - virtual void addVector3(const char* varname, const LLVector3& vec); - virtual void addVector4(const char* varname, const LLVector4& vec); - virtual void addVector3d(const char* varname, const LLVector3d& vec); - virtual void addQuat(const char* varname, const LLQuaternion& quat); - virtual void addUUID(const char* varname, const LLUUID& uuid); - virtual void addIPAddr(const char* varname, const U32 ip); - virtual void addIPPort(const char* varname, const U16 port); - virtual void addString(const char* varname, const char* s); - virtual void addString(const char* varname, const std::string& s); - - virtual BOOL isMessageFull(const char* blockname) const; - virtual void compressMessage(U8*& buf_ptr, U32& buffer_length); - - virtual BOOL isBuilt() const; - virtual BOOL isClear() const; - virtual U32 buildMessage(U8* buffer, U32 buffer_size, U8 offset_to_data); - /**< Return built message size */ - - virtual void clearMessage(); - - // TODO: babbage: remove this horror. - virtual void setBuilt(BOOL b); - - virtual S32 getMessageSize(); - virtual const char* getMessageName() const; - - virtual void copyFromMessageData(const LLMsgData& data); - virtual void copyFromLLSD(const LLSD&); - - LLMsgData* getCurrentMessage() const { return mCurrentSMessageData; } -private: - void addData(const char* varname, const void* data, - EMsgVariableType type, S32 size); - - void addData(const char* varname, const void* data, - EMsgVariableType type); - - LLMsgData* mCurrentSMessageData; - const LLMessageTemplate* mCurrentSMessageTemplate; - LLMsgBlkData* mCurrentSDataBlock; - char* mCurrentSMessageName; - char* mCurrentSBlockName; - BOOL mbSBuilt; - BOOL mbSClear; - S32 mCurrentSendTotal; - const message_template_name_map_t& mMessageTemplates; -}; - -#endif // LL_LLTEMPLATEMESSAGEBUILDER_H +/**
+ * @file lltemplatemessagebuilder.h
+ * @brief Declaration of LLTemplateMessageBuilder class.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#ifndef LL_LLTEMPLATEMESSAGEBUILDER_H
+#define LL_LLTEMPLATEMESSAGEBUILDER_H
+
+#include <map>
+
+#include "llmessagebuilder.h"
+#include "llmsgvariabletype.h"
+
+class LLMsgData;
+class LLMessageTemplate;
+class LLMsgBlkData;
+class LLMessageTemplate;
+
+class LLTemplateMessageBuilder : public LLMessageBuilder
+{
+public:
+
+ typedef std::map<const char* , LLMessageTemplate*> message_template_name_map_t;
+
+ LLTemplateMessageBuilder(const message_template_name_map_t&);
+ virtual ~LLTemplateMessageBuilder();
+
+ virtual void newMessage(const char* name);
+
+ virtual void nextBlock(const char* blockname);
+ virtual bool removeLastBlock(); // TODO: babbage: remove this horror...
+
+ /** All add* methods expect pointers to canonical varname strings. */
+ virtual void addBinaryData(const char *varname, const void *data,
+ S32 size);
+ virtual void addBOOL(const char* varname, bool b);
+ virtual void addS8(const char* varname, S8 s);
+ virtual void addU8(const char* varname, U8 u);
+ virtual void addS16(const char* varname, S16 i);
+ virtual void addU16(const char* varname, U16 i);
+ virtual void addF32(const char* varname, F32 f);
+ virtual void addS32(const char* varname, S32 s);
+ virtual void addU32(const char* varname, U32 u);
+ virtual void addU64(const char* varname, U64 lu);
+ virtual void addF64(const char* varname, F64 d);
+ virtual void addVector3(const char* varname, const LLVector3& vec);
+ virtual void addVector4(const char* varname, const LLVector4& vec);
+ virtual void addVector3d(const char* varname, const LLVector3d& vec);
+ virtual void addQuat(const char* varname, const LLQuaternion& quat);
+ virtual void addUUID(const char* varname, const LLUUID& uuid);
+ virtual void addIPAddr(const char* varname, const U32 ip);
+ virtual void addIPPort(const char* varname, const U16 port);
+ virtual void addString(const char* varname, const char* s);
+ virtual void addString(const char* varname, const std::string& s);
+
+ virtual bool isMessageFull(const char* blockname) const;
+ virtual void compressMessage(U8*& buf_ptr, U32& buffer_length);
+
+ virtual bool isBuilt() const;
+ virtual bool isClear() const;
+ virtual U32 buildMessage(U8* buffer, U32 buffer_size, U8 offset_to_data);
+ /**< Return built message size */
+
+ virtual void clearMessage();
+
+ // TODO: babbage: remove this horror.
+ virtual void setBuilt(bool b);
+
+ virtual S32 getMessageSize();
+ virtual const char* getMessageName() const;
+
+ virtual void copyFromMessageData(const LLMsgData& data);
+ virtual void copyFromLLSD(const LLSD&);
+
+ LLMsgData* getCurrentMessage() const { return mCurrentSMessageData; }
+private:
+ void addData(const char* varname, const void* data,
+ EMsgVariableType type, S32 size);
+
+ void addData(const char* varname, const void* data,
+ EMsgVariableType type);
+
+ LLMsgData* mCurrentSMessageData;
+ const LLMessageTemplate* mCurrentSMessageTemplate;
+ LLMsgBlkData* mCurrentSDataBlock;
+ char* mCurrentSMessageName;
+ char* mCurrentSBlockName;
+ bool mbSBuilt;
+ bool mbSClear;
+ S32 mCurrentSendTotal;
+ const message_template_name_map_t& mMessageTemplates;
+};
+
+#endif // LL_LLTEMPLATEMESSAGEBUILDER_H
diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 370d458eb8..46123f0f55 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -1,830 +1,830 @@ -/** - * @file lltemplatemessagereader.cpp - * @brief LLTemplateMessageReader class implementation. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "linden_common.h" -#include "lltemplatemessagereader.h" - -#include "llfasttimer.h" -#include "llmessagebuilder.h" -#include "llmessagetemplate.h" -#include "llmath.h" -#include "llquaternion.h" -#include "message.h" -#include "u64.h" -#include "v3dmath.h" -#include "v3math.h" -#include "v4math.h" - -LLTemplateMessageReader::LLTemplateMessageReader(message_template_number_map_t& - number_template_map) : - mReceiveSize(0), - mCurrentRMessageTemplate(NULL), - mCurrentRMessageData(NULL), - mMessageNumbers(number_template_map) -{ -} - -//virtual -LLTemplateMessageReader::~LLTemplateMessageReader() -{ - delete mCurrentRMessageData; - mCurrentRMessageData = NULL; -} - -//virtual -void LLTemplateMessageReader::clearMessage() -{ - mReceiveSize = -1; - mCurrentRMessageTemplate = NULL; - delete mCurrentRMessageData; - mCurrentRMessageData = NULL; -} - -void LLTemplateMessageReader::getData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum, S32 max_size) -{ - // is there a message ready to go? - if (mReceiveSize == -1) - { - LL_ERRS() << "No message waiting for decode 2!" << LL_ENDL; - return; - } - - if (!mCurrentRMessageData) - { - LL_ERRS() << "Invalid mCurrentMessageData in getData!" << LL_ENDL; - return; - } - - char *bnamep = (char *)blockname + blocknum; // this works because it's just a hash. The bnamep is never derefference - char *vnamep = (char *)varname; - - LLMsgData::msg_blk_data_map_t::const_iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep); - - if (iter == mCurrentRMessageData->mMemberBlocks.end()) - { - LL_ERRS() << "Block " << blockname << " #" << blocknum - << " not in message " << mCurrentRMessageData->mName << LL_ENDL; - return; - } - - LLMsgBlkData *msg_block_data = iter->second; - LLMsgBlkData::msg_var_data_map_t &var_data_map = msg_block_data->mMemberVarData; - - if (var_data_map.find(vnamep) == var_data_map.end()) - { - LL_ERRS() << "Variable "<< vnamep << " not in message " - << mCurrentRMessageData->mName<< " block " << bnamep << LL_ENDL; - return; - } - - LLMsgVarData& vardata = msg_block_data->mMemberVarData[vnamep]; - - if (size && size != vardata.getSize()) - { - LL_ERRS() << "Msg " << mCurrentRMessageData->mName - << " variable " << vnamep - << " is size " << vardata.getSize() - << " but copying into buffer of size " << size - << LL_ENDL; - return; - } - - - const S32 vardata_size = vardata.getSize(); - if( max_size >= vardata_size ) - { - switch( vardata_size ) - { - case 1: - *((U8*)datap) = *((U8*)vardata.getData()); - break; - case 2: - *((U16*)datap) = *((U16*)vardata.getData()); - break; - case 4: - *((U32*)datap) = *((U32*)vardata.getData()); - break; - case 8: - ((U32*)datap)[0] = ((U32*)vardata.getData())[0]; - ((U32*)datap)[1] = ((U32*)vardata.getData())[1]; - break; - default: - memcpy(datap, vardata.getData(), vardata_size); - break; - } - } - else - { - LL_WARNS() << "Msg " << mCurrentRMessageData->mName - << " variable " << vnamep - << " is size " << vardata.getSize() - << " but truncated to max size of " << max_size - << LL_ENDL; - - memcpy(datap, vardata.getData(), max_size); - } -} - -S32 LLTemplateMessageReader::getNumberOfBlocks(const char *blockname) -{ - // is there a message ready to go? - if (mReceiveSize == -1) - { - LL_ERRS() << "No message waiting for decode 3!" << LL_ENDL; - return -1; - } - - if (!mCurrentRMessageData) - { - LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL; - return -1; - } - - char *bnamep = (char *)blockname; - - LLMsgData::msg_blk_data_map_t::const_iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep); - - if (iter == mCurrentRMessageData->mMemberBlocks.end()) - { - return 0; - } - - return (iter->second)->mBlockNumber; -} - -S32 LLTemplateMessageReader::getSize(const char *blockname, const char *varname) -{ - // is there a message ready to go? - if (mReceiveSize == -1) - { // This is a serious error - crash - LL_ERRS() << "No message waiting for decode 4!" << LL_ENDL; - return LL_MESSAGE_ERROR; - } - - if (!mCurrentRMessageData) - { // This is a serious error - crash - LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL; - return LL_MESSAGE_ERROR; - } - - char *bnamep = (char *)blockname; - - LLMsgData::msg_blk_data_map_t::const_iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep); - - if (iter == mCurrentRMessageData->mMemberBlocks.end()) - { // don't crash - LL_INFOS() << "Block " << bnamep << " not in message " - << mCurrentRMessageData->mName << LL_ENDL; - return LL_BLOCK_NOT_IN_MESSAGE; - } - - char *vnamep = (char *)varname; - - LLMsgBlkData* msg_data = iter->second; - LLMsgVarData& vardata = msg_data->mMemberVarData[vnamep]; - - if (!vardata.getName()) - { // don't crash - LL_INFOS() << "Variable " << varname << " not in message " - << mCurrentRMessageData->mName << " block " << bnamep << LL_ENDL; - return LL_VARIABLE_NOT_IN_BLOCK; - } - - if (mCurrentRMessageTemplate->mMemberBlocks[bnamep]->mType != MBT_SINGLE) - { // This is a serious error - crash - LL_ERRS() << "Block " << bnamep << " isn't type MBT_SINGLE," - " use getSize with blocknum argument!" << LL_ENDL; - return LL_MESSAGE_ERROR; - } - - return vardata.getSize(); -} - -S32 LLTemplateMessageReader::getSize(const char *blockname, S32 blocknum, const char *varname) -{ - // is there a message ready to go? - if (mReceiveSize == -1) - { // This is a serious error - crash - LL_ERRS() << "No message waiting for decode 5!" << LL_ENDL; - return LL_MESSAGE_ERROR; - } - - if (!mCurrentRMessageData) - { // This is a serious error - crash - LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL; - return LL_MESSAGE_ERROR; - } - - char *bnamep = (char *)blockname + blocknum; - char *vnamep = (char *)varname; - - LLMsgData::msg_blk_data_map_t::const_iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep); - - if (iter == mCurrentRMessageData->mMemberBlocks.end()) - { // don't crash - LL_INFOS() << "Block " << bnamep << " not in message " - << mCurrentRMessageData->mName << LL_ENDL; - return LL_BLOCK_NOT_IN_MESSAGE; - } - - LLMsgBlkData* msg_data = iter->second; - LLMsgVarData& vardata = msg_data->mMemberVarData[vnamep]; - - if (!vardata.getName()) - { // don't crash - LL_INFOS() << "Variable " << vnamep << " not in message " - << mCurrentRMessageData->mName << " block " << bnamep << LL_ENDL; - return LL_VARIABLE_NOT_IN_BLOCK; - } - - return vardata.getSize(); -} - -void LLTemplateMessageReader::getBinaryData(const char *blockname, - const char *varname, void *datap, - S32 size, S32 blocknum, - S32 max_size) -{ - getData(blockname, varname, datap, size, blocknum, max_size); -} - -void LLTemplateMessageReader::getS8(const char *block, const char *var, - S8 &u, S32 blocknum) -{ - getData(block, var, &u, sizeof(S8), blocknum); -} - -void LLTemplateMessageReader::getU8(const char *block, const char *var, - U8 &u, S32 blocknum) -{ - getData(block, var, &u, sizeof(U8), blocknum); -} - -void LLTemplateMessageReader::getBOOL(const char *block, const char *var, - BOOL &b, S32 blocknum ) -{ - U8 value; - getData(block, var, &value, sizeof(U8), blocknum); - b = (BOOL) value; -} - -void LLTemplateMessageReader::getS16(const char *block, const char *var, - S16 &d, S32 blocknum) -{ - getData(block, var, &d, sizeof(S16), blocknum); -} - -void LLTemplateMessageReader::getU16(const char *block, const char *var, - U16 &d, S32 blocknum) -{ - getData(block, var, &d, sizeof(U16), blocknum); -} - -void LLTemplateMessageReader::getS32(const char *block, const char *var, - S32 &d, S32 blocknum) -{ - getData(block, var, &d, sizeof(S32), blocknum); -} - -void LLTemplateMessageReader::getU32(const char *block, const char *var, - U32 &d, S32 blocknum) -{ - getData(block, var, &d, sizeof(U32), blocknum); -} - -void LLTemplateMessageReader::getU64(const char *block, const char *var, - U64 &d, S32 blocknum) -{ - getData(block, var, &d, sizeof(U64), blocknum); -} - -void LLTemplateMessageReader::getF32(const char *block, const char *var, - F32 &d, S32 blocknum) -{ - getData(block, var, &d, sizeof(F32), blocknum); - - if( !llfinite( d ) ) - { - LL_WARNS() << "non-finite in getF32Fast " << block << " " << var - << LL_ENDL; - d = 0; - } -} - -void LLTemplateMessageReader::getF64(const char *block, const char *var, - F64 &d, S32 blocknum) -{ - getData(block, var, &d, sizeof(F64), blocknum); - - if( !llfinite( d ) ) - { - LL_WARNS() << "non-finite in getF64Fast " << block << " " << var - << LL_ENDL; - d = 0; - } -} - -void LLTemplateMessageReader::getVector3(const char *block, const char *var, - LLVector3 &v, S32 blocknum ) -{ - getData(block, var, &v.mV[0], sizeof(v.mV), blocknum); - - if( !v.isFinite() ) - { - LL_WARNS() << "non-finite in getVector3Fast " << block << " " - << var << LL_ENDL; - v.zeroVec(); - } -} - -void LLTemplateMessageReader::getVector4(const char *block, const char *var, - LLVector4 &v, S32 blocknum) -{ - getData(block, var, &v.mV[0], sizeof(v.mV), blocknum); - - if( !v.isFinite() ) - { - LL_WARNS() << "non-finite in getVector4Fast " << block << " " - << var << LL_ENDL; - v.zeroVec(); - } -} - -void LLTemplateMessageReader::getVector3d(const char *block, const char *var, - LLVector3d &v, S32 blocknum ) -{ - getData(block, var, &v.mdV[0], sizeof(v.mdV), blocknum); - - if( !v.isFinite() ) - { - LL_WARNS() << "non-finite in getVector3dFast " << block << " " - << var << LL_ENDL; - v.zeroVec(); - } - -} - -void LLTemplateMessageReader::getQuat(const char *block, const char *var, - LLQuaternion &q, S32 blocknum) -{ - LLVector3 vec; - getData(block, var, &vec.mV[0], sizeof(vec.mV), blocknum); - if( vec.isFinite() ) - { - q.unpackFromVector3( vec ); - } - else - { - LL_WARNS() << "non-finite in getQuatFast " << block << " " << var - << LL_ENDL; - q.loadIdentity(); - } -} - -void LLTemplateMessageReader::getUUID(const char *block, const char *var, - LLUUID &u, S32 blocknum) -{ - getData(block, var, &u.mData[0], sizeof(u.mData), blocknum); -} - -inline void LLTemplateMessageReader::getIPAddr(const char *block, const char *var, U32 &u, S32 blocknum) -{ - getData(block, var, &u, sizeof(U32), blocknum); -} - -inline void LLTemplateMessageReader::getIPPort(const char *block, const char *var, U16 &u, S32 blocknum) -{ - getData(block, var, &u, sizeof(U16), blocknum); - u = ntohs(u); -} - -inline void LLTemplateMessageReader::getString(const char *block, const char *var, S32 buffer_size, char *s, S32 blocknum ) -{ - s[0] = '\0'; - getData(block, var, s, 0, blocknum, buffer_size); - s[buffer_size - 1] = '\0'; -} - -inline void LLTemplateMessageReader::getString(const char *block, const char *var, std::string& outstr, S32 blocknum ) -{ - char s[MTUBYTES + 1]= {0}; // every element is initialized with 0 - getData(block, var, s, 0, blocknum, MTUBYTES); - s[MTUBYTES] = '\0'; - outstr = s; -} - -//virtual -S32 LLTemplateMessageReader::getMessageSize() const -{ - return mReceiveSize; -} - -// Returns template for the message contained in buffer -BOOL LLTemplateMessageReader::decodeTemplate( - const U8* buffer, S32 buffer_size, // inputs - LLMessageTemplate** msg_template ) // outputs -{ - const U8* header = buffer + LL_PACKET_ID_SIZE; - - // is there a message ready to go? - if (buffer_size <= 0) - { - LL_WARNS() << "No message waiting for decode!" << LL_ENDL; - return(FALSE); - } - - U32 num = 0; - - if (header[0] != 255) - { - // high frequency message - num = header[0]; - } - else if ((buffer_size >= ((S32) LL_MINIMUM_VALID_PACKET_SIZE + 1)) && (header[1] != 255)) - { - // medium frequency message - num = (255 << 8) | header[1]; - } - else if ((buffer_size >= ((S32) LL_MINIMUM_VALID_PACKET_SIZE + 3)) && (header[1] == 255)) - { - // low frequency message - U16 message_id_U16 = 0; - // I think this check busts the message system. - // it appears that if there is a NULL in the message #, it won't copy it.... - // what was the goal? - //if(header[2]) - memcpy(&message_id_U16, &header[2], 2); - - // dependant on endian-ness: - // U32 temp = (255 << 24) | (255 << 16) | header[2]; - - // independant of endian-ness: - message_id_U16 = ntohs(message_id_U16); - num = 0xFFFF0000 | message_id_U16; - } - else // bogus packet received (too short) - { - LL_WARNS() << "Packet with unusable length received (too short): " - << buffer_size << LL_ENDL; - return(FALSE); - } - - LLMessageTemplate* temp = get_ptr_in_map(mMessageNumbers,num); - if (temp) - { - *msg_template = temp; - } - else - { - // MAINT-7482 - make viewer more tolerant of unknown messages. - LL_WARNS_ONCE() << "Message #" << std::hex << num << std::dec - << " received but not registered!" << LL_ENDL; - //gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); - return(FALSE); - } - - return(TRUE); -} - -void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S32 where, const S32 wanted ) -{ - // we've run off the end of the packet! - LL_WARNS() << "Ran off end of packet " << mCurrentRMessageTemplate->mName -// << " with id " << mCurrentRecvPacketID - << " from " << host - << " trying to read " << wanted - << " bytes at position " << where - << " going past packet end at " << mReceiveSize - << LL_ENDL; - if(gMessageSystem->mVerboseLog) - { - LL_INFOS() << "MSG: -> " << host << "\tREAD PAST END:\t" -// << mCurrentRecvPacketID << " " - << getMessageName() << LL_ENDL; - } - gMessageSystem->callExceptionFunc(MX_RAN_OFF_END_OF_PACKET); -} - -static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages"); - -// decode a given message -BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender ) -{ - LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES); - - llassert( mReceiveSize >= 0 ); - llassert( mCurrentRMessageTemplate); - llassert( !mCurrentRMessageData ); - delete mCurrentRMessageData; // just to make sure - - // The offset tells us how may bytes to skip after the end of the - // message name. - U8 offset = buffer[PHL_OFFSET]; - S32 decode_pos = LL_PACKET_ID_SIZE + (S32)(mCurrentRMessageTemplate->mFrequency) + offset; - - // create base working data set - mCurrentRMessageData = new LLMsgData(mCurrentRMessageTemplate->mName); - - // loop through the template building the data structure as we go - LLMessageTemplate::message_block_map_t::const_iterator iter; - for(iter = mCurrentRMessageTemplate->mMemberBlocks.begin(); - iter != mCurrentRMessageTemplate->mMemberBlocks.end(); - ++iter) - { - LLMessageBlock* mbci = *iter; - U8 repeat_number; - S32 i; - - // how many of this block? - - if (mbci->mType == MBT_SINGLE) - { - // just one - repeat_number = 1; - } - else if (mbci->mType == MBT_MULTIPLE) - { - // a known number - repeat_number = mbci->mNumber; - } - else if (mbci->mType == MBT_VARIABLE) - { - // need to read the number from the message - // repeat number is a single byte - if (decode_pos >= mReceiveSize) - { - // commented out - hetgrid says that missing variable blocks - // at end of message are legal - // logRanOffEndOfPacket(sender, decode_pos, 1); - - // default to 0 repeats - repeat_number = 0; - } - else - { - repeat_number = buffer[decode_pos]; - decode_pos++; - } - } - else - { - LL_ERRS() << "Unknown block type" << LL_ENDL; - return FALSE; - } - - LLMsgBlkData* cur_data_block = NULL; - - // now loop through the block - for (i = 0; i < repeat_number; i++) - { - if (i) - { - // build new name to prevent collisions - // TODO: This should really change to a vector - cur_data_block = new LLMsgBlkData(mbci->mName, repeat_number); - cur_data_block->mName = mbci->mName + i; - } - else - { - cur_data_block = new LLMsgBlkData(mbci->mName, repeat_number); - } - - // add the block to the message - mCurrentRMessageData->addBlock(cur_data_block); - - // now read the variables - for (LLMessageBlock::message_variable_map_t::const_iterator iter = - mbci->mMemberVariables.begin(); - iter != mbci->mMemberVariables.end(); iter++) - { - const LLMessageVariable& mvci = **iter; - - // ok, build out the variables - // add variable block - cur_data_block->addVariable(mvci.getName(), mvci.getType()); - - // what type of variable? - if (mvci.getType() == MVT_VARIABLE) - { - // variable, get the number of bytes to read from the template - S32 data_size = mvci.getSize(); - U8 tsizeb = 0; - U16 tsizeh = 0; - U32 tsize = 0; - - if ((decode_pos + data_size) > mReceiveSize) - { - logRanOffEndOfPacket(sender, decode_pos, data_size); - - // default to 0 length variable blocks - tsize = 0; - } - else - { - switch(data_size) - { - case 1: - htolememcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1); - tsize = tsizeb; - break; - case 2: - htolememcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2); - tsize = tsizeh; - break; - case 4: - htolememcpy(&tsize, &buffer[decode_pos], MVT_U32, 4); - break; - default: - LL_ERRS() << "Attempting to read variable field with unknown size of " << data_size << LL_ENDL; - break; - } - } - decode_pos += data_size; - - cur_data_block->addData(mvci.getName(), &buffer[decode_pos], tsize, mvci.getType()); - decode_pos += tsize; - } - else - { - // fixed! - // so, copy data pointer and set data size to fixed size - if ((decode_pos + mvci.getSize()) > mReceiveSize) - { - logRanOffEndOfPacket(sender, decode_pos, mvci.getSize()); - - // default to 0s. - U32 size = mvci.getSize(); - std::vector<U8> data(size, 0); - cur_data_block->addData(mvci.getName(), &(data[0]), - size, mvci.getType()); - } - else - { - cur_data_block->addData(mvci.getName(), - &buffer[decode_pos], - mvci.getSize(), - mvci.getType()); - } - decode_pos += mvci.getSize(); - } - } - } - } - - if (mCurrentRMessageData->mMemberBlocks.empty() - && !mCurrentRMessageTemplate->mMemberBlocks.empty()) - { - LL_DEBUGS() << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << LL_ENDL; - return FALSE; - } - - { - static LLTimer decode_timer; - - if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback()) - { - decode_timer.reset(); - } - - if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) ) - { - LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL; - } - - if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback()) - { - F32 decode_time = decode_timer.getElapsedTimeF32(); - - if (gMessageSystem->getTimingCallback()) - { - (gMessageSystem->getTimingCallback())(mCurrentRMessageTemplate->mName, - decode_time, - gMessageSystem->getTimingCallbackData()); - } - - if (LLMessageReader::getTimeDecodes()) - { - mCurrentRMessageTemplate->mDecodeTimeThisFrame += decode_time; - - mCurrentRMessageTemplate->mTotalDecoded++; - mCurrentRMessageTemplate->mTotalDecodeTime += decode_time; - - if( mCurrentRMessageTemplate->mMaxDecodeTimePerMsg < decode_time ) - { - mCurrentRMessageTemplate->mMaxDecodeTimePerMsg = decode_time; - } - - - if(decode_time > LLMessageReader::getTimeDecodesSpamThreshold()) - { - LL_DEBUGS() << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " << decode_time << " seconds. (" << - mCurrentRMessageTemplate->mMaxDecodeTimePerMsg << " max, " << - (mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate->mTotalDecoded) << " avg)" << LL_ENDL; - } - } - } - } - return TRUE; -} - -BOOL LLTemplateMessageReader::validateMessage(const U8* buffer, - S32 buffer_size, - const LLHost& sender, - bool trusted) -{ - mReceiveSize = buffer_size; - BOOL valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate ); - if(valid) - { - mCurrentRMessageTemplate->mReceiveCount++; - //LL_DEBUGS() << "MessageRecvd:" - // << mCurrentRMessageTemplate->mName - // << " from " << sender << LL_ENDL; - } - - if (valid && isBanned(trusted)) - { - LL_WARNS("Messaging") << "LLMessageSystem::checkMessages " - << "received banned message " - << getMessageName() - << " from " - << ((trusted) ? "trusted " : "untrusted ") - << sender << LL_ENDL; - valid = FALSE; - } - - if(valid && isUdpBanned()) - { - LL_WARNS() << "Received UDP black listed message " - << getMessageName() - << " from " << sender << LL_ENDL; - valid = FALSE; - } - return valid; -} - -BOOL LLTemplateMessageReader::readMessage(const U8* buffer, - const LLHost& sender) -{ - return decodeData(buffer, sender); -} - -//virtual -const char* LLTemplateMessageReader::getMessageName() const -{ - if (!mCurrentRMessageTemplate) - { - // no message currently being read - return ""; - } - return mCurrentRMessageTemplate->mName; -} - -//virtual -bool LLTemplateMessageReader::isTrusted() const -{ - return mCurrentRMessageTemplate->getTrust() == MT_TRUST; -} - -bool LLTemplateMessageReader::isBanned(bool trustedSource) const -{ - return mCurrentRMessageTemplate->isBanned(trustedSource); -} - -bool LLTemplateMessageReader::isUdpBanned() const -{ - return mCurrentRMessageTemplate->isUdpBanned(); -} - -//virtual -void LLTemplateMessageReader::copyToBuilder(LLMessageBuilder& builder) const -{ - if(NULL == mCurrentRMessageTemplate) - { - return; - } - builder.copyFromMessageData(*mCurrentRMessageData); -} +/**
+ * @file lltemplatemessagereader.cpp
+ * @brief LLTemplateMessageReader class implementation.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+#include "lltemplatemessagereader.h"
+
+#include "llfasttimer.h"
+#include "llmessagebuilder.h"
+#include "llmessagetemplate.h"
+#include "llmath.h"
+#include "llquaternion.h"
+#include "message.h"
+#include "u64.h"
+#include "v3dmath.h"
+#include "v3math.h"
+#include "v4math.h"
+
+LLTemplateMessageReader::LLTemplateMessageReader(message_template_number_map_t&
+ number_template_map) :
+ mReceiveSize(0),
+ mCurrentRMessageTemplate(NULL),
+ mCurrentRMessageData(NULL),
+ mMessageNumbers(number_template_map)
+{
+}
+
+//virtual
+LLTemplateMessageReader::~LLTemplateMessageReader()
+{
+ delete mCurrentRMessageData;
+ mCurrentRMessageData = NULL;
+}
+
+//virtual
+void LLTemplateMessageReader::clearMessage()
+{
+ mReceiveSize = -1;
+ mCurrentRMessageTemplate = NULL;
+ delete mCurrentRMessageData;
+ mCurrentRMessageData = NULL;
+}
+
+void LLTemplateMessageReader::getData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum, S32 max_size)
+{
+ // is there a message ready to go?
+ if (mReceiveSize == -1)
+ {
+ LL_ERRS() << "No message waiting for decode 2!" << LL_ENDL;
+ return;
+ }
+
+ if (!mCurrentRMessageData)
+ {
+ LL_ERRS() << "Invalid mCurrentMessageData in getData!" << LL_ENDL;
+ return;
+ }
+
+ char *bnamep = (char *)blockname + blocknum; // this works because it's just a hash. The bnamep is never derefference
+ char *vnamep = (char *)varname;
+
+ LLMsgData::msg_blk_data_map_t::const_iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep);
+
+ if (iter == mCurrentRMessageData->mMemberBlocks.end())
+ {
+ LL_ERRS() << "Block " << blockname << " #" << blocknum
+ << " not in message " << mCurrentRMessageData->mName << LL_ENDL;
+ return;
+ }
+
+ LLMsgBlkData *msg_block_data = iter->second;
+ LLMsgBlkData::msg_var_data_map_t &var_data_map = msg_block_data->mMemberVarData;
+
+ if (var_data_map.find(vnamep) == var_data_map.end())
+ {
+ LL_ERRS() << "Variable "<< vnamep << " not in message "
+ << mCurrentRMessageData->mName<< " block " << bnamep << LL_ENDL;
+ return;
+ }
+
+ LLMsgVarData& vardata = msg_block_data->mMemberVarData[vnamep];
+
+ if (size && size != vardata.getSize())
+ {
+ LL_ERRS() << "Msg " << mCurrentRMessageData->mName
+ << " variable " << vnamep
+ << " is size " << vardata.getSize()
+ << " but copying into buffer of size " << size
+ << LL_ENDL;
+ return;
+ }
+
+
+ const S32 vardata_size = vardata.getSize();
+ if( max_size >= vardata_size )
+ {
+ switch( vardata_size )
+ {
+ case 1:
+ *((U8*)datap) = *((U8*)vardata.getData());
+ break;
+ case 2:
+ *((U16*)datap) = *((U16*)vardata.getData());
+ break;
+ case 4:
+ *((U32*)datap) = *((U32*)vardata.getData());
+ break;
+ case 8:
+ ((U32*)datap)[0] = ((U32*)vardata.getData())[0];
+ ((U32*)datap)[1] = ((U32*)vardata.getData())[1];
+ break;
+ default:
+ memcpy(datap, vardata.getData(), vardata_size);
+ break;
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Msg " << mCurrentRMessageData->mName
+ << " variable " << vnamep
+ << " is size " << vardata.getSize()
+ << " but truncated to max size of " << max_size
+ << LL_ENDL;
+
+ memcpy(datap, vardata.getData(), max_size);
+ }
+}
+
+S32 LLTemplateMessageReader::getNumberOfBlocks(const char *blockname)
+{
+ // is there a message ready to go?
+ if (mReceiveSize == -1)
+ {
+ LL_ERRS() << "No message waiting for decode 3!" << LL_ENDL;
+ return -1;
+ }
+
+ if (!mCurrentRMessageData)
+ {
+ LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL;
+ return -1;
+ }
+
+ char *bnamep = (char *)blockname;
+
+ LLMsgData::msg_blk_data_map_t::const_iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep);
+
+ if (iter == mCurrentRMessageData->mMemberBlocks.end())
+ {
+ return 0;
+ }
+
+ return (iter->second)->mBlockNumber;
+}
+
+S32 LLTemplateMessageReader::getSize(const char *blockname, const char *varname)
+{
+ // is there a message ready to go?
+ if (mReceiveSize == -1)
+ { // This is a serious error - crash
+ LL_ERRS() << "No message waiting for decode 4!" << LL_ENDL;
+ return LL_MESSAGE_ERROR;
+ }
+
+ if (!mCurrentRMessageData)
+ { // This is a serious error - crash
+ LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL;
+ return LL_MESSAGE_ERROR;
+ }
+
+ char *bnamep = (char *)blockname;
+
+ LLMsgData::msg_blk_data_map_t::const_iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep);
+
+ if (iter == mCurrentRMessageData->mMemberBlocks.end())
+ { // don't crash
+ LL_INFOS() << "Block " << bnamep << " not in message "
+ << mCurrentRMessageData->mName << LL_ENDL;
+ return LL_BLOCK_NOT_IN_MESSAGE;
+ }
+
+ char *vnamep = (char *)varname;
+
+ LLMsgBlkData* msg_data = iter->second;
+ LLMsgVarData& vardata = msg_data->mMemberVarData[vnamep];
+
+ if (!vardata.getName())
+ { // don't crash
+ LL_INFOS() << "Variable " << varname << " not in message "
+ << mCurrentRMessageData->mName << " block " << bnamep << LL_ENDL;
+ return LL_VARIABLE_NOT_IN_BLOCK;
+ }
+
+ if (mCurrentRMessageTemplate->mMemberBlocks[bnamep]->mType != MBT_SINGLE)
+ { // This is a serious error - crash
+ LL_ERRS() << "Block " << bnamep << " isn't type MBT_SINGLE,"
+ " use getSize with blocknum argument!" << LL_ENDL;
+ return LL_MESSAGE_ERROR;
+ }
+
+ return vardata.getSize();
+}
+
+S32 LLTemplateMessageReader::getSize(const char *blockname, S32 blocknum, const char *varname)
+{
+ // is there a message ready to go?
+ if (mReceiveSize == -1)
+ { // This is a serious error - crash
+ LL_ERRS() << "No message waiting for decode 5!" << LL_ENDL;
+ return LL_MESSAGE_ERROR;
+ }
+
+ if (!mCurrentRMessageData)
+ { // This is a serious error - crash
+ LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL;
+ return LL_MESSAGE_ERROR;
+ }
+
+ char *bnamep = (char *)blockname + blocknum;
+ char *vnamep = (char *)varname;
+
+ LLMsgData::msg_blk_data_map_t::const_iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep);
+
+ if (iter == mCurrentRMessageData->mMemberBlocks.end())
+ { // don't crash
+ LL_INFOS() << "Block " << bnamep << " not in message "
+ << mCurrentRMessageData->mName << LL_ENDL;
+ return LL_BLOCK_NOT_IN_MESSAGE;
+ }
+
+ LLMsgBlkData* msg_data = iter->second;
+ LLMsgVarData& vardata = msg_data->mMemberVarData[vnamep];
+
+ if (!vardata.getName())
+ { // don't crash
+ LL_INFOS() << "Variable " << vnamep << " not in message "
+ << mCurrentRMessageData->mName << " block " << bnamep << LL_ENDL;
+ return LL_VARIABLE_NOT_IN_BLOCK;
+ }
+
+ return vardata.getSize();
+}
+
+void LLTemplateMessageReader::getBinaryData(const char *blockname,
+ const char *varname, void *datap,
+ S32 size, S32 blocknum,
+ S32 max_size)
+{
+ getData(blockname, varname, datap, size, blocknum, max_size);
+}
+
+void LLTemplateMessageReader::getS8(const char *block, const char *var,
+ S8 &u, S32 blocknum)
+{
+ getData(block, var, &u, sizeof(S8), blocknum);
+}
+
+void LLTemplateMessageReader::getU8(const char *block, const char *var,
+ U8 &u, S32 blocknum)
+{
+ getData(block, var, &u, sizeof(U8), blocknum);
+}
+
+void LLTemplateMessageReader::getBOOL(const char *block, const char *var,
+ bool &b, S32 blocknum )
+{
+ U8 value;
+ getData(block, var, &value, sizeof(U8), blocknum);
+ b = (bool)value;
+}
+
+void LLTemplateMessageReader::getS16(const char *block, const char *var,
+ S16 &d, S32 blocknum)
+{
+ getData(block, var, &d, sizeof(S16), blocknum);
+}
+
+void LLTemplateMessageReader::getU16(const char *block, const char *var,
+ U16 &d, S32 blocknum)
+{
+ getData(block, var, &d, sizeof(U16), blocknum);
+}
+
+void LLTemplateMessageReader::getS32(const char *block, const char *var,
+ S32 &d, S32 blocknum)
+{
+ getData(block, var, &d, sizeof(S32), blocknum);
+}
+
+void LLTemplateMessageReader::getU32(const char *block, const char *var,
+ U32 &d, S32 blocknum)
+{
+ getData(block, var, &d, sizeof(U32), blocknum);
+}
+
+void LLTemplateMessageReader::getU64(const char *block, const char *var,
+ U64 &d, S32 blocknum)
+{
+ getData(block, var, &d, sizeof(U64), blocknum);
+}
+
+void LLTemplateMessageReader::getF32(const char *block, const char *var,
+ F32 &d, S32 blocknum)
+{
+ getData(block, var, &d, sizeof(F32), blocknum);
+
+ if( !llfinite( d ) )
+ {
+ LL_WARNS() << "non-finite in getF32Fast " << block << " " << var
+ << LL_ENDL;
+ d = 0;
+ }
+}
+
+void LLTemplateMessageReader::getF64(const char *block, const char *var,
+ F64 &d, S32 blocknum)
+{
+ getData(block, var, &d, sizeof(F64), blocknum);
+
+ if( !llfinite( d ) )
+ {
+ LL_WARNS() << "non-finite in getF64Fast " << block << " " << var
+ << LL_ENDL;
+ d = 0;
+ }
+}
+
+void LLTemplateMessageReader::getVector3(const char *block, const char *var,
+ LLVector3 &v, S32 blocknum )
+{
+ getData(block, var, &v.mV[0], sizeof(v.mV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ LL_WARNS() << "non-finite in getVector3Fast " << block << " "
+ << var << LL_ENDL;
+ v.zeroVec();
+ }
+}
+
+void LLTemplateMessageReader::getVector4(const char *block, const char *var,
+ LLVector4 &v, S32 blocknum)
+{
+ getData(block, var, &v.mV[0], sizeof(v.mV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ LL_WARNS() << "non-finite in getVector4Fast " << block << " "
+ << var << LL_ENDL;
+ v.zeroVec();
+ }
+}
+
+void LLTemplateMessageReader::getVector3d(const char *block, const char *var,
+ LLVector3d &v, S32 blocknum )
+{
+ getData(block, var, &v.mdV[0], sizeof(v.mdV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ LL_WARNS() << "non-finite in getVector3dFast " << block << " "
+ << var << LL_ENDL;
+ v.zeroVec();
+ }
+
+}
+
+void LLTemplateMessageReader::getQuat(const char *block, const char *var,
+ LLQuaternion &q, S32 blocknum)
+{
+ LLVector3 vec;
+ getData(block, var, &vec.mV[0], sizeof(vec.mV), blocknum);
+ if( vec.isFinite() )
+ {
+ q.unpackFromVector3( vec );
+ }
+ else
+ {
+ LL_WARNS() << "non-finite in getQuatFast " << block << " " << var
+ << LL_ENDL;
+ q.loadIdentity();
+ }
+}
+
+void LLTemplateMessageReader::getUUID(const char *block, const char *var,
+ LLUUID &u, S32 blocknum)
+{
+ getData(block, var, &u.mData[0], sizeof(u.mData), blocknum);
+}
+
+inline void LLTemplateMessageReader::getIPAddr(const char *block, const char *var, U32 &u, S32 blocknum)
+{
+ getData(block, var, &u, sizeof(U32), blocknum);
+}
+
+inline void LLTemplateMessageReader::getIPPort(const char *block, const char *var, U16 &u, S32 blocknum)
+{
+ getData(block, var, &u, sizeof(U16), blocknum);
+ u = ntohs(u);
+}
+
+inline void LLTemplateMessageReader::getString(const char *block, const char *var, S32 buffer_size, char *s, S32 blocknum )
+{
+ s[0] = '\0';
+ getData(block, var, s, 0, blocknum, buffer_size);
+ s[buffer_size - 1] = '\0';
+}
+
+inline void LLTemplateMessageReader::getString(const char *block, const char *var, std::string& outstr, S32 blocknum )
+{
+ char s[MTUBYTES + 1]= {0}; // every element is initialized with 0
+ getData(block, var, s, 0, blocknum, MTUBYTES);
+ s[MTUBYTES] = '\0';
+ outstr = s;
+}
+
+//virtual
+S32 LLTemplateMessageReader::getMessageSize() const
+{
+ return mReceiveSize;
+}
+
+// Returns template for the message contained in buffer
+bool LLTemplateMessageReader::decodeTemplate(
+ const U8* buffer, S32 buffer_size, // inputs
+ LLMessageTemplate** msg_template ) // outputs
+{
+ const U8* header = buffer + LL_PACKET_ID_SIZE;
+
+ // is there a message ready to go?
+ if (buffer_size <= 0)
+ {
+ LL_WARNS() << "No message waiting for decode!" << LL_ENDL;
+ return(false);
+ }
+
+ U32 num = 0;
+
+ if (header[0] != 255)
+ {
+ // high frequency message
+ num = header[0];
+ }
+ else if ((buffer_size >= ((S32) LL_MINIMUM_VALID_PACKET_SIZE + 1)) && (header[1] != 255))
+ {
+ // medium frequency message
+ num = (255 << 8) | header[1];
+ }
+ else if ((buffer_size >= ((S32) LL_MINIMUM_VALID_PACKET_SIZE + 3)) && (header[1] == 255))
+ {
+ // low frequency message
+ U16 message_id_U16 = 0;
+ // I think this check busts the message system.
+ // it appears that if there is a NULL in the message #, it won't copy it....
+ // what was the goal?
+ //if(header[2])
+ memcpy(&message_id_U16, &header[2], 2);
+
+ // dependant on endian-ness:
+ // U32 temp = (255 << 24) | (255 << 16) | header[2];
+
+ // independant of endian-ness:
+ message_id_U16 = ntohs(message_id_U16);
+ num = 0xFFFF0000 | message_id_U16;
+ }
+ else // bogus packet received (too short)
+ {
+ LL_WARNS() << "Packet with unusable length received (too short): "
+ << buffer_size << LL_ENDL;
+ return(false);
+ }
+
+ LLMessageTemplate* temp = get_ptr_in_map(mMessageNumbers,num);
+ if (temp)
+ {
+ *msg_template = temp;
+ }
+ else
+ {
+ // MAINT-7482 - make viewer more tolerant of unknown messages.
+ LL_WARNS_ONCE() << "Message #" << std::hex << num << std::dec
+ << " received but not registered!" << LL_ENDL;
+ //gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE);
+ return(false);
+ }
+
+ return(true);
+}
+
+void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S32 where, const S32 wanted )
+{
+ // we've run off the end of the packet!
+ LL_WARNS() << "Ran off end of packet " << mCurrentRMessageTemplate->mName
+// << " with id " << mCurrentRecvPacketID
+ << " from " << host
+ << " trying to read " << wanted
+ << " bytes at position " << where
+ << " going past packet end at " << mReceiveSize
+ << LL_ENDL;
+ if(gMessageSystem->mVerboseLog)
+ {
+ LL_INFOS() << "MSG: -> " << host << "\tREAD PAST END:\t"
+// << mCurrentRecvPacketID << " "
+ << getMessageName() << LL_ENDL;
+ }
+ gMessageSystem->callExceptionFunc(MX_RAN_OFF_END_OF_PACKET);
+}
+
+static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages");
+
+// decode a given message
+bool LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender )
+{
+ LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES);
+
+ llassert( mReceiveSize >= 0 );
+ llassert( mCurrentRMessageTemplate);
+ llassert( !mCurrentRMessageData );
+ delete mCurrentRMessageData; // just to make sure
+
+ // The offset tells us how may bytes to skip after the end of the
+ // message name.
+ U8 offset = buffer[PHL_OFFSET];
+ S32 decode_pos = LL_PACKET_ID_SIZE + (S32)(mCurrentRMessageTemplate->mFrequency) + offset;
+
+ // create base working data set
+ mCurrentRMessageData = new LLMsgData(mCurrentRMessageTemplate->mName);
+
+ // loop through the template building the data structure as we go
+ LLMessageTemplate::message_block_map_t::const_iterator iter;
+ for(iter = mCurrentRMessageTemplate->mMemberBlocks.begin();
+ iter != mCurrentRMessageTemplate->mMemberBlocks.end();
+ ++iter)
+ {
+ LLMessageBlock* mbci = *iter;
+ U8 repeat_number;
+ S32 i;
+
+ // how many of this block?
+
+ if (mbci->mType == MBT_SINGLE)
+ {
+ // just one
+ repeat_number = 1;
+ }
+ else if (mbci->mType == MBT_MULTIPLE)
+ {
+ // a known number
+ repeat_number = mbci->mNumber;
+ }
+ else if (mbci->mType == MBT_VARIABLE)
+ {
+ // need to read the number from the message
+ // repeat number is a single byte
+ if (decode_pos >= mReceiveSize)
+ {
+ // commented out - hetgrid says that missing variable blocks
+ // at end of message are legal
+ // logRanOffEndOfPacket(sender, decode_pos, 1);
+
+ // default to 0 repeats
+ repeat_number = 0;
+ }
+ else
+ {
+ repeat_number = buffer[decode_pos];
+ decode_pos++;
+ }
+ }
+ else
+ {
+ LL_ERRS() << "Unknown block type" << LL_ENDL;
+ return false;
+ }
+
+ LLMsgBlkData* cur_data_block = NULL;
+
+ // now loop through the block
+ for (i = 0; i < repeat_number; i++)
+ {
+ if (i)
+ {
+ // build new name to prevent collisions
+ // TODO: This should really change to a vector
+ cur_data_block = new LLMsgBlkData(mbci->mName, repeat_number);
+ cur_data_block->mName = mbci->mName + i;
+ }
+ else
+ {
+ cur_data_block = new LLMsgBlkData(mbci->mName, repeat_number);
+ }
+
+ // add the block to the message
+ mCurrentRMessageData->addBlock(cur_data_block);
+
+ // now read the variables
+ for (LLMessageBlock::message_variable_map_t::const_iterator iter =
+ mbci->mMemberVariables.begin();
+ iter != mbci->mMemberVariables.end(); iter++)
+ {
+ const LLMessageVariable& mvci = **iter;
+
+ // ok, build out the variables
+ // add variable block
+ cur_data_block->addVariable(mvci.getName(), mvci.getType());
+
+ // what type of variable?
+ if (mvci.getType() == MVT_VARIABLE)
+ {
+ // variable, get the number of bytes to read from the template
+ S32 data_size = mvci.getSize();
+ U8 tsizeb = 0;
+ U16 tsizeh = 0;
+ U32 tsize = 0;
+
+ if ((decode_pos + data_size) > mReceiveSize)
+ {
+ logRanOffEndOfPacket(sender, decode_pos, data_size);
+
+ // default to 0 length variable blocks
+ tsize = 0;
+ }
+ else
+ {
+ switch(data_size)
+ {
+ case 1:
+ htolememcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1);
+ tsize = tsizeb;
+ break;
+ case 2:
+ htolememcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2);
+ tsize = tsizeh;
+ break;
+ case 4:
+ htolememcpy(&tsize, &buffer[decode_pos], MVT_U32, 4);
+ break;
+ default:
+ LL_ERRS() << "Attempting to read variable field with unknown size of " << data_size << LL_ENDL;
+ break;
+ }
+ }
+ decode_pos += data_size;
+
+ cur_data_block->addData(mvci.getName(), &buffer[decode_pos], tsize, mvci.getType());
+ decode_pos += tsize;
+ }
+ else
+ {
+ // fixed!
+ // so, copy data pointer and set data size to fixed size
+ if ((decode_pos + mvci.getSize()) > mReceiveSize)
+ {
+ logRanOffEndOfPacket(sender, decode_pos, mvci.getSize());
+
+ // default to 0s.
+ U32 size = mvci.getSize();
+ std::vector<U8> data(size, 0);
+ cur_data_block->addData(mvci.getName(), &(data[0]),
+ size, mvci.getType());
+ }
+ else
+ {
+ cur_data_block->addData(mvci.getName(),
+ &buffer[decode_pos],
+ mvci.getSize(),
+ mvci.getType());
+ }
+ decode_pos += mvci.getSize();
+ }
+ }
+ }
+ }
+
+ if (mCurrentRMessageData->mMemberBlocks.empty()
+ && !mCurrentRMessageTemplate->mMemberBlocks.empty())
+ {
+ LL_DEBUGS() << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << LL_ENDL;
+ return false;
+ }
+
+ {
+ static LLTimer decode_timer;
+
+ if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback())
+ {
+ decode_timer.reset();
+ }
+
+ if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) )
+ {
+ LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL;
+ }
+
+ if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback())
+ {
+ F32 decode_time = decode_timer.getElapsedTimeF32();
+
+ if (gMessageSystem->getTimingCallback())
+ {
+ (gMessageSystem->getTimingCallback())(mCurrentRMessageTemplate->mName,
+ decode_time,
+ gMessageSystem->getTimingCallbackData());
+ }
+
+ if (LLMessageReader::getTimeDecodes())
+ {
+ mCurrentRMessageTemplate->mDecodeTimeThisFrame += decode_time;
+
+ mCurrentRMessageTemplate->mTotalDecoded++;
+ mCurrentRMessageTemplate->mTotalDecodeTime += decode_time;
+
+ if( mCurrentRMessageTemplate->mMaxDecodeTimePerMsg < decode_time )
+ {
+ mCurrentRMessageTemplate->mMaxDecodeTimePerMsg = decode_time;
+ }
+
+
+ if(decode_time > LLMessageReader::getTimeDecodesSpamThreshold())
+ {
+ LL_DEBUGS() << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " << decode_time << " seconds. (" <<
+ mCurrentRMessageTemplate->mMaxDecodeTimePerMsg << " max, " <<
+ (mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate->mTotalDecoded) << " avg)" << LL_ENDL;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool LLTemplateMessageReader::validateMessage(const U8* buffer,
+ S32 buffer_size,
+ const LLHost& sender,
+ bool trusted)
+{
+ mReceiveSize = buffer_size;
+ bool valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate );
+ if(valid)
+ {
+ mCurrentRMessageTemplate->mReceiveCount++;
+ //LL_DEBUGS() << "MessageRecvd:"
+ // << mCurrentRMessageTemplate->mName
+ // << " from " << sender << LL_ENDL;
+ }
+
+ if (valid && isBanned(trusted))
+ {
+ LL_WARNS("Messaging") << "LLMessageSystem::checkMessages "
+ << "received banned message "
+ << getMessageName()
+ << " from "
+ << ((trusted) ? "trusted " : "untrusted ")
+ << sender << LL_ENDL;
+ valid = false;
+ }
+
+ if(valid && isUdpBanned())
+ {
+ LL_WARNS() << "Received UDP black listed message "
+ << getMessageName()
+ << " from " << sender << LL_ENDL;
+ valid = false;
+ }
+ return valid;
+}
+
+bool LLTemplateMessageReader::readMessage(const U8* buffer,
+ const LLHost& sender)
+{
+ return decodeData(buffer, sender);
+}
+
+//virtual
+const char* LLTemplateMessageReader::getMessageName() const
+{
+ if (!mCurrentRMessageTemplate)
+ {
+ // no message currently being read
+ return "";
+ }
+ return mCurrentRMessageTemplate->mName;
+}
+
+//virtual
+bool LLTemplateMessageReader::isTrusted() const
+{
+ return mCurrentRMessageTemplate->getTrust() == MT_TRUST;
+}
+
+bool LLTemplateMessageReader::isBanned(bool trustedSource) const
+{
+ return mCurrentRMessageTemplate->isBanned(trustedSource);
+}
+
+bool LLTemplateMessageReader::isUdpBanned() const
+{
+ return mCurrentRMessageTemplate->isUdpBanned();
+}
+
+//virtual
+void LLTemplateMessageReader::copyToBuilder(LLMessageBuilder& builder) const
+{
+ if(NULL == mCurrentRMessageTemplate)
+ {
+ return;
+ }
+ builder.copyFromMessageData(*mCurrentRMessageData);
+}
diff --git a/indra/llmessage/lltemplatemessagereader.h b/indra/llmessage/lltemplatemessagereader.h index 1aa5d2e164..0b06f6d23a 100644 --- a/indra/llmessage/lltemplatemessagereader.h +++ b/indra/llmessage/lltemplatemessagereader.h @@ -1,127 +1,127 @@ -/** - * @file lltemplatemessagereader.h - * @brief Declaration of LLTemplateMessageReader class. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLTEMPLATEMESSAGEREADER_H -#define LL_LLTEMPLATEMESSAGEREADER_H - -#include "llmessagereader.h" - -#include <map> - -class LLMessageTemplate; -class LLMsgData; - -class LLTemplateMessageReader : public LLMessageReader -{ -public: - - typedef std::map<U32, LLMessageTemplate*> message_template_number_map_t; - - LLTemplateMessageReader(message_template_number_map_t&); - virtual ~LLTemplateMessageReader(); - - /** All get* methods expect pointers to canonical strings. */ - virtual void getBinaryData(const char *blockname, const char *varname, - void *datap, S32 size, S32 blocknum = 0, - S32 max_size = S32_MAX); - virtual void getBOOL(const char *block, const char *var, BOOL &data, - S32 blocknum = 0); - virtual void getS8(const char *block, const char *var, S8 &data, - S32 blocknum = 0); - virtual void getU8(const char *block, const char *var, U8 &data, - S32 blocknum = 0); - virtual void getS16(const char *block, const char *var, S16 &data, - S32 blocknum = 0); - virtual void getU16(const char *block, const char *var, U16 &data, - S32 blocknum = 0); - virtual void getS32(const char *block, const char *var, S32 &data, - S32 blocknum = 0); - virtual void getF32(const char *block, const char *var, F32 &data, - S32 blocknum = 0); - virtual void getU32(const char *block, const char *var, U32 &data, - S32 blocknum = 0); - virtual void getU64(const char *block, const char *var, U64 &data, - S32 blocknum = 0); - virtual void getF64(const char *block, const char *var, F64 &data, - S32 blocknum = 0); - virtual void getVector3(const char *block, const char *var, - LLVector3 &vec, S32 blocknum = 0); - virtual void getVector4(const char *block, const char *var, - LLVector4 &vec, S32 blocknum = 0); - virtual void getVector3d(const char *block, const char *var, - LLVector3d &vec, S32 blocknum = 0); - virtual void getQuat(const char *block, const char *var, LLQuaternion &q, - S32 blocknum = 0); - virtual void getUUID(const char *block, const char *var, LLUUID &uuid, - S32 blocknum = 0); - virtual void getIPAddr(const char *block, const char *var, U32 &ip, - S32 blocknum = 0); - virtual void getIPPort(const char *block, const char *var, U16 &port, - S32 blocknum = 0); - virtual void getString(const char *block, const char *var, - S32 buffer_size, char *buffer, S32 blocknum = 0); - virtual void getString(const char *block, const char *var, std::string& outstr, - S32 blocknum = 0); - - virtual S32 getNumberOfBlocks(const char *blockname); - virtual S32 getSize(const char *blockname, const char *varname); - virtual S32 getSize(const char *blockname, S32 blocknum, - const char *varname); - - virtual void clearMessage(); - - virtual const char* getMessageName() const; - virtual S32 getMessageSize() const; - - virtual void copyToBuilder(LLMessageBuilder&) const; - - BOOL validateMessage(const U8* buffer, S32 buffer_size, - const LLHost& sender, bool trusted = false); - BOOL readMessage(const U8* buffer, const LLHost& sender); - - bool isTrusted() const; - bool isBanned(bool trusted_source) const; - bool isUdpBanned() const; - -private: - - void getData(const char *blockname, const char *varname, void *datap, - S32 size = 0, S32 blocknum = 0, S32 max_size = S32_MAX); - - BOOL decodeTemplate(const U8* buffer, S32 buffer_size, // inputs - LLMessageTemplate** msg_template ); // outputs - - void logRanOffEndOfPacket( const LLHost& host, const S32 where, const S32 wanted ); - - BOOL decodeData(const U8* buffer, const LLHost& sender ); - - S32 mReceiveSize; - LLMessageTemplate* mCurrentRMessageTemplate; - LLMsgData* mCurrentRMessageData; - message_template_number_map_t& mMessageNumbers; -}; - -#endif // LL_LLTEMPLATEMESSAGEREADER_H +/**
+ * @file lltemplatemessagereader.h
+ * @brief Declaration of LLTemplateMessageReader class.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#ifndef LL_LLTEMPLATEMESSAGEREADER_H
+#define LL_LLTEMPLATEMESSAGEREADER_H
+
+#include "llmessagereader.h"
+
+#include <map>
+
+class LLMessageTemplate;
+class LLMsgData;
+
+class LLTemplateMessageReader : public LLMessageReader
+{
+public:
+
+ typedef std::map<U32, LLMessageTemplate*> message_template_number_map_t;
+
+ LLTemplateMessageReader(message_template_number_map_t&);
+ virtual ~LLTemplateMessageReader();
+
+ /** All get* methods expect pointers to canonical strings. */
+ virtual void getBinaryData(const char *blockname, const char *varname,
+ void *datap, S32 size, S32 blocknum = 0,
+ S32 max_size = S32_MAX);
+ virtual void getBOOL(const char *block, const char *var, bool &data,
+ S32 blocknum = 0);
+ virtual void getS8(const char *block, const char *var, S8 &data,
+ S32 blocknum = 0);
+ virtual void getU8(const char *block, const char *var, U8 &data,
+ S32 blocknum = 0);
+ virtual void getS16(const char *block, const char *var, S16 &data,
+ S32 blocknum = 0);
+ virtual void getU16(const char *block, const char *var, U16 &data,
+ S32 blocknum = 0);
+ virtual void getS32(const char *block, const char *var, S32 &data,
+ S32 blocknum = 0);
+ virtual void getF32(const char *block, const char *var, F32 &data,
+ S32 blocknum = 0);
+ virtual void getU32(const char *block, const char *var, U32 &data,
+ S32 blocknum = 0);
+ virtual void getU64(const char *block, const char *var, U64 &data,
+ S32 blocknum = 0);
+ virtual void getF64(const char *block, const char *var, F64 &data,
+ S32 blocknum = 0);
+ virtual void getVector3(const char *block, const char *var,
+ LLVector3 &vec, S32 blocknum = 0);
+ virtual void getVector4(const char *block, const char *var,
+ LLVector4 &vec, S32 blocknum = 0);
+ virtual void getVector3d(const char *block, const char *var,
+ LLVector3d &vec, S32 blocknum = 0);
+ virtual void getQuat(const char *block, const char *var, LLQuaternion &q,
+ S32 blocknum = 0);
+ virtual void getUUID(const char *block, const char *var, LLUUID &uuid,
+ S32 blocknum = 0);
+ virtual void getIPAddr(const char *block, const char *var, U32 &ip,
+ S32 blocknum = 0);
+ virtual void getIPPort(const char *block, const char *var, U16 &port,
+ S32 blocknum = 0);
+ virtual void getString(const char *block, const char *var,
+ S32 buffer_size, char *buffer, S32 blocknum = 0);
+ virtual void getString(const char *block, const char *var, std::string& outstr,
+ S32 blocknum = 0);
+
+ virtual S32 getNumberOfBlocks(const char *blockname);
+ virtual S32 getSize(const char *blockname, const char *varname);
+ virtual S32 getSize(const char *blockname, S32 blocknum,
+ const char *varname);
+
+ virtual void clearMessage();
+
+ virtual const char* getMessageName() const;
+ virtual S32 getMessageSize() const;
+
+ virtual void copyToBuilder(LLMessageBuilder&) const;
+
+ bool validateMessage(const U8* buffer, S32 buffer_size,
+ const LLHost& sender, bool trusted = false);
+ bool readMessage(const U8* buffer, const LLHost& sender);
+
+ bool isTrusted() const;
+ bool isBanned(bool trusted_source) const;
+ bool isUdpBanned() const;
+
+private:
+
+ void getData(const char *blockname, const char *varname, void *datap,
+ S32 size = 0, S32 blocknum = 0, S32 max_size = S32_MAX);
+
+ bool decodeTemplate(const U8* buffer, S32 buffer_size, // inputs
+ LLMessageTemplate** msg_template ); // outputs
+
+ void logRanOffEndOfPacket( const LLHost& host, const S32 where, const S32 wanted );
+
+ bool decodeData(const U8* buffer, const LLHost& sender );
+
+ S32 mReceiveSize;
+ LLMessageTemplate* mCurrentRMessageTemplate;
+ LLMsgData* mCurrentRMessageData;
+ message_template_number_map_t& mMessageNumbers;
+};
+
+#endif // LL_LLTEMPLATEMESSAGEREADER_H
diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp index 0113414d1b..a3f02204d0 100644 --- a/indra/llmessage/llthrottle.cpp +++ b/indra/llmessage/llthrottle.cpp @@ -1,577 +1,577 @@ -/** - * @file llthrottle.cpp - * @brief LLThrottle class used for network bandwidth control. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "llthrottle.h" -#include "llmath.h" -#include "lldatapacker.h" -#include "message.h" - - -LLThrottle::LLThrottle(const F32 rate) -{ - mRate = rate; - mAvailable = 0.f; - mLookaheadSecs = 0.25f; - mLastSendTime = LLMessageSystem::getMessageTimeSeconds(TRUE); -} - - -void LLThrottle::setRate(const F32 rate) -{ - // Need to accumulate available bits when adjusting the rate. - mAvailable = getAvailable(); - mLastSendTime = LLMessageSystem::getMessageTimeSeconds(); - mRate = rate; -} - -F32 LLThrottle::getAvailable() -{ - // use a temporary bits_available - // since we don't want to change mBitsAvailable every time - F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime; - return mAvailable + (mRate * elapsed_time.value()); -} - -BOOL LLThrottle::checkOverflow(const F32 amount) -{ - BOOL retval = TRUE; - - F32 lookahead_amount = mRate * mLookaheadSecs; - - // use a temporary bits_available - // since we don't want to change mBitsAvailable every time - F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime; - F32 amount_available = mAvailable + (mRate * elapsed_time.value()); - - if ((amount_available >= lookahead_amount) || (amount_available > amount)) - { - // ...enough space to send this message - // Also do if > lookahead so we can use if amount > capped amount. - retval = FALSE; - } - - return retval; -} - -BOOL LLThrottle::throttleOverflow(const F32 amount) -{ - F32Seconds elapsed_time; - F32 lookahead_amount; - BOOL retval = TRUE; - - lookahead_amount = mRate * mLookaheadSecs; - - F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); - elapsed_time = mt_sec - mLastSendTime; - mLastSendTime = mt_sec; - - mAvailable += mRate * elapsed_time.value(); - - if (mAvailable >= lookahead_amount) - { - // ...channel completely open, so allow send regardless - // of size. This allows sends on very low BPS channels. - mAvailable = lookahead_amount; - retval = FALSE; - } - else if (mAvailable > amount) - { - // ...enough space to send this message - retval = FALSE; - } - - // We actually already sent the bits. - mAvailable -= amount; - - // What if bitsavailable goes negative? - // That's OK, because it means someone is banging on the channel, - // so we need some time to recover. - - return retval; -} - - - -const F32 THROTTLE_LOOKAHEAD_TIME = 1.f; // seconds - -// Make sure that we don't set above these -// values, even if the client asks to be set -// higher -// Note that these values are replicated on the -// client side to set max bandwidth throttling there, -// in llviewerthrottle.cpp. These values are the sum -// of the top two tiers of bandwidth there. - -F32 gThrottleMaximumBPS[TC_EOF] = -{ - 150000.f, // TC_RESEND - 170000.f, // TC_LAND - 34000.f, // TC_WIND - 34000.f, // TC_CLOUD - 446000.f, // TC_TASK - 446000.f, // TC_TEXTURE - 220000.f, // TC_ASSET -}; - -// Start low until viewer informs us of capability -// Asset and resend get high values, since they -// aren't used JUST by the viewer necessarily. -// This is a HACK and should be dealt with more properly on -// circuit creation. - -F32 gThrottleDefaultBPS[TC_EOF] = -{ - 100000.f, // TC_RESEND - 4000.f, // TC_LAND - 4000.f, // TC_WIND - 4000.f, // TC_CLOUD - 4000.f, // TC_TASK - 4000.f, // TC_TEXTURE - 100000.f, // TC_ASSET -}; - -// Don't throttle down lower than this -// This potentially wastes 50 kbps, but usually -// wont. -F32 gThrottleMinimumBPS[TC_EOF] = -{ - 10000.f, // TC_RESEND - 10000.f, // TC_LAND - 4000.f, // TC_WIND - 4000.f, // TC_CLOUD - 20000.f, // TC_TASK - 10000.f, // TC_TEXTURE - 10000.f, // TC_ASSET -}; - -const char* THROTTLE_NAMES[TC_EOF] = -{ - "Resend ", - "Land ", - "Wind ", - "Cloud ", - "Task ", - "Texture", - "Asset " -}; - -LLThrottleGroup::LLThrottleGroup() -{ - S32 i; - for (i = 0; i < TC_EOF; i++) - { - mThrottleTotal[i] = gThrottleDefaultBPS[i]; - mNominalBPS[i] = gThrottleDefaultBPS[i]; - } - - resetDynamicAdjust(); -} - -void LLThrottleGroup::packThrottle(LLDataPacker &dp) const -{ - S32 i; - for (i = 0; i < TC_EOF; i++) - { - dp.packF32(mThrottleTotal[i], "Throttle"); - } -} - -void LLThrottleGroup::unpackThrottle(LLDataPacker &dp) -{ - S32 i; - for (i = 0; i < TC_EOF; i++) - { - F32 temp_throttle; - dp.unpackF32(temp_throttle, "Throttle"); - temp_throttle = llclamp(temp_throttle, 0.f, 2250000.f); - mThrottleTotal[i] = temp_throttle; - if(mThrottleTotal[i] > gThrottleMaximumBPS[i]) - { - mThrottleTotal[i] = gThrottleMaximumBPS[i]; - } - } -} - -// Call this whenever mNominalBPS changes. Need to reset -// the measurement systems. In the future, we should look -// into NOT resetting the system. -void LLThrottleGroup::resetDynamicAdjust() -{ - F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); - S32 i; - for (i = 0; i < TC_EOF; i++) - { - mCurrentBPS[i] = mNominalBPS[i]; - mBitsAvailable[i] = mNominalBPS[i] * THROTTLE_LOOKAHEAD_TIME; - mLastSendTime[i] = mt_sec; - mBitsSentThisPeriod[i] = 0; - mBitsSentHistory[i] = 0; - } - mDynamicAdjustTime = mt_sec; -} - - -BOOL LLThrottleGroup::setNominalBPS(F32* throttle_vec) -{ - BOOL changed = FALSE; - S32 i; - for (i = 0; i < TC_EOF; i++) - { - if (mNominalBPS[i] != throttle_vec[i]) - { - changed = TRUE; - mNominalBPS[i] = throttle_vec[i]; - } - } - - // If we changed the nominal settings, reset the dynamic - // adjustment subsystem. - if (changed) - { - resetDynamicAdjust(); - } - - 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 - F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]; - F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value()); - - 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) -{ - BOOL retval = TRUE; - - 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 - F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]; - F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value()); - - if (bits_available >= lookahead_bits) - { - // ...channel completely open, so allow send regardless - // of size. This allows sends on very low BPS channels. - mBitsAvailable[throttle_cat] = lookahead_bits; - retval = FALSE; - } - else if ( bits_available > bits ) - { - // ...enough space to send this message - retval = FALSE; - } - - return retval; -} - -BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits) -{ - F32Seconds elapsed_time; - F32 category_bps; - F32 lookahead_bits; - BOOL retval = TRUE; - - category_bps = mCurrentBPS[throttle_cat]; - lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME; - - F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); - elapsed_time = mt_sec - mLastSendTime[throttle_cat]; - mLastSendTime[throttle_cat] = mt_sec; - mBitsAvailable[throttle_cat] += category_bps * elapsed_time.value(); - - if (mBitsAvailable[throttle_cat] >= lookahead_bits) - { - // ...channel completely open, so allow send regardless - // of size. This allows sends on very low BPS channels. - mBitsAvailable[throttle_cat] = lookahead_bits; - retval = FALSE; - } - else if ( mBitsAvailable[throttle_cat] > bits ) - { - // ...enough space to send this message - retval = FALSE; - } - - // We actually already sent the bits. - mBitsAvailable[throttle_cat] -= bits; - - mBitsSentThisPeriod[throttle_cat] += bits; - - // What if bitsavailable goes negative? - // That's OK, because it means someone is banging on the channel, - // so we need some time to recover. - - return retval; -} - - -BOOL LLThrottleGroup::dynamicAdjust() -{ - const F32Seconds DYNAMIC_ADJUST_TIME(1.0f); - const F32 CURRENT_PERIOD_WEIGHT = .25f; // how much weight to give to last period while determining BPS utilization - const F32 BUSY_PERCENT = 0.75f; // if use more than this fraction of BPS, you are busy - const F32 IDLE_PERCENT = 0.70f; // if use less than this fraction, you are "idle" - const F32 TRANSFER_PERCENT = 0.90f; // how much unused bandwidth to take away each adjustment - const F32 RECOVER_PERCENT = 0.25f; // how much to give back during recovery phase - - S32 i; - - F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); - - // Only dynamically adjust every few seconds - if ((mt_sec - mDynamicAdjustTime) < DYNAMIC_ADJUST_TIME) - { - return FALSE; - } - mDynamicAdjustTime = mt_sec; - - // Update historical information - for (i = 0; i < TC_EOF; i++) - { - if (mBitsSentHistory[i] == 0) - { - // first run, just copy current period - mBitsSentHistory[i] = mBitsSentThisPeriod[i]; - } - else - { - // have some history, so weight accordingly - mBitsSentHistory[i] = (1.f - CURRENT_PERIOD_WEIGHT) * mBitsSentHistory[i] - + CURRENT_PERIOD_WEIGHT * mBitsSentThisPeriod[i]; - } - - mBitsSentThisPeriod[i] = 0; - } - - // Look for busy channels - // TODO: Fold into loop above. - BOOL channels_busy = FALSE; - F32 busy_nominal_sum = 0; - BOOL channel_busy[TC_EOF]; - BOOL channel_idle[TC_EOF]; - BOOL channel_over_nominal[TC_EOF]; - - for (i = 0; i < TC_EOF; i++) - { - // Is this a busy channel? - if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) - { - // this channel is busy - channels_busy = TRUE; - busy_nominal_sum += mNominalBPS[i]; // use for allocation of pooled idle bandwidth - channel_busy[i] = TRUE; - } - else - { - channel_busy[i] = FALSE; - } - - // Is this an idle channel? - if ((mBitsSentHistory[i] < IDLE_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) && - (mBitsAvailable[i] > 0)) - { - channel_idle[i] = TRUE; - } - else - { - channel_idle[i] = FALSE; - } - - // Is this an overpumped channel? - if (mCurrentBPS[i] > mNominalBPS[i]) - { - channel_over_nominal[i] = TRUE; - } - else - { - channel_over_nominal[i] = FALSE; - } - } - - if (channels_busy) - { - // Some channels are busy. Let's see if we can get them some bandwidth. - F32 used_bps; - F32 avail_bps; - F32 transfer_bps; - - F32 pool_bps = 0; - - for (i = 0; i < TC_EOF; i++) - { - if (channel_idle[i] || channel_over_nominal[i] ) - { - // Either channel i is idle, or has been overpumped. - // Therefore it's a candidate to give up some bandwidth. - // Figure out how much bandwidth it has been using, and how - // much is available to steal. - used_bps = mBitsSentHistory[i] / DYNAMIC_ADJUST_TIME.value(); - - // CRO make sure to keep a minimum amount of throttle available - // CRO NB: channels set to < MINIMUM_BPS will never give up bps, - // which is correct I think - if (used_bps < gThrottleMinimumBPS[i]) - { - used_bps = gThrottleMinimumBPS[i]; - } - - if (channel_over_nominal[i]) - { - F32 unused_current = mCurrentBPS[i] - used_bps; - avail_bps = llmax(mCurrentBPS[i] - mNominalBPS[i], unused_current); - } - else - { - avail_bps = mCurrentBPS[i] - used_bps; - } - - //LL_INFOS() << i << " avail " << avail_bps << LL_ENDL; - - // Historically, a channel could have used more than its current share, - // even if it's idle right now. - // Make sure we don't steal too much. - if (avail_bps < 0) - { - continue; - } - - // Transfer some bandwidth from this channel into the global pool. - transfer_bps = avail_bps * TRANSFER_PERCENT; - mCurrentBPS[i] -= transfer_bps; - pool_bps += transfer_bps; - } - } - - //LL_INFOS() << "Pool BPS: " << pool_bps << LL_ENDL; - // Now redistribute the bandwidth to busy channels. - F32 unused_bps = 0.f; - - for (i = 0; i < TC_EOF; i++) - { - if (channel_busy[i]) - { - F32 add_amount = pool_bps * (mNominalBPS[i] / busy_nominal_sum); - //LL_INFOS() << "Busy " << i << " gets " << pool_bps << LL_ENDL; - mCurrentBPS[i] += add_amount; - - // CRO: make sure this doesn't get too huge - // JC - Actually, need to let mCurrentBPS go less than nominal, otherwise - // you aren't allowing bandwidth to actually be moved from one channel - // to another. - // *TODO: If clamping high end, would be good to re- - // allocate to other channels in the above code. - const F32 MAX_BPS = 4 * mNominalBPS[i]; - if (mCurrentBPS[i] > MAX_BPS) - { - F32 overage = mCurrentBPS[i] - MAX_BPS; - mCurrentBPS[i] -= overage; - unused_bps += overage; - } - - // Paranoia - if (mCurrentBPS[i] < gThrottleMinimumBPS[i]) - { - mCurrentBPS[i] = gThrottleMinimumBPS[i]; - } - } - } - - // For fun, add the overage back in to objects - if (unused_bps > 0.f) - { - mCurrentBPS[TC_TASK] += unused_bps; - } - } - else - { - // No one is busy. - // Make the channel allocations seek toward nominal. - - // Look for overpumped channels - F32 starved_nominal_sum = 0; - F32 avail_bps = 0; - F32 transfer_bps = 0; - F32 pool_bps = 0; - for (i = 0; i < TC_EOF; i++) - { - if (mCurrentBPS[i] > mNominalBPS[i]) - { - avail_bps = (mCurrentBPS[i] - mNominalBPS[i]); - transfer_bps = avail_bps * RECOVER_PERCENT; - - mCurrentBPS[i] -= transfer_bps; - pool_bps += transfer_bps; - } - } - - // Evenly distribute bandwidth to channels currently - // using less than nominal. - for (i = 0; i < TC_EOF; i++) - { - if (mCurrentBPS[i] < mNominalBPS[i]) - { - // We're going to weight allocations by nominal BPS. - starved_nominal_sum += mNominalBPS[i]; - } - } - - for (i = 0; i < TC_EOF; i++) - { - if (mCurrentBPS[i] < mNominalBPS[i]) - { - // Distribute bandwidth according to nominal allocation ratios. - mCurrentBPS[i] += pool_bps * (mNominalBPS[i] / starved_nominal_sum); - } - } - } - return TRUE; -} +/**
+ * @file llthrottle.cpp
+ * @brief LLThrottle class used for network bandwidth control.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llthrottle.h"
+#include "llmath.h"
+#include "lldatapacker.h"
+#include "message.h"
+
+
+LLThrottle::LLThrottle(const F32 rate)
+{
+ mRate = rate;
+ mAvailable = 0.f;
+ mLookaheadSecs = 0.25f;
+ mLastSendTime = LLMessageSystem::getMessageTimeSeconds(true);
+}
+
+
+void LLThrottle::setRate(const F32 rate)
+{
+ // Need to accumulate available bits when adjusting the rate.
+ mAvailable = getAvailable();
+ mLastSendTime = LLMessageSystem::getMessageTimeSeconds();
+ mRate = rate;
+}
+
+F32 LLThrottle::getAvailable()
+{
+ // use a temporary bits_available
+ // since we don't want to change mBitsAvailable every time
+ F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime;
+ return mAvailable + (mRate * elapsed_time.value());
+}
+
+bool LLThrottle::checkOverflow(const F32 amount)
+{
+ bool retval = true;
+
+ F32 lookahead_amount = mRate * mLookaheadSecs;
+
+ // use a temporary bits_available
+ // since we don't want to change mBitsAvailable every time
+ F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime;
+ F32 amount_available = mAvailable + (mRate * elapsed_time.value());
+
+ if ((amount_available >= lookahead_amount) || (amount_available > amount))
+ {
+ // ...enough space to send this message
+ // Also do if > lookahead so we can use if amount > capped amount.
+ retval = false;
+ }
+
+ return retval;
+}
+
+bool LLThrottle::throttleOverflow(const F32 amount)
+{
+ F32Seconds elapsed_time;
+ F32 lookahead_amount;
+ bool retval = true;
+
+ lookahead_amount = mRate * mLookaheadSecs;
+
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+ elapsed_time = mt_sec - mLastSendTime;
+ mLastSendTime = mt_sec;
+
+ mAvailable += mRate * elapsed_time.value();
+
+ if (mAvailable >= lookahead_amount)
+ {
+ // ...channel completely open, so allow send regardless
+ // of size. This allows sends on very low BPS channels.
+ mAvailable = lookahead_amount;
+ retval = false;
+ }
+ else if (mAvailable > amount)
+ {
+ // ...enough space to send this message
+ retval = false;
+ }
+
+ // We actually already sent the bits.
+ mAvailable -= amount;
+
+ // What if bitsavailable goes negative?
+ // That's OK, because it means someone is banging on the channel,
+ // so we need some time to recover.
+
+ return retval;
+}
+
+
+
+const F32 THROTTLE_LOOKAHEAD_TIME = 1.f; // seconds
+
+// Make sure that we don't set above these
+// values, even if the client asks to be set
+// higher
+// Note that these values are replicated on the
+// client side to set max bandwidth throttling there,
+// in llviewerthrottle.cpp. These values are the sum
+// of the top two tiers of bandwidth there.
+
+F32 gThrottleMaximumBPS[TC_EOF] =
+{
+ 150000.f, // TC_RESEND
+ 170000.f, // TC_LAND
+ 34000.f, // TC_WIND
+ 34000.f, // TC_CLOUD
+ 446000.f, // TC_TASK
+ 446000.f, // TC_TEXTURE
+ 220000.f, // TC_ASSET
+};
+
+// Start low until viewer informs us of capability
+// Asset and resend get high values, since they
+// aren't used JUST by the viewer necessarily.
+// This is a HACK and should be dealt with more properly on
+// circuit creation.
+
+F32 gThrottleDefaultBPS[TC_EOF] =
+{
+ 100000.f, // TC_RESEND
+ 4000.f, // TC_LAND
+ 4000.f, // TC_WIND
+ 4000.f, // TC_CLOUD
+ 4000.f, // TC_TASK
+ 4000.f, // TC_TEXTURE
+ 100000.f, // TC_ASSET
+};
+
+// Don't throttle down lower than this
+// This potentially wastes 50 kbps, but usually
+// wont.
+F32 gThrottleMinimumBPS[TC_EOF] =
+{
+ 10000.f, // TC_RESEND
+ 10000.f, // TC_LAND
+ 4000.f, // TC_WIND
+ 4000.f, // TC_CLOUD
+ 20000.f, // TC_TASK
+ 10000.f, // TC_TEXTURE
+ 10000.f, // TC_ASSET
+};
+
+const char* THROTTLE_NAMES[TC_EOF] =
+{
+ "Resend ",
+ "Land ",
+ "Wind ",
+ "Cloud ",
+ "Task ",
+ "Texture",
+ "Asset "
+};
+
+LLThrottleGroup::LLThrottleGroup()
+{
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ mThrottleTotal[i] = gThrottleDefaultBPS[i];
+ mNominalBPS[i] = gThrottleDefaultBPS[i];
+ }
+
+ resetDynamicAdjust();
+}
+
+void LLThrottleGroup::packThrottle(LLDataPacker &dp) const
+{
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ dp.packF32(mThrottleTotal[i], "Throttle");
+ }
+}
+
+void LLThrottleGroup::unpackThrottle(LLDataPacker &dp)
+{
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ F32 temp_throttle;
+ dp.unpackF32(temp_throttle, "Throttle");
+ temp_throttle = llclamp(temp_throttle, 0.f, 2250000.f);
+ mThrottleTotal[i] = temp_throttle;
+ if(mThrottleTotal[i] > gThrottleMaximumBPS[i])
+ {
+ mThrottleTotal[i] = gThrottleMaximumBPS[i];
+ }
+ }
+}
+
+// Call this whenever mNominalBPS changes. Need to reset
+// the measurement systems. In the future, we should look
+// into NOT resetting the system.
+void LLThrottleGroup::resetDynamicAdjust()
+{
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ mCurrentBPS[i] = mNominalBPS[i];
+ mBitsAvailable[i] = mNominalBPS[i] * THROTTLE_LOOKAHEAD_TIME;
+ mLastSendTime[i] = mt_sec;
+ mBitsSentThisPeriod[i] = 0;
+ mBitsSentHistory[i] = 0;
+ }
+ mDynamicAdjustTime = mt_sec;
+}
+
+
+bool LLThrottleGroup::setNominalBPS(F32* throttle_vec)
+{
+ bool changed = false;
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mNominalBPS[i] != throttle_vec[i])
+ {
+ changed = true;
+ mNominalBPS[i] = throttle_vec[i];
+ }
+ }
+
+ // If we changed the nominal settings, reset the dynamic
+ // adjustment subsystem.
+ if (changed)
+ {
+ resetDynamicAdjust();
+ }
+
+ 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
+ F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat];
+ F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value());
+
+ 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)
+{
+ bool retval = true;
+
+ 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
+ F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat];
+ F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value());
+
+ if (bits_available >= lookahead_bits)
+ {
+ // ...channel completely open, so allow send regardless
+ // of size. This allows sends on very low BPS channels.
+ mBitsAvailable[throttle_cat] = lookahead_bits;
+ retval = false;
+ }
+ else if ( bits_available > bits )
+ {
+ // ...enough space to send this message
+ retval = false;
+ }
+
+ return retval;
+}
+
+bool LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits)
+{
+ F32Seconds elapsed_time;
+ F32 category_bps;
+ F32 lookahead_bits;
+ bool retval = true;
+
+ category_bps = mCurrentBPS[throttle_cat];
+ lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
+
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+ elapsed_time = mt_sec - mLastSendTime[throttle_cat];
+ mLastSendTime[throttle_cat] = mt_sec;
+ mBitsAvailable[throttle_cat] += category_bps * elapsed_time.value();
+
+ if (mBitsAvailable[throttle_cat] >= lookahead_bits)
+ {
+ // ...channel completely open, so allow send regardless
+ // of size. This allows sends on very low BPS channels.
+ mBitsAvailable[throttle_cat] = lookahead_bits;
+ retval = false;
+ }
+ else if ( mBitsAvailable[throttle_cat] > bits )
+ {
+ // ...enough space to send this message
+ retval = false;
+ }
+
+ // We actually already sent the bits.
+ mBitsAvailable[throttle_cat] -= bits;
+
+ mBitsSentThisPeriod[throttle_cat] += bits;
+
+ // What if bitsavailable goes negative?
+ // That's OK, because it means someone is banging on the channel,
+ // so we need some time to recover.
+
+ return retval;
+}
+
+
+bool LLThrottleGroup::dynamicAdjust()
+{
+ const F32Seconds DYNAMIC_ADJUST_TIME(1.0f);
+ const F32 CURRENT_PERIOD_WEIGHT = .25f; // how much weight to give to last period while determining BPS utilization
+ const F32 BUSY_PERCENT = 0.75f; // if use more than this fraction of BPS, you are busy
+ const F32 IDLE_PERCENT = 0.70f; // if use less than this fraction, you are "idle"
+ const F32 TRANSFER_PERCENT = 0.90f; // how much unused bandwidth to take away each adjustment
+ const F32 RECOVER_PERCENT = 0.25f; // how much to give back during recovery phase
+
+ S32 i;
+
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+
+ // Only dynamically adjust every few seconds
+ if ((mt_sec - mDynamicAdjustTime) < DYNAMIC_ADJUST_TIME)
+ {
+ return false;
+ }
+ mDynamicAdjustTime = mt_sec;
+
+ // Update historical information
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mBitsSentHistory[i] == 0)
+ {
+ // first run, just copy current period
+ mBitsSentHistory[i] = mBitsSentThisPeriod[i];
+ }
+ else
+ {
+ // have some history, so weight accordingly
+ mBitsSentHistory[i] = (1.f - CURRENT_PERIOD_WEIGHT) * mBitsSentHistory[i]
+ + CURRENT_PERIOD_WEIGHT * mBitsSentThisPeriod[i];
+ }
+
+ mBitsSentThisPeriod[i] = 0;
+ }
+
+ // Look for busy channels
+ // TODO: Fold into loop above.
+ bool channels_busy = false;
+ F32 busy_nominal_sum = 0;
+ bool channel_busy[TC_EOF];
+ bool channel_idle[TC_EOF];
+ bool channel_over_nominal[TC_EOF];
+
+ for (i = 0; i < TC_EOF; i++)
+ {
+ // Is this a busy channel?
+ if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i])
+ {
+ // this channel is busy
+ channels_busy = true;
+ busy_nominal_sum += mNominalBPS[i]; // use for allocation of pooled idle bandwidth
+ channel_busy[i] = true;
+ }
+ else
+ {
+ channel_busy[i] = false;
+ }
+
+ // Is this an idle channel?
+ if ((mBitsSentHistory[i] < IDLE_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) &&
+ (mBitsAvailable[i] > 0))
+ {
+ channel_idle[i] = true;
+ }
+ else
+ {
+ channel_idle[i] = false;
+ }
+
+ // Is this an overpumped channel?
+ if (mCurrentBPS[i] > mNominalBPS[i])
+ {
+ channel_over_nominal[i] = true;
+ }
+ else
+ {
+ channel_over_nominal[i] = false;
+ }
+ }
+
+ if (channels_busy)
+ {
+ // Some channels are busy. Let's see if we can get them some bandwidth.
+ F32 used_bps;
+ F32 avail_bps;
+ F32 transfer_bps;
+
+ F32 pool_bps = 0;
+
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (channel_idle[i] || channel_over_nominal[i] )
+ {
+ // Either channel i is idle, or has been overpumped.
+ // Therefore it's a candidate to give up some bandwidth.
+ // Figure out how much bandwidth it has been using, and how
+ // much is available to steal.
+ used_bps = mBitsSentHistory[i] / DYNAMIC_ADJUST_TIME.value();
+
+ // CRO make sure to keep a minimum amount of throttle available
+ // CRO NB: channels set to < MINIMUM_BPS will never give up bps,
+ // which is correct I think
+ if (used_bps < gThrottleMinimumBPS[i])
+ {
+ used_bps = gThrottleMinimumBPS[i];
+ }
+
+ if (channel_over_nominal[i])
+ {
+ F32 unused_current = mCurrentBPS[i] - used_bps;
+ avail_bps = llmax(mCurrentBPS[i] - mNominalBPS[i], unused_current);
+ }
+ else
+ {
+ avail_bps = mCurrentBPS[i] - used_bps;
+ }
+
+ //LL_INFOS() << i << " avail " << avail_bps << LL_ENDL;
+
+ // Historically, a channel could have used more than its current share,
+ // even if it's idle right now.
+ // Make sure we don't steal too much.
+ if (avail_bps < 0)
+ {
+ continue;
+ }
+
+ // Transfer some bandwidth from this channel into the global pool.
+ transfer_bps = avail_bps * TRANSFER_PERCENT;
+ mCurrentBPS[i] -= transfer_bps;
+ pool_bps += transfer_bps;
+ }
+ }
+
+ //LL_INFOS() << "Pool BPS: " << pool_bps << LL_ENDL;
+ // Now redistribute the bandwidth to busy channels.
+ F32 unused_bps = 0.f;
+
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (channel_busy[i])
+ {
+ F32 add_amount = pool_bps * (mNominalBPS[i] / busy_nominal_sum);
+ //LL_INFOS() << "Busy " << i << " gets " << pool_bps << LL_ENDL;
+ mCurrentBPS[i] += add_amount;
+
+ // CRO: make sure this doesn't get too huge
+ // JC - Actually, need to let mCurrentBPS go less than nominal, otherwise
+ // you aren't allowing bandwidth to actually be moved from one channel
+ // to another.
+ // *TODO: If clamping high end, would be good to re-
+ // allocate to other channels in the above code.
+ const F32 MAX_BPS = 4 * mNominalBPS[i];
+ if (mCurrentBPS[i] > MAX_BPS)
+ {
+ F32 overage = mCurrentBPS[i] - MAX_BPS;
+ mCurrentBPS[i] -= overage;
+ unused_bps += overage;
+ }
+
+ // Paranoia
+ if (mCurrentBPS[i] < gThrottleMinimumBPS[i])
+ {
+ mCurrentBPS[i] = gThrottleMinimumBPS[i];
+ }
+ }
+ }
+
+ // For fun, add the overage back in to objects
+ if (unused_bps > 0.f)
+ {
+ mCurrentBPS[TC_TASK] += unused_bps;
+ }
+ }
+ else
+ {
+ // No one is busy.
+ // Make the channel allocations seek toward nominal.
+
+ // Look for overpumped channels
+ F32 starved_nominal_sum = 0;
+ F32 avail_bps = 0;
+ F32 transfer_bps = 0;
+ F32 pool_bps = 0;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mCurrentBPS[i] > mNominalBPS[i])
+ {
+ avail_bps = (mCurrentBPS[i] - mNominalBPS[i]);
+ transfer_bps = avail_bps * RECOVER_PERCENT;
+
+ mCurrentBPS[i] -= transfer_bps;
+ pool_bps += transfer_bps;
+ }
+ }
+
+ // Evenly distribute bandwidth to channels currently
+ // using less than nominal.
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mCurrentBPS[i] < mNominalBPS[i])
+ {
+ // We're going to weight allocations by nominal BPS.
+ starved_nominal_sum += mNominalBPS[i];
+ }
+ }
+
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mCurrentBPS[i] < mNominalBPS[i])
+ {
+ // Distribute bandwidth according to nominal allocation ratios.
+ mCurrentBPS[i] += pool_bps * (mNominalBPS[i] / starved_nominal_sum);
+ }
+ }
+ }
+ return true;
+}
diff --git a/indra/llmessage/llthrottle.h b/indra/llmessage/llthrottle.h index 9450f4de88..be497d9371 100644 --- a/indra/llmessage/llthrottle.h +++ b/indra/llmessage/llthrottle.h @@ -1,101 +1,101 @@ -/** - * @file llthrottle.h - * @brief LLThrottle class used for network bandwidth control - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLTHROTTLE_H -#define LL_LLTHROTTLE_H - -#include "lltimer.h" - -const S32 MAX_THROTTLE_SIZE = 32; - -class LLDataPacker; - -// Single instance of a generic throttle -class LLThrottle -{ -public: - LLThrottle(const F32 throttle = 1.f); - ~LLThrottle() { } - - void setRate(const F32 rate); - BOOL checkOverflow(const F32 amount); // I'm about to add an amount, TRUE if would overflow throttle - BOOL throttleOverflow(const F32 amount); // I just sent amount, TRUE if that overflowed the throttle - - F32 getAvailable(); // Return the available bits - F32 getRate() const { return mRate; } -private: - F32 mLookaheadSecs; // Seconds to look ahead, maximum - F32 mRate; // BPS available, dynamically adjusted - F32 mAvailable; // Bits available to send right now on each channel - F64Seconds mLastSendTime; // Time since last send on this channel -}; - -typedef enum e_throttle_categories -{ - TC_RESEND, - TC_LAND, - TC_WIND, - TC_CLOUD, - TC_TASK, - TC_TEXTURE, - TC_ASSET, - TC_EOF -} EThrottleCats; - - -class LLThrottleGroup -{ -public: - LLThrottleGroup(); - ~LLThrottleGroup() { } - - void resetDynamicAdjust(); - BOOL checkOverflow(S32 throttle_cat, F32 bits); // I'm about to send bits, TRUE if would overflow channel - BOOL throttleOverflow(S32 throttle_cat, F32 bits); // I just sent bits, TRUE if that overflowed the channel - 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: - F32 mThrottleTotal[TC_EOF]; // BPS available, sent by viewer, sum for all simulators - -protected: - F32 mNominalBPS[TC_EOF]; // BPS available, adjusted to be just this simulator - F32 mCurrentBPS[TC_EOF]; // BPS available, dynamically adjusted - - F32 mBitsAvailable[TC_EOF]; // Bits available to send right now on each channel - F32 mBitsSentThisPeriod[TC_EOF]; // Sent in this dynamic allocation period - F32 mBitsSentHistory[TC_EOF]; // Sent before this dynamic allocation period, adjusted to one period length - - F64Seconds mLastSendTime[TC_EOF]; // Time since last send on this channel - F64Seconds mDynamicAdjustTime; // Only dynamic adjust every 2 seconds or so. - -}; - -#endif +/**
+ * @file llthrottle.h
+ * @brief LLThrottle class used for network bandwidth control
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLTHROTTLE_H
+#define LL_LLTHROTTLE_H
+
+#include "lltimer.h"
+
+const S32 MAX_THROTTLE_SIZE = 32;
+
+class LLDataPacker;
+
+// Single instance of a generic throttle
+class LLThrottle
+{
+public:
+ LLThrottle(const F32 throttle = 1.f);
+ ~LLThrottle() { }
+
+ void setRate(const F32 rate);
+ bool checkOverflow(const F32 amount); // I'm about to add an amount, true if would overflow throttle
+ bool throttleOverflow(const F32 amount); // I just sent amount, true if that overflowed the throttle
+
+ F32 getAvailable(); // Return the available bits
+ F32 getRate() const { return mRate; }
+private:
+ F32 mLookaheadSecs; // Seconds to look ahead, maximum
+ F32 mRate; // BPS available, dynamically adjusted
+ F32 mAvailable; // Bits available to send right now on each channel
+ F64Seconds mLastSendTime; // Time since last send on this channel
+};
+
+typedef enum e_throttle_categories
+{
+ TC_RESEND,
+ TC_LAND,
+ TC_WIND,
+ TC_CLOUD,
+ TC_TASK,
+ TC_TEXTURE,
+ TC_ASSET,
+ TC_EOF
+} EThrottleCats;
+
+
+class LLThrottleGroup
+{
+public:
+ LLThrottleGroup();
+ ~LLThrottleGroup() { }
+
+ void resetDynamicAdjust();
+ bool checkOverflow(S32 throttle_cat, F32 bits); // I'm about to send bits, true if would overflow channel
+ bool throttleOverflow(S32 throttle_cat, F32 bits); // I just sent bits, true if that overflowed the channel
+ 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:
+ F32 mThrottleTotal[TC_EOF]; // BPS available, sent by viewer, sum for all simulators
+
+protected:
+ F32 mNominalBPS[TC_EOF]; // BPS available, adjusted to be just this simulator
+ F32 mCurrentBPS[TC_EOF]; // BPS available, dynamically adjusted
+
+ F32 mBitsAvailable[TC_EOF]; // Bits available to send right now on each channel
+ F32 mBitsSentThisPeriod[TC_EOF]; // Sent in this dynamic allocation period
+ F32 mBitsSentHistory[TC_EOF]; // Sent before this dynamic allocation period, adjusted to one period length
+
+ F64Seconds mLastSendTime[TC_EOF]; // Time since last send on this channel
+ F64Seconds mDynamicAdjustTime; // Only dynamic adjust every 2 seconds or so.
+
+};
+
+#endif
diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp index 7f6ff3b025..f5351c6b58 100644 --- a/indra/llmessage/lltransfermanager.cpp +++ b/indra/llmessage/lltransfermanager.cpp @@ -1,1401 +1,1401 @@ -/** - * @file lltransfermanager.cpp - * @brief Improved transfer mechanism for moving data through the - * message system. - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#include "linden_common.h" - -#include "lltransfermanager.h" - -#include "llerror.h" -#include "message.h" -#include "lldatapacker.h" - -#include "lltransfersourcefile.h" -#include "lltransfersourceasset.h" -#include "lltransfertargetfile.h" -#include "lltransfertargetvfile.h" - -const S32 MAX_PACKET_DATA_SIZE = 2048; -const S32 MAX_PARAMS_SIZE = 1024; - -LLTransferManager gTransferManager; -LLTransferSource::stype_scfunc_map LLTransferSource::sSourceCreateMap; - -// -// LLTransferManager implementation -// - -LLTransferManager::LLTransferManager() : - mValid(FALSE) -{ - S32 i; - for (i = 0; i < LLTTT_NUM_TYPES; i++) - { - mTransferBitsIn[i] = 0; - mTransferBitsOut[i] = 0; - } -} - - -LLTransferManager::~LLTransferManager() -{ - // LLTransferManager should have been cleaned up by message system shutdown process - llassert(!mValid); - if (mValid) - { - // Usually happens if OS tries to kill viewer - cleanup(); - } -} - - -void LLTransferManager::init() -{ - if (mValid) - { - LL_ERRS() << "Double initializing LLTransferManager!" << LL_ENDL; - } - mValid = TRUE; - - // Register message system handlers - gMessageSystem->setHandlerFunc("TransferRequest", processTransferRequest, NULL); - gMessageSystem->setHandlerFunc("TransferInfo", processTransferInfo, NULL); - gMessageSystem->setHandlerFunc("TransferPacket", processTransferPacket, NULL); - gMessageSystem->setHandlerFunc("TransferAbort", processTransferAbort, NULL); -} - - -void LLTransferManager::cleanup() -{ - mValid = FALSE; - - host_tc_map::iterator iter; - for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++) - { - delete iter->second; - } - mTransferConnections.clear(); -} - - -void LLTransferManager::updateTransfers() -{ - host_tc_map::iterator iter,cur; - - iter = mTransferConnections.begin(); - - while (iter !=mTransferConnections.end()) - { - cur = iter; - iter++; - cur->second->updateTransfers(); - } -} - - -void LLTransferManager::cleanupConnection(const LLHost &host) -{ - host_tc_map::iterator iter; - iter = mTransferConnections.find(host); - if (iter == mTransferConnections.end()) - { - // This can happen legitimately if we've never done a transfer, and we're - // cleaning up a circuit. - //LL_WARNS() << "Cleaning up nonexistent transfer connection to " << host << LL_ENDL; - return; - } - LLTransferConnection *connp = iter->second; - delete connp; - mTransferConnections.erase(iter); -} - - -LLTransferConnection *LLTransferManager::getTransferConnection(const LLHost &host) -{ - host_tc_map::iterator iter; - iter = mTransferConnections.find(host); - if (iter == mTransferConnections.end()) - { - mTransferConnections[host] = new LLTransferConnection(host); - return mTransferConnections[host]; - } - - return iter->second; -} - - -LLTransferSourceChannel *LLTransferManager::getSourceChannel(const LLHost &host, const LLTransferChannelType type) -{ - LLTransferConnection *tcp = getTransferConnection(host); - if (!tcp) - { - return NULL; - } - return tcp->getSourceChannel(type); -} - - - -LLTransferTargetChannel *LLTransferManager::getTargetChannel(const LLHost &host, const LLTransferChannelType type) -{ - LLTransferConnection *tcp = getTransferConnection(host); - if (!tcp) - { - return NULL; - } - return tcp->getTargetChannel(type); -} - -// virtual -LLTransferSourceParams::~LLTransferSourceParams() -{ } - - -LLTransferSource *LLTransferManager::findTransferSource(const LLUUID &transfer_id) -{ - // This linear traversal could screw us later if we do lots of - // searches for sources. However, this ONLY happens right now - // in asset transfer callbacks, so this should be relatively quick. - host_tc_map::iterator iter; - for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++) - { - LLTransferConnection *tcp = iter->second; - LLTransferConnection::tsc_iter sc_iter; - for (sc_iter = tcp->mTransferSourceChannels.begin(); sc_iter != tcp->mTransferSourceChannels.end(); sc_iter++) - { - LLTransferSourceChannel *scp = *sc_iter; - LLTransferSource *sourcep = scp->findTransferSource(transfer_id); - if (sourcep) - { - return sourcep; - } - } - } - - return NULL; -} - -// -// Message handlers -// - -//static -void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **) -{ - //LL_INFOS() << "LLTransferManager::processTransferRequest" << LL_ENDL; - - LLUUID transfer_id; - LLTransferSourceType source_type; - LLTransferChannelType channel_type; - F32 priority; - - msgp->getUUID("TransferInfo", "TransferID", transfer_id); - msgp->getS32("TransferInfo", "SourceType", (S32 &)source_type); - msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type); - msgp->getF32("TransferInfo", "Priority", priority); - - LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type); - - if (!tscp) - { - LL_WARNS() << "Source channel not found" << LL_ENDL; - return; - } - - if (tscp->findTransferSource(transfer_id)) - { - LL_WARNS() << "Duplicate request for transfer " << transfer_id << ", aborting!" << LL_ENDL; - return; - } - - S32 size = msgp->getSize("TransferInfo", "Params"); - if(size > MAX_PARAMS_SIZE) - { - LL_WARNS() << "LLTransferManager::processTransferRequest params too big." - << LL_ENDL; - return; - } - - //LL_INFOS() << transfer_id << ":" << source_type << ":" << channel_type << ":" << priority << LL_ENDL; - LLTransferSource* tsp = LLTransferSource::createSource( - source_type, - transfer_id, - priority); - if(!tsp) - { - LL_WARNS() << "LLTransferManager::processTransferRequest couldn't create" - << " transfer source!" << LL_ENDL; - return; - } - U8 tmp[MAX_PARAMS_SIZE]; - msgp->getBinaryData("TransferInfo", "Params", tmp, size); - - LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE); - BOOL unpack_ok = tsp->unpackParams(dpb); - if (!unpack_ok) - { - // This should only happen if the data is corrupt or - // incorrectly packed. - // *NOTE: We may want to call abortTransfer(). - LL_WARNS() << "LLTransferManager::processTransferRequest: bad parameters." - << LL_ENDL; - delete tsp; - return; - } - - tscp->addTransferSource(tsp); - tsp->initTransfer(); -} - - -//static -void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) -{ - //LL_INFOS() << "LLTransferManager::processTransferInfo" << LL_ENDL; - - LLUUID transfer_id; - LLTransferTargetType target_type; - LLTransferChannelType channel_type; - LLTSCode status; - S32 size; - - msgp->getUUID("TransferInfo", "TransferID", transfer_id); - msgp->getS32("TransferInfo", "TargetType", (S32 &)target_type); - msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type); - msgp->getS32("TransferInfo", "Status", (S32 &)status); - msgp->getS32("TransferInfo", "Size", size); - - //LL_INFOS() << transfer_id << ":" << target_type<< ":" << channel_type << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type); - if (!ttcp) - { - LL_WARNS() << "Target channel not found" << LL_ENDL; - // Should send a message to abort the transfer. - return; - } - - LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id); - if (!ttp) - { - LL_WARNS() << "TransferInfo for unknown transfer! Not able to handle this yet!" << LL_ENDL; - // This could happen if we're doing a push transfer, although to avoid confusion, - // maybe it should be a different message. - return; - } - - if (status != LLTS_OK) - { - LL_WARNS() << transfer_id << ": Non-ok status, cleaning up" << LL_ENDL; - ttp->completionCallback(status); - // Clean up the transfer. - ttcp->deleteTransfer(ttp); - return; - } - - // unpack the params - S32 params_size = msgp->getSize("TransferInfo", "Params"); - if(params_size > MAX_PARAMS_SIZE) - { - LL_WARNS() << "LLTransferManager::processTransferInfo params too big." - << LL_ENDL; - return; - } - else if(params_size > 0) - { - U8 tmp[MAX_PARAMS_SIZE]; - msgp->getBinaryData("TransferInfo", "Params", tmp, params_size); - LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE); - if (!ttp->unpackParams(dpb)) - { - // This should only happen if the data is corrupt or - // incorrectly packed. - LL_WARNS() << "LLTransferManager::processTransferRequest: bad params." - << LL_ENDL; - ttp->abortTransfer(); - ttcp->deleteTransfer(ttp); - return; - } - } - - //LL_INFOS() << "Receiving " << transfer_id << ", size " << size << " bytes" << LL_ENDL; - ttp->setSize(size); - ttp->setGotInfo(TRUE); - - // OK, at this point we to handle any delayed transfer packets (which could happen - // if this packet was lost) - - // This is a lame cut and paste of code down below. If we change the logic down there, - // we HAVE to change the logic up here. - - while (1) - { - S32 packet_id = 0; - U8 tmp_data[MAX_PACKET_DATA_SIZE]; - // See if we've got any delayed packets - packet_id = ttp->getNextPacketID(); - if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end()) - { - // Perhaps this stuff should be inside a method in LLTransferPacket? - // I'm too lazy to do it now, though. -// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL; - LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id]; - - // This is somewhat inefficient, but avoids us having to duplicate - // code between the off-the-wire and delayed paths. - packet_id = packetp->mPacketID; - size = packetp->mSize; - if (size) - { - if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data))) - { - memcpy(tmp_data, packetp->mDatap, size); /*Flawfinder: ignore*/ - } - } - status = packetp->mStatus; - ttp->mDelayedPacketMap.erase(packet_id); - delete packetp; - } - else - { - // No matching delayed packet, we're done. - break; - } - - LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size); - if (ret_code == LLTS_OK) - { - ttp->setLastPacketID(packet_id); - } - - if (status != LLTS_OK) - { - if (status != LLTS_DONE) - { - LL_WARNS() << "LLTransferManager::processTransferInfo Error in playback!" << LL_ENDL; - } - else - { - LL_INFOS() << "LLTransferManager::processTransferInfo replay FINISHED for " << transfer_id << LL_ENDL; - } - // This transfer is done, either via error or not. - ttp->completionCallback(status); - ttcp->deleteTransfer(ttp); - return; - } - } -} - - -//static -void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) -{ - //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL; - - LLUUID transfer_id; - LLTransferChannelType channel_type; - S32 packet_id; - LLTSCode status; - S32 size; - msgp->getUUID("TransferData", "TransferID", transfer_id); - msgp->getS32("TransferData", "ChannelType", (S32 &)channel_type); - msgp->getS32("TransferData", "Packet", packet_id); - msgp->getS32("TransferData", "Status", (S32 &)status); - - // Find the transfer associated with this packet. - //LL_INFOS() << transfer_id << ":" << channel_type << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type); - if (!ttcp) - { - LL_WARNS() << "Target channel not found" << LL_ENDL; - return; - } - - LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id); - if (!ttp) - { - LL_WARNS() << "Didn't find matching transfer for " << transfer_id - << " processing packet " << packet_id - << " from " << msgp->getSender() << LL_ENDL; - return; - } - - size = msgp->getSize("TransferData", "Data"); - - S32 msg_bytes = 0; - if (msgp->getReceiveCompressedSize()) - { - msg_bytes = msgp->getReceiveCompressedSize(); - } - else - { - msg_bytes = msgp->getReceiveSize(); - } - gTransferManager.addTransferBitsIn(ttcp->mChannelType, msg_bytes*8); - - if ((size < 0) || (size > MAX_PACKET_DATA_SIZE)) - { - LL_WARNS() << "Invalid transfer packet size " << size << LL_ENDL; - return; - } - - U8 tmp_data[MAX_PACKET_DATA_SIZE]; - if (size > 0) - { - // Only pull the data out if the size is > 0 - msgp->getBinaryData("TransferData", "Data", tmp_data, size); - } - - if ((!ttp->gotInfo()) || (ttp->getNextPacketID() != packet_id)) - { - // Put this on a list of packets to be delivered later. - if(!ttp->addDelayedPacket(packet_id, status, tmp_data, size)) - { - // Whoops - failed to add a delayed packet for some reason. - LL_WARNS() << "Too many delayed packets processing transfer " - << transfer_id << " from " << msgp->getSender() << LL_ENDL; - ttp->abortTransfer(); - ttcp->deleteTransfer(ttp); - return; - } -#if 0 - // Spammy! - const S32 LL_TRANSFER_WARN_GAP = 10; - if(!ttp->gotInfo()) - { - LL_WARNS() << "Got data packet before information in transfer " - << transfer_id << " from " << msgp->getSender() - << ", got " << packet_id << LL_ENDL; - } - else if((packet_id - ttp->getNextPacketID()) > LL_TRANSFER_WARN_GAP) - { - LL_WARNS() << "Out of order packet in transfer " << transfer_id - << " from " << msgp->getSender() << ", got " << packet_id - << " expecting " << ttp->getNextPacketID() << LL_ENDL; - } -#endif - return; - } - - // Loop through this until we're done with all delayed packets - - // - // NOTE: THERE IS A CUT AND PASTE OF THIS CODE IN THE TRANSFERINFO HANDLER - // SO WE CAN PLAY BACK DELAYED PACKETS THERE!!!!!!!!!!!!!!!!!!!!!!!!! - // - BOOL done = FALSE; - while (!done) - { - LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size); - if (ret_code == LLTS_OK) - { - ttp->setLastPacketID(packet_id); - } - - if (status != LLTS_OK) - { - if (status != LLTS_DONE) - { - LL_WARNS() << "LLTransferManager::processTransferPacket Error in transfer!" << LL_ENDL; - } - else - { -// LL_INFOS() << "LLTransferManager::processTransferPacket done for " << transfer_id << LL_ENDL; - } - // This transfer is done, either via error or not. - ttp->completionCallback(status); - ttcp->deleteTransfer(ttp); - return; - } - - // See if we've got any delayed packets - packet_id = ttp->getNextPacketID(); - if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end()) - { - // Perhaps this stuff should be inside a method in LLTransferPacket? - // I'm too lazy to do it now, though. -// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL; - LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id]; - - // This is somewhat inefficient, but avoids us having to duplicate - // code between the off-the-wire and delayed paths. - packet_id = packetp->mPacketID; - size = packetp->mSize; - if (size) - { - if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data))) - { - memcpy(tmp_data, packetp->mDatap, size); /*Flawfinder: ignore*/ - } - } - status = packetp->mStatus; - ttp->mDelayedPacketMap.erase(packet_id); - delete packetp; - } - else - { - // No matching delayed packet, abort it. - done = TRUE; - } - } -} - - -//static -void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **) -{ - //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL; - - LLUUID transfer_id; - LLTransferChannelType channel_type; - msgp->getUUID("TransferInfo", "TransferID", transfer_id); - msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type); - - // See if it's a target that we're trying to abort - // Find the transfer associated with this packet. - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type); - if (ttcp) - { - LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id); - if (ttp) - { - ttp->abortTransfer(); - ttcp->deleteTransfer(ttp); - return; - } - } - - // Hmm, not a target. Maybe it's a source. - LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type); - if (tscp) - { - LLTransferSource *tsp = tscp->findTransferSource(transfer_id); - if (tsp) - { - tsp->abortTransfer(); - tscp->deleteTransfer(tsp); - return; - } - } - - LL_WARNS() << "Couldn't find transfer " << transfer_id << " to abort!" << LL_ENDL; -} - - -//static -void LLTransferManager::reliablePacketCallback(void **user_data, S32 result) -{ - LLUUID *transfer_idp = (LLUUID *)user_data; - if (result && - transfer_idp != NULL) - { - LLTransferSource *tsp = gTransferManager.findTransferSource(*transfer_idp); - if (tsp) - { - LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " due to failed reliable resends!" << LL_ENDL; - LLTransferSourceChannel *tscp = tsp->mChannelp; - tsp->abortTransfer(); - tscp->deleteTransfer(tsp); - } - else - { - LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " but can't find the LLTransferSource object" << LL_ENDL; - } - } - delete transfer_idp; -} - -// -// LLTransferConnection implementation -// - -LLTransferConnection::LLTransferConnection(const LLHost &host) -{ - mHost = host; -} - -LLTransferConnection::~LLTransferConnection() -{ - tsc_iter itersc; - for (itersc = mTransferSourceChannels.begin(); itersc != mTransferSourceChannels.end(); itersc++) - { - delete *itersc; - } - mTransferSourceChannels.clear(); - - ttc_iter itertc; - for (itertc = mTransferTargetChannels.begin(); itertc != mTransferTargetChannels.end(); itertc++) - { - delete *itertc; - } - mTransferTargetChannels.clear(); -} - - -void LLTransferConnection::updateTransfers() -{ - // Do stuff for source transfers (basically, send data out). - tsc_iter iter, cur; - iter = mTransferSourceChannels.begin(); - - while (iter !=mTransferSourceChannels.end()) - { - cur = iter; - iter++; - (*cur)->updateTransfers(); - } - - // Do stuff for target transfers - // Primarily, we should be aborting transfers that are irredeemably broken - // (large packet gaps that don't appear to be getting filled in, most likely) - // Probably should NOT be doing timeouts for other things, as new priority scheme - // means that a high priority transfer COULD block a transfer for a long time. -} - - -LLTransferSourceChannel *LLTransferConnection::getSourceChannel(const LLTransferChannelType channel_type) -{ - tsc_iter iter; - for (iter = mTransferSourceChannels.begin(); iter != mTransferSourceChannels.end(); iter++) - { - if ((*iter)->getChannelType() == channel_type) - { - return *iter; - } - } - - LLTransferSourceChannel *tscp = new LLTransferSourceChannel(channel_type, mHost); - mTransferSourceChannels.push_back(tscp); - return tscp; -} - - -LLTransferTargetChannel *LLTransferConnection::getTargetChannel(const LLTransferChannelType channel_type) -{ - ttc_iter iter; - for (iter = mTransferTargetChannels.begin(); iter != mTransferTargetChannels.end(); iter++) - { - if ((*iter)->getChannelType() == channel_type) - { - return *iter; - } - } - - LLTransferTargetChannel *ttcp = new LLTransferTargetChannel(channel_type, mHost); - mTransferTargetChannels.push_back(ttcp); - return ttcp; -} - - -// -// LLTransferSourceChannel implementation -// - -const S32 DEFAULT_PACKET_SIZE = 1000; - - -LLTransferSourceChannel::LLTransferSourceChannel(const LLTransferChannelType channel_type, const LLHost &host) : - mChannelType(channel_type), - mHost(host), - mTransferSources(LLTransferSource::sSetPriority, LLTransferSource::sGetPriority), - mThrottleID(TC_ASSET) -{ -} - - -LLTransferSourceChannel::~LLTransferSourceChannel() -{ - LLPriQueueMap<LLTransferSource*>::pqm_iter iter = - mTransferSources.mMap.begin(); - LLPriQueueMap<LLTransferSource*>::pqm_iter end = - mTransferSources.mMap.end(); - for (; iter != end; ++iter) - { - // Just kill off all of the transfers - (*iter).second->abortTransfer(); - delete iter->second; - } - mTransferSources.mMap.clear(); -} - -void LLTransferSourceChannel::updatePriority(LLTransferSource *tsp, const F32 priority) -{ - mTransferSources.reprioritize(priority, tsp); -} - -void LLTransferSourceChannel::updateTransfers() -{ - // Actually, this should do the following: - // Decide if we can actually send data. - // If so, update priorities so we know who gets to send it. - // Send data from the sources, while updating until we've sent our throttle allocation. - - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(getHost()); - if (!cdp) - { - return; - } - - if (cdp->isBlocked()) - { - // *NOTE: We need to make sure that the throttle bits - // available gets reset. - - // We DON'T want to send any packets if they're blocked, they'll just end up - // piling up on the other end. - //LL_WARNS() << "Blocking transfers due to blocked circuit for " << getHost() << LL_ENDL; - return; - } - - const S32 throttle_id = mThrottleID; - - LLThrottleGroup &tg = cdp->getThrottleGroup(); - - if (tg.checkOverflow(throttle_id, 0.f)) - { - return; - } - - LLPriQueueMap<LLTransferSource *>::pqm_iter iter, next; - - BOOL done = FALSE; - for (iter = mTransferSources.mMap.begin(); (iter != mTransferSources.mMap.end()) && !done;) - { - //LL_INFOS() << "LLTransferSourceChannel::updateTransfers()" << LL_ENDL; - // Do stuff. - next = iter; - next++; - - LLTransferSource *tsp = iter->second; - U8 *datap = NULL; - S32 data_size = 0; - BOOL delete_data = FALSE; - S32 packet_id = 0; - S32 sent_bytes = 0; - LLTSCode status = LLTS_OK; - - // Get the packetID for the next packet that we're transferring. - packet_id = tsp->getNextPacketID(); - status = tsp->dataCallback(packet_id, DEFAULT_PACKET_SIZE, &datap, data_size, delete_data); - - if (status == LLTS_SKIP) - { - // We don't have any data, but we're not done, just go on. - // This will presumably be used for streaming or async transfers that - // are stalled waiting for data from another source. - iter=next; - continue; - } - - LLUUID *cb_uuid = new LLUUID(tsp->getID()); - LLUUID transaction_id = tsp->getID(); - - // Send the data now, even if it's an error. - // The status code will tell the other end what to do. - gMessageSystem->newMessage("TransferPacket"); - gMessageSystem->nextBlock("TransferData"); - gMessageSystem->addUUID("TransferID", tsp->getID()); - gMessageSystem->addS32("ChannelType", getChannelType()); - gMessageSystem->addS32("Packet", packet_id); // HACK! Need to put in a REAL packet id - gMessageSystem->addS32("Status", status); - gMessageSystem->addBinaryData("Data", datap, data_size); - sent_bytes = gMessageSystem->getCurrentSendTotal(); - gMessageSystem->sendReliable(getHost(), LL_DEFAULT_RELIABLE_RETRIES, TRUE, F32Seconds(0.f), - LLTransferManager::reliablePacketCallback, (void**)cb_uuid); - - // Do bookkeeping for the throttle - done = tg.throttleOverflow(throttle_id, sent_bytes*8.f); - gTransferManager.addTransferBitsOut(mChannelType, sent_bytes*8); - - // Clean up our temporary data. - if (delete_data) - { - delete[] datap; - datap = NULL; - } - - if (findTransferSource(transaction_id) == NULL) - { - //Warning! In the case of an aborted transfer, the sendReliable call above calls - //AbortTransfer which in turn calls deleteTransfer which means that somewhere way - //down the chain our current iter can get invalidated resulting in an infrequent - //sim crash. This check gets us to a valid transfer source in this event. - iter=next; - continue; - } - - // Update the packet counter - tsp->setLastPacketID(packet_id); - - switch (status) - { - case LLTS_OK: - // We're OK, don't need to do anything. Keep sending data. - break; - case LLTS_ERROR: - LL_WARNS() << "Error in transfer dataCallback!" << LL_ENDL; - // fall through - case LLTS_DONE: - // We need to clean up this transfer source. - //LL_INFOS() << "LLTransferSourceChannel::updateTransfers() " << tsp->getID() << " done" << LL_ENDL; - tsp->completionCallback(status); - delete tsp; - - mTransferSources.mMap.erase(iter); - iter = next; - break; - default: - LL_ERRS() << "Unknown transfer error code!" << LL_ENDL; - } - - // At this point, we should do priority adjustment (since some transfers like - // streaming transfers will adjust priority based on how much they've sent and time, - // but I'm not going to bother yet. - djs. - } -} - - -void LLTransferSourceChannel::addTransferSource(LLTransferSource *sourcep) -{ - sourcep->mChannelp = this; - mTransferSources.push(sourcep->getPriority(), sourcep); -} - - -LLTransferSource *LLTransferSourceChannel::findTransferSource(const LLUUID &transfer_id) -{ - LLPriQueueMap<LLTransferSource *>::pqm_iter iter; - for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++) - { - LLTransferSource *tsp = iter->second; - if (tsp->getID() == transfer_id) - { - return tsp; - } - } - return NULL; -} - - -void LLTransferSourceChannel::deleteTransfer(LLTransferSource *tsp) -{ - if (tsp) - { - LLPriQueueMap<LLTransferSource *>::pqm_iter iter; - for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++) - { - if (iter->second == tsp) - { - delete tsp; - mTransferSources.mMap.erase(iter); - return; - } - } - - LL_WARNS() << "Unable to find transfer source id " - << tsp->getID() - << " to delete!" - << LL_ENDL; - } -} - - -// -// LLTransferTargetChannel implementation -// - -LLTransferTargetChannel::LLTransferTargetChannel(const LLTransferChannelType channel_type, const LLHost &host) : - mChannelType(channel_type), - mHost(host) -{ -} - -LLTransferTargetChannel::~LLTransferTargetChannel() -{ - tt_iter iter; - for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++) - { - // Abort all of the current transfers - (*iter)->abortTransfer(); - delete *iter; - } - mTransferTargets.clear(); -} - - -void LLTransferTargetChannel::requestTransfer( - const LLTransferSourceParams& source_params, - const LLTransferTargetParams& target_params, - const F32 priority) -{ - LLUUID id; - id.generate(); - LLTransferTarget* ttp = LLTransferTarget::createTarget( - target_params.getType(), - id, - source_params.getType()); - if (!ttp) - { - LL_WARNS() << "LLTransferManager::requestTransfer aborting due to target creation failure!" << LL_ENDL; - return; - } - - ttp->applyParams(target_params); - addTransferTarget(ttp); - - sendTransferRequest(ttp, source_params, priority); -} - - -void LLTransferTargetChannel::sendTransferRequest(LLTransferTarget *targetp, - const LLTransferSourceParams ¶ms, - const F32 priority) -{ - // - // Pack the message with data which explains how to get the source, and - // send it off to the source for this channel. - // - llassert(targetp); - llassert(targetp->getChannel() == this); - - gMessageSystem->newMessage("TransferRequest"); - gMessageSystem->nextBlock("TransferInfo"); - gMessageSystem->addUUID("TransferID", targetp->getID()); - gMessageSystem->addS32("SourceType", params.getType()); - gMessageSystem->addS32("ChannelType", getChannelType()); - gMessageSystem->addF32("Priority", priority); - - U8 tmp[MAX_PARAMS_SIZE]; - LLDataPackerBinaryBuffer dp(tmp, MAX_PARAMS_SIZE); - params.packParams(dp); - S32 len = dp.getCurrentSize(); - gMessageSystem->addBinaryData("Params", tmp, len); - - gMessageSystem->sendReliable(mHost); -} - - -void LLTransferTargetChannel::addTransferTarget(LLTransferTarget *targetp) -{ - targetp->mChannelp = this; - mTransferTargets.push_back(targetp); -} - - -LLTransferTarget *LLTransferTargetChannel::findTransferTarget(const LLUUID &transfer_id) -{ - tt_iter iter; - for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++) - { - LLTransferTarget *ttp = *iter; - if (ttp->getID() == transfer_id) - { - return ttp; - } - } - return NULL; -} - - -void LLTransferTargetChannel::deleteTransfer(LLTransferTarget *ttp) -{ - if (ttp) - { - tt_iter iter; - for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++) - { - if (*iter == ttp) - { - delete ttp; - mTransferTargets.erase(iter); - return; - } - } - - LL_WARNS() << "Unable to find transfer target id " - << ttp->getID() - << " to delete!" - << LL_ENDL; - } -} - - -// -// LLTransferSource implementation -// - -LLTransferSource::LLTransferSource(const LLTransferSourceType type, - const LLUUID &transfer_id, - const F32 priority) : - mType(type), - mID(transfer_id), - mChannelp(NULL), - mPriority(priority), - mSize(0), - mLastPacketID(-1) -{ - setPriority(priority); -} - - -LLTransferSource::~LLTransferSource() -{ - // No actual cleanup of the transfer is done here, this is purely for - // memory cleanup. The completionCallback is guaranteed to get called - // before this happens. -} - - -void LLTransferSource::sendTransferStatus(LLTSCode status) -{ - gMessageSystem->newMessage("TransferInfo"); - gMessageSystem->nextBlock("TransferInfo"); - gMessageSystem->addUUID("TransferID", getID()); - gMessageSystem->addS32("TargetType", LLTTT_UNKNOWN); - gMessageSystem->addS32("ChannelType", mChannelp->getChannelType()); - gMessageSystem->addS32("Status", status); - gMessageSystem->addS32("Size", mSize); - U8 tmp[MAX_PARAMS_SIZE]; - LLDataPackerBinaryBuffer dp(tmp, MAX_PARAMS_SIZE); - packParams(dp); - S32 len = dp.getCurrentSize(); - gMessageSystem->addBinaryData("Params", tmp, len); - gMessageSystem->sendReliable(mChannelp->getHost()); - - // Abort if there was as asset system issue. - if (status != LLTS_OK) - { - completionCallback(status); - mChannelp->deleteTransfer(this); - } -} - - -// This should never be called directly, the transfer manager is responsible for -// aborting the transfer from the channel. I might want to rethink this in the -// future, though. -void LLTransferSource::abortTransfer() -{ - // Send a message down, call the completion callback - LL_INFOS() << "LLTransferSource::Aborting transfer " << getID() << " to " << mChannelp->getHost() << LL_ENDL; - gMessageSystem->newMessage("TransferAbort"); - gMessageSystem->nextBlock("TransferInfo"); - gMessageSystem->addUUID("TransferID", getID()); - gMessageSystem->addS32("ChannelType", mChannelp->getChannelType()); - gMessageSystem->sendReliable(mChannelp->getHost()); - - completionCallback(LLTS_ABORT); -} - - -//static -void LLTransferSource::registerSourceType(const LLTransferSourceType stype, LLTransferSourceCreateFunc func) -{ - if (sSourceCreateMap.count(stype)) - { - // Disallow changing what class handles a source type - // Unclear when you would want to do this, and whether it would work. - LL_ERRS() << "Reregistering source type " << stype << LL_ENDL; - } - else - { - sSourceCreateMap[stype] = func; - } -} - -//static -LLTransferSource *LLTransferSource::createSource(const LLTransferSourceType stype, - const LLUUID &id, - const F32 priority) -{ - switch (stype) - { - // *NOTE: The source file transfer mechanism is highly insecure and could - // lead to easy exploitation of a server process. - // I have removed all uses of it from the codebase. Phoenix. - // - //case LLTST_FILE: - // return new LLTransferSourceFile(id, priority); - case LLTST_ASSET: - return new LLTransferSourceAsset(id, priority); - default: - { - if (!sSourceCreateMap.count(stype)) - { - // Use the callback to create the source type if it's not there. - LL_WARNS() << "Unknown transfer source type: " << stype << LL_ENDL; - return NULL; - } - return (sSourceCreateMap[stype])(id, priority); - } - } -} - - -// static -void LLTransferSource::sSetPriority(LLTransferSource *&tsp, const F32 priority) -{ - tsp->setPriority(priority); -} - - -// static -F32 LLTransferSource::sGetPriority(LLTransferSource *&tsp) -{ - return tsp->getPriority(); -} - - -// -// LLTransferPacket implementation -// - -LLTransferPacket::LLTransferPacket(const S32 packet_id, const LLTSCode status, const U8 *datap, const S32 size) : - mPacketID(packet_id), - mStatus(status), - mDatap(NULL), - mSize(size) -{ - if (size == 0) - { - return; - } - - mDatap = new U8[size]; - if (mDatap != NULL) - { - memcpy(mDatap, datap, size); /*Flawfinder: ignore*/ - } -} - -LLTransferPacket::~LLTransferPacket() -{ - delete[] mDatap; -} - -// -// LLTransferTarget implementation -// - -LLTransferTarget::LLTransferTarget( - LLTransferTargetType type, - const LLUUID& transfer_id, - LLTransferSourceType source_type) : - mType(type), - mSourceType(source_type), - mID(transfer_id), - mChannelp(NULL), - mGotInfo(FALSE), - mSize(0), - mLastPacketID(-1) -{ -} - -LLTransferTarget::~LLTransferTarget() -{ - // No actual cleanup of the transfer is done here, this is purely for - // memory cleanup. The completionCallback is guaranteed to get called - // before this happens. - tpm_iter iter; - for (iter = mDelayedPacketMap.begin(); iter != mDelayedPacketMap.end(); iter++) - { - delete iter->second; - } - mDelayedPacketMap.clear(); -} - -// This should never be called directly, the transfer manager is responsible for -// aborting the transfer from the channel. I might want to rethink this in the -// future, though. -void LLTransferTarget::abortTransfer() -{ - // Send a message up, call the completion callback - LL_INFOS() << "LLTransferTarget::Aborting transfer " << getID() << " from " << mChannelp->getHost() << LL_ENDL; - gMessageSystem->newMessage("TransferAbort"); - gMessageSystem->nextBlock("TransferInfo"); - gMessageSystem->addUUID("TransferID", getID()); - gMessageSystem->addS32("ChannelType", mChannelp->getChannelType()); - gMessageSystem->sendReliable(mChannelp->getHost()); - - completionCallback(LLTS_ABORT); -} - -bool LLTransferTarget::addDelayedPacket( - const S32 packet_id, - const LLTSCode status, - U8* datap, - const S32 size) -{ - const transfer_packet_map::size_type LL_MAX_DELAYED_PACKETS = 100; - if(mDelayedPacketMap.size() > LL_MAX_DELAYED_PACKETS) - { - // too many delayed packets - return false; - } - - LLTransferPacket* tpp = new LLTransferPacket( - packet_id, - status, - datap, - size); - -#ifdef _DEBUG - transfer_packet_map::iterator iter = mDelayedPacketMap.find(packet_id); - if (iter != mDelayedPacketMap.end()) - { - if (!(iter->second->mSize == size) && !(iter->second->mDatap == datap)) - { - LL_ERRS() << "Packet ALREADY in delayed packet map!" << LL_ENDL; - } - } -#endif - - mDelayedPacketMap[packet_id] = tpp; - return true; -} - - -LLTransferTarget* LLTransferTarget::createTarget( - LLTransferTargetType type, - const LLUUID& id, - LLTransferSourceType source_type) -{ - switch (type) - { - case LLTTT_FILE: - return new LLTransferTargetFile(id, source_type); - case LLTTT_VFILE: - return new LLTransferTargetVFile(id, source_type); - default: - LL_WARNS() << "Unknown transfer target type: " << type << LL_ENDL; - return NULL; - } -} - - -LLTransferSourceParamsInvItem::LLTransferSourceParamsInvItem() : LLTransferSourceParams(LLTST_SIM_INV_ITEM), mAssetType(LLAssetType::AT_NONE) -{ -} - - -void LLTransferSourceParamsInvItem::setAgentSession(const LLUUID &agent_id, const LLUUID &session_id) -{ - mAgentID = agent_id; - mSessionID = session_id; -} - - -void LLTransferSourceParamsInvItem::setInvItem(const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id) -{ - mOwnerID = owner_id; - mTaskID = task_id; - mItemID = item_id; -} - - -void LLTransferSourceParamsInvItem::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type) -{ - mAssetID = asset_id; - mAssetType = asset_type; -} - - -void LLTransferSourceParamsInvItem::packParams(LLDataPacker &dp) const -{ - LL_DEBUGS() << "LLTransferSourceParamsInvItem::packParams()" << LL_ENDL; - dp.packUUID(mAgentID, "AgentID"); - dp.packUUID(mSessionID, "SessionID"); - dp.packUUID(mOwnerID, "OwnerID"); - dp.packUUID(mTaskID, "TaskID"); - dp.packUUID(mItemID, "ItemID"); - dp.packUUID(mAssetID, "AssetID"); - dp.packS32(mAssetType, "AssetType"); -} - - -BOOL LLTransferSourceParamsInvItem::unpackParams(LLDataPacker &dp) -{ - S32 tmp_at; - - dp.unpackUUID(mAgentID, "AgentID"); - dp.unpackUUID(mSessionID, "SessionID"); - dp.unpackUUID(mOwnerID, "OwnerID"); - dp.unpackUUID(mTaskID, "TaskID"); - dp.unpackUUID(mItemID, "ItemID"); - dp.unpackUUID(mAssetID, "AssetID"); - dp.unpackS32(tmp_at, "AssetType"); - - mAssetType = (LLAssetType::EType)tmp_at; - - return TRUE; -} - -LLTransferSourceParamsEstate::LLTransferSourceParamsEstate() : - LLTransferSourceParams(LLTST_SIM_ESTATE), - mEstateAssetType(ET_NONE), - mAssetType(LLAssetType::AT_NONE) -{ -} - -void LLTransferSourceParamsEstate::setAgentSession(const LLUUID &agent_id, const LLUUID &session_id) -{ - mAgentID = agent_id; - mSessionID = session_id; -} - -void LLTransferSourceParamsEstate::setEstateAssetType(const EstateAssetType etype) -{ - mEstateAssetType = etype; -} - -void LLTransferSourceParamsEstate::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type) -{ - mAssetID = asset_id; - mAssetType = asset_type; -} - -void LLTransferSourceParamsEstate::packParams(LLDataPacker &dp) const -{ - dp.packUUID(mAgentID, "AgentID"); - // *NOTE: We do not want to pass the session id from the server to - // the client, but I am not sure if anyone expects this value to - // be set on the client. - dp.packUUID(mSessionID, "SessionID"); - dp.packS32(mEstateAssetType, "EstateAssetType"); -} - - -BOOL LLTransferSourceParamsEstate::unpackParams(LLDataPacker &dp) -{ - S32 tmp_et; - - dp.unpackUUID(mAgentID, "AgentID"); - dp.unpackUUID(mSessionID, "SessionID"); - dp.unpackS32(tmp_et, "EstateAssetType"); - - mEstateAssetType = (EstateAssetType)tmp_et; - - return TRUE; -} +/**
+ * @file lltransfermanager.cpp
+ * @brief Improved transfer mechanism for moving data through the
+ * message system.
+ *
+ * $LicenseInfo:firstyear=2004&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$
+ */
+
+#include "linden_common.h"
+
+#include "lltransfermanager.h"
+
+#include "llerror.h"
+#include "message.h"
+#include "lldatapacker.h"
+
+#include "lltransfersourcefile.h"
+#include "lltransfersourceasset.h"
+#include "lltransfertargetfile.h"
+#include "lltransfertargetvfile.h"
+
+const S32 MAX_PACKET_DATA_SIZE = 2048;
+const S32 MAX_PARAMS_SIZE = 1024;
+
+LLTransferManager gTransferManager;
+LLTransferSource::stype_scfunc_map LLTransferSource::sSourceCreateMap;
+
+//
+// LLTransferManager implementation
+//
+
+LLTransferManager::LLTransferManager() :
+ mValid(false)
+{
+ S32 i;
+ for (i = 0; i < LLTTT_NUM_TYPES; i++)
+ {
+ mTransferBitsIn[i] = 0;
+ mTransferBitsOut[i] = 0;
+ }
+}
+
+
+LLTransferManager::~LLTransferManager()
+{
+ // LLTransferManager should have been cleaned up by message system shutdown process
+ llassert(!mValid);
+ if (mValid)
+ {
+ // Usually happens if OS tries to kill viewer
+ cleanup();
+ }
+}
+
+
+void LLTransferManager::init()
+{
+ if (mValid)
+ {
+ LL_ERRS() << "Double initializing LLTransferManager!" << LL_ENDL;
+ }
+ mValid = true;
+
+ // Register message system handlers
+ gMessageSystem->setHandlerFunc("TransferRequest", processTransferRequest, NULL);
+ gMessageSystem->setHandlerFunc("TransferInfo", processTransferInfo, NULL);
+ gMessageSystem->setHandlerFunc("TransferPacket", processTransferPacket, NULL);
+ gMessageSystem->setHandlerFunc("TransferAbort", processTransferAbort, NULL);
+}
+
+
+void LLTransferManager::cleanup()
+{
+ mValid = false;
+
+ host_tc_map::iterator iter;
+ for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++)
+ {
+ delete iter->second;
+ }
+ mTransferConnections.clear();
+}
+
+
+void LLTransferManager::updateTransfers()
+{
+ host_tc_map::iterator iter,cur;
+
+ iter = mTransferConnections.begin();
+
+ while (iter !=mTransferConnections.end())
+ {
+ cur = iter;
+ iter++;
+ cur->second->updateTransfers();
+ }
+}
+
+
+void LLTransferManager::cleanupConnection(const LLHost &host)
+{
+ host_tc_map::iterator iter;
+ iter = mTransferConnections.find(host);
+ if (iter == mTransferConnections.end())
+ {
+ // This can happen legitimately if we've never done a transfer, and we're
+ // cleaning up a circuit.
+ //LL_WARNS() << "Cleaning up nonexistent transfer connection to " << host << LL_ENDL;
+ return;
+ }
+ LLTransferConnection *connp = iter->second;
+ delete connp;
+ mTransferConnections.erase(iter);
+}
+
+
+LLTransferConnection *LLTransferManager::getTransferConnection(const LLHost &host)
+{
+ host_tc_map::iterator iter;
+ iter = mTransferConnections.find(host);
+ if (iter == mTransferConnections.end())
+ {
+ mTransferConnections[host] = new LLTransferConnection(host);
+ return mTransferConnections[host];
+ }
+
+ return iter->second;
+}
+
+
+LLTransferSourceChannel *LLTransferManager::getSourceChannel(const LLHost &host, const LLTransferChannelType type)
+{
+ LLTransferConnection *tcp = getTransferConnection(host);
+ if (!tcp)
+ {
+ return NULL;
+ }
+ return tcp->getSourceChannel(type);
+}
+
+
+
+LLTransferTargetChannel *LLTransferManager::getTargetChannel(const LLHost &host, const LLTransferChannelType type)
+{
+ LLTransferConnection *tcp = getTransferConnection(host);
+ if (!tcp)
+ {
+ return NULL;
+ }
+ return tcp->getTargetChannel(type);
+}
+
+// virtual
+LLTransferSourceParams::~LLTransferSourceParams()
+{ }
+
+
+LLTransferSource *LLTransferManager::findTransferSource(const LLUUID &transfer_id)
+{
+ // This linear traversal could screw us later if we do lots of
+ // searches for sources. However, this ONLY happens right now
+ // in asset transfer callbacks, so this should be relatively quick.
+ host_tc_map::iterator iter;
+ for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++)
+ {
+ LLTransferConnection *tcp = iter->second;
+ LLTransferConnection::tsc_iter sc_iter;
+ for (sc_iter = tcp->mTransferSourceChannels.begin(); sc_iter != tcp->mTransferSourceChannels.end(); sc_iter++)
+ {
+ LLTransferSourceChannel *scp = *sc_iter;
+ LLTransferSource *sourcep = scp->findTransferSource(transfer_id);
+ if (sourcep)
+ {
+ return sourcep;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+//
+// Message handlers
+//
+
+//static
+void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **)
+{
+ //LL_INFOS() << "LLTransferManager::processTransferRequest" << LL_ENDL;
+
+ LLUUID transfer_id;
+ LLTransferSourceType source_type;
+ LLTransferChannelType channel_type;
+ F32 priority;
+
+ msgp->getUUID("TransferInfo", "TransferID", transfer_id);
+ msgp->getS32("TransferInfo", "SourceType", (S32 &)source_type);
+ msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);
+ msgp->getF32("TransferInfo", "Priority", priority);
+
+ LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type);
+
+ if (!tscp)
+ {
+ LL_WARNS() << "Source channel not found" << LL_ENDL;
+ return;
+ }
+
+ if (tscp->findTransferSource(transfer_id))
+ {
+ LL_WARNS() << "Duplicate request for transfer " << transfer_id << ", aborting!" << LL_ENDL;
+ return;
+ }
+
+ S32 size = msgp->getSize("TransferInfo", "Params");
+ if(size > MAX_PARAMS_SIZE)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferRequest params too big."
+ << LL_ENDL;
+ return;
+ }
+
+ //LL_INFOS() << transfer_id << ":" << source_type << ":" << channel_type << ":" << priority << LL_ENDL;
+ LLTransferSource* tsp = LLTransferSource::createSource(
+ source_type,
+ transfer_id,
+ priority);
+ if(!tsp)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferRequest couldn't create"
+ << " transfer source!" << LL_ENDL;
+ return;
+ }
+ U8 tmp[MAX_PARAMS_SIZE];
+ msgp->getBinaryData("TransferInfo", "Params", tmp, size);
+
+ LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE);
+ bool unpack_ok = tsp->unpackParams(dpb);
+ if (!unpack_ok)
+ {
+ // This should only happen if the data is corrupt or
+ // incorrectly packed.
+ // *NOTE: We may want to call abortTransfer().
+ LL_WARNS() << "LLTransferManager::processTransferRequest: bad parameters."
+ << LL_ENDL;
+ delete tsp;
+ return;
+ }
+
+ tscp->addTransferSource(tsp);
+ tsp->initTransfer();
+}
+
+
+//static
+void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **)
+{
+ //LL_INFOS() << "LLTransferManager::processTransferInfo" << LL_ENDL;
+
+ LLUUID transfer_id;
+ LLTransferTargetType target_type;
+ LLTransferChannelType channel_type;
+ LLTSCode status;
+ S32 size;
+
+ msgp->getUUID("TransferInfo", "TransferID", transfer_id);
+ msgp->getS32("TransferInfo", "TargetType", (S32 &)target_type);
+ msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);
+ msgp->getS32("TransferInfo", "Status", (S32 &)status);
+ msgp->getS32("TransferInfo", "Size", size);
+
+ //LL_INFOS() << transfer_id << ":" << target_type<< ":" << channel_type << LL_ENDL;
+ LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
+ if (!ttcp)
+ {
+ LL_WARNS() << "Target channel not found" << LL_ENDL;
+ // Should send a message to abort the transfer.
+ return;
+ }
+
+ LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
+ if (!ttp)
+ {
+ LL_WARNS() << "TransferInfo for unknown transfer! Not able to handle this yet!" << LL_ENDL;
+ // This could happen if we're doing a push transfer, although to avoid confusion,
+ // maybe it should be a different message.
+ return;
+ }
+
+ if (status != LLTS_OK)
+ {
+ LL_WARNS() << transfer_id << ": Non-ok status, cleaning up" << LL_ENDL;
+ ttp->completionCallback(status);
+ // Clean up the transfer.
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+
+ // unpack the params
+ S32 params_size = msgp->getSize("TransferInfo", "Params");
+ if(params_size > MAX_PARAMS_SIZE)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferInfo params too big."
+ << LL_ENDL;
+ return;
+ }
+ else if(params_size > 0)
+ {
+ U8 tmp[MAX_PARAMS_SIZE];
+ msgp->getBinaryData("TransferInfo", "Params", tmp, params_size);
+ LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE);
+ if (!ttp->unpackParams(dpb))
+ {
+ // This should only happen if the data is corrupt or
+ // incorrectly packed.
+ LL_WARNS() << "LLTransferManager::processTransferRequest: bad params."
+ << LL_ENDL;
+ ttp->abortTransfer();
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+ }
+
+ //LL_INFOS() << "Receiving " << transfer_id << ", size " << size << " bytes" << LL_ENDL;
+ ttp->setSize(size);
+ ttp->setGotInfo(true);
+
+ // OK, at this point we to handle any delayed transfer packets (which could happen
+ // if this packet was lost)
+
+ // This is a lame cut and paste of code down below. If we change the logic down there,
+ // we HAVE to change the logic up here.
+
+ while (1)
+ {
+ S32 packet_id = 0;
+ U8 tmp_data[MAX_PACKET_DATA_SIZE];
+ // See if we've got any delayed packets
+ packet_id = ttp->getNextPacketID();
+ if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end())
+ {
+ // Perhaps this stuff should be inside a method in LLTransferPacket?
+ // I'm too lazy to do it now, though.
+// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL;
+ LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id];
+
+ // This is somewhat inefficient, but avoids us having to duplicate
+ // code between the off-the-wire and delayed paths.
+ packet_id = packetp->mPacketID;
+ size = packetp->mSize;
+ if (size)
+ {
+ if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data)))
+ {
+ memcpy(tmp_data, packetp->mDatap, size); /*Flawfinder: ignore*/
+ }
+ }
+ status = packetp->mStatus;
+ ttp->mDelayedPacketMap.erase(packet_id);
+ delete packetp;
+ }
+ else
+ {
+ // No matching delayed packet, we're done.
+ break;
+ }
+
+ LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size);
+ if (ret_code == LLTS_OK)
+ {
+ ttp->setLastPacketID(packet_id);
+ }
+
+ if (status != LLTS_OK)
+ {
+ if (status != LLTS_DONE)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferInfo Error in playback!" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "LLTransferManager::processTransferInfo replay FINISHED for " << transfer_id << LL_ENDL;
+ }
+ // This transfer is done, either via error or not.
+ ttp->completionCallback(status);
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+ }
+}
+
+
+//static
+void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **)
+{
+ //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL;
+
+ LLUUID transfer_id;
+ LLTransferChannelType channel_type;
+ S32 packet_id;
+ LLTSCode status;
+ S32 size;
+ msgp->getUUID("TransferData", "TransferID", transfer_id);
+ msgp->getS32("TransferData", "ChannelType", (S32 &)channel_type);
+ msgp->getS32("TransferData", "Packet", packet_id);
+ msgp->getS32("TransferData", "Status", (S32 &)status);
+
+ // Find the transfer associated with this packet.
+ //LL_INFOS() << transfer_id << ":" << channel_type << LL_ENDL;
+ LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
+ if (!ttcp)
+ {
+ LL_WARNS() << "Target channel not found" << LL_ENDL;
+ return;
+ }
+
+ LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
+ if (!ttp)
+ {
+ LL_WARNS() << "Didn't find matching transfer for " << transfer_id
+ << " processing packet " << packet_id
+ << " from " << msgp->getSender() << LL_ENDL;
+ return;
+ }
+
+ size = msgp->getSize("TransferData", "Data");
+
+ S32 msg_bytes = 0;
+ if (msgp->getReceiveCompressedSize())
+ {
+ msg_bytes = msgp->getReceiveCompressedSize();
+ }
+ else
+ {
+ msg_bytes = msgp->getReceiveSize();
+ }
+ gTransferManager.addTransferBitsIn(ttcp->mChannelType, msg_bytes*8);
+
+ if ((size < 0) || (size > MAX_PACKET_DATA_SIZE))
+ {
+ LL_WARNS() << "Invalid transfer packet size " << size << LL_ENDL;
+ return;
+ }
+
+ U8 tmp_data[MAX_PACKET_DATA_SIZE];
+ if (size > 0)
+ {
+ // Only pull the data out if the size is > 0
+ msgp->getBinaryData("TransferData", "Data", tmp_data, size);
+ }
+
+ if ((!ttp->gotInfo()) || (ttp->getNextPacketID() != packet_id))
+ {
+ // Put this on a list of packets to be delivered later.
+ if(!ttp->addDelayedPacket(packet_id, status, tmp_data, size))
+ {
+ // Whoops - failed to add a delayed packet for some reason.
+ LL_WARNS() << "Too many delayed packets processing transfer "
+ << transfer_id << " from " << msgp->getSender() << LL_ENDL;
+ ttp->abortTransfer();
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+#if 0
+ // Spammy!
+ const S32 LL_TRANSFER_WARN_GAP = 10;
+ if(!ttp->gotInfo())
+ {
+ LL_WARNS() << "Got data packet before information in transfer "
+ << transfer_id << " from " << msgp->getSender()
+ << ", got " << packet_id << LL_ENDL;
+ }
+ else if((packet_id - ttp->getNextPacketID()) > LL_TRANSFER_WARN_GAP)
+ {
+ LL_WARNS() << "Out of order packet in transfer " << transfer_id
+ << " from " << msgp->getSender() << ", got " << packet_id
+ << " expecting " << ttp->getNextPacketID() << LL_ENDL;
+ }
+#endif
+ return;
+ }
+
+ // Loop through this until we're done with all delayed packets
+
+ //
+ // NOTE: THERE IS A CUT AND PASTE OF THIS CODE IN THE TRANSFERINFO HANDLER
+ // SO WE CAN PLAY BACK DELAYED PACKETS THERE!!!!!!!!!!!!!!!!!!!!!!!!!
+ //
+ bool done = false;
+ while (!done)
+ {
+ LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size);
+ if (ret_code == LLTS_OK)
+ {
+ ttp->setLastPacketID(packet_id);
+ }
+
+ if (status != LLTS_OK)
+ {
+ if (status != LLTS_DONE)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferPacket Error in transfer!" << LL_ENDL;
+ }
+ else
+ {
+// LL_INFOS() << "LLTransferManager::processTransferPacket done for " << transfer_id << LL_ENDL;
+ }
+ // This transfer is done, either via error or not.
+ ttp->completionCallback(status);
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+
+ // See if we've got any delayed packets
+ packet_id = ttp->getNextPacketID();
+ if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end())
+ {
+ // Perhaps this stuff should be inside a method in LLTransferPacket?
+ // I'm too lazy to do it now, though.
+// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL;
+ LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id];
+
+ // This is somewhat inefficient, but avoids us having to duplicate
+ // code between the off-the-wire and delayed paths.
+ packet_id = packetp->mPacketID;
+ size = packetp->mSize;
+ if (size)
+ {
+ if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data)))
+ {
+ memcpy(tmp_data, packetp->mDatap, size); /*Flawfinder: ignore*/
+ }
+ }
+ status = packetp->mStatus;
+ ttp->mDelayedPacketMap.erase(packet_id);
+ delete packetp;
+ }
+ else
+ {
+ // No matching delayed packet, abort it.
+ done = true;
+ }
+ }
+}
+
+
+//static
+void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **)
+{
+ //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL;
+
+ LLUUID transfer_id;
+ LLTransferChannelType channel_type;
+ msgp->getUUID("TransferInfo", "TransferID", transfer_id);
+ msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);
+
+ // See if it's a target that we're trying to abort
+ // Find the transfer associated with this packet.
+ LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
+ if (ttcp)
+ {
+ LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
+ if (ttp)
+ {
+ ttp->abortTransfer();
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+ }
+
+ // Hmm, not a target. Maybe it's a source.
+ LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type);
+ if (tscp)
+ {
+ LLTransferSource *tsp = tscp->findTransferSource(transfer_id);
+ if (tsp)
+ {
+ tsp->abortTransfer();
+ tscp->deleteTransfer(tsp);
+ return;
+ }
+ }
+
+ LL_WARNS() << "Couldn't find transfer " << transfer_id << " to abort!" << LL_ENDL;
+}
+
+
+//static
+void LLTransferManager::reliablePacketCallback(void **user_data, S32 result)
+{
+ LLUUID *transfer_idp = (LLUUID *)user_data;
+ if (result &&
+ transfer_idp != NULL)
+ {
+ LLTransferSource *tsp = gTransferManager.findTransferSource(*transfer_idp);
+ if (tsp)
+ {
+ LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " due to failed reliable resends!" << LL_ENDL;
+ LLTransferSourceChannel *tscp = tsp->mChannelp;
+ tsp->abortTransfer();
+ tscp->deleteTransfer(tsp);
+ }
+ else
+ {
+ LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " but can't find the LLTransferSource object" << LL_ENDL;
+ }
+ }
+ delete transfer_idp;
+}
+
+//
+// LLTransferConnection implementation
+//
+
+LLTransferConnection::LLTransferConnection(const LLHost &host)
+{
+ mHost = host;
+}
+
+LLTransferConnection::~LLTransferConnection()
+{
+ tsc_iter itersc;
+ for (itersc = mTransferSourceChannels.begin(); itersc != mTransferSourceChannels.end(); itersc++)
+ {
+ delete *itersc;
+ }
+ mTransferSourceChannels.clear();
+
+ ttc_iter itertc;
+ for (itertc = mTransferTargetChannels.begin(); itertc != mTransferTargetChannels.end(); itertc++)
+ {
+ delete *itertc;
+ }
+ mTransferTargetChannels.clear();
+}
+
+
+void LLTransferConnection::updateTransfers()
+{
+ // Do stuff for source transfers (basically, send data out).
+ tsc_iter iter, cur;
+ iter = mTransferSourceChannels.begin();
+
+ while (iter !=mTransferSourceChannels.end())
+ {
+ cur = iter;
+ iter++;
+ (*cur)->updateTransfers();
+ }
+
+ // Do stuff for target transfers
+ // Primarily, we should be aborting transfers that are irredeemably broken
+ // (large packet gaps that don't appear to be getting filled in, most likely)
+ // Probably should NOT be doing timeouts for other things, as new priority scheme
+ // means that a high priority transfer COULD block a transfer for a long time.
+}
+
+
+LLTransferSourceChannel *LLTransferConnection::getSourceChannel(const LLTransferChannelType channel_type)
+{
+ tsc_iter iter;
+ for (iter = mTransferSourceChannels.begin(); iter != mTransferSourceChannels.end(); iter++)
+ {
+ if ((*iter)->getChannelType() == channel_type)
+ {
+ return *iter;
+ }
+ }
+
+ LLTransferSourceChannel *tscp = new LLTransferSourceChannel(channel_type, mHost);
+ mTransferSourceChannels.push_back(tscp);
+ return tscp;
+}
+
+
+LLTransferTargetChannel *LLTransferConnection::getTargetChannel(const LLTransferChannelType channel_type)
+{
+ ttc_iter iter;
+ for (iter = mTransferTargetChannels.begin(); iter != mTransferTargetChannels.end(); iter++)
+ {
+ if ((*iter)->getChannelType() == channel_type)
+ {
+ return *iter;
+ }
+ }
+
+ LLTransferTargetChannel *ttcp = new LLTransferTargetChannel(channel_type, mHost);
+ mTransferTargetChannels.push_back(ttcp);
+ return ttcp;
+}
+
+
+//
+// LLTransferSourceChannel implementation
+//
+
+const S32 DEFAULT_PACKET_SIZE = 1000;
+
+
+LLTransferSourceChannel::LLTransferSourceChannel(const LLTransferChannelType channel_type, const LLHost &host) :
+ mChannelType(channel_type),
+ mHost(host),
+ mTransferSources(LLTransferSource::sSetPriority, LLTransferSource::sGetPriority),
+ mThrottleID(TC_ASSET)
+{
+}
+
+
+LLTransferSourceChannel::~LLTransferSourceChannel()
+{
+ LLPriQueueMap<LLTransferSource*>::pqm_iter iter =
+ mTransferSources.mMap.begin();
+ LLPriQueueMap<LLTransferSource*>::pqm_iter end =
+ mTransferSources.mMap.end();
+ for (; iter != end; ++iter)
+ {
+ // Just kill off all of the transfers
+ (*iter).second->abortTransfer();
+ delete iter->second;
+ }
+ mTransferSources.mMap.clear();
+}
+
+void LLTransferSourceChannel::updatePriority(LLTransferSource *tsp, const F32 priority)
+{
+ mTransferSources.reprioritize(priority, tsp);
+}
+
+void LLTransferSourceChannel::updateTransfers()
+{
+ // Actually, this should do the following:
+ // Decide if we can actually send data.
+ // If so, update priorities so we know who gets to send it.
+ // Send data from the sources, while updating until we've sent our throttle allocation.
+
+ LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(getHost());
+ if (!cdp)
+ {
+ return;
+ }
+
+ if (cdp->isBlocked())
+ {
+ // *NOTE: We need to make sure that the throttle bits
+ // available gets reset.
+
+ // We DON'T want to send any packets if they're blocked, they'll just end up
+ // piling up on the other end.
+ //LL_WARNS() << "Blocking transfers due to blocked circuit for " << getHost() << LL_ENDL;
+ return;
+ }
+
+ const S32 throttle_id = mThrottleID;
+
+ LLThrottleGroup &tg = cdp->getThrottleGroup();
+
+ if (tg.checkOverflow(throttle_id, 0.f))
+ {
+ return;
+ }
+
+ LLPriQueueMap<LLTransferSource *>::pqm_iter iter, next;
+
+ bool done = false;
+ for (iter = mTransferSources.mMap.begin(); (iter != mTransferSources.mMap.end()) && !done;)
+ {
+ //LL_INFOS() << "LLTransferSourceChannel::updateTransfers()" << LL_ENDL;
+ // Do stuff.
+ next = iter;
+ next++;
+
+ LLTransferSource *tsp = iter->second;
+ U8 *datap = NULL;
+ S32 data_size = 0;
+ bool delete_data = false;
+ S32 packet_id = 0;
+ S32 sent_bytes = 0;
+ LLTSCode status = LLTS_OK;
+
+ // Get the packetID for the next packet that we're transferring.
+ packet_id = tsp->getNextPacketID();
+ status = tsp->dataCallback(packet_id, DEFAULT_PACKET_SIZE, &datap, data_size, delete_data);
+
+ if (status == LLTS_SKIP)
+ {
+ // We don't have any data, but we're not done, just go on.
+ // This will presumably be used for streaming or async transfers that
+ // are stalled waiting for data from another source.
+ iter=next;
+ continue;
+ }
+
+ LLUUID *cb_uuid = new LLUUID(tsp->getID());
+ LLUUID transaction_id = tsp->getID();
+
+ // Send the data now, even if it's an error.
+ // The status code will tell the other end what to do.
+ gMessageSystem->newMessage("TransferPacket");
+ gMessageSystem->nextBlock("TransferData");
+ gMessageSystem->addUUID("TransferID", tsp->getID());
+ gMessageSystem->addS32("ChannelType", getChannelType());
+ gMessageSystem->addS32("Packet", packet_id); // HACK! Need to put in a REAL packet id
+ gMessageSystem->addS32("Status", status);
+ gMessageSystem->addBinaryData("Data", datap, data_size);
+ sent_bytes = gMessageSystem->getCurrentSendTotal();
+ gMessageSystem->sendReliable(getHost(), LL_DEFAULT_RELIABLE_RETRIES, true, F32Seconds(0.f),
+ LLTransferManager::reliablePacketCallback, (void**)cb_uuid);
+
+ // Do bookkeeping for the throttle
+ done = tg.throttleOverflow(throttle_id, sent_bytes*8.f);
+ gTransferManager.addTransferBitsOut(mChannelType, sent_bytes*8);
+
+ // Clean up our temporary data.
+ if (delete_data)
+ {
+ delete[] datap;
+ datap = NULL;
+ }
+
+ if (findTransferSource(transaction_id) == NULL)
+ {
+ //Warning! In the case of an aborted transfer, the sendReliable call above calls
+ //AbortTransfer which in turn calls deleteTransfer which means that somewhere way
+ //down the chain our current iter can get invalidated resulting in an infrequent
+ //sim crash. This check gets us to a valid transfer source in this event.
+ iter=next;
+ continue;
+ }
+
+ // Update the packet counter
+ tsp->setLastPacketID(packet_id);
+
+ switch (status)
+ {
+ case LLTS_OK:
+ // We're OK, don't need to do anything. Keep sending data.
+ break;
+ case LLTS_ERROR:
+ LL_WARNS() << "Error in transfer dataCallback!" << LL_ENDL;
+ // fall through
+ case LLTS_DONE:
+ // We need to clean up this transfer source.
+ //LL_INFOS() << "LLTransferSourceChannel::updateTransfers() " << tsp->getID() << " done" << LL_ENDL;
+ tsp->completionCallback(status);
+ delete tsp;
+
+ mTransferSources.mMap.erase(iter);
+ iter = next;
+ break;
+ default:
+ LL_ERRS() << "Unknown transfer error code!" << LL_ENDL;
+ }
+
+ // At this point, we should do priority adjustment (since some transfers like
+ // streaming transfers will adjust priority based on how much they've sent and time,
+ // but I'm not going to bother yet. - djs.
+ }
+}
+
+
+void LLTransferSourceChannel::addTransferSource(LLTransferSource *sourcep)
+{
+ sourcep->mChannelp = this;
+ mTransferSources.push(sourcep->getPriority(), sourcep);
+}
+
+
+LLTransferSource *LLTransferSourceChannel::findTransferSource(const LLUUID &transfer_id)
+{
+ LLPriQueueMap<LLTransferSource *>::pqm_iter iter;
+ for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++)
+ {
+ LLTransferSource *tsp = iter->second;
+ if (tsp->getID() == transfer_id)
+ {
+ return tsp;
+ }
+ }
+ return NULL;
+}
+
+
+void LLTransferSourceChannel::deleteTransfer(LLTransferSource *tsp)
+{
+ if (tsp)
+ {
+ LLPriQueueMap<LLTransferSource *>::pqm_iter iter;
+ for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++)
+ {
+ if (iter->second == tsp)
+ {
+ delete tsp;
+ mTransferSources.mMap.erase(iter);
+ return;
+ }
+ }
+
+ LL_WARNS() << "Unable to find transfer source id "
+ << tsp->getID()
+ << " to delete!"
+ << LL_ENDL;
+ }
+}
+
+
+//
+// LLTransferTargetChannel implementation
+//
+
+LLTransferTargetChannel::LLTransferTargetChannel(const LLTransferChannelType channel_type, const LLHost &host) :
+ mChannelType(channel_type),
+ mHost(host)
+{
+}
+
+LLTransferTargetChannel::~LLTransferTargetChannel()
+{
+ tt_iter iter;
+ for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++)
+ {
+ // Abort all of the current transfers
+ (*iter)->abortTransfer();
+ delete *iter;
+ }
+ mTransferTargets.clear();
+}
+
+
+void LLTransferTargetChannel::requestTransfer(
+ const LLTransferSourceParams& source_params,
+ const LLTransferTargetParams& target_params,
+ const F32 priority)
+{
+ LLUUID id;
+ id.generate();
+ LLTransferTarget* ttp = LLTransferTarget::createTarget(
+ target_params.getType(),
+ id,
+ source_params.getType());
+ if (!ttp)
+ {
+ LL_WARNS() << "LLTransferManager::requestTransfer aborting due to target creation failure!" << LL_ENDL;
+ return;
+ }
+
+ ttp->applyParams(target_params);
+ addTransferTarget(ttp);
+
+ sendTransferRequest(ttp, source_params, priority);
+}
+
+
+void LLTransferTargetChannel::sendTransferRequest(LLTransferTarget *targetp,
+ const LLTransferSourceParams ¶ms,
+ const F32 priority)
+{
+ //
+ // Pack the message with data which explains how to get the source, and
+ // send it off to the source for this channel.
+ //
+ llassert(targetp);
+ llassert(targetp->getChannel() == this);
+
+ gMessageSystem->newMessage("TransferRequest");
+ gMessageSystem->nextBlock("TransferInfo");
+ gMessageSystem->addUUID("TransferID", targetp->getID());
+ gMessageSystem->addS32("SourceType", params.getType());
+ gMessageSystem->addS32("ChannelType", getChannelType());
+ gMessageSystem->addF32("Priority", priority);
+
+ U8 tmp[MAX_PARAMS_SIZE];
+ LLDataPackerBinaryBuffer dp(tmp, MAX_PARAMS_SIZE);
+ params.packParams(dp);
+ S32 len = dp.getCurrentSize();
+ gMessageSystem->addBinaryData("Params", tmp, len);
+
+ gMessageSystem->sendReliable(mHost);
+}
+
+
+void LLTransferTargetChannel::addTransferTarget(LLTransferTarget *targetp)
+{
+ targetp->mChannelp = this;
+ mTransferTargets.push_back(targetp);
+}
+
+
+LLTransferTarget *LLTransferTargetChannel::findTransferTarget(const LLUUID &transfer_id)
+{
+ tt_iter iter;
+ for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++)
+ {
+ LLTransferTarget *ttp = *iter;
+ if (ttp->getID() == transfer_id)
+ {
+ return ttp;
+ }
+ }
+ return NULL;
+}
+
+
+void LLTransferTargetChannel::deleteTransfer(LLTransferTarget *ttp)
+{
+ if (ttp)
+ {
+ tt_iter iter;
+ for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++)
+ {
+ if (*iter == ttp)
+ {
+ delete ttp;
+ mTransferTargets.erase(iter);
+ return;
+ }
+ }
+
+ LL_WARNS() << "Unable to find transfer target id "
+ << ttp->getID()
+ << " to delete!"
+ << LL_ENDL;
+ }
+}
+
+
+//
+// LLTransferSource implementation
+//
+
+LLTransferSource::LLTransferSource(const LLTransferSourceType type,
+ const LLUUID &transfer_id,
+ const F32 priority) :
+ mType(type),
+ mID(transfer_id),
+ mChannelp(NULL),
+ mPriority(priority),
+ mSize(0),
+ mLastPacketID(-1)
+{
+ setPriority(priority);
+}
+
+
+LLTransferSource::~LLTransferSource()
+{
+ // No actual cleanup of the transfer is done here, this is purely for
+ // memory cleanup. The completionCallback is guaranteed to get called
+ // before this happens.
+}
+
+
+void LLTransferSource::sendTransferStatus(LLTSCode status)
+{
+ gMessageSystem->newMessage("TransferInfo");
+ gMessageSystem->nextBlock("TransferInfo");
+ gMessageSystem->addUUID("TransferID", getID());
+ gMessageSystem->addS32("TargetType", LLTTT_UNKNOWN);
+ gMessageSystem->addS32("ChannelType", mChannelp->getChannelType());
+ gMessageSystem->addS32("Status", status);
+ gMessageSystem->addS32("Size", mSize);
+ U8 tmp[MAX_PARAMS_SIZE];
+ LLDataPackerBinaryBuffer dp(tmp, MAX_PARAMS_SIZE);
+ packParams(dp);
+ S32 len = dp.getCurrentSize();
+ gMessageSystem->addBinaryData("Params", tmp, len);
+ gMessageSystem->sendReliable(mChannelp->getHost());
+
+ // Abort if there was as asset system issue.
+ if (status != LLTS_OK)
+ {
+ completionCallback(status);
+ mChannelp->deleteTransfer(this);
+ }
+}
+
+
+// This should never be called directly, the transfer manager is responsible for
+// aborting the transfer from the channel. I might want to rethink this in the
+// future, though.
+void LLTransferSource::abortTransfer()
+{
+ // Send a message down, call the completion callback
+ LL_INFOS() << "LLTransferSource::Aborting transfer " << getID() << " to " << mChannelp->getHost() << LL_ENDL;
+ gMessageSystem->newMessage("TransferAbort");
+ gMessageSystem->nextBlock("TransferInfo");
+ gMessageSystem->addUUID("TransferID", getID());
+ gMessageSystem->addS32("ChannelType", mChannelp->getChannelType());
+ gMessageSystem->sendReliable(mChannelp->getHost());
+
+ completionCallback(LLTS_ABORT);
+}
+
+
+//static
+void LLTransferSource::registerSourceType(const LLTransferSourceType stype, LLTransferSourceCreateFunc func)
+{
+ if (sSourceCreateMap.count(stype))
+ {
+ // Disallow changing what class handles a source type
+ // Unclear when you would want to do this, and whether it would work.
+ LL_ERRS() << "Reregistering source type " << stype << LL_ENDL;
+ }
+ else
+ {
+ sSourceCreateMap[stype] = func;
+ }
+}
+
+//static
+LLTransferSource *LLTransferSource::createSource(const LLTransferSourceType stype,
+ const LLUUID &id,
+ const F32 priority)
+{
+ switch (stype)
+ {
+ // *NOTE: The source file transfer mechanism is highly insecure and could
+ // lead to easy exploitation of a server process.
+ // I have removed all uses of it from the codebase. Phoenix.
+ //
+ //case LLTST_FILE:
+ // return new LLTransferSourceFile(id, priority);
+ case LLTST_ASSET:
+ return new LLTransferSourceAsset(id, priority);
+ default:
+ {
+ if (!sSourceCreateMap.count(stype))
+ {
+ // Use the callback to create the source type if it's not there.
+ LL_WARNS() << "Unknown transfer source type: " << stype << LL_ENDL;
+ return NULL;
+ }
+ return (sSourceCreateMap[stype])(id, priority);
+ }
+ }
+}
+
+
+// static
+void LLTransferSource::sSetPriority(LLTransferSource *&tsp, const F32 priority)
+{
+ tsp->setPriority(priority);
+}
+
+
+// static
+F32 LLTransferSource::sGetPriority(LLTransferSource *&tsp)
+{
+ return tsp->getPriority();
+}
+
+
+//
+// LLTransferPacket implementation
+//
+
+LLTransferPacket::LLTransferPacket(const S32 packet_id, const LLTSCode status, const U8 *datap, const S32 size) :
+ mPacketID(packet_id),
+ mStatus(status),
+ mDatap(NULL),
+ mSize(size)
+{
+ if (size == 0)
+ {
+ return;
+ }
+
+ mDatap = new U8[size];
+ if (mDatap != NULL)
+ {
+ memcpy(mDatap, datap, size); /*Flawfinder: ignore*/
+ }
+}
+
+LLTransferPacket::~LLTransferPacket()
+{
+ delete[] mDatap;
+}
+
+//
+// LLTransferTarget implementation
+//
+
+LLTransferTarget::LLTransferTarget(
+ LLTransferTargetType type,
+ const LLUUID& transfer_id,
+ LLTransferSourceType source_type) :
+ mType(type),
+ mSourceType(source_type),
+ mID(transfer_id),
+ mChannelp(NULL),
+ mGotInfo(false),
+ mSize(0),
+ mLastPacketID(-1)
+{
+}
+
+LLTransferTarget::~LLTransferTarget()
+{
+ // No actual cleanup of the transfer is done here, this is purely for
+ // memory cleanup. The completionCallback is guaranteed to get called
+ // before this happens.
+ tpm_iter iter;
+ for (iter = mDelayedPacketMap.begin(); iter != mDelayedPacketMap.end(); iter++)
+ {
+ delete iter->second;
+ }
+ mDelayedPacketMap.clear();
+}
+
+// This should never be called directly, the transfer manager is responsible for
+// aborting the transfer from the channel. I might want to rethink this in the
+// future, though.
+void LLTransferTarget::abortTransfer()
+{
+ // Send a message up, call the completion callback
+ LL_INFOS() << "LLTransferTarget::Aborting transfer " << getID() << " from " << mChannelp->getHost() << LL_ENDL;
+ gMessageSystem->newMessage("TransferAbort");
+ gMessageSystem->nextBlock("TransferInfo");
+ gMessageSystem->addUUID("TransferID", getID());
+ gMessageSystem->addS32("ChannelType", mChannelp->getChannelType());
+ gMessageSystem->sendReliable(mChannelp->getHost());
+
+ completionCallback(LLTS_ABORT);
+}
+
+bool LLTransferTarget::addDelayedPacket(
+ const S32 packet_id,
+ const LLTSCode status,
+ U8* datap,
+ const S32 size)
+{
+ const transfer_packet_map::size_type LL_MAX_DELAYED_PACKETS = 100;
+ if(mDelayedPacketMap.size() > LL_MAX_DELAYED_PACKETS)
+ {
+ // too many delayed packets
+ return false;
+ }
+
+ LLTransferPacket* tpp = new LLTransferPacket(
+ packet_id,
+ status,
+ datap,
+ size);
+
+#ifdef _DEBUG
+ transfer_packet_map::iterator iter = mDelayedPacketMap.find(packet_id);
+ if (iter != mDelayedPacketMap.end())
+ {
+ if (!(iter->second->mSize == size) && !(iter->second->mDatap == datap))
+ {
+ LL_ERRS() << "Packet ALREADY in delayed packet map!" << LL_ENDL;
+ }
+ }
+#endif
+
+ mDelayedPacketMap[packet_id] = tpp;
+ return true;
+}
+
+
+LLTransferTarget* LLTransferTarget::createTarget(
+ LLTransferTargetType type,
+ const LLUUID& id,
+ LLTransferSourceType source_type)
+{
+ switch (type)
+ {
+ case LLTTT_FILE:
+ return new LLTransferTargetFile(id, source_type);
+ case LLTTT_VFILE:
+ return new LLTransferTargetVFile(id, source_type);
+ default:
+ LL_WARNS() << "Unknown transfer target type: " << type << LL_ENDL;
+ return NULL;
+ }
+}
+
+
+LLTransferSourceParamsInvItem::LLTransferSourceParamsInvItem() : LLTransferSourceParams(LLTST_SIM_INV_ITEM), mAssetType(LLAssetType::AT_NONE)
+{
+}
+
+
+void LLTransferSourceParamsInvItem::setAgentSession(const LLUUID &agent_id, const LLUUID &session_id)
+{
+ mAgentID = agent_id;
+ mSessionID = session_id;
+}
+
+
+void LLTransferSourceParamsInvItem::setInvItem(const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id)
+{
+ mOwnerID = owner_id;
+ mTaskID = task_id;
+ mItemID = item_id;
+}
+
+
+void LLTransferSourceParamsInvItem::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type)
+{
+ mAssetID = asset_id;
+ mAssetType = asset_type;
+}
+
+
+void LLTransferSourceParamsInvItem::packParams(LLDataPacker &dp) const
+{
+ LL_DEBUGS() << "LLTransferSourceParamsInvItem::packParams()" << LL_ENDL;
+ dp.packUUID(mAgentID, "AgentID");
+ dp.packUUID(mSessionID, "SessionID");
+ dp.packUUID(mOwnerID, "OwnerID");
+ dp.packUUID(mTaskID, "TaskID");
+ dp.packUUID(mItemID, "ItemID");
+ dp.packUUID(mAssetID, "AssetID");
+ dp.packS32(mAssetType, "AssetType");
+}
+
+
+bool LLTransferSourceParamsInvItem::unpackParams(LLDataPacker &dp)
+{
+ S32 tmp_at;
+
+ dp.unpackUUID(mAgentID, "AgentID");
+ dp.unpackUUID(mSessionID, "SessionID");
+ dp.unpackUUID(mOwnerID, "OwnerID");
+ dp.unpackUUID(mTaskID, "TaskID");
+ dp.unpackUUID(mItemID, "ItemID");
+ dp.unpackUUID(mAssetID, "AssetID");
+ dp.unpackS32(tmp_at, "AssetType");
+
+ mAssetType = (LLAssetType::EType)tmp_at;
+
+ return true;
+}
+
+LLTransferSourceParamsEstate::LLTransferSourceParamsEstate() :
+ LLTransferSourceParams(LLTST_SIM_ESTATE),
+ mEstateAssetType(ET_NONE),
+ mAssetType(LLAssetType::AT_NONE)
+{
+}
+
+void LLTransferSourceParamsEstate::setAgentSession(const LLUUID &agent_id, const LLUUID &session_id)
+{
+ mAgentID = agent_id;
+ mSessionID = session_id;
+}
+
+void LLTransferSourceParamsEstate::setEstateAssetType(const EstateAssetType etype)
+{
+ mEstateAssetType = etype;
+}
+
+void LLTransferSourceParamsEstate::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type)
+{
+ mAssetID = asset_id;
+ mAssetType = asset_type;
+}
+
+void LLTransferSourceParamsEstate::packParams(LLDataPacker &dp) const
+{
+ dp.packUUID(mAgentID, "AgentID");
+ // *NOTE: We do not want to pass the session id from the server to
+ // the client, but I am not sure if anyone expects this value to
+ // be set on the client.
+ dp.packUUID(mSessionID, "SessionID");
+ dp.packS32(mEstateAssetType, "EstateAssetType");
+}
+
+
+bool LLTransferSourceParamsEstate::unpackParams(LLDataPacker &dp)
+{
+ S32 tmp_et;
+
+ dp.unpackUUID(mAgentID, "AgentID");
+ dp.unpackUUID(mSessionID, "SessionID");
+ dp.unpackS32(tmp_et, "EstateAssetType");
+
+ mEstateAssetType = (EstateAssetType)tmp_et;
+
+ return true;
+}
diff --git a/indra/llmessage/lltransfermanager.h b/indra/llmessage/lltransfermanager.h index 9e42797c31..184ff2563a 100644 --- a/indra/llmessage/lltransfermanager.h +++ b/indra/llmessage/lltransfermanager.h @@ -1,499 +1,499 @@ -/** - * @file lltransfermanager.h - * @brief Improved transfer mechanism for moving data through the - * message system. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#ifndef LL_LLTRANSFERMANAGER_H -#define LL_LLTRANSFERMANAGER_H - -#include <map> -#include <list> - -#include "llhost.h" -#include "lluuid.h" -#include "llthrottle.h" -#include "llpriqueuemap.h" -#include "llassettype.h" - -// -// Definition of the manager class for the new LLXfer replacement. -// Provides prioritized, bandwidth-throttled transport of arbitrary -// binary data between host/circuit combos -// - - -typedef enum e_transfer_channel_type -{ - LLTCT_UNKNOWN = 0, - LLTCT_MISC, - LLTCT_ASSET, - LLTCT_NUM_TYPES -} LLTransferChannelType; - - -typedef enum e_transfer_source_type -{ - LLTST_UNKNOWN = 0, - LLTST_FILE, - LLTST_ASSET, - LLTST_SIM_INV_ITEM, // Simulator specific, may not be handled - LLTST_SIM_ESTATE, // Simulator specific, may not be handled - LLTST_NUM_TYPES -} LLTransferSourceType; - - -typedef enum e_transfer_target_type -{ - LLTTT_UNKNOWN = 0, - LLTTT_FILE, - LLTTT_VFILE, - LLTTT_NUM_TYPES -} LLTransferTargetType; - - -// Errors are negative, expected values are positive. -typedef enum e_status_codes -{ - LLTS_OK = 0, - LLTS_DONE = 1, - LLTS_SKIP = 2, - LLTS_ABORT = 3, - LLTS_ERROR = -1, - LLTS_UNKNOWN_SOURCE = -2, // Equivalent of a 404 - LLTS_INSUFFICIENT_PERMISSIONS = -3 // Not enough permissions -} LLTSCode; - -// Types of requests for estate wide information -typedef enum e_estate_type -{ - ET_Covenant = 0, - ET_NONE = -1 -} EstateAssetType; - -class LLMessageSystem; -class LLDataPacker; - -class LLTransferConnection; -class LLTransferSourceChannel; -class LLTransferTargetChannel; -class LLTransferSourceParams; -class LLTransferTargetParams; -class LLTransferSource; -class LLTransferTarget; - -class LLTransferManager -{ -public: - LLTransferManager(); - virtual ~LLTransferManager(); - - void init(); - void cleanup(); - - void updateTransfers(); // Called per frame to push packets out on the various different channels. - void cleanupConnection(const LLHost &host); - - - LLTransferSourceChannel *getSourceChannel(const LLHost &host, const LLTransferChannelType stype); - LLTransferTargetChannel *getTargetChannel(const LLHost &host, const LLTransferChannelType stype); - - LLTransferSource *findTransferSource(const LLUUID &transfer_id); - - BOOL isValid() const { return mValid; } - - static void processTransferRequest(LLMessageSystem *mesgsys, void **); - static void processTransferInfo(LLMessageSystem *mesgsys, void **); - static void processTransferPacket(LLMessageSystem *mesgsys, void **); - static void processTransferAbort(LLMessageSystem *mesgsys, void **); - - static void reliablePacketCallback(void **, S32 result); - - S32 getTransferBitsIn(const LLTransferChannelType tctype) const { return mTransferBitsIn[tctype]; } - S32 getTransferBitsOut(const LLTransferChannelType tctype) const { return mTransferBitsOut[tctype]; } - void resetTransferBitsIn(const LLTransferChannelType tctype) { mTransferBitsIn[tctype] = 0; } - void resetTransferBitsOut(const LLTransferChannelType tctype) { mTransferBitsOut[tctype] = 0; } - void addTransferBitsIn(const LLTransferChannelType tctype, const S32 bits) { mTransferBitsIn[tctype] += bits; } - void addTransferBitsOut(const LLTransferChannelType tctype, const S32 bits) { mTransferBitsOut[tctype] += bits; } -protected: - LLTransferConnection *getTransferConnection(const LLHost &host); - BOOL removeTransferConnection(const LLHost &host); - -protected: - // Convenient typedefs - typedef std::map<LLHost, LLTransferConnection *> host_tc_map; - - BOOL mValid; - LLHost mHost; - - S32 mTransferBitsIn[LLTTT_NUM_TYPES]; - S32 mTransferBitsOut[LLTTT_NUM_TYPES]; - - // We keep a map between each host and LLTransferConnection. - host_tc_map mTransferConnections; -}; - - -// -// Keeps tracks of all channels to/from a particular host. -// -class LLTransferConnection -{ -public: - LLTransferConnection(const LLHost &host); - virtual ~LLTransferConnection(); - - void updateTransfers(); - - LLTransferSourceChannel *getSourceChannel(const LLTransferChannelType type); - LLTransferTargetChannel *getTargetChannel(const LLTransferChannelType type); - - // Convenient typedefs - typedef std::list<LLTransferSourceChannel *>::iterator tsc_iter; - typedef std::list<LLTransferTargetChannel *>::iterator ttc_iter; - friend class LLTransferManager; -protected: - - LLHost mHost; - std::list<LLTransferSourceChannel *> mTransferSourceChannels; - std::list<LLTransferTargetChannel *> mTransferTargetChannels; - -}; - - -// -// A channel which is pushing data out. -// - -class LLTransferSourceChannel -{ -public: - LLTransferSourceChannel(const LLTransferChannelType channel_type, - const LLHost &host); - virtual ~LLTransferSourceChannel(); - - void updateTransfers(); - - void updatePriority(LLTransferSource *tsp, const F32 priority); - - void addTransferSource(LLTransferSource *sourcep); - LLTransferSource *findTransferSource(const LLUUID &transfer_id); - void deleteTransfer(LLTransferSource *tsp); - - void setThrottleID(const S32 throttle_id) { mThrottleID = throttle_id; } - - LLTransferChannelType getChannelType() const { return mChannelType; } - LLHost getHost() const { return mHost; } - -protected: - typedef std::list<LLTransferSource *>::iterator ts_iter; - - LLTransferChannelType mChannelType; - LLHost mHost; - LLPriQueueMap<LLTransferSource*> mTransferSources; - - // The throttle that this source channel should use - S32 mThrottleID; -}; - - -// -// A channel receiving data from a source. -// -class LLTransferTargetChannel -{ -public: - LLTransferTargetChannel(const LLTransferChannelType channel_type, const LLHost &host); - virtual ~LLTransferTargetChannel(); - - void requestTransfer(const LLTransferSourceParams &source_params, - const LLTransferTargetParams &target_params, - const F32 priority); - - LLTransferTarget *findTransferTarget(const LLUUID &transfer_id); - void deleteTransfer(LLTransferTarget *ttp); - - - LLTransferChannelType getChannelType() const { return mChannelType; } - LLHost getHost() const { return mHost; } - -protected: - void sendTransferRequest(LLTransferTarget *targetp, - const LLTransferSourceParams ¶ms, - const F32 priority); - - void addTransferTarget(LLTransferTarget *targetp); - - friend class LLTransferTarget; - friend class LLTransferManager; -protected: - typedef std::list<LLTransferTarget *>::iterator tt_iter; - - LLTransferChannelType mChannelType; - LLHost mHost; - std::list<LLTransferTarget *> mTransferTargets; -}; - - -class LLTransferSourceParams -{ -public: - LLTransferSourceParams(const LLTransferSourceType type) : mType(type) { } - virtual ~LLTransferSourceParams(); - - virtual void packParams(LLDataPacker &dp) const = 0; - virtual BOOL unpackParams(LLDataPacker &dp) = 0; - - LLTransferSourceType getType() const { return mType; } - -protected: - LLTransferSourceType mType; -}; - - -// -// LLTransferSource is an interface, all transfer sources should be derived from it. -// -typedef LLTransferSource *(*LLTransferSourceCreateFunc)(const LLUUID &id, const F32 priority); - -class LLTransferSource -{ -public: - - LLUUID getID() { return mID; } - - friend class LLTransferManager; - friend class LLTransferSourceChannel; - -protected: - LLTransferSource(const LLTransferSourceType source_type, - const LLUUID &request_id, - const F32 priority); - virtual ~LLTransferSource(); - - void sendTransferStatus(LLTSCode status); // When you've figured out your transfer status, do this - - virtual void initTransfer() = 0; - virtual F32 updatePriority() = 0; - virtual LLTSCode dataCallback(const S32 packet_id, - const S32 max_bytes, - U8 **datap, - S32 &returned_bytes, - BOOL &delete_returned) = 0; - - // The completionCallback is GUARANTEED to be called before the destructor. - virtual void completionCallback(const LLTSCode status) = 0; - - virtual void packParams(LLDataPacker& dp) const = 0; - virtual BOOL unpackParams(LLDataPacker& dp) = 0; - - virtual S32 getNextPacketID() { return mLastPacketID + 1; } - virtual void setLastPacketID(const S32 packet_id) { mLastPacketID = packet_id; } - - - // For now, no self-induced priority changes - F32 getPriority() { return mPriority; } - void setPriority(const F32 pri) { mPriority = pri; } - - virtual void abortTransfer(); // DON'T USE THIS ONE, used internally by LLTransferManager - - static LLTransferSource *createSource(const LLTransferSourceType stype, - const LLUUID &request_id, - const F32 priority); - static void registerSourceType(const LLTransferSourceType stype, LLTransferSourceCreateFunc); - - static void sSetPriority(LLTransferSource *&tsp, const F32 priority); - static F32 sGetPriority(LLTransferSource *&tsp); -protected: - typedef std::map<LLTransferSourceType, LLTransferSourceCreateFunc> stype_scfunc_map; - static stype_scfunc_map sSourceCreateMap; - - LLTransferSourceType mType; - LLUUID mID; - LLTransferSourceChannel *mChannelp; - F32 mPriority; - S32 mSize; - S32 mLastPacketID; -}; - - -class LLTransferTargetParams -{ -public: - LLTransferTargetParams(const LLTransferTargetType type) : mType(type) {} - LLTransferTargetType getType() const { return mType; } -protected: - LLTransferTargetType mType; -}; - - -class LLTransferPacket -{ - // Used for storing a packet that's being delivered later because it's out of order. - // ONLY should be accessed by the following two classes, for now. - friend class LLTransferTarget; - friend class LLTransferManager; - -protected: - - LLTransferPacket(const S32 packet_id, const LLTSCode status, const U8 *datap, const S32 size); - virtual ~LLTransferPacket(); - -protected: - S32 mPacketID; - LLTSCode mStatus; - U8 *mDatap; - S32 mSize; -}; - - -class LLTransferTarget -{ -public: - LLTransferTarget( - LLTransferTargetType target_type, - const LLUUID& transfer_id, - LLTransferSourceType source_type); - virtual ~LLTransferTarget(); - - // Accessors - LLUUID getID() const { return mID; } - LLTransferTargetType getType() const { return mType; } - LLTransferTargetChannel *getChannel() const { return mChannelp; } - LLTransferSourceType getSourceType() const { return mSourceType; } - - // Static functionality - static LLTransferTarget* createTarget( - LLTransferTargetType target_type, - const LLUUID& request_id, - LLTransferSourceType source_type); - - // friends - friend class LLTransferManager; - friend class LLTransferTargetChannel; - -protected: - // Implementation - virtual bool unpackParams(LLDataPacker& dp) = 0; - virtual void applyParams(const LLTransferTargetParams ¶ms) = 0; - virtual LLTSCode dataCallback(const S32 packet_id, U8 *in_datap, const S32 in_size) = 0; - - // The completionCallback is GUARANTEED to be called before the destructor, so all handling - // of errors/aborts should be done here. - virtual void completionCallback(const LLTSCode status) = 0; - - void abortTransfer(); - - virtual S32 getNextPacketID() { return mLastPacketID + 1; } - virtual void setLastPacketID(const S32 packet_id) { mLastPacketID = packet_id; } - void setSize(const S32 size) { mSize = size; } - void setGotInfo(const BOOL got_info) { mGotInfo = got_info; } - BOOL gotInfo() const { return mGotInfo; } - - bool addDelayedPacket( - const S32 packet_id, - const LLTSCode status, - U8* datap, - const S32 size); - -protected: - typedef std::map<S32, LLTransferPacket *> transfer_packet_map; - typedef std::map<S32, LLTransferPacket *>::iterator tpm_iter; - - LLTransferTargetType mType; - LLTransferSourceType mSourceType; - LLUUID mID; - LLTransferTargetChannel *mChannelp; - BOOL mGotInfo; - S32 mSize; - S32 mLastPacketID; - - transfer_packet_map mDelayedPacketMap; // Packets that are waiting because of missing/out of order issues -}; - - -// Hack, here so it's publicly available even though LLTransferSourceInvItem is only available on the simulator -class LLTransferSourceParamsInvItem: public LLTransferSourceParams -{ -public: - LLTransferSourceParamsInvItem(); - virtual ~LLTransferSourceParamsInvItem() {} - /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); - - void setAgentSession(const LLUUID &agent_id, const LLUUID &session_id); - void setInvItem(const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id); - void setAsset(const LLUUID &asset_id, const LLAssetType::EType at); - - LLUUID getAgentID() const { return mAgentID; } - LLUUID getSessionID() const { return mSessionID; } - LLUUID getOwnerID() const { return mOwnerID; } - LLUUID getTaskID() const { return mTaskID; } - LLUUID getItemID() const { return mItemID; } - LLUUID getAssetID() const { return mAssetID; } - LLAssetType::EType getAssetType() const { return mAssetType; } - -protected: - LLUUID mAgentID; - LLUUID mSessionID; - LLUUID mOwnerID; - LLUUID mTaskID; - LLUUID mItemID; - LLUUID mAssetID; - LLAssetType::EType mAssetType; -}; - - -// Hack, here so it's publicly available even though LLTransferSourceEstate is only available on the simulator -class LLTransferSourceParamsEstate: public LLTransferSourceParams -{ -public: - LLTransferSourceParamsEstate(); - virtual ~LLTransferSourceParamsEstate() {} - /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); - - void setAgentSession(const LLUUID &agent_id, const LLUUID &session_id); - void setEstateAssetType(const EstateAssetType etype); - void setAsset(const LLUUID &asset_id, const LLAssetType::EType at); - - LLUUID getAgentID() const { return mAgentID; } - LLUUID getSessionID() const { return mSessionID; } - EstateAssetType getEstateAssetType() const { return mEstateAssetType; } - LLUUID getAssetID() const { return mAssetID; } - LLAssetType::EType getAssetType() const { return mAssetType; } - -protected: - LLUUID mAgentID; - LLUUID mSessionID; - EstateAssetType mEstateAssetType; - // these are set on the sim based on estateinfotype - LLUUID mAssetID; - LLAssetType::EType mAssetType; -}; - - -extern LLTransferManager gTransferManager; - -#endif//LL_LLTRANSFERMANAGER_H +/**
+ * @file lltransfermanager.h
+ * @brief Improved transfer mechanism for moving data through the
+ * message system.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#ifndef LL_LLTRANSFERMANAGER_H
+#define LL_LLTRANSFERMANAGER_H
+
+#include <map>
+#include <list>
+
+#include "llhost.h"
+#include "lluuid.h"
+#include "llthrottle.h"
+#include "llpriqueuemap.h"
+#include "llassettype.h"
+
+//
+// Definition of the manager class for the new LLXfer replacement.
+// Provides prioritized, bandwidth-throttled transport of arbitrary
+// binary data between host/circuit combos
+//
+
+
+typedef enum e_transfer_channel_type
+{
+ LLTCT_UNKNOWN = 0,
+ LLTCT_MISC,
+ LLTCT_ASSET,
+ LLTCT_NUM_TYPES
+} LLTransferChannelType;
+
+
+typedef enum e_transfer_source_type
+{
+ LLTST_UNKNOWN = 0,
+ LLTST_FILE,
+ LLTST_ASSET,
+ LLTST_SIM_INV_ITEM, // Simulator specific, may not be handled
+ LLTST_SIM_ESTATE, // Simulator specific, may not be handled
+ LLTST_NUM_TYPES
+} LLTransferSourceType;
+
+
+typedef enum e_transfer_target_type
+{
+ LLTTT_UNKNOWN = 0,
+ LLTTT_FILE,
+ LLTTT_VFILE,
+ LLTTT_NUM_TYPES
+} LLTransferTargetType;
+
+
+// Errors are negative, expected values are positive.
+typedef enum e_status_codes
+{
+ LLTS_OK = 0,
+ LLTS_DONE = 1,
+ LLTS_SKIP = 2,
+ LLTS_ABORT = 3,
+ LLTS_ERROR = -1,
+ LLTS_UNKNOWN_SOURCE = -2, // Equivalent of a 404
+ LLTS_INSUFFICIENT_PERMISSIONS = -3 // Not enough permissions
+} LLTSCode;
+
+// Types of requests for estate wide information
+typedef enum e_estate_type
+{
+ ET_Covenant = 0,
+ ET_NONE = -1
+} EstateAssetType;
+
+class LLMessageSystem;
+class LLDataPacker;
+
+class LLTransferConnection;
+class LLTransferSourceChannel;
+class LLTransferTargetChannel;
+class LLTransferSourceParams;
+class LLTransferTargetParams;
+class LLTransferSource;
+class LLTransferTarget;
+
+class LLTransferManager
+{
+public:
+ LLTransferManager();
+ virtual ~LLTransferManager();
+
+ void init();
+ void cleanup();
+
+ void updateTransfers(); // Called per frame to push packets out on the various different channels.
+ void cleanupConnection(const LLHost &host);
+
+
+ LLTransferSourceChannel *getSourceChannel(const LLHost &host, const LLTransferChannelType stype);
+ LLTransferTargetChannel *getTargetChannel(const LLHost &host, const LLTransferChannelType stype);
+
+ LLTransferSource *findTransferSource(const LLUUID &transfer_id);
+
+ bool isValid() const { return mValid; }
+
+ static void processTransferRequest(LLMessageSystem *mesgsys, void **);
+ static void processTransferInfo(LLMessageSystem *mesgsys, void **);
+ static void processTransferPacket(LLMessageSystem *mesgsys, void **);
+ static void processTransferAbort(LLMessageSystem *mesgsys, void **);
+
+ static void reliablePacketCallback(void **, S32 result);
+
+ S32 getTransferBitsIn(const LLTransferChannelType tctype) const { return mTransferBitsIn[tctype]; }
+ S32 getTransferBitsOut(const LLTransferChannelType tctype) const { return mTransferBitsOut[tctype]; }
+ void resetTransferBitsIn(const LLTransferChannelType tctype) { mTransferBitsIn[tctype] = 0; }
+ void resetTransferBitsOut(const LLTransferChannelType tctype) { mTransferBitsOut[tctype] = 0; }
+ void addTransferBitsIn(const LLTransferChannelType tctype, const S32 bits) { mTransferBitsIn[tctype] += bits; }
+ void addTransferBitsOut(const LLTransferChannelType tctype, const S32 bits) { mTransferBitsOut[tctype] += bits; }
+protected:
+ LLTransferConnection *getTransferConnection(const LLHost &host);
+ bool removeTransferConnection(const LLHost &host);
+
+protected:
+ // Convenient typedefs
+ typedef std::map<LLHost, LLTransferConnection *> host_tc_map;
+
+ bool mValid;
+ LLHost mHost;
+
+ S32 mTransferBitsIn[LLTTT_NUM_TYPES];
+ S32 mTransferBitsOut[LLTTT_NUM_TYPES];
+
+ // We keep a map between each host and LLTransferConnection.
+ host_tc_map mTransferConnections;
+};
+
+
+//
+// Keeps tracks of all channels to/from a particular host.
+//
+class LLTransferConnection
+{
+public:
+ LLTransferConnection(const LLHost &host);
+ virtual ~LLTransferConnection();
+
+ void updateTransfers();
+
+ LLTransferSourceChannel *getSourceChannel(const LLTransferChannelType type);
+ LLTransferTargetChannel *getTargetChannel(const LLTransferChannelType type);
+
+ // Convenient typedefs
+ typedef std::list<LLTransferSourceChannel *>::iterator tsc_iter;
+ typedef std::list<LLTransferTargetChannel *>::iterator ttc_iter;
+ friend class LLTransferManager;
+protected:
+
+ LLHost mHost;
+ std::list<LLTransferSourceChannel *> mTransferSourceChannels;
+ std::list<LLTransferTargetChannel *> mTransferTargetChannels;
+
+};
+
+
+//
+// A channel which is pushing data out.
+//
+
+class LLTransferSourceChannel
+{
+public:
+ LLTransferSourceChannel(const LLTransferChannelType channel_type,
+ const LLHost &host);
+ virtual ~LLTransferSourceChannel();
+
+ void updateTransfers();
+
+ void updatePriority(LLTransferSource *tsp, const F32 priority);
+
+ void addTransferSource(LLTransferSource *sourcep);
+ LLTransferSource *findTransferSource(const LLUUID &transfer_id);
+ void deleteTransfer(LLTransferSource *tsp);
+
+ void setThrottleID(const S32 throttle_id) { mThrottleID = throttle_id; }
+
+ LLTransferChannelType getChannelType() const { return mChannelType; }
+ LLHost getHost() const { return mHost; }
+
+protected:
+ typedef std::list<LLTransferSource *>::iterator ts_iter;
+
+ LLTransferChannelType mChannelType;
+ LLHost mHost;
+ LLPriQueueMap<LLTransferSource*> mTransferSources;
+
+ // The throttle that this source channel should use
+ S32 mThrottleID;
+};
+
+
+//
+// A channel receiving data from a source.
+//
+class LLTransferTargetChannel
+{
+public:
+ LLTransferTargetChannel(const LLTransferChannelType channel_type, const LLHost &host);
+ virtual ~LLTransferTargetChannel();
+
+ void requestTransfer(const LLTransferSourceParams &source_params,
+ const LLTransferTargetParams &target_params,
+ const F32 priority);
+
+ LLTransferTarget *findTransferTarget(const LLUUID &transfer_id);
+ void deleteTransfer(LLTransferTarget *ttp);
+
+
+ LLTransferChannelType getChannelType() const { return mChannelType; }
+ LLHost getHost() const { return mHost; }
+
+protected:
+ void sendTransferRequest(LLTransferTarget *targetp,
+ const LLTransferSourceParams ¶ms,
+ const F32 priority);
+
+ void addTransferTarget(LLTransferTarget *targetp);
+
+ friend class LLTransferTarget;
+ friend class LLTransferManager;
+protected:
+ typedef std::list<LLTransferTarget *>::iterator tt_iter;
+
+ LLTransferChannelType mChannelType;
+ LLHost mHost;
+ std::list<LLTransferTarget *> mTransferTargets;
+};
+
+
+class LLTransferSourceParams
+{
+public:
+ LLTransferSourceParams(const LLTransferSourceType type) : mType(type) { }
+ virtual ~LLTransferSourceParams();
+
+ virtual void packParams(LLDataPacker &dp) const = 0;
+ virtual bool unpackParams(LLDataPacker &dp) = 0;
+
+ LLTransferSourceType getType() const { return mType; }
+
+protected:
+ LLTransferSourceType mType;
+};
+
+
+//
+// LLTransferSource is an interface, all transfer sources should be derived from it.
+//
+typedef LLTransferSource *(*LLTransferSourceCreateFunc)(const LLUUID &id, const F32 priority);
+
+class LLTransferSource
+{
+public:
+
+ LLUUID getID() { return mID; }
+
+ friend class LLTransferManager;
+ friend class LLTransferSourceChannel;
+
+protected:
+ LLTransferSource(const LLTransferSourceType source_type,
+ const LLUUID &request_id,
+ const F32 priority);
+ virtual ~LLTransferSource();
+
+ void sendTransferStatus(LLTSCode status); // When you've figured out your transfer status, do this
+
+ virtual void initTransfer() = 0;
+ virtual F32 updatePriority() = 0;
+ virtual LLTSCode dataCallback(const S32 packet_id,
+ const S32 max_bytes,
+ U8 **datap,
+ S32 &returned_bytes,
+ bool &delete_returned) = 0;
+
+ // The completionCallback is GUARANTEED to be called before the destructor.
+ virtual void completionCallback(const LLTSCode status) = 0;
+
+ virtual void packParams(LLDataPacker& dp) const = 0;
+ virtual bool unpackParams(LLDataPacker& dp) = 0;
+
+ virtual S32 getNextPacketID() { return mLastPacketID + 1; }
+ virtual void setLastPacketID(const S32 packet_id) { mLastPacketID = packet_id; }
+
+
+ // For now, no self-induced priority changes
+ F32 getPriority() { return mPriority; }
+ void setPriority(const F32 pri) { mPriority = pri; }
+
+ virtual void abortTransfer(); // DON'T USE THIS ONE, used internally by LLTransferManager
+
+ static LLTransferSource *createSource(const LLTransferSourceType stype,
+ const LLUUID &request_id,
+ const F32 priority);
+ static void registerSourceType(const LLTransferSourceType stype, LLTransferSourceCreateFunc);
+
+ static void sSetPriority(LLTransferSource *&tsp, const F32 priority);
+ static F32 sGetPriority(LLTransferSource *&tsp);
+protected:
+ typedef std::map<LLTransferSourceType, LLTransferSourceCreateFunc> stype_scfunc_map;
+ static stype_scfunc_map sSourceCreateMap;
+
+ LLTransferSourceType mType;
+ LLUUID mID;
+ LLTransferSourceChannel *mChannelp;
+ F32 mPriority;
+ S32 mSize;
+ S32 mLastPacketID;
+};
+
+
+class LLTransferTargetParams
+{
+public:
+ LLTransferTargetParams(const LLTransferTargetType type) : mType(type) {}
+ LLTransferTargetType getType() const { return mType; }
+protected:
+ LLTransferTargetType mType;
+};
+
+
+class LLTransferPacket
+{
+ // Used for storing a packet that's being delivered later because it's out of order.
+ // ONLY should be accessed by the following two classes, for now.
+ friend class LLTransferTarget;
+ friend class LLTransferManager;
+
+protected:
+
+ LLTransferPacket(const S32 packet_id, const LLTSCode status, const U8 *datap, const S32 size);
+ virtual ~LLTransferPacket();
+
+protected:
+ S32 mPacketID;
+ LLTSCode mStatus;
+ U8 *mDatap;
+ S32 mSize;
+};
+
+
+class LLTransferTarget
+{
+public:
+ LLTransferTarget(
+ LLTransferTargetType target_type,
+ const LLUUID& transfer_id,
+ LLTransferSourceType source_type);
+ virtual ~LLTransferTarget();
+
+ // Accessors
+ LLUUID getID() const { return mID; }
+ LLTransferTargetType getType() const { return mType; }
+ LLTransferTargetChannel *getChannel() const { return mChannelp; }
+ LLTransferSourceType getSourceType() const { return mSourceType; }
+
+ // Static functionality
+ static LLTransferTarget* createTarget(
+ LLTransferTargetType target_type,
+ const LLUUID& request_id,
+ LLTransferSourceType source_type);
+
+ // friends
+ friend class LLTransferManager;
+ friend class LLTransferTargetChannel;
+
+protected:
+ // Implementation
+ virtual bool unpackParams(LLDataPacker& dp) = 0;
+ virtual void applyParams(const LLTransferTargetParams ¶ms) = 0;
+ virtual LLTSCode dataCallback(const S32 packet_id, U8 *in_datap, const S32 in_size) = 0;
+
+ // The completionCallback is GUARANTEED to be called before the destructor, so all handling
+ // of errors/aborts should be done here.
+ virtual void completionCallback(const LLTSCode status) = 0;
+
+ void abortTransfer();
+
+ virtual S32 getNextPacketID() { return mLastPacketID + 1; }
+ virtual void setLastPacketID(const S32 packet_id) { mLastPacketID = packet_id; }
+ void setSize(const S32 size) { mSize = size; }
+ void setGotInfo(const bool got_info) { mGotInfo = got_info; }
+ bool gotInfo() const { return mGotInfo; }
+
+ bool addDelayedPacket(
+ const S32 packet_id,
+ const LLTSCode status,
+ U8* datap,
+ const S32 size);
+
+protected:
+ typedef std::map<S32, LLTransferPacket *> transfer_packet_map;
+ typedef std::map<S32, LLTransferPacket *>::iterator tpm_iter;
+
+ LLTransferTargetType mType;
+ LLTransferSourceType mSourceType;
+ LLUUID mID;
+ LLTransferTargetChannel *mChannelp;
+ bool mGotInfo;
+ S32 mSize;
+ S32 mLastPacketID;
+
+ transfer_packet_map mDelayedPacketMap; // Packets that are waiting because of missing/out of order issues
+};
+
+
+// Hack, here so it's publicly available even though LLTransferSourceInvItem is only available on the simulator
+class LLTransferSourceParamsInvItem: public LLTransferSourceParams
+{
+public:
+ LLTransferSourceParamsInvItem();
+ virtual ~LLTransferSourceParamsInvItem() {}
+ /*virtual*/ void packParams(LLDataPacker &dp) const;
+ /*virtual*/ bool unpackParams(LLDataPacker &dp);
+
+ void setAgentSession(const LLUUID &agent_id, const LLUUID &session_id);
+ void setInvItem(const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id);
+ void setAsset(const LLUUID &asset_id, const LLAssetType::EType at);
+
+ LLUUID getAgentID() const { return mAgentID; }
+ LLUUID getSessionID() const { return mSessionID; }
+ LLUUID getOwnerID() const { return mOwnerID; }
+ LLUUID getTaskID() const { return mTaskID; }
+ LLUUID getItemID() const { return mItemID; }
+ LLUUID getAssetID() const { return mAssetID; }
+ LLAssetType::EType getAssetType() const { return mAssetType; }
+
+protected:
+ LLUUID mAgentID;
+ LLUUID mSessionID;
+ LLUUID mOwnerID;
+ LLUUID mTaskID;
+ LLUUID mItemID;
+ LLUUID mAssetID;
+ LLAssetType::EType mAssetType;
+};
+
+
+// Hack, here so it's publicly available even though LLTransferSourceEstate is only available on the simulator
+class LLTransferSourceParamsEstate: public LLTransferSourceParams
+{
+public:
+ LLTransferSourceParamsEstate();
+ virtual ~LLTransferSourceParamsEstate() {}
+ /*virtual*/ void packParams(LLDataPacker &dp) const;
+ /*virtual*/ bool unpackParams(LLDataPacker &dp);
+
+ void setAgentSession(const LLUUID &agent_id, const LLUUID &session_id);
+ void setEstateAssetType(const EstateAssetType etype);
+ void setAsset(const LLUUID &asset_id, const LLAssetType::EType at);
+
+ LLUUID getAgentID() const { return mAgentID; }
+ LLUUID getSessionID() const { return mSessionID; }
+ EstateAssetType getEstateAssetType() const { return mEstateAssetType; }
+ LLUUID getAssetID() const { return mAssetID; }
+ LLAssetType::EType getAssetType() const { return mAssetType; }
+
+protected:
+ LLUUID mAgentID;
+ LLUUID mSessionID;
+ EstateAssetType mEstateAssetType;
+ // these are set on the sim based on estateinfotype
+ LLUUID mAssetID;
+ LLAssetType::EType mAssetType;
+};
+
+
+extern LLTransferManager gTransferManager;
+
+#endif//LL_LLTRANSFERMANAGER_H
diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 3ffade9bdc..f09855aacd 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -1,254 +1,254 @@ -/** - * @file lltransfersourceasset.cpp - * @brief Transfer system for sending an asset. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#include "linden_common.h" - -#include "lltransfersourceasset.h" - -#include "llerror.h" -#include "message.h" -#include "lldatapacker.h" -#include "lldir.h" -#include "llfilesystem.h" - -LLTransferSourceAsset::LLTransferSourceAsset(const LLUUID &request_id, const F32 priority) : - LLTransferSource(LLTST_ASSET, request_id, priority), - mGotResponse(FALSE), - mCurPos(0) -{ -} - -LLTransferSourceAsset::~LLTransferSourceAsset() -{ -} - - -void LLTransferSourceAsset::initTransfer() -{ - if (gAssetStorage) - { - // *HACK: asset transfers will only be coming from the viewer - // to the simulator. This is subset of assets we allow to be - // simply pulled straight from the asset system. - LLUUID* tidp; - if(LLAssetType::lookupIsAssetFetchByIDAllowed(mParams.getAssetType())) - { - tidp = new LLUUID(getID()); - gAssetStorage->getAssetData( - mParams.getAssetID(), - mParams.getAssetType(), - LLTransferSourceAsset::responderCallback, - tidp, - FALSE); - } - else - { - LL_WARNS() << "Attempted to request blocked asset " - << mParams.getAssetID() << ":" - << LLAssetType::lookupHumanReadable(mParams.getAssetType()) - << LL_ENDL; - sendTransferStatus(LLTS_ERROR); - } - } - else - { - LL_WARNS() << "Attempted to request asset " << mParams.getAssetID() - << ":" << LLAssetType::lookupHumanReadable(mParams.getAssetType()) - << " without an asset system!" << LL_ENDL; - sendTransferStatus(LLTS_ERROR); - } -} - -F32 LLTransferSourceAsset::updatePriority() -{ - return 0.f; -} - -LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id, - const S32 max_bytes, - U8 **data_handle, - S32 &returned_bytes, - BOOL &delete_returned) -{ - //LL_INFOS() << "LLTransferSourceAsset::dataCallback" << LL_ENDL; - if (!mGotResponse) - { - return LLTS_SKIP; - } - - LLFileSystem vf(mParams.getAssetID(), mParams.getAssetType(), LLFileSystem::READ); - - if (!vf.getSize()) - { - // Something bad happened with the asset request! - return LLTS_ERROR; - } - - if (packet_id != mLastPacketID + 1) - { - LL_ERRS() << "Can't handle out of order file transfer yet!" << LL_ENDL; - } - - // grab a buffer from the right place in the file - if (!vf.seek(mCurPos, 0)) - { - LL_WARNS() << "LLTransferSourceAsset Can't seek to " << mCurPos << " length " << vf.getSize() << LL_ENDL; - LL_WARNS() << "While sending " << mParams.getAssetID() << LL_ENDL; - return LLTS_ERROR; - } - - delete_returned = TRUE; - U8 *tmpp = new U8[max_bytes]; - *data_handle = tmpp; - if (!vf.read(tmpp, max_bytes)) /* Flawfinder: Ignore */ - { - // Read failure, need to deal with it. - delete[] tmpp; - *data_handle = NULL; - returned_bytes = 0; - delete_returned = FALSE; - return LLTS_ERROR; - } - - returned_bytes = vf.getLastBytesRead(); - mCurPos += returned_bytes; - - - if (vf.eof()) - { - if (!returned_bytes) - { - delete[] tmpp; - *data_handle = NULL; - returned_bytes = 0; - delete_returned = FALSE; - } - return LLTS_DONE; - } - - return LLTS_OK; -} - -void LLTransferSourceAsset::completionCallback(const LLTSCode status) -{ - // No matter what happens, all we want to do is close the vfile if - // we've got it open. -} - -void LLTransferSourceAsset::packParams(LLDataPacker& dp) const -{ - //LL_INFOS() << "LLTransferSourceAsset::packParams" << LL_ENDL; - mParams.packParams(dp); -} - -BOOL LLTransferSourceAsset::unpackParams(LLDataPacker &dp) -{ - //LL_INFOS() << "LLTransferSourceAsset::unpackParams" << LL_ENDL; - return mParams.unpackParams(dp); -} - - -void LLTransferSourceAsset::responderCallback(const LLUUID& uuid, LLAssetType::EType type, - void *user_data, S32 result, LLExtStat ext_status ) -{ - LLUUID *tidp = ((LLUUID*) user_data); - LLUUID transfer_id = *(tidp); - delete tidp; - tidp = NULL; - - LLTransferSourceAsset *tsap = (LLTransferSourceAsset *) gTransferManager.findTransferSource(transfer_id); - - if (!tsap) - { - LL_INFOS() << "Aborting transfer " << transfer_id << " callback, transfer source went away" << LL_ENDL; - return; - } - - if (result) - { - LL_INFOS() << "AssetStorage: Error " << gAssetStorage->getErrorString(result) << " downloading uuid " << uuid << LL_ENDL; - } - - LLTSCode status; - - tsap->mGotResponse = TRUE; - if (LL_ERR_NOERR == result) - { - // Everything's OK. - LLFileSystem vf(uuid, type, LLFileSystem::READ); - tsap->mSize = vf.getSize(); - status = LLTS_OK; - } - else - { - // Uh oh, something bad happened when we tried to get this asset! - switch (result) - { - case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE: - status = LLTS_UNKNOWN_SOURCE; - break; - default: - status = LLTS_ERROR; - } - } - - tsap->sendTransferStatus(status); -} - - - -LLTransferSourceParamsAsset::LLTransferSourceParamsAsset() - : LLTransferSourceParams(LLTST_ASSET), - - mAssetType(LLAssetType::AT_NONE) -{ -} - -void LLTransferSourceParamsAsset::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type) -{ - mAssetID = asset_id; - mAssetType = asset_type; -} - -void LLTransferSourceParamsAsset::packParams(LLDataPacker &dp) const -{ - dp.packUUID(mAssetID, "AssetID"); - dp.packS32(mAssetType, "AssetType"); -} - - -BOOL LLTransferSourceParamsAsset::unpackParams(LLDataPacker &dp) -{ - S32 tmp_at; - - dp.unpackUUID(mAssetID, "AssetID"); - dp.unpackS32(tmp_at, "AssetType"); - - mAssetType = (LLAssetType::EType)tmp_at; - - return TRUE; -} - +/**
+ * @file lltransfersourceasset.cpp
+ * @brief Transfer system for sending an asset.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include "linden_common.h"
+
+#include "lltransfersourceasset.h"
+
+#include "llerror.h"
+#include "message.h"
+#include "lldatapacker.h"
+#include "lldir.h"
+#include "llfilesystem.h"
+
+LLTransferSourceAsset::LLTransferSourceAsset(const LLUUID &request_id, const F32 priority) :
+ LLTransferSource(LLTST_ASSET, request_id, priority),
+ mGotResponse(false),
+ mCurPos(0)
+{
+}
+
+LLTransferSourceAsset::~LLTransferSourceAsset()
+{
+}
+
+
+void LLTransferSourceAsset::initTransfer()
+{
+ if (gAssetStorage)
+ {
+ // *HACK: asset transfers will only be coming from the viewer
+ // to the simulator. This is subset of assets we allow to be
+ // simply pulled straight from the asset system.
+ LLUUID* tidp;
+ if(LLAssetType::lookupIsAssetFetchByIDAllowed(mParams.getAssetType()))
+ {
+ tidp = new LLUUID(getID());
+ gAssetStorage->getAssetData(
+ mParams.getAssetID(),
+ mParams.getAssetType(),
+ LLTransferSourceAsset::responderCallback,
+ tidp,
+ false);
+ }
+ else
+ {
+ LL_WARNS() << "Attempted to request blocked asset "
+ << mParams.getAssetID() << ":"
+ << LLAssetType::lookupHumanReadable(mParams.getAssetType())
+ << LL_ENDL;
+ sendTransferStatus(LLTS_ERROR);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Attempted to request asset " << mParams.getAssetID()
+ << ":" << LLAssetType::lookupHumanReadable(mParams.getAssetType())
+ << " without an asset system!" << LL_ENDL;
+ sendTransferStatus(LLTS_ERROR);
+ }
+}
+
+F32 LLTransferSourceAsset::updatePriority()
+{
+ return 0.f;
+}
+
+LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id,
+ const S32 max_bytes,
+ U8 **data_handle,
+ S32 &returned_bytes,
+ bool &delete_returned)
+{
+ //LL_INFOS() << "LLTransferSourceAsset::dataCallback" << LL_ENDL;
+ if (!mGotResponse)
+ {
+ return LLTS_SKIP;
+ }
+
+ LLFileSystem vf(mParams.getAssetID(), mParams.getAssetType(), LLFileSystem::READ);
+
+ if (!vf.getSize())
+ {
+ // Something bad happened with the asset request!
+ return LLTS_ERROR;
+ }
+
+ if (packet_id != mLastPacketID + 1)
+ {
+ LL_ERRS() << "Can't handle out of order file transfer yet!" << LL_ENDL;
+ }
+
+ // grab a buffer from the right place in the file
+ if (!vf.seek(mCurPos, 0))
+ {
+ LL_WARNS() << "LLTransferSourceAsset Can't seek to " << mCurPos << " length " << vf.getSize() << LL_ENDL;
+ LL_WARNS() << "While sending " << mParams.getAssetID() << LL_ENDL;
+ return LLTS_ERROR;
+ }
+
+ delete_returned = true;
+ U8 *tmpp = new U8[max_bytes];
+ *data_handle = tmpp;
+ if (!vf.read(tmpp, max_bytes)) /* Flawfinder: Ignore */
+ {
+ // Read failure, need to deal with it.
+ delete[] tmpp;
+ *data_handle = NULL;
+ returned_bytes = 0;
+ delete_returned = false;
+ return LLTS_ERROR;
+ }
+
+ returned_bytes = vf.getLastBytesRead();
+ mCurPos += returned_bytes;
+
+
+ if (vf.eof())
+ {
+ if (!returned_bytes)
+ {
+ delete[] tmpp;
+ *data_handle = NULL;
+ returned_bytes = 0;
+ delete_returned = false;
+ }
+ return LLTS_DONE;
+ }
+
+ return LLTS_OK;
+}
+
+void LLTransferSourceAsset::completionCallback(const LLTSCode status)
+{
+ // No matter what happens, all we want to do is close the vfile if
+ // we've got it open.
+}
+
+void LLTransferSourceAsset::packParams(LLDataPacker& dp) const
+{
+ //LL_INFOS() << "LLTransferSourceAsset::packParams" << LL_ENDL;
+ mParams.packParams(dp);
+}
+
+bool LLTransferSourceAsset::unpackParams(LLDataPacker &dp)
+{
+ //LL_INFOS() << "LLTransferSourceAsset::unpackParams" << LL_ENDL;
+ return mParams.unpackParams(dp);
+}
+
+
+void LLTransferSourceAsset::responderCallback(const LLUUID& uuid, LLAssetType::EType type,
+ void *user_data, S32 result, LLExtStat ext_status )
+{
+ LLUUID *tidp = ((LLUUID*) user_data);
+ LLUUID transfer_id = *(tidp);
+ delete tidp;
+ tidp = NULL;
+
+ LLTransferSourceAsset *tsap = (LLTransferSourceAsset *) gTransferManager.findTransferSource(transfer_id);
+
+ if (!tsap)
+ {
+ LL_INFOS() << "Aborting transfer " << transfer_id << " callback, transfer source went away" << LL_ENDL;
+ return;
+ }
+
+ if (result)
+ {
+ LL_INFOS() << "AssetStorage: Error " << gAssetStorage->getErrorString(result) << " downloading uuid " << uuid << LL_ENDL;
+ }
+
+ LLTSCode status;
+
+ tsap->mGotResponse = true;
+ if (LL_ERR_NOERR == result)
+ {
+ // Everything's OK.
+ LLFileSystem vf(uuid, type, LLFileSystem::READ);
+ tsap->mSize = vf.getSize();
+ status = LLTS_OK;
+ }
+ else
+ {
+ // Uh oh, something bad happened when we tried to get this asset!
+ switch (result)
+ {
+ case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE:
+ status = LLTS_UNKNOWN_SOURCE;
+ break;
+ default:
+ status = LLTS_ERROR;
+ }
+ }
+
+ tsap->sendTransferStatus(status);
+}
+
+
+
+LLTransferSourceParamsAsset::LLTransferSourceParamsAsset()
+ : LLTransferSourceParams(LLTST_ASSET),
+
+ mAssetType(LLAssetType::AT_NONE)
+{
+}
+
+void LLTransferSourceParamsAsset::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type)
+{
+ mAssetID = asset_id;
+ mAssetType = asset_type;
+}
+
+void LLTransferSourceParamsAsset::packParams(LLDataPacker &dp) const
+{
+ dp.packUUID(mAssetID, "AssetID");
+ dp.packS32(mAssetType, "AssetType");
+}
+
+
+bool LLTransferSourceParamsAsset::unpackParams(LLDataPacker &dp)
+{
+ S32 tmp_at;
+
+ dp.unpackUUID(mAssetID, "AssetID");
+ dp.unpackS32(tmp_at, "AssetType");
+
+ mAssetType = (LLAssetType::EType)tmp_at;
+
+ return true;
+}
+
diff --git a/indra/llmessage/lltransfersourceasset.h b/indra/llmessage/lltransfersourceasset.h index f241a1e4a1..50755d65ad 100644 --- a/indra/llmessage/lltransfersourceasset.h +++ b/indra/llmessage/lltransfersourceasset.h @@ -1,81 +1,81 @@ -/** - * @file lltransfersourceasset.h - * @brief Transfer system for sending an asset. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#ifndef LL_LLTRANSFERSOURCEASSET_H -#define LL_LLTRANSFERSOURCEASSET_H - -#include "lltransfermanager.h" -#include "llassetstorage.h" - -class LLFileSystem; - -class LLTransferSourceParamsAsset : public LLTransferSourceParams -{ -public: - LLTransferSourceParamsAsset(); - virtual ~LLTransferSourceParamsAsset() {} - /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); - - void setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type); - - LLUUID getAssetID() const { return mAssetID; } - LLAssetType::EType getAssetType() const { return mAssetType; } - -protected: - LLUUID mAssetID; - LLAssetType::EType mAssetType; -}; - -class LLTransferSourceAsset : public LLTransferSource -{ -public: - LLTransferSourceAsset(const LLUUID &request_id, const F32 priority); - virtual ~LLTransferSourceAsset(); - - static void responderCallback(const LLUUID& uuid, LLAssetType::EType type, - void *user_data, S32 result, LLExtStat ext_status ); -protected: - /*virtual*/ void initTransfer(); - /*virtual*/ F32 updatePriority(); - /*virtual*/ LLTSCode dataCallback(const S32 packet_id, - const S32 max_bytes, - U8 **datap, - S32 &returned_bytes, - BOOL &delete_returned); - /*virtual*/ void completionCallback(const LLTSCode status); - - virtual void packParams(LLDataPacker& dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); - -protected: - LLTransferSourceParamsAsset mParams; - BOOL mGotResponse; - - S32 mCurPos; -}; - -#endif // LL_LLTRANSFERSOURCEASSET_H +/**
+ * @file lltransfersourceasset.h
+ * @brief Transfer system for sending an asset.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#ifndef LL_LLTRANSFERSOURCEASSET_H
+#define LL_LLTRANSFERSOURCEASSET_H
+
+#include "lltransfermanager.h"
+#include "llassetstorage.h"
+
+class LLFileSystem;
+
+class LLTransferSourceParamsAsset : public LLTransferSourceParams
+{
+public:
+ LLTransferSourceParamsAsset();
+ virtual ~LLTransferSourceParamsAsset() {}
+ /*virtual*/ void packParams(LLDataPacker &dp) const;
+ /*virtual*/ bool unpackParams(LLDataPacker &dp);
+
+ void setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type);
+
+ LLUUID getAssetID() const { return mAssetID; }
+ LLAssetType::EType getAssetType() const { return mAssetType; }
+
+protected:
+ LLUUID mAssetID;
+ LLAssetType::EType mAssetType;
+};
+
+class LLTransferSourceAsset : public LLTransferSource
+{
+public:
+ LLTransferSourceAsset(const LLUUID &request_id, const F32 priority);
+ virtual ~LLTransferSourceAsset();
+
+ static void responderCallback(const LLUUID& uuid, LLAssetType::EType type,
+ void *user_data, S32 result, LLExtStat ext_status );
+protected:
+ /*virtual*/ void initTransfer();
+ /*virtual*/ F32 updatePriority();
+ /*virtual*/ LLTSCode dataCallback(const S32 packet_id,
+ const S32 max_bytes,
+ U8 **datap,
+ S32 &returned_bytes,
+ bool &delete_returned);
+ /*virtual*/ void completionCallback(const LLTSCode status);
+
+ virtual void packParams(LLDataPacker& dp) const;
+ /*virtual*/ bool unpackParams(LLDataPacker &dp);
+
+protected:
+ LLTransferSourceParamsAsset mParams;
+ bool mGotResponse;
+
+ S32 mCurPos;
+};
+
+#endif // LL_LLTRANSFERSOURCEASSET_H
diff --git a/indra/llmessage/lltransfersourcefile.cpp b/indra/llmessage/lltransfersourcefile.cpp index ee0f176b9d..97d5716ca4 100644 --- a/indra/llmessage/lltransfersourcefile.cpp +++ b/indra/llmessage/lltransfersourcefile.cpp @@ -1,174 +1,174 @@ -/** - * @file lltransfersourcefile.cpp - * @brief Transfer system for sending a file. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#include "linden_common.h" - -#include "lltransfersourcefile.h" - -#include "llerror.h" -#include "message.h" -#include "lldatapacker.h" -#include "lldir.h" - -LLTransferSourceFile::LLTransferSourceFile(const LLUUID &request_id, const F32 priority) : - LLTransferSource(LLTST_FILE, request_id, priority), - mFP(NULL) -{ -} - -LLTransferSourceFile::~LLTransferSourceFile() -{ - if (mFP) - { - LL_ERRS() << "Destructor called without the completion callback being called!" << LL_ENDL; - } -} - -void LLTransferSourceFile::initTransfer() -{ - std::string filename = mParams.getFilename(); - std::string delimiter = gDirUtilp->getDirDelimiter(); - - if((filename == ".") - || (filename == "..") - || (filename.find(delimiter[0]) != std::string::npos)) - { - LL_WARNS() << "Attempting to transfer file " << filename << " with path delimiter, aborting!" << LL_ENDL; - - sendTransferStatus(LLTS_ERROR); - return; - } - // Look for the file. - mFP = LLFile::fopen(mParams.getFilename(), "rb"); /* Flawfinder: ignore */ - if (!mFP) - { - sendTransferStatus(LLTS_ERROR); - return; - } - - // Get the size of the file using the hack from - fseek(mFP,0,SEEK_END); - mSize = ftell(mFP); - fseek(mFP,0,SEEK_SET); - - sendTransferStatus(LLTS_OK); -} - -F32 LLTransferSourceFile::updatePriority() -{ - return 0.f; -} - -LLTSCode LLTransferSourceFile::dataCallback(const S32 packet_id, - const S32 max_bytes, - U8 **data_handle, - S32 &returned_bytes, - BOOL &delete_returned) -{ - //LL_INFOS() << "LLTransferSourceFile::dataCallback" << LL_ENDL; - - if (!mFP) - { - LL_ERRS() << "Data callback without file set!" << LL_ENDL; - return LLTS_ERROR; - } - - if (packet_id != mLastPacketID + 1) - { - LL_ERRS() << "Can't handle out of order file transfer yet!" << LL_ENDL; - } - - // Grab up until the max number of bytes from the file. - delete_returned = TRUE; - U8 *tmpp = new U8[max_bytes]; - *data_handle = tmpp; - returned_bytes = (S32)fread(tmpp, 1, max_bytes, mFP); - if (!returned_bytes) - { - delete[] tmpp; - *data_handle = NULL; - returned_bytes = 0; - delete_returned = FALSE; - return LLTS_DONE; - } - - return LLTS_OK; -} - -void LLTransferSourceFile::completionCallback(const LLTSCode status) -{ - // No matter what happens, all we want to do is close the file pointer if - // we've got it open. - if (mFP) - { - fclose(mFP); - mFP = NULL; - - } - // Delete the file iff the filename begins with "TEMP" - if (mParams.getDeleteOnCompletion() && mParams.getFilename().substr(0, 4) == "TEMP") - { - LLFile::remove(mParams.getFilename()); - } -} - -void LLTransferSourceFile::packParams(LLDataPacker& dp) const -{ - //LL_INFOS() << "LLTransferSourceFile::packParams" << LL_ENDL; - mParams.packParams(dp); -} - -BOOL LLTransferSourceFile::unpackParams(LLDataPacker &dp) -{ - //LL_INFOS() << "LLTransferSourceFile::unpackParams" << LL_ENDL; - return mParams.unpackParams(dp); -} - - -LLTransferSourceParamsFile::LLTransferSourceParamsFile() : - LLTransferSourceParams(LLTST_FILE), - mDeleteOnCompletion(FALSE) -{ -} - - -void LLTransferSourceParamsFile::packParams(LLDataPacker &dp) const -{ - dp.packString(mFilename, "Filename"); - dp.packU8((U8)mDeleteOnCompletion, "Delete"); -} - - -BOOL LLTransferSourceParamsFile::unpackParams(LLDataPacker &dp) -{ - dp.unpackString(mFilename, "Filename"); - U8 delete_flag; - dp.unpackU8(delete_flag, "Delete"); - mDeleteOnCompletion = delete_flag; - - LL_INFOS() << "Unpacked filename: " << mFilename << LL_ENDL; - return TRUE; -} +/**
+ * @file lltransfersourcefile.cpp
+ * @brief Transfer system for sending a file.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include "linden_common.h"
+
+#include "lltransfersourcefile.h"
+
+#include "llerror.h"
+#include "message.h"
+#include "lldatapacker.h"
+#include "lldir.h"
+
+LLTransferSourceFile::LLTransferSourceFile(const LLUUID &request_id, const F32 priority) :
+ LLTransferSource(LLTST_FILE, request_id, priority),
+ mFP(NULL)
+{
+}
+
+LLTransferSourceFile::~LLTransferSourceFile()
+{
+ if (mFP)
+ {
+ LL_ERRS() << "Destructor called without the completion callback being called!" << LL_ENDL;
+ }
+}
+
+void LLTransferSourceFile::initTransfer()
+{
+ std::string filename = mParams.getFilename();
+ std::string delimiter = gDirUtilp->getDirDelimiter();
+
+ if((filename == ".")
+ || (filename == "..")
+ || (filename.find(delimiter[0]) != std::string::npos))
+ {
+ LL_WARNS() << "Attempting to transfer file " << filename << " with path delimiter, aborting!" << LL_ENDL;
+
+ sendTransferStatus(LLTS_ERROR);
+ return;
+ }
+ // Look for the file.
+ mFP = LLFile::fopen(mParams.getFilename(), "rb"); /* Flawfinder: ignore */
+ if (!mFP)
+ {
+ sendTransferStatus(LLTS_ERROR);
+ return;
+ }
+
+ // Get the size of the file using the hack from
+ fseek(mFP,0,SEEK_END);
+ mSize = ftell(mFP);
+ fseek(mFP,0,SEEK_SET);
+
+ sendTransferStatus(LLTS_OK);
+}
+
+F32 LLTransferSourceFile::updatePriority()
+{
+ return 0.f;
+}
+
+LLTSCode LLTransferSourceFile::dataCallback(const S32 packet_id,
+ const S32 max_bytes,
+ U8 **data_handle,
+ S32 &returned_bytes,
+ bool &delete_returned)
+{
+ //LL_INFOS() << "LLTransferSourceFile::dataCallback" << LL_ENDL;
+
+ if (!mFP)
+ {
+ LL_ERRS() << "Data callback without file set!" << LL_ENDL;
+ return LLTS_ERROR;
+ }
+
+ if (packet_id != mLastPacketID + 1)
+ {
+ LL_ERRS() << "Can't handle out of order file transfer yet!" << LL_ENDL;
+ }
+
+ // Grab up until the max number of bytes from the file.
+ delete_returned = true;
+ U8 *tmpp = new U8[max_bytes];
+ *data_handle = tmpp;
+ returned_bytes = (S32)fread(tmpp, 1, max_bytes, mFP);
+ if (!returned_bytes)
+ {
+ delete[] tmpp;
+ *data_handle = NULL;
+ returned_bytes = 0;
+ delete_returned = false;
+ return LLTS_DONE;
+ }
+
+ return LLTS_OK;
+}
+
+void LLTransferSourceFile::completionCallback(const LLTSCode status)
+{
+ // No matter what happens, all we want to do is close the file pointer if
+ // we've got it open.
+ if (mFP)
+ {
+ fclose(mFP);
+ mFP = NULL;
+
+ }
+ // Delete the file iff the filename begins with "TEMP"
+ if (mParams.getDeleteOnCompletion() && mParams.getFilename().substr(0, 4) == "TEMP")
+ {
+ LLFile::remove(mParams.getFilename());
+ }
+}
+
+void LLTransferSourceFile::packParams(LLDataPacker& dp) const
+{
+ //LL_INFOS() << "LLTransferSourceFile::packParams" << LL_ENDL;
+ mParams.packParams(dp);
+}
+
+bool LLTransferSourceFile::unpackParams(LLDataPacker &dp)
+{
+ //LL_INFOS() << "LLTransferSourceFile::unpackParams" << LL_ENDL;
+ return mParams.unpackParams(dp);
+}
+
+
+LLTransferSourceParamsFile::LLTransferSourceParamsFile() :
+ LLTransferSourceParams(LLTST_FILE),
+ mDeleteOnCompletion(false)
+{
+}
+
+
+void LLTransferSourceParamsFile::packParams(LLDataPacker &dp) const
+{
+ dp.packString(mFilename, "Filename");
+ dp.packU8((U8)mDeleteOnCompletion, "Delete");
+}
+
+
+bool LLTransferSourceParamsFile::unpackParams(LLDataPacker &dp)
+{
+ dp.unpackString(mFilename, "Filename");
+ U8 delete_flag;
+ dp.unpackU8(delete_flag, "Delete");
+ mDeleteOnCompletion = delete_flag;
+
+ LL_INFOS() << "Unpacked filename: " << mFilename << LL_ENDL;
+ return true;
+}
diff --git a/indra/llmessage/lltransfersourcefile.h b/indra/llmessage/lltransfersourcefile.h index a84e5066e3..3b9cd7231c 100644 --- a/indra/llmessage/lltransfersourcefile.h +++ b/indra/llmessage/lltransfersourcefile.h @@ -1,75 +1,75 @@ -/** - * @file lltransfersourcefile.h - * @brief Transfer system for sending a file. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#ifndef LL_LLTRANSFERSOURCEFILE_H -#define LL_LLTRANSFERSOURCEFILE_H - -#include "lltransfermanager.h" - -class LLTransferSourceParamsFile : public LLTransferSourceParams -{ -public: - LLTransferSourceParamsFile(); - virtual ~LLTransferSourceParamsFile() {} - /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); - - void setFilename(const std::string &filename) { mFilename = filename; } - std::string getFilename() const { return mFilename; } - - void setDeleteOnCompletion(BOOL enabled) { mDeleteOnCompletion = enabled; } - BOOL getDeleteOnCompletion() { return mDeleteOnCompletion; } -protected: - std::string mFilename; - // ONLY DELETE THINGS OFF THE SIM IF THE FILENAME BEGINS IN 'TEMP' - BOOL mDeleteOnCompletion; -}; - -class LLTransferSourceFile : public LLTransferSource -{ -public: - LLTransferSourceFile(const LLUUID &transfer_id, const F32 priority); - virtual ~LLTransferSourceFile(); - -protected: - /*virtual*/ void initTransfer(); - /*virtual*/ F32 updatePriority(); - /*virtual*/ LLTSCode dataCallback(const S32 packet_id, - const S32 max_bytes, - U8 **datap, - S32 &returned_bytes, - BOOL &delete_returned); - /*virtual*/ void completionCallback(const LLTSCode status); - - virtual void packParams(LLDataPacker& dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); - -protected: - LLTransferSourceParamsFile mParams; - LLFILE *mFP; -}; - -#endif // LL_LLTRANSFERSOURCEFILE_H +/**
+ * @file lltransfersourcefile.h
+ * @brief Transfer system for sending a file.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#ifndef LL_LLTRANSFERSOURCEFILE_H
+#define LL_LLTRANSFERSOURCEFILE_H
+
+#include "lltransfermanager.h"
+
+class LLTransferSourceParamsFile : public LLTransferSourceParams
+{
+public:
+ LLTransferSourceParamsFile();
+ virtual ~LLTransferSourceParamsFile() {}
+ /*virtual*/ void packParams(LLDataPacker &dp) const;
+ /*virtual*/ bool unpackParams(LLDataPacker &dp);
+
+ void setFilename(const std::string &filename) { mFilename = filename; }
+ std::string getFilename() const { return mFilename; }
+
+ void setDeleteOnCompletion(bool enabled) { mDeleteOnCompletion = enabled; }
+ bool getDeleteOnCompletion() { return mDeleteOnCompletion; }
+protected:
+ std::string mFilename;
+ // ONLY DELETE THINGS OFF THE SIM IF THE FILENAME BEGINS IN 'TEMP'
+ bool mDeleteOnCompletion;
+};
+
+class LLTransferSourceFile : public LLTransferSource
+{
+public:
+ LLTransferSourceFile(const LLUUID &transfer_id, const F32 priority);
+ virtual ~LLTransferSourceFile();
+
+protected:
+ /*virtual*/ void initTransfer();
+ /*virtual*/ F32 updatePriority();
+ /*virtual*/ LLTSCode dataCallback(const S32 packet_id,
+ const S32 max_bytes,
+ U8 **datap,
+ S32 &returned_bytes,
+ bool &delete_returned);
+ /*virtual*/ void completionCallback(const LLTSCode status);
+
+ virtual void packParams(LLDataPacker& dp) const;
+ /*virtual*/ bool unpackParams(LLDataPacker &dp);
+
+protected:
+ LLTransferSourceParamsFile mParams;
+ LLFILE *mFP;
+};
+
+#endif // LL_LLTRANSFERSOURCEFILE_H
diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp index 53962b6633..dbf377bfa2 100644 --- a/indra/llmessage/lltransfertargetvfile.cpp +++ b/indra/llmessage/lltransfertargetvfile.cpp @@ -1,234 +1,234 @@ -/** - * @file lltransfertargetvfile.cpp - * @brief Transfer system for receiving a vfile. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#include "linden_common.h" - -#include "lltransfertargetvfile.h" - -#include "lldatapacker.h" -#include "llerror.h" -#include "llfilesystem.h" - -//static -void LLTransferTargetVFile::updateQueue(bool shutdown) -{ -} - - -LLTransferTargetParamsVFile::LLTransferTargetParamsVFile() : - LLTransferTargetParams(LLTTT_VFILE), - mAssetType(LLAssetType::AT_NONE), - mCompleteCallback(NULL), - mRequestDatap(NULL), - mErrCode(0) -{ -} - -void LLTransferTargetParamsVFile::setAsset( - const LLUUID& asset_id, - LLAssetType::EType asset_type) -{ - mAssetID = asset_id; - mAssetType = asset_type; -} - -void LLTransferTargetParamsVFile::setCallback(LLTTVFCompleteCallback cb, LLBaseDownloadRequest& request) -{ - mCompleteCallback = cb; - if (mRequestDatap) - { - delete mRequestDatap; - } - mRequestDatap = request.getCopy(); -} - -bool LLTransferTargetParamsVFile::unpackParams(LLDataPacker& dp) -{ - // if the source provided a new key, assign that to the asset id. - if(dp.hasNext()) - { - LLUUID dummy_id; - dp.unpackUUID(dummy_id, "AgentID"); - dp.unpackUUID(dummy_id, "SessionID"); - dp.unpackUUID(dummy_id, "OwnerID"); - dp.unpackUUID(dummy_id, "TaskID"); - dp.unpackUUID(dummy_id, "ItemID"); - dp.unpackUUID(mAssetID, "AssetID"); - S32 dummy_type; - dp.unpackS32(dummy_type, "AssetType"); - } - - // if we never got an asset id, this will always fail. - if(mAssetID.isNull()) - { - return false; - } - return true; -} - - -LLTransferTargetVFile::LLTransferTargetVFile( - const LLUUID& uuid, - LLTransferSourceType src_type) : - LLTransferTarget(LLTTT_VFILE, uuid, src_type), - mNeedsCreate(TRUE) -{ - mTempID.generate(); -} - - -LLTransferTargetVFile::~LLTransferTargetVFile() -{ - if (mParams.mRequestDatap) - { - // TODO: Consider doing it in LLTransferTargetParamsVFile's destructor - delete mParams.mRequestDatap; - mParams.mRequestDatap = NULL; - } -} - - -// virtual -bool LLTransferTargetVFile::unpackParams(LLDataPacker& dp) -{ - if(LLTST_SIM_INV_ITEM == mSourceType) - { - return mParams.unpackParams(dp); - } - return true; -} - -void LLTransferTargetVFile::applyParams(const LLTransferTargetParams ¶ms) -{ - if (params.getType() != mType) - { - LL_WARNS() << "Target parameter type doesn't match!" << LL_ENDL; - return; - } - - mParams = (LLTransferTargetParamsVFile &)params; -} - - -LLTSCode LLTransferTargetVFile::dataCallback(const S32 packet_id, U8 *in_datap, const S32 in_size) -{ - //LL_INFOS() << "LLTransferTargetFile::dataCallback" << LL_ENDL; - //LL_INFOS() << "Packet: " << packet_id << LL_ENDL; - - LLFileSystem vf(mTempID, mParams.getAssetType(), LLFileSystem::APPEND); - if (mNeedsCreate) - { - mNeedsCreate = FALSE; - } - - if (!in_size) - { - return LLTS_OK; - } - - if (!vf.write(in_datap, in_size)) - { - LL_WARNS() << "Failure in LLTransferTargetVFile::dataCallback!" << LL_ENDL; - return LLTS_ERROR; - } - return LLTS_OK; -} - - -void LLTransferTargetVFile::completionCallback(const LLTSCode status) -{ - //LL_INFOS() << "LLTransferTargetVFile::completionCallback" << LL_ENDL; - - if (!gAssetStorage) - { - LL_WARNS() << "Aborting vfile transfer after asset storage shut down!" << LL_ENDL; - return; - } - - // Still need to gracefully handle error conditions. - S32 err_code = 0; - switch (status) - { - case LLTS_DONE: - if (!mNeedsCreate) - { - LLFileSystem file(mTempID, mParams.getAssetType(), LLFileSystem::WRITE); - if (!file.rename(mParams.getAssetID(), mParams.getAssetType())) - { - LL_ERRS() << "LLTransferTargetVFile: rename failed" << LL_ENDL; - } - } - err_code = LL_ERR_NOERR; - LL_DEBUGS() << "LLTransferTargetVFile::completionCallback for " - << mParams.getAssetID() << "," - << LLAssetType::lookup(mParams.getAssetType()) - << " with temp id " << mTempID << LL_ENDL; - break; - case LLTS_ERROR: - case LLTS_ABORT: - case LLTS_UNKNOWN_SOURCE: - default: - { - // We're aborting this transfer, we don't want to keep this file. - LL_WARNS() << "Aborting vfile transfer for " << mParams.getAssetID() << LL_ENDL; - LLFileSystem vf(mTempID, mParams.getAssetType(), LLFileSystem::APPEND); - vf.remove(); - } - break; - } - - switch (status) - { - case LLTS_DONE: - err_code = LL_ERR_NOERR; - break; - case LLTS_UNKNOWN_SOURCE: - err_code = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; - break; - case LLTS_INSUFFICIENT_PERMISSIONS: - err_code = LL_ERR_INSUFFICIENT_PERMISSIONS; - break; - case LLTS_ERROR: - case LLTS_ABORT: - default: - err_code = LL_ERR_ASSET_REQUEST_FAILED; - break; - } - - if (mParams.mRequestDatap) - { - if (mParams.mCompleteCallback) - { - mParams.mCompleteCallback(err_code, - mParams.getAssetID(), - mParams.getAssetType(), - mParams.mRequestDatap, - LLExtStat::NONE); - } - delete mParams.mRequestDatap; - mParams.mRequestDatap = NULL; - } -} +/**
+ * @file lltransfertargetvfile.cpp
+ * @brief Transfer system for receiving a vfile.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include "linden_common.h"
+
+#include "lltransfertargetvfile.h"
+
+#include "lldatapacker.h"
+#include "llerror.h"
+#include "llfilesystem.h"
+
+//static
+void LLTransferTargetVFile::updateQueue(bool shutdown)
+{
+}
+
+
+LLTransferTargetParamsVFile::LLTransferTargetParamsVFile() :
+ LLTransferTargetParams(LLTTT_VFILE),
+ mAssetType(LLAssetType::AT_NONE),
+ mCompleteCallback(NULL),
+ mRequestDatap(NULL),
+ mErrCode(0)
+{
+}
+
+void LLTransferTargetParamsVFile::setAsset(
+ const LLUUID& asset_id,
+ LLAssetType::EType asset_type)
+{
+ mAssetID = asset_id;
+ mAssetType = asset_type;
+}
+
+void LLTransferTargetParamsVFile::setCallback(LLTTVFCompleteCallback cb, LLBaseDownloadRequest& request)
+{
+ mCompleteCallback = cb;
+ if (mRequestDatap)
+ {
+ delete mRequestDatap;
+ }
+ mRequestDatap = request.getCopy();
+}
+
+bool LLTransferTargetParamsVFile::unpackParams(LLDataPacker& dp)
+{
+ // if the source provided a new key, assign that to the asset id.
+ if(dp.hasNext())
+ {
+ LLUUID dummy_id;
+ dp.unpackUUID(dummy_id, "AgentID");
+ dp.unpackUUID(dummy_id, "SessionID");
+ dp.unpackUUID(dummy_id, "OwnerID");
+ dp.unpackUUID(dummy_id, "TaskID");
+ dp.unpackUUID(dummy_id, "ItemID");
+ dp.unpackUUID(mAssetID, "AssetID");
+ S32 dummy_type;
+ dp.unpackS32(dummy_type, "AssetType");
+ }
+
+ // if we never got an asset id, this will always fail.
+ if(mAssetID.isNull())
+ {
+ return false;
+ }
+ return true;
+}
+
+
+LLTransferTargetVFile::LLTransferTargetVFile(
+ const LLUUID& uuid,
+ LLTransferSourceType src_type) :
+ LLTransferTarget(LLTTT_VFILE, uuid, src_type),
+ mNeedsCreate(true)
+{
+ mTempID.generate();
+}
+
+
+LLTransferTargetVFile::~LLTransferTargetVFile()
+{
+ if (mParams.mRequestDatap)
+ {
+ // TODO: Consider doing it in LLTransferTargetParamsVFile's destructor
+ delete mParams.mRequestDatap;
+ mParams.mRequestDatap = NULL;
+ }
+}
+
+
+// virtual
+bool LLTransferTargetVFile::unpackParams(LLDataPacker& dp)
+{
+ if(LLTST_SIM_INV_ITEM == mSourceType)
+ {
+ return mParams.unpackParams(dp);
+ }
+ return true;
+}
+
+void LLTransferTargetVFile::applyParams(const LLTransferTargetParams ¶ms)
+{
+ if (params.getType() != mType)
+ {
+ LL_WARNS() << "Target parameter type doesn't match!" << LL_ENDL;
+ return;
+ }
+
+ mParams = (LLTransferTargetParamsVFile &)params;
+}
+
+
+LLTSCode LLTransferTargetVFile::dataCallback(const S32 packet_id, U8 *in_datap, const S32 in_size)
+{
+ //LL_INFOS() << "LLTransferTargetFile::dataCallback" << LL_ENDL;
+ //LL_INFOS() << "Packet: " << packet_id << LL_ENDL;
+
+ LLFileSystem vf(mTempID, mParams.getAssetType(), LLFileSystem::APPEND);
+ if (mNeedsCreate)
+ {
+ mNeedsCreate = false;
+ }
+
+ if (!in_size)
+ {
+ return LLTS_OK;
+ }
+
+ if (!vf.write(in_datap, in_size))
+ {
+ LL_WARNS() << "Failure in LLTransferTargetVFile::dataCallback!" << LL_ENDL;
+ return LLTS_ERROR;
+ }
+ return LLTS_OK;
+}
+
+
+void LLTransferTargetVFile::completionCallback(const LLTSCode status)
+{
+ //LL_INFOS() << "LLTransferTargetVFile::completionCallback" << LL_ENDL;
+
+ if (!gAssetStorage)
+ {
+ LL_WARNS() << "Aborting vfile transfer after asset storage shut down!" << LL_ENDL;
+ return;
+ }
+
+ // Still need to gracefully handle error conditions.
+ S32 err_code = 0;
+ switch (status)
+ {
+ case LLTS_DONE:
+ if (!mNeedsCreate)
+ {
+ LLFileSystem file(mTempID, mParams.getAssetType(), LLFileSystem::WRITE);
+ if (!file.rename(mParams.getAssetID(), mParams.getAssetType()))
+ {
+ LL_ERRS() << "LLTransferTargetVFile: rename failed" << LL_ENDL;
+ }
+ }
+ err_code = LL_ERR_NOERR;
+ LL_DEBUGS() << "LLTransferTargetVFile::completionCallback for "
+ << mParams.getAssetID() << ","
+ << LLAssetType::lookup(mParams.getAssetType())
+ << " with temp id " << mTempID << LL_ENDL;
+ break;
+ case LLTS_ERROR:
+ case LLTS_ABORT:
+ case LLTS_UNKNOWN_SOURCE:
+ default:
+ {
+ // We're aborting this transfer, we don't want to keep this file.
+ LL_WARNS() << "Aborting vfile transfer for " << mParams.getAssetID() << LL_ENDL;
+ LLFileSystem vf(mTempID, mParams.getAssetType(), LLFileSystem::APPEND);
+ vf.remove();
+ }
+ break;
+ }
+
+ switch (status)
+ {
+ case LLTS_DONE:
+ err_code = LL_ERR_NOERR;
+ break;
+ case LLTS_UNKNOWN_SOURCE:
+ err_code = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
+ break;
+ case LLTS_INSUFFICIENT_PERMISSIONS:
+ err_code = LL_ERR_INSUFFICIENT_PERMISSIONS;
+ break;
+ case LLTS_ERROR:
+ case LLTS_ABORT:
+ default:
+ err_code = LL_ERR_ASSET_REQUEST_FAILED;
+ break;
+ }
+
+ if (mParams.mRequestDatap)
+ {
+ if (mParams.mCompleteCallback)
+ {
+ mParams.mCompleteCallback(err_code,
+ mParams.getAssetID(),
+ mParams.getAssetType(),
+ mParams.mRequestDatap,
+ LLExtStat::NONE);
+ }
+ delete mParams.mRequestDatap;
+ mParams.mRequestDatap = NULL;
+ }
+}
diff --git a/indra/llmessage/lltransfertargetvfile.h b/indra/llmessage/lltransfertargetvfile.h index 83cfd5fc5d..e1d48ce73d 100644 --- a/indra/llmessage/lltransfertargetvfile.h +++ b/indra/llmessage/lltransfertargetvfile.h @@ -1,93 +1,93 @@ -/** - * @file lltransfertargetvfile.h - * @brief Transfer system for receiving a vfile. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#ifndef LL_LLTRANSFERTARGETVFILE_H -#define LL_LLTRANSFERTARGETVFILE_H - -#include "lltransfermanager.h" -#include "llassetstorage.h" -#include "llfilesystem.h" - -class LLFileSystem; - -// Lame, an S32 for now until I figure out the deal with how we want to do -// error codes. -typedef void (*LLTTVFCompleteCallback)( - S32 status, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, LLExtStat ext_status ); - -class LLTransferTargetParamsVFile : public LLTransferTargetParams -{ -public: - LLTransferTargetParamsVFile(); - - void setAsset(const LLUUID& asset_id, LLAssetType::EType asset_type); - void setCallback(LLTTVFCompleteCallback cb, LLBaseDownloadRequest& request); - - LLUUID getAssetID() const { return mAssetID; } - LLAssetType::EType getAssetType() const { return mAssetType; } - - friend class LLTransferTargetVFile; -protected: - bool unpackParams(LLDataPacker& dp); - - LLUUID mAssetID; - LLAssetType::EType mAssetType; - - LLTTVFCompleteCallback mCompleteCallback; - LLBaseDownloadRequest* mRequestDatap; - S32 mErrCode; -}; - - -class LLTransferTargetVFile : public LLTransferTarget -{ -public: - LLTransferTargetVFile(const LLUUID& uuid, LLTransferSourceType src_type); - virtual ~LLTransferTargetVFile(); - - //static void requestTransfer(LLTransferTargetChannel* channelp, - // const char* local_filename, - // const LLTransferSourceParams& source_params, - // LLTTVFCompleteCallback callback); - - static void updateQueue(bool shutdown = false); - -protected: - virtual bool unpackParams(LLDataPacker& dp); - /*virtual*/ void applyParams(const LLTransferTargetParams& params); - /*virtual*/ LLTSCode dataCallback(const S32 packet_id, U8* in_datap, const S32 in_size); - /*virtual*/ void completionCallback(const LLTSCode status); - - LLTransferTargetParamsVFile mParams; - - BOOL mNeedsCreate; - LLUUID mTempID; -}; - -#endif // LL_LLTRANSFERTARGETFILE_H +/**
+ * @file lltransfertargetvfile.h
+ * @brief Transfer system for receiving a vfile.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#ifndef LL_LLTRANSFERTARGETVFILE_H
+#define LL_LLTRANSFERTARGETVFILE_H
+
+#include "lltransfermanager.h"
+#include "llassetstorage.h"
+#include "llfilesystem.h"
+
+class LLFileSystem;
+
+// Lame, an S32 for now until I figure out the deal with how we want to do
+// error codes.
+typedef void (*LLTTVFCompleteCallback)(
+ S32 status,
+ const LLUUID& file_id,
+ LLAssetType::EType file_type,
+ LLBaseDownloadRequest* user_data, LLExtStat ext_status );
+
+class LLTransferTargetParamsVFile : public LLTransferTargetParams
+{
+public:
+ LLTransferTargetParamsVFile();
+
+ void setAsset(const LLUUID& asset_id, LLAssetType::EType asset_type);
+ void setCallback(LLTTVFCompleteCallback cb, LLBaseDownloadRequest& request);
+
+ LLUUID getAssetID() const { return mAssetID; }
+ LLAssetType::EType getAssetType() const { return mAssetType; }
+
+ friend class LLTransferTargetVFile;
+protected:
+ bool unpackParams(LLDataPacker& dp);
+
+ LLUUID mAssetID;
+ LLAssetType::EType mAssetType;
+
+ LLTTVFCompleteCallback mCompleteCallback;
+ LLBaseDownloadRequest* mRequestDatap;
+ S32 mErrCode;
+};
+
+
+class LLTransferTargetVFile : public LLTransferTarget
+{
+public:
+ LLTransferTargetVFile(const LLUUID& uuid, LLTransferSourceType src_type);
+ virtual ~LLTransferTargetVFile();
+
+ //static void requestTransfer(LLTransferTargetChannel* channelp,
+ // const char* local_filename,
+ // const LLTransferSourceParams& source_params,
+ // LLTTVFCompleteCallback callback);
+
+ static void updateQueue(bool shutdown = false);
+
+protected:
+ virtual bool unpackParams(LLDataPacker& dp);
+ /*virtual*/ void applyParams(const LLTransferTargetParams& params);
+ /*virtual*/ LLTSCode dataCallback(const S32 packet_id, U8* in_datap, const S32 in_size);
+ /*virtual*/ void completionCallback(const LLTSCode status);
+
+ LLTransferTargetParamsVFile mParams;
+
+ bool mNeedsCreate;
+ LLUUID mTempID;
+};
+
+#endif // LL_LLTRANSFERTARGETFILE_H
diff --git a/indra/llmessage/lluseroperation.cpp b/indra/llmessage/lluseroperation.cpp index c7c9ccd3bd..f7897f9754 100644 --- a/indra/llmessage/lluseroperation.cpp +++ b/indra/llmessage/lluseroperation.cpp @@ -1,190 +1,190 @@ -/** - * @file lluseroperation.cpp - * @brief LLUserOperation class definition. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#include "linden_common.h" - -#include "lluseroperation.h" - -///---------------------------------------------------------------------------- -/// Local function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- - -LLUserOperationMgr* gUserOperationMgr = NULL; - -///---------------------------------------------------------------------------- -/// Class LLUserOperation -///---------------------------------------------------------------------------- - -LLUserOperation::LLUserOperation(const LLUUID& agent_id) -: mAgentID(agent_id), - mTimer(), - mNoExpire(FALSE) -{ - mTransactionID.generate(); -} - -LLUserOperation::LLUserOperation(const LLUUID& agent_id, - const LLUUID& transaction_id) : - mAgentID(agent_id), - mTransactionID(transaction_id), - mTimer(), - mNoExpire(FALSE) -{ -} - -// protected constructor which is used by base classes that determine -// transaction, agent, et. after construction. -LLUserOperation::LLUserOperation() : - mTimer(), - mNoExpire(FALSE) -{ -} - -LLUserOperation::~LLUserOperation() -{ -} - -void LLUserOperation::SetNoExpireFlag(const BOOL flag) -{ - mNoExpire = flag; -} - -BOOL LLUserOperation::isExpired() -{ - if (!mNoExpire) - { - const F32 EXPIRE_TIME_SECS = 10.f; - return mTimer.getElapsedTimeF32() > EXPIRE_TIME_SECS; - } - return FALSE; -} - -void LLUserOperation::expire() -{ - // by default, do do anything. -} - -///---------------------------------------------------------------------------- -/// Class LLUserOperationMgr -///---------------------------------------------------------------------------- - -LLUserOperationMgr::LLUserOperationMgr() -{ -} - - -LLUserOperationMgr::~LLUserOperationMgr() -{ - if (mUserOperationList.size() > 0) - { - LL_WARNS() << "Exiting with user operations pending." << LL_ENDL; - } -} - - -void LLUserOperationMgr::addOperation(LLUserOperation* op) -{ - if(!op) - { - LL_WARNS() << "Tried to add null op" << LL_ENDL; - return; - } - LLUUID id = op->getTransactionID(); - llassert(mUserOperationList.count(id) == 0); - mUserOperationList[id] = op; -} - - -LLUserOperation* LLUserOperationMgr::findOperation(const LLUUID& tid) -{ - user_operation_list_t::iterator iter = mUserOperationList.find(tid); - if (iter != mUserOperationList.end()) - return iter->second; - else - return NULL; -} - - -BOOL LLUserOperationMgr::deleteOperation(LLUserOperation* op) -{ - size_t rv = 0; - if(op) - { - LLUUID id = op->getTransactionID(); - rv = mUserOperationList.erase(id); - delete op; - op = NULL; - } - return rv ? TRUE : FALSE; -} - -void LLUserOperationMgr::deleteExpiredOperations() -{ - const S32 MAX_OPS_CONSIDERED = 2000; - S32 ops_left = MAX_OPS_CONSIDERED; - LLUserOperation* op = NULL; - user_operation_list_t::iterator it; - if(mLastOperationConsidered.isNull()) - { - it = mUserOperationList.begin(); - } - else - { - it = mUserOperationList.lower_bound(mLastOperationConsidered); - } - while((ops_left--) && (it != mUserOperationList.end())) - { - op = (*it).second; - if(op && op->isExpired()) - { - LL_DEBUGS() << "expiring: " << (*it).first << LL_ENDL; - op->expire(); - mUserOperationList.erase(it++); - delete op; - } - else if(op) - { - ++it; - } - else - { - mUserOperationList.erase(it++); - } - } - if(it != mUserOperationList.end()) - { - mLastOperationConsidered = (*it).first; - } - else - { - mLastOperationConsidered.setNull(); - } -} - - -///---------------------------------------------------------------------------- -/// Local function definitions -///---------------------------------------------------------------------------- +/**
+ * @file lluseroperation.cpp
+ * @brief LLUserOperation class definition.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "linden_common.h"
+
+#include "lluseroperation.h"
+
+///----------------------------------------------------------------------------
+/// Local function declarations, constants, enums, and typedefs
+///----------------------------------------------------------------------------
+
+LLUserOperationMgr* gUserOperationMgr = NULL;
+
+///----------------------------------------------------------------------------
+/// Class LLUserOperation
+///----------------------------------------------------------------------------
+
+LLUserOperation::LLUserOperation(const LLUUID& agent_id)
+: mAgentID(agent_id),
+ mTimer(),
+ mNoExpire(false)
+{
+ mTransactionID.generate();
+}
+
+LLUserOperation::LLUserOperation(const LLUUID& agent_id,
+ const LLUUID& transaction_id) :
+ mAgentID(agent_id),
+ mTransactionID(transaction_id),
+ mTimer(),
+ mNoExpire(false)
+{
+}
+
+// protected constructor which is used by base classes that determine
+// transaction, agent, et. after construction.
+LLUserOperation::LLUserOperation() :
+ mTimer(),
+ mNoExpire(false)
+{
+}
+
+LLUserOperation::~LLUserOperation()
+{
+}
+
+void LLUserOperation::SetNoExpireFlag(const bool flag)
+{
+ mNoExpire = flag;
+}
+
+bool LLUserOperation::isExpired()
+{
+ if (!mNoExpire)
+ {
+ const F32 EXPIRE_TIME_SECS = 10.f;
+ return mTimer.getElapsedTimeF32() > EXPIRE_TIME_SECS;
+ }
+ return false;
+}
+
+void LLUserOperation::expire()
+{
+ // by default, do do anything.
+}
+
+///----------------------------------------------------------------------------
+/// Class LLUserOperationMgr
+///----------------------------------------------------------------------------
+
+LLUserOperationMgr::LLUserOperationMgr()
+{
+}
+
+
+LLUserOperationMgr::~LLUserOperationMgr()
+{
+ if (mUserOperationList.size() > 0)
+ {
+ LL_WARNS() << "Exiting with user operations pending." << LL_ENDL;
+ }
+}
+
+
+void LLUserOperationMgr::addOperation(LLUserOperation* op)
+{
+ if(!op)
+ {
+ LL_WARNS() << "Tried to add null op" << LL_ENDL;
+ return;
+ }
+ LLUUID id = op->getTransactionID();
+ llassert(mUserOperationList.count(id) == 0);
+ mUserOperationList[id] = op;
+}
+
+
+LLUserOperation* LLUserOperationMgr::findOperation(const LLUUID& tid)
+{
+ user_operation_list_t::iterator iter = mUserOperationList.find(tid);
+ if (iter != mUserOperationList.end())
+ return iter->second;
+ else
+ return NULL;
+}
+
+
+bool LLUserOperationMgr::deleteOperation(LLUserOperation* op)
+{
+ size_t rv = 0;
+ if(op)
+ {
+ LLUUID id = op->getTransactionID();
+ rv = mUserOperationList.erase(id);
+ delete op;
+ op = NULL;
+ }
+ return rv != 0;
+}
+
+void LLUserOperationMgr::deleteExpiredOperations()
+{
+ const S32 MAX_OPS_CONSIDERED = 2000;
+ S32 ops_left = MAX_OPS_CONSIDERED;
+ LLUserOperation* op = NULL;
+ user_operation_list_t::iterator it;
+ if(mLastOperationConsidered.isNull())
+ {
+ it = mUserOperationList.begin();
+ }
+ else
+ {
+ it = mUserOperationList.lower_bound(mLastOperationConsidered);
+ }
+ while((ops_left--) && (it != mUserOperationList.end()))
+ {
+ op = (*it).second;
+ if(op && op->isExpired())
+ {
+ LL_DEBUGS() << "expiring: " << (*it).first << LL_ENDL;
+ op->expire();
+ mUserOperationList.erase(it++);
+ delete op;
+ }
+ else if(op)
+ {
+ ++it;
+ }
+ else
+ {
+ mUserOperationList.erase(it++);
+ }
+ }
+ if(it != mUserOperationList.end())
+ {
+ mLastOperationConsidered = (*it).first;
+ }
+ else
+ {
+ mLastOperationConsidered.setNull();
+ }
+}
+
+
+///----------------------------------------------------------------------------
+/// Local function definitions
+///----------------------------------------------------------------------------
diff --git a/indra/llmessage/lluseroperation.h b/indra/llmessage/lluseroperation.h index 953e36d7c0..384978571c 100644 --- a/indra/llmessage/lluseroperation.h +++ b/indra/llmessage/lluseroperation.h @@ -1,97 +1,97 @@ -/** - * @file lluseroperation.h - * @brief LLUserOperation class header file - used for message based - * transaction. For example, L$ transactions. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#ifndef LL_LLUSEROPERATION_H -#define LL_LLUSEROPERATION_H - -#include "lluuid.h" -#include "llframetimer.h" - -#include <map> - -class LLUserOperation -{ -public: - LLUserOperation(const LLUUID& agent_id); - LLUserOperation(const LLUUID& agent_id, const LLUUID& transaction_id); - virtual ~LLUserOperation(); - - const LLUUID& getTransactionID() const { return mTransactionID; } - const LLUUID& getAgentID() const { return mAgentID; } - - // Operation never got necessary data, so expired - virtual BOOL isExpired(); - - // ability to mark this operation as never expiring. - void SetNoExpireFlag(const BOOL flag); - - // Send request to the dataserver - virtual void sendRequest() = 0; - - // Run the operation. This will only be called in the case of an - // actual success or failure of the operation. - virtual BOOL execute(BOOL transaction_success) = 0; - - // This method is called when the user op has expired, and is - // about to be deleted by the manager. This gives the user op the - // ability to nack someone when the user op is never evaluated - virtual void expire(); - -protected: - LLUserOperation(); - -protected: - LLUUID mAgentID; - LLUUID mTransactionID; - LLFrameTimer mTimer; - BOOL mNoExpire; // this is used for operations that expect an answer and will wait till it gets one. -}; - - -class LLUserOperationMgr -{ -public: - LLUserOperationMgr(); - ~LLUserOperationMgr(); - - void addOperation(LLUserOperation* op); - LLUserOperation* findOperation(const LLUUID& transaction_id); - BOOL deleteOperation(LLUserOperation* op); - - // Call this method every once in a while to clean up old - // transactions. - void deleteExpiredOperations(); - -private: - typedef std::map<LLUUID, LLUserOperation*> user_operation_list_t; - user_operation_list_t mUserOperationList; - LLUUID mLastOperationConsidered; -}; - -extern LLUserOperationMgr* gUserOperationMgr; - -#endif // LL_LLUSEROPERATION_H +/**
+ * @file lluseroperation.h
+ * @brief LLUserOperation class header file - used for message based
+ * transaction. For example, L$ transactions.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLUSEROPERATION_H
+#define LL_LLUSEROPERATION_H
+
+#include "lluuid.h"
+#include "llframetimer.h"
+
+#include <map>
+
+class LLUserOperation
+{
+public:
+ LLUserOperation(const LLUUID& agent_id);
+ LLUserOperation(const LLUUID& agent_id, const LLUUID& transaction_id);
+ virtual ~LLUserOperation();
+
+ const LLUUID& getTransactionID() const { return mTransactionID; }
+ const LLUUID& getAgentID() const { return mAgentID; }
+
+ // Operation never got necessary data, so expired
+ virtual bool isExpired();
+
+ // ability to mark this operation as never expiring.
+ void SetNoExpireFlag(const bool flag);
+
+ // Send request to the dataserver
+ virtual void sendRequest() = 0;
+
+ // Run the operation. This will only be called in the case of an
+ // actual success or failure of the operation.
+ virtual bool execute(bool transaction_success) = 0;
+
+ // This method is called when the user op has expired, and is
+ // about to be deleted by the manager. This gives the user op the
+ // ability to nack someone when the user op is never evaluated
+ virtual void expire();
+
+protected:
+ LLUserOperation();
+
+protected:
+ LLUUID mAgentID;
+ LLUUID mTransactionID;
+ LLFrameTimer mTimer;
+ bool mNoExpire; // this is used for operations that expect an answer and will wait till it gets one.
+};
+
+
+class LLUserOperationMgr
+{
+public:
+ LLUserOperationMgr();
+ ~LLUserOperationMgr();
+
+ void addOperation(LLUserOperation* op);
+ LLUserOperation* findOperation(const LLUUID& transaction_id);
+ bool deleteOperation(LLUserOperation* op);
+
+ // Call this method every once in a while to clean up old
+ // transactions.
+ void deleteExpiredOperations();
+
+private:
+ typedef std::map<LLUUID, LLUserOperation*> user_operation_list_t;
+ user_operation_list_t mUserOperationList;
+ LLUUID mLastOperationConsidered;
+};
+
+extern LLUserOperationMgr* gUserOperationMgr;
+
+#endif // LL_LLUSEROPERATION_H
diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index ea2309fbba..057f4de0ab 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -1,388 +1,388 @@ -/** - * @file llxfer.cpp - * @brief implementation of LLXfer class for a single xfer. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "llxfer.h" -#include "lluuid.h" -#include "llerror.h" -#include "llmath.h" -#include "u64.h" - -//number of bytes sent in each message -const U32 LL_XFER_CHUNK_SIZE = 1000; - -const U32 LLXfer::XFER_FILE = 1; -const U32 LLXfer::XFER_VFILE = 2; -const U32 LLXfer::XFER_MEM = 3; - -/////////////////////////////////////////////////////////// - -LLXfer::LLXfer (S32 chunk_size) -{ - init(chunk_size); -} - -/////////////////////////////////////////////////////////// - -LLXfer::~LLXfer () -{ - cleanup(); -} - -/////////////////////////////////////////////////////////// - -void LLXfer::init (S32 chunk_size) -{ - mID = 0; - - mPacketNum = -1; // there's a preincrement before sending the zeroth packet - mXferSize = 0; - - mStatus = e_LL_XFER_UNINITIALIZED; - mWaitingForACK = FALSE; - - mCallback = NULL; - mCallbackDataHandle = NULL; - mCallbackResult = 0; - - mBufferContainsEOF = FALSE; - mBuffer = NULL; - mBufferLength = 0; - mBufferStartOffset = 0; - - mRetries = 0; - - if (chunk_size < 1) - { - chunk_size = LL_XFER_CHUNK_SIZE; - } - mChunkSize = chunk_size; -} - -/////////////////////////////////////////////////////////// - -void LLXfer::cleanup () -{ - if (mBuffer) - { - delete[] mBuffer; - mBuffer = NULL; - } -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host) -{ - LL_WARNS("Xfer") << "unexpected call to base class LLXfer::startSend for " << getFileName() << LL_ENDL; - return (-1); -} - -/////////////////////////////////////////////////////////// - -void LLXfer::closeFileHandle() -{ - LL_WARNS("Xfer") << "unexpected call to base class LLXfer::closeFileHandle for " << getFileName() << LL_ENDL; -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer::reopenFileHandle() -{ - LL_WARNS("Xfer") << "unexpected call to base class LLXfer::reopenFileHandle for " << getFileName() << LL_ENDL; - return (-1); -} - -/////////////////////////////////////////////////////////// - -void LLXfer::setXferSize (S32 xfer_size) -{ - mXferSize = xfer_size; -// cout << "starting transfer of size: " << xfer_size << endl; -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer::startDownload() -{ - LL_WARNS("Xfer") << "undifferentiated LLXfer::startDownload for " << getFileName() - << LL_ENDL; - return (-1); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer::receiveData (char *datap, S32 data_size) -{ - S32 retval = 0; - - if (((S32) mBufferLength + data_size) > getMaxBufferSize()) - { // Write existing data to disk if it's larger than the buffer size - retval = flush(); - } - - if (!retval) - { - if (datap != NULL) - { // Append new data to mBuffer - memcpy(&mBuffer[mBufferLength],datap,data_size); /*Flawfinder: ignore*/ - mBufferLength += data_size; - } - else - { - LL_ERRS("Xfer") << "NULL data passed in receiveData" << LL_ENDL; - } - } - - return (retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer::flush() -{ - // only files have somewhere to flush to - // if we get called with a flush it means we've blown past our - // allocated buffer size - - return (-1); -} - - -/////////////////////////////////////////////////////////// - -S32 LLXfer::suck(S32 start_position) -{ - LL_WARNS("Xfer") << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << LL_ENDL; - return (-1); -} - -/////////////////////////////////////////////////////////// - -void LLXfer::sendPacket(S32 packet_num) -{ - char fdata_buf[LL_XFER_LARGE_PAYLOAD+4]; /* Flawfinder: ignore */ - S32 fdata_size = mChunkSize; - BOOL last_packet = FALSE; - S32 num_copy = 0; - - // if the desired packet is not in our current buffered excerpt from the file. . . - if (((U32)packet_num*fdata_size < mBufferStartOffset) - || ((U32)llmin((U32)mXferSize,(U32)((U32)(packet_num+1)*fdata_size)) > mBufferStartOffset + mBufferLength)) - - { - if (suck(packet_num*fdata_size)) // returns non-zero on failure - { - abort(LL_ERR_EOF); - return; - } - } - - S32 desired_read_position = 0; - - desired_read_position = packet_num * fdata_size - mBufferStartOffset; - - fdata_size = llmin((S32)mBufferLength-desired_read_position, mChunkSize); - - if (fdata_size < 0) - { - LL_WARNS("Xfer") << "negative data size in xfer send, aborting" << LL_ENDL; - abort(LL_ERR_EOF); - return; - } - - if (((U32)(desired_read_position + fdata_size) >= (U32)mBufferLength) && (mBufferContainsEOF)) - { - last_packet = TRUE; - } - - if (packet_num) - { - num_copy = llmin(fdata_size, (S32)sizeof(fdata_buf)); - num_copy = llmin(num_copy, (S32)(mBufferLength - desired_read_position)); - if (num_copy > 0) - { - memcpy(fdata_buf,&mBuffer[desired_read_position],num_copy); /*Flawfinder: ignore*/ - } - } - else - { - // if we're the first packet, encode size as an additional S32 - // at start of data. - num_copy = llmin(fdata_size, (S32)(sizeof(fdata_buf)-sizeof(S32))); - num_copy = llmin( - num_copy, - (S32)(mBufferLength - desired_read_position)); - if (num_copy > 0) - { - memcpy( /*Flawfinder: ignore*/ - fdata_buf + sizeof(S32), - &mBuffer[desired_read_position], - num_copy); - } - fdata_size += sizeof(S32); - htolememcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32)); - } - - S32 encoded_packetnum = encodePacketNum(packet_num,last_packet); - - if (fdata_size) - { - // send the packet - gMessageSystem->newMessageFast(_PREHASH_SendXferPacket); - gMessageSystem->nextBlockFast(_PREHASH_XferID); - - gMessageSystem->addU64Fast(_PREHASH_ID, mID); - gMessageSystem->addU32Fast(_PREHASH_Packet, encoded_packetnum); - - gMessageSystem->nextBlockFast(_PREHASH_DataPacket); - gMessageSystem->addBinaryDataFast(_PREHASH_Data, &fdata_buf,fdata_size); - - S32 sent_something = gMessageSystem->sendMessage(mRemoteHost); - if (sent_something == 0) - { - abort(LL_ERR_CIRCUIT_GONE); - return; - } - - ACKTimer.reset(); - mWaitingForACK = TRUE; - } - if (last_packet) - { - mStatus = e_LL_XFER_COMPLETE; - } - else - { - mStatus = e_LL_XFER_IN_PROGRESS; - } -} - -/////////////////////////////////////////////////////////// - -void LLXfer::sendNextPacket() -{ - mRetries = 0; - sendPacket(++mPacketNum); -} - -/////////////////////////////////////////////////////////// - -void LLXfer::resendLastPacket() -{ - mRetries++; - sendPacket(mPacketNum); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer::processEOF() -{ - S32 retval = 0; - - mStatus = e_LL_XFER_COMPLETE; - - if (LL_ERR_NOERR == mCallbackResult) - { - LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " complete: " << getFileName() - << LL_ENDL; - } - else - { - LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " failed, code " - << mCallbackResult << ": " << getFileName() << LL_ENDL; - } - - if (mCallback) - { - mCallback(mCallbackDataHandle,mCallbackResult, LLExtStat::NONE); - } - - return(retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer::encodePacketNum(S32 packet_num, BOOL is_EOF) -{ - if (is_EOF) - { - packet_num |= 0x80000000; - } - return packet_num; -} - -/////////////////////////////////////////////////////////// - -void LLXfer::abort (S32 result_code) -{ - mCallbackResult = result_code; - - LL_INFOS("Xfer") << "Aborting xfer from " << mRemoteHost << " named " << getFileName() - << " - error: " << result_code << LL_ENDL; - - if (result_code != LL_ERR_CIRCUIT_GONE) - { - gMessageSystem->newMessageFast(_PREHASH_AbortXfer); - gMessageSystem->nextBlockFast(_PREHASH_XferID); - gMessageSystem->addU64Fast(_PREHASH_ID, mID); - gMessageSystem->addS32Fast(_PREHASH_Result, result_code); - - gMessageSystem->sendMessage(mRemoteHost); - } - - mStatus = e_LL_XFER_ABORTED; -} - - -/////////////////////////////////////////////////////////// - -std::string LLXfer::getFileName() -{ - return U64_to_str(mID); -} - -/////////////////////////////////////////////////////////// - -U32 LLXfer::getXferTypeTag() -{ - return 0; -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer::getMaxBufferSize () -{ - return(mXferSize); -} - - -std::ostream& operator<< (std::ostream& os, LLXfer &hh) -{ - os << hh.getFileName() ; - return os; -} +/**
+ * @file llxfer.cpp
+ * @brief implementation of LLXfer class for a single xfer.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llxfer.h"
+#include "lluuid.h"
+#include "llerror.h"
+#include "llmath.h"
+#include "u64.h"
+
+//number of bytes sent in each message
+const U32 LL_XFER_CHUNK_SIZE = 1000;
+
+const U32 LLXfer::XFER_FILE = 1;
+const U32 LLXfer::XFER_VFILE = 2;
+const U32 LLXfer::XFER_MEM = 3;
+
+///////////////////////////////////////////////////////////
+
+LLXfer::LLXfer (S32 chunk_size)
+{
+ init(chunk_size);
+}
+
+///////////////////////////////////////////////////////////
+
+LLXfer::~LLXfer ()
+{
+ cleanup();
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer::init (S32 chunk_size)
+{
+ mID = 0;
+
+ mPacketNum = -1; // there's a preincrement before sending the zeroth packet
+ mXferSize = 0;
+
+ mStatus = e_LL_XFER_UNINITIALIZED;
+ mWaitingForACK = false;
+
+ mCallback = NULL;
+ mCallbackDataHandle = NULL;
+ mCallbackResult = 0;
+
+ mBufferContainsEOF = false;
+ mBuffer = NULL;
+ mBufferLength = 0;
+ mBufferStartOffset = 0;
+
+ mRetries = 0;
+
+ if (chunk_size < 1)
+ {
+ chunk_size = LL_XFER_CHUNK_SIZE;
+ }
+ mChunkSize = chunk_size;
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer::cleanup ()
+{
+ if (mBuffer)
+ {
+ delete[] mBuffer;
+ mBuffer = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host)
+{
+ LL_WARNS("Xfer") << "unexpected call to base class LLXfer::startSend for " << getFileName() << LL_ENDL;
+ return (-1);
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer::closeFileHandle()
+{
+ LL_WARNS("Xfer") << "unexpected call to base class LLXfer::closeFileHandle for " << getFileName() << LL_ENDL;
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::reopenFileHandle()
+{
+ LL_WARNS("Xfer") << "unexpected call to base class LLXfer::reopenFileHandle for " << getFileName() << LL_ENDL;
+ return (-1);
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer::setXferSize (S32 xfer_size)
+{
+ mXferSize = xfer_size;
+// cout << "starting transfer of size: " << xfer_size << endl;
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::startDownload()
+{
+ LL_WARNS("Xfer") << "undifferentiated LLXfer::startDownload for " << getFileName()
+ << LL_ENDL;
+ return (-1);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::receiveData (char *datap, S32 data_size)
+{
+ S32 retval = 0;
+
+ if (((S32) mBufferLength + data_size) > getMaxBufferSize())
+ { // Write existing data to disk if it's larger than the buffer size
+ retval = flush();
+ }
+
+ if (!retval)
+ {
+ if (datap != NULL)
+ { // Append new data to mBuffer
+ memcpy(&mBuffer[mBufferLength],datap,data_size); /*Flawfinder: ignore*/
+ mBufferLength += data_size;
+ }
+ else
+ {
+ LL_ERRS("Xfer") << "NULL data passed in receiveData" << LL_ENDL;
+ }
+ }
+
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::flush()
+{
+ // only files have somewhere to flush to
+ // if we get called with a flush it means we've blown past our
+ // allocated buffer size
+
+ return (-1);
+}
+
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::suck(S32 start_position)
+{
+ LL_WARNS("Xfer") << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << LL_ENDL;
+ return (-1);
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer::sendPacket(S32 packet_num)
+{
+ char fdata_buf[LL_XFER_LARGE_PAYLOAD+4]; /* Flawfinder: ignore */
+ S32 fdata_size = mChunkSize;
+ bool last_packet = false;
+ S32 num_copy = 0;
+
+ // if the desired packet is not in our current buffered excerpt from the file. . .
+ if (((U32)packet_num*fdata_size < mBufferStartOffset)
+ || ((U32)llmin((U32)mXferSize,(U32)((U32)(packet_num+1)*fdata_size)) > mBufferStartOffset + mBufferLength))
+
+ {
+ if (suck(packet_num*fdata_size)) // returns non-zero on failure
+ {
+ abort(LL_ERR_EOF);
+ return;
+ }
+ }
+
+ S32 desired_read_position = 0;
+
+ desired_read_position = packet_num * fdata_size - mBufferStartOffset;
+
+ fdata_size = llmin((S32)mBufferLength-desired_read_position, mChunkSize);
+
+ if (fdata_size < 0)
+ {
+ LL_WARNS("Xfer") << "negative data size in xfer send, aborting" << LL_ENDL;
+ abort(LL_ERR_EOF);
+ return;
+ }
+
+ if (((U32)(desired_read_position + fdata_size) >= (U32)mBufferLength) && (mBufferContainsEOF))
+ {
+ last_packet = true;
+ }
+
+ if (packet_num)
+ {
+ num_copy = llmin(fdata_size, (S32)sizeof(fdata_buf));
+ num_copy = llmin(num_copy, (S32)(mBufferLength - desired_read_position));
+ if (num_copy > 0)
+ {
+ memcpy(fdata_buf,&mBuffer[desired_read_position],num_copy); /*Flawfinder: ignore*/
+ }
+ }
+ else
+ {
+ // if we're the first packet, encode size as an additional S32
+ // at start of data.
+ num_copy = llmin(fdata_size, (S32)(sizeof(fdata_buf)-sizeof(S32)));
+ num_copy = llmin(
+ num_copy,
+ (S32)(mBufferLength - desired_read_position));
+ if (num_copy > 0)
+ {
+ memcpy( /*Flawfinder: ignore*/
+ fdata_buf + sizeof(S32),
+ &mBuffer[desired_read_position],
+ num_copy);
+ }
+ fdata_size += sizeof(S32);
+ htolememcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32));
+ }
+
+ S32 encoded_packetnum = encodePacketNum(packet_num,last_packet);
+
+ if (fdata_size)
+ {
+ // send the packet
+ gMessageSystem->newMessageFast(_PREHASH_SendXferPacket);
+ gMessageSystem->nextBlockFast(_PREHASH_XferID);
+
+ gMessageSystem->addU64Fast(_PREHASH_ID, mID);
+ gMessageSystem->addU32Fast(_PREHASH_Packet, encoded_packetnum);
+
+ gMessageSystem->nextBlockFast(_PREHASH_DataPacket);
+ gMessageSystem->addBinaryDataFast(_PREHASH_Data, &fdata_buf,fdata_size);
+
+ S32 sent_something = gMessageSystem->sendMessage(mRemoteHost);
+ if (sent_something == 0)
+ {
+ abort(LL_ERR_CIRCUIT_GONE);
+ return;
+ }
+
+ ACKTimer.reset();
+ mWaitingForACK = true;
+ }
+ if (last_packet)
+ {
+ mStatus = e_LL_XFER_COMPLETE;
+ }
+ else
+ {
+ mStatus = e_LL_XFER_IN_PROGRESS;
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer::sendNextPacket()
+{
+ mRetries = 0;
+ sendPacket(++mPacketNum);
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer::resendLastPacket()
+{
+ mRetries++;
+ sendPacket(mPacketNum);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::processEOF()
+{
+ S32 retval = 0;
+
+ mStatus = e_LL_XFER_COMPLETE;
+
+ if (LL_ERR_NOERR == mCallbackResult)
+ {
+ LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " complete: " << getFileName()
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " failed, code "
+ << mCallbackResult << ": " << getFileName() << LL_ENDL;
+ }
+
+ if (mCallback)
+ {
+ mCallback(mCallbackDataHandle,mCallbackResult, LLExtStat::NONE);
+ }
+
+ return(retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::encodePacketNum(S32 packet_num, bool is_EOF)
+{
+ if (is_EOF)
+ {
+ packet_num |= 0x80000000;
+ }
+ return packet_num;
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer::abort (S32 result_code)
+{
+ mCallbackResult = result_code;
+
+ LL_INFOS("Xfer") << "Aborting xfer from " << mRemoteHost << " named " << getFileName()
+ << " - error: " << result_code << LL_ENDL;
+
+ if (result_code != LL_ERR_CIRCUIT_GONE)
+ {
+ gMessageSystem->newMessageFast(_PREHASH_AbortXfer);
+ gMessageSystem->nextBlockFast(_PREHASH_XferID);
+ gMessageSystem->addU64Fast(_PREHASH_ID, mID);
+ gMessageSystem->addS32Fast(_PREHASH_Result, result_code);
+
+ gMessageSystem->sendMessage(mRemoteHost);
+ }
+
+ mStatus = e_LL_XFER_ABORTED;
+}
+
+
+///////////////////////////////////////////////////////////
+
+std::string LLXfer::getFileName()
+{
+ return U64_to_str(mID);
+}
+
+///////////////////////////////////////////////////////////
+
+U32 LLXfer::getXferTypeTag()
+{
+ return 0;
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer::getMaxBufferSize ()
+{
+ return(mXferSize);
+}
+
+
+std::ostream& operator<< (std::ostream& os, LLXfer &hh)
+{
+ os << hh.getFileName() ;
+ return os;
+}
diff --git a/indra/llmessage/llxfer.h b/indra/llmessage/llxfer.h index 2f880381d5..22cf05ba5a 100644 --- a/indra/llmessage/llxfer.h +++ b/indra/llmessage/llxfer.h @@ -1,123 +1,123 @@ -/** - * @file llxfer.h - * @brief definition of LLXfer class for a single xfer - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLXFER_H -#define LL_LLXFER_H - -#include "message.h" -#include "lltimer.h" -#include "llextendedstatus.h" - -const S32 LL_XFER_LARGE_PAYLOAD = 7680; -const S32 LL_ERR_FILE_EMPTY = -44; -const int LL_ERR_FILE_NOT_FOUND = -43; -const int LL_ERR_CANNOT_OPEN_FILE = -42; -const int LL_ERR_EOF = -39; - -typedef enum ELLXferStatus { - e_LL_XFER_UNINITIALIZED, - e_LL_XFER_REGISTERED, // a buffer which has been registered as available for a request - e_LL_XFER_PENDING, // a transfer which has been requested but is waiting for a free slot - e_LL_XFER_IN_PROGRESS, - e_LL_XFER_COMPLETE, - e_LL_XFER_ABORTED, - e_LL_XFER_NONE -} ELLXferStatus; - -class LLXfer -{ - private: - protected: - S32 mChunkSize; - - public: - U64 mID; - S32 mPacketNum; - - LLHost mRemoteHost; - S32 mXferSize; - - char *mBuffer; - U32 mBufferLength; // Size of valid data, not actual allocated buffer size - U32 mBufferStartOffset; - BOOL mBufferContainsEOF; - - ELLXferStatus mStatus; - - BOOL mWaitingForACK; - - void (*mCallback)(void **,S32,LLExtStat); - void **mCallbackDataHandle; - S32 mCallbackResult; - - LLTimer ACKTimer; - S32 mRetries; - - static const U32 XFER_FILE; - static const U32 XFER_VFILE; - static const U32 XFER_MEM; - - private: - protected: - public: - LLXfer (S32 chunk_size); - virtual ~LLXfer(); - - void init(S32 chunk_size); - virtual void cleanup(); - - virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); - virtual void closeFileHandle(); - virtual S32 reopenFileHandle(); - virtual void sendPacket(S32 packet_num); - virtual void sendNextPacket(); - virtual void resendLastPacket(); - virtual S32 processEOF(); - virtual S32 startDownload(); - virtual S32 receiveData (char *datap, S32 data_size); - virtual void abort(S32); - - virtual S32 suck(S32 start_position); - virtual S32 flush(); - - virtual S32 encodePacketNum(S32 packet_num, BOOL is_eof); - virtual void setXferSize (S32 data_size); - virtual S32 getMaxBufferSize(); - - virtual std::string getFileName(); - - virtual U32 getXferTypeTag(); - - friend std::ostream& operator<< (std::ostream& os, LLXfer &hh); - -}; - -#endif - - - - - +/**
+ * @file llxfer.h
+ * @brief definition of LLXfer class for a single xfer
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLXFER_H
+#define LL_LLXFER_H
+
+#include "message.h"
+#include "lltimer.h"
+#include "llextendedstatus.h"
+
+const S32 LL_XFER_LARGE_PAYLOAD = 7680;
+const S32 LL_ERR_FILE_EMPTY = -44;
+const int LL_ERR_FILE_NOT_FOUND = -43;
+const int LL_ERR_CANNOT_OPEN_FILE = -42;
+const int LL_ERR_EOF = -39;
+
+typedef enum ELLXferStatus {
+ e_LL_XFER_UNINITIALIZED,
+ e_LL_XFER_REGISTERED, // a buffer which has been registered as available for a request
+ e_LL_XFER_PENDING, // a transfer which has been requested but is waiting for a free slot
+ e_LL_XFER_IN_PROGRESS,
+ e_LL_XFER_COMPLETE,
+ e_LL_XFER_ABORTED,
+ e_LL_XFER_NONE
+} ELLXferStatus;
+
+class LLXfer
+{
+ private:
+ protected:
+ S32 mChunkSize;
+
+ public:
+ U64 mID;
+ S32 mPacketNum;
+
+ LLHost mRemoteHost;
+ S32 mXferSize;
+
+ char *mBuffer;
+ U32 mBufferLength; // Size of valid data, not actual allocated buffer size
+ U32 mBufferStartOffset;
+ bool mBufferContainsEOF;
+
+ ELLXferStatus mStatus;
+
+ bool mWaitingForACK;
+
+ void (*mCallback)(void **,S32,LLExtStat);
+ void **mCallbackDataHandle;
+ S32 mCallbackResult;
+
+ LLTimer ACKTimer;
+ S32 mRetries;
+
+ static const U32 XFER_FILE;
+ static const U32 XFER_VFILE;
+ static const U32 XFER_MEM;
+
+ private:
+ protected:
+ public:
+ LLXfer (S32 chunk_size);
+ virtual ~LLXfer();
+
+ void init(S32 chunk_size);
+ virtual void cleanup();
+
+ virtual S32 startSend(U64 xfer_id, const LLHost &remote_host);
+ virtual void closeFileHandle();
+ virtual S32 reopenFileHandle();
+ virtual void sendPacket(S32 packet_num);
+ virtual void sendNextPacket();
+ virtual void resendLastPacket();
+ virtual S32 processEOF();
+ virtual S32 startDownload();
+ virtual S32 receiveData (char *datap, S32 data_size);
+ virtual void abort(S32);
+
+ virtual S32 suck(S32 start_position);
+ virtual S32 flush();
+
+ virtual S32 encodePacketNum(S32 packet_num, bool is_eof);
+ virtual void setXferSize (S32 data_size);
+ virtual S32 getMaxBufferSize();
+
+ virtual std::string getFileName();
+
+ virtual U32 getXferTypeTag();
+
+ friend std::ostream& operator<< (std::ostream& os, LLXfer &hh);
+
+};
+
+#endif
+
+
+
+
+
diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index bdd7e35fd5..a9450f725b 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -1,475 +1,475 @@ -/** - * @file llxfer_file.cpp - * @brief implementation of LLXfer_File class for a single xfer (file) - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#if !LL_WINDOWS -#include <errno.h> -#include <unistd.h> -#endif - -#include "llxfer_file.h" -#include "lluuid.h" -#include "llerror.h" -#include "llmath.h" -#include "llstring.h" -#include "lldir.h" - -// size of chunks read from/written to disk -const U32 LL_MAX_XFER_FILE_BUFFER = 65536; - -// local function to copy a file -S32 copy_file(const std::string& from, const std::string& to); - -/////////////////////////////////////////////////////////// - -LLXfer_File::LLXfer_File (S32 chunk_size) -: LLXfer(chunk_size) -{ - init(LLStringUtil::null, FALSE, chunk_size); -} - -LLXfer_File::LLXfer_File (const std::string& local_filename, BOOL delete_local_on_completion, S32 chunk_size) -: LLXfer(chunk_size) -{ - init(local_filename, delete_local_on_completion, chunk_size); -} - -/////////////////////////////////////////////////////////// - -LLXfer_File::~LLXfer_File () -{ - cleanup(); -} - -/////////////////////////////////////////////////////////// - -void LLXfer_File::init (const std::string& local_filename, BOOL delete_local_on_completion, S32 chunk_size) -{ - - mFp = NULL; - mLocalFilename.clear(); - mRemoteFilename.clear(); - mRemotePath = LL_PATH_NONE; - mTempFilename.clear(); - mDeleteLocalOnCompletion = FALSE; - mDeleteRemoteOnCompletion = FALSE; - - if (!local_filename.empty()) - { - mLocalFilename = local_filename.substr(0,LL_MAX_PATH-1); - - // You can only automatically delete .tmp file as a safeguard against nasty messages. - std::string exten = mLocalFilename.substr(mLocalFilename.length()-4, 4); - mDeleteLocalOnCompletion = (delete_local_on_completion && exten == ".tmp"); - } -} - -/////////////////////////////////////////////////////////// - -void LLXfer_File::cleanup () -{ - if (mFp) - { - fclose(mFp); - mFp = NULL; - } - - LLFile::remove(mTempFilename, ENOENT); - - if (mDeleteLocalOnCompletion) - { - LL_DEBUGS("Xfer") << "Removing file: " << mLocalFilename << LL_ENDL; - LLFile::remove(mLocalFilename, ENOENT); - } - else - { - LL_DEBUGS("Xfer") << "Keeping local file: " << mLocalFilename << LL_ENDL; - } - - LLXfer::cleanup(); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_File::initializeRequest(U64 xfer_id, - const std::string& local_filename, - const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void**,S32,LLExtStat), - void** user_data) -{ - S32 retval = 0; // presume success - - mID = xfer_id; - mLocalFilename = local_filename; - mRemoteFilename = remote_filename; - mRemotePath = remote_path; - mRemoteHost = remote_host; - mDeleteRemoteOnCompletion = delete_remote_on_completion; - - mTempFilename = gDirUtilp->getTempFilename(); - - mCallback = callback; - mCallbackDataHandle = user_data; - mCallbackResult = LL_ERR_NOERR; - - LL_INFOS("Xfer") << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << LL_ENDL; - - if (mBuffer) - { - delete(mBuffer); - mBuffer = NULL; - } - - mBuffer = new char[LL_MAX_XFER_FILE_BUFFER]; - mBufferLength = 0; - - mPacketNum = 0; - - mStatus = e_LL_XFER_PENDING; - return retval; -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_File::startDownload() -{ - S32 retval = 0; // presume success - mFp = LLFile::fopen(mTempFilename,"w+b"); /* Flawfinder : ignore */ - if (mFp) - { - fclose(mFp); - mFp = NULL; - - // tbd - is it premature to send this message if the queue is backed up? - gMessageSystem->newMessageFast(_PREHASH_RequestXfer); - gMessageSystem->nextBlockFast(_PREHASH_XferID); - gMessageSystem->addU64Fast(_PREHASH_ID, mID); - gMessageSystem->addStringFast(_PREHASH_Filename, mRemoteFilename); - gMessageSystem->addU8("FilePath", (U8) mRemotePath); - gMessageSystem->addBOOL("DeleteOnCompletion", mDeleteRemoteOnCompletion); - gMessageSystem->addBOOL("UseBigPackets", BOOL(mChunkSize == LL_XFER_LARGE_PAYLOAD)); - gMessageSystem->addUUIDFast(_PREHASH_VFileID, LLUUID::null); - gMessageSystem->addS16Fast(_PREHASH_VFileType, -1); - - gMessageSystem->sendReliable(mRemoteHost); - mStatus = e_LL_XFER_IN_PROGRESS; - } - else - { - LL_WARNS("Xfer") << "Couldn't create file to be received!" << LL_ENDL; - retval = -1; - } - - return (retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) -{ - S32 retval = LL_ERR_NOERR; // presume success - - mRemoteHost = remote_host; - mID = xfer_id; - mPacketNum = -1; - -// cout << "Sending file: " << mLocalFilename << endl; - - delete [] mBuffer; - mBuffer = new char[LL_MAX_XFER_FILE_BUFFER]; - - mBufferLength = 0; - mBufferStartOffset = 0; - - // We leave the file open, assuming we'll start reading and sending soon - mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ - if (mFp) - { - fseek(mFp,0,SEEK_END); - - S32 file_size = ftell(mFp); - if (file_size <= 0) - { - return LL_ERR_FILE_EMPTY; - } - setXferSize(file_size); - - fseek(mFp,0,SEEK_SET); - } - else - { - LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found." << LL_ENDL; - return (LL_ERR_FILE_NOT_FOUND); - } - - mStatus = e_LL_XFER_PENDING; - - return (retval); -} - -/////////////////////////////////////////////////////////// -void LLXfer_File::closeFileHandle() -{ - if (mFp) - { - fclose(mFp); - mFp = NULL; - } -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_File::reopenFileHandle() -{ - S32 retval = LL_ERR_NOERR; // presume success - - if (mFp == NULL) - { - mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ - if (mFp == NULL) - { - LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL; - retval = LL_ERR_FILE_NOT_FOUND; - } - } - - return retval; -} - - -/////////////////////////////////////////////////////////// - -S32 LLXfer_File::getMaxBufferSize () -{ - return(LL_MAX_XFER_FILE_BUFFER); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_File::suck(S32 start_position) -{ - S32 retval = 0; - - if (mFp) - { - // grab a buffer from the right place in the file - fseek (mFp,start_position,SEEK_SET); - - mBufferLength = (U32)fread(mBuffer,1,LL_MAX_XFER_FILE_BUFFER,mFp); - mBufferStartOffset = start_position; - - if (feof(mFp)) - { - mBufferContainsEOF = TRUE; - } - else - { - mBufferContainsEOF = FALSE; - } - } - else - { - retval = -1; - } - - return (retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_File::flush() -{ - S32 retval = 0; - if (mBufferLength) - { - if (mFp) - { - LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL; - } - mFp = LLFile::fopen(mTempFilename,"a+b"); /* Flawfinder : ignore */ - - if (mFp) - { - S32 write_size = fwrite(mBuffer,1,mBufferLength,mFp); - if (write_size != mBufferLength) - { - LL_WARNS("Xfer") << "Non-matching write size, requested " << mBufferLength - << " but wrote " << write_size - << LL_ENDL; - } - -// LL_INFOS("Xfer") << "******* wrote " << mBufferLength << " bytes of file xfer" << LL_ENDL; - fclose(mFp); - mFp = NULL; - - mBufferLength = 0; - } - else - { - LL_WARNS("Xfer") << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << LL_ENDL; - retval = LL_ERR_CANNOT_OPEN_FILE; - } - } - return (retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_File::processEOF() -{ - S32 retval = 0; - mStatus = e_LL_XFER_COMPLETE; - - S32 flushval = flush(); - - // If we have no other errors, our error becomes the error generated by - // flush. - if (!mCallbackResult) - { - mCallbackResult = flushval; - } - - LLFile::remove(mLocalFilename, ENOENT); - - if (!mCallbackResult) - { - if (LLFile::rename(mTempFilename,mLocalFilename)) - { -#if !LL_WINDOWS - S32 error_number = errno; - LL_INFOS("Xfer") << "Rename failure (" << error_number << ") - " - << mTempFilename << " to " << mLocalFilename << LL_ENDL; - if(EXDEV == error_number) - { - if(copy_file(mTempFilename, mLocalFilename) == 0) - { - LL_INFOS("Xfer") << "Rename across mounts; copying+unlinking the file instead." << LL_ENDL; - unlink(mTempFilename.c_str()); - } - else - { - LL_WARNS("Xfer") << "Copy failure - " << mTempFilename << " to " - << mLocalFilename << LL_ENDL; - } - } - else - { - //LLFILE* fp = LLFile::fopen(mTempFilename, "r"); - //LL_WARNS() << "File " << mTempFilename << " does " - // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; - //if(fp) fclose(fp); - //fp = LLFile::fopen(mLocalFilename, "r"); - //LL_WARNS() << "File " << mLocalFilename << " does " - // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; - //if(fp) fclose(fp); - LL_WARNS("Xfer") << "Rename fatally failed, can only handle EXDEV (" - << EXDEV << ")" << LL_ENDL; - } -#else - LL_WARNS("Xfer") << "Rename failure - " << mTempFilename << " to " - << mLocalFilename << LL_ENDL; -#endif - } - } - - if (mFp) - { - fclose(mFp); - mFp = NULL; - } - - retval = LLXfer::processEOF(); - - return(retval); -} - -/////////////////////////////////////////////////////////// - -BOOL LLXfer_File::matchesLocalFilename(const std::string& filename) -{ - return (filename == mLocalFilename); -} - -/////////////////////////////////////////////////////////// - -BOOL LLXfer_File::matchesRemoteFilename(const std::string& filename, ELLPath remote_path) -{ - return ((filename == mRemoteFilename) && (remote_path == mRemotePath)); -} - - -/////////////////////////////////////////////////////////// - -std::string LLXfer_File::getFileName() -{ - return mLocalFilename; -} - -/////////////////////////////////////////////////////////// - -// hacky - doesn't matter what this is -// as long as it's different from the other classes -U32 LLXfer_File::getXferTypeTag() -{ - return LLXfer::XFER_FILE; -} - -/////////////////////////////////////////////////////////// - -#if !LL_WINDOWS - -// This is really close to, but not quite a general purpose copy -// function. It does not really spam enough information, but is useful -// for this cpp file, because this should never be called in a -// production environment. -S32 copy_file(const std::string& from, const std::string& to) -{ - S32 rv = 0; - LLFILE* in = LLFile::fopen(from, "rb"); /*Flawfinder: ignore*/ - LLFILE* out = LLFile::fopen(to, "wb"); /*Flawfinder: ignore*/ - if(in && out) - { - S32 read = 0; - const S32 COPY_BUFFER_SIZE = 16384; - U8 buffer[COPY_BUFFER_SIZE]; - while(((read = fread(buffer, 1, sizeof(buffer), in)) > 0) - && (fwrite(buffer, 1, read, out) == (U32)read)); /* Flawfinder : ignore */ - if(ferror(in) || ferror(out)) rv = -2; - } - else - { - rv = -1; - } - if(in) fclose(in); - if(out) fclose(out); - return rv; -} -#endif - +/**
+ * @file llxfer_file.cpp
+ * @brief implementation of LLXfer_File class for a single xfer (file)
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#if !LL_WINDOWS
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+#include "llxfer_file.h"
+#include "lluuid.h"
+#include "llerror.h"
+#include "llmath.h"
+#include "llstring.h"
+#include "lldir.h"
+
+// size of chunks read from/written to disk
+const U32 LL_MAX_XFER_FILE_BUFFER = 65536;
+
+// local function to copy a file
+S32 copy_file(const std::string& from, const std::string& to);
+
+///////////////////////////////////////////////////////////
+
+LLXfer_File::LLXfer_File (S32 chunk_size)
+: LLXfer(chunk_size)
+{
+ init(LLStringUtil::null, false, chunk_size);
+}
+
+LLXfer_File::LLXfer_File (const std::string& local_filename, bool delete_local_on_completion, S32 chunk_size)
+: LLXfer(chunk_size)
+{
+ init(local_filename, delete_local_on_completion, chunk_size);
+}
+
+///////////////////////////////////////////////////////////
+
+LLXfer_File::~LLXfer_File ()
+{
+ cleanup();
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_File::init (const std::string& local_filename, bool delete_local_on_completion, S32 chunk_size)
+{
+
+ mFp = NULL;
+ mLocalFilename.clear();
+ mRemoteFilename.clear();
+ mRemotePath = LL_PATH_NONE;
+ mTempFilename.clear();
+ mDeleteLocalOnCompletion = false;
+ mDeleteRemoteOnCompletion = false;
+
+ if (!local_filename.empty())
+ {
+ mLocalFilename = local_filename.substr(0,LL_MAX_PATH-1);
+
+ // You can only automatically delete .tmp file as a safeguard against nasty messages.
+ std::string exten = mLocalFilename.substr(mLocalFilename.length()-4, 4);
+ mDeleteLocalOnCompletion = (delete_local_on_completion && exten == ".tmp");
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_File::cleanup ()
+{
+ if (mFp)
+ {
+ fclose(mFp);
+ mFp = NULL;
+ }
+
+ LLFile::remove(mTempFilename, ENOENT);
+
+ if (mDeleteLocalOnCompletion)
+ {
+ LL_DEBUGS("Xfer") << "Removing file: " << mLocalFilename << LL_ENDL;
+ LLFile::remove(mLocalFilename, ENOENT);
+ }
+ else
+ {
+ LL_DEBUGS("Xfer") << "Keeping local file: " << mLocalFilename << LL_ENDL;
+ }
+
+ LLXfer::cleanup();
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_File::initializeRequest(U64 xfer_id,
+ const std::string& local_filename,
+ const std::string& remote_filename,
+ ELLPath remote_path,
+ const LLHost& remote_host,
+ bool delete_remote_on_completion,
+ void (*callback)(void**,S32,LLExtStat),
+ void** user_data)
+{
+ S32 retval = 0; // presume success
+
+ mID = xfer_id;
+ mLocalFilename = local_filename;
+ mRemoteFilename = remote_filename;
+ mRemotePath = remote_path;
+ mRemoteHost = remote_host;
+ mDeleteRemoteOnCompletion = delete_remote_on_completion;
+
+ mTempFilename = gDirUtilp->getTempFilename();
+
+ mCallback = callback;
+ mCallbackDataHandle = user_data;
+ mCallbackResult = LL_ERR_NOERR;
+
+ LL_INFOS("Xfer") << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << LL_ENDL;
+
+ if (mBuffer)
+ {
+ delete(mBuffer);
+ mBuffer = NULL;
+ }
+
+ mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
+ mBufferLength = 0;
+
+ mPacketNum = 0;
+
+ mStatus = e_LL_XFER_PENDING;
+ return retval;
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_File::startDownload()
+{
+ S32 retval = 0; // presume success
+ mFp = LLFile::fopen(mTempFilename,"w+b"); /* Flawfinder : ignore */
+ if (mFp)
+ {
+ fclose(mFp);
+ mFp = NULL;
+
+ // tbd - is it premature to send this message if the queue is backed up?
+ gMessageSystem->newMessageFast(_PREHASH_RequestXfer);
+ gMessageSystem->nextBlockFast(_PREHASH_XferID);
+ gMessageSystem->addU64Fast(_PREHASH_ID, mID);
+ gMessageSystem->addStringFast(_PREHASH_Filename, mRemoteFilename);
+ gMessageSystem->addU8("FilePath", (U8) mRemotePath);
+ gMessageSystem->addBOOL("DeleteOnCompletion", mDeleteRemoteOnCompletion);
+ gMessageSystem->addBOOL("UseBigPackets", mChunkSize == LL_XFER_LARGE_PAYLOAD);
+ gMessageSystem->addUUIDFast(_PREHASH_VFileID, LLUUID::null);
+ gMessageSystem->addS16Fast(_PREHASH_VFileType, -1);
+
+ gMessageSystem->sendReliable(mRemoteHost);
+ mStatus = e_LL_XFER_IN_PROGRESS;
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "Couldn't create file to be received!" << LL_ENDL;
+ retval = -1;
+ }
+
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host)
+{
+ S32 retval = LL_ERR_NOERR; // presume success
+
+ mRemoteHost = remote_host;
+ mID = xfer_id;
+ mPacketNum = -1;
+
+// cout << "Sending file: " << mLocalFilename << endl;
+
+ delete [] mBuffer;
+ mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
+
+ mBufferLength = 0;
+ mBufferStartOffset = 0;
+
+ // We leave the file open, assuming we'll start reading and sending soon
+ mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */
+ if (mFp)
+ {
+ fseek(mFp,0,SEEK_END);
+
+ S32 file_size = ftell(mFp);
+ if (file_size <= 0)
+ {
+ return LL_ERR_FILE_EMPTY;
+ }
+ setXferSize(file_size);
+
+ fseek(mFp,0,SEEK_SET);
+ }
+ else
+ {
+ LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found." << LL_ENDL;
+ return (LL_ERR_FILE_NOT_FOUND);
+ }
+
+ mStatus = e_LL_XFER_PENDING;
+
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+void LLXfer_File::closeFileHandle()
+{
+ if (mFp)
+ {
+ fclose(mFp);
+ mFp = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_File::reopenFileHandle()
+{
+ S32 retval = LL_ERR_NOERR; // presume success
+
+ if (mFp == NULL)
+ {
+ mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */
+ if (mFp == NULL)
+ {
+ LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL;
+ retval = LL_ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ return retval;
+}
+
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_File::getMaxBufferSize ()
+{
+ return(LL_MAX_XFER_FILE_BUFFER);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_File::suck(S32 start_position)
+{
+ S32 retval = 0;
+
+ if (mFp)
+ {
+ // grab a buffer from the right place in the file
+ fseek (mFp,start_position,SEEK_SET);
+
+ mBufferLength = (U32)fread(mBuffer,1,LL_MAX_XFER_FILE_BUFFER,mFp);
+ mBufferStartOffset = start_position;
+
+ if (feof(mFp))
+ {
+ mBufferContainsEOF = true;
+ }
+ else
+ {
+ mBufferContainsEOF = false;
+ }
+ }
+ else
+ {
+ retval = -1;
+ }
+
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_File::flush()
+{
+ S32 retval = 0;
+ if (mBufferLength)
+ {
+ if (mFp)
+ {
+ LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL;
+ }
+ mFp = LLFile::fopen(mTempFilename,"a+b"); /* Flawfinder : ignore */
+
+ if (mFp)
+ {
+ S32 write_size = fwrite(mBuffer,1,mBufferLength,mFp);
+ if (write_size != mBufferLength)
+ {
+ LL_WARNS("Xfer") << "Non-matching write size, requested " << mBufferLength
+ << " but wrote " << write_size
+ << LL_ENDL;
+ }
+
+// LL_INFOS("Xfer") << "******* wrote " << mBufferLength << " bytes of file xfer" << LL_ENDL;
+ fclose(mFp);
+ mFp = NULL;
+
+ mBufferLength = 0;
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << LL_ENDL;
+ retval = LL_ERR_CANNOT_OPEN_FILE;
+ }
+ }
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_File::processEOF()
+{
+ S32 retval = 0;
+ mStatus = e_LL_XFER_COMPLETE;
+
+ S32 flushval = flush();
+
+ // If we have no other errors, our error becomes the error generated by
+ // flush.
+ if (!mCallbackResult)
+ {
+ mCallbackResult = flushval;
+ }
+
+ LLFile::remove(mLocalFilename, ENOENT);
+
+ if (!mCallbackResult)
+ {
+ if (LLFile::rename(mTempFilename,mLocalFilename))
+ {
+#if !LL_WINDOWS
+ S32 error_number = errno;
+ LL_INFOS("Xfer") << "Rename failure (" << error_number << ") - "
+ << mTempFilename << " to " << mLocalFilename << LL_ENDL;
+ if(EXDEV == error_number)
+ {
+ if(copy_file(mTempFilename, mLocalFilename) == 0)
+ {
+ LL_INFOS("Xfer") << "Rename across mounts; copying+unlinking the file instead." << LL_ENDL;
+ unlink(mTempFilename.c_str());
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "Copy failure - " << mTempFilename << " to "
+ << mLocalFilename << LL_ENDL;
+ }
+ }
+ else
+ {
+ //LLFILE* fp = LLFile::fopen(mTempFilename, "r");
+ //LL_WARNS() << "File " << mTempFilename << " does "
+ // << (!fp ? "not" : "" ) << " exit." << LL_ENDL;
+ //if(fp) fclose(fp);
+ //fp = LLFile::fopen(mLocalFilename, "r");
+ //LL_WARNS() << "File " << mLocalFilename << " does "
+ // << (!fp ? "not" : "" ) << " exit." << LL_ENDL;
+ //if(fp) fclose(fp);
+ LL_WARNS("Xfer") << "Rename fatally failed, can only handle EXDEV ("
+ << EXDEV << ")" << LL_ENDL;
+ }
+#else
+ LL_WARNS("Xfer") << "Rename failure - " << mTempFilename << " to "
+ << mLocalFilename << LL_ENDL;
+#endif
+ }
+ }
+
+ if (mFp)
+ {
+ fclose(mFp);
+ mFp = NULL;
+ }
+
+ retval = LLXfer::processEOF();
+
+ return(retval);
+}
+
+///////////////////////////////////////////////////////////
+
+bool LLXfer_File::matchesLocalFilename(const std::string& filename)
+{
+ return (filename == mLocalFilename);
+}
+
+///////////////////////////////////////////////////////////
+
+bool LLXfer_File::matchesRemoteFilename(const std::string& filename, ELLPath remote_path)
+{
+ return ((filename == mRemoteFilename) && (remote_path == mRemotePath));
+}
+
+
+///////////////////////////////////////////////////////////
+
+std::string LLXfer_File::getFileName()
+{
+ return mLocalFilename;
+}
+
+///////////////////////////////////////////////////////////
+
+// hacky - doesn't matter what this is
+// as long as it's different from the other classes
+U32 LLXfer_File::getXferTypeTag()
+{
+ return LLXfer::XFER_FILE;
+}
+
+///////////////////////////////////////////////////////////
+
+#if !LL_WINDOWS
+
+// This is really close to, but not quite a general purpose copy
+// function. It does not really spam enough information, but is useful
+// for this cpp file, because this should never be called in a
+// production environment.
+S32 copy_file(const std::string& from, const std::string& to)
+{
+ S32 rv = 0;
+ LLFILE* in = LLFile::fopen(from, "rb"); /*Flawfinder: ignore*/
+ LLFILE* out = LLFile::fopen(to, "wb"); /*Flawfinder: ignore*/
+ if(in && out)
+ {
+ S32 read = 0;
+ const S32 COPY_BUFFER_SIZE = 16384;
+ U8 buffer[COPY_BUFFER_SIZE];
+ while(((read = fread(buffer, 1, sizeof(buffer), in)) > 0)
+ && (fwrite(buffer, 1, read, out) == (U32)read)); /* Flawfinder : ignore */
+ if(ferror(in) || ferror(out)) rv = -2;
+ }
+ else
+ {
+ rv = -1;
+ }
+ if(in) fclose(in);
+ if(out) fclose(out);
+ return rv;
+}
+#endif
+
diff --git a/indra/llmessage/llxfer_file.h b/indra/llmessage/llxfer_file.h index cb2da47e44..baf57753ae 100644 --- a/indra/llmessage/llxfer_file.h +++ b/indra/llmessage/llxfer_file.h @@ -1,87 +1,87 @@ -/** - * @file llxfer_file.h - * @brief definition of LLXfer_File class for a single xfer_file. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLXFER_FILE_H -#define LL_LLXFER_FILE_H - -#include "llxfer.h" -#include "lldir.h" - -class LLXfer_File : public LLXfer -{ - protected: - LLFILE *mFp; - std::string mLocalFilename; - std::string mRemoteFilename; - ELLPath mRemotePath; - std::string mTempFilename; - - BOOL mDeleteLocalOnCompletion; - BOOL mDeleteRemoteOnCompletion; - - public: - LLXfer_File (S32 chunk_size); - LLXfer_File (const std::string& local_filename, BOOL delete_local_on_completion, S32 chunk_size); - virtual ~LLXfer_File(); - - virtual void init(const std::string& local_filename, BOOL delete_local_on_completion, S32 chunk_size); - virtual void cleanup(); - - virtual S32 initializeRequest(U64 xfer_id, - const std::string& local_filename, - const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void**,S32,LLExtStat), - void** user_data); - virtual S32 startDownload(); - - virtual S32 processEOF(); - - virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); - virtual void closeFileHandle(); - virtual S32 reopenFileHandle(); - - virtual S32 suck(S32 start_position); - virtual S32 flush(); - - virtual BOOL matchesLocalFilename(const std::string& filename); - virtual BOOL matchesRemoteFilename(const std::string& filename, ELLPath remote_path); - - virtual S32 getMaxBufferSize(); - - virtual U32 getXferTypeTag(); - - virtual std::string getFileName(); -}; - -#endif - - - - - +/**
+ * @file llxfer_file.h
+ * @brief definition of LLXfer_File class for a single xfer_file.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLXFER_FILE_H
+#define LL_LLXFER_FILE_H
+
+#include "llxfer.h"
+#include "lldir.h"
+
+class LLXfer_File : public LLXfer
+{
+ protected:
+ LLFILE *mFp;
+ std::string mLocalFilename;
+ std::string mRemoteFilename;
+ ELLPath mRemotePath;
+ std::string mTempFilename;
+
+ bool mDeleteLocalOnCompletion;
+ bool mDeleteRemoteOnCompletion;
+
+ public:
+ LLXfer_File (S32 chunk_size);
+ LLXfer_File (const std::string& local_filename, bool delete_local_on_completion, S32 chunk_size);
+ virtual ~LLXfer_File();
+
+ virtual void init(const std::string& local_filename, bool delete_local_on_completion, S32 chunk_size);
+ virtual void cleanup();
+
+ virtual S32 initializeRequest(U64 xfer_id,
+ const std::string& local_filename,
+ const std::string& remote_filename,
+ ELLPath remote_path,
+ const LLHost& remote_host,
+ bool delete_remote_on_completion,
+ void (*callback)(void**,S32,LLExtStat),
+ void** user_data);
+ virtual S32 startDownload();
+
+ virtual S32 processEOF();
+
+ virtual S32 startSend(U64 xfer_id, const LLHost &remote_host);
+ virtual void closeFileHandle();
+ virtual S32 reopenFileHandle();
+
+ virtual S32 suck(S32 start_position);
+ virtual S32 flush();
+
+ virtual bool matchesLocalFilename(const std::string& filename);
+ virtual bool matchesRemoteFilename(const std::string& filename, ELLPath remote_path);
+
+ virtual S32 getMaxBufferSize();
+
+ virtual U32 getXferTypeTag();
+
+ virtual std::string getFileName();
+};
+
+#endif
+
+
+
+
+
diff --git a/indra/llmessage/llxfer_mem.cpp b/indra/llmessage/llxfer_mem.cpp index 100a67e422..825bff3820 100644 --- a/indra/llmessage/llxfer_mem.cpp +++ b/indra/llmessage/llxfer_mem.cpp @@ -1,196 +1,196 @@ -/** - * @file llxfer_mem.cpp - * @brief implementation of LLXfer_Mem class for a single xfer - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "llxfer_mem.h" -#include "lluuid.h" -#include "llerror.h" -#include "llmath.h" - -/////////////////////////////////////////////////////////// - -LLXfer_Mem::LLXfer_Mem () -: LLXfer(-1) -{ - init(); -} - -/////////////////////////////////////////////////////////// - -LLXfer_Mem::~LLXfer_Mem () -{ - cleanup(); -} - -/////////////////////////////////////////////////////////// - -void LLXfer_Mem::init () -{ - mRemoteFilename.clear(); - mRemotePath = LL_PATH_NONE; - mDeleteRemoteOnCompletion = FALSE; -} - -/////////////////////////////////////////////////////////// - -void LLXfer_Mem::cleanup () -{ - LLXfer::cleanup(); -} - -/////////////////////////////////////////////////////////// - -void LLXfer_Mem::setXferSize (S32 xfer_size) -{ - mXferSize = xfer_size; - - delete[] mBuffer; - mBuffer = new char[xfer_size]; - - mBufferLength = 0; - mBufferStartOffset = 0; - mBufferContainsEOF = TRUE; - -// cout << "starting transfer of size: " << xfer_size << endl; -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_Mem::startSend (U64 xfer_id, const LLHost &remote_host) -{ - S32 retval = LL_ERR_NOERR; // presume success - - if (mXferSize <= 0) - { - return LL_ERR_FILE_EMPTY; - } - - mRemoteHost = remote_host; - mID = xfer_id; - mPacketNum = -1; - -// cout << "Sending file: " << getFileName() << endl; - - mStatus = e_LL_XFER_PENDING; - - return (retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_Mem::processEOF() -{ - S32 retval = 0; - - mStatus = e_LL_XFER_COMPLETE; - - LL_INFOS() << "xfer complete: " << getFileName() << LL_ENDL; - - if (mCallback) - { - mCallback((void *)mBuffer,mBufferLength,mCallbackDataHandle,mCallbackResult, LLExtStat::NONE); - } - - return(retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_Mem::initializeRequest(U64 xfer_id, - const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void*,S32,void**,S32,LLExtStat), - void** user_data) -{ - S32 retval = 0; // presume success - - mRemoteHost = remote_host; - - // create a temp filename string using a GUID - mID = xfer_id; - mCallback = callback; - mCallbackDataHandle = user_data; - mCallbackResult = LL_ERR_NOERR; - - mRemoteFilename = remote_filename; - mRemotePath = remote_path; - mDeleteRemoteOnCompletion = delete_remote_on_completion; - - LL_INFOS() << "Requesting file: " << remote_filename << LL_ENDL; - - delete [] mBuffer; - mBuffer = NULL; - - mBufferLength = 0; - mPacketNum = 0; - mStatus = e_LL_XFER_PENDING; - return retval; -} - -////////////////////////////////////////////////////////// - -S32 LLXfer_Mem::startDownload() -{ - S32 retval = 0; // presume success - gMessageSystem->newMessageFast(_PREHASH_RequestXfer); - gMessageSystem->nextBlockFast(_PREHASH_XferID); - gMessageSystem->addU64Fast(_PREHASH_ID, mID); - gMessageSystem->addStringFast(_PREHASH_Filename, mRemoteFilename); - gMessageSystem->addU8("FilePath", (U8) mRemotePath); - gMessageSystem->addBOOL("DeleteOnCompletion", mDeleteRemoteOnCompletion); - gMessageSystem->addBOOL("UseBigPackets", BOOL(mChunkSize == LL_XFER_LARGE_PAYLOAD)); - gMessageSystem->addUUIDFast(_PREHASH_VFileID, LLUUID::null); - gMessageSystem->addS16Fast(_PREHASH_VFileType, -1); - - gMessageSystem->sendReliable(mRemoteHost); - mStatus = e_LL_XFER_IN_PROGRESS; - - return (retval); -} - -////////////////////////////////////////////////////////// - -U32 LLXfer_Mem::getXferTypeTag() -{ - return LLXfer::XFER_MEM; -} - - - - - - - - - - - - - - +/**
+ * @file llxfer_mem.cpp
+ * @brief implementation of LLXfer_Mem class for a single xfer
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llxfer_mem.h"
+#include "lluuid.h"
+#include "llerror.h"
+#include "llmath.h"
+
+///////////////////////////////////////////////////////////
+
+LLXfer_Mem::LLXfer_Mem ()
+: LLXfer(-1)
+{
+ init();
+}
+
+///////////////////////////////////////////////////////////
+
+LLXfer_Mem::~LLXfer_Mem ()
+{
+ cleanup();
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_Mem::init ()
+{
+ mRemoteFilename.clear();
+ mRemotePath = LL_PATH_NONE;
+ mDeleteRemoteOnCompletion = false;
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_Mem::cleanup ()
+{
+ LLXfer::cleanup();
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_Mem::setXferSize (S32 xfer_size)
+{
+ mXferSize = xfer_size;
+
+ delete[] mBuffer;
+ mBuffer = new char[xfer_size];
+
+ mBufferLength = 0;
+ mBufferStartOffset = 0;
+ mBufferContainsEOF = true;
+
+// cout << "starting transfer of size: " << xfer_size << endl;
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_Mem::startSend (U64 xfer_id, const LLHost &remote_host)
+{
+ S32 retval = LL_ERR_NOERR; // presume success
+
+ if (mXferSize <= 0)
+ {
+ return LL_ERR_FILE_EMPTY;
+ }
+
+ mRemoteHost = remote_host;
+ mID = xfer_id;
+ mPacketNum = -1;
+
+// cout << "Sending file: " << getFileName() << endl;
+
+ mStatus = e_LL_XFER_PENDING;
+
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_Mem::processEOF()
+{
+ S32 retval = 0;
+
+ mStatus = e_LL_XFER_COMPLETE;
+
+ LL_INFOS() << "xfer complete: " << getFileName() << LL_ENDL;
+
+ if (mCallback)
+ {
+ mCallback((void *)mBuffer,mBufferLength,mCallbackDataHandle,mCallbackResult, LLExtStat::NONE);
+ }
+
+ return(retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_Mem::initializeRequest(U64 xfer_id,
+ const std::string& remote_filename,
+ ELLPath remote_path,
+ const LLHost& remote_host,
+ bool delete_remote_on_completion,
+ void (*callback)(void*,S32,void**,S32,LLExtStat),
+ void** user_data)
+{
+ S32 retval = 0; // presume success
+
+ mRemoteHost = remote_host;
+
+ // create a temp filename string using a GUID
+ mID = xfer_id;
+ mCallback = callback;
+ mCallbackDataHandle = user_data;
+ mCallbackResult = LL_ERR_NOERR;
+
+ mRemoteFilename = remote_filename;
+ mRemotePath = remote_path;
+ mDeleteRemoteOnCompletion = delete_remote_on_completion;
+
+ LL_INFOS() << "Requesting file: " << remote_filename << LL_ENDL;
+
+ delete [] mBuffer;
+ mBuffer = NULL;
+
+ mBufferLength = 0;
+ mPacketNum = 0;
+ mStatus = e_LL_XFER_PENDING;
+ return retval;
+}
+
+//////////////////////////////////////////////////////////
+
+S32 LLXfer_Mem::startDownload()
+{
+ S32 retval = 0; // presume success
+ gMessageSystem->newMessageFast(_PREHASH_RequestXfer);
+ gMessageSystem->nextBlockFast(_PREHASH_XferID);
+ gMessageSystem->addU64Fast(_PREHASH_ID, mID);
+ gMessageSystem->addStringFast(_PREHASH_Filename, mRemoteFilename);
+ gMessageSystem->addU8("FilePath", (U8) mRemotePath);
+ gMessageSystem->addBOOL("DeleteOnCompletion", mDeleteRemoteOnCompletion);
+ gMessageSystem->addBOOL("UseBigPackets", mChunkSize == LL_XFER_LARGE_PAYLOAD);
+ gMessageSystem->addUUIDFast(_PREHASH_VFileID, LLUUID::null);
+ gMessageSystem->addS16Fast(_PREHASH_VFileType, -1);
+
+ gMessageSystem->sendReliable(mRemoteHost);
+ mStatus = e_LL_XFER_IN_PROGRESS;
+
+ return (retval);
+}
+
+//////////////////////////////////////////////////////////
+
+U32 LLXfer_Mem::getXferTypeTag()
+{
+ return LLXfer::XFER_MEM;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/llmessage/llxfer_mem.h b/indra/llmessage/llxfer_mem.h index ef8e9e2483..49c3e8d20d 100644 --- a/indra/llmessage/llxfer_mem.h +++ b/indra/llmessage/llxfer_mem.h @@ -1,77 +1,77 @@ -/** - * @file llxfer_mem.h - * @brief definition of LLXfer_Mem class for a single xfer - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLXFER_MEM_H -#define LL_LLXFER_MEM_H - -#include "message.h" -#include "lltimer.h" -#include "llxfer.h" -#include "lldir.h" - -class LLXfer_Mem : public LLXfer -{ - private: - protected: - void (*mCallback)(void *, S32, void **, S32, LLExtStat); - std::string mRemoteFilename; - ELLPath mRemotePath; - BOOL mDeleteRemoteOnCompletion; - - public: - - private: - protected: - public: - LLXfer_Mem (); - virtual ~LLXfer_Mem(); - - virtual void init(); - virtual void cleanup(); - - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); - virtual void setXferSize (S32 data_size); - - virtual S32 initializeRequest(U64 xfer_id, - const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void*,S32,void**,S32,LLExtStat), - void** user_data); - virtual S32 startDownload(); - - virtual S32 processEOF(); - - virtual U32 getXferTypeTag(); -}; - -#endif - - - - - +/**
+ * @file llxfer_mem.h
+ * @brief definition of LLXfer_Mem class for a single xfer
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLXFER_MEM_H
+#define LL_LLXFER_MEM_H
+
+#include "message.h"
+#include "lltimer.h"
+#include "llxfer.h"
+#include "lldir.h"
+
+class LLXfer_Mem : public LLXfer
+{
+ private:
+ protected:
+ void (*mCallback)(void *, S32, void **, S32, LLExtStat);
+ std::string mRemoteFilename;
+ ELLPath mRemotePath;
+ bool mDeleteRemoteOnCompletion;
+
+ public:
+
+ private:
+ protected:
+ public:
+ LLXfer_Mem ();
+ virtual ~LLXfer_Mem();
+
+ virtual void init();
+ virtual void cleanup();
+
+ virtual S32 startSend (U64 xfer_id, const LLHost &remote_host);
+ virtual void setXferSize (S32 data_size);
+
+ virtual S32 initializeRequest(U64 xfer_id,
+ const std::string& remote_filename,
+ ELLPath remote_path,
+ const LLHost& remote_host,
+ bool delete_remote_on_completion,
+ void (*callback)(void*,S32,void**,S32,LLExtStat),
+ void** user_data);
+ virtual S32 startDownload();
+
+ virtual S32 processEOF();
+
+ virtual U32 getXferTypeTag();
+};
+
+#endif
+
+
+
+
+
diff --git a/indra/llmessage/llxfer_vfile.cpp b/indra/llmessage/llxfer_vfile.cpp index fbe880d05d..c37ee1ca2d 100644 --- a/indra/llmessage/llxfer_vfile.cpp +++ b/indra/llmessage/llxfer_vfile.cpp @@ -1,397 +1,397 @@ -/** - * @file llxfer_vfile.cpp - * @brief implementation of LLXfer_VFile class for a single xfer (vfile). - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#include "linden_common.h" - -#include "llxfer_vfile.h" -#include "lluuid.h" -#include "llerror.h" -#include "llmath.h" -#include "llfilesystem.h" -#include "lldir.h" - -// size of chunks read from/written to disk -const U32 LL_MAX_XFER_FILE_BUFFER = 65536; - -/////////////////////////////////////////////////////////// - -LLXfer_VFile::LLXfer_VFile () -: LLXfer(-1) -{ - init(LLUUID::null, LLAssetType::AT_NONE); -} - -LLXfer_VFile::LLXfer_VFile (const LLUUID &local_id, LLAssetType::EType type) -: LLXfer(-1) -{ - init(local_id, type); -} - -/////////////////////////////////////////////////////////// - -LLXfer_VFile::~LLXfer_VFile () -{ - cleanup(); -} - -/////////////////////////////////////////////////////////// - -void LLXfer_VFile::init (const LLUUID &local_id, LLAssetType::EType type) -{ - mLocalID = local_id; - mType = type; - - mVFile = NULL; - - std::string id_string; - mLocalID.toString(id_string); - - mName = llformat("VFile %s:%s", id_string.c_str(), LLAssetType::lookup(mType)); -} - -/////////////////////////////////////////////////////////// - -void LLXfer_VFile::cleanup () -{ - if (mTempID.notNull() && - mDeleteTempFile) - { - if (LLFileSystem::getExists(mTempID, mType)) - { - LLFileSystem file(mTempID, mType, LLFileSystem::WRITE); - file.remove(); - } - else - { - LL_WARNS("Xfer") << "LLXfer_VFile::cleanup() can't open to delete cache file " << mTempID << "." << LLAssetType::lookup(mType) - << ", mRemoteID is " << mRemoteID << LL_ENDL; - } - } - - delete mVFile; - mVFile = NULL; - - LLXfer::cleanup(); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_VFile::initializeRequest(U64 xfer_id, - const LLUUID& local_id, - const LLUUID& remote_id, - LLAssetType::EType type, - const LLHost& remote_host, - void (*callback)(void**,S32,LLExtStat), - void** user_data) -{ - S32 retval = 0; // presume success - - mRemoteHost = remote_host; - - mLocalID = local_id; - mRemoteID = remote_id; - mType = type; - - mID = xfer_id; - mCallback = callback; - mCallbackDataHandle = user_data; - mCallbackResult = LL_ERR_NOERR; - - std::string id_string; - mLocalID.toString(id_string); - - mName = llformat("VFile %s:%s", id_string.c_str(), LLAssetType::lookup(mType)); - - LL_INFOS("Xfer") << "Requesting " << mName << LL_ENDL; - - if (mBuffer) - { - delete[] mBuffer; - mBuffer = NULL; - } - - mBuffer = new char[LL_MAX_XFER_FILE_BUFFER]; - - mBufferLength = 0; - mPacketNum = 0; - mTempID.generate(); - mDeleteTempFile = TRUE; - mStatus = e_LL_XFER_PENDING; - return retval; -} - -////////////////////////////////////////////////////////// - -S32 LLXfer_VFile::startDownload() -{ - S32 retval = 0; // presume success - - // Don't need to create the file here, it will happen when data arrives - - gMessageSystem->newMessageFast(_PREHASH_RequestXfer); - gMessageSystem->nextBlockFast(_PREHASH_XferID); - gMessageSystem->addU64Fast(_PREHASH_ID, mID); - gMessageSystem->addStringFast(_PREHASH_Filename, ""); - gMessageSystem->addU8("FilePath", (U8) LL_PATH_NONE); - gMessageSystem->addBOOL("DeleteOnCompletion", FALSE); - gMessageSystem->addBOOL("UseBigPackets", BOOL(mChunkSize == LL_XFER_LARGE_PAYLOAD)); - gMessageSystem->addUUIDFast(_PREHASH_VFileID, mRemoteID); - gMessageSystem->addS16Fast(_PREHASH_VFileType, (S16)mType); - - gMessageSystem->sendReliable(mRemoteHost); - mStatus = e_LL_XFER_IN_PROGRESS; - - return (retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) -{ - S32 retval = LL_ERR_NOERR; // presume success - - mRemoteHost = remote_host; - mID = xfer_id; - mPacketNum = -1; - -// cout << "Sending file: " << mLocalFilename << endl; - - delete [] mBuffer; - mBuffer = new char[LL_MAX_XFER_FILE_BUFFER]; - - mBufferLength = 0; - mBufferStartOffset = 0; - - delete mVFile; - mVFile = NULL; - if(LLFileSystem::getExists(mLocalID, mType)) - { - mVFile = new LLFileSystem(mLocalID, mType, LLFileSystem::READ); - - if (mVFile->getSize() <= 0) - { - LL_WARNS("Xfer") << "LLXfer_VFile::startSend() cache file " << mLocalID << "." << LLAssetType::lookup(mType) - << " has unexpected file size of " << mVFile->getSize() << LL_ENDL; - delete mVFile; - mVFile = NULL; - - return LL_ERR_FILE_EMPTY; - } - } - - if(mVFile) - { - setXferSize(mVFile->getSize()); - mStatus = e_LL_XFER_PENDING; - } - else - { - LL_WARNS("Xfer") << "LLXfer_VFile::startSend() can't read cache file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; - retval = LL_ERR_FILE_NOT_FOUND; - } - - return (retval); -} - -/////////////////////////////////////////////////////////// - -void LLXfer_VFile::closeFileHandle() -{ - if (mVFile) - { - delete mVFile; - mVFile = NULL; - } -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_VFile::reopenFileHandle() -{ - S32 retval = LL_ERR_NOERR; // presume success - - if (mVFile == NULL) - { - if (LLFileSystem::getExists(mLocalID, mType)) - { - mVFile = new LLFileSystem(mLocalID, mType, LLFileSystem::READ); - } - else - { - LL_WARNS("Xfer") << "LLXfer_VFile::reopenFileHandle() can't read cache file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; - retval = LL_ERR_FILE_NOT_FOUND; - } - } - - return retval; -} - - -/////////////////////////////////////////////////////////// - -void LLXfer_VFile::setXferSize (S32 xfer_size) -{ - LLXfer::setXferSize(xfer_size); - - // Don't do this on the server side, where we have a persistent mVFile - // It would be nice if LLXFers could tell which end of the pipe they were - if (! mVFile) - { - LLFileSystem file(mTempID, mType, LLFileSystem::APPEND); - } -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_VFile::getMaxBufferSize () -{ - return(LL_MAX_XFER_FILE_BUFFER); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_VFile::suck(S32 start_position) -{ - S32 retval = 0; - - if (mVFile) - { - // grab a buffer from the right place in the file - if (! mVFile->seek(start_position, 0)) - { - LL_WARNS("Xfer") << "VFile Xfer Can't seek to position " << start_position << ", file length " << mVFile->getSize() << LL_ENDL; - LL_WARNS("Xfer") << "While sending file " << mLocalID << LL_ENDL; - return -1; - } - - if (mVFile->read((U8*)mBuffer, LL_MAX_XFER_FILE_BUFFER)) /* Flawfinder : ignore */ - { - mBufferLength = mVFile->getLastBytesRead(); - mBufferStartOffset = start_position; - - mBufferContainsEOF = mVFile->eof(); - } - else - { - retval = -1; - } - } - else - { - retval = -1; - } - - return (retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_VFile::flush() -{ - S32 retval = 0; - if (mBufferLength) - { - LLFileSystem file(mTempID, mType, LLFileSystem::APPEND); - - file.write((U8*)mBuffer, mBufferLength); - - mBufferLength = 0; - } - return (retval); -} - -/////////////////////////////////////////////////////////// - -S32 LLXfer_VFile::processEOF() -{ - S32 retval = 0; - mStatus = e_LL_XFER_COMPLETE; - - flush(); - - if (!mCallbackResult) - { - if (LLFileSystem::getExists(mTempID, mType)) - { - LLFileSystem file(mTempID, mType, LLFileSystem::WRITE); - if (!file.rename(mLocalID, mType)) - { - LL_WARNS("Xfer") << "Cache rename of temp file failed: unable to rename " << mTempID << " to " << mLocalID << LL_ENDL; - } - else - { - // Rename worked: the original file is gone. Clear mDeleteTempFile - // so we don't attempt to delete the file in cleanup() - mDeleteTempFile = FALSE; - } - } - else - { - LL_WARNS("Xfer") << "LLXfer_VFile::processEOF() can't open for renaming cache file " << mTempID << "." << LLAssetType::lookup(mType) << LL_ENDL; - } - } - - if (mVFile) - { - delete mVFile; - mVFile = NULL; - } - - retval = LLXfer::processEOF(); - - return(retval); -} - -//////////////////////////////////////////////////////////// - -BOOL LLXfer_VFile::matchesLocalFile(const LLUUID &id, LLAssetType::EType type) -{ - return (id == mLocalID && type == mType); -} - -////////////////////////////////////////////////////////// - -BOOL LLXfer_VFile::matchesRemoteFile(const LLUUID &id, LLAssetType::EType type) -{ - return (id == mRemoteID && type == mType); -} - -////////////////////////////////////////////////////////// - -std::string LLXfer_VFile::getFileName() -{ - return mName; -} - -////////////////////////////////////////////////////////// - -// hacky - doesn't matter what this is -// as long as it's different from the other classes -U32 LLXfer_VFile::getXferTypeTag() -{ - return LLXfer::XFER_VFILE; -} - +/**
+ * @file llxfer_vfile.cpp
+ * @brief implementation of LLXfer_VFile class for a single xfer (vfile).
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "linden_common.h"
+
+#include "llxfer_vfile.h"
+#include "lluuid.h"
+#include "llerror.h"
+#include "llmath.h"
+#include "llfilesystem.h"
+#include "lldir.h"
+
+// size of chunks read from/written to disk
+const U32 LL_MAX_XFER_FILE_BUFFER = 65536;
+
+///////////////////////////////////////////////////////////
+
+LLXfer_VFile::LLXfer_VFile ()
+: LLXfer(-1)
+{
+ init(LLUUID::null, LLAssetType::AT_NONE);
+}
+
+LLXfer_VFile::LLXfer_VFile (const LLUUID &local_id, LLAssetType::EType type)
+: LLXfer(-1)
+{
+ init(local_id, type);
+}
+
+///////////////////////////////////////////////////////////
+
+LLXfer_VFile::~LLXfer_VFile ()
+{
+ cleanup();
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_VFile::init (const LLUUID &local_id, LLAssetType::EType type)
+{
+ mLocalID = local_id;
+ mType = type;
+
+ mVFile = NULL;
+
+ std::string id_string;
+ mLocalID.toString(id_string);
+
+ mName = llformat("VFile %s:%s", id_string.c_str(), LLAssetType::lookup(mType));
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_VFile::cleanup ()
+{
+ if (mTempID.notNull() &&
+ mDeleteTempFile)
+ {
+ if (LLFileSystem::getExists(mTempID, mType))
+ {
+ LLFileSystem file(mTempID, mType, LLFileSystem::WRITE);
+ file.remove();
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "LLXfer_VFile::cleanup() can't open to delete cache file " << mTempID << "." << LLAssetType::lookup(mType)
+ << ", mRemoteID is " << mRemoteID << LL_ENDL;
+ }
+ }
+
+ delete mVFile;
+ mVFile = NULL;
+
+ LLXfer::cleanup();
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_VFile::initializeRequest(U64 xfer_id,
+ const LLUUID& local_id,
+ const LLUUID& remote_id,
+ LLAssetType::EType type,
+ const LLHost& remote_host,
+ void (*callback)(void**,S32,LLExtStat),
+ void** user_data)
+{
+ S32 retval = 0; // presume success
+
+ mRemoteHost = remote_host;
+
+ mLocalID = local_id;
+ mRemoteID = remote_id;
+ mType = type;
+
+ mID = xfer_id;
+ mCallback = callback;
+ mCallbackDataHandle = user_data;
+ mCallbackResult = LL_ERR_NOERR;
+
+ std::string id_string;
+ mLocalID.toString(id_string);
+
+ mName = llformat("VFile %s:%s", id_string.c_str(), LLAssetType::lookup(mType));
+
+ LL_INFOS("Xfer") << "Requesting " << mName << LL_ENDL;
+
+ if (mBuffer)
+ {
+ delete[] mBuffer;
+ mBuffer = NULL;
+ }
+
+ mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
+
+ mBufferLength = 0;
+ mPacketNum = 0;
+ mTempID.generate();
+ mDeleteTempFile = true;
+ mStatus = e_LL_XFER_PENDING;
+ return retval;
+}
+
+//////////////////////////////////////////////////////////
+
+S32 LLXfer_VFile::startDownload()
+{
+ S32 retval = 0; // presume success
+
+ // Don't need to create the file here, it will happen when data arrives
+
+ gMessageSystem->newMessageFast(_PREHASH_RequestXfer);
+ gMessageSystem->nextBlockFast(_PREHASH_XferID);
+ gMessageSystem->addU64Fast(_PREHASH_ID, mID);
+ gMessageSystem->addStringFast(_PREHASH_Filename, "");
+ gMessageSystem->addU8("FilePath", (U8) LL_PATH_NONE);
+ gMessageSystem->addBOOL("DeleteOnCompletion", false);
+ gMessageSystem->addBOOL("UseBigPackets", mChunkSize == LL_XFER_LARGE_PAYLOAD);
+ gMessageSystem->addUUIDFast(_PREHASH_VFileID, mRemoteID);
+ gMessageSystem->addS16Fast(_PREHASH_VFileType, (S16)mType);
+
+ gMessageSystem->sendReliable(mRemoteHost);
+ mStatus = e_LL_XFER_IN_PROGRESS;
+
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host)
+{
+ S32 retval = LL_ERR_NOERR; // presume success
+
+ mRemoteHost = remote_host;
+ mID = xfer_id;
+ mPacketNum = -1;
+
+// cout << "Sending file: " << mLocalFilename << endl;
+
+ delete [] mBuffer;
+ mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
+
+ mBufferLength = 0;
+ mBufferStartOffset = 0;
+
+ delete mVFile;
+ mVFile = NULL;
+ if(LLFileSystem::getExists(mLocalID, mType))
+ {
+ mVFile = new LLFileSystem(mLocalID, mType, LLFileSystem::READ);
+
+ if (mVFile->getSize() <= 0)
+ {
+ LL_WARNS("Xfer") << "LLXfer_VFile::startSend() cache file " << mLocalID << "." << LLAssetType::lookup(mType)
+ << " has unexpected file size of " << mVFile->getSize() << LL_ENDL;
+ delete mVFile;
+ mVFile = NULL;
+
+ return LL_ERR_FILE_EMPTY;
+ }
+ }
+
+ if(mVFile)
+ {
+ setXferSize(mVFile->getSize());
+ mStatus = e_LL_XFER_PENDING;
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "LLXfer_VFile::startSend() can't read cache file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL;
+ retval = LL_ERR_FILE_NOT_FOUND;
+ }
+
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_VFile::closeFileHandle()
+{
+ if (mVFile)
+ {
+ delete mVFile;
+ mVFile = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_VFile::reopenFileHandle()
+{
+ S32 retval = LL_ERR_NOERR; // presume success
+
+ if (mVFile == NULL)
+ {
+ if (LLFileSystem::getExists(mLocalID, mType))
+ {
+ mVFile = new LLFileSystem(mLocalID, mType, LLFileSystem::READ);
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "LLXfer_VFile::reopenFileHandle() can't read cache file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL;
+ retval = LL_ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ return retval;
+}
+
+
+///////////////////////////////////////////////////////////
+
+void LLXfer_VFile::setXferSize (S32 xfer_size)
+{
+ LLXfer::setXferSize(xfer_size);
+
+ // Don't do this on the server side, where we have a persistent mVFile
+ // It would be nice if LLXFers could tell which end of the pipe they were
+ if (! mVFile)
+ {
+ LLFileSystem file(mTempID, mType, LLFileSystem::APPEND);
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_VFile::getMaxBufferSize ()
+{
+ return(LL_MAX_XFER_FILE_BUFFER);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_VFile::suck(S32 start_position)
+{
+ S32 retval = 0;
+
+ if (mVFile)
+ {
+ // grab a buffer from the right place in the file
+ if (! mVFile->seek(start_position, 0))
+ {
+ LL_WARNS("Xfer") << "VFile Xfer Can't seek to position " << start_position << ", file length " << mVFile->getSize() << LL_ENDL;
+ LL_WARNS("Xfer") << "While sending file " << mLocalID << LL_ENDL;
+ return -1;
+ }
+
+ if (mVFile->read((U8*)mBuffer, LL_MAX_XFER_FILE_BUFFER)) /* Flawfinder : ignore */
+ {
+ mBufferLength = mVFile->getLastBytesRead();
+ mBufferStartOffset = start_position;
+
+ mBufferContainsEOF = mVFile->eof();
+ }
+ else
+ {
+ retval = -1;
+ }
+ }
+ else
+ {
+ retval = -1;
+ }
+
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_VFile::flush()
+{
+ S32 retval = 0;
+ if (mBufferLength)
+ {
+ LLFileSystem file(mTempID, mType, LLFileSystem::APPEND);
+
+ file.write((U8*)mBuffer, mBufferLength);
+
+ mBufferLength = 0;
+ }
+ return (retval);
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXfer_VFile::processEOF()
+{
+ S32 retval = 0;
+ mStatus = e_LL_XFER_COMPLETE;
+
+ flush();
+
+ if (!mCallbackResult)
+ {
+ if (LLFileSystem::getExists(mTempID, mType))
+ {
+ LLFileSystem file(mTempID, mType, LLFileSystem::WRITE);
+ if (!file.rename(mLocalID, mType))
+ {
+ LL_WARNS("Xfer") << "Cache rename of temp file failed: unable to rename " << mTempID << " to " << mLocalID << LL_ENDL;
+ }
+ else
+ {
+ // Rename worked: the original file is gone. Clear mDeleteTempFile
+ // so we don't attempt to delete the file in cleanup()
+ mDeleteTempFile = false;
+ }
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "LLXfer_VFile::processEOF() can't open for renaming cache file " << mTempID << "." << LLAssetType::lookup(mType) << LL_ENDL;
+ }
+ }
+
+ if (mVFile)
+ {
+ delete mVFile;
+ mVFile = NULL;
+ }
+
+ retval = LLXfer::processEOF();
+
+ return(retval);
+}
+
+////////////////////////////////////////////////////////////
+
+bool LLXfer_VFile::matchesLocalFile(const LLUUID &id, LLAssetType::EType type)
+{
+ return (id == mLocalID && type == mType);
+}
+
+//////////////////////////////////////////////////////////
+
+bool LLXfer_VFile::matchesRemoteFile(const LLUUID &id, LLAssetType::EType type)
+{
+ return (id == mRemoteID && type == mType);
+}
+
+//////////////////////////////////////////////////////////
+
+std::string LLXfer_VFile::getFileName()
+{
+ return mName;
+}
+
+//////////////////////////////////////////////////////////
+
+// hacky - doesn't matter what this is
+// as long as it's different from the other classes
+U32 LLXfer_VFile::getXferTypeTag()
+{
+ return LLXfer::XFER_VFILE;
+}
+
diff --git a/indra/llmessage/llxfer_vfile.h b/indra/llmessage/llxfer_vfile.h index 5ab767b052..33fb63f68c 100644 --- a/indra/llmessage/llxfer_vfile.h +++ b/indra/llmessage/llxfer_vfile.h @@ -1,91 +1,91 @@ -/** - * @file llxfer_vfile.h - * @brief definition of LLXfer_VFile class for a single xfer_vfile. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#ifndef LL_LLXFER_VFILE_H -#define LL_LLXFER_VFILE_H - -#include "llxfer.h" -#include "llassetstorage.h" - -class LLFileSystem; - -class LLXfer_VFile : public LLXfer -{ - protected: - LLUUID mLocalID; - LLUUID mRemoteID; - LLUUID mTempID; - LLAssetType::EType mType; - - LLFileSystem *mVFile; - - std::string mName; - - BOOL mDeleteTempFile; - - public: - LLXfer_VFile (); - LLXfer_VFile (const LLUUID &local_id, LLAssetType::EType type); - virtual ~LLXfer_VFile(); - - virtual void init(const LLUUID &local_id, LLAssetType::EType type); - virtual void cleanup(); - - virtual S32 initializeRequest(U64 xfer_id, - const LLUUID &local_id, - const LLUUID &remote_id, - const LLAssetType::EType type, - const LLHost &remote_host, - void (*callback)(void **,S32,LLExtStat), - void **user_data); - virtual S32 startDownload(); - - virtual S32 processEOF(); - - virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); - virtual void closeFileHandle(); - virtual S32 reopenFileHandle(); - - virtual S32 suck(S32 start_position); - virtual S32 flush(); - - virtual BOOL matchesLocalFile(const LLUUID &id, LLAssetType::EType type); - virtual BOOL matchesRemoteFile(const LLUUID &id, LLAssetType::EType type); - - virtual void setXferSize(S32 xfer_size); - virtual S32 getMaxBufferSize(); - - virtual U32 getXferTypeTag(); - - virtual std::string getFileName(); -}; - -#endif - - - - - +/**
+ * @file llxfer_vfile.h
+ * @brief definition of LLXfer_VFile class for a single xfer_vfile.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLXFER_VFILE_H
+#define LL_LLXFER_VFILE_H
+
+#include "llxfer.h"
+#include "llassetstorage.h"
+
+class LLFileSystem;
+
+class LLXfer_VFile : public LLXfer
+{
+ protected:
+ LLUUID mLocalID;
+ LLUUID mRemoteID;
+ LLUUID mTempID;
+ LLAssetType::EType mType;
+
+ LLFileSystem *mVFile;
+
+ std::string mName;
+
+ bool mDeleteTempFile;
+
+ public:
+ LLXfer_VFile ();
+ LLXfer_VFile (const LLUUID &local_id, LLAssetType::EType type);
+ virtual ~LLXfer_VFile();
+
+ virtual void init(const LLUUID &local_id, LLAssetType::EType type);
+ virtual void cleanup();
+
+ virtual S32 initializeRequest(U64 xfer_id,
+ const LLUUID &local_id,
+ const LLUUID &remote_id,
+ const LLAssetType::EType type,
+ const LLHost &remote_host,
+ void (*callback)(void **,S32,LLExtStat),
+ void **user_data);
+ virtual S32 startDownload();
+
+ virtual S32 processEOF();
+
+ virtual S32 startSend(U64 xfer_id, const LLHost &remote_host);
+ virtual void closeFileHandle();
+ virtual S32 reopenFileHandle();
+
+ virtual S32 suck(S32 start_position);
+ virtual S32 flush();
+
+ virtual bool matchesLocalFile(const LLUUID &id, LLAssetType::EType type);
+ virtual bool matchesRemoteFile(const LLUUID &id, LLAssetType::EType type);
+
+ virtual void setXferSize(S32 xfer_size);
+ virtual S32 getMaxBufferSize();
+
+ virtual U32 getXferTypeTag();
+
+ virtual std::string getFileName();
+};
+
+#endif
+
+
+
+
+
diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index ea1fe0a963..d4d12b8ff2 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -1,1326 +1,1326 @@ -/** - * @file llxfermanager.cpp - * @brief implementation of LLXferManager class for a collection of xfers - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "llxfermanager.h" - -#include "llxfer.h" -#include "llxfer_file.h" -#include "llxfer_mem.h" -#include "llxfer_vfile.h" - -#include "llerror.h" -#include "lluuid.h" -#include "u64.h" - -const F32 LL_XFER_REGISTRATION_TIMEOUT = 60.0f; // timeout if a registered transfer hasn't been requested in 60 seconds -const F32 LL_PACKET_TIMEOUT = 3.0f; // packet timeout at 3 s -const S32 LL_PACKET_RETRY_LIMIT = 10; // packet retransmission limit - -const S32 LL_DEFAULT_MAX_SIMULTANEOUS_XFERS = 10; -const S32 LL_DEFAULT_MAX_REQUEST_FIFO_XFERS = 1000; - -// Kills the connection if a viewer download queue hits this many requests backed up -// Also set in simulator.xml at "hard_limit_outgoing_xfers_per_circuit" -const S32 LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS = 500; - -// Use this to show sending some ConfirmXferPacket messages -//#define LL_XFER_PROGRESS_MESSAGES 1 - -// Use this for lots of diagnostic spam -//#define LL_XFER_DIAGNOISTIC_LOGGING 1 - -/////////////////////////////////////////////////////////// - -LLXferManager::LLXferManager () -{ - init(); -} - -/////////////////////////////////////////////////////////// - -LLXferManager::~LLXferManager () -{ - cleanup(); -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::init() -{ - cleanup(); - - setMaxOutgoingXfersPerCircuit(LL_DEFAULT_MAX_SIMULTANEOUS_XFERS); - setHardLimitOutgoingXfersPerCircuit(LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS); - setMaxIncomingXfers(LL_DEFAULT_MAX_REQUEST_FIFO_XFERS); - - // Turn on or off ack throttling - mUseAckThrottling = FALSE; - setAckThrottleBPS(100000); -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::cleanup () -{ - for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer()); - mOutgoingHosts.clear(); - - for_each(mSendList.begin(), mSendList.end(), DeletePointer()); - mSendList.clear(); - - for_each(mReceiveList.begin(), mReceiveList.end(), DeletePointer()); - mReceiveList.clear(); -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::setMaxIncomingXfers(S32 max_num) -{ - mMaxIncomingXfers = max_num; -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::setMaxOutgoingXfersPerCircuit(S32 max_num) -{ - mMaxOutgoingXfersPerCircuit = max_num; -} - -void LLXferManager::setHardLimitOutgoingXfersPerCircuit(S32 max_num) -{ - mHardLimitOutgoingXfersPerCircuit = max_num; -} - -void LLXferManager::setUseAckThrottling(const BOOL use) -{ - mUseAckThrottling = use; -} - -void LLXferManager::setAckThrottleBPS(const F32 bps) -{ - // Let's figure out the min we can set based on the ack retry rate - // and number of simultaneous. - - // Assuming we're running as slow as possible, this is the lowest ack - // rate we can use. - F32 min_bps = (1000.f * 8.f* mMaxIncomingXfers) / LL_PACKET_TIMEOUT; - - // Set - F32 actual_rate = llmax(min_bps*1.1f, bps); - LL_DEBUGS("AppInit") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL; - LL_DEBUGS("AppInit") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL; - #ifdef LL_XFER_DIAGNOISTIC_LOGGING - LL_INFOS("Xfer") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL; - LL_INFOS("Xfer") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL; - #endif // LL_XFER_DIAGNOISTIC_LOGGING - - mAckThrottle.setRate(actual_rate); -} - - -/////////////////////////////////////////////////////////// - -void LLXferManager::updateHostStatus() -{ - // Clear the outgoing host list - for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer()); - mOutgoingHosts.clear(); - - // Loop through all outgoing xfers and re-build mOutgoingHosts - for (xfer_list_t::iterator send_iter = mSendList.begin(); - send_iter != mSendList.end(); ++send_iter) - { - LLHostStatus *host_statusp = NULL; - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) - { - if ((*iter)->mHost == (*send_iter)->mRemoteHost) - { // Already have this host - host_statusp = *iter; - break; - } - } - if (!host_statusp) - { // Don't have this host, so add it - host_statusp = new LLHostStatus(); - if (host_statusp) - { - host_statusp->mHost = (*send_iter)->mRemoteHost; - mOutgoingHosts.push_front(host_statusp); - } - } - if (host_statusp) - { // Do the accounting - if ((*send_iter)->mStatus == e_LL_XFER_PENDING) - { - host_statusp->mNumPending++; - } - else if ((*send_iter)->mStatus == e_LL_XFER_IN_PROGRESS) - { - host_statusp->mNumActive++; - } - } - } - -#ifdef LL_XFER_DIAGNOISTIC_LOGGING - for (xfer_list_t::iterator send_iter = mSendList.begin(); - send_iter != mSendList.end(); ++send_iter) - { - LLXfer * xferp = *send_iter; - LL_INFOS("Xfer") << "xfer to host " << xferp->mRemoteHost - << " is " << xferp->mXferSize << " bytes" - << ", status " << (S32)(xferp->mStatus) - << ", waiting for ACK: " << (S32)(xferp->mWaitingForACK) - << " in frame " << (S32) LLFrameTimer::getFrameCount() - << LL_ENDL; - } - - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) - { - LL_INFOS("Xfer") << "LLXfer host " << (*iter)->mHost.getIPandPort() - << " has " << (*iter)->mNumActive - << " active, " << (*iter)->mNumPending - << " pending" - << " in frame " << (S32) LLFrameTimer::getFrameCount() - << LL_ENDL; - } -#endif // LL_XFER_DIAGNOISTIC_LOGGING - -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::printHostStatus() -{ - LLHostStatus *host_statusp = NULL; - if (!mOutgoingHosts.empty()) - { - LL_INFOS("Xfer") << "Outgoing Xfers:" << LL_ENDL; - - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) - { - host_statusp = *iter; - LL_INFOS("Xfer") << " " << host_statusp->mHost << " active: " << host_statusp->mNumActive << " pending: " << host_statusp->mNumPending << LL_ENDL; - } - } -} - -/////////////////////////////////////////////////////////// - -LLXfer * LLXferManager::findXferByID(U64 id, xfer_list_t & xfer_list) -{ - for (xfer_list_t::iterator iter = xfer_list.begin(); - iter != xfer_list.end(); - ++iter) - { - if ((*iter)->mID == id) - { - return(*iter); - } - } - return(NULL); -} - - -/////////////////////////////////////////////////////////// - -// WARNING: this invalidates iterators from xfer_list -void LLXferManager::removeXfer(LLXfer *delp, xfer_list_t & xfer_list) -{ - if (delp) - { - std::string direction = "send"; - if (&xfer_list == &mReceiveList) - { - direction = "receive"; - } - - // This assumes that delp will occur in the list once at most - // Find the pointer in the list - for (xfer_list_t::iterator iter = xfer_list.begin(); - iter != xfer_list.end(); - ++iter) - { - if ((*iter) == delp) - { - LL_DEBUGS("Xfer") << "Deleting xfer to host " << (*iter)->mRemoteHost - << " of " << (*iter)->mXferSize << " bytes" - << ", status " << (S32)((*iter)->mStatus) - << " from the " << direction << " list" - << LL_ENDL; - - xfer_list.erase(iter); - delete (delp); - break; - } - } - } -} - -/////////////////////////////////////////////////////////// - -LLHostStatus * LLXferManager::findHostStatus(const LLHost &host) -{ - LLHostStatus *host_statusp = NULL; - - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) - { - host_statusp = *iter; - if (host_statusp->mHost == host) - { - return (host_statusp); - } - } - return 0; -} - -/////////////////////////////////////////////////////////// - -S32 LLXferManager::numPendingXfers(const LLHost &host) -{ - LLHostStatus *host_statusp = findHostStatus(host); - if (host_statusp) - { - return host_statusp->mNumPending; - } - return 0; -} - -/////////////////////////////////////////////////////////// - -S32 LLXferManager::numActiveXfers(const LLHost &host) -{ - LLHostStatus *host_statusp = findHostStatus(host); - if (host_statusp) - { - return host_statusp->mNumActive; - } - return 0; -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::changeNumActiveXfers(const LLHost &host, S32 delta) -{ - LLHostStatus *host_statusp = NULL; - - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) - { - host_statusp = *iter; - if (host_statusp->mHost == host) - { - host_statusp->mNumActive += delta; - } - } -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::registerCallbacks(LLMessageSystem *msgsystem) -{ - msgsystem->setHandlerFuncFast(_PREHASH_ConfirmXferPacket, process_confirm_packet, NULL); - msgsystem->setHandlerFuncFast(_PREHASH_RequestXfer, process_request_xfer, NULL); - msgsystem->setHandlerFuncFast(_PREHASH_SendXferPacket, continue_file_receive, NULL); - msgsystem->setHandlerFuncFast(_PREHASH_AbortXfer, process_abort_xfer, NULL); -} - -/////////////////////////////////////////////////////////// - -U64 LLXferManager::getNextID () -{ - LLUUID a_guid; - - a_guid.generate(); - - - return(*((U64*)(a_guid.mData))); -} - -/////////////////////////////////////////////////////////// - -S32 LLXferManager::encodePacketNum(S32 packet_num, BOOL is_EOF) -{ - if (is_EOF) - { - packet_num |= 0x80000000; - } - return packet_num; -} - -/////////////////////////////////////////////////////////// - -S32 LLXferManager::decodePacketNum(S32 packet_num) -{ - return(packet_num & 0x0FFFFFFF); -} - -/////////////////////////////////////////////////////////// - -BOOL LLXferManager::isLastPacket(S32 packet_num) -{ - return(packet_num & 0x80000000); -} - -/////////////////////////////////////////////////////////// - -U64 LLXferManager::requestFile(const std::string& local_filename, - const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void**,S32,LLExtStat), - void** user_data, - BOOL is_priority, - BOOL use_big_packets) -{ - LLXfer_File* file_xfer_p = NULL; - - // First check to see if it's already requested - for (xfer_list_t::iterator iter = mReceiveList.begin(); - iter != mReceiveList.end(); ++iter) - { - if ((*iter)->getXferTypeTag() == LLXfer::XFER_FILE) - { - file_xfer_p = (LLXfer_File*)(*iter); - if (file_xfer_p->matchesLocalFilename(local_filename) - && file_xfer_p->matchesRemoteFilename(remote_filename, remote_path) - && (remote_host == file_xfer_p->mRemoteHost) - && (callback == file_xfer_p->mCallback) - && (user_data == file_xfer_p->mCallbackDataHandle)) - { - // Already have the request (already in progress) - return (*iter)->mID; - } - } - } - - U64 xfer_id = 0; - - S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1; - file_xfer_p = new LLXfer_File(chunk_size); - if (file_xfer_p) - { - addToList(file_xfer_p, mReceiveList, is_priority); - - // Remove any file by the same name that happens to be lying - // around. - // Note: according to AaronB, this is here to deal with locks on files that were - // in transit during a crash, - if(delete_remote_on_completion && - (remote_filename.substr(remote_filename.length()-4) == ".tmp")) - { - LLFile::remove(local_filename, ENOENT); - } - xfer_id = getNextID(); - file_xfer_p->initializeRequest( - xfer_id, - local_filename, - remote_filename, - remote_path, - remote_host, - delete_remote_on_completion, - callback,user_data); - startPendingDownloads(); - } - else - { - LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL; - } - return xfer_id; -} - -void LLXferManager::requestVFile(const LLUUID& local_id, - const LLUUID& remote_id, - LLAssetType::EType type, - const LLHost& remote_host, - void (*callback)(void**,S32,LLExtStat), - void** user_data, - BOOL is_priority) -{ - LLXfer_VFile * xfer_p = NULL; - - for (xfer_list_t::iterator iter = mReceiveList.begin(); - iter != mReceiveList.end(); ++iter) - { // Find any matching existing requests - if ((*iter)->getXferTypeTag() == LLXfer::XFER_VFILE) - { - xfer_p = (LLXfer_VFile*) (*iter); - if (xfer_p->matchesLocalFile(local_id, type) - && xfer_p->matchesRemoteFile(remote_id, type) - && (remote_host == xfer_p->mRemoteHost) - && (callback == xfer_p->mCallback) - && (user_data == xfer_p->mCallbackDataHandle)) - - { // Have match, don't add a duplicate - #ifdef LL_XFER_DIAGNOISTIC_LOGGING - LL_INFOS("Xfer") << "Dropping duplicate xfer request for " << remote_id - << " on " << remote_host.getIPandPort() - << " local id " << local_id - << LL_ENDL; - #endif // LL_XFER_DIAGNOISTIC_LOGGING - - return; - } - } - } - - xfer_p = new LLXfer_VFile(); - if (xfer_p) - { - #ifdef LL_XFER_DIAGNOISTIC_LOGGING - LL_INFOS("Xfer") << "Starting file xfer for " << remote_id - << " type " << LLAssetType::lookupHumanReadable(type) - << " from " << xfer_p->mRemoteHost.getIPandPort() - << ", local id " << local_id - << LL_ENDL; - #endif // LL_XFER_DIAGNOISTIC_LOGGING - - addToList(xfer_p, mReceiveList, is_priority); - ((LLXfer_VFile *)xfer_p)->initializeRequest(getNextID(), - local_id, - remote_id, - type, - remote_host, - callback, - user_data); - startPendingDownloads(); - } - else - { - LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL; - } - -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user_data*/) -{ - // there's sometimes an extra 4 bytes added to an xfer payload - const S32 BUF_SIZE = LL_XFER_LARGE_PAYLOAD + 4; - char fdata_buf[BUF_SIZE]; /* Flawfinder : ignore */ - S32 fdata_size; - U64 id; - S32 packetnum; - LLXfer * xferp; - - mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); - mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetnum); - - fdata_size = mesgsys->getSizeFast(_PREHASH_DataPacket,_PREHASH_Data); - if (fdata_size < 0 || - fdata_size > BUF_SIZE) - { - char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_WARNS("Xfer") << "Received invalid xfer data size of " << fdata_size - << " in packet number " << packetnum - << " from " << mesgsys->getSender() - << " for xfer id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) - << LL_ENDL; - return; - } - mesgsys->getBinaryDataFast(_PREHASH_DataPacket, _PREHASH_Data, fdata_buf, fdata_size, 0, BUF_SIZE); - - xferp = findXferByID(id, mReceiveList); - if (!xferp) - { - char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_WARNS("Xfer") << "received xfer data from " << mesgsys->getSender() - << " for non-existent xfer id: " - << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << LL_ENDL; - return; - } - - S32 xfer_size; - - if (decodePacketNum(packetnum) != xferp->mPacketNum) // is the packet different from what we were expecting? - { - // confirm it if it was a resend of the last one, since the confirmation might have gotten dropped - if (decodePacketNum(packetnum) == (xferp->mPacketNum - 1)) - { - LL_INFOS("Xfer") << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << LL_ENDL; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender()); - } - else - { - LL_INFOS("Xfer") << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << LL_ENDL; - } - return; - } - - S32 result = 0; - - if (xferp->mPacketNum == 0) // first packet has size encoded as additional S32 at beginning of data - { - ntohmemcpy(&xfer_size,fdata_buf,MVT_S32,sizeof(S32)); - -// do any necessary things on first packet ie. allocate memory - xferp->setXferSize(xfer_size); - - // adjust buffer start and size - result = xferp->receiveData(&(fdata_buf[sizeof(S32)]),fdata_size-(sizeof(S32))); - } - else - { - result = xferp->receiveData(fdata_buf,fdata_size); - } - - if (result == LL_ERR_CANNOT_OPEN_FILE) - { - xferp->abort(LL_ERR_CANNOT_OPEN_FILE); - removeXfer(xferp,mReceiveList); - startPendingDownloads(); - return; - } - - xferp->mPacketNum++; // expect next packet - - if (!mUseAckThrottling) - { - // No throttling, confirm right away - sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender()); - } - else - { - // Throttling, put on queue to be confirmed later. - LLXferAckInfo ack_info; - ack_info.mID = id; - ack_info.mPacketNum = decodePacketNum(packetnum); - ack_info.mRemoteHost = mesgsys->getSender(); - mXferAckQueue.push_back(ack_info); - } - - if (isLastPacket(packetnum)) - { - xferp->processEOF(); - removeXfer(xferp,mReceiveList); - startPendingDownloads(); - } -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host) -{ -#ifdef LL_XFER_PROGRESS_MESSAGES - if (!(packetnum % 50)) - { - cout << "confirming xfer packet #" << packetnum << endl; - } -#endif - mesgsys->newMessageFast(_PREHASH_ConfirmXferPacket); - mesgsys->nextBlockFast(_PREHASH_XferID); - mesgsys->addU64Fast(_PREHASH_ID, id); - mesgsys->addU32Fast(_PREHASH_Packet, packetnum); - - // Ignore a circuit failure here, we'll catch it with another message - mesgsys->sendMessage(remote_host); -} - -/////////////////////////////////////////////////////////// - -static bool find_and_remove(std::multiset<std::string>& files, - const std::string& filename) -{ - std::multiset<std::string>::iterator ptr; - if ( (ptr = files.find(filename)) != files.end()) - { - //erase(filename) erases *all* entries with that key - files.erase(ptr); - return true; - } - return false; -} - -void LLXferManager::expectFileForRequest(const std::string& filename) -{ - mExpectedRequests.insert(filename); -} - -bool LLXferManager::validateFileForRequest(const std::string& filename) -{ - return find_and_remove(mExpectedRequests, filename); -} - -void LLXferManager::expectFileForTransfer(const std::string& filename) -{ - mExpectedTransfers.insert(filename); -} - -bool LLXferManager::validateFileForTransfer(const std::string& filename) -{ - return find_and_remove(mExpectedTransfers, filename); -} - -/* Present in fireengine, not used by viewer -void LLXferManager::expectVFileForRequest(const std::string& filename) -{ - mExpectedVFileRequests.insert(filename); -} - -bool LLXferManager::validateVFileForRequest(const std::string& filename) -{ - return find_and_remove(mExpectedVFileRequests, filename); -} - -void LLXferManager::expectVFileForTransfer(const std::string& filename) -{ - mExpectedVFileTransfers.insert(filename); -} - -bool LLXferManager::validateVFileForTransfer(const std::string& filename) -{ - return find_and_remove(mExpectedVFileTransfers, filename); -} -*/ - -static bool remove_prefix(std::string& filename, const std::string& prefix) -{ - if (std::equal(prefix.begin(), prefix.end(), filename.begin())) - { - filename = filename.substr(prefix.length()); - return true; - } - return false; -} - -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. 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("[0-9a-zA-Z_-]<1,46>\.tmp"); - if (len < 5 || len > 50) - { - return false; - } - for(size_t i=0; i<(len-4); ++i) - { - char c = filename[i]; - bool ok = isalnum(c) || '_'==c || '-'==c; - if (!ok) - { - return false; - } - } - return filename[len-4] == '.' - && filename[len-3] == 't' - && filename[len-2] == 'm' - && filename[len-1] == 'p'; -} - -void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user_data*/) -{ - - U64 id; - std::string local_filename; - ELLPath local_path = LL_PATH_NONE; - S32 result = LL_ERR_NOERR; - LLUUID uuid; - LLAssetType::EType type; - S16 type_s16; - BOOL b_use_big_packets; - - mesgsys->getBOOL("XferID", "UseBigPackets", b_use_big_packets); - - mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); - char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_INFOS("Xfer") << "xfer request id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) - << " to " << mesgsys->getSender() << LL_ENDL; - - mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, local_filename); - - { - U8 local_path_u8; - mesgsys->getU8("XferID", "FilePath", local_path_u8); - local_path = (ELLPath)local_path_u8; - } - - mesgsys->getUUIDFast(_PREHASH_XferID, _PREHASH_VFileID, uuid); - mesgsys->getS16Fast(_PREHASH_XferID, _PREHASH_VFileType, type_s16); - type = (LLAssetType::EType)type_s16; - - LLXfer *xferp; - - if (uuid != LLUUID::null) - { // Request for an asset - use a cache file - if(NULL == LLAssetType::lookup(type)) - { - LL_WARNS("Xfer") << "Invalid type for xfer request: " << uuid << ":" - << type_s16 << " to " << mesgsys->getSender() << LL_ENDL; - return; - } - - LL_INFOS("Xfer") << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << LL_ENDL; - - xferp = (LLXfer *)new LLXfer_VFile(uuid, type); - if (xferp) - { - mSendList.push_front(xferp); - result = xferp->startSend(id,mesgsys->getSender()); - } - else - { - LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL; - } - } - else if (!local_filename.empty()) - { // Was given a file name to send - // See DEV-21775 for detailed security issues - - if (local_path == LL_PATH_NONE) - { - // this handles legacy simulators that are passing objects - // by giving a filename that explicitly names the cache directory - static const std::string legacy_cache_prefix = "data/"; - if (remove_prefix(local_filename, legacy_cache_prefix)) - { - local_path = LL_PATH_CACHE; - } - } - - switch (local_path) - { - case LL_PATH_NONE: - if(!validateFileForTransfer(local_filename)) - { - LL_WARNS("Xfer") << "SECURITY: Unapproved filename '" << local_filename << LL_ENDL; - return; - } - break; - - case LL_PATH_CACHE: - if(!verify_cache_filename(local_filename)) - { - LL_WARNS("Xfer") << "SECURITY: Illegal cache filename '" << local_filename << LL_ENDL; - return; - } - break; - - default: - LL_WARNS("Xfer") << "SECURITY: Restricted file dir enum: " << (U32)local_path << LL_ENDL; - return; - } - - // If we want to use a special path (e.g. LL_PATH_CACHE), we want to make sure we create the - // proper expanded filename. - std::string expanded_filename; - if (local_path != LL_PATH_NONE) - { - expanded_filename = gDirUtilp->getExpandedFilename( local_path, local_filename ); - } - else - { - expanded_filename = local_filename; - } - LL_INFOS("Xfer") << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << LL_ENDL; - - BOOL delete_local_on_completion = FALSE; - mesgsys->getBOOL("XferID", "DeleteOnCompletion", delete_local_on_completion); - - // -1 chunk_size causes it to use the default - xferp = (LLXfer *)new LLXfer_File(expanded_filename, delete_local_on_completion, b_use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1); - - if (xferp) - { - mSendList.push_front(xferp); - result = xferp->startSend(id,mesgsys->getSender()); - } - else - { - LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL; - } - } - else - { // no uuid or filename - use the ID sent - char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_INFOS("Xfer") << "starting memory transfer: " - << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << " to " - << mesgsys->getSender() << LL_ENDL; - - xferp = findXferByID(id, mSendList); - - if (xferp) - { - result = xferp->startSend(id,mesgsys->getSender()); - } - else - { - LL_INFOS("Xfer") << "Warning: xfer ID " << U64_BUF << " not found." << LL_ENDL; - result = LL_ERR_FILE_NOT_FOUND; - } - } - - if (result) - { - if (xferp) - { - xferp->abort(result); - removeXfer(xferp, mSendList); - } - else // can happen with a memory transfer not found - { - LL_INFOS("Xfer") << "Aborting xfer to " << mesgsys->getSender() << " with error: " << result << LL_ENDL; - - mesgsys->newMessageFast(_PREHASH_AbortXfer); - mesgsys->nextBlockFast(_PREHASH_XferID); - mesgsys->addU64Fast(_PREHASH_ID, id); - mesgsys->addS32Fast(_PREHASH_Result, result); - - mesgsys->sendMessage(mesgsys->getSender()); - } - } - else if(xferp) - { - // Figure out how many transfers the host has requested - LLHostStatus *host_statusp = findHostStatus(xferp->mRemoteHost); - if (host_statusp) - { - if (host_statusp->mNumActive < mMaxOutgoingXfersPerCircuit) - { // Not many transfers in progress already, so start immediately - xferp->sendNextPacket(); - changeNumActiveXfers(xferp->mRemoteHost,1); - LL_DEBUGS("Xfer") << "Starting xfer ID " << U64_to_str(id) << " immediately" << LL_ENDL; - } - else if (mHardLimitOutgoingXfersPerCircuit == 0 || - (host_statusp->mNumActive + host_statusp->mNumPending) < mHardLimitOutgoingXfersPerCircuit) - { // Must close the file handle and wait for earlier ones to complete - LL_INFOS("Xfer") << " queueing xfer request id " << U64_to_str(id) << ", " - << host_statusp->mNumActive << " active and " - << host_statusp->mNumPending << " pending ahead of this one" - << LL_ENDL; - xferp->closeFileHandle(); // Close the file handle until we're ready to send again - } - else if (mHardLimitOutgoingXfersPerCircuit > 0) - { // Way too many requested ... it's time to stop being nice and kill the circuit - xferp->closeFileHandle(); // Close the file handle in any case - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(xferp->mRemoteHost); - if (cdp) - { - if (cdp->getTrusted()) - { // Trusted internal circuit - don't kill it - LL_WARNS("Xfer") << "Trusted circuit to " << xferp->mRemoteHost << " has too many xfer requests in the queue " - << host_statusp->mNumActive << " active and " - << host_statusp->mNumPending << " pending ahead of this one" - << LL_ENDL; - } - else - { // Untrusted circuit - time to stop messing around and kill it - LL_WARNS("Xfer") << "Killing circuit to " << xferp->mRemoteHost << " for having too many xfer requests in the queue " - << host_statusp->mNumActive << " active and " - << host_statusp->mNumPending << " pending ahead of this one" - << LL_ENDL; - gMessageSystem->disableCircuit(xferp->mRemoteHost); - } - } - else - { // WTF? Why can't we find a circuit? Try to kill it off - LL_WARNS("Xfer") << "Backlog with circuit to " << xferp->mRemoteHost << " with too many xfer requests in the queue " - << host_statusp->mNumActive << " active and " - << host_statusp->mNumPending << " pending ahead of this one" - << " but no LLCircuitData found???" - << LL_ENDL; - gMessageSystem->disableCircuit(xferp->mRemoteHost); - } - } - } - else - { - LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no LLHostStatus found for id " << U64_to_str(id) - << " host " << xferp->mRemoteHost << LL_ENDL; - } - } - else - { - LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no xfer found for id " << U64_to_str(id) << LL_ENDL; - } -} - -/////////////////////////////////////////////////////////// - -// Return true if host is in a transfer-flood sitation. Same check for both internal and external hosts -bool LLXferManager::isHostFlooded(const LLHost & host) -{ - bool flooded = false; - LLHostStatus *host_statusp = findHostStatus(host); - if (host_statusp) - { - flooded = (mHardLimitOutgoingXfersPerCircuit > 0 && - (host_statusp->mNumActive + host_statusp->mNumPending) >= (S32)(mHardLimitOutgoingXfersPerCircuit * 0.8f)); - } - - return flooded; -} - - -/////////////////////////////////////////////////////////// - -void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*user_data*/) -{ - U64 id = 0; - S32 packetNum = 0; - - mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); - mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetNum); - - LLXfer* xferp = findXferByID(id, mSendList); - if (xferp) - { -// cout << "confirmed packet #" << packetNum << " ping: "<< xferp->ACKTimer.getElapsedTimeF32() << endl; - xferp->mWaitingForACK = FALSE; - if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) - { - xferp->sendNextPacket(); - } - else - { - removeXfer(xferp, mSendList); - } - } -} - -/////////////////////////////////////////////////////////// - -// Called from LLMessageSystem::processAcks() -void LLXferManager::retransmitUnackedPackets() -{ - LLXfer *xferp; - - xfer_list_t::iterator iter = mReceiveList.begin(); - while (iter != mReceiveList.end()) - { - xferp = (*iter); - if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) - { - // if the circuit dies, abort - if (! gMessageSystem->mCircuitInfo.isCircuitAlive( xferp->mRemoteHost )) - { - LL_WARNS("Xfer") << "Xfer found in progress on dead circuit, aborting transfer to " - << xferp->mRemoteHost.getIPandPort() - << LL_ENDL; - xferp->mCallbackResult = LL_ERR_CIRCUIT_GONE; - xferp->processEOF(); - - iter = mReceiveList.erase(iter); // iter is set to next one after the deletion point - delete (xferp); - continue; - } - - } - ++iter; - } - - // Re-build mOutgoingHosts data - updateHostStatus(); - - F32 et; - iter = mSendList.begin(); - while (iter != mSendList.end()) - { - xferp = (*iter); - if (xferp->mWaitingForACK && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_PACKET_TIMEOUT)) - { - if (xferp->mRetries > LL_PACKET_RETRY_LIMIT) - { - LL_INFOS("Xfer") << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << LL_ENDL; - xferp->abort(LL_ERR_TCP_TIMEOUT); - iter = mSendList.erase(iter); - delete xferp; - continue; - } - else - { - LL_INFOS("Xfer") << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << LL_ENDL; - xferp->resendLastPacket(); - } - } - else if ((xferp->mStatus == e_LL_XFER_REGISTERED) && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_XFER_REGISTRATION_TIMEOUT)) - { - LL_INFOS("Xfer") << "registered xfer never requested, xfer dropped" << LL_ENDL; - xferp->abort(LL_ERR_TCP_TIMEOUT); - iter = mSendList.erase(iter); - delete xferp; - continue; - } - else if (xferp->mStatus == e_LL_XFER_ABORTED) - { - LL_WARNS("Xfer") << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << LL_ENDL; - iter = mSendList.erase(iter); - delete xferp; - continue; - } - else if (xferp->mStatus == e_LL_XFER_PENDING) - { -// LL_INFOS("Xfer") << "*** numActiveXfers = " << numActiveXfers(xferp->mRemoteHost) << " mMaxOutgoingXfersPerCircuit = " << mMaxOutgoingXfersPerCircuit << LL_ENDL; - if (numActiveXfers(xferp->mRemoteHost) < mMaxOutgoingXfersPerCircuit) - { - if (xferp->reopenFileHandle()) - { - LL_WARNS("Xfer") << "Error re-opening file handle for xfer ID " << U64_to_str(xferp->mID) - << " to host " << xferp->mRemoteHost << LL_ENDL; - xferp->abort(LL_ERR_CANNOT_OPEN_FILE); - iter = mSendList.erase(iter); - delete xferp; - continue; - } - else - { // No error re-opening the file, send the first packet - LL_DEBUGS("Xfer") << "Moving pending xfer ID " << U64_to_str(xferp->mID) << " to active" << LL_ENDL; - xferp->sendNextPacket(); - changeNumActiveXfers(xferp->mRemoteHost,1); - } - } - } - ++iter; - } // end while() loop - - // - // HACK - if we're using xfer confirm throttling, throttle our xfer confirms here - // so we don't blow through bandwidth. - // - - while (mXferAckQueue.size()) - { - if (mAckThrottle.checkOverflow(1000.0f*8.0f)) - { - break; - } - //LL_INFOS("Xfer") << "Confirm packet queue length:" << mXferAckQueue.size() << LL_ENDL; - LLXferAckInfo ack_info = mXferAckQueue.front(); - mXferAckQueue.pop_front(); - //LL_INFOS("Xfer") << "Sending confirm packet" << LL_ENDL; - sendConfirmPacket(gMessageSystem, ack_info.mID, ack_info.mPacketNum, ack_info.mRemoteHost); - mAckThrottle.throttleOverflow(1000.f*8.f); // Assume 1000 bytes/packet - } -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code) -{ - LLXfer * xferp = findXferByID(xfer_id, mReceiveList); - if (xferp) - { - if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) - { - // causes processAbort(); - xferp->abort(result_code); - } - else - { - xferp->mCallbackResult = result_code; - xferp->processEOF(); //should notify requester - removeXfer(xferp, mReceiveList); - } - // Since already removed or marked as aborted no need - // to wait for processAbort() to start new download - startPendingDownloads(); - } -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::processAbort (LLMessageSystem *mesgsys, void ** /*user_data*/) -{ - U64 id = 0; - S32 result_code = 0; - LLXfer * xferp; - - mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); - mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Result, result_code); - - xferp = findXferByID(id, mReceiveList); - if (xferp) - { - xferp->mCallbackResult = result_code; - xferp->processEOF(); - removeXfer(xferp, mReceiveList); - startPendingDownloads(); - } -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::startPendingDownloads() -{ - // This method goes through the list, and starts pending - // operations until active downloads == mMaxIncomingXfers. I copy - // the pending xfers into a temporary data structure because the - // xfers are stored as an intrusive linked list where older - // requests get pushed toward the back. Thus, if we didn't do a - // stateful iteration, it would be possible for old requests to - // never start. - LLXfer* xferp; - std::list<LLXfer*> pending_downloads; - S32 download_count = 0; - S32 pending_count = 0; - for (xfer_list_t::iterator iter = mReceiveList.begin(); - iter != mReceiveList.end(); - ++iter) - { - xferp = (*iter); - if(xferp->mStatus == e_LL_XFER_PENDING) - { // Count and accumulate pending downloads - ++pending_count; - pending_downloads.push_front(xferp); - } - else if(xferp->mStatus == e_LL_XFER_IN_PROGRESS) - { // Count downloads in progress - ++download_count; - } - } - - S32 start_count = mMaxIncomingXfers - download_count; - - LL_DEBUGS("Xfer") << "LLXferManager::startPendingDownloads() - XFER_IN_PROGRESS: " - << download_count << " XFER_PENDING: " << pending_count - << " startring " << llmin(start_count, pending_count) << LL_ENDL; - - if((start_count > 0) && (pending_count > 0)) - { - S32 result; - for (std::list<LLXfer*>::iterator iter = pending_downloads.begin(); - iter != pending_downloads.end(); ++iter) - { - xferp = *iter; - if (start_count-- <= 0) - break; - result = xferp->startDownload(); - if(result) - { - xferp->abort(result); - ++start_count; - } - } - } -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority) -{ - if(is_priority) - { - xfer_list.push_back(xferp); - } - else - { - xfer_list.push_front(xferp); - } -} - -/////////////////////////////////////////////////////////// -// Globals and C routines -/////////////////////////////////////////////////////////// - -LLXferManager *gXferManager = NULL; - - -void start_xfer_manager() -{ - gXferManager = new LLXferManager(); -} - -void cleanup_xfer_manager() -{ - if (gXferManager) - { - delete(gXferManager); - gXferManager = NULL; - } -} - -void process_confirm_packet (LLMessageSystem *mesgsys, void **user_data) -{ - gXferManager->processConfirmation(mesgsys,user_data); -} - -void process_request_xfer(LLMessageSystem *mesgsys, void **user_data) -{ - gXferManager->processFileRequest(mesgsys,user_data); -} - -void continue_file_receive(LLMessageSystem *mesgsys, void **user_data) -{ -#if LL_TEST_XFER_REXMIT - if (ll_frand() > 0.05f) - { -#endif - gXferManager->processReceiveData(mesgsys,user_data); -#if LL_TEST_XFER_REXMIT - } - else - { - cout << "oops! dropped a xfer packet" << endl; - } -#endif -} - -void process_abort_xfer(LLMessageSystem *mesgsys, void **user_data) -{ - gXferManager->processAbort(mesgsys,user_data); -} - - - - - - - - - - - - - - - - - - - - - - - - - - +/**
+ * @file llxfermanager.cpp
+ * @brief implementation of LLXferManager class for a collection of xfers
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llxfermanager.h"
+
+#include "llxfer.h"
+#include "llxfer_file.h"
+#include "llxfer_mem.h"
+#include "llxfer_vfile.h"
+
+#include "llerror.h"
+#include "lluuid.h"
+#include "u64.h"
+
+const F32 LL_XFER_REGISTRATION_TIMEOUT = 60.0f; // timeout if a registered transfer hasn't been requested in 60 seconds
+const F32 LL_PACKET_TIMEOUT = 3.0f; // packet timeout at 3 s
+const S32 LL_PACKET_RETRY_LIMIT = 10; // packet retransmission limit
+
+const S32 LL_DEFAULT_MAX_SIMULTANEOUS_XFERS = 10;
+const S32 LL_DEFAULT_MAX_REQUEST_FIFO_XFERS = 1000;
+
+// Kills the connection if a viewer download queue hits this many requests backed up
+// Also set in simulator.xml at "hard_limit_outgoing_xfers_per_circuit"
+const S32 LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS = 500;
+
+// Use this to show sending some ConfirmXferPacket messages
+//#define LL_XFER_PROGRESS_MESSAGES 1
+
+// Use this for lots of diagnostic spam
+//#define LL_XFER_DIAGNOISTIC_LOGGING 1
+
+///////////////////////////////////////////////////////////
+
+LLXferManager::LLXferManager ()
+{
+ init();
+}
+
+///////////////////////////////////////////////////////////
+
+LLXferManager::~LLXferManager ()
+{
+ cleanup();
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::init()
+{
+ cleanup();
+
+ setMaxOutgoingXfersPerCircuit(LL_DEFAULT_MAX_SIMULTANEOUS_XFERS);
+ setHardLimitOutgoingXfersPerCircuit(LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS);
+ setMaxIncomingXfers(LL_DEFAULT_MAX_REQUEST_FIFO_XFERS);
+
+ // Turn on or off ack throttling
+ mUseAckThrottling = false;
+ setAckThrottleBPS(100000);
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::cleanup ()
+{
+ for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer());
+ mOutgoingHosts.clear();
+
+ for_each(mSendList.begin(), mSendList.end(), DeletePointer());
+ mSendList.clear();
+
+ for_each(mReceiveList.begin(), mReceiveList.end(), DeletePointer());
+ mReceiveList.clear();
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::setMaxIncomingXfers(S32 max_num)
+{
+ mMaxIncomingXfers = max_num;
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::setMaxOutgoingXfersPerCircuit(S32 max_num)
+{
+ mMaxOutgoingXfersPerCircuit = max_num;
+}
+
+void LLXferManager::setHardLimitOutgoingXfersPerCircuit(S32 max_num)
+{
+ mHardLimitOutgoingXfersPerCircuit = max_num;
+}
+
+void LLXferManager::setUseAckThrottling(const bool use)
+{
+ mUseAckThrottling = use;
+}
+
+void LLXferManager::setAckThrottleBPS(const F32 bps)
+{
+ // Let's figure out the min we can set based on the ack retry rate
+ // and number of simultaneous.
+
+ // Assuming we're running as slow as possible, this is the lowest ack
+ // rate we can use.
+ F32 min_bps = (1000.f * 8.f* mMaxIncomingXfers) / LL_PACKET_TIMEOUT;
+
+ // Set
+ F32 actual_rate = llmax(min_bps*1.1f, bps);
+ LL_DEBUGS("AppInit") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL;
+ LL_DEBUGS("AppInit") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL;
+ #ifdef LL_XFER_DIAGNOISTIC_LOGGING
+ LL_INFOS("Xfer") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL;
+ LL_INFOS("Xfer") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL;
+ #endif // LL_XFER_DIAGNOISTIC_LOGGING
+
+ mAckThrottle.setRate(actual_rate);
+}
+
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::updateHostStatus()
+{
+ // Clear the outgoing host list
+ for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer());
+ mOutgoingHosts.clear();
+
+ // Loop through all outgoing xfers and re-build mOutgoingHosts
+ for (xfer_list_t::iterator send_iter = mSendList.begin();
+ send_iter != mSendList.end(); ++send_iter)
+ {
+ LLHostStatus *host_statusp = NULL;
+ for (status_list_t::iterator iter = mOutgoingHosts.begin();
+ iter != mOutgoingHosts.end(); ++iter)
+ {
+ if ((*iter)->mHost == (*send_iter)->mRemoteHost)
+ { // Already have this host
+ host_statusp = *iter;
+ break;
+ }
+ }
+ if (!host_statusp)
+ { // Don't have this host, so add it
+ host_statusp = new LLHostStatus();
+ if (host_statusp)
+ {
+ host_statusp->mHost = (*send_iter)->mRemoteHost;
+ mOutgoingHosts.push_front(host_statusp);
+ }
+ }
+ if (host_statusp)
+ { // Do the accounting
+ if ((*send_iter)->mStatus == e_LL_XFER_PENDING)
+ {
+ host_statusp->mNumPending++;
+ }
+ else if ((*send_iter)->mStatus == e_LL_XFER_IN_PROGRESS)
+ {
+ host_statusp->mNumActive++;
+ }
+ }
+ }
+
+#ifdef LL_XFER_DIAGNOISTIC_LOGGING
+ for (xfer_list_t::iterator send_iter = mSendList.begin();
+ send_iter != mSendList.end(); ++send_iter)
+ {
+ LLXfer * xferp = *send_iter;
+ LL_INFOS("Xfer") << "xfer to host " << xferp->mRemoteHost
+ << " is " << xferp->mXferSize << " bytes"
+ << ", status " << (S32)(xferp->mStatus)
+ << ", waiting for ACK: " << (S32)(xferp->mWaitingForACK)
+ << " in frame " << (S32) LLFrameTimer::getFrameCount()
+ << LL_ENDL;
+ }
+
+ for (status_list_t::iterator iter = mOutgoingHosts.begin();
+ iter != mOutgoingHosts.end(); ++iter)
+ {
+ LL_INFOS("Xfer") << "LLXfer host " << (*iter)->mHost.getIPandPort()
+ << " has " << (*iter)->mNumActive
+ << " active, " << (*iter)->mNumPending
+ << " pending"
+ << " in frame " << (S32) LLFrameTimer::getFrameCount()
+ << LL_ENDL;
+ }
+#endif // LL_XFER_DIAGNOISTIC_LOGGING
+
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::printHostStatus()
+{
+ LLHostStatus *host_statusp = NULL;
+ if (!mOutgoingHosts.empty())
+ {
+ LL_INFOS("Xfer") << "Outgoing Xfers:" << LL_ENDL;
+
+ for (status_list_t::iterator iter = mOutgoingHosts.begin();
+ iter != mOutgoingHosts.end(); ++iter)
+ {
+ host_statusp = *iter;
+ LL_INFOS("Xfer") << " " << host_statusp->mHost << " active: " << host_statusp->mNumActive << " pending: " << host_statusp->mNumPending << LL_ENDL;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+LLXfer * LLXferManager::findXferByID(U64 id, xfer_list_t & xfer_list)
+{
+ for (xfer_list_t::iterator iter = xfer_list.begin();
+ iter != xfer_list.end();
+ ++iter)
+ {
+ if ((*iter)->mID == id)
+ {
+ return(*iter);
+ }
+ }
+ return(NULL);
+}
+
+
+///////////////////////////////////////////////////////////
+
+// WARNING: this invalidates iterators from xfer_list
+void LLXferManager::removeXfer(LLXfer *delp, xfer_list_t & xfer_list)
+{
+ if (delp)
+ {
+ std::string direction = "send";
+ if (&xfer_list == &mReceiveList)
+ {
+ direction = "receive";
+ }
+
+ // This assumes that delp will occur in the list once at most
+ // Find the pointer in the list
+ for (xfer_list_t::iterator iter = xfer_list.begin();
+ iter != xfer_list.end();
+ ++iter)
+ {
+ if ((*iter) == delp)
+ {
+ LL_DEBUGS("Xfer") << "Deleting xfer to host " << (*iter)->mRemoteHost
+ << " of " << (*iter)->mXferSize << " bytes"
+ << ", status " << (S32)((*iter)->mStatus)
+ << " from the " << direction << " list"
+ << LL_ENDL;
+
+ xfer_list.erase(iter);
+ delete (delp);
+ break;
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+LLHostStatus * LLXferManager::findHostStatus(const LLHost &host)
+{
+ LLHostStatus *host_statusp = NULL;
+
+ for (status_list_t::iterator iter = mOutgoingHosts.begin();
+ iter != mOutgoingHosts.end(); ++iter)
+ {
+ host_statusp = *iter;
+ if (host_statusp->mHost == host)
+ {
+ return (host_statusp);
+ }
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXferManager::numPendingXfers(const LLHost &host)
+{
+ LLHostStatus *host_statusp = findHostStatus(host);
+ if (host_statusp)
+ {
+ return host_statusp->mNumPending;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXferManager::numActiveXfers(const LLHost &host)
+{
+ LLHostStatus *host_statusp = findHostStatus(host);
+ if (host_statusp)
+ {
+ return host_statusp->mNumActive;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::changeNumActiveXfers(const LLHost &host, S32 delta)
+{
+ LLHostStatus *host_statusp = NULL;
+
+ for (status_list_t::iterator iter = mOutgoingHosts.begin();
+ iter != mOutgoingHosts.end(); ++iter)
+ {
+ host_statusp = *iter;
+ if (host_statusp->mHost == host)
+ {
+ host_statusp->mNumActive += delta;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::registerCallbacks(LLMessageSystem *msgsystem)
+{
+ msgsystem->setHandlerFuncFast(_PREHASH_ConfirmXferPacket, process_confirm_packet, NULL);
+ msgsystem->setHandlerFuncFast(_PREHASH_RequestXfer, process_request_xfer, NULL);
+ msgsystem->setHandlerFuncFast(_PREHASH_SendXferPacket, continue_file_receive, NULL);
+ msgsystem->setHandlerFuncFast(_PREHASH_AbortXfer, process_abort_xfer, NULL);
+}
+
+///////////////////////////////////////////////////////////
+
+U64 LLXferManager::getNextID ()
+{
+ LLUUID a_guid;
+
+ a_guid.generate();
+
+
+ return(*((U64*)(a_guid.mData)));
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXferManager::encodePacketNum(S32 packet_num, bool is_EOF)
+{
+ if (is_EOF)
+ {
+ packet_num |= 0x80000000;
+ }
+ return packet_num;
+}
+
+///////////////////////////////////////////////////////////
+
+S32 LLXferManager::decodePacketNum(S32 packet_num)
+{
+ return(packet_num & 0x0FFFFFFF);
+}
+
+///////////////////////////////////////////////////////////
+
+bool LLXferManager::isLastPacket(S32 packet_num)
+{
+ return(packet_num & 0x80000000);
+}
+
+///////////////////////////////////////////////////////////
+
+U64 LLXferManager::requestFile(const std::string& local_filename,
+ const std::string& remote_filename,
+ ELLPath remote_path,
+ const LLHost& remote_host,
+ bool delete_remote_on_completion,
+ void (*callback)(void**,S32,LLExtStat),
+ void** user_data,
+ bool is_priority,
+ bool use_big_packets)
+{
+ LLXfer_File* file_xfer_p = NULL;
+
+ // First check to see if it's already requested
+ for (xfer_list_t::iterator iter = mReceiveList.begin();
+ iter != mReceiveList.end(); ++iter)
+ {
+ if ((*iter)->getXferTypeTag() == LLXfer::XFER_FILE)
+ {
+ file_xfer_p = (LLXfer_File*)(*iter);
+ if (file_xfer_p->matchesLocalFilename(local_filename)
+ && file_xfer_p->matchesRemoteFilename(remote_filename, remote_path)
+ && (remote_host == file_xfer_p->mRemoteHost)
+ && (callback == file_xfer_p->mCallback)
+ && (user_data == file_xfer_p->mCallbackDataHandle))
+ {
+ // Already have the request (already in progress)
+ return (*iter)->mID;
+ }
+ }
+ }
+
+ U64 xfer_id = 0;
+
+ S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1;
+ file_xfer_p = new LLXfer_File(chunk_size);
+ if (file_xfer_p)
+ {
+ addToList(file_xfer_p, mReceiveList, is_priority);
+
+ // Remove any file by the same name that happens to be lying
+ // around.
+ // Note: according to AaronB, this is here to deal with locks on files that were
+ // in transit during a crash,
+ if(delete_remote_on_completion &&
+ (remote_filename.substr(remote_filename.length()-4) == ".tmp"))
+ {
+ LLFile::remove(local_filename, ENOENT);
+ }
+ xfer_id = getNextID();
+ file_xfer_p->initializeRequest(
+ xfer_id,
+ local_filename,
+ remote_filename,
+ remote_path,
+ remote_host,
+ delete_remote_on_completion,
+ callback,user_data);
+ startPendingDownloads();
+ }
+ else
+ {
+ LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL;
+ }
+ return xfer_id;
+}
+
+void LLXferManager::requestVFile(const LLUUID& local_id,
+ const LLUUID& remote_id,
+ LLAssetType::EType type,
+ const LLHost& remote_host,
+ void (*callback)(void**,S32,LLExtStat),
+ void** user_data,
+ bool is_priority)
+{
+ LLXfer_VFile * xfer_p = NULL;
+
+ for (xfer_list_t::iterator iter = mReceiveList.begin();
+ iter != mReceiveList.end(); ++iter)
+ { // Find any matching existing requests
+ if ((*iter)->getXferTypeTag() == LLXfer::XFER_VFILE)
+ {
+ xfer_p = (LLXfer_VFile*) (*iter);
+ if (xfer_p->matchesLocalFile(local_id, type)
+ && xfer_p->matchesRemoteFile(remote_id, type)
+ && (remote_host == xfer_p->mRemoteHost)
+ && (callback == xfer_p->mCallback)
+ && (user_data == xfer_p->mCallbackDataHandle))
+
+ { // Have match, don't add a duplicate
+ #ifdef LL_XFER_DIAGNOISTIC_LOGGING
+ LL_INFOS("Xfer") << "Dropping duplicate xfer request for " << remote_id
+ << " on " << remote_host.getIPandPort()
+ << " local id " << local_id
+ << LL_ENDL;
+ #endif // LL_XFER_DIAGNOISTIC_LOGGING
+
+ return;
+ }
+ }
+ }
+
+ xfer_p = new LLXfer_VFile();
+ if (xfer_p)
+ {
+ #ifdef LL_XFER_DIAGNOISTIC_LOGGING
+ LL_INFOS("Xfer") << "Starting file xfer for " << remote_id
+ << " type " << LLAssetType::lookupHumanReadable(type)
+ << " from " << xfer_p->mRemoteHost.getIPandPort()
+ << ", local id " << local_id
+ << LL_ENDL;
+ #endif // LL_XFER_DIAGNOISTIC_LOGGING
+
+ addToList(xfer_p, mReceiveList, is_priority);
+ ((LLXfer_VFile *)xfer_p)->initializeRequest(getNextID(),
+ local_id,
+ remote_id,
+ type,
+ remote_host,
+ callback,
+ user_data);
+ startPendingDownloads();
+ }
+ else
+ {
+ LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL;
+ }
+
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user_data*/)
+{
+ // there's sometimes an extra 4 bytes added to an xfer payload
+ const S32 BUF_SIZE = LL_XFER_LARGE_PAYLOAD + 4;
+ char fdata_buf[BUF_SIZE]; /* Flawfinder : ignore */
+ S32 fdata_size;
+ U64 id;
+ S32 packetnum;
+ LLXfer * xferp;
+
+ mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id);
+ mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetnum);
+
+ fdata_size = mesgsys->getSizeFast(_PREHASH_DataPacket,_PREHASH_Data);
+ if (fdata_size < 0 ||
+ fdata_size > BUF_SIZE)
+ {
+ char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */
+ LL_WARNS("Xfer") << "Received invalid xfer data size of " << fdata_size
+ << " in packet number " << packetnum
+ << " from " << mesgsys->getSender()
+ << " for xfer id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF))
+ << LL_ENDL;
+ return;
+ }
+ mesgsys->getBinaryDataFast(_PREHASH_DataPacket, _PREHASH_Data, fdata_buf, fdata_size, 0, BUF_SIZE);
+
+ xferp = findXferByID(id, mReceiveList);
+ if (!xferp)
+ {
+ char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */
+ LL_WARNS("Xfer") << "received xfer data from " << mesgsys->getSender()
+ << " for non-existent xfer id: "
+ << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << LL_ENDL;
+ return;
+ }
+
+ S32 xfer_size;
+
+ if (decodePacketNum(packetnum) != xferp->mPacketNum) // is the packet different from what we were expecting?
+ {
+ // confirm it if it was a resend of the last one, since the confirmation might have gotten dropped
+ if (decodePacketNum(packetnum) == (xferp->mPacketNum - 1))
+ {
+ LL_INFOS("Xfer") << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << LL_ENDL; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender());
+ }
+ else
+ {
+ LL_INFOS("Xfer") << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << LL_ENDL;
+ }
+ return;
+ }
+
+ S32 result = 0;
+
+ if (xferp->mPacketNum == 0) // first packet has size encoded as additional S32 at beginning of data
+ {
+ ntohmemcpy(&xfer_size,fdata_buf,MVT_S32,sizeof(S32));
+
+// do any necessary things on first packet ie. allocate memory
+ xferp->setXferSize(xfer_size);
+
+ // adjust buffer start and size
+ result = xferp->receiveData(&(fdata_buf[sizeof(S32)]),fdata_size-(sizeof(S32)));
+ }
+ else
+ {
+ result = xferp->receiveData(fdata_buf,fdata_size);
+ }
+
+ if (result == LL_ERR_CANNOT_OPEN_FILE)
+ {
+ xferp->abort(LL_ERR_CANNOT_OPEN_FILE);
+ removeXfer(xferp,mReceiveList);
+ startPendingDownloads();
+ return;
+ }
+
+ xferp->mPacketNum++; // expect next packet
+
+ if (!mUseAckThrottling)
+ {
+ // No throttling, confirm right away
+ sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender());
+ }
+ else
+ {
+ // Throttling, put on queue to be confirmed later.
+ LLXferAckInfo ack_info;
+ ack_info.mID = id;
+ ack_info.mPacketNum = decodePacketNum(packetnum);
+ ack_info.mRemoteHost = mesgsys->getSender();
+ mXferAckQueue.push_back(ack_info);
+ }
+
+ if (isLastPacket(packetnum))
+ {
+ xferp->processEOF();
+ removeXfer(xferp,mReceiveList);
+ startPendingDownloads();
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host)
+{
+#ifdef LL_XFER_PROGRESS_MESSAGES
+ if (!(packetnum % 50))
+ {
+ cout << "confirming xfer packet #" << packetnum << endl;
+ }
+#endif
+ mesgsys->newMessageFast(_PREHASH_ConfirmXferPacket);
+ mesgsys->nextBlockFast(_PREHASH_XferID);
+ mesgsys->addU64Fast(_PREHASH_ID, id);
+ mesgsys->addU32Fast(_PREHASH_Packet, packetnum);
+
+ // Ignore a circuit failure here, we'll catch it with another message
+ mesgsys->sendMessage(remote_host);
+}
+
+///////////////////////////////////////////////////////////
+
+static bool find_and_remove(std::multiset<std::string>& files,
+ const std::string& filename)
+{
+ std::multiset<std::string>::iterator ptr;
+ if ( (ptr = files.find(filename)) != files.end())
+ {
+ //erase(filename) erases *all* entries with that key
+ files.erase(ptr);
+ return true;
+ }
+ return false;
+}
+
+void LLXferManager::expectFileForRequest(const std::string& filename)
+{
+ mExpectedRequests.insert(filename);
+}
+
+bool LLXferManager::validateFileForRequest(const std::string& filename)
+{
+ return find_and_remove(mExpectedRequests, filename);
+}
+
+void LLXferManager::expectFileForTransfer(const std::string& filename)
+{
+ mExpectedTransfers.insert(filename);
+}
+
+bool LLXferManager::validateFileForTransfer(const std::string& filename)
+{
+ return find_and_remove(mExpectedTransfers, filename);
+}
+
+/* Present in fireengine, not used by viewer
+void LLXferManager::expectVFileForRequest(const std::string& filename)
+{
+ mExpectedVFileRequests.insert(filename);
+}
+
+bool LLXferManager::validateVFileForRequest(const std::string& filename)
+{
+ return find_and_remove(mExpectedVFileRequests, filename);
+}
+
+void LLXferManager::expectVFileForTransfer(const std::string& filename)
+{
+ mExpectedVFileTransfers.insert(filename);
+}
+
+bool LLXferManager::validateVFileForTransfer(const std::string& filename)
+{
+ return find_and_remove(mExpectedVFileTransfers, filename);
+}
+*/
+
+static bool remove_prefix(std::string& filename, const std::string& prefix)
+{
+ if (std::equal(prefix.begin(), prefix.end(), filename.begin()))
+ {
+ filename = filename.substr(prefix.length());
+ return true;
+ }
+ return false;
+}
+
+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. 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("[0-9a-zA-Z_-]<1,46>\.tmp");
+ if (len < 5 || len > 50)
+ {
+ return false;
+ }
+ for(size_t i=0; i<(len-4); ++i)
+ {
+ char c = filename[i];
+ bool ok = isalnum(c) || '_'==c || '-'==c;
+ if (!ok)
+ {
+ return false;
+ }
+ }
+ return filename[len-4] == '.'
+ && filename[len-3] == 't'
+ && filename[len-2] == 'm'
+ && filename[len-1] == 'p';
+}
+
+void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user_data*/)
+{
+
+ U64 id;
+ std::string local_filename;
+ ELLPath local_path = LL_PATH_NONE;
+ S32 result = LL_ERR_NOERR;
+ LLUUID uuid;
+ LLAssetType::EType type;
+ S16 type_s16;
+ bool b_use_big_packets;
+
+ mesgsys->getBOOL("XferID", "UseBigPackets", b_use_big_packets);
+
+ mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id);
+ char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */
+ LL_INFOS("Xfer") << "xfer request id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF))
+ << " to " << mesgsys->getSender() << LL_ENDL;
+
+ mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, local_filename);
+
+ {
+ U8 local_path_u8;
+ mesgsys->getU8("XferID", "FilePath", local_path_u8);
+ local_path = (ELLPath)local_path_u8;
+ }
+
+ mesgsys->getUUIDFast(_PREHASH_XferID, _PREHASH_VFileID, uuid);
+ mesgsys->getS16Fast(_PREHASH_XferID, _PREHASH_VFileType, type_s16);
+ type = (LLAssetType::EType)type_s16;
+
+ LLXfer *xferp;
+
+ if (uuid != LLUUID::null)
+ { // Request for an asset - use a cache file
+ if(NULL == LLAssetType::lookup(type))
+ {
+ LL_WARNS("Xfer") << "Invalid type for xfer request: " << uuid << ":"
+ << type_s16 << " to " << mesgsys->getSender() << LL_ENDL;
+ return;
+ }
+
+ LL_INFOS("Xfer") << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << LL_ENDL;
+
+ xferp = (LLXfer *)new LLXfer_VFile(uuid, type);
+ if (xferp)
+ {
+ mSendList.push_front(xferp);
+ result = xferp->startSend(id,mesgsys->getSender());
+ }
+ else
+ {
+ LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL;
+ }
+ }
+ else if (!local_filename.empty())
+ { // Was given a file name to send
+ // See DEV-21775 for detailed security issues
+
+ if (local_path == LL_PATH_NONE)
+ {
+ // this handles legacy simulators that are passing objects
+ // by giving a filename that explicitly names the cache directory
+ static const std::string legacy_cache_prefix = "data/";
+ if (remove_prefix(local_filename, legacy_cache_prefix))
+ {
+ local_path = LL_PATH_CACHE;
+ }
+ }
+
+ switch (local_path)
+ {
+ case LL_PATH_NONE:
+ if(!validateFileForTransfer(local_filename))
+ {
+ LL_WARNS("Xfer") << "SECURITY: Unapproved filename '" << local_filename << LL_ENDL;
+ return;
+ }
+ break;
+
+ case LL_PATH_CACHE:
+ if(!verify_cache_filename(local_filename))
+ {
+ LL_WARNS("Xfer") << "SECURITY: Illegal cache filename '" << local_filename << LL_ENDL;
+ return;
+ }
+ break;
+
+ default:
+ LL_WARNS("Xfer") << "SECURITY: Restricted file dir enum: " << (U32)local_path << LL_ENDL;
+ return;
+ }
+
+ // If we want to use a special path (e.g. LL_PATH_CACHE), we want to make sure we create the
+ // proper expanded filename.
+ std::string expanded_filename;
+ if (local_path != LL_PATH_NONE)
+ {
+ expanded_filename = gDirUtilp->getExpandedFilename( local_path, local_filename );
+ }
+ else
+ {
+ expanded_filename = local_filename;
+ }
+ LL_INFOS("Xfer") << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << LL_ENDL;
+
+ bool delete_local_on_completion = false;
+ mesgsys->getBOOL("XferID", "DeleteOnCompletion", delete_local_on_completion);
+
+ // -1 chunk_size causes it to use the default
+ xferp = (LLXfer *)new LLXfer_File(expanded_filename, delete_local_on_completion, b_use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1);
+
+ if (xferp)
+ {
+ mSendList.push_front(xferp);
+ result = xferp->startSend(id,mesgsys->getSender());
+ }
+ else
+ {
+ LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL;
+ }
+ }
+ else
+ { // no uuid or filename - use the ID sent
+ char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */
+ LL_INFOS("Xfer") << "starting memory transfer: "
+ << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << " to "
+ << mesgsys->getSender() << LL_ENDL;
+
+ xferp = findXferByID(id, mSendList);
+
+ if (xferp)
+ {
+ result = xferp->startSend(id,mesgsys->getSender());
+ }
+ else
+ {
+ LL_INFOS("Xfer") << "Warning: xfer ID " << U64_BUF << " not found." << LL_ENDL;
+ result = LL_ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ if (result)
+ {
+ if (xferp)
+ {
+ xferp->abort(result);
+ removeXfer(xferp, mSendList);
+ }
+ else // can happen with a memory transfer not found
+ {
+ LL_INFOS("Xfer") << "Aborting xfer to " << mesgsys->getSender() << " with error: " << result << LL_ENDL;
+
+ mesgsys->newMessageFast(_PREHASH_AbortXfer);
+ mesgsys->nextBlockFast(_PREHASH_XferID);
+ mesgsys->addU64Fast(_PREHASH_ID, id);
+ mesgsys->addS32Fast(_PREHASH_Result, result);
+
+ mesgsys->sendMessage(mesgsys->getSender());
+ }
+ }
+ else if(xferp)
+ {
+ // Figure out how many transfers the host has requested
+ LLHostStatus *host_statusp = findHostStatus(xferp->mRemoteHost);
+ if (host_statusp)
+ {
+ if (host_statusp->mNumActive < mMaxOutgoingXfersPerCircuit)
+ { // Not many transfers in progress already, so start immediately
+ xferp->sendNextPacket();
+ changeNumActiveXfers(xferp->mRemoteHost,1);
+ LL_DEBUGS("Xfer") << "Starting xfer ID " << U64_to_str(id) << " immediately" << LL_ENDL;
+ }
+ else if (mHardLimitOutgoingXfersPerCircuit == 0 ||
+ (host_statusp->mNumActive + host_statusp->mNumPending) < mHardLimitOutgoingXfersPerCircuit)
+ { // Must close the file handle and wait for earlier ones to complete
+ LL_INFOS("Xfer") << " queueing xfer request id " << U64_to_str(id) << ", "
+ << host_statusp->mNumActive << " active and "
+ << host_statusp->mNumPending << " pending ahead of this one"
+ << LL_ENDL;
+ xferp->closeFileHandle(); // Close the file handle until we're ready to send again
+ }
+ else if (mHardLimitOutgoingXfersPerCircuit > 0)
+ { // Way too many requested ... it's time to stop being nice and kill the circuit
+ xferp->closeFileHandle(); // Close the file handle in any case
+ LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(xferp->mRemoteHost);
+ if (cdp)
+ {
+ if (cdp->getTrusted())
+ { // Trusted internal circuit - don't kill it
+ LL_WARNS("Xfer") << "Trusted circuit to " << xferp->mRemoteHost << " has too many xfer requests in the queue "
+ << host_statusp->mNumActive << " active and "
+ << host_statusp->mNumPending << " pending ahead of this one"
+ << LL_ENDL;
+ }
+ else
+ { // Untrusted circuit - time to stop messing around and kill it
+ LL_WARNS("Xfer") << "Killing circuit to " << xferp->mRemoteHost << " for having too many xfer requests in the queue "
+ << host_statusp->mNumActive << " active and "
+ << host_statusp->mNumPending << " pending ahead of this one"
+ << LL_ENDL;
+ gMessageSystem->disableCircuit(xferp->mRemoteHost);
+ }
+ }
+ else
+ { // WTF? Why can't we find a circuit? Try to kill it off
+ LL_WARNS("Xfer") << "Backlog with circuit to " << xferp->mRemoteHost << " with too many xfer requests in the queue "
+ << host_statusp->mNumActive << " active and "
+ << host_statusp->mNumPending << " pending ahead of this one"
+ << " but no LLCircuitData found???"
+ << LL_ENDL;
+ gMessageSystem->disableCircuit(xferp->mRemoteHost);
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no LLHostStatus found for id " << U64_to_str(id)
+ << " host " << xferp->mRemoteHost << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no xfer found for id " << U64_to_str(id) << LL_ENDL;
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+// Return true if host is in a transfer-flood sitation. Same check for both internal and external hosts
+bool LLXferManager::isHostFlooded(const LLHost & host)
+{
+ bool flooded = false;
+ LLHostStatus *host_statusp = findHostStatus(host);
+ if (host_statusp)
+ {
+ flooded = (mHardLimitOutgoingXfersPerCircuit > 0 &&
+ (host_statusp->mNumActive + host_statusp->mNumPending) >= (S32)(mHardLimitOutgoingXfersPerCircuit * 0.8f));
+ }
+
+ return flooded;
+}
+
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*user_data*/)
+{
+ U64 id = 0;
+ S32 packetNum = 0;
+
+ mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id);
+ mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetNum);
+
+ LLXfer* xferp = findXferByID(id, mSendList);
+ if (xferp)
+ {
+// cout << "confirmed packet #" << packetNum << " ping: "<< xferp->ACKTimer.getElapsedTimeF32() << endl;
+ xferp->mWaitingForACK = false;
+ if (xferp->mStatus == e_LL_XFER_IN_PROGRESS)
+ {
+ xferp->sendNextPacket();
+ }
+ else
+ {
+ removeXfer(xferp, mSendList);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+// Called from LLMessageSystem::processAcks()
+void LLXferManager::retransmitUnackedPackets()
+{
+ LLXfer *xferp;
+
+ xfer_list_t::iterator iter = mReceiveList.begin();
+ while (iter != mReceiveList.end())
+ {
+ xferp = (*iter);
+ if (xferp->mStatus == e_LL_XFER_IN_PROGRESS)
+ {
+ // if the circuit dies, abort
+ if (! gMessageSystem->mCircuitInfo.isCircuitAlive( xferp->mRemoteHost ))
+ {
+ LL_WARNS("Xfer") << "Xfer found in progress on dead circuit, aborting transfer to "
+ << xferp->mRemoteHost.getIPandPort()
+ << LL_ENDL;
+ xferp->mCallbackResult = LL_ERR_CIRCUIT_GONE;
+ xferp->processEOF();
+
+ iter = mReceiveList.erase(iter); // iter is set to next one after the deletion point
+ delete (xferp);
+ continue;
+ }
+
+ }
+ ++iter;
+ }
+
+ // Re-build mOutgoingHosts data
+ updateHostStatus();
+
+ F32 et;
+ iter = mSendList.begin();
+ while (iter != mSendList.end())
+ {
+ xferp = (*iter);
+ if (xferp->mWaitingForACK && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_PACKET_TIMEOUT))
+ {
+ if (xferp->mRetries > LL_PACKET_RETRY_LIMIT)
+ {
+ LL_INFOS("Xfer") << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << LL_ENDL;
+ xferp->abort(LL_ERR_TCP_TIMEOUT);
+ iter = mSendList.erase(iter);
+ delete xferp;
+ continue;
+ }
+ else
+ {
+ LL_INFOS("Xfer") << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << LL_ENDL;
+ xferp->resendLastPacket();
+ }
+ }
+ else if ((xferp->mStatus == e_LL_XFER_REGISTERED) && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_XFER_REGISTRATION_TIMEOUT))
+ {
+ LL_INFOS("Xfer") << "registered xfer never requested, xfer dropped" << LL_ENDL;
+ xferp->abort(LL_ERR_TCP_TIMEOUT);
+ iter = mSendList.erase(iter);
+ delete xferp;
+ continue;
+ }
+ else if (xferp->mStatus == e_LL_XFER_ABORTED)
+ {
+ LL_WARNS("Xfer") << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << LL_ENDL;
+ iter = mSendList.erase(iter);
+ delete xferp;
+ continue;
+ }
+ else if (xferp->mStatus == e_LL_XFER_PENDING)
+ {
+// LL_INFOS("Xfer") << "*** numActiveXfers = " << numActiveXfers(xferp->mRemoteHost) << " mMaxOutgoingXfersPerCircuit = " << mMaxOutgoingXfersPerCircuit << LL_ENDL;
+ if (numActiveXfers(xferp->mRemoteHost) < mMaxOutgoingXfersPerCircuit)
+ {
+ if (xferp->reopenFileHandle())
+ {
+ LL_WARNS("Xfer") << "Error re-opening file handle for xfer ID " << U64_to_str(xferp->mID)
+ << " to host " << xferp->mRemoteHost << LL_ENDL;
+ xferp->abort(LL_ERR_CANNOT_OPEN_FILE);
+ iter = mSendList.erase(iter);
+ delete xferp;
+ continue;
+ }
+ else
+ { // No error re-opening the file, send the first packet
+ LL_DEBUGS("Xfer") << "Moving pending xfer ID " << U64_to_str(xferp->mID) << " to active" << LL_ENDL;
+ xferp->sendNextPacket();
+ changeNumActiveXfers(xferp->mRemoteHost,1);
+ }
+ }
+ }
+ ++iter;
+ } // end while() loop
+
+ //
+ // HACK - if we're using xfer confirm throttling, throttle our xfer confirms here
+ // so we don't blow through bandwidth.
+ //
+
+ while (mXferAckQueue.size())
+ {
+ if (mAckThrottle.checkOverflow(1000.0f*8.0f))
+ {
+ break;
+ }
+ //LL_INFOS("Xfer") << "Confirm packet queue length:" << mXferAckQueue.size() << LL_ENDL;
+ LLXferAckInfo ack_info = mXferAckQueue.front();
+ mXferAckQueue.pop_front();
+ //LL_INFOS("Xfer") << "Sending confirm packet" << LL_ENDL;
+ sendConfirmPacket(gMessageSystem, ack_info.mID, ack_info.mPacketNum, ack_info.mRemoteHost);
+ mAckThrottle.throttleOverflow(1000.f*8.f); // Assume 1000 bytes/packet
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code)
+{
+ LLXfer * xferp = findXferByID(xfer_id, mReceiveList);
+ if (xferp)
+ {
+ if (xferp->mStatus == e_LL_XFER_IN_PROGRESS)
+ {
+ // causes processAbort();
+ xferp->abort(result_code);
+ }
+ else
+ {
+ xferp->mCallbackResult = result_code;
+ xferp->processEOF(); //should notify requester
+ removeXfer(xferp, mReceiveList);
+ }
+ // Since already removed or marked as aborted no need
+ // to wait for processAbort() to start new download
+ startPendingDownloads();
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::processAbort (LLMessageSystem *mesgsys, void ** /*user_data*/)
+{
+ U64 id = 0;
+ S32 result_code = 0;
+ LLXfer * xferp;
+
+ mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id);
+ mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Result, result_code);
+
+ xferp = findXferByID(id, mReceiveList);
+ if (xferp)
+ {
+ xferp->mCallbackResult = result_code;
+ xferp->processEOF();
+ removeXfer(xferp, mReceiveList);
+ startPendingDownloads();
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::startPendingDownloads()
+{
+ // This method goes through the list, and starts pending
+ // operations until active downloads == mMaxIncomingXfers. I copy
+ // the pending xfers into a temporary data structure because the
+ // xfers are stored as an intrusive linked list where older
+ // requests get pushed toward the back. Thus, if we didn't do a
+ // stateful iteration, it would be possible for old requests to
+ // never start.
+ LLXfer* xferp;
+ std::list<LLXfer*> pending_downloads;
+ S32 download_count = 0;
+ S32 pending_count = 0;
+ for (xfer_list_t::iterator iter = mReceiveList.begin();
+ iter != mReceiveList.end();
+ ++iter)
+ {
+ xferp = (*iter);
+ if(xferp->mStatus == e_LL_XFER_PENDING)
+ { // Count and accumulate pending downloads
+ ++pending_count;
+ pending_downloads.push_front(xferp);
+ }
+ else if(xferp->mStatus == e_LL_XFER_IN_PROGRESS)
+ { // Count downloads in progress
+ ++download_count;
+ }
+ }
+
+ S32 start_count = mMaxIncomingXfers - download_count;
+
+ LL_DEBUGS("Xfer") << "LLXferManager::startPendingDownloads() - XFER_IN_PROGRESS: "
+ << download_count << " XFER_PENDING: " << pending_count
+ << " startring " << llmin(start_count, pending_count) << LL_ENDL;
+
+ if((start_count > 0) && (pending_count > 0))
+ {
+ S32 result;
+ for (std::list<LLXfer*>::iterator iter = pending_downloads.begin();
+ iter != pending_downloads.end(); ++iter)
+ {
+ xferp = *iter;
+ if (start_count-- <= 0)
+ break;
+ result = xferp->startDownload();
+ if(result)
+ {
+ xferp->abort(result);
+ ++start_count;
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////
+
+void LLXferManager::addToList(LLXfer* xferp, xfer_list_t & xfer_list, bool is_priority)
+{
+ if(is_priority)
+ {
+ xfer_list.push_back(xferp);
+ }
+ else
+ {
+ xfer_list.push_front(xferp);
+ }
+}
+
+///////////////////////////////////////////////////////////
+// Globals and C routines
+///////////////////////////////////////////////////////////
+
+LLXferManager *gXferManager = NULL;
+
+
+void start_xfer_manager()
+{
+ gXferManager = new LLXferManager();
+}
+
+void cleanup_xfer_manager()
+{
+ if (gXferManager)
+ {
+ delete(gXferManager);
+ gXferManager = NULL;
+ }
+}
+
+void process_confirm_packet (LLMessageSystem *mesgsys, void **user_data)
+{
+ gXferManager->processConfirmation(mesgsys,user_data);
+}
+
+void process_request_xfer(LLMessageSystem *mesgsys, void **user_data)
+{
+ gXferManager->processFileRequest(mesgsys,user_data);
+}
+
+void continue_file_receive(LLMessageSystem *mesgsys, void **user_data)
+{
+#if LL_TEST_XFER_REXMIT
+ if (ll_frand() > 0.05f)
+ {
+#endif
+ gXferManager->processReceiveData(mesgsys,user_data);
+#if LL_TEST_XFER_REXMIT
+ }
+ else
+ {
+ cout << "oops! dropped a xfer packet" << endl;
+ }
+#endif
+}
+
+void process_abort_xfer(LLMessageSystem *mesgsys, void **user_data)
+{
+ gXferManager->processAbort(mesgsys,user_data);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index 3999b41862..ce412ddd26 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -1,223 +1,223 @@ -/** - * @file llxfermanager.h - * @brief definition of LLXferManager class for a keeping track of - * multiple xfers - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLXFERMANAGER_H -#define LL_LLXFERMANAGER_H - -/** - * this manager keeps both a send list and a receive list; anything with a - * LLXferManager can send and receive files via messages - */ - -//Forward declaration to avoid circular dependencies -class LLXfer; - -#include "llxfer.h" -#include "message.h" -#include "llassetstorage.h" -#include "lldir.h" -#include <deque> -#include "llthrottle.h" - -class LLHostStatus -{ - public: - LLHost mHost; - S32 mNumActive; - S32 mNumPending; - - LLHostStatus() {mNumActive = 0; mNumPending = 0;}; - virtual ~LLHostStatus(){}; -}; - -// Class stores ack information, to be put on list so we can throttle xfer rate. -class LLXferAckInfo -{ -public: - LLXferAckInfo(U32 dummy = 0) - { - mID = 0; - mPacketNum = -1; - } - - U64 mID; - S32 mPacketNum; - LLHost mRemoteHost; -}; - -class LLXferManager -{ - protected: - S32 mMaxOutgoingXfersPerCircuit; - S32 mHardLimitOutgoingXfersPerCircuit; // At this limit, kill off the connection - S32 mMaxIncomingXfers; - - BOOL mUseAckThrottling; // Use ack throttling to cap file xfer bandwidth - std::deque<LLXferAckInfo> mXferAckQueue; - LLThrottle mAckThrottle; - public: - - // This enumeration is useful in the requestFile() to specify if - // an xfer must happen asap. - enum - { - LOW_PRIORITY = FALSE, - HIGH_PRIORITY = TRUE, - }; - - // Linked FIFO list, add to the front and pull from back - typedef std::deque<LLXfer *> xfer_list_t; - xfer_list_t mSendList; - xfer_list_t mReceiveList; - - typedef std::list<LLHostStatus*> status_list_t; - status_list_t mOutgoingHosts; - - protected: - // implementation methods - virtual void startPendingDownloads(); - virtual void addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority); - std::multiset<std::string> mExpectedTransfers; // files that are authorized to transfer out - std::multiset<std::string> mExpectedRequests; // files that are authorized to be downloaded on top of - std::multiset<std::string> mExpectedVFileTransfers; // files that are authorized to transfer out - std::multiset<std::string> mExpectedVFileRequests; // files that are authorized to be downloaded on top of - - public: - LLXferManager(); - virtual ~LLXferManager(); - - virtual void init(); - virtual void cleanup(); - - void setUseAckThrottling(const BOOL use); - void setAckThrottleBPS(const F32 bps); - -// list management routines - virtual LLXfer *findXferByID(U64 id, xfer_list_t & xfer_list); - virtual void removeXfer (LLXfer *delp, xfer_list_t & xfer_list); - - LLHostStatus * findHostStatus(const LLHost &host); - virtual S32 numActiveXfers(const LLHost &host); - virtual S32 numPendingXfers(const LLHost &host); - - virtual void changeNumActiveXfers(const LLHost &host, S32 delta); - - virtual void setMaxOutgoingXfersPerCircuit (S32 max_num); - virtual void setHardLimitOutgoingXfersPerCircuit(S32 max_num); - virtual void setMaxIncomingXfers(S32 max_num); - virtual void updateHostStatus(); - virtual void printHostStatus(); - -// general utility routines - virtual void registerCallbacks(LLMessageSystem *mesgsys); - virtual U64 getNextID (); - virtual S32 encodePacketNum(S32 packet_num, BOOL is_eof); - virtual S32 decodePacketNum(S32 packet_num); - virtual BOOL isLastPacket(S32 packet_num); - -// file requesting routines -// .. to file - virtual U64 requestFile(const std::string& local_filename, - const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void**,S32,LLExtStat), void** user_data, - BOOL is_priority = FALSE, - BOOL use_big_packets = FALSE); - /* -// .. to memory - virtual void requestFile(const std::string& remote_filename, - ELLPath remote_path, - const LLHost &remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void*, S32, void**, S32, LLExtStat), - void** user_data, - BOOL is_priority = FALSE); - */ -// vfile requesting -// .. to vfile - virtual void requestVFile(const LLUUID &local_id, const LLUUID& remote_id, - LLAssetType::EType type, - const LLHost& remote_host, - void (*callback)(void**,S32,LLExtStat), void** user_data, - BOOL is_priority = FALSE); - /** - When arbitrary files are requested to be transfered (by giving a dir of LL_PATH_NONE) - they must be "expected", but having something pre-authorize them. This pair of functions - maintains a pre-authorized list. The first function adds something to the list, the second - checks if is authorized, removing it if so. In this way, a file is only authorized for - a single use. - */ - virtual void expectFileForTransfer(const std::string& filename); - virtual bool validateFileForTransfer(const std::string& filename); - /** - Same idea, but for the viewer about to call InitiateDownload to track what it requested. - */ - virtual void expectFileForRequest(const std::string& filename); - virtual bool validateFileForRequest(const std::string& filename); - - /** - Same idea but for VFiles, kept separate to avoid namespace overlap - */ - /* Present in fireengine, not used by viewer - virtual void expectVFileForTransfer(const std::string& filename); - virtual bool validateVFileForTransfer(const std::string& filename); - virtual void expectVFileForRequest(const std::string& filename); - virtual bool validateVFileForRequest(const std::string& filename); - */ - - virtual void processReceiveData (LLMessageSystem *mesgsys, void **user_data); - virtual void sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host); - -// file sending routines - virtual void processFileRequest (LLMessageSystem *mesgsys, void **user_data); - virtual void processConfirmation (LLMessageSystem *mesgsys, void **user_data); - virtual void retransmitUnackedPackets (); - -// error handling - void abortRequestById(U64 xfer_id, S32 result_code); - virtual void processAbort (LLMessageSystem *mesgsys, void **user_data); - - virtual bool isHostFlooded(const LLHost & host); -}; - -extern LLXferManager* gXferManager; - -// initialization and garbage collection -void start_xfer_manager(); -void cleanup_xfer_manager(); - -// message system callbacks -void process_confirm_packet (LLMessageSystem *mesgsys, void **user_data); -void process_request_xfer (LLMessageSystem *mesgsys, void **user_data); -void continue_file_receive(LLMessageSystem *mesgsys, void **user_data); -void process_abort_xfer (LLMessageSystem *mesgsys, void **user_data); -#endif - - - +/**
+ * @file llxfermanager.h
+ * @brief definition of LLXferManager class for a keeping track of
+ * multiple xfers
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLXFERMANAGER_H
+#define LL_LLXFERMANAGER_H
+
+/**
+ * this manager keeps both a send list and a receive list; anything with a
+ * LLXferManager can send and receive files via messages
+ */
+
+//Forward declaration to avoid circular dependencies
+class LLXfer;
+
+#include "llxfer.h"
+#include "message.h"
+#include "llassetstorage.h"
+#include "lldir.h"
+#include <deque>
+#include "llthrottle.h"
+
+class LLHostStatus
+{
+ public:
+ LLHost mHost;
+ S32 mNumActive;
+ S32 mNumPending;
+
+ LLHostStatus() {mNumActive = 0; mNumPending = 0;};
+ virtual ~LLHostStatus(){};
+};
+
+// Class stores ack information, to be put on list so we can throttle xfer rate.
+class LLXferAckInfo
+{
+public:
+ LLXferAckInfo(U32 dummy = 0)
+ {
+ mID = 0;
+ mPacketNum = -1;
+ }
+
+ U64 mID;
+ S32 mPacketNum;
+ LLHost mRemoteHost;
+};
+
+class LLXferManager
+{
+ protected:
+ S32 mMaxOutgoingXfersPerCircuit;
+ S32 mHardLimitOutgoingXfersPerCircuit; // At this limit, kill off the connection
+ S32 mMaxIncomingXfers;
+
+ bool mUseAckThrottling; // Use ack throttling to cap file xfer bandwidth
+ std::deque<LLXferAckInfo> mXferAckQueue;
+ LLThrottle mAckThrottle;
+ public:
+
+ // This enumeration is useful in the requestFile() to specify if
+ // an xfer must happen asap.
+ enum
+ {
+ LOW_PRIORITY = false,
+ HIGH_PRIORITY = true,
+ };
+
+ // Linked FIFO list, add to the front and pull from back
+ typedef std::deque<LLXfer *> xfer_list_t;
+ xfer_list_t mSendList;
+ xfer_list_t mReceiveList;
+
+ typedef std::list<LLHostStatus*> status_list_t;
+ status_list_t mOutgoingHosts;
+
+ protected:
+ // implementation methods
+ virtual void startPendingDownloads();
+ virtual void addToList(LLXfer* xferp, xfer_list_t & xfer_list, bool is_priority);
+ std::multiset<std::string> mExpectedTransfers; // files that are authorized to transfer out
+ std::multiset<std::string> mExpectedRequests; // files that are authorized to be downloaded on top of
+ std::multiset<std::string> mExpectedVFileTransfers; // files that are authorized to transfer out
+ std::multiset<std::string> mExpectedVFileRequests; // files that are authorized to be downloaded on top of
+
+ public:
+ LLXferManager();
+ virtual ~LLXferManager();
+
+ virtual void init();
+ virtual void cleanup();
+
+ void setUseAckThrottling(const bool use);
+ void setAckThrottleBPS(const F32 bps);
+
+// list management routines
+ virtual LLXfer *findXferByID(U64 id, xfer_list_t & xfer_list);
+ virtual void removeXfer (LLXfer *delp, xfer_list_t & xfer_list);
+
+ LLHostStatus * findHostStatus(const LLHost &host);
+ virtual S32 numActiveXfers(const LLHost &host);
+ virtual S32 numPendingXfers(const LLHost &host);
+
+ virtual void changeNumActiveXfers(const LLHost &host, S32 delta);
+
+ virtual void setMaxOutgoingXfersPerCircuit (S32 max_num);
+ virtual void setHardLimitOutgoingXfersPerCircuit(S32 max_num);
+ virtual void setMaxIncomingXfers(S32 max_num);
+ virtual void updateHostStatus();
+ virtual void printHostStatus();
+
+// general utility routines
+ virtual void registerCallbacks(LLMessageSystem *mesgsys);
+ virtual U64 getNextID ();
+ virtual S32 encodePacketNum(S32 packet_num, bool is_eof);
+ virtual S32 decodePacketNum(S32 packet_num);
+ virtual bool isLastPacket(S32 packet_num);
+
+// file requesting routines
+// .. to file
+ virtual U64 requestFile(const std::string& local_filename,
+ const std::string& remote_filename,
+ ELLPath remote_path,
+ const LLHost& remote_host,
+ bool delete_remote_on_completion,
+ void (*callback)(void**,S32,LLExtStat), void** user_data,
+ bool is_priority = false,
+ bool use_big_packets = false);
+ /*
+// .. to memory
+ virtual void requestFile(const std::string& remote_filename,
+ ELLPath remote_path,
+ const LLHost &remote_host,
+ bool delete_remote_on_completion,
+ void (*callback)(void*, S32, void**, S32, LLExtStat),
+ void** user_data,
+ bool is_priority = false);
+ */
+// vfile requesting
+// .. to vfile
+ virtual void requestVFile(const LLUUID &local_id, const LLUUID& remote_id,
+ LLAssetType::EType type,
+ const LLHost& remote_host,
+ void (*callback)(void**,S32,LLExtStat), void** user_data,
+ bool is_priority = false);
+ /**
+ When arbitrary files are requested to be transfered (by giving a dir of LL_PATH_NONE)
+ they must be "expected", but having something pre-authorize them. This pair of functions
+ maintains a pre-authorized list. The first function adds something to the list, the second
+ checks if is authorized, removing it if so. In this way, a file is only authorized for
+ a single use.
+ */
+ virtual void expectFileForTransfer(const std::string& filename);
+ virtual bool validateFileForTransfer(const std::string& filename);
+ /**
+ Same idea, but for the viewer about to call InitiateDownload to track what it requested.
+ */
+ virtual void expectFileForRequest(const std::string& filename);
+ virtual bool validateFileForRequest(const std::string& filename);
+
+ /**
+ Same idea but for VFiles, kept separate to avoid namespace overlap
+ */
+ /* Present in fireengine, not used by viewer
+ virtual void expectVFileForTransfer(const std::string& filename);
+ virtual bool validateVFileForTransfer(const std::string& filename);
+ virtual void expectVFileForRequest(const std::string& filename);
+ virtual bool validateVFileForRequest(const std::string& filename);
+ */
+
+ virtual void processReceiveData (LLMessageSystem *mesgsys, void **user_data);
+ virtual void sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host);
+
+// file sending routines
+ virtual void processFileRequest (LLMessageSystem *mesgsys, void **user_data);
+ virtual void processConfirmation (LLMessageSystem *mesgsys, void **user_data);
+ virtual void retransmitUnackedPackets ();
+
+// error handling
+ void abortRequestById(U64 xfer_id, S32 result_code);
+ virtual void processAbort (LLMessageSystem *mesgsys, void **user_data);
+
+ virtual bool isHostFlooded(const LLHost & host);
+};
+
+extern LLXferManager* gXferManager;
+
+// initialization and garbage collection
+void start_xfer_manager();
+void cleanup_xfer_manager();
+
+// message system callbacks
+void process_confirm_packet (LLMessageSystem *mesgsys, void **user_data);
+void process_request_xfer (LLMessageSystem *mesgsys, void **user_data);
+void continue_file_receive(LLMessageSystem *mesgsys, void **user_data);
+void process_abort_xfer (LLMessageSystem *mesgsys, void **user_data);
+#endif
+
+
+
diff --git a/indra/llmessage/llxorcipher.cpp b/indra/llmessage/llxorcipher.cpp index dc92fb7f85..2770200fe5 100644 --- a/indra/llmessage/llxorcipher.cpp +++ b/indra/llmessage/llxorcipher.cpp @@ -1,128 +1,128 @@ -/** - * @file llxorcipher.cpp - * @brief Implementation of LLXORCipher - * - * $LicenseInfo:firstyear=2003&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$ - */ - -#include "linden_common.h" - -#include "llxorcipher.h" - -#include "llerror.h" - -///---------------------------------------------------------------------------- -/// Class LLXORCipher -///---------------------------------------------------------------------------- - -LLXORCipher::LLXORCipher(const U8* pad, U32 pad_len) : - mPad(NULL), - mHead(NULL), - mPadLen(0) -{ - init(pad, pad_len); -} - -// Destroys the object -LLXORCipher::~LLXORCipher() -{ - init(NULL, 0); -} - -LLXORCipher::LLXORCipher(const LLXORCipher& cipher) : - mPad(NULL), - mHead(NULL), - mPadLen(0) -{ - init(cipher.mPad, cipher.mPadLen); -} - -LLXORCipher& LLXORCipher::operator=(const LLXORCipher& cipher) -{ - if(this == &cipher) return *this; - init(cipher.mPad, cipher.mPadLen); - return *this; -} - -U32 LLXORCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) -{ - if(!src || !src_len || !dst || !dst_len || !mPad) return 0; - U8* pad_end = mPad + mPadLen; - U32 count = src_len; - while(count--) - { - *dst++ = *src++ ^ *mHead++; - if(mHead >= pad_end) mHead = mPad; - } - return src_len; -} - -U32 LLXORCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) -{ - // xor is a symetric cipher, thus, just call the other function. - return encrypt(src, src_len, dst, dst_len); -} - -U32 LLXORCipher::requiredEncryptionSpace(U32 len) const -{ - return len; -} - -void LLXORCipher::init(const U8* pad, U32 pad_len) -{ - if(mPad) - { - delete [] mPad; - mPad = NULL; - mPadLen = 0; - } - if(pad && pad_len) - { - mPadLen = pad_len; - mPad = new U8[mPadLen]; - if (mPad != NULL) - { - memcpy(mPad, pad, mPadLen); /* Flawfinder : ignore */ - } - } - mHead = mPad; -} - -#ifdef _DEBUG -// static -BOOL LLXORCipher::testHarness() -{ - const U32 PAD_LEN = 3; - const U8 PAD[] = "abc"; - const S32 MSG_LENGTH = 12; - const char MESSAGE[MSG_LENGTH+1] = "gesundheight"; /* Flawfinder : ignore */ - U8 encrypted[MSG_LENGTH]; - U8 decrypted[MSG_LENGTH]; - - LLXORCipher cipher(PAD, PAD_LEN); - cipher.encrypt((U8*)MESSAGE, MSG_LENGTH, encrypted, MSG_LENGTH); - cipher.decrypt(encrypted, MSG_LENGTH, decrypted, MSG_LENGTH); - - if(0 != memcmp((void*)MESSAGE, decrypted, MSG_LENGTH)) return FALSE; - return TRUE; -} -#endif +/**
+ * @file llxorcipher.cpp
+ * @brief Implementation of LLXORCipher
+ *
+ * $LicenseInfo:firstyear=2003&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$
+ */
+
+#include "linden_common.h"
+
+#include "llxorcipher.h"
+
+#include "llerror.h"
+
+///----------------------------------------------------------------------------
+/// Class LLXORCipher
+///----------------------------------------------------------------------------
+
+LLXORCipher::LLXORCipher(const U8* pad, U32 pad_len) :
+ mPad(NULL),
+ mHead(NULL),
+ mPadLen(0)
+{
+ init(pad, pad_len);
+}
+
+// Destroys the object
+LLXORCipher::~LLXORCipher()
+{
+ init(NULL, 0);
+}
+
+LLXORCipher::LLXORCipher(const LLXORCipher& cipher) :
+ mPad(NULL),
+ mHead(NULL),
+ mPadLen(0)
+{
+ init(cipher.mPad, cipher.mPadLen);
+}
+
+LLXORCipher& LLXORCipher::operator=(const LLXORCipher& cipher)
+{
+ if(this == &cipher) return *this;
+ init(cipher.mPad, cipher.mPadLen);
+ return *this;
+}
+
+U32 LLXORCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+{
+ if(!src || !src_len || !dst || !dst_len || !mPad) return 0;
+ U8* pad_end = mPad + mPadLen;
+ U32 count = src_len;
+ while(count--)
+ {
+ *dst++ = *src++ ^ *mHead++;
+ if(mHead >= pad_end) mHead = mPad;
+ }
+ return src_len;
+}
+
+U32 LLXORCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
+{
+ // xor is a symetric cipher, thus, just call the other function.
+ return encrypt(src, src_len, dst, dst_len);
+}
+
+U32 LLXORCipher::requiredEncryptionSpace(U32 len) const
+{
+ return len;
+}
+
+void LLXORCipher::init(const U8* pad, U32 pad_len)
+{
+ if(mPad)
+ {
+ delete [] mPad;
+ mPad = NULL;
+ mPadLen = 0;
+ }
+ if(pad && pad_len)
+ {
+ mPadLen = pad_len;
+ mPad = new U8[mPadLen];
+ if (mPad != NULL)
+ {
+ memcpy(mPad, pad, mPadLen); /* Flawfinder : ignore */
+ }
+ }
+ mHead = mPad;
+}
+
+#ifdef _DEBUG
+// static
+bool LLXORCipher::testHarness()
+{
+ const U32 PAD_LEN = 3;
+ const U8 PAD[] = "abc";
+ const S32 MSG_LENGTH = 12;
+ const char MESSAGE[MSG_LENGTH+1] = "gesundheight"; /* Flawfinder : ignore */
+ U8 encrypted[MSG_LENGTH];
+ U8 decrypted[MSG_LENGTH];
+
+ LLXORCipher cipher(PAD, PAD_LEN);
+ cipher.encrypt((U8*)MESSAGE, MSG_LENGTH, encrypted, MSG_LENGTH);
+ cipher.decrypt(encrypted, MSG_LENGTH, decrypted, MSG_LENGTH);
+
+ if(0 != memcmp((void*)MESSAGE, decrypted, MSG_LENGTH)) return false;
+ return true;
+}
+#endif
diff --git a/indra/llmessage/llxorcipher.h b/indra/llmessage/llxorcipher.h index fa1fb11b78..14cea5dc02 100644 --- a/indra/llmessage/llxorcipher.h +++ b/indra/llmessage/llxorcipher.h @@ -1,67 +1,67 @@ -/** - * @file llxorcipher.h - * - * $LicenseInfo:firstyear=2003&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$ - */ - -#ifndef LLXORCIPHER_H -#define LLXORCIPHER_H - -#include "llcipher.h" - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLXORCipher -// -// Implementation of LLCipher which encrypts using a XOR pad. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLXORCipher : public LLCipher -{ -public: - LLXORCipher(const U8* pad, U32 pad_len); - LLXORCipher(const LLXORCipher& cipher); - virtual ~LLXORCipher(); - LLXORCipher& operator=(const LLXORCipher& cipher); - - // Cipher functions - /*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); - /*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); - /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const; - - // special syntactic-sugar since xor can be performed in place. - BOOL encrypt(U8* buf, U32 len) { return encrypt((const U8*)buf, len, buf, len); } - BOOL decrypt(U8* buf, U32 len) { return decrypt((const U8*)buf, len, buf, len); } - -#ifdef _DEBUG - // This function runs tests to make sure the crc is - // working. Returns TRUE if it is. - static BOOL testHarness(); -#endif - -protected: - void init(const U8* pad, U32 pad_len); - U8* mPad; - U8* mHead; - U32 mPadLen; -}; - -#endif +/**
+ * @file llxorcipher.h
+ *
+ * $LicenseInfo:firstyear=2003&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$
+ */
+
+#ifndef LLXORCIPHER_H
+#define LLXORCIPHER_H
+
+#include "llcipher.h"
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLXORCipher
+//
+// Implementation of LLCipher which encrypts using a XOR pad.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLXORCipher : public LLCipher
+{
+public:
+ LLXORCipher(const U8* pad, U32 pad_len);
+ LLXORCipher(const LLXORCipher& cipher);
+ virtual ~LLXORCipher();
+ LLXORCipher& operator=(const LLXORCipher& cipher);
+
+ // Cipher functions
+ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) override;
+ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) override;
+ U32 requiredEncryptionSpace(U32 src_len) const override;
+
+ // special syntactic-sugar since xor can be performed in place.
+ bool encrypt(U8* buf, U32 len) { return encrypt((const U8*)buf, len, buf, len) > 0; }
+ bool decrypt(U8* buf, U32 len) { return decrypt((const U8*)buf, len, buf, len) > 0; }
+
+#ifdef _DEBUG
+ // This function runs tests to make sure the crc is
+ // working. Returns true if it is.
+ static bool testHarness();
+#endif
+
+protected:
+ void init(const U8* pad, U32 pad_len);
+ U8* mPad;
+ U8* mHead;
+ U32 mPadLen;
+};
+
+#endif
diff --git a/indra/llmessage/machine.h b/indra/llmessage/machine.h index 17cfd9771f..67e890d19a 100644 --- a/indra/llmessage/machine.h +++ b/indra/llmessage/machine.h @@ -1,95 +1,95 @@ -/** - * @file machine.h - * @brief LLMachine class header file - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_MACHINE_H -#define LL_MACHINE_H - -#include "net.h" -#include "llhost.h" - -typedef enum e_machine_type -{ - MT_NULL, - MT_SIMULATOR, - MT_VIEWER, - MT_SPACE_SERVER, - MT_OBJECT_REPOSITORY, - MT_PROXY, - MT_EOF -} EMachineType; - -const U32 ADDRESS_STRING_SIZE = 12; - -class LLMachine -{ -public: - LLMachine() - : mMachineType(MT_NULL), mControlPort(0) {} - - LLMachine(EMachineType machine_type, U32 ip, S32 port) - : mMachineType(machine_type), mControlPort(0), mHost(ip,port) {} - - LLMachine(EMachineType machine_type, const LLHost &host) - : mMachineType(machine_type) {mHost = host; mControlPort = 0;} - - ~LLMachine() {} - - // get functions - EMachineType getMachineType() const { return mMachineType; } - U32 getMachineIP() const { return mHost.getAddress(); } - S32 getMachinePort() const { return mHost.getPort(); } - const LLHost &getMachineHost() const { return mHost; } - // The control port is the listen port of the parent process that - // launched this machine. 0 means none or not known. - const S32 &getControlPort() const { return mControlPort; } - BOOL isValid() const { return (mHost.getPort() != 0); } // TRUE if corresponds to functioning machine - - // set functions - void setMachineType(EMachineType machine_type) { mMachineType = machine_type; } - void setMachineIP(U32 ip) { mHost.setAddress(ip); } - void setMachineHost(const LLHost &host) { mHost = host; } - - void setMachinePort(S32 port); - void setControlPort( S32 port ); - - - // member variables - -// Someday these should be made private. -// When they are, some of the code that breaks should -// become member functions of LLMachine -- Leviathan -//private: - - // I fixed the others, somebody should fix these! - djs - EMachineType mMachineType; - -protected: - - S32 mControlPort; - LLHost mHost; -}; - -#endif +/**
+ * @file machine.h
+ * @brief LLMachine class header file
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_MACHINE_H
+#define LL_MACHINE_H
+
+#include "net.h"
+#include "llhost.h"
+
+typedef enum e_machine_type
+{
+ MT_NULL,
+ MT_SIMULATOR,
+ MT_VIEWER,
+ MT_SPACE_SERVER,
+ MT_OBJECT_REPOSITORY,
+ MT_PROXY,
+ MT_EOF
+} EMachineType;
+
+const U32 ADDRESS_STRING_SIZE = 12;
+
+class LLMachine
+{
+public:
+ LLMachine()
+ : mMachineType(MT_NULL), mControlPort(0) {}
+
+ LLMachine(EMachineType machine_type, U32 ip, S32 port)
+ : mMachineType(machine_type), mControlPort(0), mHost(ip,port) {}
+
+ LLMachine(EMachineType machine_type, const LLHost &host)
+ : mMachineType(machine_type) {mHost = host; mControlPort = 0;}
+
+ ~LLMachine() {}
+
+ // get functions
+ EMachineType getMachineType() const { return mMachineType; }
+ U32 getMachineIP() const { return mHost.getAddress(); }
+ S32 getMachinePort() const { return mHost.getPort(); }
+ const LLHost &getMachineHost() const { return mHost; }
+ // The control port is the listen port of the parent process that
+ // launched this machine. 0 means none or not known.
+ const S32 &getControlPort() const { return mControlPort; }
+ bool isValid() const { return (mHost.getPort() != 0); } // true if corresponds to functioning machine
+
+ // set functions
+ void setMachineType(EMachineType machine_type) { mMachineType = machine_type; }
+ void setMachineIP(U32 ip) { mHost.setAddress(ip); }
+ void setMachineHost(const LLHost &host) { mHost = host; }
+
+ void setMachinePort(S32 port);
+ void setControlPort( S32 port );
+
+
+ // member variables
+
+// Someday these should be made private.
+// When they are, some of the code that breaks should
+// become member functions of LLMachine -- Leviathan
+//private:
+
+ // I fixed the others, somebody should fix these! - djs
+ EMachineType mMachineType;
+
+protected:
+
+ S32 mControlPort;
+ LLHost mHost;
+};
+
+#endif
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 398b3ac757..b57f8f4513 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -1,4052 +1,4055 @@ -/** - * @file message.cpp - * @brief LLMessageSystem class implementation - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "message.h" - -// system library includes -#if !LL_WINDOWS -// following header files required for inet_addr() -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#endif -#include <iomanip> -#include <iterator> -#include <sstream> - -#include "llapr.h" -#include "apr_portable.h" -#include "apr_network_io.h" -#include "apr_poll.h" - -// linden library headers -#include "llapp.h" -#include "indra_constants.h" -#include "lldir.h" -#include "llerror.h" -#include "llfasttimer.h" -#include "llhttpnodeadapter.h" -#include "llmd5.h" -#include "llmessagebuilder.h" -#include "llmessageconfig.h" -#include "lltemplatemessagedispatcher.h" -#include "llpumpio.h" -#include "lltemplatemessagebuilder.h" -#include "lltemplatemessagereader.h" -#include "lltrustedmessageservice.h" -#include "llmessagetemplate.h" -#include "llmessagetemplateparser.h" -#include "llsd.h" -#include "llsdmessagebuilder.h" -#include "llsdmessagereader.h" -#include "llsdserialize.h" -#include "llstring.h" -#include "lltransfermanager.h" -#include "lluuid.h" -#include "llxfermanager.h" -#include "llquaternion.h" -#include "u64.h" -#include "v3dmath.h" -#include "v3math.h" -#include "v4math.h" -#include "lltransfertargetvfile.h" -#include "llcorehttputil.h" -#include "llpounceable.h" - -// Constants -//const char* MESSAGE_LOG_FILENAME = "message.log"; -static const F32Seconds CIRCUIT_DUMP_TIMEOUT(30.f); -static const S32 TRUST_TIME_WINDOW = 3; - -// *NOTE: This needs to be moved into a seperate file so that it never gets -// included in the viewer. 30 Sep 2002 mark -// *NOTE: I don't think it's important that the messgage system tracks -// this since it must get set externally. 2004.08.25 Phoenix. -static std::string g_shared_secret; -std::string get_shared_secret(); - -class LLMessagePollInfo -{ -public: - apr_socket_t *mAPRSocketp; - apr_pollfd_t mPollFD; -}; - -class LLMessageHandlerBridge : public LLHTTPNode -{ - virtual bool validate(const std::string& name, LLSD& context) const - { return true; } - - virtual void post(LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const; -}; - -//virtual -void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response, - const LLSD& context, const LLSD& input) const -{ - std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"]; - char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str()); - - LL_DEBUGS() << "Setting mLastSender " << input["sender"].asString() << LL_ENDL; - gMessageSystem->mLastSender = LLHost(input["sender"].asString()); - gMessageSystem->mPacketsIn += 1; - gMessageSystem->mLLSDMessageReader->setMessage(namePtr, input["body"]); - LockMessageReader rdr(gMessageSystem->mMessageReader, gMessageSystem->mLLSDMessageReader); - - if(gMessageSystem->callHandler(namePtr, false, gMessageSystem)) - { - response->result(LLSD()); - } - else - { - response->notFound(); - } -} - -LLHTTPRegistration<LLMessageHandlerBridge> - gHTTPRegistrationMessageWildcard("/message/<message-name>"); - -//virtual -LLUseCircuitCodeResponder::~LLUseCircuitCodeResponder() -{ - // even abstract base classes need a concrete destructor -} - -static const char* nullToEmpty(const char* s) -{ - static char emptyString[] = ""; - return s? s : emptyString; -} - -void LLMessageSystem::init() -{ - // initialize member variables - mVerboseLog = FALSE; - - mbError = FALSE; - mErrorCode = 0; - mSendReliable = FALSE; - - mUnackedListDepth = 0; - mUnackedListSize = 0; - mDSMaxListDepth = 0; - - mNumberHighFreqMessages = 0; - mNumberMediumFreqMessages = 0; - mNumberLowFreqMessages = 0; - mPacketsIn = mPacketsOut = 0; - mBytesIn = mBytesOut = 0; - mCompressedPacketsIn = mCompressedPacketsOut = 0; - mReliablePacketsIn = mReliablePacketsOut = 0; - - mCompressedBytesIn = 0; - mCompressedBytesOut = 0; - mUncompressedBytesIn = 0; - mUncompressedBytesOut = 0; - mTotalBytesIn = 0; - mTotalBytesOut = 0; - - mDroppedPackets = 0; // total dropped packets in - mResentPackets = 0; // total resent packets out - mFailedResendPackets = 0; // total resend failure packets out - mOffCircuitPackets = 0; // total # of off-circuit packets rejected - mInvalidOnCircuitPackets = 0; // total # of on-circuit packets rejected - - mOurCircuitCode = 0; - - mIncomingCompressedSize = 0; - mCurrentRecvPacketID = 0; - - mMessageFileVersionNumber = 0.f; - - mTimingCallback = NULL; - mTimingCallbackData = NULL; - - mMessageBuilder = NULL; - LockMessageReader(mMessageReader, NULL); -} - -// Read file and build message templates -LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, - S32 version_major, - S32 version_minor, - S32 version_patch, - bool failure_is_fatal, - const F32 circuit_heartbeat_interval, const F32 circuit_timeout) : - mCircuitInfo(F32Seconds(circuit_heartbeat_interval), F32Seconds(circuit_timeout)), - mLastMessageFromTrustedMessageService(false) -{ - init(); - - mSendSize = 0; - - mSystemVersionMajor = version_major; - mSystemVersionMinor = version_minor; - mSystemVersionPatch = version_patch; - mSystemVersionServer = 0; - mVersionFlags = 0x0; - - // default to not accepting packets from not alive circuits - mbProtected = TRUE; - - // default to blocking trusted connections on a public interface if one is specified - mBlockUntrustedInterface = true; - - mSendPacketFailureCount = 0; - - mCircuitPrintFreq = F32Seconds(60.f); - - loadTemplateFile(filename, failure_is_fatal); - - mTemplateMessageBuilder = new LLTemplateMessageBuilder(mMessageTemplates); - mLLSDMessageBuilder = new LLSDMessageBuilder(); - mMessageBuilder = NULL; - - mTemplateMessageReader = new LLTemplateMessageReader(mMessageNumbers); - mLLSDMessageReader = new LLSDMessageReader(); - - // initialize various bits of net info - mSocket = 0; - mPort = port; - - S32 error = start_net(mSocket, mPort); - if (error != 0) - { - mbError = TRUE; - mErrorCode = error; - } -// LL_DEBUGS("Messaging") << << "*** port: " << mPort << LL_ENDL; - - // - // Create the data structure that we can poll on - // - if (!gAPRPoolp) - { - LL_ERRS("Messaging") << "No APR pool before message system initialization!" << LL_ENDL; - ll_init_apr(); - } - apr_socket_t *aprSocketp = NULL; - apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, gAPRPoolp); - - mPollInfop = new LLMessagePollInfo; - mPollInfop->mAPRSocketp = aprSocketp; - mPollInfop->mPollFD.p = gAPRPoolp; - mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET; - mPollInfop->mPollFD.reqevents = APR_POLLIN; - mPollInfop->mPollFD.rtnevents = 0; - mPollInfop->mPollFD.desc.s = aprSocketp; - mPollInfop->mPollFD.client_data = NULL; - - F64Seconds mt_sec = getMessageTimeSeconds(); - mResendDumpTime = mt_sec; - mMessageCountTime = mt_sec; - mCircuitPrintTime = mt_sec; - mCurrentMessageTime = F64Seconds(mt_sec); - - // Constants for dumping output based on message processing time/count - mNumMessageCounts = 0; - mMaxMessageCounts = 200; // >= 0 means dump warnings - mMaxMessageTime = F32Seconds(1.f); - - mTrueReceiveSize = 0; - - mReceiveTime = F32Seconds(0.f); -} - - - -// Read file and build message templates -void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure_is_fatal) -{ - if(filename.empty()) - { - LL_ERRS("Messaging") << "No template filename specified" << LL_ENDL; - mbError = TRUE; - return; - } - - std::string template_body; - if(!_read_file_into_string(template_body, filename)) - { - if (failure_is_fatal) { - LL_ERRS("Messaging") << "Failed to open template: " << filename << LL_ENDL; - } else { - LL_WARNS("Messaging") << "Failed to open template: " << filename << LL_ENDL; - } - mbError = TRUE; - return; - } - - LLTemplateTokenizer tokens(template_body); - LLTemplateParser parsed(tokens); - mMessageFileVersionNumber = parsed.getVersion(); - for(LLTemplateParser::message_iterator iter = parsed.getMessagesBegin(); - iter != parsed.getMessagesEnd(); - iter++) - { - addTemplate(*iter); - } -} - - -LLMessageSystem::~LLMessageSystem() -{ - mMessageTemplates.clear(); // don't delete templates. - for_each(mMessageNumbers.begin(), mMessageNumbers.end(), DeletePairedPointer()); - mMessageNumbers.clear(); - - if (!mbError) - { - end_net(mSocket); - } - mSocket = 0; - - delete mTemplateMessageReader; - mTemplateMessageReader = NULL; - - delete mTemplateMessageBuilder; - mTemplateMessageBuilder = NULL; - mMessageBuilder = NULL; - - delete mLLSDMessageReader; - mLLSDMessageReader = NULL; - - delete mLLSDMessageBuilder; - mLLSDMessageBuilder = NULL; - - delete mPollInfop; - mPollInfop = NULL; - - mIncomingCompressedSize = 0; - mCurrentRecvPacketID = 0; -} - -void LLMessageSystem::clearReceiveState() -{ - mCurrentRecvPacketID = 0; - mIncomingCompressedSize = 0; - mLastSender.invalidate(); - mLastReceivingIF.invalidate(); - mMessageReader->clearMessage(); - mLastMessageFromTrustedMessageService = false; -} - - -BOOL LLMessageSystem::poll(F32 seconds) -{ - S32 num_socks; - apr_status_t status; - status = apr_poll(&(mPollInfop->mPollFD), 1, &num_socks,(U64)(seconds*1000000.f)); - if (status != APR_TIMEUP) - { - ll_apr_warn_status(status); - } - if (num_socks) - { - return TRUE; - } - else - { - return FALSE; - } -} - -bool LLMessageSystem::isTrustedSender(const LLHost& host) const -{ - LLCircuitData* cdp = mCircuitInfo.findCircuit(host); - if(NULL == cdp) - { - return false; - } - return cdp->getTrusted(); -} - -void LLMessageSystem::receivedMessageFromTrustedSender() -{ - mLastMessageFromTrustedMessageService = true; -} - -bool LLMessageSystem::isTrustedSender() const -{ - return mLastMessageFromTrustedMessageService || - isTrustedSender(getSender()); -} - -static LLMessageSystem::message_template_name_map_t::const_iterator -findTemplate(const LLMessageSystem::message_template_name_map_t& templates, - std::string name) -{ - const char* namePrehash = LLMessageStringTable::getInstance()->getString(name.c_str()); - if(NULL == namePrehash) {return templates.end();} - return templates.find(namePrehash); -} - -bool LLMessageSystem::isTrustedMessage(const std::string& name) const -{ - message_template_name_map_t::const_iterator iter = - findTemplate(mMessageTemplates, name); - if(iter == mMessageTemplates.end()) {return false;} - return iter->second->getTrust() == MT_TRUST; -} - -bool LLMessageSystem::isUntrustedMessage(const std::string& name) const -{ - message_template_name_map_t::const_iterator iter = - findTemplate(mMessageTemplates, name); - if(iter == mMessageTemplates.end()) {return false;} - return iter->second->getTrust() == MT_NOTRUST; -} - -LLCircuitData* LLMessageSystem::findCircuit(const LLHost& host, - bool resetPacketId) -{ - LLCircuitData* cdp = mCircuitInfo.findCircuit(host); - if (!cdp) - { - // This packet comes from a circuit we don't know about. - - // Are we rejecting off-circuit packets? - if (mbProtected) - { - // cdp is already NULL, so we don't need to unset it. - } - else - { - // nope, open the new circuit - cdp = mCircuitInfo.addCircuitData(host, mCurrentRecvPacketID); - - if(resetPacketId) - { - // I added this - I think it's correct - DJS - // reset packet in ID - cdp->setPacketInID(mCurrentRecvPacketID); - } - // And claim the packet is on the circuit we just added. - } - } - else - { - // this is an old circuit. . . is it still alive? - if (!cdp->isAlive()) - { - // nope. don't accept if we're protected - if (mbProtected) - { - // don't accept packets from unexpected sources - cdp = NULL; - } - else - { - // wake up the circuit - cdp->setAlive(TRUE); - - if(resetPacketId) - { - // reset packet in ID - cdp->setPacketInID(mCurrentRecvPacketID); - } - } - } - } - return cdp; -} - -// Returns TRUE if a valid, on-circuit message has been received. -// Requiring a non-const LockMessageChecker reference ensures that -// mMessageReader has been set to mTemplateMessageReader. -BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) -{ - // Pump - BOOL valid_packet = FALSE; - - LLTransferTargetVFile::updateQueue(); - - if (!mNumMessageCounts) - { - // This is the first message being handled after a resetReceiveCounts, - // we must be starting the message processing loop. Reset the timers. - mCurrentMessageTime = totalTime(); - mMessageCountTime = getMessageTimeSeconds(); - } - - // loop until either no packets or a valid packet - // i.e., burn through packets from unregistered circuits - S32 receive_size = 0; - do - { - clearReceiveState(); - - BOOL recv_reliable = FALSE; - BOOL recv_resent = FALSE; - S32 acks = 0; - S32 true_rcv_size = 0; - - U8* buffer = mTrueReceiveBuffer; - - mTrueReceiveSize = mPacketRing.receivePacket(mSocket, (char *)mTrueReceiveBuffer); - // If you want to dump all received packets into SecondLife.log, uncomment this - //dumpPacketToLog(); - - receive_size = mTrueReceiveSize; - mLastSender = mPacketRing.getLastSender(); - mLastReceivingIF = mPacketRing.getLastReceivingInterface(); - - if (receive_size < (S32) LL_MINIMUM_VALID_PACKET_SIZE) - { - // A receive size of zero is OK, that means that there are no more packets available. - // Ones that are non-zero but below the minimum packet size are worrisome. - if (receive_size > 0) - { - LL_WARNS("Messaging") << "Invalid (too short) packet discarded " << receive_size << LL_ENDL; - callExceptionFunc(MX_PACKET_TOO_SHORT); - } - // no data in packet receive buffer - valid_packet = FALSE; - } - else - { - LLHost host; - LLCircuitData* cdp; - - // note if packet acks are appended. - if(buffer[0] & LL_ACK_FLAG) - { - acks += buffer[--receive_size]; - true_rcv_size = receive_size; - if(receive_size >= ((S32)(acks * sizeof(TPACKETID) + LL_MINIMUM_VALID_PACKET_SIZE))) - { - receive_size -= acks * sizeof(TPACKETID); - } - else - { - // mal-formed packet. ignore it and continue with - // the next one - LL_WARNS("Messaging") << "Malformed packet received. Packet size " - << receive_size << " with invalid no. of acks " << acks - << LL_ENDL; - valid_packet = FALSE; - continue; - } - } - - // process the message as normal - mIncomingCompressedSize = zeroCodeExpand(&buffer, &receive_size); - mCurrentRecvPacketID = ntohl(*((U32*)(&buffer[1]))); - host = getSender(); - - const bool resetPacketId = true; - cdp = findCircuit(host, resetPacketId); - - // At this point, cdp is now a pointer to the circuit that - // this message came in on if it's valid, and NULL if the - // circuit was bogus. - - if(cdp && (acks > 0) && ((S32)(acks * sizeof(TPACKETID)) < (true_rcv_size))) - { - TPACKETID packet_id; - U32 mem_id=0; - for(S32 i = 0; i < acks; ++i) - { - true_rcv_size -= sizeof(TPACKETID); - memcpy(&mem_id, &mTrueReceiveBuffer[true_rcv_size], /* Flawfinder: ignore*/ - sizeof(TPACKETID)); - packet_id = ntohl(mem_id); - //LL_INFOS("Messaging") << "got ack: " << packet_id << LL_ENDL; - cdp->ackReliablePacket(packet_id); - } - if (!cdp->getUnackedPacketCount()) - { - // Remove this circuit from the list of circuits with unacked packets - mCircuitInfo.mUnackedCircuitMap.erase(cdp->mHost); - } - } - - if (buffer[0] & LL_RELIABLE_FLAG) - { - recv_reliable = TRUE; - } - if (buffer[0] & LL_RESENT_FLAG) - { - recv_resent = TRUE; - if (cdp && cdp->isDuplicateResend(mCurrentRecvPacketID)) - { - // We need to ACK here to suppress - // further resends of packets we've - // already seen. - if (recv_reliable) - { - //mAckList.addData(new LLPacketAck(host, mCurrentRecvPacketID)); - // *************************************** - // TESTING CODE - //if(mCircuitInfo.mCurrentCircuit->mHost != host) - //{ - // LL_WARNS("Messaging") << "DISCARDED PACKET HOST MISMATCH! HOST: " - // << host << " CIRCUIT: " - // << mCircuitInfo.mCurrentCircuit->mHost - // << LL_ENDL; - //} - // *************************************** - //mCircuitInfo.mCurrentCircuit->mAcks.put(mCurrentRecvPacketID); - cdp->collectRAck(mCurrentRecvPacketID); - } - - LL_DEBUGS("Messaging") << "Discarding duplicate resend from " << host << LL_ENDL; - if(mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << host; - std::string tbuf; - tbuf = llformat( "\t%6d\t%6d\t%6d ", receive_size, (mIncomingCompressedSize ? mIncomingCompressedSize : receive_size), mCurrentRecvPacketID); - str << tbuf << "(unknown)" - << (recv_reliable ? " reliable" : "") - << " resent " - << ((acks > 0) ? "acks" : "") - << " DISCARD DUPLICATE"; - LL_INFOS("Messaging") << str.str() << LL_ENDL; - } - mPacketsIn++; - valid_packet = FALSE; - continue; - } - } - - // UseCircuitCode can be a valid, off-circuit packet. - // But we don't want to acknowledge UseCircuitCode until the circuit is - // available, which is why the acknowledgement test is done above. JC - bool trusted = cdp && cdp->getTrusted(); - valid_packet = mTemplateMessageReader->validateMessage( - buffer, - receive_size, - host, - trusted); - if (!valid_packet) - { - clearReceiveState(); - } - - // UseCircuitCode is allowed in even from an invalid circuit, so that - // we can toss circuits around. - if( - valid_packet && - !cdp && - (mTemplateMessageReader->getMessageName() != - _PREHASH_UseCircuitCode)) - { - logMsgFromInvalidCircuit( host, recv_reliable ); - clearReceiveState(); - valid_packet = FALSE; - } - - if( - valid_packet && - cdp && - !cdp->getTrusted() && - mTemplateMessageReader->isTrusted()) - { - logTrustedMsgFromUntrustedCircuit( host ); - clearReceiveState(); - - sendDenyTrustedCircuit(host); - valid_packet = FALSE; - } - - if( valid_packet ) - { - logValidMsg(cdp, host, recv_reliable, recv_resent, (BOOL)(acks>0) ); - valid_packet = mTemplateMessageReader->readMessage(buffer, host); - } - - // It's possible that the circuit went away, because ANY message can disable the circuit - // (for example, UseCircuit, CloseCircuit, DisableSimulator). Find it again. - cdp = mCircuitInfo.findCircuit(host); - - if (valid_packet) - { - mPacketsIn++; - mBytesIn += mTrueReceiveSize; - - // ACK here for valid packets that we've seen - // for the first time. - if (cdp && recv_reliable) - { - // Add to the recently received list for duplicate suppression - cdp->mRecentlyReceivedReliablePackets[mCurrentRecvPacketID] = getMessageTimeUsecs(); - - // Put it onto the list of packets to be acked - cdp->collectRAck(mCurrentRecvPacketID); - mReliablePacketsIn++; - } - } - else - { - if (mbProtected && (!cdp)) - { - LL_WARNS("Messaging") << "Invalid Packet from invalid circuit " << host << LL_ENDL; - mOffCircuitPackets++; - } - else - { - mInvalidOnCircuitPackets++; - } - } - } - } while (!valid_packet && receive_size > 0); - - F64Seconds mt_sec = getMessageTimeSeconds(); - // Check to see if we need to print debug info - if ((mt_sec - mCircuitPrintTime) > mCircuitPrintFreq) - { - dumpCircuitInfo(); - mCircuitPrintTime = mt_sec; - } - - if( !valid_packet ) - { - clearReceiveState(); - } - - return valid_packet; -} - -S32 LLMessageSystem::getReceiveBytes() const -{ - if (getReceiveCompressedSize()) - { - return getReceiveCompressedSize() * 8; - } - else - { - return getReceiveSize() * 8; - } -} - - -void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time) -{ - F64Seconds mt_sec = getMessageTimeSeconds(); - { - gTransferManager.updateTransfers(); - - if (gXferManager) - { - gXferManager->retransmitUnackedPackets(); - } - - if (gAssetStorage) - { - gAssetStorage->checkForTimeouts(); - } - } - - BOOL dump = FALSE; - { - // Check the status of circuits - mCircuitInfo.updateWatchDogTimers(this); - - //resend any necessary packets - mCircuitInfo.resendUnackedPackets(mUnackedListDepth, mUnackedListSize); - - //cycle through ack list for each host we need to send acks to - mCircuitInfo.sendAcks(collect_time); - - if (!mDenyTrustedCircuitSet.empty()) - { - LL_INFOS("Messaging") << "Sending queued DenyTrustedCircuit messages." << LL_ENDL; - for (host_set_t::iterator hostit = mDenyTrustedCircuitSet.begin(); hostit != mDenyTrustedCircuitSet.end(); ++hostit) - { - reallySendDenyTrustedCircuit(*hostit); - } - mDenyTrustedCircuitSet.clear(); - } - - if (mMaxMessageCounts >= 0) - { - if (mNumMessageCounts >= mMaxMessageCounts) - { - dump = TRUE; - } - } - - if (mMaxMessageTime >= F32Seconds(0.f)) - { - // This is one of the only places where we're required to get REAL message system time. - mReceiveTime = getMessageTimeSeconds(TRUE) - mMessageCountTime; - if (mReceiveTime > mMaxMessageTime) - { - dump = TRUE; - } - } - } - - if (dump) - { - dumpReceiveCounts(); - } - resetReceiveCounts(); - - if ((mt_sec - mResendDumpTime) > CIRCUIT_DUMP_TIMEOUT) - { - mResendDumpTime = mt_sec; - mCircuitInfo.dumpResends(); - } -} - -void LLMessageSystem::copyMessageReceivedToSend() -{ - // NOTE: babbage: switch builder to match reader to avoid - // converting message format - if(mMessageReader == mTemplateMessageReader) - { - mMessageBuilder = mTemplateMessageBuilder; - } - else - { - mMessageBuilder = mLLSDMessageBuilder; - } - mSendReliable = FALSE; - mMessageBuilder->newMessage(mMessageReader->getMessageName()); - mMessageReader->copyToBuilder(*mMessageBuilder); -} - -LLSD LLMessageSystem::getReceivedMessageLLSD() const -{ - LLSDMessageBuilder builder; - mMessageReader->copyToBuilder(builder); - return builder.getMessage(); -} - -LLSD LLMessageSystem::getBuiltMessageLLSD() const -{ - LLSD result; - if (mLLSDMessageBuilder == mMessageBuilder) - { - result = mLLSDMessageBuilder->getMessage(); - } - else - { - // TODO: implement as below? - LL_ERRS() << "Message not built as LLSD." << LL_ENDL; - } - return result; -} - -LLSD LLMessageSystem::wrapReceivedTemplateData() const -{ - if(mMessageReader == mTemplateMessageReader) - { - LLTemplateMessageBuilder builder(mMessageTemplates); - builder.newMessage(mMessageReader->getMessageName()); - mMessageReader->copyToBuilder(builder); - U8 buffer[MAX_BUFFER_SIZE]; - const U8 offset_to_data = 0; - U32 size = builder.buildMessage(buffer, MAX_BUFFER_SIZE, - offset_to_data); - std::vector<U8> binary_data(buffer, buffer+size); - LLSD wrapped_data = LLSD::emptyMap(); - wrapped_data["binary-template-data"] = binary_data; - return wrapped_data; - } - else - { - return getReceivedMessageLLSD(); - } -} - -LLSD LLMessageSystem::wrapBuiltTemplateData() const -{ - LLSD result; - if (mLLSDMessageBuilder == mMessageBuilder) - { - result = getBuiltMessageLLSD(); - } - else - { - U8 buffer[MAX_BUFFER_SIZE]; - const U8 offset_to_data = 0; - U32 size = mTemplateMessageBuilder->buildMessage( - buffer, MAX_BUFFER_SIZE, - offset_to_data); - std::vector<U8> binary_data(buffer, buffer+size); - LLSD wrapped_data = LLSD::emptyMap(); - wrapped_data["binary-template-data"] = binary_data; - result = wrapped_data; - } - return result; -} - -LLStoredMessagePtr LLMessageSystem::getReceivedMessage() const -{ - const std::string& name = mMessageReader->getMessageName(); - LLSD message = wrapReceivedTemplateData(); - - return LLStoredMessagePtr(new LLStoredMessage(name, message)); -} - -LLStoredMessagePtr LLMessageSystem::getBuiltMessage() const -{ - const std::string& name = mMessageBuilder->getMessageName(); - LLSD message = wrapBuiltTemplateData(); - - return LLStoredMessagePtr(new LLStoredMessage(name, message)); -} - -S32 LLMessageSystem::sendMessage(const LLHost &host, LLStoredMessagePtr message) -{ - return sendMessage(host, message->mName.c_str(), message->mMessage); -} - - -void LLMessageSystem::clearMessage() -{ - mSendReliable = FALSE; - mMessageBuilder->clearMessage(); -} - -// set block to add data to within current message -void LLMessageSystem::nextBlockFast(const char *blockname) -{ - mMessageBuilder->nextBlock(blockname); -} - -void LLMessageSystem::nextBlock(const char *blockname) -{ - nextBlockFast(LLMessageStringTable::getInstance()->getString(blockname)); -} - -BOOL LLMessageSystem::isSendFull(const char* blockname) -{ - char* stringTableName = NULL; - if(NULL != blockname) - { - stringTableName = LLMessageStringTable::getInstance()->getString(blockname); - } - return isSendFullFast(stringTableName); -} - -BOOL LLMessageSystem::isSendFullFast(const char* blockname) -{ - return mMessageBuilder->isMessageFull(blockname); -} - - -// blow away the last block of a message, return FALSE if that leaves no blocks or there wasn't a block to remove -// TODO: Babbage: Remove this horror. -BOOL LLMessageSystem::removeLastBlock() -{ - return mMessageBuilder->removeLastBlock(); -} - -S32 LLMessageSystem::sendReliable(const LLHost &host) -{ - return sendReliable(host, LL_DEFAULT_RELIABLE_RETRIES, TRUE, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL); -} - - -S32 LLMessageSystem::sendSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data) -{ - F32Seconds timeout; - - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS, - F32Seconds(LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged())); - } - else - { - timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX; - } - - const S32 retries = 0; - const BOOL ping_based_timeout = FALSE; - return sendReliable(host, retries, ping_based_timeout, timeout, callback, callback_data); -} - -// send the message via a UDP packet -S32 LLMessageSystem::sendReliable( const LLHost &host, - S32 retries, - BOOL ping_based_timeout, - F32Seconds timeout, - void (*callback)(void **,S32), - void ** callback_data) -{ - if (ping_based_timeout) - { - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged())); - } - else - { - timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX)); - } - } - - mSendReliable = TRUE; - mReliablePacketParams.set(host, retries, ping_based_timeout, timeout, - callback, callback_data, - const_cast<char*>(mMessageBuilder->getMessageName())); - return sendMessage(host); -} - -void LLMessageSystem::forwardMessage(const LLHost &host) -{ - copyMessageReceivedToSend(); - sendMessage(host); -} - -void LLMessageSystem::forwardReliable(const LLHost &host) -{ - copyMessageReceivedToSend(); - sendReliable(host); -} - -void LLMessageSystem::forwardReliable(const U32 circuit_code) -{ - copyMessageReceivedToSend(); - sendReliable(findHost(circuit_code)); -} - -S32 LLMessageSystem::forwardReliable( const LLHost &host, - S32 retries, - BOOL ping_based_timeout, - F32Seconds timeout, - void (*callback)(void **,S32), - void ** callback_data) -{ - copyMessageReceivedToSend(); - return sendReliable(host, retries, ping_based_timeout, timeout, callback, callback_data); -} - -S32 LLMessageSystem::flushSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data) -{ - F32Seconds timeout; - - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS, - F32Seconds(LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged())); - } - else - { - timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX; - } - - S32 send_bytes = 0; - if (mMessageBuilder->getMessageSize()) - { - mSendReliable = TRUE; - // No need for ping-based retry as not going to retry - mReliablePacketParams.set(host, 0, FALSE, timeout, callback, - callback_data, - const_cast<char*>(mMessageBuilder->getMessageName())); - send_bytes = sendMessage(host); - clearMessage(); - } - else - { - delete callback_data; - } - return send_bytes; -} - -S32 LLMessageSystem::flushReliable(const LLHost &host) -{ - S32 send_bytes = 0; - if (mMessageBuilder->getMessageSize()) - { - send_bytes = sendReliable(host); - } - clearMessage(); - return send_bytes; -} - -// This can be called from signal handlers, -// so should should not use LL_INFOS(). -S32 LLMessageSystem::sendMessage(const LLHost &host) -{ - if (! mMessageBuilder->isBuilt()) - { - mSendSize = mMessageBuilder->buildMessage( - mSendBuffer, - MAX_BUFFER_SIZE, - 0); - } - - if (!(host.isOk())) // if port and ip are zero, don't bother trying to send the message - { - return 0; - } - - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (!cdp) - { - // this is a new circuit! - // are we protected? - if (mbProtected) - { - // yup! don't send packets to an unknown circuit - if(mVerboseLog) - { - LL_INFOS_ONCE("Messaging") << "MSG: -> " << host << "\tUNKNOWN CIRCUIT:\t" - << mMessageBuilder->getMessageName() << LL_ENDL; - } - LL_WARNS_ONCE("Messaging") << "sendMessage - Trying to send " - << mMessageBuilder->getMessageName() << " on unknown circuit " - << host << LL_ENDL; - return 0; - } - else - { - // nope, open the new circuit - - cdp = mCircuitInfo.addCircuitData(host, 0); - } - } - else - { - // this is an old circuit. . . is it still alive? - if (!cdp->isAlive()) - { - // nope. don't send to dead circuits - if(mVerboseLog) - { - LL_INFOS("Messaging") << "MSG: -> " << host << "\tDEAD CIRCUIT\t\t" - << mMessageBuilder->getMessageName() << LL_ENDL; - } - LL_WARNS("Messaging") << "sendMessage - Trying to send message " - << mMessageBuilder->getMessageName() << " to dead circuit " - << host << LL_ENDL; - return 0; - } - } - - // NOTE: babbage: LLSD message -> HTTP, template message -> UDP - if(mMessageBuilder == mLLSDMessageBuilder) - { - LLSD message = mLLSDMessageBuilder->getMessage(); - - UntrustedCallback_t cb = NULL; - if ((mSendReliable) && (mReliablePacketParams.mCallback)) - { - cb = boost::bind(mReliablePacketParams.mCallback, mReliablePacketParams.mCallbackData, _1); - } - - LLCoros::instance().launch("LLMessageSystem::sendUntrustedSimulatorMessageCoro", - boost::bind(&LLMessageSystem::sendUntrustedSimulatorMessageCoro, this, - host.getUntrustedSimulatorCap(), - mLLSDMessageBuilder->getMessageName(), message, cb)); - - mSendReliable = FALSE; - mReliablePacketParams.clear(); - return 1; - } - - // zero out the flags and packetid. Subtract 1 here so that we do - // not overwrite the offset if it was set set in buildMessage(). - memset(mSendBuffer, 0, LL_PACKET_ID_SIZE - 1); - - // add the send id to the front of the message - cdp->nextPacketOutID(); - - // Packet ID size is always 4 - *((S32*)&mSendBuffer[PHL_PACKET_ID]) = htonl(cdp->getPacketOutID()); - - // Compress the message, which will usually reduce its size. - U8 * buf_ptr = (U8 *)mSendBuffer; - U32 buffer_length = mSendSize; - mMessageBuilder->compressMessage(buf_ptr, buffer_length); - - if (buffer_length > 1500) - { - if((mMessageBuilder->getMessageName() != _PREHASH_ChildAgentUpdate) - && (mMessageBuilder->getMessageName() != _PREHASH_SendXferPacket)) - { - LL_WARNS("Messaging") << "sendMessage - Trying to send " - << ((buffer_length > 4000) ? "EXTRA " : "") - << "BIG message " << mMessageBuilder->getMessageName() << " - " - << buffer_length << LL_ENDL; - } - } - if (mSendReliable) - { - buf_ptr[0] |= LL_RELIABLE_FLAG; - - if (!cdp->getUnackedPacketCount()) - { - // We are adding the first packed onto the unacked packet list(s) - // Add this circuit to the list of circuits with unacked packets - mCircuitInfo.mUnackedCircuitMap[cdp->mHost] = cdp; - } - - cdp->addReliablePacket(mSocket,buf_ptr,buffer_length, &mReliablePacketParams); - mReliablePacketsOut++; - } - - // tack packet acks onto the end of this message - S32 space_left = (MTUBYTES - buffer_length) / sizeof(TPACKETID); // space left for packet ids - S32 ack_count = (S32)cdp->mAcks.size(); - BOOL is_ack_appended = FALSE; - std::vector<TPACKETID> acks; - if((space_left > 0) && (ack_count > 0) && - (mMessageBuilder->getMessageName() != _PREHASH_PacketAck)) - { - buf_ptr[0] |= LL_ACK_FLAG; - S32 append_ack_count = llmin(space_left, ack_count); - const S32 MAX_ACKS = 250; - append_ack_count = llmin(append_ack_count, MAX_ACKS); - std::vector<TPACKETID>::iterator iter = cdp->mAcks.begin(); - std::vector<TPACKETID>::iterator last = cdp->mAcks.begin(); - last += append_ack_count; - TPACKETID packet_id; - for( ; iter != last ; ++iter) - { - // grab the next packet id. - packet_id = (*iter); - if(mVerboseLog) - { - acks.push_back(packet_id); - } - - // put it on the end of the buffer - packet_id = htonl(packet_id); - - if((S32)(buffer_length + sizeof(TPACKETID)) < MAX_BUFFER_SIZE) - { - memcpy(&buf_ptr[buffer_length], &packet_id, sizeof(TPACKETID)); /* Flawfinder: ignore */ - // Do the accounting - buffer_length += sizeof(TPACKETID); - } - else - { - // Just reporting error is likely not enough. Need to - // check how to abort or error out gracefully from - // this function. XXXTBD - // *NOTE: Actually hitting this error would indicate - // the calculation above for space_left, ack_count, - // append_acout_count is incorrect or that - // MAX_BUFFER_SIZE has fallen below MTU which is bad - // and probably programmer error. - LL_ERRS("Messaging") << "Buffer packing failed due to size.." << LL_ENDL; - } - } - - // clean up the source - cdp->mAcks.erase(cdp->mAcks.begin(), last); - - // tack the count in the final byte - U8 count = (U8)append_ack_count; - buf_ptr[buffer_length++] = count; - is_ack_appended = TRUE; - } - - BOOL success; - success = mPacketRing.sendPacket(mSocket, (char *)buf_ptr, buffer_length, host); - - if (!success) - { - mSendPacketFailureCount++; - } - else - { - // mCircuitInfo already points to the correct circuit data - cdp->addBytesOut( (S32Bytes)buffer_length ); - } - - if(mVerboseLog) - { - std::ostringstream str; - str << "MSG: -> " << host; - std::string buffer; - buffer = llformat( "\t%6d\t%6d\t%6d ", mSendSize, buffer_length, cdp->getPacketOutID()); - str << buffer - << mMessageBuilder->getMessageName() - << (mSendReliable ? " reliable " : ""); - if(is_ack_appended) - { - str << "\tACKS:\t"; - std::ostream_iterator<TPACKETID> append(str, " "); - std::copy(acks.begin(), acks.end(), append); - } - LL_INFOS("Messaging") << str.str() << LL_ENDL; - } - - - mPacketsOut++; - mTotalBytesOut += buffer_length; - - mSendReliable = FALSE; - mReliablePacketParams.clear(); - return buffer_length; -} - -void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, BOOL recv_reliable ) -{ - if(mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << host; - std::string buffer; - buffer = llformat( "\t%6d\t%6d\t%6d ", mMessageReader->getMessageSize(), (mIncomingCompressedSize ? mIncomingCompressedSize: mMessageReader->getMessageSize()), mCurrentRecvPacketID); - str << buffer - << nullToEmpty(mMessageReader->getMessageName()) - << (recv_reliable ? " reliable" : "") - << " REJECTED"; - LL_INFOS("Messaging") << str.str() << LL_ENDL; - } - // nope! - // cout << "Rejecting unexpected message " << mCurrentMessageTemplate->mName << " from " << hex << ip << " , " << dec << port << endl; - - // Keep track of rejected messages as well - if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM) - { - LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << LL_ENDL; - } - else - { - // TODO: babbage: work out if we need these - // mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber; - mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize(); - mMessageCountList[mNumMessageCounts].mInvalid = TRUE; - mNumMessageCounts++; - } -} - -S32 LLMessageSystem::sendMessage( - const LLHost &host, - const char* name, - const LLSD& message) -{ - if (!(host.isOk())) - { - LL_WARNS("Messaging") << "trying to send message to invalid host" << LL_ENDL; - return 0; - } - - UntrustedCallback_t cb = NULL; - if ((mSendReliable) && (mReliablePacketParams.mCallback)) - { - cb = boost::bind(mReliablePacketParams.mCallback, mReliablePacketParams.mCallbackData, _1); - } - - LLCoros::instance().launch("LLMessageSystem::sendUntrustedSimulatorMessageCoro", - boost::bind(&LLMessageSystem::sendUntrustedSimulatorMessageCoro, this, - host.getUntrustedSimulatorCap(), name, message, cb)); - return 1; -} - -void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host ) -{ - // RequestTrustedCircuit is how we establish trust, so don't spam - // if it's received on a trusted circuit. JC - if (strcmp(mMessageReader->getMessageName(), "RequestTrustedCircuit")) - { - LL_WARNS("Messaging") << "Received trusted message on untrusted circuit. " - << "Will reply with deny. " - << "Message: " << nullToEmpty(mMessageReader->getMessageName()) - << " Host: " << host << LL_ENDL; - } - - if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM) - { - LL_WARNS("Messaging") << "got more than " << MAX_MESSAGE_COUNT_NUM - << " packets without clearing counts" - << LL_ENDL; - } - else - { - // TODO: babbage: work out if we need these - //mMessageCountList[mNumMessageCounts].mMessageNum - // = mCurrentRMessageTemplate->mMessageNumber; - mMessageCountList[mNumMessageCounts].mMessageBytes - = mMessageReader->getMessageSize(); - mMessageCountList[mNumMessageCounts].mInvalid = TRUE; - mNumMessageCounts++; - } -} - -void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, BOOL recv_reliable, BOOL recv_resent, BOOL recv_acks ) -{ - if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM) - { - LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << LL_ENDL; - } - else - { - // TODO: babbage: work out if we need these - //mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber; - mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize(); - mMessageCountList[mNumMessageCounts].mInvalid = FALSE; - mNumMessageCounts++; - } - - if (cdp) - { - // update circuit packet ID tracking (missing/out of order packets) - cdp->checkPacketInID( mCurrentRecvPacketID, recv_resent ); - cdp->addBytesIn( (S32Bytes)mTrueReceiveSize ); - } - - if(mVerboseLog) - { - std::ostringstream str; - str << "MSG: <- " << host; - std::string buffer; - buffer = llformat( "\t%6d\t%6d\t%6d ", mMessageReader->getMessageSize(), (mIncomingCompressedSize ? mIncomingCompressedSize : mMessageReader->getMessageSize()), mCurrentRecvPacketID); - str << buffer - << nullToEmpty(mMessageReader->getMessageName()) - << (recv_reliable ? " reliable" : "") - << (recv_resent ? " resent" : "") - << (recv_acks ? " acks" : ""); - LL_INFOS("Messaging") << str.str() << LL_ENDL; - } -} - -void LLMessageSystem::sanityCheck() -{ -// TODO: babbage: reinstate - -// if (!mCurrentRMessageData) -// { -// LL_ERRS("Messaging") << "mCurrentRMessageData is NULL" << LL_ENDL; -// } - -// if (!mCurrentRMessageTemplate) -// { -// LL_ERRS("Messaging") << "mCurrentRMessageTemplate is NULL" << LL_ENDL; -// } - -// if (!mCurrentRTemplateBlock) -// { -// LL_ERRS("Messaging") << "mCurrentRTemplateBlock is NULL" << LL_ENDL; -// } - -// if (!mCurrentRDataBlock) -// { -// LL_ERRS("Messaging") << "mCurrentRDataBlock is NULL" << LL_ENDL; -// } - -// if (!mCurrentSMessageData) -// { -// LL_ERRS("Messaging") << "mCurrentSMessageData is NULL" << LL_ENDL; -// } - -// if (!mCurrentSMessageTemplate) -// { -// LL_ERRS("Messaging") << "mCurrentSMessageTemplate is NULL" << LL_ENDL; -// } - -// if (!mCurrentSTemplateBlock) -// { -// LL_ERRS("Messaging") << "mCurrentSTemplateBlock is NULL" << LL_ENDL; -// } - -// if (!mCurrentSDataBlock) -// { -// LL_ERRS("Messaging") << "mCurrentSDataBlock is NULL" << LL_ENDL; -// } -} - -void LLMessageSystem::showCircuitInfo() -{ - LL_INFOS("Messaging") << mCircuitInfo << LL_ENDL; -} - - -void LLMessageSystem::dumpCircuitInfo() -{ - LL_DEBUGS("Messaging") << mCircuitInfo << LL_ENDL; -} - -/* virtual */ -U32 LLMessageSystem::getOurCircuitCode() -{ - return mOurCircuitCode; -} - -void LLMessageSystem::getCircuitInfo(LLSD& info) const -{ - mCircuitInfo.getInfo(info); -} - -// returns whether the given host is on a trusted circuit -BOOL LLMessageSystem::getCircuitTrust(const LLHost &host) -{ - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - return cdp->getTrusted(); - } - - return FALSE; -} - -// Activate a circuit, and set its trust level (TRUE if trusted, -// FALSE if not). -void LLMessageSystem::enableCircuit(const LLHost &host, BOOL trusted) -{ - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (!cdp) - { - cdp = mCircuitInfo.addCircuitData(host, 0); - } - else - { - cdp->setAlive(TRUE); - } - cdp->setTrusted(trusted); -} - -void LLMessageSystem::disableCircuit(const LLHost &host) -{ - LL_INFOS("Messaging") << "LLMessageSystem::disableCircuit for " << host << LL_ENDL; - U32 code = gMessageSystem->findCircuitCode( host ); - - // Don't need to do this, as we're removing the circuit info anyway - djs 01/28/03 - - // don't clean up 0 circuit code entries - // because many hosts (neighbor sims, etc) can have the 0 circuit - if (code) - { - //if (mCircuitCodes.checkKey(code)) - code_session_map_t::iterator it = mCircuitCodes.find(code); - if(it != mCircuitCodes.end()) - { - LL_INFOS("Messaging") << "Circuit " << code << " removed from list" << LL_ENDL; - //mCircuitCodes.removeData(code); - mCircuitCodes.erase(it); - } - - U64 ip_port = 0; - std::map<U32, U64>::iterator iter = gMessageSystem->mCircuitCodeToIPPort.find(code); - if (iter != gMessageSystem->mCircuitCodeToIPPort.end()) - { - ip_port = iter->second; - - gMessageSystem->mCircuitCodeToIPPort.erase(iter); - - U32 old_port = (U32)(ip_port & (U64)0xFFFFFFFF); - U32 old_ip = (U32)(ip_port >> 32); - - LL_INFOS("Messaging") << "Host " << LLHost(old_ip, old_port) << " circuit " << code << " removed from lookup table" << LL_ENDL; - gMessageSystem->mIPPortToCircuitCode.erase(ip_port); - } - mCircuitInfo.removeCircuitData(host); - } - else - { - // Sigh, since we can open circuits which don't have circuit - // codes, it's possible for this to happen... - - LL_WARNS("Messaging") << "Couldn't find circuit code for " << host << LL_ENDL; - } - -} - - -void LLMessageSystem::setCircuitAllowTimeout(const LLHost &host, BOOL allow) -{ - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - cdp->setAllowTimeout(allow); - } -} - -void LLMessageSystem::setCircuitTimeoutCallback(const LLHost &host, void (*callback_func)(const LLHost & host, void *user_data), void *user_data) -{ - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - cdp->setTimeoutCallback(callback_func, user_data); - } -} - - -BOOL LLMessageSystem::checkCircuitBlocked(const U32 circuit) -{ - LLHost host = findHost(circuit); - - if (!host.isOk()) - { - LL_DEBUGS("Messaging") << "checkCircuitBlocked: Unknown circuit " << circuit << LL_ENDL; - return TRUE; - } - - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - return cdp->isBlocked(); - } - else - { - LL_INFOS("Messaging") << "checkCircuitBlocked(circuit): Unknown host - " << host << LL_ENDL; - return FALSE; - } -} - -BOOL LLMessageSystem::checkCircuitAlive(const U32 circuit) -{ - LLHost host = findHost(circuit); - - if (!host.isOk()) - { - LL_DEBUGS("Messaging") << "checkCircuitAlive: Unknown circuit " << circuit << LL_ENDL; - return FALSE; - } - - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - return cdp->isAlive(); - } - else - { - LL_INFOS("Messaging") << "checkCircuitAlive(circuit): Unknown host - " << host << LL_ENDL; - return FALSE; - } -} - -BOOL LLMessageSystem::checkCircuitAlive(const LLHost &host) -{ - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (cdp) - { - return cdp->isAlive(); - } - else - { - LL_DEBUGS("Messaging") << "checkCircuitAlive(host): Unknown host - " << host << LL_ENDL; - return FALSE; - } -} - - -void LLMessageSystem::setCircuitProtection(BOOL b_protect) -{ - mbProtected = b_protect; -} - - -U32 LLMessageSystem::findCircuitCode(const LLHost &host) -{ - U64 ip64 = (U64) host.getAddress(); - U64 port64 = (U64) host.getPort(); - U64 ip_port = (ip64 << 32) | port64; - - return get_if_there(mIPPortToCircuitCode, ip_port, U32(0)); -} - -LLHost LLMessageSystem::findHost(const U32 circuit_code) -{ - if (mCircuitCodeToIPPort.count(circuit_code) > 0) - { - return LLHost(mCircuitCodeToIPPort[circuit_code]); - } - else - { - return LLHost(); - } -} - -void LLMessageSystem::setMaxMessageTime(const F32 seconds) -{ - mMaxMessageTime = F32Seconds(seconds); -} - -void LLMessageSystem::setMaxMessageCounts(const S32 num) -{ - mMaxMessageCounts = num; -} - - -std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg) -{ - U32 i; - if (msg.mbError) - { - s << "Message system not correctly initialized"; - } - else - { - s << "Message system open on port " << msg.mPort << " and socket " << msg.mSocket << "\n"; -// s << "Message template file " << msg.mName << " loaded\n"; - - s << "\nHigh frequency messages:\n"; - - for (i = 1; msg.mMessageNumbers[i] && (i < 255); i++) - { - s << *(msg.mMessageNumbers[i]); - } - - s << "\nMedium frequency messages:\n"; - - for (i = (255 << 8) + 1; msg.mMessageNumbers[i] && (i < (255 << 8) + 255); i++) - { - s << *msg.mMessageNumbers[i]; - } - - s << "\nLow frequency messages:\n"; - - for (i = (0xFFFF0000) + 1; msg.mMessageNumbers[i] && (i < 0xFFFFFFFF); i++) - { - s << *msg.mMessageNumbers[i]; - } - } - return s; -} - -// LLPounceable supports callWhenReady(), to permit clients to queue up (e.g.) -// callback registrations for when gMessageSystem is first assigned -LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; - -// update appropriate ping info -void process_complete_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/) -{ - U8 ping_id; - msgsystem->getU8Fast(_PREHASH_PingID, _PREHASH_PingID, ping_id); - - LLCircuitData *cdp; - cdp = msgsystem->mCircuitInfo.findCircuit(msgsystem->getSender()); - - // stop the appropriate timer - if (cdp) - { - cdp->pingTimerStop(ping_id); - } -} - -void process_start_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/) -{ - U8 ping_id; - msgsystem->getU8Fast(_PREHASH_PingID, _PREHASH_PingID, ping_id); - - LLCircuitData *cdp; - cdp = msgsystem->mCircuitInfo.findCircuit(msgsystem->getSender()); - if (cdp) - { - // Grab the packet id of the oldest unacked packet - U32 packet_id; - msgsystem->getU32Fast(_PREHASH_PingID, _PREHASH_OldestUnacked, packet_id); - cdp->clearDuplicateList(packet_id); - } - - // Send off the response - msgsystem->newMessageFast(_PREHASH_CompletePingCheck); - msgsystem->nextBlockFast(_PREHASH_PingID); - msgsystem->addU8(_PREHASH_PingID, ping_id); - msgsystem->sendMessage(msgsystem->getSender()); -} - - - -// Note: this is currently unused. --mark -void open_circuit(LLMessageSystem *msgsystem, void** /*user_data*/) -{ - U32 ip; - U16 port; - - msgsystem->getIPAddrFast(_PREHASH_CircuitInfo, _PREHASH_IP, ip); - msgsystem->getIPPortFast(_PREHASH_CircuitInfo, _PREHASH_Port, port); - - // By default, OpenCircuit's are untrusted - msgsystem->enableCircuit(LLHost(ip, port), FALSE); -} - -void close_circuit(LLMessageSystem *msgsystem, void** /*user_data*/) -{ - msgsystem->disableCircuit(msgsystem->getSender()); -} - -// static -/* -void LLMessageSystem::processAssignCircuitCode(LLMessageSystem* msg, void**) -{ - // if we already have a circuit code, we can bail - if(msg->mOurCircuitCode) return; - LLUUID session_id; - msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id); - if(session_id != msg->getMySessionID()) - { - LL_WARNS("Messaging") << "AssignCircuitCode, bad session id. Expecting " - << msg->getMySessionID() << " but got " << session_id - << LL_ENDL; - return; - } - U32 code; - msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, code); - if (!code) - { - LL_ERRS("Messaging") << "Assigning circuit code of zero!" << LL_ENDL; - } - - msg->mOurCircuitCode = code; - LL_INFOS("Messaging") << "Circuit code " << code << " assigned." << LL_ENDL; -} -*/ - -// static -void LLMessageSystem::processAddCircuitCode(LLMessageSystem* msg, void**) -{ - U32 code; - msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, code); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id); - (void)msg->addCircuitCode(code, session_id); - - // Send the ack back - //msg->newMessageFast(_PREHASH_AckAddCircuitCode); - //msg->nextBlockFast(_PREHASH_CircuitCode); - //msg->addU32Fast(_PREHASH_Code, code); - //msg->sendMessage(msg->getSender()); -} - -bool LLMessageSystem::addCircuitCode(U32 code, const LLUUID& session_id) -{ - if(!code) - { - LL_WARNS("Messaging") << "addCircuitCode: zero circuit code" << LL_ENDL; - return false; - } - code_session_map_t::iterator it = mCircuitCodes.find(code); - if(it == mCircuitCodes.end()) - { - LL_INFOS("Messaging") << "New circuit code " << code << " added" << LL_ENDL; - //msg->mCircuitCodes[circuit_code] = circuit_code; - - mCircuitCodes.insert(code_session_map_t::value_type(code, session_id)); - } - else - { - LL_INFOS("Messaging") << "Duplicate circuit code " << code << " added" << LL_ENDL; - } - return true; -} - -//void ack_add_circuit_code(LLMessageSystem *msgsystem, void** /*user_data*/) -//{ - // By default, we do nothing. This particular message is only handled by the spaceserver -//} - -// static -void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, - void** user) -{ - U32 circuit_code_in; - msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, circuit_code_in); - - U32 ip = msg->getSenderIP(); - U32 port = msg->getSenderPort(); - - U64 ip64 = ip; - U64 port64 = port; - U64 ip_port_in = (ip64 << 32) | port64; - - if (circuit_code_in) - { - //if (!msg->mCircuitCodes.checkKey(circuit_code_in)) - code_session_map_t::iterator it; - it = msg->mCircuitCodes.find(circuit_code_in); - if(it == msg->mCircuitCodes.end()) - { - // Whoah, abort! We don't know anything about this circuit code. - LL_WARNS("Messaging") << "UseCircuitCode for " << circuit_code_in - << " received without AddCircuitCode message - aborting" - << LL_ENDL; - return; - } - - LLUUID id; - msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_ID, id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id); - if(session_id != (*it).second) - { - LL_WARNS("Messaging") << "UseCircuitCode unmatched session id. Got " - << session_id << " but expected " << (*it).second - << LL_ENDL; - return; - } - - // Clean up previous references to this ip/port or circuit - U64 ip_port_old = get_if_there(msg->mCircuitCodeToIPPort, circuit_code_in, U64(0)); - U32 circuit_code_old = get_if_there(msg->mIPPortToCircuitCode, ip_port_in, U32(0)); - - if (ip_port_old) - { - if ((ip_port_old == ip_port_in) && (circuit_code_old == circuit_code_in)) - { - // Current information is the same as incoming info, ignore - LL_INFOS("Messaging") << "Got duplicate UseCircuitCode for circuit " << circuit_code_in << " to " << msg->getSender() << LL_ENDL; - return; - } - - // Hmm, got a different IP and port for the same circuit code. - U32 circut_code_old_ip_port = get_if_there(msg->mIPPortToCircuitCode, ip_port_old, U32(0)); - msg->mCircuitCodeToIPPort.erase(circut_code_old_ip_port); - msg->mIPPortToCircuitCode.erase(ip_port_old); - U32 old_port = (U32)(ip_port_old & (U64)0xFFFFFFFF); - U32 old_ip = (U32)(ip_port_old >> 32); - LL_INFOS("Messaging") << "Removing derelict lookup entry for circuit " << circuit_code_old << " to " << LLHost(old_ip, old_port) << LL_ENDL; - } - - if (circuit_code_old) - { - LLHost cur_host(ip, port); - - LL_WARNS("Messaging") << "Disabling existing circuit for " << cur_host << LL_ENDL; - msg->disableCircuit(cur_host); - if (circuit_code_old == circuit_code_in) - { - LL_WARNS("Messaging") << "Asymmetrical circuit to ip/port lookup!" << LL_ENDL; - LL_WARNS("Messaging") << "Multiple circuit codes for " << cur_host << " probably!" << LL_ENDL; - LL_WARNS("Messaging") << "Permanently disabling circuit" << LL_ENDL; - return; - } - else - { - LL_WARNS("Messaging") << "Circuit code changed for " << msg->getSender() - << " from " << circuit_code_old << " to " - << circuit_code_in << LL_ENDL; - } - } - - // Since this comes from the viewer, it's untrusted, but it - // passed the circuit code and session id check, so we will go - // ahead and persist the ID associated. - LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender()); - BOOL had_circuit_already = cdp ? TRUE : FALSE; - - msg->enableCircuit(msg->getSender(), FALSE); - cdp = msg->mCircuitInfo.findCircuit(msg->getSender()); - if(cdp) - { - cdp->setRemoteID(id); - cdp->setRemoteSessionID(session_id); - } - - if (!had_circuit_already) - { - // - // HACK HACK HACK HACK HACK! - // - // This would NORMALLY happen inside logValidMsg, but at the point that this happens - // inside logValidMsg, there's no circuit for this message yet. So the awful thing that - // we do here is do it inside this message handler immediately AFTER the message is - // handled. - // - // We COULD not do this, but then what happens is that some of the circuit bookkeeping - // gets broken, especially the packets in count. That causes some later packets to flush - // the RecentlyReceivedReliable list, resulting in an error in which UseCircuitCode - // doesn't get properly duplicate suppressed. Not a BIG deal, but it's somewhat confusing - // (and bad from a state point of view). DJS 9/23/04 - // - cdp->checkPacketInID(gMessageSystem->mCurrentRecvPacketID, FALSE ); // Since this is the first message on the circuit, by definition it's not resent. - } - - msg->mIPPortToCircuitCode[ip_port_in] = circuit_code_in; - msg->mCircuitCodeToIPPort[circuit_code_in] = ip_port_in; - - LL_INFOS("Messaging") << "Circuit code " << circuit_code_in << " from " - << msg->getSender() << " for agent " << id << " in session " - << session_id << LL_ENDL; - - const LLUseCircuitCodeResponder* responder = - (const LLUseCircuitCodeResponder*) user; - if(responder) - { - responder->complete(msg->getSender(), id); - } - } - else - { - LL_WARNS("Messaging") << "Got zero circuit code in use_circuit_code" << LL_ENDL; - } -} - -// static -void LLMessageSystem::processError(LLMessageSystem* msg, void**) -{ - S32 error_code = 0; - msg->getS32("Data", "Code", error_code); - std::string error_token; - msg->getString("Data", "Token", error_token); - - LLUUID error_id; - msg->getUUID("Data", "ID", error_id); - std::string error_system; - msg->getString("Data", "System", error_system); - - std::string error_message; - msg->getString("Data", "Message", error_message); - - LL_WARNS("Messaging") << "Message error from " << msg->getSender() << " - " - << error_code << " " << error_token << " " << error_id << " \"" - << error_system << "\" \"" << error_message << "\"" << LL_ENDL; -} - - -static LLHTTPNode& messageRootNode() -{ - static LLHTTPNode root_node; - static bool initialized = false; - if (!initialized) { - initialized = true; - LLHTTPRegistrar::buildAllServices(root_node); - } - - return root_node; -} - -//static -void LLMessageSystem::dispatch( - const std::string& msg_name, - const LLSD& message) -{ - LLPointer<LLSimpleResponse> responsep = LLSimpleResponse::create(); - dispatch(msg_name, message, responsep); -} - -//static -void LLMessageSystem::dispatch( - const std::string& msg_name, - const LLSD& message, - LLHTTPNode::ResponsePtr responsep) -{ - if ((gMessageSystem->mMessageTemplates.find - (LLMessageStringTable::getInstance()->getString(msg_name.c_str())) == - gMessageSystem->mMessageTemplates.end()) && - !LLMessageConfig::isValidMessage(msg_name)) - { - LL_WARNS("Messaging") << "Ignoring unknown message " << msg_name << LL_ENDL; - responsep->notFound("Invalid message name"); - return; - } - - std::string path = "/message/" + msg_name; - LLSD context; - const LLHTTPNode* handler = messageRootNode().traverse(path, context); - if (!handler) - { - LL_WARNS("Messaging") << "LLMessageService::dispatch > no handler for " - << path << LL_ENDL; - return; - } - // enable this for output of message names - LL_DEBUGS("Messaging") << "< \"" << msg_name << "\"" << LL_ENDL; - LL_DEBUGS("Messaging") << "context: " << context << LL_ENDL; - LL_DEBUGS("Messaging") << "message: " << message << LL_ENDL; - - handler->post(responsep, context, message); -} - -//static -void LLMessageSystem::dispatchTemplate(const std::string& msg_name, - const LLSD& message, - LLHTTPNode::ResponsePtr responsep) -{ - LLTemplateMessageDispatcher dispatcher(*(gMessageSystem->mTemplateMessageReader)); - dispatcher.dispatch(msg_name, message, responsep); -} - -static void check_for_unrecognized_messages( - const char* type, - const LLSD& map, - LLMessageSystem::message_template_name_map_t& templates) -{ - for (LLSD::map_const_iterator iter = map.beginMap(), - end = map.endMap(); - iter != end; ++iter) - { - const char* name = LLMessageStringTable::getInstance()->getString(iter->first.c_str()); - - if (templates.find(name) == templates.end()) - { - LL_INFOS("AppInit") << " " << type - << " ban list contains unrecognized message " - << name << LL_ENDL; - } - } -} - -void LLMessageSystem::setMessageBans( - const LLSD& trusted, const LLSD& untrusted) -{ - LL_DEBUGS("AppInit") << "LLMessageSystem::setMessageBans:" << LL_ENDL; - bool any_set = false; - - for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(), - end = mMessageTemplates.end(); - iter != end; ++iter) - { - LLMessageTemplate* mt = iter->second; - - std::string name(mt->mName); - bool ban_from_trusted - = trusted.has(name) && trusted.get(name).asBoolean(); - bool ban_from_untrusted - = untrusted.has(name) && untrusted.get(name).asBoolean(); - - mt->mBanFromTrusted = ban_from_trusted; - mt->mBanFromUntrusted = ban_from_untrusted; - - if (ban_from_trusted || ban_from_untrusted) - { - LL_INFOS("AppInit") << " " << name << " banned from " - << (ban_from_trusted ? "TRUSTED " : " ") - << (ban_from_untrusted ? "UNTRUSTED " : " ") - << LL_ENDL; - any_set = true; - } - } - - if (!any_set) - { - LL_DEBUGS("AppInit") << " no messages banned" << LL_ENDL; - } - - check_for_unrecognized_messages("trusted", trusted, mMessageTemplates); - check_for_unrecognized_messages("untrusted", untrusted, mMessageTemplates); -} - -S32 LLMessageSystem::sendError( - const LLHost& host, - const LLUUID& agent_id, - S32 code, - const std::string& token, - const LLUUID& id, - const std::string& system, - const std::string& message, - const LLSD& data) -{ - newMessage("Error"); - nextBlockFast(_PREHASH_AgentData); - addUUIDFast(_PREHASH_AgentID, agent_id); - nextBlockFast(_PREHASH_Data); - addS32("Code", code); - addString("Token", token); - addUUID("ID", id); - addString("System", system); - std::string temp; - temp = message; - if(temp.size() > (size_t)MTUBYTES) temp.resize((size_t)MTUBYTES); - addString("Message", message); - LLPointer<LLSDBinaryFormatter> formatter = new LLSDBinaryFormatter; - std::ostringstream ostr; - formatter->format(data, ostr); - temp = ostr.str(); - bool pack_data = true; - static const std::string ERROR_MESSAGE_NAME("Error"); - if (LLMessageConfig::getMessageFlavor(ERROR_MESSAGE_NAME) == - LLMessageConfig::TEMPLATE_FLAVOR) - { - S32 msg_size = temp.size() + mMessageBuilder->getMessageSize(); - if(msg_size >= ETHERNET_MTU_BYTES) - { - pack_data = false; - } - } - if(pack_data) - { - addBinaryData("Data", (void*)temp.c_str(), temp.size()); - } - else - { - LL_WARNS("Messaging") << "Data and message were too large -- data removed." - << LL_ENDL; - addBinaryData("Data", NULL, 0); - } - return sendReliable(host); -} - -void process_packet_ack(LLMessageSystem *msgsystem, void** /*user_data*/) -{ - TPACKETID packet_id; - - LLHost host = msgsystem->getSender(); - LLCircuitData *cdp = msgsystem->mCircuitInfo.findCircuit(host); - if (cdp) - { - - S32 ack_count = msgsystem->getNumberOfBlocksFast(_PREHASH_Packets); - - for (S32 i = 0; i < ack_count; i++) - { - msgsystem->getU32Fast(_PREHASH_Packets, _PREHASH_ID, packet_id, i); -// LL_DEBUGS("Messaging") << "ack recvd' from " << host << " for packet " << (TPACKETID)packet_id << LL_ENDL; - cdp->ackReliablePacket(packet_id); - } - if (!cdp->getUnackedPacketCount()) - { - // Remove this circuit from the list of circuits with unacked packets - gMessageSystem->mCircuitInfo.mUnackedCircuitMap.erase(host); - } - } -} - - -/* -void process_log_messages(LLMessageSystem* msg, void**) -{ - U8 log_message; - - msg->getU8Fast(_PREHASH_Options, _PREHASH_Enable, log_message); - - if (log_message) - { - LL_INFOS("Messaging") << "Starting logging via message" << LL_ENDL; - msg->startLogging(); - } - else - { - LL_INFOS("Messaging") << "Stopping logging via message" << LL_ENDL; - msg->stopLogging(); - } -}*/ - -// Make circuit trusted if the MD5 Digest matches, otherwise -// notify remote end that they are not trusted. -void process_create_trusted_circuit(LLMessageSystem *msg, void **) -{ - // don't try to create trust on machines with no shared secret - std::string shared_secret = get_shared_secret(); - if(shared_secret.empty()) return; - - LLUUID remote_id; - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_EndPointID, remote_id); - - LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender()); - if (!cdp) - { - LL_WARNS("Messaging") << "Attempt to create trusted circuit without circuit data: " - << msg->getSender() << LL_ENDL; - return; - } - - LLUUID local_id; - local_id = cdp->getLocalEndPointID(); - if (remote_id == local_id) - { - // Don't respond to requests that use the same end point ID - return; - } - - U32 untrusted_interface = msg->getUntrustedInterface().getAddress(); - U32 last_interface = msg->getReceivingInterface().getAddress(); - if ( ( untrusted_interface != INVALID_HOST_IP_ADDRESS ) && ( untrusted_interface == last_interface ) ) - { - if( msg->getBlockUntrustedInterface() ) - { - LL_WARNS("Messaging") << "Ignoring CreateTrustedCircuit on public interface from host: " - << msg->getSender() << LL_ENDL; - return; - } - else - { - LL_WARNS("Messaging") << "Processing CreateTrustedCircuit on public interface from host: " - << msg->getSender() << LL_ENDL; - } - } - - char their_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ - S32 size = msg->getSizeFast(_PREHASH_DataBlock, _PREHASH_Digest); - if(size != MD5HEX_STR_BYTES) - { - // ignore requests which pack the wrong amount of data. - return; - } - msg->getBinaryDataFast(_PREHASH_DataBlock, _PREHASH_Digest, their_digest, MD5HEX_STR_BYTES); - their_digest[MD5HEX_STR_SIZE - 1] = '\0'; - if(msg->isMatchingDigestForWindowAndUUIDs(their_digest, TRUST_TIME_WINDOW, local_id, remote_id)) - { - cdp->setTrusted(TRUE); - LL_INFOS("Messaging") << "Trusted digest from " << msg->getSender() << LL_ENDL; - return; - } - else if (cdp->getTrusted()) - { - // The digest is bad, but this circuit is already trusted. - // This means that this could just be the result of a stale deny sent from a while back, and - // the message system is being slow. Don't bother sending the deny, as it may continually - // ping-pong back and forth on a very hosed circuit. - LL_WARNS("Messaging") << "Ignoring bad digest from known trusted circuit: " << their_digest - << " host: " << msg->getSender() << LL_ENDL; - return; - } - else - { - LL_WARNS("Messaging") << "Bad digest from known circuit: " << their_digest - << " host: " << msg->getSender() << LL_ENDL; - msg->sendDenyTrustedCircuit(msg->getSender()); - return; - } -} - -void process_deny_trusted_circuit(LLMessageSystem *msg, void **) -{ - // don't try to create trust on machines with no shared secret - std::string shared_secret = get_shared_secret(); - if(shared_secret.empty()) return; - - LLUUID remote_id; - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_EndPointID, remote_id); - - LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender()); - if (!cdp) - { - return; - } - - LLUUID local_id; - local_id = cdp->getLocalEndPointID(); - if (remote_id == local_id) - { - // Don't respond to requests that use the same end point ID - return; - } - - U32 untrusted_interface = msg->getUntrustedInterface().getAddress(); - U32 last_interface = msg->getReceivingInterface().getAddress(); - if ( ( untrusted_interface != INVALID_HOST_IP_ADDRESS ) && ( untrusted_interface == last_interface ) ) - { - if( msg->getBlockUntrustedInterface() ) - { - LL_WARNS("Messaging") << "Ignoring DenyTrustedCircuit on public interface from host: " - << msg->getSender() << LL_ENDL; - return; - } - else - { - LL_WARNS("Messaging") << "Processing DenyTrustedCircuit on public interface from host: " - << msg->getSender() << LL_ENDL; - } - } - - - // Assume that we require trust to proceed, so resend. - // This catches the case where a circuit that was trusted - // times out, and allows us to re-establish it, but does - // mean that if our shared_secret or clock is wrong, we'll - // spin. - // *TODO: probably should keep a count of number of resends - // per circuit, and stop resending after a while. - LL_INFOS("Messaging") << "Got DenyTrustedCircuit. Sending CreateTrustedCircuit to " - << msg->getSender() << LL_ENDL; - msg->sendCreateTrustedCircuit(msg->getSender(), local_id, remote_id); -} - - -void dump_prehash_files() -{ - U32 i; - std::string filename("../../indra/llmessage/message_prehash.h"); - LLFILE* fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */ - if (fp) - { - fprintf( - fp, - "/**\n" - " * @file message_prehash.h\n" - " * @brief header file of externs of prehashed variables plus defines.\n" - " *\n" - " * $LicenseInfo:firstyear=2003&license=viewerlgpl$" - " * $/LicenseInfo$" - " */\n\n" - "#ifndef LL_MESSAGE_PREHASH_H\n#define LL_MESSAGE_PREHASH_H\n\n"); - fprintf( - fp, - "/**\n" - " * Generated from message template version number %.3f\n" - " */\n", - gMessageSystem->mMessageFileVersionNumber); - fprintf(fp, "\n\nextern F32 const gPrehashVersionNumber;\n\n"); - for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++) - { - if (!LLMessageStringTable::getInstance()->mEmpty[i] && LLMessageStringTable::getInstance()->mString[i][0] != '.') - { - fprintf(fp, "extern char const* const _PREHASH_%s;\n", LLMessageStringTable::getInstance()->mString[i]); - } - } - fprintf(fp, "\n\n#endif\n"); - fclose(fp); - } - filename = std::string("../../indra/llmessage/message_prehash.cpp"); - fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */ - if (fp) - { - fprintf( - fp, - "/**\n" - " * @file message_prehash.cpp\n" - " * @brief file of prehashed variables\n" - " *\n" - " * $LicenseInfo:firstyear=2003&license=viewerlgpl$" - " * $/LicenseInfo$" - " */\n\n" - "/**\n" - " * Generated from message template version number %.3f\n" - " */\n", - gMessageSystem->mMessageFileVersionNumber); - fprintf(fp, "#include \"linden_common.h\"\n"); - fprintf(fp, "#include \"message.h\"\n\n"); - fprintf(fp, "\n\nF32 const gPrehashVersionNumber = %.3ff;\n\n", gMessageSystem->mMessageFileVersionNumber); - for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++) - { - if (!LLMessageStringTable::getInstance()->mEmpty[i] && LLMessageStringTable::getInstance()->mString[i][0] != '.') - { - fprintf(fp, "char const* const _PREHASH_%s = LLMessageStringTable::getInstance()->getString(\"%s\");\n", LLMessageStringTable::getInstance()->mString[i], LLMessageStringTable::getInstance()->mString[i]); - } - } - fclose(fp); - } -} - -bool start_messaging_system( - const std::string& template_name, - U32 port, - S32 version_major, - S32 version_minor, - S32 version_patch, - bool b_dump_prehash_file, - const std::string& secret, - const LLUseCircuitCodeResponder* responder, - bool failure_is_fatal, - const F32 circuit_heartbeat_interval, - const F32 circuit_timeout) -{ - gMessageSystem = new LLMessageSystem( - template_name, - port, - version_major, - version_minor, - version_patch, - failure_is_fatal, - circuit_heartbeat_interval, - circuit_timeout); - g_shared_secret.assign(secret); - - if (!gMessageSystem) - { - LL_ERRS("AppInit") << "Messaging system initialization failed." << LL_ENDL; - return FALSE; - } - - // bail if system encountered an error. - if(!gMessageSystem->isOK()) - { - return FALSE; - } - - if (b_dump_prehash_file) - { - dump_prehash_files(); - exit(0); - } - else - { - if (gMessageSystem->mMessageFileVersionNumber != gPrehashVersionNumber) - { - LL_INFOS("AppInit") << "Message template version does not match prehash version number" << LL_ENDL; - LL_INFOS("AppInit") << "Run simulator with -prehash command line option to rebuild prehash data" << LL_ENDL; - } - else - { - LL_DEBUGS("AppInit") << "Message template version matches prehash version number" << LL_ENDL; - } - } - - gMessageSystem->setHandlerFuncFast(_PREHASH_StartPingCheck, process_start_ping_check, NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_CompletePingCheck, process_complete_ping_check, NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_OpenCircuit, open_circuit, NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_CloseCircuit, close_circuit, NULL); - - //gMessageSystem->setHandlerFuncFast(_PREHASH_AssignCircuitCode, LLMessageSystem::processAssignCircuitCode); - gMessageSystem->setHandlerFuncFast(_PREHASH_AddCircuitCode, LLMessageSystem::processAddCircuitCode); - //gMessageSystem->setHandlerFuncFast(_PREHASH_AckAddCircuitCode, ack_add_circuit_code, NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_UseCircuitCode, LLMessageSystem::processUseCircuitCode, (void**)responder); - gMessageSystem->setHandlerFuncFast(_PREHASH_PacketAck, process_packet_ack, NULL); - //gMessageSystem->setHandlerFuncFast(_PREHASH_LogMessages, process_log_messages, NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_CreateTrustedCircuit, - process_create_trusted_circuit, - NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_DenyTrustedCircuit, - process_deny_trusted_circuit, - NULL); - gMessageSystem->setHandlerFunc("Error", LLMessageSystem::processError); - - // We can hand this to the null_message_callback since it is a - // trusted message, so it will automatically be denied if it isn't - // trusted and ignored if it is -- exactly what we want. - gMessageSystem->setHandlerFunc( - "RequestTrustedCircuit", - null_message_callback, - NULL); - - // Initialize the transfer manager - gTransferManager.init(); - - return TRUE; -} - -void LLMessageSystem::startLogging() -{ - mVerboseLog = TRUE; - std::ostringstream str; - str << "START MESSAGE LOG" << std::endl; - str << "Legend:" << std::endl; - str << "\t<-\tincoming message" <<std::endl; - str << "\t->\toutgoing message" << std::endl; - str << " <> host size zero id name"; - LL_INFOS("Messaging") << str.str() << LL_ENDL; -} - -void LLMessageSystem::stopLogging() -{ - if(mVerboseLog) - { - mVerboseLog = FALSE; - LL_INFOS("Messaging") << "END MESSAGE LOG" << LL_ENDL; - } -} - -void LLMessageSystem::summarizeLogs(std::ostream& str) -{ - std::string buffer; - std::string tmp_str; - F32 run_time = mMessageSystemTimer.getElapsedTimeF32(); - str << "START MESSAGE LOG SUMMARY" << std::endl; - buffer = llformat( "Run time: %12.3f seconds", run_time); - - // Incoming - str << buffer << std::endl << "Incoming:" << std::endl; - tmp_str = U64_to_str(mTotalBytesIn); - buffer = llformat( "Total bytes received: %20s (%5.2f kbits per second)", tmp_str.c_str(), ((F32)mTotalBytesIn * 0.008f) / run_time); - str << buffer << std::endl; - tmp_str = U64_to_str(mPacketsIn); - buffer = llformat( "Total packets received: %20s (%5.2f packets per second)", tmp_str.c_str(), ((F32) mPacketsIn / run_time)); - str << buffer << std::endl; - buffer = llformat( "Average packet size: %20.0f bytes", (F32)mTotalBytesIn / (F32)mPacketsIn); - str << buffer << std::endl; - tmp_str = U64_to_str(mReliablePacketsIn); - buffer = llformat( "Total reliable packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mReliablePacketsIn)/((F32) mPacketsIn + 1)); - str << buffer << std::endl; - tmp_str = U64_to_str(mCompressedPacketsIn); - buffer = llformat( "Total compressed packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mCompressedPacketsIn)/((F32) mPacketsIn + 1)); - str << buffer << std::endl; - S64 savings = mUncompressedBytesIn - mCompressedBytesIn; - tmp_str = U64_to_str(savings); - buffer = llformat( "Total compression savings: %20s bytes", tmp_str.c_str()); - str << buffer << std::endl; - tmp_str = U64_to_str(savings/(mCompressedPacketsIn +1)); - buffer = llformat( "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mUncompressedBytesIn)/((F32) mCompressedBytesIn+1)); - str << buffer << std::endl; - tmp_str = U64_to_str(savings/(mPacketsIn+1)); - buffer = llformat( "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mTotalBytesIn + (F32) savings)/((F32) mTotalBytesIn + 1.f)); - - // Outgoing - str << buffer << std::endl << std::endl << "Outgoing:" << std::endl; - tmp_str = U64_to_str(mTotalBytesOut); - buffer = llformat( "Total bytes sent: %20s (%5.2f kbits per second)", tmp_str.c_str(), ((F32)mTotalBytesOut * 0.008f) / run_time ); - str << buffer << std::endl; - tmp_str = U64_to_str(mPacketsOut); - buffer = llformat( "Total packets sent: %20s (%5.2f packets per second)", tmp_str.c_str(), ((F32)mPacketsOut / run_time)); - str << buffer << std::endl; - buffer = llformat( "Average packet size: %20.0f bytes", (F32)mTotalBytesOut / (F32)mPacketsOut); - str << buffer << std::endl; - tmp_str = U64_to_str(mReliablePacketsOut); - buffer = llformat( "Total reliable packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mReliablePacketsOut)/((F32) mPacketsOut + 1)); - str << buffer << std::endl; - tmp_str = U64_to_str(mCompressedPacketsOut); - buffer = llformat( "Total compressed packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mCompressedPacketsOut)/((F32) mPacketsOut + 1)); - str << buffer << std::endl; - savings = mUncompressedBytesOut - mCompressedBytesOut; - tmp_str = U64_to_str(savings); - buffer = llformat( "Total compression savings: %20s bytes", tmp_str.c_str()); - str << buffer << std::endl; - tmp_str = U64_to_str(savings/(mCompressedPacketsOut +1)); - buffer = llformat( "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mUncompressedBytesOut)/((F32) mCompressedBytesOut+1)); - str << buffer << std::endl; - tmp_str = U64_to_str(savings/(mPacketsOut+1)); - buffer = llformat( "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mTotalBytesOut + (F32) savings)/((F32) mTotalBytesOut + 1.f)); - str << buffer << std::endl << std::endl; - buffer = llformat( "SendPacket failures: %20d", mSendPacketFailureCount); - str << buffer << std::endl; - buffer = llformat( "Dropped packets: %20d", mDroppedPackets); - str << buffer << std::endl; - buffer = llformat( "Resent packets: %20d", mResentPackets); - str << buffer << std::endl; - buffer = llformat( "Failed reliable resends: %20d", mFailedResendPackets); - str << buffer << std::endl; - buffer = llformat( "Off-circuit rejected packets: %17d", mOffCircuitPackets); - str << buffer << std::endl; - buffer = llformat( "On-circuit invalid packets: %17d", mInvalidOnCircuitPackets); - str << buffer << std::endl << std::endl; - - str << "Decoding: " << std::endl; - buffer = llformat( "%35s%10s%10s%10s%10s", "Message", "Count", "Time", "Max", "Avg"); - str << buffer << std:: endl; - F32 avg; - for (message_template_name_map_t::const_iterator iter = mMessageTemplates.begin(), - end = mMessageTemplates.end(); - iter != end; iter++) - { - const LLMessageTemplate* mt = iter->second; - if(mt->mTotalDecoded > 0) - { - avg = mt->mTotalDecodeTime / (F32)mt->mTotalDecoded; - buffer = llformat( "%35s%10u%10f%10f%10f", mt->mName, mt->mTotalDecoded, mt->mTotalDecodeTime, mt->mMaxDecodeTimePerMsg, avg); - str << buffer << std::endl; - } - } - str << "END MESSAGE LOG SUMMARY" << std::endl; -} - -void end_messaging_system(bool print_summary) -{ - gTransferManager.cleanup(); - LLTransferTargetVFile::updateQueue(true); // shutdown LLTransferTargetVFile - if (gMessageSystem) - { - gMessageSystem->stopLogging(); - - if (print_summary) - { - std::ostringstream str; - gMessageSystem->summarizeLogs(str); - LL_INFOS("Messaging") << str.str().c_str() << LL_ENDL; - } - - delete static_cast<LLMessageSystem*>(gMessageSystem); - gMessageSystem = NULL; - } -} - -void LLMessageSystem::resetReceiveCounts() -{ - mNumMessageCounts = 0; - - for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(), - end = mMessageTemplates.end(); - iter != end; iter++) - { - LLMessageTemplate* mt = iter->second; - mt->mDecodeTimeThisFrame = 0.f; - } -} - - -void LLMessageSystem::dumpReceiveCounts() -{ - LLMessageTemplate *mt; - - for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(), - end = mMessageTemplates.end(); - iter != end; iter++) - { - LLMessageTemplate* mt = iter->second; - mt->mReceiveCount = 0; - mt->mReceiveBytes = 0; - mt->mReceiveInvalid = 0; - } - - S32 i; - for (i = 0; i < mNumMessageCounts; i++) - { - mt = get_ptr_in_map(mMessageNumbers,mMessageCountList[i].mMessageNum); - if (mt) - { - mt->mReceiveCount++; - mt->mReceiveBytes += mMessageCountList[i].mMessageBytes; - if (mMessageCountList[i].mInvalid) - { - mt->mReceiveInvalid++; - } - } - } - - if(mNumMessageCounts > 0) - { - LL_DEBUGS("Messaging") << "Dump: " << mNumMessageCounts << " messages processed in " << mReceiveTime << " seconds" << LL_ENDL; - for (message_template_name_map_t::const_iterator iter = mMessageTemplates.begin(), - end = mMessageTemplates.end(); - iter != end; iter++) - { - const LLMessageTemplate* mt = iter->second; - if (mt->mReceiveCount > 0) - { - LL_INFOS("Messaging") << "Num: " << std::setw(3) << mt->mReceiveCount << " Bytes: " << std::setw(6) << mt->mReceiveBytes - << " Invalid: " << std::setw(3) << mt->mReceiveInvalid << " " << mt->mName << " " << ll_round(100 * mt->mDecodeTimeThisFrame / mReceiveTime.value()) << "%" << LL_ENDL; - } - } - } -} - - - -BOOL LLMessageSystem::isClear() const -{ - return mMessageBuilder->isClear(); -} - - -S32 LLMessageSystem::flush(const LLHost &host) -{ - if (mMessageBuilder->getMessageSize()) - { - S32 sentbytes = sendMessage(host); - clearMessage(); - return sentbytes; - } - else - { - return 0; - } -} - -U32 LLMessageSystem::getListenPort( void ) const -{ - return mPort; -} - -// TODO: babbage: remove this horror! -S32 LLMessageSystem::zeroCodeAdjustCurrentSendTotal() -{ - if(mMessageBuilder == mLLSDMessageBuilder) - { - // babbage: don't compress LLSD messages, so delta is 0 - return 0; - } - - if (! mMessageBuilder->isBuilt()) - { - mSendSize = mMessageBuilder->buildMessage( - mSendBuffer, - MAX_BUFFER_SIZE, - 0); - } - // TODO: babbage: remove this horror - mMessageBuilder->setBuilt(FALSE); - - S32 count = mSendSize; - - S32 net_gain = 0; - U8 num_zeroes = 0; - - U8 *inptr = (U8 *)mSendBuffer; - -// skip the packet id field - - for (U32 ii = 0; ii < LL_PACKET_ID_SIZE; ++ii) - { - count--; - inptr++; - } - -// don't actually build, just test - -// sequential zero bytes are encoded as 0 [U8 count] -// with 0 0 [count] representing wrap (>256 zeroes) - - while (count--) - { - if (!(*inptr)) // in a zero count - { - if (num_zeroes) - { - if (++num_zeroes > 254) - { - num_zeroes = 0; - } - net_gain--; // subseqent zeroes save one - } - else - { - net_gain++; // starting a zero count adds one - num_zeroes = 1; - } - inptr++; - } - else - { - if (num_zeroes) - { - num_zeroes = 0; - } - inptr++; - } - } - if (net_gain < 0) - { - return net_gain; - } - else - { - return 0; - } -} - - - -S32 LLMessageSystem::zeroCodeExpand(U8** data, S32* data_size) -{ - if ((*data_size ) < LL_MINIMUM_VALID_PACKET_SIZE) - { - LL_WARNS("Messaging") << "zeroCodeExpand() called with data_size of " << *data_size - << LL_ENDL; - } - - mTotalBytesIn += *data_size; - - // if we're not zero-coded, simply return. - if (!(*data[0] & LL_ZERO_CODE_FLAG)) - { - return 0; - } - - S32 in_size = *data_size; - mCompressedPacketsIn++; - mCompressedBytesIn += *data_size; - - *data[0] &= (~LL_ZERO_CODE_FLAG); - - S32 count = (*data_size); - - U8 *inptr = (U8 *)*data; - U8 *outptr = (U8 *)mEncodedRecvBuffer; - -// skip the packet id field - - for (U32 ii = 0; ii < LL_PACKET_ID_SIZE; ++ii) - { - count--; - *outptr++ = *inptr++; - } - -// reconstruct encoded packet, keeping track of net size gain - -// sequential zero bytes are encoded as 0 [U8 count] -// with 0 0 [count] representing wrap (>256 zeroes) - - while (count--) - { - if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-1])) - { - LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 1" << LL_ENDL; - callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE); - outptr = mEncodedRecvBuffer; - break; - } - if (!((*outptr++ = *inptr++))) - { - while (((count--)) && (!(*inptr))) - { - *outptr++ = *inptr++; - if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-256])) - { - LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 2" << LL_ENDL; - callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE); - outptr = mEncodedRecvBuffer; - count = -1; - break; - } - memset(outptr,0,255); - outptr += 255; - } - - if (count < 0) - { - break; - } - - else - { - if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-(*inptr)])) - { - LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 3" << LL_ENDL; - callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE); - outptr = mEncodedRecvBuffer; - } - memset(outptr,0,(*inptr) - 1); - outptr += ((*inptr) - 1); - inptr++; - } - } - } - - *data = mEncodedRecvBuffer; - *data_size = (S32)(outptr - mEncodedRecvBuffer); - mUncompressedBytesIn += *data_size; - - return(in_size); -} - - -void LLMessageSystem::addTemplate(LLMessageTemplate *templatep) -{ - if (mMessageTemplates.count(templatep->mName) > 0) - { - LL_ERRS("Messaging") << templatep->mName << " already used as a template name!" - << LL_ENDL; - } - mMessageTemplates[templatep->mName] = templatep; - mMessageNumbers[templatep->mMessageNumber] = templatep; -} - - -void LLMessageSystem::setHandlerFuncFast(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data) -{ - LLMessageTemplate* msgtemplate = get_ptr_in_map(mMessageTemplates, name); - if (msgtemplate) - { - msgtemplate->setHandlerFunc(handler_func, user_data); - } - else - { - LL_ERRS("Messaging") << name << " is not a known message name!" << LL_ENDL; - } -} - -bool LLMessageSystem::callHandler(const char *name, - bool trustedSource, LLMessageSystem* msg) -{ - name = LLMessageStringTable::getInstance()->getString(name); - message_template_name_map_t::const_iterator iter; - iter = mMessageTemplates.find(name); - if(iter == mMessageTemplates.end()) - { - LL_WARNS("Messaging") << "LLMessageSystem::callHandler: unknown message " - << name << LL_ENDL; - return false; - } - - const LLMessageTemplate* msg_template = iter->second; - if (msg_template->isBanned(trustedSource)) - { - LL_WARNS("Messaging") << "LLMessageSystem::callHandler: banned message " - << name - << " from " - << (trustedSource ? "trusted " : "untrusted ") - << "source" << LL_ENDL; - return false; - } - - return msg_template->callHandlerFunc(msg); -} - - -void LLMessageSystem::setExceptionFunc(EMessageException e, - msg_exception_callback func, - void* data) -{ - callbacks_t::iterator it = mExceptionCallbacks.find(e); - if(it != mExceptionCallbacks.end()) - { - mExceptionCallbacks.erase(it); - } - if(func) - { - mExceptionCallbacks.insert(callbacks_t::value_type(e, exception_t(func, data))); - } -} - -BOOL LLMessageSystem::callExceptionFunc(EMessageException exception) -{ - callbacks_t::iterator it = mExceptionCallbacks.find(exception); - if(it == mExceptionCallbacks.end()) - { - return FALSE; - } - - exception_t& ex = it->second; - msg_exception_callback ex_cb = ex.first; - - if (!ex_cb) - { - LL_WARNS("Messaging") << "LLMessageSystem::callExceptionFunc: bad message exception callback." << LL_ENDL; - return FALSE; - } - - (ex_cb)(this, ex.second, exception); - - return TRUE; -} - -void LLMessageSystem::setTimingFunc(msg_timing_callback func, void* data) -{ - mTimingCallback = func; - mTimingCallbackData = data; -} - -BOOL LLMessageSystem::isCircuitCodeKnown(U32 code) const -{ - if(mCircuitCodes.find(code) == mCircuitCodes.end()) - return FALSE; - return TRUE; -} - -BOOL LLMessageSystem::isMessageFast(const char *msg) -{ - return msg == mMessageReader->getMessageName(); -} - - -char* LLMessageSystem::getMessageName() -{ - return const_cast<char*>(mMessageReader->getMessageName()); -} - -const LLUUID& LLMessageSystem::getSenderID() const -{ - LLCircuitData *cdp = mCircuitInfo.findCircuit(mLastSender); - if (cdp) - { - return (cdp->mRemoteID); - } - - return LLUUID::null; -} - -const LLUUID& LLMessageSystem::getSenderSessionID() const -{ - LLCircuitData *cdp = mCircuitInfo.findCircuit(mLastSender); - if (cdp) - { - return (cdp->mRemoteSessionID); - } - return LLUUID::null; -} - -bool LLMessageSystem::generateDigestForNumberAndUUIDs( - char* digest, - const U32 number, - const LLUUID& id1, - const LLUUID& id2) const -{ - // *NOTE: This method is needlessly inefficient. Instead of - // calling LLUUID::asString, it should just call - // LLUUID::toString(). - - const char *colon = ":"; - char tbuf[16]; /* Flawfinder: ignore */ - LLMD5 d; - std::string id1string = id1.asString(); - std::string id2string = id2.asString(); - std::string shared_secret = get_shared_secret(); - unsigned char * secret = (unsigned char*)shared_secret.c_str(); - unsigned char * id1str = (unsigned char*)id1string.c_str(); - unsigned char * id2str = (unsigned char*)id2string.c_str(); - - memset(digest, 0, MD5HEX_STR_SIZE); - - if( secret != NULL) - { - d.update(secret, (U32)strlen((char *) secret)); /* Flawfinder: ignore */ - } - - d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */ - - snprintf(tbuf, sizeof(tbuf),"%i", number); /* Flawfinder: ignore */ - d.update((unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */ - - d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */ - if( (char*) id1str != NULL) - { - d.update(id1str, (U32)strlen((char *) id1str)); /* Flawfinder: ignore */ - } - d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */ - - if( (char*) id2str != NULL) - { - d.update(id2str, (U32)strlen((char *) id2str)); /* Flawfinder: ignore */ - } - - d.finalize(); - d.hex_digest(digest); - digest[MD5HEX_STR_SIZE - 1] = '\0'; - - return true; -} - -bool LLMessageSystem::generateDigestForWindowAndUUIDs(char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const -{ - if(0 == window) return false; - std::string shared_secret = get_shared_secret(); - if(shared_secret.empty()) - { - LL_ERRS("Messaging") << "Trying to generate complex digest on a machine without a shared secret!" << LL_ENDL; - } - - U32 now = (U32)time(NULL); - - now /= window; - - bool result = generateDigestForNumberAndUUIDs(digest, now, id1, id2); - - return result; -} - -bool LLMessageSystem::isMatchingDigestForWindowAndUUIDs(const char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const -{ - if(0 == window) return false; - - std::string shared_secret = get_shared_secret(); - if(shared_secret.empty()) - { - LL_ERRS("Messaging") << "Trying to compare complex digests on a machine without a shared secret!" << LL_ENDL; - } - - char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ - U32 now = (U32)time(NULL); - - now /= window; - - // Check 1 window ago, now, and one window from now to catch edge - // conditions. Process them as current window, one window ago, and - // one window in the future to catch the edges. - const S32 WINDOW_BIN_COUNT = 3; - U32 window_bin[WINDOW_BIN_COUNT]; - window_bin[0] = now; - window_bin[1] = now - 1; - window_bin[2] = now + 1; - for(S32 i = 0; i < WINDOW_BIN_COUNT; ++i) - { - generateDigestForNumberAndUUIDs(our_digest, window_bin[i], id2, id1); - if(0 == strncmp(digest, our_digest, MD5HEX_STR_BYTES)) - { - return true; - } - } - return false; -} - -bool LLMessageSystem::generateDigestForNumber(char* digest, const U32 number) const -{ - memset(digest, 0, MD5HEX_STR_SIZE); - - LLMD5 d; - std::string shared_secret = get_shared_secret(); - d = LLMD5((const unsigned char *)shared_secret.c_str(), number); - d.hex_digest(digest); - digest[MD5HEX_STR_SIZE - 1] = '\0'; - - return true; -} - -bool LLMessageSystem::generateDigestForWindow(char* digest, const S32 window) const -{ - if(0 == window) return false; - - std::string shared_secret = get_shared_secret(); - if(shared_secret.empty()) - { - LL_ERRS("Messaging") << "Trying to generate simple digest on a machine without a shared secret!" << LL_ENDL; - } - - U32 now = (U32)time(NULL); - - now /= window; - - bool result = generateDigestForNumber(digest, now); - - return result; -} - -bool LLMessageSystem::isMatchingDigestForWindow(const char* digest, S32 const window) const -{ - if(0 == window) return false; - - std::string shared_secret = get_shared_secret(); - if(shared_secret.empty()) - { - LL_ERRS("Messaging") << "Trying to compare simple digests on a machine without a shared secret!" << LL_ENDL; - } - - char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ - U32 now = (S32)time(NULL); - - now /= window; - - // Check 1 window ago, now, and one window from now to catch edge - // conditions. Process them as current window, one window ago, and - // one window in the future to catch the edges. - const S32 WINDOW_BIN_COUNT = 3; - U32 window_bin[WINDOW_BIN_COUNT]; - window_bin[0] = now; - window_bin[1] = now - 1; - window_bin[2] = now + 1; - for(S32 i = 0; i < WINDOW_BIN_COUNT; ++i) - { - generateDigestForNumber(our_digest, window_bin[i]); - if(0 == strncmp(digest, our_digest, MD5HEX_STR_BYTES)) - { - return true; - } - } - return false; -} - -void LLMessageSystem::sendCreateTrustedCircuit(const LLHost &host, const LLUUID & id1, const LLUUID & id2) -{ - std::string shared_secret = get_shared_secret(); - if(shared_secret.empty()) return; - char digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ - if (id1.isNull()) - { - LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the local end point ID" << LL_ENDL; - return; - } - if (id2.isNull()) - { - LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the remote end point ID" << LL_ENDL; - return; - } - generateDigestForWindowAndUUIDs(digest, TRUST_TIME_WINDOW, id1, id2); - newMessageFast(_PREHASH_CreateTrustedCircuit); - nextBlockFast(_PREHASH_DataBlock); - addUUIDFast(_PREHASH_EndPointID, id1); - addBinaryDataFast(_PREHASH_Digest, digest, MD5HEX_STR_BYTES); - LL_INFOS("Messaging") << "xmitting digest: " << digest << " Host: " << host << LL_ENDL; - sendMessage(host); -} - -void LLMessageSystem::sendDenyTrustedCircuit(const LLHost &host) -{ - mDenyTrustedCircuitSet.insert(host); -} - -void LLMessageSystem::reallySendDenyTrustedCircuit(const LLHost &host) -{ - LLCircuitData *cdp = mCircuitInfo.findCircuit(host); - if (!cdp) - { - LL_WARNS("Messaging") << "Not sending DenyTrustedCircuit to host without a circuit." << LL_ENDL; - return; - } - LL_INFOS("Messaging") << "Sending DenyTrustedCircuit to " << host << LL_ENDL; - newMessageFast(_PREHASH_DenyTrustedCircuit); - nextBlockFast(_PREHASH_DataBlock); - addUUIDFast(_PREHASH_EndPointID, cdp->getLocalEndPointID()); - sendMessage(host); -} - -void null_message_callback(LLMessageSystem *msg, void **data) -{ - // Nothing should ever go here, but we use this to register messages - // that we are expecting to see (and spinning on) at startup. - return; -} - -// Try to establish a bidirectional trust metric by pinging a host until it's -// up, and then sending auth messages. -void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_count ) -{ - LockMessageChecker lmc(this); - - std::string shared_secret = get_shared_secret(); - if(shared_secret.empty()) - { - LL_ERRS("Messaging") << "Trying to establish bidirectional trust on a machine without a shared secret!" << LL_ENDL; - } - LLTimer timeout; - - timeout.setTimerExpirySec(20.0); - setHandlerFuncFast(_PREHASH_StartPingCheck, null_message_callback, NULL); - setHandlerFuncFast(_PREHASH_CompletePingCheck, null_message_callback, - NULL); - - while (! timeout.hasExpired()) - { - newMessageFast(_PREHASH_StartPingCheck); - nextBlockFast(_PREHASH_PingID); - addU8Fast(_PREHASH_PingID, 0); - addU32Fast(_PREHASH_OldestUnacked, 0); - sendMessage(host); - if (lmc.checkMessages( frame_count )) - { - if (isMessageFast(_PREHASH_CompletePingCheck) && - (getSender() == host)) - { - break; - } - } - lmc.processAcks(); - ms_sleep(1); - } - - // Send a request, a deny, and give the host 2 seconds to complete - // the trust handshake. - newMessage("RequestTrustedCircuit"); - sendMessage(host); - reallySendDenyTrustedCircuit(host); - setHandlerFuncFast(_PREHASH_StartPingCheck, process_start_ping_check, NULL); - setHandlerFuncFast(_PREHASH_CompletePingCheck, process_complete_ping_check, NULL); - - timeout.setTimerExpirySec(2.0); - LLCircuitData* cdp = NULL; - while(!timeout.hasExpired()) - { - cdp = mCircuitInfo.findCircuit(host); - if(!cdp) break; // no circuit anymore, no point continuing. - if(cdp->getTrusted()) break; // circuit is trusted. - lmc.checkMessages(frame_count); - lmc.processAcks(); - ms_sleep(1); - } -} - - -void LLMessageSystem::dumpPacketToLog() -{ - LL_WARNS("Messaging") << "Packet Dump from:" << mPacketRing.getLastSender() << LL_ENDL; - LL_WARNS("Messaging") << "Packet Size:" << mTrueReceiveSize << LL_ENDL; - char line_buffer[256]; /* Flawfinder: ignore */ - S32 i; - S32 cur_line_pos = 0; - S32 cur_line = 0; - - for (i = 0; i < mTrueReceiveSize; i++) - { - S32 offset = cur_line_pos * 3; - snprintf(line_buffer + offset, sizeof(line_buffer) - offset, - "%02x ", mTrueReceiveBuffer[i]); /* Flawfinder: ignore */ - cur_line_pos++; - if (cur_line_pos >= 16) - { - cur_line_pos = 0; - LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << LL_ENDL; - cur_line++; - } - } - if (cur_line_pos) - { - LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << LL_ENDL; - } -} - - -//static -U64Microseconds LLMessageSystem::getMessageTimeUsecs(const BOOL update) -{ - if (gMessageSystem) - { - if (update) - { - gMessageSystem->mCurrentMessageTime = totalTime(); - } - return gMessageSystem->mCurrentMessageTime; - } - else - { - return totalTime(); - } -} - -//static -F64Seconds LLMessageSystem::getMessageTimeSeconds(const BOOL update) -{ - if (gMessageSystem) - { - if (update) - { - gMessageSystem->mCurrentMessageTime = totalTime(); - } - return gMessageSystem->mCurrentMessageTime; - } - else - { - return F64Seconds(totalTime()); - } -} - -std::string get_shared_secret() -{ - static const std::string SHARED_SECRET_KEY("shared_secret"); - if(g_shared_secret.empty()) - { - LLApp* app = LLApp::instance(); - if(app) return app->getOption(SHARED_SECRET_KEY); - } - return g_shared_secret; -} - -typedef std::map<const char*, LLMessageBuilder*> BuilderMap; - -void LLMessageSystem::newMessageFast(const char *name) -{ - //LL_DEBUGS("Messaging") << "creating new message: " << name << LL_ENDL; - LLMessageConfig::Flavor message_flavor = - LLMessageConfig::getMessageFlavor(name); - LLMessageConfig::Flavor server_flavor = - LLMessageConfig::getServerDefaultFlavor(); - - if(message_flavor == LLMessageConfig::TEMPLATE_FLAVOR) - { - mMessageBuilder = mTemplateMessageBuilder; - } - else if (message_flavor == LLMessageConfig::LLSD_FLAVOR) - { - mMessageBuilder = mLLSDMessageBuilder; - } - // NO_FLAVOR - else - { - if (server_flavor == LLMessageConfig::LLSD_FLAVOR) - { - mMessageBuilder = mLLSDMessageBuilder; - } - // TEMPLATE_FLAVOR or NO_FLAVOR - else - { - mMessageBuilder = mTemplateMessageBuilder; - } - } - mSendReliable = FALSE; - mMessageBuilder->newMessage(name); -} - -void LLMessageSystem::newMessage(const char *name) -{ - newMessageFast(LLMessageStringTable::getInstance()->getString(name)); -} - -void LLMessageSystem::addBinaryDataFast(const char *varname, const void *data, S32 size) -{ - mMessageBuilder->addBinaryData(varname, data, size); -} - -void LLMessageSystem::addBinaryData(const char *varname, const void *data, S32 size) -{ - mMessageBuilder->addBinaryData(LLMessageStringTable::getInstance()->getString(varname),data, size); -} - -void LLMessageSystem::addS8Fast(const char *varname, S8 v) -{ - mMessageBuilder->addS8(varname, v); -} - -void LLMessageSystem::addS8(const char *varname, S8 v) -{ - mMessageBuilder->addS8(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addU8Fast(const char *varname, U8 v) -{ - mMessageBuilder->addU8(varname, v); -} - -void LLMessageSystem::addU8(const char *varname, U8 v) -{ - mMessageBuilder->addU8(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addS16Fast(const char *varname, S16 v) -{ - mMessageBuilder->addS16(varname, v); -} - -void LLMessageSystem::addS16(const char *varname, S16 v) -{ - mMessageBuilder->addS16(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addU16Fast(const char *varname, U16 v) -{ - mMessageBuilder->addU16(varname, v); -} - -void LLMessageSystem::addU16(const char *varname, U16 v) -{ - mMessageBuilder->addU16(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addF32Fast(const char *varname, F32 v) -{ - mMessageBuilder->addF32(varname, v); -} - -void LLMessageSystem::addF32(const char *varname, F32 v) -{ - mMessageBuilder->addF32(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addS32Fast(const char *varname, S32 v) -{ - mMessageBuilder->addS32(varname, v); -} - -void LLMessageSystem::addS32(const char *varname, S32 v) -{ - mMessageBuilder->addS32(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addU32Fast(const char *varname, U32 v) -{ - mMessageBuilder->addU32(varname, v); -} - -void LLMessageSystem::addU32(const char *varname, U32 v) -{ - mMessageBuilder->addU32(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addU64Fast(const char *varname, U64 v) -{ - mMessageBuilder->addU64(varname, v); -} - -void LLMessageSystem::addU64(const char *varname, U64 v) -{ - mMessageBuilder->addU64(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addF64Fast(const char *varname, F64 v) -{ - mMessageBuilder->addF64(varname, v); -} - -void LLMessageSystem::addF64(const char *varname, F64 v) -{ - mMessageBuilder->addF64(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addIPAddrFast(const char *varname, U32 v) -{ - mMessageBuilder->addIPAddr(varname, v); -} - -void LLMessageSystem::addIPAddr(const char *varname, U32 v) -{ - mMessageBuilder->addIPAddr(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addIPPortFast(const char *varname, U16 v) -{ - mMessageBuilder->addIPPort(varname, v); -} - -void LLMessageSystem::addIPPort(const char *varname, U16 v) -{ - mMessageBuilder->addIPPort(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addBOOLFast(const char* varname, BOOL v) -{ - mMessageBuilder->addBOOL(varname, v); -} - -void LLMessageSystem::addBOOL(const char* varname, BOOL v) -{ - mMessageBuilder->addBOOL(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addStringFast(const char* varname, const char* v) -{ - mMessageBuilder->addString(varname, v); -} - -void LLMessageSystem::addString(const char* varname, const char* v) -{ - mMessageBuilder->addString(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addStringFast(const char* varname, const std::string& v) -{ - mMessageBuilder->addString(varname, v); -} - -void LLMessageSystem::addString(const char* varname, const std::string& v) -{ - mMessageBuilder->addString(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addVector3Fast(const char *varname, const LLVector3& v) -{ - mMessageBuilder->addVector3(varname, v); -} - -void LLMessageSystem::addVector3(const char *varname, const LLVector3& v) -{ - mMessageBuilder->addVector3(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addVector4Fast(const char *varname, const LLVector4& v) -{ - mMessageBuilder->addVector4(varname, v); -} - -void LLMessageSystem::addVector4(const char *varname, const LLVector4& v) -{ - mMessageBuilder->addVector4(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addVector3dFast(const char *varname, const LLVector3d& v) -{ - mMessageBuilder->addVector3d(varname, v); -} - -void LLMessageSystem::addVector3d(const char *varname, const LLVector3d& v) -{ - mMessageBuilder->addVector3d(LLMessageStringTable::getInstance()->getString(varname), v); -} - -void LLMessageSystem::addQuatFast(const char *varname, const LLQuaternion& v) -{ - mMessageBuilder->addQuat(varname, v); -} - -void LLMessageSystem::addQuat(const char *varname, const LLQuaternion& v) -{ - mMessageBuilder->addQuat(LLMessageStringTable::getInstance()->getString(varname), v); -} - - -void LLMessageSystem::addUUIDFast(const char *varname, const LLUUID& v) -{ - mMessageBuilder->addUUID(varname, v); -} - -void LLMessageSystem::addUUID(const char *varname, const LLUUID& v) -{ - mMessageBuilder->addUUID(LLMessageStringTable::getInstance()->getString(varname), v); -} - -S32 LLMessageSystem::getCurrentSendTotal() const -{ - return mMessageBuilder->getMessageSize(); -} - -void LLMessageSystem::getS8Fast(const char *block, const char *var, S8 &u, - S32 blocknum) -{ - mMessageReader->getS8(block, var, u, blocknum); -} - -void LLMessageSystem::getS8(const char *block, const char *var, S8 &u, - S32 blocknum) -{ - getS8Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), u, blocknum); -} - -void LLMessageSystem::getU8Fast(const char *block, const char *var, U8 &u, - S32 blocknum) -{ - mMessageReader->getU8(block, var, u, blocknum); -} - -void LLMessageSystem::getU8(const char *block, const char *var, U8 &u, - S32 blocknum) -{ - getU8Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), u, blocknum); -} - -void LLMessageSystem::getBOOLFast(const char *block, const char *var, BOOL &b, - S32 blocknum) -{ - mMessageReader->getBOOL(block, var, b, blocknum); -} - -void LLMessageSystem::getBOOL(const char *block, const char *var, BOOL &b, - S32 blocknum) -{ - getBOOLFast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), b, blocknum); -} - -void LLMessageSystem::getS16Fast(const char *block, const char *var, S16 &d, - S32 blocknum) -{ - mMessageReader->getS16(block, var, d, blocknum); -} - -void LLMessageSystem::getS16(const char *block, const char *var, S16 &d, - S32 blocknum) -{ - getS16Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), d, blocknum); -} - -void LLMessageSystem::getU16Fast(const char *block, const char *var, U16 &d, - S32 blocknum) -{ - mMessageReader->getU16(block, var, d, blocknum); -} - -void LLMessageSystem::getU16(const char *block, const char *var, U16 &d, - S32 blocknum) -{ - getU16Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), d, blocknum); -} - -void LLMessageSystem::getS32Fast(const char *block, const char *var, S32 &d, - S32 blocknum) -{ - mMessageReader->getS32(block, var, d, blocknum); -} - -void LLMessageSystem::getS32(const char *block, const char *var, S32 &d, - S32 blocknum) -{ - getS32Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), d, blocknum); -} - -void LLMessageSystem::getU32Fast(const char *block, const char *var, U32 &d, - S32 blocknum) -{ - mMessageReader->getU32(block, var, d, blocknum); -} - -void LLMessageSystem::getU32(const char *block, const char *var, U32 &d, - S32 blocknum) -{ - getU32Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), d, blocknum); -} - -void LLMessageSystem::getU64Fast(const char *block, const char *var, U64 &d, - S32 blocknum) -{ - mMessageReader->getU64(block, var, d, blocknum); -} - -void LLMessageSystem::getU64(const char *block, const char *var, U64 &d, - S32 blocknum) -{ - - getU64Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), d, blocknum); -} - -void LLMessageSystem::getBinaryDataFast(const char *blockname, - const char *varname, - void *datap, S32 size, - S32 blocknum, S32 max_size) -{ - mMessageReader->getBinaryData(blockname, varname, datap, size, blocknum, - max_size); -} - -void LLMessageSystem::getBinaryData(const char *blockname, - const char *varname, - void *datap, S32 size, - S32 blocknum, S32 max_size) -{ - getBinaryDataFast(LLMessageStringTable::getInstance()->getString(blockname), - LLMessageStringTable::getInstance()->getString(varname), - datap, size, blocknum, max_size); -} - -void LLMessageSystem::getF32Fast(const char *block, const char *var, F32 &d, - S32 blocknum) -{ - mMessageReader->getF32(block, var, d, blocknum); -} - -void LLMessageSystem::getF32(const char *block, const char *var, F32 &d, - S32 blocknum) -{ - getF32Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), d, blocknum); -} - -void LLMessageSystem::getF64Fast(const char *block, const char *var, F64 &d, - S32 blocknum) -{ - mMessageReader->getF64(block, var, d, blocknum); -} - -void LLMessageSystem::getF64(const char *block, const char *var, F64 &d, - S32 blocknum) -{ - getF64Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), d, blocknum); -} - - -void LLMessageSystem::getVector3Fast(const char *block, const char *var, - LLVector3 &v, S32 blocknum ) -{ - mMessageReader->getVector3(block, var, v, blocknum); -} - -void LLMessageSystem::getVector3(const char *block, const char *var, - LLVector3 &v, S32 blocknum ) -{ - getVector3Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), v, blocknum); -} - -void LLMessageSystem::getVector4Fast(const char *block, const char *var, - LLVector4 &v, S32 blocknum ) -{ - mMessageReader->getVector4(block, var, v, blocknum); -} - -void LLMessageSystem::getVector4(const char *block, const char *var, - LLVector4 &v, S32 blocknum ) -{ - getVector4Fast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), v, blocknum); -} - -void LLMessageSystem::getVector3dFast(const char *block, const char *var, - LLVector3d &v, S32 blocknum ) -{ - mMessageReader->getVector3d(block, var, v, blocknum); -} - -void LLMessageSystem::getVector3d(const char *block, const char *var, - LLVector3d &v, S32 blocknum ) -{ - getVector3dFast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), v, blocknum); -} - -void LLMessageSystem::getQuatFast(const char *block, const char *var, - LLQuaternion &q, S32 blocknum ) -{ - mMessageReader->getQuat(block, var, q, blocknum); -} - -void LLMessageSystem::getQuat(const char *block, const char *var, - LLQuaternion &q, S32 blocknum) -{ - getQuatFast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), q, blocknum); -} - -void LLMessageSystem::getUUIDFast(const char *block, const char *var, - LLUUID &u, S32 blocknum ) -{ - mMessageReader->getUUID(block, var, u, blocknum); -} - -void LLMessageSystem::getUUID(const char *block, const char *var, LLUUID &u, - S32 blocknum ) -{ - getUUIDFast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), u, blocknum); -} - -void LLMessageSystem::getIPAddrFast(const char *block, const char *var, - U32 &u, S32 blocknum) -{ - mMessageReader->getIPAddr(block, var, u, blocknum); -} - -void LLMessageSystem::getIPAddr(const char *block, const char *var, U32 &u, - S32 blocknum) -{ - getIPAddrFast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), u, blocknum); -} - -void LLMessageSystem::getIPPortFast(const char *block, const char *var, - U16 &u, S32 blocknum) -{ - mMessageReader->getIPPort(block, var, u, blocknum); -} - -void LLMessageSystem::getIPPort(const char *block, const char *var, U16 &u, - S32 blocknum) -{ - getIPPortFast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), u, - blocknum); -} - - -void LLMessageSystem::getStringFast(const char *block, const char *var, - S32 buffer_size, char *s, S32 blocknum) -{ - if(buffer_size <= 0) - { - LL_WARNS("Messaging") << "buffer_size <= 0" << LL_ENDL; - } - mMessageReader->getString(block, var, buffer_size, s, blocknum); -} - -void LLMessageSystem::getString(const char *block, const char *var, - S32 buffer_size, char *s, S32 blocknum ) -{ - getStringFast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), buffer_size, s, - blocknum); -} - -void LLMessageSystem::getStringFast(const char *block, const char *var, - std::string& outstr, S32 blocknum) -{ - mMessageReader->getString(block, var, outstr, blocknum); -} - -void LLMessageSystem::getString(const char *block, const char *var, - std::string& outstr, S32 blocknum ) -{ - getStringFast(LLMessageStringTable::getInstance()->getString(block), - LLMessageStringTable::getInstance()->getString(var), outstr, - blocknum); -} - -BOOL LLMessageSystem::has(const char *blockname) const -{ - return getNumberOfBlocks(blockname) > 0; -} - -S32 LLMessageSystem::getNumberOfBlocksFast(const char *blockname) const -{ - return mMessageReader->getNumberOfBlocks(blockname); -} - -S32 LLMessageSystem::getNumberOfBlocks(const char *blockname) const -{ - return getNumberOfBlocksFast(LLMessageStringTable::getInstance()->getString(blockname)); -} - -S32 LLMessageSystem::getSizeFast(const char *blockname, const char *varname) const -{ - return mMessageReader->getSize(blockname, varname); -} - -S32 LLMessageSystem::getSize(const char *blockname, const char *varname) const -{ - return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname), - LLMessageStringTable::getInstance()->getString(varname)); -} - -// size in bytes of variable length data -S32 LLMessageSystem::getSizeFast(const char *blockname, S32 blocknum, - const char *varname) const -{ - return mMessageReader->getSize(blockname, blocknum, varname); -} - -S32 LLMessageSystem::getSize(const char *blockname, S32 blocknum, - const char *varname) const -{ - return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname), blocknum, - LLMessageStringTable::getInstance()->getString(varname)); -} - -S32 LLMessageSystem::getReceiveSize() const -{ - return mMessageReader->getMessageSize(); -} - -//static -void LLMessageSystem::setTimeDecodes( BOOL b ) -{ - LLMessageReader::setTimeDecodes(b); -} - -//static -void LLMessageSystem::setTimeDecodesSpamThreshold( F32 seconds ) -{ - LLMessageReader::setTimeDecodesSpamThreshold(seconds); -} - -LockMessageChecker::LockMessageChecker(LLMessageSystem* msgsystem): - // for the lifespan of this LockMessageChecker instance, use - // LLTemplateMessageReader as msgsystem's mMessageReader - LockMessageReader(msgsystem->mMessageReader, msgsystem->mTemplateMessageReader), - mMessageSystem(msgsystem) -{} - -// HACK! babbage: return true if message rxed via either UDP or HTTP -// TODO: babbage: move gServicePump in to LLMessageSystem? -bool LLMessageSystem::checkAllMessages(LockMessageChecker& lmc, S64 frame_count, LLPumpIO* http_pump) -{ - if(lmc.checkMessages(frame_count)) - { - return true; - } - U32 packetsIn = mPacketsIn; - http_pump->pump(); - http_pump->callback(); - return (mPacketsIn - packetsIn) > 0; -} - -void LLMessageSystem::banUdpMessage(const std::string& name) -{ - message_template_name_map_t::iterator itt = mMessageTemplates.find( - LLMessageStringTable::getInstance()->getString(name.c_str()) - ); - if(itt != mMessageTemplates.end()) - { - itt->second->banUdp(); - } - else - { - LL_WARNS() << "Attempted to ban an unknown message: " << name << "." << LL_ENDL; - } -} -const LLHost& LLMessageSystem::getSender() const -{ - return mLastSender; -} - -void LLMessageSystem::sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("untrustedSimulatorMessage", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); - - - if (url.empty()) - { - LL_WARNS() << "sendUntrustedSimulatorMessageCoro called with empty capability!" << LL_ENDL; - return; - } - - LL_INFOS() << "sendUntrustedSimulatorMessageCoro: message " << message << " to cap " << url << LL_ENDL; - LLSD postData; - postData["message"] = message; - postData["body"] = body; - - LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if ((callback) && (!callback.empty())) - callback((status) ? LL_ERR_NOERR : LL_ERR_TCP_TIMEOUT); -} - - -LLHTTPRegistration<LLHTTPNodeAdapter<LLTrustedMessageService> > - gHTTPRegistrationTrustedMessageWildcard("/trusted-message/<message-name>"); - +/**
+ * @file message.cpp
+ * @brief LLMessageSystem class implementation
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "message.h"
+
+// system library includes
+#if !LL_WINDOWS
+// following header files required for inet_addr()
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <iomanip>
+#include <iterator>
+#include <sstream>
+
+#include "llapr.h"
+#include "apr_portable.h"
+#include "apr_network_io.h"
+#include "apr_poll.h"
+
+// linden library headers
+#include "llapp.h"
+#include "indra_constants.h"
+#include "lldir.h"
+#include "llerror.h"
+#include "llfasttimer.h"
+#include "llhttpnodeadapter.h"
+#include "llmd5.h"
+#include "llmessagebuilder.h"
+#include "llmessageconfig.h"
+#include "lltemplatemessagedispatcher.h"
+#include "llpumpio.h"
+#include "lltemplatemessagebuilder.h"
+#include "lltemplatemessagereader.h"
+#include "lltrustedmessageservice.h"
+#include "llmessagetemplate.h"
+#include "llmessagetemplateparser.h"
+#include "llsd.h"
+#include "llsdmessagebuilder.h"
+#include "llsdmessagereader.h"
+#include "llsdserialize.h"
+#include "llstring.h"
+#include "lltransfermanager.h"
+#include "lluuid.h"
+#include "llxfermanager.h"
+#include "llquaternion.h"
+#include "u64.h"
+#include "v3dmath.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "lltransfertargetvfile.h"
+#include "llcorehttputil.h"
+#include "llpounceable.h"
+
+// Constants
+//const char* MESSAGE_LOG_FILENAME = "message.log";
+static const F32Seconds CIRCUIT_DUMP_TIMEOUT(30.f);
+static const S32 TRUST_TIME_WINDOW = 3;
+
+// *NOTE: This needs to be moved into a seperate file so that it never gets
+// included in the viewer. 30 Sep 2002 mark
+// *NOTE: I don't think it's important that the messgage system tracks
+// this since it must get set externally. 2004.08.25 Phoenix.
+static std::string g_shared_secret;
+std::string get_shared_secret();
+
+class LLMessagePollInfo
+{
+public:
+ apr_socket_t *mAPRSocketp;
+ apr_pollfd_t mPollFD;
+};
+
+class LLMessageHandlerBridge : public LLHTTPNode
+{
+ virtual bool validate(const std::string& name, LLSD& context) const
+ { return true; }
+
+ virtual void post(LLHTTPNode::ResponsePtr response, const LLSD& context,
+ const LLSD& input) const;
+};
+
+//virtual
+void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response,
+ const LLSD& context, const LLSD& input) const
+{
+ std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"];
+ char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str());
+
+ LL_DEBUGS() << "Setting mLastSender " << input["sender"].asString() << LL_ENDL;
+ gMessageSystem->mLastSender = LLHost(input["sender"].asString());
+ gMessageSystem->mPacketsIn += 1;
+ gMessageSystem->mLLSDMessageReader->setMessage(namePtr, input["body"]);
+ LockMessageReader rdr(gMessageSystem->mMessageReader, gMessageSystem->mLLSDMessageReader);
+
+ if(gMessageSystem->callHandler(namePtr, false, gMessageSystem))
+ {
+ response->result(LLSD());
+ }
+ else
+ {
+ response->notFound();
+ }
+}
+
+LLHTTPRegistration<LLMessageHandlerBridge>
+ gHTTPRegistrationMessageWildcard("/message/<message-name>");
+
+//virtual
+LLUseCircuitCodeResponder::~LLUseCircuitCodeResponder()
+{
+ // even abstract base classes need a concrete destructor
+}
+
+static const char* nullToEmpty(const char* s)
+{
+ static char emptyString[] = "";
+ return s? s : emptyString;
+}
+
+void LLMessageSystem::init()
+{
+ // initialize member variables
+ mVerboseLog = false;
+
+ mbError = false;
+ mErrorCode = 0;
+ mSendReliable = false;
+
+ mUnackedListDepth = 0;
+ mUnackedListSize = 0;
+ mDSMaxListDepth = 0;
+
+ mNumberHighFreqMessages = 0;
+ mNumberMediumFreqMessages = 0;
+ mNumberLowFreqMessages = 0;
+ mPacketsIn = mPacketsOut = 0;
+ mBytesIn = mBytesOut = 0;
+ mCompressedPacketsIn = mCompressedPacketsOut = 0;
+ mReliablePacketsIn = mReliablePacketsOut = 0;
+
+ mCompressedBytesIn = 0;
+ mCompressedBytesOut = 0;
+ mUncompressedBytesIn = 0;
+ mUncompressedBytesOut = 0;
+ mTotalBytesIn = 0;
+ mTotalBytesOut = 0;
+
+ mDroppedPackets = 0; // total dropped packets in
+ mResentPackets = 0; // total resent packets out
+ mFailedResendPackets = 0; // total resend failure packets out
+ mOffCircuitPackets = 0; // total # of off-circuit packets rejected
+ mInvalidOnCircuitPackets = 0; // total # of on-circuit packets rejected
+
+ mOurCircuitCode = 0;
+
+ mIncomingCompressedSize = 0;
+ mCurrentRecvPacketID = 0;
+
+ mMessageFileVersionNumber = 0.f;
+
+ mTimingCallback = NULL;
+ mTimingCallbackData = NULL;
+
+ mMessageBuilder = NULL;
+ LockMessageReader(mMessageReader, NULL);
+}
+
+// Read file and build message templates
+LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port,
+ S32 version_major,
+ S32 version_minor,
+ S32 version_patch,
+ bool failure_is_fatal,
+ const F32 circuit_heartbeat_interval, const F32 circuit_timeout) :
+ mCircuitInfo(F32Seconds(circuit_heartbeat_interval), F32Seconds(circuit_timeout)),
+ mLastMessageFromTrustedMessageService(false)
+{
+ init();
+
+ mSendSize = 0;
+
+ mSystemVersionMajor = version_major;
+ mSystemVersionMinor = version_minor;
+ mSystemVersionPatch = version_patch;
+ mSystemVersionServer = 0;
+ mVersionFlags = 0x0;
+
+ // default to not accepting packets from not alive circuits
+ mbProtected = true;
+
+ // default to blocking trusted connections on a public interface if one is specified
+ mBlockUntrustedInterface = true;
+
+ mSendPacketFailureCount = 0;
+
+ mCircuitPrintFreq = F32Seconds(60.f);
+
+ loadTemplateFile(filename, failure_is_fatal);
+
+ mTemplateMessageBuilder = new LLTemplateMessageBuilder(mMessageTemplates);
+ mLLSDMessageBuilder = new LLSDMessageBuilder();
+ mMessageBuilder = NULL;
+
+ mTemplateMessageReader = new LLTemplateMessageReader(mMessageNumbers);
+ mLLSDMessageReader = new LLSDMessageReader();
+
+ // initialize various bits of net info
+ mSocket = 0;
+ mPort = port;
+
+ S32 error = start_net(mSocket, mPort);
+ if (error != 0)
+ {
+ mbError = true;
+ mErrorCode = error;
+ }
+// LL_DEBUGS("Messaging") << << "*** port: " << mPort << LL_ENDL;
+
+ //
+ // Create the data structure that we can poll on
+ //
+ if (!gAPRPoolp)
+ {
+ LL_ERRS("Messaging") << "No APR pool before message system initialization!" << LL_ENDL;
+ ll_init_apr();
+ }
+ apr_socket_t *aprSocketp = NULL;
+ apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, gAPRPoolp);
+
+ mPollInfop = new LLMessagePollInfo;
+ mPollInfop->mAPRSocketp = aprSocketp;
+ mPollInfop->mPollFD.p = gAPRPoolp;
+ mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET;
+ mPollInfop->mPollFD.reqevents = APR_POLLIN;
+ mPollInfop->mPollFD.rtnevents = 0;
+ mPollInfop->mPollFD.desc.s = aprSocketp;
+ mPollInfop->mPollFD.client_data = NULL;
+
+ F64Seconds mt_sec = getMessageTimeSeconds();
+ mResendDumpTime = mt_sec;
+ mMessageCountTime = mt_sec;
+ mCircuitPrintTime = mt_sec;
+ mCurrentMessageTime = F64Seconds(mt_sec);
+
+ // Constants for dumping output based on message processing time/count
+ mNumMessageCounts = 0;
+ mMaxMessageCounts = 200; // >= 0 means dump warnings
+ mMaxMessageTime = F32Seconds(1.f);
+
+ mTrueReceiveSize = 0;
+
+ mReceiveTime = F32Seconds(0.f);
+}
+
+
+
+// Read file and build message templates
+void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure_is_fatal)
+{
+ if(filename.empty())
+ {
+ LL_ERRS("Messaging") << "No template filename specified" << LL_ENDL;
+ mbError = true;
+ return;
+ }
+
+ std::string template_body;
+ if(!_read_file_into_string(template_body, filename))
+ {
+ if (failure_is_fatal) {
+ LL_ERRS("Messaging") << "Failed to open template: " << filename << LL_ENDL;
+ } else {
+ LL_WARNS("Messaging") << "Failed to open template: " << filename << LL_ENDL;
+ }
+ mbError = true;
+ return;
+ }
+
+ LLTemplateTokenizer tokens(template_body);
+ LLTemplateParser parsed(tokens);
+ mMessageFileVersionNumber = parsed.getVersion();
+ S32 count = 0;
+ for(LLTemplateParser::message_iterator iter = parsed.getMessagesBegin();
+ iter != parsed.getMessagesEnd();
+ iter++)
+ {
+ addTemplate(*iter);
+ count++;
+ }
+ LL_INFOS("Messaging") << "Read " << count << " messages from " << filename << LL_ENDL;
+}
+
+
+LLMessageSystem::~LLMessageSystem()
+{
+ mMessageTemplates.clear(); // don't delete templates.
+ for_each(mMessageNumbers.begin(), mMessageNumbers.end(), DeletePairedPointer());
+ mMessageNumbers.clear();
+
+ if (!mbError)
+ {
+ end_net(mSocket);
+ }
+ mSocket = 0;
+
+ delete mTemplateMessageReader;
+ mTemplateMessageReader = NULL;
+
+ delete mTemplateMessageBuilder;
+ mTemplateMessageBuilder = NULL;
+ mMessageBuilder = NULL;
+
+ delete mLLSDMessageReader;
+ mLLSDMessageReader = NULL;
+
+ delete mLLSDMessageBuilder;
+ mLLSDMessageBuilder = NULL;
+
+ delete mPollInfop;
+ mPollInfop = NULL;
+
+ mIncomingCompressedSize = 0;
+ mCurrentRecvPacketID = 0;
+}
+
+void LLMessageSystem::clearReceiveState()
+{
+ mCurrentRecvPacketID = 0;
+ mIncomingCompressedSize = 0;
+ mLastSender.invalidate();
+ mLastReceivingIF.invalidate();
+ mMessageReader->clearMessage();
+ mLastMessageFromTrustedMessageService = false;
+}
+
+
+bool LLMessageSystem::poll(F32 seconds)
+{
+ S32 num_socks;
+ apr_status_t status;
+ status = apr_poll(&(mPollInfop->mPollFD), 1, &num_socks,(U64)(seconds*1000000.f));
+ if (status != APR_TIMEUP)
+ {
+ ll_apr_warn_status(status);
+ }
+ if (num_socks)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool LLMessageSystem::isTrustedSender(const LLHost& host) const
+{
+ LLCircuitData* cdp = mCircuitInfo.findCircuit(host);
+ if(NULL == cdp)
+ {
+ return false;
+ }
+ return cdp->getTrusted();
+}
+
+void LLMessageSystem::receivedMessageFromTrustedSender()
+{
+ mLastMessageFromTrustedMessageService = true;
+}
+
+bool LLMessageSystem::isTrustedSender() const
+{
+ return mLastMessageFromTrustedMessageService ||
+ isTrustedSender(getSender());
+}
+
+static LLMessageSystem::message_template_name_map_t::const_iterator
+findTemplate(const LLMessageSystem::message_template_name_map_t& templates,
+ std::string name)
+{
+ const char* namePrehash = LLMessageStringTable::getInstance()->getString(name.c_str());
+ if(NULL == namePrehash) {return templates.end();}
+ return templates.find(namePrehash);
+}
+
+bool LLMessageSystem::isTrustedMessage(const std::string& name) const
+{
+ message_template_name_map_t::const_iterator iter =
+ findTemplate(mMessageTemplates, name);
+ if(iter == mMessageTemplates.end()) {return false;}
+ return iter->second->getTrust() == MT_TRUST;
+}
+
+bool LLMessageSystem::isUntrustedMessage(const std::string& name) const
+{
+ message_template_name_map_t::const_iterator iter =
+ findTemplate(mMessageTemplates, name);
+ if(iter == mMessageTemplates.end()) {return false;}
+ return iter->second->getTrust() == MT_NOTRUST;
+}
+
+LLCircuitData* LLMessageSystem::findCircuit(const LLHost& host,
+ bool resetPacketId)
+{
+ LLCircuitData* cdp = mCircuitInfo.findCircuit(host);
+ if (!cdp)
+ {
+ // This packet comes from a circuit we don't know about.
+
+ // Are we rejecting off-circuit packets?
+ if (mbProtected)
+ {
+ // cdp is already NULL, so we don't need to unset it.
+ }
+ else
+ {
+ // nope, open the new circuit
+ cdp = mCircuitInfo.addCircuitData(host, mCurrentRecvPacketID);
+
+ if(resetPacketId)
+ {
+ // I added this - I think it's correct - DJS
+ // reset packet in ID
+ cdp->setPacketInID(mCurrentRecvPacketID);
+ }
+ // And claim the packet is on the circuit we just added.
+ }
+ }
+ else
+ {
+ // this is an old circuit. . . is it still alive?
+ if (!cdp->isAlive())
+ {
+ // nope. don't accept if we're protected
+ if (mbProtected)
+ {
+ // don't accept packets from unexpected sources
+ cdp = NULL;
+ }
+ else
+ {
+ // wake up the circuit
+ cdp->setAlive(true);
+
+ if(resetPacketId)
+ {
+ // reset packet in ID
+ cdp->setPacketInID(mCurrentRecvPacketID);
+ }
+ }
+ }
+ }
+ return cdp;
+}
+
+// Returns true if a valid, on-circuit message has been received.
+// Requiring a non-const LockMessageChecker reference ensures that
+// mMessageReader has been set to mTemplateMessageReader.
+bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
+{
+ // Pump
+ bool valid_packet = false;
+
+ LLTransferTargetVFile::updateQueue();
+
+ if (!mNumMessageCounts)
+ {
+ // This is the first message being handled after a resetReceiveCounts,
+ // we must be starting the message processing loop. Reset the timers.
+ mCurrentMessageTime = totalTime();
+ mMessageCountTime = getMessageTimeSeconds();
+ }
+
+ // loop until either no packets or a valid packet
+ // i.e., burn through packets from unregistered circuits
+ S32 receive_size = 0;
+ do
+ {
+ clearReceiveState();
+
+ bool recv_reliable = false;
+ bool recv_resent = false;
+ S32 acks = 0;
+ S32 true_rcv_size = 0;
+
+ U8* buffer = mTrueReceiveBuffer;
+
+ mTrueReceiveSize = mPacketRing.receivePacket(mSocket, (char *)mTrueReceiveBuffer);
+ // If you want to dump all received packets into SecondLife.log, uncomment this
+ //dumpPacketToLog();
+
+ receive_size = mTrueReceiveSize;
+ mLastSender = mPacketRing.getLastSender();
+ mLastReceivingIF = mPacketRing.getLastReceivingInterface();
+
+ if (receive_size < (S32) LL_MINIMUM_VALID_PACKET_SIZE)
+ {
+ // A receive size of zero is OK, that means that there are no more packets available.
+ // Ones that are non-zero but below the minimum packet size are worrisome.
+ if (receive_size > 0)
+ {
+ LL_WARNS("Messaging") << "Invalid (too short) packet discarded " << receive_size << LL_ENDL;
+ callExceptionFunc(MX_PACKET_TOO_SHORT);
+ }
+ // no data in packet receive buffer
+ valid_packet = false;
+ }
+ else
+ {
+ LLHost host;
+ LLCircuitData* cdp;
+
+ // note if packet acks are appended.
+ if(buffer[0] & LL_ACK_FLAG)
+ {
+ acks += buffer[--receive_size];
+ true_rcv_size = receive_size;
+ if(receive_size >= ((S32)(acks * sizeof(TPACKETID) + LL_MINIMUM_VALID_PACKET_SIZE)))
+ {
+ receive_size -= acks * sizeof(TPACKETID);
+ }
+ else
+ {
+ // mal-formed packet. ignore it and continue with
+ // the next one
+ LL_WARNS("Messaging") << "Malformed packet received. Packet size "
+ << receive_size << " with invalid no. of acks " << acks
+ << LL_ENDL;
+ valid_packet = false;
+ continue;
+ }
+ }
+
+ // process the message as normal
+ mIncomingCompressedSize = zeroCodeExpand(&buffer, &receive_size);
+ mCurrentRecvPacketID = ntohl(*((U32*)(&buffer[1])));
+ host = getSender();
+
+ const bool resetPacketId = true;
+ cdp = findCircuit(host, resetPacketId);
+
+ // At this point, cdp is now a pointer to the circuit that
+ // this message came in on if it's valid, and NULL if the
+ // circuit was bogus.
+
+ if(cdp && (acks > 0) && ((S32)(acks * sizeof(TPACKETID)) < (true_rcv_size)))
+ {
+ TPACKETID packet_id;
+ U32 mem_id=0;
+ for(S32 i = 0; i < acks; ++i)
+ {
+ true_rcv_size -= sizeof(TPACKETID);
+ memcpy(&mem_id, &mTrueReceiveBuffer[true_rcv_size], /* Flawfinder: ignore*/
+ sizeof(TPACKETID));
+ packet_id = ntohl(mem_id);
+ //LL_INFOS("Messaging") << "got ack: " << packet_id << LL_ENDL;
+ cdp->ackReliablePacket(packet_id);
+ }
+ if (!cdp->getUnackedPacketCount())
+ {
+ // Remove this circuit from the list of circuits with unacked packets
+ mCircuitInfo.mUnackedCircuitMap.erase(cdp->mHost);
+ }
+ }
+
+ if (buffer[0] & LL_RELIABLE_FLAG)
+ {
+ recv_reliable = true;
+ }
+ if (buffer[0] & LL_RESENT_FLAG)
+ {
+ recv_resent = true;
+ if (cdp && cdp->isDuplicateResend(mCurrentRecvPacketID))
+ {
+ // We need to ACK here to suppress
+ // further resends of packets we've
+ // already seen.
+ if (recv_reliable)
+ {
+ //mAckList.addData(new LLPacketAck(host, mCurrentRecvPacketID));
+ // ***************************************
+ // TESTING CODE
+ //if(mCircuitInfo.mCurrentCircuit->mHost != host)
+ //{
+ // LL_WARNS("Messaging") << "DISCARDED PACKET HOST MISMATCH! HOST: "
+ // << host << " CIRCUIT: "
+ // << mCircuitInfo.mCurrentCircuit->mHost
+ // << LL_ENDL;
+ //}
+ // ***************************************
+ //mCircuitInfo.mCurrentCircuit->mAcks.put(mCurrentRecvPacketID);
+ cdp->collectRAck(mCurrentRecvPacketID);
+ }
+
+ LL_DEBUGS("Messaging") << "Discarding duplicate resend from " << host << LL_ENDL;
+ if(mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << host;
+ std::string tbuf;
+ tbuf = llformat( "\t%6d\t%6d\t%6d ", receive_size, (mIncomingCompressedSize ? mIncomingCompressedSize : receive_size), mCurrentRecvPacketID);
+ str << tbuf << "(unknown)"
+ << (recv_reliable ? " reliable" : "")
+ << " resent "
+ << ((acks > 0) ? "acks" : "")
+ << " DISCARD DUPLICATE";
+ LL_INFOS("Messaging") << str.str() << LL_ENDL;
+ }
+ mPacketsIn++;
+ valid_packet = false;
+ continue;
+ }
+ }
+
+ // UseCircuitCode can be a valid, off-circuit packet.
+ // But we don't want to acknowledge UseCircuitCode until the circuit is
+ // available, which is why the acknowledgement test is done above. JC
+ bool trusted = cdp && cdp->getTrusted();
+ valid_packet = mTemplateMessageReader->validateMessage(
+ buffer,
+ receive_size,
+ host,
+ trusted);
+ if (!valid_packet)
+ {
+ clearReceiveState();
+ }
+
+ // UseCircuitCode is allowed in even from an invalid circuit, so that
+ // we can toss circuits around.
+ if(
+ valid_packet &&
+ !cdp &&
+ (mTemplateMessageReader->getMessageName() !=
+ _PREHASH_UseCircuitCode))
+ {
+ logMsgFromInvalidCircuit( host, recv_reliable );
+ clearReceiveState();
+ valid_packet = false;
+ }
+
+ if(
+ valid_packet &&
+ cdp &&
+ !cdp->getTrusted() &&
+ mTemplateMessageReader->isTrusted())
+ {
+ logTrustedMsgFromUntrustedCircuit( host );
+ clearReceiveState();
+
+ sendDenyTrustedCircuit(host);
+ valid_packet = false;
+ }
+
+ if( valid_packet )
+ {
+ logValidMsg(cdp, host, recv_reliable, recv_resent, acks>0 );
+ valid_packet = mTemplateMessageReader->readMessage(buffer, host);
+ }
+
+ // It's possible that the circuit went away, because ANY message can disable the circuit
+ // (for example, UseCircuit, CloseCircuit, DisableSimulator). Find it again.
+ cdp = mCircuitInfo.findCircuit(host);
+
+ if (valid_packet)
+ {
+ mPacketsIn++;
+ mBytesIn += mTrueReceiveSize;
+
+ // ACK here for valid packets that we've seen
+ // for the first time.
+ if (cdp && recv_reliable)
+ {
+ // Add to the recently received list for duplicate suppression
+ cdp->mRecentlyReceivedReliablePackets[mCurrentRecvPacketID] = getMessageTimeUsecs();
+
+ // Put it onto the list of packets to be acked
+ cdp->collectRAck(mCurrentRecvPacketID);
+ mReliablePacketsIn++;
+ }
+ }
+ else
+ {
+ if (mbProtected && (!cdp))
+ {
+ LL_WARNS("Messaging") << "Invalid Packet from invalid circuit " << host << LL_ENDL;
+ mOffCircuitPackets++;
+ }
+ else
+ {
+ mInvalidOnCircuitPackets++;
+ }
+ }
+ }
+ } while (!valid_packet && receive_size > 0);
+
+ F64Seconds mt_sec = getMessageTimeSeconds();
+ // Check to see if we need to print debug info
+ if ((mt_sec - mCircuitPrintTime) > mCircuitPrintFreq)
+ {
+ dumpCircuitInfo();
+ mCircuitPrintTime = mt_sec;
+ }
+
+ if( !valid_packet )
+ {
+ clearReceiveState();
+ }
+
+ return valid_packet;
+}
+
+S32 LLMessageSystem::getReceiveBytes() const
+{
+ if (getReceiveCompressedSize())
+ {
+ return getReceiveCompressedSize() * 8;
+ }
+ else
+ {
+ return getReceiveSize() * 8;
+ }
+}
+
+
+void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time)
+{
+ F64Seconds mt_sec = getMessageTimeSeconds();
+ {
+ gTransferManager.updateTransfers();
+
+ if (gXferManager)
+ {
+ gXferManager->retransmitUnackedPackets();
+ }
+
+ if (gAssetStorage)
+ {
+ gAssetStorage->checkForTimeouts();
+ }
+ }
+
+ bool dump = false;
+ {
+ // Check the status of circuits
+ mCircuitInfo.updateWatchDogTimers(this);
+
+ //resend any necessary packets
+ mCircuitInfo.resendUnackedPackets(mUnackedListDepth, mUnackedListSize);
+
+ //cycle through ack list for each host we need to send acks to
+ mCircuitInfo.sendAcks(collect_time);
+
+ if (!mDenyTrustedCircuitSet.empty())
+ {
+ LL_INFOS("Messaging") << "Sending queued DenyTrustedCircuit messages." << LL_ENDL;
+ for (host_set_t::iterator hostit = mDenyTrustedCircuitSet.begin(); hostit != mDenyTrustedCircuitSet.end(); ++hostit)
+ {
+ reallySendDenyTrustedCircuit(*hostit);
+ }
+ mDenyTrustedCircuitSet.clear();
+ }
+
+ if (mMaxMessageCounts >= 0)
+ {
+ if (mNumMessageCounts >= mMaxMessageCounts)
+ {
+ dump = true;
+ }
+ }
+
+ if (mMaxMessageTime >= F32Seconds(0.f))
+ {
+ // This is one of the only places where we're required to get REAL message system time.
+ mReceiveTime = getMessageTimeSeconds(true) - mMessageCountTime;
+ if (mReceiveTime > mMaxMessageTime)
+ {
+ dump = true;
+ }
+ }
+ }
+
+ if (dump)
+ {
+ dumpReceiveCounts();
+ }
+ resetReceiveCounts();
+
+ if ((mt_sec - mResendDumpTime) > CIRCUIT_DUMP_TIMEOUT)
+ {
+ mResendDumpTime = mt_sec;
+ mCircuitInfo.dumpResends();
+ }
+}
+
+void LLMessageSystem::copyMessageReceivedToSend()
+{
+ // NOTE: babbage: switch builder to match reader to avoid
+ // converting message format
+ if(mMessageReader == mTemplateMessageReader)
+ {
+ mMessageBuilder = mTemplateMessageBuilder;
+ }
+ else
+ {
+ mMessageBuilder = mLLSDMessageBuilder;
+ }
+ mSendReliable = false;
+ mMessageBuilder->newMessage(mMessageReader->getMessageName());
+ mMessageReader->copyToBuilder(*mMessageBuilder);
+}
+
+LLSD LLMessageSystem::getReceivedMessageLLSD() const
+{
+ LLSDMessageBuilder builder;
+ mMessageReader->copyToBuilder(builder);
+ return builder.getMessage();
+}
+
+LLSD LLMessageSystem::getBuiltMessageLLSD() const
+{
+ LLSD result;
+ if (mLLSDMessageBuilder == mMessageBuilder)
+ {
+ result = mLLSDMessageBuilder->getMessage();
+ }
+ else
+ {
+ // TODO: implement as below?
+ LL_ERRS() << "Message not built as LLSD." << LL_ENDL;
+ }
+ return result;
+}
+
+LLSD LLMessageSystem::wrapReceivedTemplateData() const
+{
+ if(mMessageReader == mTemplateMessageReader)
+ {
+ LLTemplateMessageBuilder builder(mMessageTemplates);
+ builder.newMessage(mMessageReader->getMessageName());
+ mMessageReader->copyToBuilder(builder);
+ U8 buffer[MAX_BUFFER_SIZE];
+ const U8 offset_to_data = 0;
+ U32 size = builder.buildMessage(buffer, MAX_BUFFER_SIZE,
+ offset_to_data);
+ std::vector<U8> binary_data(buffer, buffer+size);
+ LLSD wrapped_data = LLSD::emptyMap();
+ wrapped_data["binary-template-data"] = binary_data;
+ return wrapped_data;
+ }
+ else
+ {
+ return getReceivedMessageLLSD();
+ }
+}
+
+LLSD LLMessageSystem::wrapBuiltTemplateData() const
+{
+ LLSD result;
+ if (mLLSDMessageBuilder == mMessageBuilder)
+ {
+ result = getBuiltMessageLLSD();
+ }
+ else
+ {
+ U8 buffer[MAX_BUFFER_SIZE];
+ const U8 offset_to_data = 0;
+ U32 size = mTemplateMessageBuilder->buildMessage(
+ buffer, MAX_BUFFER_SIZE,
+ offset_to_data);
+ std::vector<U8> binary_data(buffer, buffer+size);
+ LLSD wrapped_data = LLSD::emptyMap();
+ wrapped_data["binary-template-data"] = binary_data;
+ result = wrapped_data;
+ }
+ return result;
+}
+
+LLStoredMessagePtr LLMessageSystem::getReceivedMessage() const
+{
+ const std::string& name = mMessageReader->getMessageName();
+ LLSD message = wrapReceivedTemplateData();
+
+ return LLStoredMessagePtr(new LLStoredMessage(name, message));
+}
+
+LLStoredMessagePtr LLMessageSystem::getBuiltMessage() const
+{
+ const std::string& name = mMessageBuilder->getMessageName();
+ LLSD message = wrapBuiltTemplateData();
+
+ return LLStoredMessagePtr(new LLStoredMessage(name, message));
+}
+
+S32 LLMessageSystem::sendMessage(const LLHost &host, LLStoredMessagePtr message)
+{
+ return sendMessage(host, message->mName.c_str(), message->mMessage);
+}
+
+
+void LLMessageSystem::clearMessage()
+{
+ mSendReliable = false;
+ mMessageBuilder->clearMessage();
+}
+
+// set block to add data to within current message
+void LLMessageSystem::nextBlockFast(const char *blockname)
+{
+ mMessageBuilder->nextBlock(blockname);
+}
+
+void LLMessageSystem::nextBlock(const char *blockname)
+{
+ nextBlockFast(LLMessageStringTable::getInstance()->getString(blockname));
+}
+
+bool LLMessageSystem::isSendFull(const char* blockname)
+{
+ char* stringTableName = NULL;
+ if(NULL != blockname)
+ {
+ stringTableName = LLMessageStringTable::getInstance()->getString(blockname);
+ }
+ return isSendFullFast(stringTableName);
+}
+
+bool LLMessageSystem::isSendFullFast(const char* blockname)
+{
+ return mMessageBuilder->isMessageFull(blockname);
+}
+
+
+// blow away the last block of a message, return false if that leaves no blocks or there wasn't a block to remove
+// TODO: Babbage: Remove this horror.
+bool LLMessageSystem::removeLastBlock()
+{
+ return mMessageBuilder->removeLastBlock();
+}
+
+S32 LLMessageSystem::sendReliable(const LLHost &host)
+{
+ return sendReliable(host, LL_DEFAULT_RELIABLE_RETRIES, true, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL);
+}
+
+
+S32 LLMessageSystem::sendSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data)
+{
+ F32Seconds timeout;
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS,
+ F32Seconds(LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()));
+ }
+ else
+ {
+ timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX;
+ }
+
+ constexpr S32 retries = 0;
+ constexpr bool ping_based_timeout = false;
+ return sendReliable(host, retries, ping_based_timeout, timeout, callback, callback_data);
+}
+
+// send the message via a UDP packet
+S32 LLMessageSystem::sendReliable( const LLHost &host,
+ S32 retries,
+ bool ping_based_timeout,
+ F32Seconds timeout,
+ void (*callback)(void **,S32),
+ void ** callback_data)
+{
+ if (ping_based_timeout)
+ {
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()));
+ }
+ else
+ {
+ timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX));
+ }
+ }
+
+ mSendReliable = true;
+ mReliablePacketParams.set(host, retries, ping_based_timeout, timeout,
+ callback, callback_data,
+ const_cast<char*>(mMessageBuilder->getMessageName()));
+ return sendMessage(host);
+}
+
+void LLMessageSystem::forwardMessage(const LLHost &host)
+{
+ copyMessageReceivedToSend();
+ sendMessage(host);
+}
+
+void LLMessageSystem::forwardReliable(const LLHost &host)
+{
+ copyMessageReceivedToSend();
+ sendReliable(host);
+}
+
+void LLMessageSystem::forwardReliable(const U32 circuit_code)
+{
+ copyMessageReceivedToSend();
+ sendReliable(findHost(circuit_code));
+}
+
+S32 LLMessageSystem::forwardReliable( const LLHost &host,
+ S32 retries,
+ bool ping_based_timeout,
+ F32Seconds timeout,
+ void (*callback)(void **,S32),
+ void ** callback_data)
+{
+ copyMessageReceivedToSend();
+ return sendReliable(host, retries, ping_based_timeout, timeout, callback, callback_data);
+}
+
+S32 LLMessageSystem::flushSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data)
+{
+ F32Seconds timeout;
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS,
+ F32Seconds(LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()));
+ }
+ else
+ {
+ timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX;
+ }
+
+ S32 send_bytes = 0;
+ if (mMessageBuilder->getMessageSize())
+ {
+ mSendReliable = true;
+ // No need for ping-based retry as not going to retry
+ mReliablePacketParams.set(host, 0, false, timeout, callback,
+ callback_data,
+ const_cast<char*>(mMessageBuilder->getMessageName()));
+ send_bytes = sendMessage(host);
+ clearMessage();
+ }
+ else
+ {
+ delete callback_data;
+ }
+ return send_bytes;
+}
+
+S32 LLMessageSystem::flushReliable(const LLHost &host)
+{
+ S32 send_bytes = 0;
+ if (mMessageBuilder->getMessageSize())
+ {
+ send_bytes = sendReliable(host);
+ }
+ clearMessage();
+ return send_bytes;
+}
+
+// This can be called from signal handlers,
+// so should should not use LL_INFOS().
+S32 LLMessageSystem::sendMessage(const LLHost &host)
+{
+ if (! mMessageBuilder->isBuilt())
+ {
+ mSendSize = mMessageBuilder->buildMessage(
+ mSendBuffer,
+ MAX_BUFFER_SIZE,
+ 0);
+ }
+
+ if (!(host.isOk())) // if port and ip are zero, don't bother trying to send the message
+ {
+ return 0;
+ }
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (!cdp)
+ {
+ // this is a new circuit!
+ // are we protected?
+ if (mbProtected)
+ {
+ // yup! don't send packets to an unknown circuit
+ if(mVerboseLog)
+ {
+ LL_INFOS_ONCE("Messaging") << "MSG: -> " << host << "\tUNKNOWN CIRCUIT:\t"
+ << mMessageBuilder->getMessageName() << LL_ENDL;
+ }
+ LL_WARNS_ONCE("Messaging") << "sendMessage - Trying to send "
+ << mMessageBuilder->getMessageName() << " on unknown circuit "
+ << host << LL_ENDL;
+ return 0;
+ }
+ else
+ {
+ // nope, open the new circuit
+
+ cdp = mCircuitInfo.addCircuitData(host, 0);
+ }
+ }
+ else
+ {
+ // this is an old circuit. . . is it still alive?
+ if (!cdp->isAlive())
+ {
+ // nope. don't send to dead circuits
+ if(mVerboseLog)
+ {
+ LL_INFOS("Messaging") << "MSG: -> " << host << "\tDEAD CIRCUIT\t\t"
+ << mMessageBuilder->getMessageName() << LL_ENDL;
+ }
+ LL_WARNS("Messaging") << "sendMessage - Trying to send message "
+ << mMessageBuilder->getMessageName() << " to dead circuit "
+ << host << LL_ENDL;
+ return 0;
+ }
+ }
+
+ // NOTE: babbage: LLSD message -> HTTP, template message -> UDP
+ if(mMessageBuilder == mLLSDMessageBuilder)
+ {
+ LLSD message = mLLSDMessageBuilder->getMessage();
+
+ UntrustedCallback_t cb = NULL;
+ if ((mSendReliable) && (mReliablePacketParams.mCallback))
+ {
+ cb = boost::bind(mReliablePacketParams.mCallback, mReliablePacketParams.mCallbackData, _1);
+ }
+
+ LLCoros::instance().launch("LLMessageSystem::sendUntrustedSimulatorMessageCoro",
+ boost::bind(&LLMessageSystem::sendUntrustedSimulatorMessageCoro, this,
+ host.getUntrustedSimulatorCap(),
+ mLLSDMessageBuilder->getMessageName(), message, cb));
+
+ mSendReliable = false;
+ mReliablePacketParams.clear();
+ return 1;
+ }
+
+ // zero out the flags and packetid. Subtract 1 here so that we do
+ // not overwrite the offset if it was set set in buildMessage().
+ memset(mSendBuffer, 0, LL_PACKET_ID_SIZE - 1);
+
+ // add the send id to the front of the message
+ cdp->nextPacketOutID();
+
+ // Packet ID size is always 4
+ *((S32*)&mSendBuffer[PHL_PACKET_ID]) = htonl(cdp->getPacketOutID());
+
+ // Compress the message, which will usually reduce its size.
+ U8 * buf_ptr = (U8 *)mSendBuffer;
+ U32 buffer_length = mSendSize;
+ mMessageBuilder->compressMessage(buf_ptr, buffer_length);
+
+ if (buffer_length > 1500)
+ {
+ if((mMessageBuilder->getMessageName() != _PREHASH_ChildAgentUpdate)
+ && (mMessageBuilder->getMessageName() != _PREHASH_SendXferPacket))
+ {
+ LL_WARNS("Messaging") << "sendMessage - Trying to send "
+ << ((buffer_length > 4000) ? "EXTRA " : "")
+ << "BIG message " << mMessageBuilder->getMessageName() << " - "
+ << buffer_length << LL_ENDL;
+ }
+ }
+ if (mSendReliable)
+ {
+ buf_ptr[0] |= LL_RELIABLE_FLAG;
+
+ if (!cdp->getUnackedPacketCount())
+ {
+ // We are adding the first packed onto the unacked packet list(s)
+ // Add this circuit to the list of circuits with unacked packets
+ mCircuitInfo.mUnackedCircuitMap[cdp->mHost] = cdp;
+ }
+
+ cdp->addReliablePacket(mSocket,buf_ptr,buffer_length, &mReliablePacketParams);
+ mReliablePacketsOut++;
+ }
+
+ // tack packet acks onto the end of this message
+ S32 space_left = (MTUBYTES - buffer_length) / sizeof(TPACKETID); // space left for packet ids
+ S32 ack_count = (S32)cdp->mAcks.size();
+ bool is_ack_appended = false;
+ std::vector<TPACKETID> acks;
+ if((space_left > 0) && (ack_count > 0) &&
+ (mMessageBuilder->getMessageName() != _PREHASH_PacketAck))
+ {
+ buf_ptr[0] |= LL_ACK_FLAG;
+ S32 append_ack_count = llmin(space_left, ack_count);
+ const S32 MAX_ACKS = 250;
+ append_ack_count = llmin(append_ack_count, MAX_ACKS);
+ std::vector<TPACKETID>::iterator iter = cdp->mAcks.begin();
+ std::vector<TPACKETID>::iterator last = cdp->mAcks.begin();
+ last += append_ack_count;
+ TPACKETID packet_id;
+ for( ; iter != last ; ++iter)
+ {
+ // grab the next packet id.
+ packet_id = (*iter);
+ if(mVerboseLog)
+ {
+ acks.push_back(packet_id);
+ }
+
+ // put it on the end of the buffer
+ packet_id = htonl(packet_id);
+
+ if((S32)(buffer_length + sizeof(TPACKETID)) < MAX_BUFFER_SIZE)
+ {
+ memcpy(&buf_ptr[buffer_length], &packet_id, sizeof(TPACKETID)); /* Flawfinder: ignore */
+ // Do the accounting
+ buffer_length += sizeof(TPACKETID);
+ }
+ else
+ {
+ // Just reporting error is likely not enough. Need to
+ // check how to abort or error out gracefully from
+ // this function. XXXTBD
+ // *NOTE: Actually hitting this error would indicate
+ // the calculation above for space_left, ack_count,
+ // append_acout_count is incorrect or that
+ // MAX_BUFFER_SIZE has fallen below MTU which is bad
+ // and probably programmer error.
+ LL_ERRS("Messaging") << "Buffer packing failed due to size.." << LL_ENDL;
+ }
+ }
+
+ // clean up the source
+ cdp->mAcks.erase(cdp->mAcks.begin(), last);
+
+ // tack the count in the final byte
+ U8 count = (U8)append_ack_count;
+ buf_ptr[buffer_length++] = count;
+ is_ack_appended = true;
+ }
+
+ bool success;
+ success = mPacketRing.sendPacket(mSocket, (char *)buf_ptr, buffer_length, host);
+
+ if (!success)
+ {
+ mSendPacketFailureCount++;
+ }
+ else
+ {
+ // mCircuitInfo already points to the correct circuit data
+ cdp->addBytesOut( (S32Bytes)buffer_length );
+ }
+
+ if(mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: -> " << host;
+ std::string buffer;
+ buffer = llformat( "\t%6d\t%6d\t%6d ", mSendSize, buffer_length, cdp->getPacketOutID());
+ str << buffer
+ << mMessageBuilder->getMessageName()
+ << (mSendReliable ? " reliable " : "");
+ if(is_ack_appended)
+ {
+ str << "\tACKS:\t";
+ std::ostream_iterator<TPACKETID> append(str, " ");
+ std::copy(acks.begin(), acks.end(), append);
+ }
+ LL_INFOS("Messaging") << str.str() << LL_ENDL;
+ }
+
+
+ mPacketsOut++;
+ mTotalBytesOut += buffer_length;
+
+ mSendReliable = false;
+ mReliablePacketParams.clear();
+ return buffer_length;
+}
+
+void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, bool recv_reliable )
+{
+ if(mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << host;
+ std::string buffer;
+ buffer = llformat( "\t%6d\t%6d\t%6d ", mMessageReader->getMessageSize(), (mIncomingCompressedSize ? mIncomingCompressedSize: mMessageReader->getMessageSize()), mCurrentRecvPacketID);
+ str << buffer
+ << nullToEmpty(mMessageReader->getMessageName())
+ << (recv_reliable ? " reliable" : "")
+ << " REJECTED";
+ LL_INFOS("Messaging") << str.str() << LL_ENDL;
+ }
+ // nope!
+ // cout << "Rejecting unexpected message " << mCurrentMessageTemplate->mName << " from " << hex << ip << " , " << dec << port << endl;
+
+ // Keep track of rejected messages as well
+ if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM)
+ {
+ LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << LL_ENDL;
+ }
+ else
+ {
+ // TODO: babbage: work out if we need these
+ // mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber;
+ mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize();
+ mMessageCountList[mNumMessageCounts].mInvalid = true;
+ mNumMessageCounts++;
+ }
+}
+
+S32 LLMessageSystem::sendMessage(
+ const LLHost &host,
+ const char* name,
+ const LLSD& message)
+{
+ if (!(host.isOk()))
+ {
+ LL_WARNS("Messaging") << "trying to send message to invalid host" << LL_ENDL;
+ return 0;
+ }
+
+ UntrustedCallback_t cb = NULL;
+ if ((mSendReliable) && (mReliablePacketParams.mCallback))
+ {
+ cb = boost::bind(mReliablePacketParams.mCallback, mReliablePacketParams.mCallbackData, _1);
+ }
+
+ LLCoros::instance().launch("LLMessageSystem::sendUntrustedSimulatorMessageCoro",
+ boost::bind(&LLMessageSystem::sendUntrustedSimulatorMessageCoro, this,
+ host.getUntrustedSimulatorCap(), name, message, cb));
+ return 1;
+}
+
+void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host )
+{
+ // RequestTrustedCircuit is how we establish trust, so don't spam
+ // if it's received on a trusted circuit. JC
+ if (strcmp(mMessageReader->getMessageName(), "RequestTrustedCircuit"))
+ {
+ LL_WARNS("Messaging") << "Received trusted message on untrusted circuit. "
+ << "Will reply with deny. "
+ << "Message: " << nullToEmpty(mMessageReader->getMessageName())
+ << " Host: " << host << LL_ENDL;
+ }
+
+ if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM)
+ {
+ LL_WARNS("Messaging") << "got more than " << MAX_MESSAGE_COUNT_NUM
+ << " packets without clearing counts"
+ << LL_ENDL;
+ }
+ else
+ {
+ // TODO: babbage: work out if we need these
+ //mMessageCountList[mNumMessageCounts].mMessageNum
+ // = mCurrentRMessageTemplate->mMessageNumber;
+ mMessageCountList[mNumMessageCounts].mMessageBytes
+ = mMessageReader->getMessageSize();
+ mMessageCountList[mNumMessageCounts].mInvalid = true;
+ mNumMessageCounts++;
+ }
+}
+
+void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, bool recv_reliable, bool recv_resent, bool recv_acks )
+{
+ if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM)
+ {
+ LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << LL_ENDL;
+ }
+ else
+ {
+ // TODO: babbage: work out if we need these
+ //mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber;
+ mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize();
+ mMessageCountList[mNumMessageCounts].mInvalid = false;
+ mNumMessageCounts++;
+ }
+
+ if (cdp)
+ {
+ // update circuit packet ID tracking (missing/out of order packets)
+ cdp->checkPacketInID( mCurrentRecvPacketID, recv_resent );
+ cdp->addBytesIn( (S32Bytes)mTrueReceiveSize );
+ }
+
+ if(mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << host;
+ std::string buffer;
+ buffer = llformat( "\t%6d\t%6d\t%6d ", mMessageReader->getMessageSize(), (mIncomingCompressedSize ? mIncomingCompressedSize : mMessageReader->getMessageSize()), mCurrentRecvPacketID);
+ str << buffer
+ << nullToEmpty(mMessageReader->getMessageName())
+ << (recv_reliable ? " reliable" : "")
+ << (recv_resent ? " resent" : "")
+ << (recv_acks ? " acks" : "");
+ LL_INFOS("Messaging") << str.str() << LL_ENDL;
+ }
+}
+
+void LLMessageSystem::sanityCheck()
+{
+// TODO: babbage: reinstate
+
+// if (!mCurrentRMessageData)
+// {
+// LL_ERRS("Messaging") << "mCurrentRMessageData is NULL" << LL_ENDL;
+// }
+
+// if (!mCurrentRMessageTemplate)
+// {
+// LL_ERRS("Messaging") << "mCurrentRMessageTemplate is NULL" << LL_ENDL;
+// }
+
+// if (!mCurrentRTemplateBlock)
+// {
+// LL_ERRS("Messaging") << "mCurrentRTemplateBlock is NULL" << LL_ENDL;
+// }
+
+// if (!mCurrentRDataBlock)
+// {
+// LL_ERRS("Messaging") << "mCurrentRDataBlock is NULL" << LL_ENDL;
+// }
+
+// if (!mCurrentSMessageData)
+// {
+// LL_ERRS("Messaging") << "mCurrentSMessageData is NULL" << LL_ENDL;
+// }
+
+// if (!mCurrentSMessageTemplate)
+// {
+// LL_ERRS("Messaging") << "mCurrentSMessageTemplate is NULL" << LL_ENDL;
+// }
+
+// if (!mCurrentSTemplateBlock)
+// {
+// LL_ERRS("Messaging") << "mCurrentSTemplateBlock is NULL" << LL_ENDL;
+// }
+
+// if (!mCurrentSDataBlock)
+// {
+// LL_ERRS("Messaging") << "mCurrentSDataBlock is NULL" << LL_ENDL;
+// }
+}
+
+void LLMessageSystem::showCircuitInfo()
+{
+ LL_INFOS("Messaging") << mCircuitInfo << LL_ENDL;
+}
+
+
+void LLMessageSystem::dumpCircuitInfo()
+{
+ LL_DEBUGS("Messaging") << mCircuitInfo << LL_ENDL;
+}
+
+/* virtual */
+U32 LLMessageSystem::getOurCircuitCode()
+{
+ return mOurCircuitCode;
+}
+
+void LLMessageSystem::getCircuitInfo(LLSD& info) const
+{
+ mCircuitInfo.getInfo(info);
+}
+
+// returns whether the given host is on a trusted circuit
+bool LLMessageSystem::getCircuitTrust(const LLHost &host)
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ return cdp->getTrusted();
+ }
+
+ return false;
+}
+
+// Activate a circuit, and set its trust level (true if trusted,
+// false if not).
+void LLMessageSystem::enableCircuit(const LLHost &host, bool trusted)
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (!cdp)
+ {
+ cdp = mCircuitInfo.addCircuitData(host, 0);
+ }
+ else
+ {
+ cdp->setAlive(true);
+ }
+ cdp->setTrusted(trusted);
+}
+
+void LLMessageSystem::disableCircuit(const LLHost &host)
+{
+ LL_INFOS("Messaging") << "LLMessageSystem::disableCircuit for " << host << LL_ENDL;
+ U32 code = gMessageSystem->findCircuitCode( host );
+
+ // Don't need to do this, as we're removing the circuit info anyway - djs 01/28/03
+
+ // don't clean up 0 circuit code entries
+ // because many hosts (neighbor sims, etc) can have the 0 circuit
+ if (code)
+ {
+ //if (mCircuitCodes.checkKey(code))
+ code_session_map_t::iterator it = mCircuitCodes.find(code);
+ if(it != mCircuitCodes.end())
+ {
+ LL_INFOS("Messaging") << "Circuit " << code << " removed from list" << LL_ENDL;
+ //mCircuitCodes.removeData(code);
+ mCircuitCodes.erase(it);
+ }
+
+ U64 ip_port = 0;
+ std::map<U32, U64>::iterator iter = gMessageSystem->mCircuitCodeToIPPort.find(code);
+ if (iter != gMessageSystem->mCircuitCodeToIPPort.end())
+ {
+ ip_port = iter->second;
+
+ gMessageSystem->mCircuitCodeToIPPort.erase(iter);
+
+ U32 old_port = (U32)(ip_port & (U64)0xFFFFFFFF);
+ U32 old_ip = (U32)(ip_port >> 32);
+
+ LL_INFOS("Messaging") << "Host " << LLHost(old_ip, old_port) << " circuit " << code << " removed from lookup table" << LL_ENDL;
+ gMessageSystem->mIPPortToCircuitCode.erase(ip_port);
+ }
+ mCircuitInfo.removeCircuitData(host);
+ }
+ else
+ {
+ // Sigh, since we can open circuits which don't have circuit
+ // codes, it's possible for this to happen...
+
+ LL_WARNS("Messaging") << "Couldn't find circuit code for " << host << LL_ENDL;
+ }
+
+}
+
+
+void LLMessageSystem::setCircuitAllowTimeout(const LLHost &host, bool allow)
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ cdp->setAllowTimeout(allow);
+ }
+}
+
+void LLMessageSystem::setCircuitTimeoutCallback(const LLHost &host, void (*callback_func)(const LLHost & host, void *user_data), void *user_data)
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ cdp->setTimeoutCallback(callback_func, user_data);
+ }
+}
+
+
+bool LLMessageSystem::checkCircuitBlocked(const U32 circuit)
+{
+ LLHost host = findHost(circuit);
+
+ if (!host.isOk())
+ {
+ LL_DEBUGS("Messaging") << "checkCircuitBlocked: Unknown circuit " << circuit << LL_ENDL;
+ return true;
+ }
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ return cdp->isBlocked();
+ }
+ else
+ {
+ LL_INFOS("Messaging") << "checkCircuitBlocked(circuit): Unknown host - " << host << LL_ENDL;
+ return false;
+ }
+}
+
+bool LLMessageSystem::checkCircuitAlive(const U32 circuit)
+{
+ LLHost host = findHost(circuit);
+
+ if (!host.isOk())
+ {
+ LL_DEBUGS("Messaging") << "checkCircuitAlive: Unknown circuit " << circuit << LL_ENDL;
+ return false;
+ }
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ return cdp->isAlive();
+ }
+ else
+ {
+ LL_INFOS("Messaging") << "checkCircuitAlive(circuit): Unknown host - " << host << LL_ENDL;
+ return false;
+ }
+}
+
+bool LLMessageSystem::checkCircuitAlive(const LLHost &host)
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ return cdp->isAlive();
+ }
+ else
+ {
+ LL_DEBUGS("Messaging") << "checkCircuitAlive(host): Unknown host - " << host << LL_ENDL;
+ return false;
+ }
+}
+
+
+void LLMessageSystem::setCircuitProtection(bool b_protect)
+{
+ mbProtected = b_protect;
+}
+
+
+U32 LLMessageSystem::findCircuitCode(const LLHost &host)
+{
+ U64 ip64 = (U64) host.getAddress();
+ U64 port64 = (U64) host.getPort();
+ U64 ip_port = (ip64 << 32) | port64;
+
+ return get_if_there(mIPPortToCircuitCode, ip_port, U32(0));
+}
+
+LLHost LLMessageSystem::findHost(const U32 circuit_code)
+{
+ if (mCircuitCodeToIPPort.count(circuit_code) > 0)
+ {
+ return LLHost(mCircuitCodeToIPPort[circuit_code]);
+ }
+ else
+ {
+ return LLHost();
+ }
+}
+
+void LLMessageSystem::setMaxMessageTime(const F32 seconds)
+{
+ mMaxMessageTime = F32Seconds(seconds);
+}
+
+void LLMessageSystem::setMaxMessageCounts(const S32 num)
+{
+ mMaxMessageCounts = num;
+}
+
+
+std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg)
+{
+ U32 i;
+ if (msg.mbError)
+ {
+ s << "Message system not correctly initialized";
+ }
+ else
+ {
+ s << "Message system open on port " << msg.mPort << " and socket " << msg.mSocket << "\n";
+// s << "Message template file " << msg.mName << " loaded\n";
+
+ s << "\nHigh frequency messages:\n";
+
+ for (i = 1; msg.mMessageNumbers[i] && (i < 255); i++)
+ {
+ s << *(msg.mMessageNumbers[i]);
+ }
+
+ s << "\nMedium frequency messages:\n";
+
+ for (i = (255 << 8) + 1; msg.mMessageNumbers[i] && (i < (255 << 8) + 255); i++)
+ {
+ s << *msg.mMessageNumbers[i];
+ }
+
+ s << "\nLow frequency messages:\n";
+
+ for (i = (0xFFFF0000) + 1; msg.mMessageNumbers[i] && (i < 0xFFFFFFFF); i++)
+ {
+ s << *msg.mMessageNumbers[i];
+ }
+ }
+ return s;
+}
+
+// LLPounceable supports callWhenReady(), to permit clients to queue up (e.g.)
+// callback registrations for when gMessageSystem is first assigned
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
+
+// update appropriate ping info
+void process_complete_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/)
+{
+ U8 ping_id;
+ msgsystem->getU8Fast(_PREHASH_PingID, _PREHASH_PingID, ping_id);
+
+ LLCircuitData *cdp;
+ cdp = msgsystem->mCircuitInfo.findCircuit(msgsystem->getSender());
+
+ // stop the appropriate timer
+ if (cdp)
+ {
+ cdp->pingTimerStop(ping_id);
+ }
+}
+
+void process_start_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/)
+{
+ U8 ping_id;
+ msgsystem->getU8Fast(_PREHASH_PingID, _PREHASH_PingID, ping_id);
+
+ LLCircuitData *cdp;
+ cdp = msgsystem->mCircuitInfo.findCircuit(msgsystem->getSender());
+ if (cdp)
+ {
+ // Grab the packet id of the oldest unacked packet
+ U32 packet_id;
+ msgsystem->getU32Fast(_PREHASH_PingID, _PREHASH_OldestUnacked, packet_id);
+ cdp->clearDuplicateList(packet_id);
+ }
+
+ // Send off the response
+ msgsystem->newMessageFast(_PREHASH_CompletePingCheck);
+ msgsystem->nextBlockFast(_PREHASH_PingID);
+ msgsystem->addU8(_PREHASH_PingID, ping_id);
+ msgsystem->sendMessage(msgsystem->getSender());
+}
+
+
+
+// Note: this is currently unused. --mark
+void open_circuit(LLMessageSystem *msgsystem, void** /*user_data*/)
+{
+ U32 ip;
+ U16 port;
+
+ msgsystem->getIPAddrFast(_PREHASH_CircuitInfo, _PREHASH_IP, ip);
+ msgsystem->getIPPortFast(_PREHASH_CircuitInfo, _PREHASH_Port, port);
+
+ // By default, OpenCircuit's are untrusted
+ msgsystem->enableCircuit(LLHost(ip, port), false);
+}
+
+void close_circuit(LLMessageSystem *msgsystem, void** /*user_data*/)
+{
+ msgsystem->disableCircuit(msgsystem->getSender());
+}
+
+// static
+/*
+void LLMessageSystem::processAssignCircuitCode(LLMessageSystem* msg, void**)
+{
+ // if we already have a circuit code, we can bail
+ if(msg->mOurCircuitCode) return;
+ LLUUID session_id;
+ msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id);
+ if(session_id != msg->getMySessionID())
+ {
+ LL_WARNS("Messaging") << "AssignCircuitCode, bad session id. Expecting "
+ << msg->getMySessionID() << " but got " << session_id
+ << LL_ENDL;
+ return;
+ }
+ U32 code;
+ msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, code);
+ if (!code)
+ {
+ LL_ERRS("Messaging") << "Assigning circuit code of zero!" << LL_ENDL;
+ }
+
+ msg->mOurCircuitCode = code;
+ LL_INFOS("Messaging") << "Circuit code " << code << " assigned." << LL_ENDL;
+}
+*/
+
+// static
+void LLMessageSystem::processAddCircuitCode(LLMessageSystem* msg, void**)
+{
+ U32 code;
+ msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, code);
+ LLUUID session_id;
+ msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id);
+ (void)msg->addCircuitCode(code, session_id);
+
+ // Send the ack back
+ //msg->newMessageFast(_PREHASH_AckAddCircuitCode);
+ //msg->nextBlockFast(_PREHASH_CircuitCode);
+ //msg->addU32Fast(_PREHASH_Code, code);
+ //msg->sendMessage(msg->getSender());
+}
+
+bool LLMessageSystem::addCircuitCode(U32 code, const LLUUID& session_id)
+{
+ if(!code)
+ {
+ LL_WARNS("Messaging") << "addCircuitCode: zero circuit code" << LL_ENDL;
+ return false;
+ }
+ code_session_map_t::iterator it = mCircuitCodes.find(code);
+ if(it == mCircuitCodes.end())
+ {
+ LL_INFOS("Messaging") << "New circuit code " << code << " added" << LL_ENDL;
+ //msg->mCircuitCodes[circuit_code] = circuit_code;
+
+ mCircuitCodes.insert(code_session_map_t::value_type(code, session_id));
+ }
+ else
+ {
+ LL_INFOS("Messaging") << "Duplicate circuit code " << code << " added" << LL_ENDL;
+ }
+ return true;
+}
+
+//void ack_add_circuit_code(LLMessageSystem *msgsystem, void** /*user_data*/)
+//{
+ // By default, we do nothing. This particular message is only handled by the spaceserver
+//}
+
+// static
+void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg,
+ void** user)
+{
+ U32 circuit_code_in;
+ msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, circuit_code_in);
+
+ U32 ip = msg->getSenderIP();
+ U32 port = msg->getSenderPort();
+
+ U64 ip64 = ip;
+ U64 port64 = port;
+ U64 ip_port_in = (ip64 << 32) | port64;
+
+ if (circuit_code_in)
+ {
+ //if (!msg->mCircuitCodes.checkKey(circuit_code_in))
+ code_session_map_t::iterator it;
+ it = msg->mCircuitCodes.find(circuit_code_in);
+ if(it == msg->mCircuitCodes.end())
+ {
+ // Whoah, abort! We don't know anything about this circuit code.
+ LL_WARNS("Messaging") << "UseCircuitCode for " << circuit_code_in
+ << " received without AddCircuitCode message - aborting"
+ << LL_ENDL;
+ return;
+ }
+
+ LLUUID id;
+ msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_ID, id);
+ LLUUID session_id;
+ msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id);
+ if(session_id != (*it).second)
+ {
+ LL_WARNS("Messaging") << "UseCircuitCode unmatched session id. Got "
+ << session_id << " but expected " << (*it).second
+ << LL_ENDL;
+ return;
+ }
+
+ // Clean up previous references to this ip/port or circuit
+ U64 ip_port_old = get_if_there(msg->mCircuitCodeToIPPort, circuit_code_in, U64(0));
+ U32 circuit_code_old = get_if_there(msg->mIPPortToCircuitCode, ip_port_in, U32(0));
+
+ if (ip_port_old)
+ {
+ if ((ip_port_old == ip_port_in) && (circuit_code_old == circuit_code_in))
+ {
+ // Current information is the same as incoming info, ignore
+ LL_INFOS("Messaging") << "Got duplicate UseCircuitCode for circuit " << circuit_code_in << " to " << msg->getSender() << LL_ENDL;
+ return;
+ }
+
+ // Hmm, got a different IP and port for the same circuit code.
+ U32 circut_code_old_ip_port = get_if_there(msg->mIPPortToCircuitCode, ip_port_old, U32(0));
+ msg->mCircuitCodeToIPPort.erase(circut_code_old_ip_port);
+ msg->mIPPortToCircuitCode.erase(ip_port_old);
+ U32 old_port = (U32)(ip_port_old & (U64)0xFFFFFFFF);
+ U32 old_ip = (U32)(ip_port_old >> 32);
+ LL_INFOS("Messaging") << "Removing derelict lookup entry for circuit " << circuit_code_old << " to " << LLHost(old_ip, old_port) << LL_ENDL;
+ }
+
+ if (circuit_code_old)
+ {
+ LLHost cur_host(ip, port);
+
+ LL_WARNS("Messaging") << "Disabling existing circuit for " << cur_host << LL_ENDL;
+ msg->disableCircuit(cur_host);
+ if (circuit_code_old == circuit_code_in)
+ {
+ LL_WARNS("Messaging") << "Asymmetrical circuit to ip/port lookup!" << LL_ENDL;
+ LL_WARNS("Messaging") << "Multiple circuit codes for " << cur_host << " probably!" << LL_ENDL;
+ LL_WARNS("Messaging") << "Permanently disabling circuit" << LL_ENDL;
+ return;
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Circuit code changed for " << msg->getSender()
+ << " from " << circuit_code_old << " to "
+ << circuit_code_in << LL_ENDL;
+ }
+ }
+
+ // Since this comes from the viewer, it's untrusted, but it
+ // passed the circuit code and session id check, so we will go
+ // ahead and persist the ID associated.
+ LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
+ bool had_circuit_already = cdp != nullptr;
+
+ msg->enableCircuit(msg->getSender(), false);
+ cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
+ if(cdp)
+ {
+ cdp->setRemoteID(id);
+ cdp->setRemoteSessionID(session_id);
+ }
+
+ if (!had_circuit_already)
+ {
+ //
+ // HACK HACK HACK HACK HACK!
+ //
+ // This would NORMALLY happen inside logValidMsg, but at the point that this happens
+ // inside logValidMsg, there's no circuit for this message yet. So the awful thing that
+ // we do here is do it inside this message handler immediately AFTER the message is
+ // handled.
+ //
+ // We COULD not do this, but then what happens is that some of the circuit bookkeeping
+ // gets broken, especially the packets in count. That causes some later packets to flush
+ // the RecentlyReceivedReliable list, resulting in an error in which UseCircuitCode
+ // doesn't get properly duplicate suppressed. Not a BIG deal, but it's somewhat confusing
+ // (and bad from a state point of view). DJS 9/23/04
+ //
+ cdp->checkPacketInID(gMessageSystem->mCurrentRecvPacketID, false ); // Since this is the first message on the circuit, by definition it's not resent.
+ }
+
+ msg->mIPPortToCircuitCode[ip_port_in] = circuit_code_in;
+ msg->mCircuitCodeToIPPort[circuit_code_in] = ip_port_in;
+
+ LL_INFOS("Messaging") << "Circuit code " << circuit_code_in << " from "
+ << msg->getSender() << " for agent " << id << " in session "
+ << session_id << LL_ENDL;
+
+ const LLUseCircuitCodeResponder* responder =
+ (const LLUseCircuitCodeResponder*) user;
+ if(responder)
+ {
+ responder->complete(msg->getSender(), id);
+ }
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Got zero circuit code in use_circuit_code" << LL_ENDL;
+ }
+}
+
+// static
+void LLMessageSystem::processError(LLMessageSystem* msg, void**)
+{
+ S32 error_code = 0;
+ msg->getS32("Data", "Code", error_code);
+ std::string error_token;
+ msg->getString("Data", "Token", error_token);
+
+ LLUUID error_id;
+ msg->getUUID("Data", "ID", error_id);
+ std::string error_system;
+ msg->getString("Data", "System", error_system);
+
+ std::string error_message;
+ msg->getString("Data", "Message", error_message);
+
+ LL_WARNS("Messaging") << "Message error from " << msg->getSender() << " - "
+ << error_code << " " << error_token << " " << error_id << " \""
+ << error_system << "\" \"" << error_message << "\"" << LL_ENDL;
+}
+
+
+static LLHTTPNode& messageRootNode()
+{
+ static LLHTTPNode root_node;
+ static bool initialized = false;
+ if (!initialized) {
+ initialized = true;
+ LLHTTPRegistrar::buildAllServices(root_node);
+ }
+
+ return root_node;
+}
+
+//static
+void LLMessageSystem::dispatch(
+ const std::string& msg_name,
+ const LLSD& message)
+{
+ LLPointer<LLSimpleResponse> responsep = LLSimpleResponse::create();
+ dispatch(msg_name, message, responsep);
+}
+
+//static
+void LLMessageSystem::dispatch(
+ const std::string& msg_name,
+ const LLSD& message,
+ LLHTTPNode::ResponsePtr responsep)
+{
+ if ((gMessageSystem->mMessageTemplates.find
+ (LLMessageStringTable::getInstance()->getString(msg_name.c_str())) ==
+ gMessageSystem->mMessageTemplates.end()) &&
+ !LLMessageConfig::isValidMessage(msg_name))
+ {
+ LL_WARNS("Messaging") << "Ignoring unknown message " << msg_name << LL_ENDL;
+ responsep->notFound("Invalid message name");
+ return;
+ }
+
+ std::string path = "/message/" + msg_name;
+ LLSD context;
+ const LLHTTPNode* handler = messageRootNode().traverse(path, context);
+ if (!handler)
+ {
+ LL_WARNS("Messaging") << "LLMessageService::dispatch > no handler for "
+ << path << LL_ENDL;
+ return;
+ }
+ // enable this for output of message names
+ LL_DEBUGS("Messaging") << "< \"" << msg_name << "\"" << LL_ENDL;
+ LL_DEBUGS("Messaging") << "context: " << context << LL_ENDL;
+ LL_DEBUGS("Messaging") << "message: " << message << LL_ENDL;
+
+ handler->post(responsep, context, message);
+}
+
+//static
+void LLMessageSystem::dispatchTemplate(const std::string& msg_name,
+ const LLSD& message,
+ LLHTTPNode::ResponsePtr responsep)
+{
+ LLTemplateMessageDispatcher dispatcher(*(gMessageSystem->mTemplateMessageReader));
+ dispatcher.dispatch(msg_name, message, responsep);
+}
+
+static void check_for_unrecognized_messages(
+ const char* type,
+ const LLSD& map,
+ LLMessageSystem::message_template_name_map_t& templates)
+{
+ for (LLSD::map_const_iterator iter = map.beginMap(),
+ end = map.endMap();
+ iter != end; ++iter)
+ {
+ const char* name = LLMessageStringTable::getInstance()->getString(iter->first.c_str());
+
+ if (templates.find(name) == templates.end())
+ {
+ LL_INFOS("AppInit") << " " << type
+ << " ban list contains unrecognized message "
+ << name << LL_ENDL;
+ }
+ }
+}
+
+void LLMessageSystem::setMessageBans(
+ const LLSD& trusted, const LLSD& untrusted)
+{
+ LL_DEBUGS("AppInit") << "LLMessageSystem::setMessageBans:" << LL_ENDL;
+ bool any_set = false;
+
+ for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(),
+ end = mMessageTemplates.end();
+ iter != end; ++iter)
+ {
+ LLMessageTemplate* mt = iter->second;
+
+ std::string name(mt->mName);
+ bool ban_from_trusted
+ = trusted.has(name) && trusted.get(name).asBoolean();
+ bool ban_from_untrusted
+ = untrusted.has(name) && untrusted.get(name).asBoolean();
+
+ mt->mBanFromTrusted = ban_from_trusted;
+ mt->mBanFromUntrusted = ban_from_untrusted;
+
+ if (ban_from_trusted || ban_from_untrusted)
+ {
+ LL_INFOS("AppInit") << " " << name << " banned from "
+ << (ban_from_trusted ? "TRUSTED " : " ")
+ << (ban_from_untrusted ? "UNTRUSTED " : " ")
+ << LL_ENDL;
+ any_set = true;
+ }
+ }
+
+ if (!any_set)
+ {
+ LL_DEBUGS("AppInit") << " no messages banned" << LL_ENDL;
+ }
+
+ check_for_unrecognized_messages("trusted", trusted, mMessageTemplates);
+ check_for_unrecognized_messages("untrusted", untrusted, mMessageTemplates);
+}
+
+S32 LLMessageSystem::sendError(
+ const LLHost& host,
+ const LLUUID& agent_id,
+ S32 code,
+ const std::string& token,
+ const LLUUID& id,
+ const std::string& system,
+ const std::string& message,
+ const LLSD& data)
+{
+ newMessage("Error");
+ nextBlockFast(_PREHASH_AgentData);
+ addUUIDFast(_PREHASH_AgentID, agent_id);
+ nextBlockFast(_PREHASH_Data);
+ addS32("Code", code);
+ addString("Token", token);
+ addUUID("ID", id);
+ addString("System", system);
+ std::string temp;
+ temp = message;
+ if(temp.size() > (size_t)MTUBYTES) temp.resize((size_t)MTUBYTES);
+ addString("Message", message);
+ LLPointer<LLSDBinaryFormatter> formatter = new LLSDBinaryFormatter;
+ std::ostringstream ostr;
+ formatter->format(data, ostr);
+ temp = ostr.str();
+ bool pack_data = true;
+ static const std::string ERROR_MESSAGE_NAME("Error");
+ if (LLMessageConfig::getMessageFlavor(ERROR_MESSAGE_NAME) ==
+ LLMessageConfig::TEMPLATE_FLAVOR)
+ {
+ S32 msg_size = temp.size() + mMessageBuilder->getMessageSize();
+ if(msg_size >= ETHERNET_MTU_BYTES)
+ {
+ pack_data = false;
+ }
+ }
+ if(pack_data)
+ {
+ addBinaryData("Data", (void*)temp.c_str(), temp.size());
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Data and message were too large -- data removed."
+ << LL_ENDL;
+ addBinaryData("Data", NULL, 0);
+ }
+ return sendReliable(host);
+}
+
+void process_packet_ack(LLMessageSystem *msgsystem, void** /*user_data*/)
+{
+ TPACKETID packet_id;
+
+ LLHost host = msgsystem->getSender();
+ LLCircuitData *cdp = msgsystem->mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+
+ S32 ack_count = msgsystem->getNumberOfBlocksFast(_PREHASH_Packets);
+
+ for (S32 i = 0; i < ack_count; i++)
+ {
+ msgsystem->getU32Fast(_PREHASH_Packets, _PREHASH_ID, packet_id, i);
+// LL_DEBUGS("Messaging") << "ack recvd' from " << host << " for packet " << (TPACKETID)packet_id << LL_ENDL;
+ cdp->ackReliablePacket(packet_id);
+ }
+ if (!cdp->getUnackedPacketCount())
+ {
+ // Remove this circuit from the list of circuits with unacked packets
+ gMessageSystem->mCircuitInfo.mUnackedCircuitMap.erase(host);
+ }
+ }
+}
+
+
+/*
+void process_log_messages(LLMessageSystem* msg, void**)
+{
+ U8 log_message;
+
+ msg->getU8Fast(_PREHASH_Options, _PREHASH_Enable, log_message);
+
+ if (log_message)
+ {
+ LL_INFOS("Messaging") << "Starting logging via message" << LL_ENDL;
+ msg->startLogging();
+ }
+ else
+ {
+ LL_INFOS("Messaging") << "Stopping logging via message" << LL_ENDL;
+ msg->stopLogging();
+ }
+}*/
+
+// Make circuit trusted if the MD5 Digest matches, otherwise
+// notify remote end that they are not trusted.
+void process_create_trusted_circuit(LLMessageSystem *msg, void **)
+{
+ // don't try to create trust on machines with no shared secret
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty()) return;
+
+ LLUUID remote_id;
+ msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_EndPointID, remote_id);
+
+ LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
+ if (!cdp)
+ {
+ LL_WARNS("Messaging") << "Attempt to create trusted circuit without circuit data: "
+ << msg->getSender() << LL_ENDL;
+ return;
+ }
+
+ LLUUID local_id;
+ local_id = cdp->getLocalEndPointID();
+ if (remote_id == local_id)
+ {
+ // Don't respond to requests that use the same end point ID
+ return;
+ }
+
+ U32 untrusted_interface = msg->getUntrustedInterface().getAddress();
+ U32 last_interface = msg->getReceivingInterface().getAddress();
+ if ( ( untrusted_interface != INVALID_HOST_IP_ADDRESS ) && ( untrusted_interface == last_interface ) )
+ {
+ if( msg->getBlockUntrustedInterface() )
+ {
+ LL_WARNS("Messaging") << "Ignoring CreateTrustedCircuit on public interface from host: "
+ << msg->getSender() << LL_ENDL;
+ return;
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Processing CreateTrustedCircuit on public interface from host: "
+ << msg->getSender() << LL_ENDL;
+ }
+ }
+
+ char their_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
+ S32 size = msg->getSizeFast(_PREHASH_DataBlock, _PREHASH_Digest);
+ if(size != MD5HEX_STR_BYTES)
+ {
+ // ignore requests which pack the wrong amount of data.
+ return;
+ }
+ msg->getBinaryDataFast(_PREHASH_DataBlock, _PREHASH_Digest, their_digest, MD5HEX_STR_BYTES);
+ their_digest[MD5HEX_STR_SIZE - 1] = '\0';
+ if(msg->isMatchingDigestForWindowAndUUIDs(their_digest, TRUST_TIME_WINDOW, local_id, remote_id))
+ {
+ cdp->setTrusted(true);
+ LL_INFOS("Messaging") << "Trusted digest from " << msg->getSender() << LL_ENDL;
+ return;
+ }
+ else if (cdp->getTrusted())
+ {
+ // The digest is bad, but this circuit is already trusted.
+ // This means that this could just be the result of a stale deny sent from a while back, and
+ // the message system is being slow. Don't bother sending the deny, as it may continually
+ // ping-pong back and forth on a very hosed circuit.
+ LL_WARNS("Messaging") << "Ignoring bad digest from known trusted circuit: " << their_digest
+ << " host: " << msg->getSender() << LL_ENDL;
+ return;
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Bad digest from known circuit: " << their_digest
+ << " host: " << msg->getSender() << LL_ENDL;
+ msg->sendDenyTrustedCircuit(msg->getSender());
+ return;
+ }
+}
+
+void process_deny_trusted_circuit(LLMessageSystem *msg, void **)
+{
+ // don't try to create trust on machines with no shared secret
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty()) return;
+
+ LLUUID remote_id;
+ msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_EndPointID, remote_id);
+
+ LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
+ if (!cdp)
+ {
+ return;
+ }
+
+ LLUUID local_id;
+ local_id = cdp->getLocalEndPointID();
+ if (remote_id == local_id)
+ {
+ // Don't respond to requests that use the same end point ID
+ return;
+ }
+
+ U32 untrusted_interface = msg->getUntrustedInterface().getAddress();
+ U32 last_interface = msg->getReceivingInterface().getAddress();
+ if ( ( untrusted_interface != INVALID_HOST_IP_ADDRESS ) && ( untrusted_interface == last_interface ) )
+ {
+ if( msg->getBlockUntrustedInterface() )
+ {
+ LL_WARNS("Messaging") << "Ignoring DenyTrustedCircuit on public interface from host: "
+ << msg->getSender() << LL_ENDL;
+ return;
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Processing DenyTrustedCircuit on public interface from host: "
+ << msg->getSender() << LL_ENDL;
+ }
+ }
+
+
+ // Assume that we require trust to proceed, so resend.
+ // This catches the case where a circuit that was trusted
+ // times out, and allows us to re-establish it, but does
+ // mean that if our shared_secret or clock is wrong, we'll
+ // spin.
+ // *TODO: probably should keep a count of number of resends
+ // per circuit, and stop resending after a while.
+ LL_INFOS("Messaging") << "Got DenyTrustedCircuit. Sending CreateTrustedCircuit to "
+ << msg->getSender() << LL_ENDL;
+ msg->sendCreateTrustedCircuit(msg->getSender(), local_id, remote_id);
+}
+
+
+void dump_prehash_files()
+{
+ U32 i;
+ std::string filename("../../indra/llmessage/message_prehash.h");
+ LLFILE* fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */
+ if (fp)
+ {
+ fprintf(
+ fp,
+ "/**\n"
+ " * @file message_prehash.h\n"
+ " * @brief header file of externs of prehashed variables plus defines.\n"
+ " *\n"
+ " * $LicenseInfo:firstyear=2003&license=viewerlgpl$"
+ " * $/LicenseInfo$"
+ " */\n\n"
+ "#ifndef LL_MESSAGE_PREHASH_H\n#define LL_MESSAGE_PREHASH_H\n\n");
+ fprintf(
+ fp,
+ "/**\n"
+ " * Generated from message template version number %.3f\n"
+ " */\n",
+ gMessageSystem->mMessageFileVersionNumber);
+ fprintf(fp, "\n\nextern F32 const gPrehashVersionNumber;\n\n");
+ for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
+ {
+ if (!LLMessageStringTable::getInstance()->mEmpty[i] && LLMessageStringTable::getInstance()->mString[i][0] != '.')
+ {
+ fprintf(fp, "extern char const* const _PREHASH_%s;\n", LLMessageStringTable::getInstance()->mString[i]);
+ }
+ }
+ fprintf(fp, "\n\n#endif\n");
+ fclose(fp);
+ }
+ filename = std::string("../../indra/llmessage/message_prehash.cpp");
+ fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */
+ if (fp)
+ {
+ fprintf(
+ fp,
+ "/**\n"
+ " * @file message_prehash.cpp\n"
+ " * @brief file of prehashed variables\n"
+ " *\n"
+ " * $LicenseInfo:firstyear=2003&license=viewerlgpl$"
+ " * $/LicenseInfo$"
+ " */\n\n"
+ "/**\n"
+ " * Generated from message template version number %.3f\n"
+ " */\n",
+ gMessageSystem->mMessageFileVersionNumber);
+ fprintf(fp, "#include \"linden_common.h\"\n");
+ fprintf(fp, "#include \"message.h\"\n\n");
+ fprintf(fp, "\n\nF32 const gPrehashVersionNumber = %.3ff;\n\n", gMessageSystem->mMessageFileVersionNumber);
+ for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
+ {
+ if (!LLMessageStringTable::getInstance()->mEmpty[i] && LLMessageStringTable::getInstance()->mString[i][0] != '.')
+ {
+ fprintf(fp, "char const* const _PREHASH_%s = LLMessageStringTable::getInstance()->getString(\"%s\");\n", LLMessageStringTable::getInstance()->mString[i], LLMessageStringTable::getInstance()->mString[i]);
+ }
+ }
+ fclose(fp);
+ }
+}
+
+bool start_messaging_system(
+ const std::string& template_name,
+ U32 port,
+ S32 version_major,
+ S32 version_minor,
+ S32 version_patch,
+ bool b_dump_prehash_file,
+ const std::string& secret,
+ const LLUseCircuitCodeResponder* responder,
+ bool failure_is_fatal,
+ const F32 circuit_heartbeat_interval,
+ const F32 circuit_timeout)
+{
+ gMessageSystem = new LLMessageSystem(
+ template_name,
+ port,
+ version_major,
+ version_minor,
+ version_patch,
+ failure_is_fatal,
+ circuit_heartbeat_interval,
+ circuit_timeout);
+ g_shared_secret.assign(secret);
+
+ if (!gMessageSystem)
+ {
+ LL_ERRS("AppInit") << "Messaging system initialization failed." << LL_ENDL;
+ return false;
+ }
+
+ // bail if system encountered an error.
+ if(!gMessageSystem->isOK())
+ {
+ return false;
+ }
+
+ if (b_dump_prehash_file)
+ {
+ dump_prehash_files();
+ exit(0);
+ }
+ else
+ {
+ if (gMessageSystem->mMessageFileVersionNumber != gPrehashVersionNumber)
+ {
+ LL_INFOS("AppInit") << "Message template version does not match prehash version number" << LL_ENDL;
+ LL_INFOS("AppInit") << "Run simulator with -prehash command line option to rebuild prehash data" << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("AppInit") << "Message template version matches prehash version number" << LL_ENDL;
+ }
+ }
+
+ gMessageSystem->setHandlerFuncFast(_PREHASH_StartPingCheck, process_start_ping_check, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_CompletePingCheck, process_complete_ping_check, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_OpenCircuit, open_circuit, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_CloseCircuit, close_circuit, NULL);
+
+ //gMessageSystem->setHandlerFuncFast(_PREHASH_AssignCircuitCode, LLMessageSystem::processAssignCircuitCode);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_AddCircuitCode, LLMessageSystem::processAddCircuitCode);
+ //gMessageSystem->setHandlerFuncFast(_PREHASH_AckAddCircuitCode, ack_add_circuit_code, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_UseCircuitCode, LLMessageSystem::processUseCircuitCode, (void**)responder);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_PacketAck, process_packet_ack, NULL);
+ //gMessageSystem->setHandlerFuncFast(_PREHASH_LogMessages, process_log_messages, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_CreateTrustedCircuit,
+ process_create_trusted_circuit,
+ NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_DenyTrustedCircuit,
+ process_deny_trusted_circuit,
+ NULL);
+ gMessageSystem->setHandlerFunc("Error", LLMessageSystem::processError);
+
+ // We can hand this to the null_message_callback since it is a
+ // trusted message, so it will automatically be denied if it isn't
+ // trusted and ignored if it is -- exactly what we want.
+ gMessageSystem->setHandlerFunc(
+ "RequestTrustedCircuit",
+ null_message_callback,
+ NULL);
+
+ // Initialize the transfer manager
+ gTransferManager.init();
+
+ return true;
+}
+
+void LLMessageSystem::startLogging()
+{
+ mVerboseLog = true;
+ std::ostringstream str;
+ str << "START MESSAGE LOG" << std::endl;
+ str << "Legend:" << std::endl;
+ str << "\t<-\tincoming message" <<std::endl;
+ str << "\t->\toutgoing message" << std::endl;
+ str << " <> host size zero id name";
+ LL_INFOS("Messaging") << str.str() << LL_ENDL;
+}
+
+void LLMessageSystem::stopLogging()
+{
+ if(mVerboseLog)
+ {
+ mVerboseLog = false;
+ LL_INFOS("Messaging") << "END MESSAGE LOG" << LL_ENDL;
+ }
+}
+
+void LLMessageSystem::summarizeLogs(std::ostream& str)
+{
+ std::string buffer;
+ std::string tmp_str;
+ F32 run_time = mMessageSystemTimer.getElapsedTimeF32();
+ str << "START MESSAGE LOG SUMMARY" << std::endl;
+ buffer = llformat( "Run time: %12.3f seconds", run_time);
+
+ // Incoming
+ str << buffer << std::endl << "Incoming:" << std::endl;
+ tmp_str = U64_to_str(mTotalBytesIn);
+ buffer = llformat( "Total bytes received: %20s (%5.2f kbits per second)", tmp_str.c_str(), ((F32)mTotalBytesIn * 0.008f) / run_time);
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(mPacketsIn);
+ buffer = llformat( "Total packets received: %20s (%5.2f packets per second)", tmp_str.c_str(), ((F32) mPacketsIn / run_time));
+ str << buffer << std::endl;
+ buffer = llformat( "Average packet size: %20.0f bytes", (F32)mTotalBytesIn / (F32)mPacketsIn);
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(mReliablePacketsIn);
+ buffer = llformat( "Total reliable packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mReliablePacketsIn)/((F32) mPacketsIn + 1));
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(mCompressedPacketsIn);
+ buffer = llformat( "Total compressed packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mCompressedPacketsIn)/((F32) mPacketsIn + 1));
+ str << buffer << std::endl;
+ S64 savings = mUncompressedBytesIn - mCompressedBytesIn;
+ tmp_str = U64_to_str(savings);
+ buffer = llformat( "Total compression savings: %20s bytes", tmp_str.c_str());
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(savings/(mCompressedPacketsIn +1));
+ buffer = llformat( "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mUncompressedBytesIn)/((F32) mCompressedBytesIn+1));
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(savings/(mPacketsIn+1));
+ buffer = llformat( "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mTotalBytesIn + (F32) savings)/((F32) mTotalBytesIn + 1.f));
+
+ // Outgoing
+ str << buffer << std::endl << std::endl << "Outgoing:" << std::endl;
+ tmp_str = U64_to_str(mTotalBytesOut);
+ buffer = llformat( "Total bytes sent: %20s (%5.2f kbits per second)", tmp_str.c_str(), ((F32)mTotalBytesOut * 0.008f) / run_time );
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(mPacketsOut);
+ buffer = llformat( "Total packets sent: %20s (%5.2f packets per second)", tmp_str.c_str(), ((F32)mPacketsOut / run_time));
+ str << buffer << std::endl;
+ buffer = llformat( "Average packet size: %20.0f bytes", (F32)mTotalBytesOut / (F32)mPacketsOut);
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(mReliablePacketsOut);
+ buffer = llformat( "Total reliable packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mReliablePacketsOut)/((F32) mPacketsOut + 1));
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(mCompressedPacketsOut);
+ buffer = llformat( "Total compressed packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mCompressedPacketsOut)/((F32) mPacketsOut + 1));
+ str << buffer << std::endl;
+ savings = mUncompressedBytesOut - mCompressedBytesOut;
+ tmp_str = U64_to_str(savings);
+ buffer = llformat( "Total compression savings: %20s bytes", tmp_str.c_str());
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(savings/(mCompressedPacketsOut +1));
+ buffer = llformat( "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mUncompressedBytesOut)/((F32) mCompressedBytesOut+1));
+ str << buffer << std::endl;
+ tmp_str = U64_to_str(savings/(mPacketsOut+1));
+ buffer = llformat( "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mTotalBytesOut + (F32) savings)/((F32) mTotalBytesOut + 1.f));
+ str << buffer << std::endl << std::endl;
+ buffer = llformat( "SendPacket failures: %20d", mSendPacketFailureCount);
+ str << buffer << std::endl;
+ buffer = llformat( "Dropped packets: %20d", mDroppedPackets);
+ str << buffer << std::endl;
+ buffer = llformat( "Resent packets: %20d", mResentPackets);
+ str << buffer << std::endl;
+ buffer = llformat( "Failed reliable resends: %20d", mFailedResendPackets);
+ str << buffer << std::endl;
+ buffer = llformat( "Off-circuit rejected packets: %17d", mOffCircuitPackets);
+ str << buffer << std::endl;
+ buffer = llformat( "On-circuit invalid packets: %17d", mInvalidOnCircuitPackets);
+ str << buffer << std::endl << std::endl;
+
+ str << "Decoding: " << std::endl;
+ buffer = llformat( "%35s%10s%10s%10s%10s", "Message", "Count", "Time", "Max", "Avg");
+ str << buffer << std:: endl;
+ F32 avg;
+ for (message_template_name_map_t::const_iterator iter = mMessageTemplates.begin(),
+ end = mMessageTemplates.end();
+ iter != end; iter++)
+ {
+ const LLMessageTemplate* mt = iter->second;
+ if(mt->mTotalDecoded > 0)
+ {
+ avg = mt->mTotalDecodeTime / (F32)mt->mTotalDecoded;
+ buffer = llformat( "%35s%10u%10f%10f%10f", mt->mName, mt->mTotalDecoded, mt->mTotalDecodeTime, mt->mMaxDecodeTimePerMsg, avg);
+ str << buffer << std::endl;
+ }
+ }
+ str << "END MESSAGE LOG SUMMARY" << std::endl;
+}
+
+void end_messaging_system(bool print_summary)
+{
+ gTransferManager.cleanup();
+ LLTransferTargetVFile::updateQueue(true); // shutdown LLTransferTargetVFile
+ if (gMessageSystem)
+ {
+ gMessageSystem->stopLogging();
+
+ if (print_summary)
+ {
+ std::ostringstream str;
+ gMessageSystem->summarizeLogs(str);
+ LL_INFOS("Messaging") << str.str().c_str() << LL_ENDL;
+ }
+
+ delete static_cast<LLMessageSystem*>(gMessageSystem);
+ gMessageSystem = NULL;
+ }
+}
+
+void LLMessageSystem::resetReceiveCounts()
+{
+ mNumMessageCounts = 0;
+
+ for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(),
+ end = mMessageTemplates.end();
+ iter != end; iter++)
+ {
+ LLMessageTemplate* mt = iter->second;
+ mt->mDecodeTimeThisFrame = 0.f;
+ }
+}
+
+
+void LLMessageSystem::dumpReceiveCounts()
+{
+ LLMessageTemplate *mt;
+
+ for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(),
+ end = mMessageTemplates.end();
+ iter != end; iter++)
+ {
+ LLMessageTemplate* mt = iter->second;
+ mt->mReceiveCount = 0;
+ mt->mReceiveBytes = 0;
+ mt->mReceiveInvalid = 0;
+ }
+
+ S32 i;
+ for (i = 0; i < mNumMessageCounts; i++)
+ {
+ mt = get_ptr_in_map(mMessageNumbers,mMessageCountList[i].mMessageNum);
+ if (mt)
+ {
+ mt->mReceiveCount++;
+ mt->mReceiveBytes += mMessageCountList[i].mMessageBytes;
+ if (mMessageCountList[i].mInvalid)
+ {
+ mt->mReceiveInvalid++;
+ }
+ }
+ }
+
+ if(mNumMessageCounts > 0)
+ {
+ LL_DEBUGS("Messaging") << "Dump: " << mNumMessageCounts << " messages processed in " << mReceiveTime << " seconds" << LL_ENDL;
+ for (message_template_name_map_t::const_iterator iter = mMessageTemplates.begin(),
+ end = mMessageTemplates.end();
+ iter != end; iter++)
+ {
+ const LLMessageTemplate* mt = iter->second;
+ if (mt->mReceiveCount > 0)
+ {
+ LL_INFOS("Messaging") << "Num: " << std::setw(3) << mt->mReceiveCount << " Bytes: " << std::setw(6) << mt->mReceiveBytes
+ << " Invalid: " << std::setw(3) << mt->mReceiveInvalid << " " << mt->mName << " " << ll_round(100 * mt->mDecodeTimeThisFrame / mReceiveTime.value()) << "%" << LL_ENDL;
+ }
+ }
+ }
+}
+
+
+
+bool LLMessageSystem::isClear() const
+{
+ return mMessageBuilder->isClear();
+}
+
+
+S32 LLMessageSystem::flush(const LLHost &host)
+{
+ if (mMessageBuilder->getMessageSize())
+ {
+ S32 sentbytes = sendMessage(host);
+ clearMessage();
+ return sentbytes;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+U32 LLMessageSystem::getListenPort( void ) const
+{
+ return mPort;
+}
+
+// TODO: babbage: remove this horror!
+S32 LLMessageSystem::zeroCodeAdjustCurrentSendTotal()
+{
+ if(mMessageBuilder == mLLSDMessageBuilder)
+ {
+ // babbage: don't compress LLSD messages, so delta is 0
+ return 0;
+ }
+
+ if (! mMessageBuilder->isBuilt())
+ {
+ mSendSize = mMessageBuilder->buildMessage(
+ mSendBuffer,
+ MAX_BUFFER_SIZE,
+ 0);
+ }
+ // TODO: babbage: remove this horror
+ mMessageBuilder->setBuilt(false);
+
+ S32 count = mSendSize;
+
+ S32 net_gain = 0;
+ U8 num_zeroes = 0;
+
+ U8 *inptr = (U8 *)mSendBuffer;
+
+// skip the packet id field
+
+ for (U32 ii = 0; ii < LL_PACKET_ID_SIZE; ++ii)
+ {
+ count--;
+ inptr++;
+ }
+
+// don't actually build, just test
+
+// sequential zero bytes are encoded as 0 [U8 count]
+// with 0 0 [count] representing wrap (>256 zeroes)
+
+ while (count--)
+ {
+ if (!(*inptr)) // in a zero count
+ {
+ if (num_zeroes)
+ {
+ if (++num_zeroes > 254)
+ {
+ num_zeroes = 0;
+ }
+ net_gain--; // subseqent zeroes save one
+ }
+ else
+ {
+ net_gain++; // starting a zero count adds one
+ num_zeroes = 1;
+ }
+ inptr++;
+ }
+ else
+ {
+ if (num_zeroes)
+ {
+ num_zeroes = 0;
+ }
+ inptr++;
+ }
+ }
+ if (net_gain < 0)
+ {
+ return net_gain;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+
+S32 LLMessageSystem::zeroCodeExpand(U8** data, S32* data_size)
+{
+ if ((*data_size ) < LL_MINIMUM_VALID_PACKET_SIZE)
+ {
+ LL_WARNS("Messaging") << "zeroCodeExpand() called with data_size of " << *data_size
+ << LL_ENDL;
+ }
+
+ mTotalBytesIn += *data_size;
+
+ // if we're not zero-coded, simply return.
+ if (!(*data[0] & LL_ZERO_CODE_FLAG))
+ {
+ return 0;
+ }
+
+ S32 in_size = *data_size;
+ mCompressedPacketsIn++;
+ mCompressedBytesIn += *data_size;
+
+ *data[0] &= (~LL_ZERO_CODE_FLAG);
+
+ S32 count = (*data_size);
+
+ U8 *inptr = (U8 *)*data;
+ U8 *outptr = (U8 *)mEncodedRecvBuffer;
+
+// skip the packet id field
+
+ for (U32 ii = 0; ii < LL_PACKET_ID_SIZE; ++ii)
+ {
+ count--;
+ *outptr++ = *inptr++;
+ }
+
+// reconstruct encoded packet, keeping track of net size gain
+
+// sequential zero bytes are encoded as 0 [U8 count]
+// with 0 0 [count] representing wrap (>256 zeroes)
+
+ while (count--)
+ {
+ if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-1]))
+ {
+ LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 1" << LL_ENDL;
+ callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE);
+ outptr = mEncodedRecvBuffer;
+ break;
+ }
+ if (!((*outptr++ = *inptr++)))
+ {
+ while (((count--)) && (!(*inptr)))
+ {
+ *outptr++ = *inptr++;
+ if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-256]))
+ {
+ LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 2" << LL_ENDL;
+ callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE);
+ outptr = mEncodedRecvBuffer;
+ count = -1;
+ break;
+ }
+ memset(outptr,0,255);
+ outptr += 255;
+ }
+
+ if (count < 0)
+ {
+ break;
+ }
+
+ else
+ {
+ if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-(*inptr)]))
+ {
+ LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 3" << LL_ENDL;
+ callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE);
+ outptr = mEncodedRecvBuffer;
+ }
+ memset(outptr,0,(*inptr) - 1);
+ outptr += ((*inptr) - 1);
+ inptr++;
+ }
+ }
+ }
+
+ *data = mEncodedRecvBuffer;
+ *data_size = (S32)(outptr - mEncodedRecvBuffer);
+ mUncompressedBytesIn += *data_size;
+
+ return(in_size);
+}
+
+
+void LLMessageSystem::addTemplate(LLMessageTemplate *templatep)
+{
+ if (mMessageTemplates.count(templatep->mName) > 0)
+ {
+ LL_ERRS("Messaging") << templatep->mName << " already used as a template name!"
+ << LL_ENDL;
+ }
+ mMessageTemplates[templatep->mName] = templatep;
+ mMessageNumbers[templatep->mMessageNumber] = templatep;
+}
+
+
+void LLMessageSystem::setHandlerFuncFast(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data)
+{
+ LLMessageTemplate* msgtemplate = get_ptr_in_map(mMessageTemplates, name);
+ if (msgtemplate)
+ {
+ msgtemplate->setHandlerFunc(handler_func, user_data);
+ }
+ else
+ {
+ LL_ERRS("Messaging") << name << " is not a known message name!" << LL_ENDL;
+ }
+}
+
+bool LLMessageSystem::callHandler(const char *name,
+ bool trustedSource, LLMessageSystem* msg)
+{
+ name = LLMessageStringTable::getInstance()->getString(name);
+ message_template_name_map_t::const_iterator iter;
+ iter = mMessageTemplates.find(name);
+ if(iter == mMessageTemplates.end())
+ {
+ LL_WARNS("Messaging") << "LLMessageSystem::callHandler: unknown message "
+ << name << LL_ENDL;
+ return false;
+ }
+
+ const LLMessageTemplate* msg_template = iter->second;
+ if (msg_template->isBanned(trustedSource))
+ {
+ LL_WARNS("Messaging") << "LLMessageSystem::callHandler: banned message "
+ << name
+ << " from "
+ << (trustedSource ? "trusted " : "untrusted ")
+ << "source" << LL_ENDL;
+ return false;
+ }
+
+ return msg_template->callHandlerFunc(msg);
+}
+
+
+void LLMessageSystem::setExceptionFunc(EMessageException e,
+ msg_exception_callback func,
+ void* data)
+{
+ callbacks_t::iterator it = mExceptionCallbacks.find(e);
+ if(it != mExceptionCallbacks.end())
+ {
+ mExceptionCallbacks.erase(it);
+ }
+ if(func)
+ {
+ mExceptionCallbacks.insert(callbacks_t::value_type(e, exception_t(func, data)));
+ }
+}
+
+bool LLMessageSystem::callExceptionFunc(EMessageException exception)
+{
+ callbacks_t::iterator it = mExceptionCallbacks.find(exception);
+ if(it == mExceptionCallbacks.end())
+ {
+ return false;
+ }
+
+ exception_t& ex = it->second;
+ msg_exception_callback ex_cb = ex.first;
+
+ if (!ex_cb)
+ {
+ LL_WARNS("Messaging") << "LLMessageSystem::callExceptionFunc: bad message exception callback." << LL_ENDL;
+ return false;
+ }
+
+ (ex_cb)(this, ex.second, exception);
+
+ return true;
+}
+
+void LLMessageSystem::setTimingFunc(msg_timing_callback func, void* data)
+{
+ mTimingCallback = func;
+ mTimingCallbackData = data;
+}
+
+bool LLMessageSystem::isCircuitCodeKnown(U32 code) const
+{
+ if(mCircuitCodes.find(code) == mCircuitCodes.end())
+ return false;
+ return true;
+}
+
+bool LLMessageSystem::isMessageFast(const char *msg)
+{
+ return msg == mMessageReader->getMessageName();
+}
+
+
+char* LLMessageSystem::getMessageName()
+{
+ return const_cast<char*>(mMessageReader->getMessageName());
+}
+
+const LLUUID& LLMessageSystem::getSenderID() const
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(mLastSender);
+ if (cdp)
+ {
+ return (cdp->mRemoteID);
+ }
+
+ return LLUUID::null;
+}
+
+const LLUUID& LLMessageSystem::getSenderSessionID() const
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(mLastSender);
+ if (cdp)
+ {
+ return (cdp->mRemoteSessionID);
+ }
+ return LLUUID::null;
+}
+
+bool LLMessageSystem::generateDigestForNumberAndUUIDs(
+ char* digest,
+ const U32 number,
+ const LLUUID& id1,
+ const LLUUID& id2) const
+{
+ // *NOTE: This method is needlessly inefficient. Instead of
+ // calling LLUUID::asString, it should just call
+ // LLUUID::toString().
+
+ const char *colon = ":";
+ char tbuf[16]; /* Flawfinder: ignore */
+ LLMD5 d;
+ std::string id1string = id1.asString();
+ std::string id2string = id2.asString();
+ std::string shared_secret = get_shared_secret();
+ unsigned char * secret = (unsigned char*)shared_secret.c_str();
+ unsigned char * id1str = (unsigned char*)id1string.c_str();
+ unsigned char * id2str = (unsigned char*)id2string.c_str();
+
+ memset(digest, 0, MD5HEX_STR_SIZE);
+
+ if( secret != NULL)
+ {
+ d.update(secret, (U32)strlen((char *) secret)); /* Flawfinder: ignore */
+ }
+
+ d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
+
+ snprintf(tbuf, sizeof(tbuf),"%i", number); /* Flawfinder: ignore */
+ d.update((unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */
+
+ d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
+ if( (char*) id1str != NULL)
+ {
+ d.update(id1str, (U32)strlen((char *) id1str)); /* Flawfinder: ignore */
+ }
+ d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
+
+ if( (char*) id2str != NULL)
+ {
+ d.update(id2str, (U32)strlen((char *) id2str)); /* Flawfinder: ignore */
+ }
+
+ d.finalize();
+ d.hex_digest(digest);
+ digest[MD5HEX_STR_SIZE - 1] = '\0';
+
+ return true;
+}
+
+bool LLMessageSystem::generateDigestForWindowAndUUIDs(char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const
+{
+ if(0 == window) return false;
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty())
+ {
+ LL_ERRS("Messaging") << "Trying to generate complex digest on a machine without a shared secret!" << LL_ENDL;
+ }
+
+ U32 now = (U32)time(NULL);
+
+ now /= window;
+
+ bool result = generateDigestForNumberAndUUIDs(digest, now, id1, id2);
+
+ return result;
+}
+
+bool LLMessageSystem::isMatchingDigestForWindowAndUUIDs(const char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const
+{
+ if(0 == window) return false;
+
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty())
+ {
+ LL_ERRS("Messaging") << "Trying to compare complex digests on a machine without a shared secret!" << LL_ENDL;
+ }
+
+ char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
+ U32 now = (U32)time(NULL);
+
+ now /= window;
+
+ // Check 1 window ago, now, and one window from now to catch edge
+ // conditions. Process them as current window, one window ago, and
+ // one window in the future to catch the edges.
+ const S32 WINDOW_BIN_COUNT = 3;
+ U32 window_bin[WINDOW_BIN_COUNT];
+ window_bin[0] = now;
+ window_bin[1] = now - 1;
+ window_bin[2] = now + 1;
+ for(S32 i = 0; i < WINDOW_BIN_COUNT; ++i)
+ {
+ generateDigestForNumberAndUUIDs(our_digest, window_bin[i], id2, id1);
+ if(0 == strncmp(digest, our_digest, MD5HEX_STR_BYTES))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LLMessageSystem::generateDigestForNumber(char* digest, const U32 number) const
+{
+ memset(digest, 0, MD5HEX_STR_SIZE);
+
+ LLMD5 d;
+ std::string shared_secret = get_shared_secret();
+ d = LLMD5((const unsigned char *)shared_secret.c_str(), number);
+ d.hex_digest(digest);
+ digest[MD5HEX_STR_SIZE - 1] = '\0';
+
+ return true;
+}
+
+bool LLMessageSystem::generateDigestForWindow(char* digest, const S32 window) const
+{
+ if(0 == window) return false;
+
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty())
+ {
+ LL_ERRS("Messaging") << "Trying to generate simple digest on a machine without a shared secret!" << LL_ENDL;
+ }
+
+ U32 now = (U32)time(NULL);
+
+ now /= window;
+
+ bool result = generateDigestForNumber(digest, now);
+
+ return result;
+}
+
+bool LLMessageSystem::isMatchingDigestForWindow(const char* digest, S32 const window) const
+{
+ if(0 == window) return false;
+
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty())
+ {
+ LL_ERRS("Messaging") << "Trying to compare simple digests on a machine without a shared secret!" << LL_ENDL;
+ }
+
+ char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
+ U32 now = (S32)time(NULL);
+
+ now /= window;
+
+ // Check 1 window ago, now, and one window from now to catch edge
+ // conditions. Process them as current window, one window ago, and
+ // one window in the future to catch the edges.
+ const S32 WINDOW_BIN_COUNT = 3;
+ U32 window_bin[WINDOW_BIN_COUNT];
+ window_bin[0] = now;
+ window_bin[1] = now - 1;
+ window_bin[2] = now + 1;
+ for(S32 i = 0; i < WINDOW_BIN_COUNT; ++i)
+ {
+ generateDigestForNumber(our_digest, window_bin[i]);
+ if(0 == strncmp(digest, our_digest, MD5HEX_STR_BYTES))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void LLMessageSystem::sendCreateTrustedCircuit(const LLHost &host, const LLUUID & id1, const LLUUID & id2)
+{
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty()) return;
+ char digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
+ if (id1.isNull())
+ {
+ LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the local end point ID" << LL_ENDL;
+ return;
+ }
+ if (id2.isNull())
+ {
+ LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the remote end point ID" << LL_ENDL;
+ return;
+ }
+ generateDigestForWindowAndUUIDs(digest, TRUST_TIME_WINDOW, id1, id2);
+ newMessageFast(_PREHASH_CreateTrustedCircuit);
+ nextBlockFast(_PREHASH_DataBlock);
+ addUUIDFast(_PREHASH_EndPointID, id1);
+ addBinaryDataFast(_PREHASH_Digest, digest, MD5HEX_STR_BYTES);
+ LL_INFOS("Messaging") << "xmitting digest: " << digest << " Host: " << host << LL_ENDL;
+ sendMessage(host);
+}
+
+void LLMessageSystem::sendDenyTrustedCircuit(const LLHost &host)
+{
+ mDenyTrustedCircuitSet.insert(host);
+}
+
+void LLMessageSystem::reallySendDenyTrustedCircuit(const LLHost &host)
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (!cdp)
+ {
+ LL_WARNS("Messaging") << "Not sending DenyTrustedCircuit to host without a circuit." << LL_ENDL;
+ return;
+ }
+ LL_INFOS("Messaging") << "Sending DenyTrustedCircuit to " << host << LL_ENDL;
+ newMessageFast(_PREHASH_DenyTrustedCircuit);
+ nextBlockFast(_PREHASH_DataBlock);
+ addUUIDFast(_PREHASH_EndPointID, cdp->getLocalEndPointID());
+ sendMessage(host);
+}
+
+void null_message_callback(LLMessageSystem *msg, void **data)
+{
+ // Nothing should ever go here, but we use this to register messages
+ // that we are expecting to see (and spinning on) at startup.
+ return;
+}
+
+// Try to establish a bidirectional trust metric by pinging a host until it's
+// up, and then sending auth messages.
+void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_count )
+{
+ LockMessageChecker lmc(this);
+
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty())
+ {
+ LL_ERRS("Messaging") << "Trying to establish bidirectional trust on a machine without a shared secret!" << LL_ENDL;
+ }
+ LLTimer timeout;
+
+ timeout.setTimerExpirySec(20.0);
+ setHandlerFuncFast(_PREHASH_StartPingCheck, null_message_callback, NULL);
+ setHandlerFuncFast(_PREHASH_CompletePingCheck, null_message_callback,
+ NULL);
+
+ while (! timeout.hasExpired())
+ {
+ newMessageFast(_PREHASH_StartPingCheck);
+ nextBlockFast(_PREHASH_PingID);
+ addU8Fast(_PREHASH_PingID, 0);
+ addU32Fast(_PREHASH_OldestUnacked, 0);
+ sendMessage(host);
+ if (lmc.checkMessages( frame_count ))
+ {
+ if (isMessageFast(_PREHASH_CompletePingCheck) &&
+ (getSender() == host))
+ {
+ break;
+ }
+ }
+ lmc.processAcks();
+ ms_sleep(1);
+ }
+
+ // Send a request, a deny, and give the host 2 seconds to complete
+ // the trust handshake.
+ newMessage("RequestTrustedCircuit");
+ sendMessage(host);
+ reallySendDenyTrustedCircuit(host);
+ setHandlerFuncFast(_PREHASH_StartPingCheck, process_start_ping_check, NULL);
+ setHandlerFuncFast(_PREHASH_CompletePingCheck, process_complete_ping_check, NULL);
+
+ timeout.setTimerExpirySec(2.0);
+ LLCircuitData* cdp = NULL;
+ while(!timeout.hasExpired())
+ {
+ cdp = mCircuitInfo.findCircuit(host);
+ if(!cdp) break; // no circuit anymore, no point continuing.
+ if(cdp->getTrusted()) break; // circuit is trusted.
+ lmc.checkMessages(frame_count);
+ lmc.processAcks();
+ ms_sleep(1);
+ }
+}
+
+
+void LLMessageSystem::dumpPacketToLog()
+{
+ LL_WARNS("Messaging") << "Packet Dump from:" << mPacketRing.getLastSender() << LL_ENDL;
+ LL_WARNS("Messaging") << "Packet Size:" << mTrueReceiveSize << LL_ENDL;
+ char line_buffer[256]; /* Flawfinder: ignore */
+ S32 i;
+ S32 cur_line_pos = 0;
+ S32 cur_line = 0;
+
+ for (i = 0; i < mTrueReceiveSize; i++)
+ {
+ S32 offset = cur_line_pos * 3;
+ snprintf(line_buffer + offset, sizeof(line_buffer) - offset,
+ "%02x ", mTrueReceiveBuffer[i]); /* Flawfinder: ignore */
+ cur_line_pos++;
+ if (cur_line_pos >= 16)
+ {
+ cur_line_pos = 0;
+ LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << LL_ENDL;
+ cur_line++;
+ }
+ }
+ if (cur_line_pos)
+ {
+ LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << LL_ENDL;
+ }
+}
+
+
+//static
+U64Microseconds LLMessageSystem::getMessageTimeUsecs(const bool update)
+{
+ if (gMessageSystem)
+ {
+ if (update)
+ {
+ gMessageSystem->mCurrentMessageTime = totalTime();
+ }
+ return gMessageSystem->mCurrentMessageTime;
+ }
+ else
+ {
+ return totalTime();
+ }
+}
+
+//static
+F64Seconds LLMessageSystem::getMessageTimeSeconds(const bool update)
+{
+ if (gMessageSystem)
+ {
+ if (update)
+ {
+ gMessageSystem->mCurrentMessageTime = totalTime();
+ }
+ return gMessageSystem->mCurrentMessageTime;
+ }
+ else
+ {
+ return F64Seconds(totalTime());
+ }
+}
+
+std::string get_shared_secret()
+{
+ static const std::string SHARED_SECRET_KEY("shared_secret");
+ if(g_shared_secret.empty())
+ {
+ LLApp* app = LLApp::instance();
+ if(app) return app->getOption(SHARED_SECRET_KEY);
+ }
+ return g_shared_secret;
+}
+
+typedef std::map<const char*, LLMessageBuilder*> BuilderMap;
+
+void LLMessageSystem::newMessageFast(const char *name)
+{
+ //LL_DEBUGS("Messaging") << "creating new message: " << name << LL_ENDL;
+ LLMessageConfig::Flavor message_flavor =
+ LLMessageConfig::getMessageFlavor(name);
+ LLMessageConfig::Flavor server_flavor =
+ LLMessageConfig::getServerDefaultFlavor();
+
+ if(message_flavor == LLMessageConfig::TEMPLATE_FLAVOR)
+ {
+ mMessageBuilder = mTemplateMessageBuilder;
+ }
+ else if (message_flavor == LLMessageConfig::LLSD_FLAVOR)
+ {
+ mMessageBuilder = mLLSDMessageBuilder;
+ }
+ // NO_FLAVOR
+ else
+ {
+ if (server_flavor == LLMessageConfig::LLSD_FLAVOR)
+ {
+ mMessageBuilder = mLLSDMessageBuilder;
+ }
+ // TEMPLATE_FLAVOR or NO_FLAVOR
+ else
+ {
+ mMessageBuilder = mTemplateMessageBuilder;
+ }
+ }
+ mSendReliable = false;
+ mMessageBuilder->newMessage(name);
+}
+
+void LLMessageSystem::newMessage(const char *name)
+{
+ newMessageFast(LLMessageStringTable::getInstance()->getString(name));
+}
+
+void LLMessageSystem::addBinaryDataFast(const char *varname, const void *data, S32 size)
+{
+ mMessageBuilder->addBinaryData(varname, data, size);
+}
+
+void LLMessageSystem::addBinaryData(const char *varname, const void *data, S32 size)
+{
+ mMessageBuilder->addBinaryData(LLMessageStringTable::getInstance()->getString(varname),data, size);
+}
+
+void LLMessageSystem::addS8Fast(const char *varname, S8 v)
+{
+ mMessageBuilder->addS8(varname, v);
+}
+
+void LLMessageSystem::addS8(const char *varname, S8 v)
+{
+ mMessageBuilder->addS8(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addU8Fast(const char *varname, U8 v)
+{
+ mMessageBuilder->addU8(varname, v);
+}
+
+void LLMessageSystem::addU8(const char *varname, U8 v)
+{
+ mMessageBuilder->addU8(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addS16Fast(const char *varname, S16 v)
+{
+ mMessageBuilder->addS16(varname, v);
+}
+
+void LLMessageSystem::addS16(const char *varname, S16 v)
+{
+ mMessageBuilder->addS16(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addU16Fast(const char *varname, U16 v)
+{
+ mMessageBuilder->addU16(varname, v);
+}
+
+void LLMessageSystem::addU16(const char *varname, U16 v)
+{
+ mMessageBuilder->addU16(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addF32Fast(const char *varname, F32 v)
+{
+ mMessageBuilder->addF32(varname, v);
+}
+
+void LLMessageSystem::addF32(const char *varname, F32 v)
+{
+ mMessageBuilder->addF32(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addS32Fast(const char *varname, S32 v)
+{
+ mMessageBuilder->addS32(varname, v);
+}
+
+void LLMessageSystem::addS32(const char *varname, S32 v)
+{
+ mMessageBuilder->addS32(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addU32Fast(const char *varname, U32 v)
+{
+ mMessageBuilder->addU32(varname, v);
+}
+
+void LLMessageSystem::addU32(const char *varname, U32 v)
+{
+ mMessageBuilder->addU32(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addU64Fast(const char *varname, U64 v)
+{
+ mMessageBuilder->addU64(varname, v);
+}
+
+void LLMessageSystem::addU64(const char *varname, U64 v)
+{
+ mMessageBuilder->addU64(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addF64Fast(const char *varname, F64 v)
+{
+ mMessageBuilder->addF64(varname, v);
+}
+
+void LLMessageSystem::addF64(const char *varname, F64 v)
+{
+ mMessageBuilder->addF64(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addIPAddrFast(const char *varname, U32 v)
+{
+ mMessageBuilder->addIPAddr(varname, v);
+}
+
+void LLMessageSystem::addIPAddr(const char *varname, U32 v)
+{
+ mMessageBuilder->addIPAddr(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addIPPortFast(const char *varname, U16 v)
+{
+ mMessageBuilder->addIPPort(varname, v);
+}
+
+void LLMessageSystem::addIPPort(const char *varname, U16 v)
+{
+ mMessageBuilder->addIPPort(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addBOOLFast(const char* varname, bool v)
+{
+ mMessageBuilder->addBOOL(varname, v);
+}
+
+void LLMessageSystem::addBOOL(const char* varname, bool v)
+{
+ mMessageBuilder->addBOOL(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addStringFast(const char* varname, const char* v)
+{
+ mMessageBuilder->addString(varname, v);
+}
+
+void LLMessageSystem::addString(const char* varname, const char* v)
+{
+ mMessageBuilder->addString(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addStringFast(const char* varname, const std::string& v)
+{
+ mMessageBuilder->addString(varname, v);
+}
+
+void LLMessageSystem::addString(const char* varname, const std::string& v)
+{
+ mMessageBuilder->addString(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addVector3Fast(const char *varname, const LLVector3& v)
+{
+ mMessageBuilder->addVector3(varname, v);
+}
+
+void LLMessageSystem::addVector3(const char *varname, const LLVector3& v)
+{
+ mMessageBuilder->addVector3(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addVector4Fast(const char *varname, const LLVector4& v)
+{
+ mMessageBuilder->addVector4(varname, v);
+}
+
+void LLMessageSystem::addVector4(const char *varname, const LLVector4& v)
+{
+ mMessageBuilder->addVector4(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addVector3dFast(const char *varname, const LLVector3d& v)
+{
+ mMessageBuilder->addVector3d(varname, v);
+}
+
+void LLMessageSystem::addVector3d(const char *varname, const LLVector3d& v)
+{
+ mMessageBuilder->addVector3d(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+void LLMessageSystem::addQuatFast(const char *varname, const LLQuaternion& v)
+{
+ mMessageBuilder->addQuat(varname, v);
+}
+
+void LLMessageSystem::addQuat(const char *varname, const LLQuaternion& v)
+{
+ mMessageBuilder->addQuat(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+
+void LLMessageSystem::addUUIDFast(const char *varname, const LLUUID& v)
+{
+ mMessageBuilder->addUUID(varname, v);
+}
+
+void LLMessageSystem::addUUID(const char *varname, const LLUUID& v)
+{
+ mMessageBuilder->addUUID(LLMessageStringTable::getInstance()->getString(varname), v);
+}
+
+S32 LLMessageSystem::getCurrentSendTotal() const
+{
+ return mMessageBuilder->getMessageSize();
+}
+
+void LLMessageSystem::getS8Fast(const char *block, const char *var, S8 &u,
+ S32 blocknum)
+{
+ mMessageReader->getS8(block, var, u, blocknum);
+}
+
+void LLMessageSystem::getS8(const char *block, const char *var, S8 &u,
+ S32 blocknum)
+{
+ getS8Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), u, blocknum);
+}
+
+void LLMessageSystem::getU8Fast(const char *block, const char *var, U8 &u,
+ S32 blocknum)
+{
+ mMessageReader->getU8(block, var, u, blocknum);
+}
+
+void LLMessageSystem::getU8(const char *block, const char *var, U8 &u,
+ S32 blocknum)
+{
+ getU8Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), u, blocknum);
+}
+
+void LLMessageSystem::getBOOLFast(const char *block, const char *var, bool &b,
+ S32 blocknum)
+{
+ mMessageReader->getBOOL(block, var, b, blocknum);
+}
+
+void LLMessageSystem::getBOOL(const char *block, const char *var, bool &b,
+ S32 blocknum)
+{
+ getBOOLFast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), b, blocknum);
+}
+
+void LLMessageSystem::getS16Fast(const char *block, const char *var, S16 &d,
+ S32 blocknum)
+{
+ mMessageReader->getS16(block, var, d, blocknum);
+}
+
+void LLMessageSystem::getS16(const char *block, const char *var, S16 &d,
+ S32 blocknum)
+{
+ getS16Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), d, blocknum);
+}
+
+void LLMessageSystem::getU16Fast(const char *block, const char *var, U16 &d,
+ S32 blocknum)
+{
+ mMessageReader->getU16(block, var, d, blocknum);
+}
+
+void LLMessageSystem::getU16(const char *block, const char *var, U16 &d,
+ S32 blocknum)
+{
+ getU16Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), d, blocknum);
+}
+
+void LLMessageSystem::getS32Fast(const char *block, const char *var, S32 &d,
+ S32 blocknum)
+{
+ mMessageReader->getS32(block, var, d, blocknum);
+}
+
+void LLMessageSystem::getS32(const char *block, const char *var, S32 &d,
+ S32 blocknum)
+{
+ getS32Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), d, blocknum);
+}
+
+void LLMessageSystem::getU32Fast(const char *block, const char *var, U32 &d,
+ S32 blocknum)
+{
+ mMessageReader->getU32(block, var, d, blocknum);
+}
+
+void LLMessageSystem::getU32(const char *block, const char *var, U32 &d,
+ S32 blocknum)
+{
+ getU32Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), d, blocknum);
+}
+
+void LLMessageSystem::getU64Fast(const char *block, const char *var, U64 &d,
+ S32 blocknum)
+{
+ mMessageReader->getU64(block, var, d, blocknum);
+}
+
+void LLMessageSystem::getU64(const char *block, const char *var, U64 &d,
+ S32 blocknum)
+{
+
+ getU64Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), d, blocknum);
+}
+
+void LLMessageSystem::getBinaryDataFast(const char *blockname,
+ const char *varname,
+ void *datap, S32 size,
+ S32 blocknum, S32 max_size)
+{
+ mMessageReader->getBinaryData(blockname, varname, datap, size, blocknum,
+ max_size);
+}
+
+void LLMessageSystem::getBinaryData(const char *blockname,
+ const char *varname,
+ void *datap, S32 size,
+ S32 blocknum, S32 max_size)
+{
+ getBinaryDataFast(LLMessageStringTable::getInstance()->getString(blockname),
+ LLMessageStringTable::getInstance()->getString(varname),
+ datap, size, blocknum, max_size);
+}
+
+void LLMessageSystem::getF32Fast(const char *block, const char *var, F32 &d,
+ S32 blocknum)
+{
+ mMessageReader->getF32(block, var, d, blocknum);
+}
+
+void LLMessageSystem::getF32(const char *block, const char *var, F32 &d,
+ S32 blocknum)
+{
+ getF32Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), d, blocknum);
+}
+
+void LLMessageSystem::getF64Fast(const char *block, const char *var, F64 &d,
+ S32 blocknum)
+{
+ mMessageReader->getF64(block, var, d, blocknum);
+}
+
+void LLMessageSystem::getF64(const char *block, const char *var, F64 &d,
+ S32 blocknum)
+{
+ getF64Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), d, blocknum);
+}
+
+
+void LLMessageSystem::getVector3Fast(const char *block, const char *var,
+ LLVector3 &v, S32 blocknum )
+{
+ mMessageReader->getVector3(block, var, v, blocknum);
+}
+
+void LLMessageSystem::getVector3(const char *block, const char *var,
+ LLVector3 &v, S32 blocknum )
+{
+ getVector3Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), v, blocknum);
+}
+
+void LLMessageSystem::getVector4Fast(const char *block, const char *var,
+ LLVector4 &v, S32 blocknum )
+{
+ mMessageReader->getVector4(block, var, v, blocknum);
+}
+
+void LLMessageSystem::getVector4(const char *block, const char *var,
+ LLVector4 &v, S32 blocknum )
+{
+ getVector4Fast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), v, blocknum);
+}
+
+void LLMessageSystem::getVector3dFast(const char *block, const char *var,
+ LLVector3d &v, S32 blocknum )
+{
+ mMessageReader->getVector3d(block, var, v, blocknum);
+}
+
+void LLMessageSystem::getVector3d(const char *block, const char *var,
+ LLVector3d &v, S32 blocknum )
+{
+ getVector3dFast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), v, blocknum);
+}
+
+void LLMessageSystem::getQuatFast(const char *block, const char *var,
+ LLQuaternion &q, S32 blocknum )
+{
+ mMessageReader->getQuat(block, var, q, blocknum);
+}
+
+void LLMessageSystem::getQuat(const char *block, const char *var,
+ LLQuaternion &q, S32 blocknum)
+{
+ getQuatFast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), q, blocknum);
+}
+
+void LLMessageSystem::getUUIDFast(const char *block, const char *var,
+ LLUUID &u, S32 blocknum )
+{
+ mMessageReader->getUUID(block, var, u, blocknum);
+}
+
+void LLMessageSystem::getUUID(const char *block, const char *var, LLUUID &u,
+ S32 blocknum )
+{
+ getUUIDFast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), u, blocknum);
+}
+
+void LLMessageSystem::getIPAddrFast(const char *block, const char *var,
+ U32 &u, S32 blocknum)
+{
+ mMessageReader->getIPAddr(block, var, u, blocknum);
+}
+
+void LLMessageSystem::getIPAddr(const char *block, const char *var, U32 &u,
+ S32 blocknum)
+{
+ getIPAddrFast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), u, blocknum);
+}
+
+void LLMessageSystem::getIPPortFast(const char *block, const char *var,
+ U16 &u, S32 blocknum)
+{
+ mMessageReader->getIPPort(block, var, u, blocknum);
+}
+
+void LLMessageSystem::getIPPort(const char *block, const char *var, U16 &u,
+ S32 blocknum)
+{
+ getIPPortFast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), u,
+ blocknum);
+}
+
+
+void LLMessageSystem::getStringFast(const char *block, const char *var,
+ S32 buffer_size, char *s, S32 blocknum)
+{
+ if(buffer_size <= 0)
+ {
+ LL_WARNS("Messaging") << "buffer_size <= 0" << LL_ENDL;
+ }
+ mMessageReader->getString(block, var, buffer_size, s, blocknum);
+}
+
+void LLMessageSystem::getString(const char *block, const char *var,
+ S32 buffer_size, char *s, S32 blocknum )
+{
+ getStringFast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), buffer_size, s,
+ blocknum);
+}
+
+void LLMessageSystem::getStringFast(const char *block, const char *var,
+ std::string& outstr, S32 blocknum)
+{
+ mMessageReader->getString(block, var, outstr, blocknum);
+}
+
+void LLMessageSystem::getString(const char *block, const char *var,
+ std::string& outstr, S32 blocknum )
+{
+ getStringFast(LLMessageStringTable::getInstance()->getString(block),
+ LLMessageStringTable::getInstance()->getString(var), outstr,
+ blocknum);
+}
+
+bool LLMessageSystem::has(const char *blockname) const
+{
+ return getNumberOfBlocks(blockname) > 0;
+}
+
+S32 LLMessageSystem::getNumberOfBlocksFast(const char *blockname) const
+{
+ return mMessageReader->getNumberOfBlocks(blockname);
+}
+
+S32 LLMessageSystem::getNumberOfBlocks(const char *blockname) const
+{
+ return getNumberOfBlocksFast(LLMessageStringTable::getInstance()->getString(blockname));
+}
+
+S32 LLMessageSystem::getSizeFast(const char *blockname, const char *varname) const
+{
+ return mMessageReader->getSize(blockname, varname);
+}
+
+S32 LLMessageSystem::getSize(const char *blockname, const char *varname) const
+{
+ return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname),
+ LLMessageStringTable::getInstance()->getString(varname));
+}
+
+// size in bytes of variable length data
+S32 LLMessageSystem::getSizeFast(const char *blockname, S32 blocknum,
+ const char *varname) const
+{
+ return mMessageReader->getSize(blockname, blocknum, varname);
+}
+
+S32 LLMessageSystem::getSize(const char *blockname, S32 blocknum,
+ const char *varname) const
+{
+ return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname), blocknum,
+ LLMessageStringTable::getInstance()->getString(varname));
+}
+
+S32 LLMessageSystem::getReceiveSize() const
+{
+ return mMessageReader->getMessageSize();
+}
+
+//static
+void LLMessageSystem::setTimeDecodes( bool b )
+{
+ LLMessageReader::setTimeDecodes(b);
+}
+
+//static
+void LLMessageSystem::setTimeDecodesSpamThreshold( F32 seconds )
+{
+ LLMessageReader::setTimeDecodesSpamThreshold(seconds);
+}
+
+LockMessageChecker::LockMessageChecker(LLMessageSystem* msgsystem):
+ // for the lifespan of this LockMessageChecker instance, use
+ // LLTemplateMessageReader as msgsystem's mMessageReader
+ LockMessageReader(msgsystem->mMessageReader, msgsystem->mTemplateMessageReader),
+ mMessageSystem(msgsystem)
+{}
+
+// HACK! babbage: return true if message rxed via either UDP or HTTP
+// TODO: babbage: move gServicePump in to LLMessageSystem?
+bool LLMessageSystem::checkAllMessages(LockMessageChecker& lmc, S64 frame_count, LLPumpIO* http_pump)
+{
+ if(lmc.checkMessages(frame_count))
+ {
+ return true;
+ }
+ U32 packetsIn = mPacketsIn;
+ http_pump->pump();
+ http_pump->callback();
+ return (mPacketsIn - packetsIn) > 0;
+}
+
+void LLMessageSystem::banUdpMessage(const std::string& name)
+{
+ message_template_name_map_t::iterator itt = mMessageTemplates.find(
+ LLMessageStringTable::getInstance()->getString(name.c_str())
+ );
+ if(itt != mMessageTemplates.end())
+ {
+ itt->second->banUdp();
+ }
+ else
+ {
+ LL_WARNS() << "Attempted to ban an unknown message: " << name << "." << LL_ENDL;
+ }
+}
+const LLHost& LLMessageSystem::getSender() const
+{
+ return mLastSender;
+}
+
+void LLMessageSystem::sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("untrustedSimulatorMessage", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+
+ if (url.empty())
+ {
+ LL_WARNS() << "sendUntrustedSimulatorMessageCoro called with empty capability!" << LL_ENDL;
+ return;
+ }
+
+ LL_INFOS() << "sendUntrustedSimulatorMessageCoro: message " << message << " to cap " << url << LL_ENDL;
+ LLSD postData;
+ postData["message"] = message;
+ postData["body"] = body;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if ((callback) && (!callback.empty()))
+ callback((status) ? LL_ERR_NOERR : LL_ERR_TCP_TIMEOUT);
+}
+
+
+LLHTTPRegistration<LLHTTPNodeAdapter<LLTrustedMessageService> >
+ gHTTPRegistrationTrustedMessageWildcard("/trusted-message/<message-name>");
+
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 2d212c6b3c..8f15bc266d 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -1,1171 +1,1171 @@ -/** - * @file message.h - * @brief LLMessageSystem class header file - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_MESSAGE_H -#define LL_MESSAGE_H - -#include <cstring> -#include <set> - -#if LL_LINUX -#include <endian.h> -#include <netinet/in.h> -#endif - -#if LL_WINDOWS -#include "winsock2.h" // htons etc. -#endif - -#include "llerror.h" -#include "net.h" -#include "llstringtable.h" -#include "llcircuit.h" -#include "lltimer.h" -#include "llpacketring.h" -#include "llhost.h" -#include "llhttpnode.h" -//#include "llpacketack.h" -#include "llsingleton.h" -#include "message_prehash.h" -#include "llstl.h" -#include "llmsgvariabletype.h" -#include "llmessagesenderinterface.h" - -#include "llstoredmessage.h" -#include "boost/function.hpp" -#include "llpounceable.h" -#include "llcoros.h" -#include LLCOROS_MUTEX_HEADER - -const U32 MESSAGE_MAX_STRINGS_LENGTH = 64; -const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192; - -const S32 MESSAGE_MAX_PER_FRAME = 400; - -class LLMessageStringTable : public LLSingleton<LLMessageStringTable> -{ - LLSINGLETON(LLMessageStringTable); - ~LLMessageStringTable(); - -public: - char *getString(const char *str); - - U32 mUsed; - BOOL mEmpty[MESSAGE_NUMBER_OF_HASH_BUCKETS]; - char mString[MESSAGE_NUMBER_OF_HASH_BUCKETS][MESSAGE_MAX_STRINGS_LENGTH]; /* Flawfinder: ignore */ -}; - - -// Individual Messages are described with the following format -// Note that to ease parsing, keywords are used -// -// // Comment (Comment like a C++ single line comment) -// Comments can only be placed between Messages -// { -// MessageName (same naming restrictions as C variable) -// Frequency ("High", "Medium", or "Low" - determines whether message ID is 8, 16, or 32-bits -- -// there can 254 messages in the first 2 groups, 32K in the last group) -// (A message can be made up only of the Name if it is only a signal) -// Trust ("Trusted", "NotTrusted" - determines if a message will be accepted -// on a circuit. "Trusted" messages are not accepted from NotTrusted circuits -// while NotTrusted messages are accepted on any circuit. An example of a -// NotTrusted circuit is any circuit from the viewer.) -// Encoding ("Zerocoded", "Unencoded" - zerocoded messages attempt to compress sequences of -// zeros, but if there is no space win, it discards the compression and goes unencoded) -// { -// Block Name (same naming restrictions as C variable) -// Block Type ("Single", "Multiple", or "Variable" - determines if the block is coded once, -// a known number of times, or has a 8 bit argument encoded to tell the decoder -// how many times the group is repeated) -// Block Repeat Number (Optional - used only with the "Multiple" type - tells how many times the field is repeated -// { -// Variable 1 Name (same naming restrictions as C variable) -// Variable Type ("Fixed" or "Variable" - determines if the variable is of fixed size or needs to -// encode an argument describing the size in bytes) -// Variable Size (In bytes, either of the "Fixed" variable itself or of the size argument) -// -// repeat variables -// -// } -// -// Repeat for number of variables in block -// } -// -// Repeat for number of blocks in message -// } -// Repeat for number of messages in file -// - -// Constants -const S32 MAX_MESSAGE_INTERNAL_NAME_SIZE = 255; -const S32 MAX_BUFFER_SIZE = NET_BUFFER_SIZE; -const S32 MAX_BLOCKS = 255; - -const U8 LL_ZERO_CODE_FLAG = 0x80; -const U8 LL_RELIABLE_FLAG = 0x40; -const U8 LL_RESENT_FLAG = 0x20; -const U8 LL_ACK_FLAG = 0x10; - -// 1 byte flags, 4 bytes sequence, 1 byte offset + 1 byte message name (high) -const S32 LL_MINIMUM_VALID_PACKET_SIZE = LL_PACKET_ID_SIZE + 1; -enum EPacketHeaderLayout -{ - PHL_FLAGS = 0, - PHL_PACKET_ID = 1, - PHL_OFFSET = 5, - PHL_NAME = 6 -}; - - -const S32 LL_DEFAULT_RELIABLE_RETRIES = 3; -const F32Seconds LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS(1.f); -const F32Seconds LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS(1.f); -const F32Seconds LL_PING_BASED_TIMEOUT_DUMMY(0.0f); - -const F32 LL_SEMIRELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping -const F32 LL_RELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping -const F32 LL_LOST_TIMEOUT_FACTOR = 16.f; // averaged ping for marking packets "Lost" -const F32Seconds LL_MAX_LOST_TIMEOUT(5.f); // Maximum amount of time before considering something "lost" - -const S32 MAX_MESSAGE_COUNT_NUM = 1024; - -// Forward declarations -class LLVector3; -class LLVector4; -class LLVector3d; -class LLQuaternion; -class LLSD; -class LLUUID; -class LLMessageSystem; -class LLPumpIO; - -// message system exceptional condition handlers. -enum EMessageException -{ - MX_UNREGISTERED_MESSAGE, // message number not part of template - MX_PACKET_TOO_SHORT, // invalid packet, shorter than minimum packet size - MX_RAN_OFF_END_OF_PACKET, // ran off the end of the packet during decode - MX_WROTE_PAST_BUFFER_SIZE // wrote past buffer size in zero code expand -}; -typedef void (*msg_exception_callback)(LLMessageSystem*,void*,EMessageException); - - -// message data pieces are used to collect the data called for by the message template -class LLMsgData; -class LLMsgBlkData; -class LLMessageTemplate; - -class LLMessagePollInfo; -class LLMessageBuilder; -class LLTemplateMessageBuilder; -class LLSDMessageBuilder; -class LLMessageReader; -class LLTemplateMessageReader; -class LLSDMessageReader; - - - -class LLUseCircuitCodeResponder -{ - LOG_CLASS(LLMessageSystem); - -public: - virtual ~LLUseCircuitCodeResponder(); - virtual void complete(const LLHost& host, const LLUUID& agent) const = 0; -}; - -/** - * SL-12204: We've observed crashes when consumer code sets - * LLMessageSystem::mMessageReader, assuming that all subsequent processing of - * the current message will use the same mMessageReader value -- only to have - * a different coroutine sneak in and replace mMessageReader before - * completion. This is a limitation of sharing a stateful global resource for - * message parsing; instead code receiving a new message should instantiate a - * (trivially constructed) local message parser and use that. - * - * Until then, when one coroutine sets a particular LLMessageReader subclass - * as the current message reader, ensure that no other coroutine can replace - * it until the first coroutine has finished with its message. - * - * This is achieved with two helper classes. LLMessageSystem::mMessageReader - * is now an LLMessageReaderPointer instance, which can efficiently compare or - * dereference its contained LLMessageReader* but which cannot be directly - * assigned. To change the value of LLMessageReaderPointer, you must - * instantiate LockMessageReader with the LLMessageReader* you wish to make - * current. mMessageReader will have that value for the lifetime of the - * LockMessageReader instance, then revert to nullptr. Moreover, as its name - * implies, LockMessageReader locks the mutex in LLMessageReaderPointer so - * that any other coroutine instantiating LockMessageReader will block until - * the first coroutine has destroyed its instance. - */ -class LLMessageReaderPointer -{ -public: - LLMessageReaderPointer(): mPtr(nullptr) {} - // It is essential that comparison and dereferencing must be fast, which - // is why we don't check for nullptr when dereferencing. - LLMessageReader* operator->() const { return mPtr; } - bool operator==(const LLMessageReader* other) const { return mPtr == other; } - bool operator!=(const LLMessageReader* other) const { return ! (*this == other); } -private: - // Only LockMessageReader can set mPtr. - friend class LockMessageReader; - LLMessageReader* mPtr; - LLCoros::Mutex mMutex; -}; - -/** - * To set mMessageReader to nullptr: - * - * @code - * // use an anonymous instance that is destroyed immediately - * LockMessageReader(gMessageSystem->mMessageReader, nullptr); - * @endcode - * - * Why do we still require going through LockMessageReader at all? Because it - * would be Bad if any coroutine set mMessageReader to nullptr while another - * coroutine was still parsing a message. - */ -class LockMessageReader -{ -public: - LockMessageReader(LLMessageReaderPointer& var, LLMessageReader* instance): - mVar(var.mPtr), - mLock(var.mMutex) - { - mVar = instance; - } - // Some compilers reportedly fail to suppress generating implicit copy - // operations even though we have a move-only LockType data member. - LockMessageReader(const LockMessageReader&) = delete; - LockMessageReader& operator=(const LockMessageReader&) = delete; - ~LockMessageReader() - { - mVar = nullptr; - } -private: - // capture a reference to LLMessageReaderPointer::mPtr - decltype(LLMessageReaderPointer::mPtr)& mVar; - // while holding a lock on LLMessageReaderPointer::mMutex - LLCoros::LockType mLock; -}; - -/** - * LockMessageReader is great as long as you only need mMessageReader locked - * during a single LLMessageSystem function call. However, empirically the - * sequence from checkAllMessages() through processAcks() need mMessageReader - * locked to LLTemplateMessageReader. Enforce that by making them require an - * instance of LockMessageChecker. - */ -class LockMessageChecker; - -class LLMessageSystem : public LLMessageSenderInterface -{ - private: - U8 mSendBuffer[MAX_BUFFER_SIZE]; - S32 mSendSize; - - bool mBlockUntrustedInterface; - LLHost mUntrustedInterface; - - public: - LLPacketRing mPacketRing; - LLReliablePacketParams mReliablePacketParams; - - // Set this flag to TRUE when you want *very* verbose logs. - BOOL mVerboseLog; - - F32 mMessageFileVersionNumber; - - typedef std::map<const char *, LLMessageTemplate*> message_template_name_map_t; - typedef std::map<U32, LLMessageTemplate*> message_template_number_map_t; - -private: - message_template_name_map_t mMessageTemplates; - message_template_number_map_t mMessageNumbers; - -public: - S32 mSystemVersionMajor; - S32 mSystemVersionMinor; - S32 mSystemVersionPatch; - S32 mSystemVersionServer; - U32 mVersionFlags; - - BOOL mbProtected; - - U32 mNumberHighFreqMessages; - U32 mNumberMediumFreqMessages; - U32 mNumberLowFreqMessages; - S32 mPort; - S32 mSocket; - - U32 mPacketsIn; // total packets in, including compressed and uncompressed - U32 mPacketsOut; // total packets out, including compressed and uncompressed - - U64 mBytesIn; // total bytes in, including compressed and uncompressed - U64 mBytesOut; // total bytes out, including compressed and uncompressed - - U32 mCompressedPacketsIn; // total compressed packets in - U32 mCompressedPacketsOut; // total compressed packets out - - U32 mReliablePacketsIn; // total reliable packets in - U32 mReliablePacketsOut; // total reliable packets out - - U32 mDroppedPackets; // total dropped packets in - U32 mResentPackets; // total resent packets out - U32 mFailedResendPackets; // total resend failure packets out - U32 mOffCircuitPackets; // total # of off-circuit packets rejected - U32 mInvalidOnCircuitPackets; // total # of on-circuit but invalid packets rejected - - S64 mUncompressedBytesIn; // total uncompressed size of compressed packets in - S64 mUncompressedBytesOut; // total uncompressed size of compressed packets out - S64 mCompressedBytesIn; // total compressed size of compressed packets in - S64 mCompressedBytesOut; // total compressed size of compressed packets out - S64 mTotalBytesIn; // total size of all uncompressed packets in - S64 mTotalBytesOut; // total size of all uncompressed packets out - - BOOL mSendReliable; // does the outgoing message require a pos ack? - - LLCircuit mCircuitInfo; - F64Seconds mCircuitPrintTime; // used to print circuit debug info every couple minutes - F32Seconds mCircuitPrintFreq; - - std::map<U64, U32> mIPPortToCircuitCode; - std::map<U32, U64> mCircuitCodeToIPPort; - U32 mOurCircuitCode; - S32 mSendPacketFailureCount; - S32 mUnackedListDepth; - S32 mUnackedListSize; - S32 mDSMaxListDepth; - -public: - // Read file and build message templates - LLMessageSystem(const std::string& filename, U32 port, S32 version_major, - S32 version_minor, S32 version_patch, - bool failure_is_fatal, - const F32 circuit_heartbeat_interval, const F32 circuit_timeout); - - ~LLMessageSystem(); - - BOOL isOK() const { return !mbError; } - S32 getErrorCode() const { return mErrorCode; } - - // Read file and build message templates filename must point to a - // valid string which specifies the path of a valid linden - // template. - void loadTemplateFile(const std::string& filename, bool failure_is_fatal); - - - // methods for building, sending, receiving, and handling messages - void setHandlerFuncFast(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data = NULL); - void setHandlerFunc(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data = NULL) - { - setHandlerFuncFast(LLMessageStringTable::getInstance()->getString(name), handler_func, user_data); - } - - // Set a callback function for a message system exception. - void setExceptionFunc(EMessageException exception, msg_exception_callback func, void* data = NULL); - // Call the specified exception func, and return TRUE if a - // function was found and called. Otherwise return FALSE. - BOOL callExceptionFunc(EMessageException exception); - - // Set a function that will be called once per packet processed with the - // hashed message name and the time spent in the processing handler function - // measured in seconds. JC - typedef void (*msg_timing_callback)(const char* hashed_name, F32 time, void* data); - void setTimingFunc(msg_timing_callback func, void* data = NULL); - msg_timing_callback getTimingCallback() - { - return mTimingCallback; - } - void* getTimingCallbackData() - { - return mTimingCallbackData; - } - - // This method returns true if the code is in the circuit codes map. - BOOL isCircuitCodeKnown(U32 code) const; - - // usually called in response to an AddCircuitCode message, but - // may also be called by the login process. - bool addCircuitCode(U32 code, const LLUUID& session_id); - - BOOL poll(F32 seconds); // Number of seconds that we want to block waiting for data, returns if data was received - BOOL checkMessages(LockMessageChecker&, S64 frame_count = 0 ); - void processAcks(LockMessageChecker&, F32 collect_time = 0.f); - - BOOL isMessageFast(const char *msg); - BOOL isMessage(const char *msg) - { - return isMessageFast(LLMessageStringTable::getInstance()->getString(msg)); - } - - void dumpPacketToLog(); - - char *getMessageName(); - - const LLHost& getSender() const; - U32 getSenderIP() const; // getSender() is preferred - U32 getSenderPort() const; // getSender() is preferred - - const LLHost& getReceivingInterface() const; - - // This method returns the uuid associated with the sender. The - // UUID will be null if it is not yet known or is a server - // circuit. - const LLUUID& getSenderID() const; - - // This method returns the session id associated with the last - // sender. - const LLUUID& getSenderSessionID() const; - - // set & get the session id (useful for viewers for now.) - void setMySessionID(const LLUUID& session_id) { mSessionID = session_id; } - const LLUUID& getMySessionID() { return mSessionID; } - - void newMessageFast(const char *name); - void newMessage(const char *name); - - -public: - LLStoredMessagePtr getReceivedMessage() const; - LLStoredMessagePtr getBuiltMessage() const; - S32 sendMessage(const LLHost &host, LLStoredMessagePtr message); - -private: - LLSD getReceivedMessageLLSD() const; - LLSD getBuiltMessageLLSD() const; - - // NOTE: babbage: Only use to support legacy misuse of the - // LLMessageSystem API where values are dangerously written - // as one type and read as another. LLSD does not support - // dangerous conversions and so converting the message to an - // LLSD would result in the reads failing. All code which - // misuses the message system in this way should be made safe - // but while the unsafe code is run in old processes, this - // method should be used to forward unsafe messages. - LLSD wrapReceivedTemplateData() const; - LLSD wrapBuiltTemplateData() const; - -public: - - void copyMessageReceivedToSend(); - void clearMessage(); - - void nextBlockFast(const char *blockname); - void nextBlock(const char *blockname); - -public: - void addBinaryDataFast(const char *varname, const void *data, S32 size); - void addBinaryData(const char *varname, const void *data, S32 size); - - void addBOOLFast( const char* varname, BOOL b); // typed, checks storage space - void addBOOL( const char* varname, BOOL b); // typed, checks storage space - void addS8Fast( const char *varname, S8 s); // typed, checks storage space - void addS8( const char *varname, S8 s); // typed, checks storage space - void addU8Fast( const char *varname, U8 u); // typed, checks storage space - void addU8( const char *varname, U8 u); // typed, checks storage space - void addS16Fast( const char *varname, S16 i); // typed, checks storage space - void addS16( const char *varname, S16 i); // typed, checks storage space - void addU16Fast( const char *varname, U16 i); // typed, checks storage space - void addU16( const char *varname, U16 i); // typed, checks storage space - void addF32Fast( const char *varname, F32 f); // typed, checks storage space - void addF32( const char *varname, F32 f); // typed, checks storage space - void addS32Fast( const char *varname, S32 s); // typed, checks storage space - void addS32( const char *varname, S32 s); // typed, checks storage space - void addU32Fast( const char *varname, U32 u); // typed, checks storage space - void addU32( const char *varname, U32 u); // typed, checks storage space - void addU64Fast( const char *varname, U64 lu); // typed, checks storage space - void addU64( const char *varname, U64 lu); // typed, checks storage space - void addF64Fast( const char *varname, F64 d); // typed, checks storage space - void addF64( const char *varname, F64 d); // typed, checks storage space - void addVector3Fast( const char *varname, const LLVector3& vec); // typed, checks storage space - void addVector3( const char *varname, const LLVector3& vec); // typed, checks storage space - void addVector4Fast( const char *varname, const LLVector4& vec); // typed, checks storage space - void addVector4( const char *varname, const LLVector4& vec); // typed, checks storage space - void addVector3dFast( const char *varname, const LLVector3d& vec); // typed, checks storage space - void addVector3d( const char *varname, const LLVector3d& vec); // typed, checks storage space - void addQuatFast( const char *varname, const LLQuaternion& quat); // typed, checks storage space - void addQuat( const char *varname, const LLQuaternion& quat); // typed, checks storage space - void addUUIDFast( const char *varname, const LLUUID& uuid); // typed, checks storage space - void addUUID( const char *varname, const LLUUID& uuid); // typed, checks storage space - void addIPAddrFast( const char *varname, const U32 ip); // typed, checks storage space - void addIPAddr( const char *varname, const U32 ip); // typed, checks storage space - void addIPPortFast( const char *varname, const U16 port); // typed, checks storage space - void addIPPort( const char *varname, const U16 port); // typed, checks storage space - void addStringFast( const char* varname, const char* s); // typed, checks storage space - void addString( const char* varname, const char* s); // typed, checks storage space - void addStringFast( const char* varname, const std::string& s); // typed, checks storage space - void addString( const char* varname, const std::string& s); // typed, checks storage space - - S32 getCurrentSendTotal() const; - TPACKETID getCurrentRecvPacketID() { return mCurrentRecvPacketID; } - - // This method checks for current send total and returns true if - // you need to go to the next block type or need to start a new - // message. Specify the current blockname to check block counts, - // otherwise the method only checks against MTU. - BOOL isSendFull(const char* blockname = NULL); - BOOL isSendFullFast(const char* blockname = NULL); - - BOOL removeLastBlock(); - - //void buildMessage(); - - S32 zeroCode(U8 **data, S32 *data_size); - S32 zeroCodeExpand(U8 **data, S32 *data_size); - S32 zeroCodeAdjustCurrentSendTotal(); - - // Uses ping-based retry - S32 sendReliable(const LLHost &host); - - // Uses ping-based retry - S32 sendReliable(const U32 circuit) { return sendReliable(findHost(circuit)); } - - // Use this one if you DON'T want automatic ping-based retry. - S32 sendReliable( const LLHost &host, - S32 retries, - BOOL ping_based_retries, - F32Seconds timeout, - void (*callback)(void **,S32), - void ** callback_data); - - S32 sendSemiReliable( const LLHost &host, - void (*callback)(void **,S32), void ** callback_data); - - // flush sends a message only if data's been pushed on it. - S32 flushSemiReliable( const LLHost &host, - void (*callback)(void **,S32), void ** callback_data); - - S32 flushReliable( const LLHost &host ); - - void forwardMessage(const LLHost &host); - void forwardReliable(const LLHost &host); - void forwardReliable(const U32 circuit_code); - S32 forwardReliable( - const LLHost &host, - S32 retries, - BOOL ping_based_timeout, - F32Seconds timeout, - void (*callback)(void **,S32), - void ** callback_data); - - S32 sendMessage(const LLHost &host); - S32 sendMessage(const U32 circuit); -private: - S32 sendMessage(const LLHost &host, const char* name, - const LLSD& message); -public: - // BOOL decodeData(const U8 *buffer, const LLHost &host); - - /** - gets binary data from the current message. - - @param blockname the name of the block in the message (from the message template) - - @param varname - - @param datap - - @param size expected size - set to zero to get any amount of data up to max_size. - Make sure max_size is set in that case! - - @param blocknum - - @param max_size the max number of bytes to read - */ - void getBinaryDataFast(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX); - void getBinaryData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX); - void getBOOLFast( const char *block, const char *var, BOOL &data, S32 blocknum = 0); - void getBOOL( const char *block, const char *var, BOOL &data, S32 blocknum = 0); - void getS8Fast( const char *block, const char *var, S8 &data, S32 blocknum = 0); - void getS8( const char *block, const char *var, S8 &data, S32 blocknum = 0); - void getU8Fast( const char *block, const char *var, U8 &data, S32 blocknum = 0); - void getU8( const char *block, const char *var, U8 &data, S32 blocknum = 0); - void getS16Fast( const char *block, const char *var, S16 &data, S32 blocknum = 0); - void getS16( const char *block, const char *var, S16 &data, S32 blocknum = 0); - void getU16Fast( const char *block, const char *var, U16 &data, S32 blocknum = 0); - void getU16( const char *block, const char *var, U16 &data, S32 blocknum = 0); - void getS32Fast( const char *block, const char *var, S32 &data, S32 blocknum = 0); - void getS32( const char *block, const char *var, S32 &data, S32 blocknum = 0); - void getF32Fast( const char *block, const char *var, F32 &data, S32 blocknum = 0); - void getF32( const char *block, const char *var, F32 &data, S32 blocknum = 0); - void getU32Fast( const char *block, const char *var, U32 &data, S32 blocknum = 0); - void getU32( const char *block, const char *var, U32 &data, S32 blocknum = 0); - void getU64Fast( const char *block, const char *var, U64 &data, S32 blocknum = 0); - void getU64( const char *block, const char *var, U64 &data, S32 blocknum = 0); - void getF64Fast( const char *block, const char *var, F64 &data, S32 blocknum = 0); - void getF64( const char *block, const char *var, F64 &data, S32 blocknum = 0); - void getVector3Fast( const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0); - void getVector3( const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0); - void getVector4Fast( const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0); - void getVector4( const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0); - void getVector3dFast(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0); - void getVector3d(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0); - void getQuatFast( const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0); - void getQuat( const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0); - void getUUIDFast( const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0); - void getUUID( const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0); - void getIPAddrFast( const char *block, const char *var, U32 &ip, S32 blocknum = 0); - void getIPAddr( const char *block, const char *var, U32 &ip, S32 blocknum = 0); - void getIPPortFast( const char *block, const char *var, U16 &port, S32 blocknum = 0); - void getIPPort( const char *block, const char *var, U16 &port, S32 blocknum = 0); - void getStringFast( const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0); - void getString( const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0); - void getStringFast( const char *block, const char *var, std::string& outstr, S32 blocknum = 0); - void getString( const char *block, const char *var, std::string& outstr, S32 blocknum = 0); - - - // Utility functions to generate a replay-resistant digest check - // against the shared secret. The window specifies how much of a - // time window is allowed - 1 second is good for tight - // connections, but multi-process windows might want to be upwards - // of 5 seconds. For generateDigest, you want to pass in a - // character array of at least MD5HEX_STR_SIZE so that the hex - // digest and null termination will fit. - bool generateDigestForNumberAndUUIDs(char* digest, const U32 number, const LLUUID &id1, const LLUUID &id2) const; - bool generateDigestForWindowAndUUIDs(char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const; - bool isMatchingDigestForWindowAndUUIDs(const char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const; - - bool generateDigestForNumber(char* digest, const U32 number) const; - bool generateDigestForWindow(char* digest, const S32 window) const; - bool isMatchingDigestForWindow(const char* digest, const S32 window) const; - - void showCircuitInfo(); - void getCircuitInfo(LLSD& info) const; - - U32 getOurCircuitCode(); - - void enableCircuit(const LLHost &host, BOOL trusted); - void disableCircuit(const LLHost &host); - - // Use this to establish trust on startup and in response to - // DenyTrustedCircuit. - void sendCreateTrustedCircuit(const LLHost& host, const LLUUID & id1, const LLUUID & id2); - - // Use this to inform a peer that they aren't currently trusted... - // This now enqueues the request so that we can ensure that we only send - // one deny per circuit per message loop so that this doesn't become a DoS. - // The actual sending is done by reallySendDenyTrustedCircuit() - void sendDenyTrustedCircuit(const LLHost &host); - - /** Return false if host is unknown or untrusted */ - // Note:DaveH/Babbage some trusted messages can be received without a circuit - bool isTrustedSender(const LLHost& host) const; - - /** Return true if current message is from trusted source */ - bool isTrustedSender() const; - - /** Return false true if name is unknown or untrusted */ - bool isTrustedMessage(const std::string& name) const; - - /** Return false true if name is unknown or trusted */ - bool isUntrustedMessage(const std::string& name) const; - - // Mark an interface ineligible for trust - void setUntrustedInterface( const LLHost host ) { mUntrustedInterface = host; } - LLHost getUntrustedInterface() const { return mUntrustedInterface; } - void setBlockUntrustedInterface( bool block ) { mBlockUntrustedInterface = block; } // Throw a switch to allow, sending warnings only - bool getBlockUntrustedInterface() const { return mBlockUntrustedInterface; } - - // Change this message to be UDP black listed. - void banUdpMessage(const std::string& name); - - -private: - // A list of the circuits that need to be sent DenyTrustedCircuit messages. - typedef std::set<LLHost> host_set_t; - host_set_t mDenyTrustedCircuitSet; - - // Really sends the DenyTrustedCircuit message to a given host - // related to sendDenyTrustedCircuit() - void reallySendDenyTrustedCircuit(const LLHost &host); - -public: - // Use this to establish trust to and from a host. This blocks - // until trust has been established, and probably should only be - // used on startup. - void establishBidirectionalTrust(const LLHost &host, S64 frame_count = 0); - - // returns whether the given host is on a trusted circuit - // Note:DaveH/Babbage some trusted messages can be received without a circuit - BOOL getCircuitTrust(const LLHost &host); - - void setCircuitAllowTimeout(const LLHost &host, BOOL allow); - void setCircuitTimeoutCallback(const LLHost &host, void (*callback_func)(const LLHost &host, void *user_data), void *user_data); - - BOOL checkCircuitBlocked(const U32 circuit); - BOOL checkCircuitAlive(const U32 circuit); - BOOL checkCircuitAlive(const LLHost &host); - void setCircuitProtection(BOOL b_protect); - U32 findCircuitCode(const LLHost &host); - LLHost findHost(const U32 circuit_code); - void sanityCheck(); - - BOOL has(const char *blockname) const; - S32 getNumberOfBlocksFast(const char *blockname) const; - S32 getNumberOfBlocks(const char *blockname) const; - S32 getSizeFast(const char *blockname, const char *varname) const; - S32 getSize(const char *blockname, const char *varname) const; - S32 getSizeFast(const char *blockname, S32 blocknum, - const char *varname) const; // size in bytes of data - S32 getSize(const char *blockname, S32 blocknum, const char *varname) const; - - void resetReceiveCounts(); // resets receive counts for all message types to 0 - void dumpReceiveCounts(); // dumps receive count for each message type to LL_INFOS() - void dumpCircuitInfo(); // Circuit information to LL_INFOS() - - BOOL isClear() const; // returns mbSClear; - S32 flush(const LLHost &host); - - U32 getListenPort( void ) const; - - void startLogging(); // start verbose logging - void stopLogging(); // flush and close file - void summarizeLogs(std::ostream& str); // log statistics - - S32 getReceiveSize() const; - S32 getReceiveCompressedSize() const { return mIncomingCompressedSize; } - S32 getReceiveBytes() const; - - S32 getUnackedListSize() const { return mUnackedListSize; } - - //const char* getCurrentSMessageName() const { return mCurrentSMessageName; } - //const char* getCurrentSBlockName() const { return mCurrentSBlockName; } - - // friends - friend std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg); - - void setMaxMessageTime(const F32 seconds); // Max time to process messages before warning and dumping (neg to disable) - void setMaxMessageCounts(const S32 num); // Max number of messages before dumping (neg to disable) - - static U64Microseconds getMessageTimeUsecs(const BOOL update = FALSE); // Get the current message system time in microseconds - static F64Seconds getMessageTimeSeconds(const BOOL update = FALSE); // Get the current message system time in seconds - - static void setTimeDecodes(BOOL b); - static void setTimeDecodesSpamThreshold(F32 seconds); - - // message handlers internal to the message systesm - //static void processAssignCircuitCode(LLMessageSystem* msg, void**); - static void processAddCircuitCode(LLMessageSystem* msg, void**); - static void processUseCircuitCode(LLMessageSystem* msg, void**); - static void processError(LLMessageSystem* msg, void**); - - // dispatch llsd message to http node tree - static void dispatch(const std::string& msg_name, - const LLSD& message); - static void dispatch(const std::string& msg_name, - const LLSD& message, - LLHTTPNode::ResponsePtr responsep); - - // this is added to support specific legacy messages and is - // ***not intended for general use*** Si, Gabriel, 2009 - static void dispatchTemplate(const std::string& msg_name, - const LLSD& message, - LLHTTPNode::ResponsePtr responsep); - - void setMessageBans(const LLSD& trusted, const LLSD& untrusted); - - /** - * @brief send an error message to the host. This is a helper method. - * - * @param host Destination host. - * @param agent_id Destination agent id (may be null) - * @param code An HTTP status compatible error code. - * @param token A specific short string based message - * @param id The transactionid/uniqueid/sessionid whatever. - * @param system The hierarchical path to the system (255 bytes) - * @param message Human readable message (1200 bytes) - * @param data Extra info. - * @return Returns value returned from sendReliable(). - */ - S32 sendError( - const LLHost& host, - const LLUUID& agent_id, - S32 code, - const std::string& token, - const LLUUID& id, - const std::string& system, - const std::string& message, - const LLSD& data); - - // Check UDP messages and pump http_pump to receive HTTP messages. - bool checkAllMessages(LockMessageChecker&, S64 frame_count, LLPumpIO* http_pump); - - // Moved to allow access from LLTemplateMessageDispatcher - void clearReceiveState(); - - // This will cause all trust queries to return true until the next message - // is read: use with caution! - void receivedMessageFromTrustedSender(); - -private: - typedef boost::function<void(S32)> UntrustedCallback_t; - void sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback); - - - bool mLastMessageFromTrustedMessageService; - - // The mCircuitCodes is a map from circuit codes to session - // ids. This allows us to verify sessions on connect. - typedef std::map<U32, LLUUID> code_session_map_t; - code_session_map_t mCircuitCodes; - - // Viewers need to track a process session in order to make sure - // that no one gives them a bad circuit code. - LLUUID mSessionID; - - void addTemplate(LLMessageTemplate *templatep); - BOOL decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template ); - - void logMsgFromInvalidCircuit( const LLHost& sender, BOOL recv_reliable ); - void logTrustedMsgFromUntrustedCircuit( const LLHost& sender ); - void logValidMsg(LLCircuitData *cdp, const LLHost& sender, BOOL recv_reliable, BOOL recv_resent, BOOL recv_acks ); - void logRanOffEndOfPacket( const LLHost& sender ); - - class LLMessageCountInfo - { - public: - U32 mMessageNum; - U32 mMessageBytes; - BOOL mInvalid; - }; - - LLMessagePollInfo *mPollInfop; - - U8 mEncodedRecvBuffer[MAX_BUFFER_SIZE]; - U8 mTrueReceiveBuffer[MAX_BUFFER_SIZE]; - S32 mTrueReceiveSize; - - // Must be valid during decode - - BOOL mbError; - S32 mErrorCode; - - F64Seconds mResendDumpTime; // The last time we dumped resends - - LLMessageCountInfo mMessageCountList[MAX_MESSAGE_COUNT_NUM]; - S32 mNumMessageCounts; - F32Seconds mReceiveTime; - F32Seconds mMaxMessageTime; // Max number of seconds for processing messages - S32 mMaxMessageCounts; // Max number of messages to process before dumping. - F64Seconds mMessageCountTime; - - F64Seconds mCurrentMessageTime; // The current "message system time" (updated the first call to checkMessages after a resetReceiveCount - - // message system exceptions - typedef std::pair<msg_exception_callback, void*> exception_t; - typedef std::map<EMessageException, exception_t> callbacks_t; - callbacks_t mExceptionCallbacks; - - // stuff for logging - LLTimer mMessageSystemTimer; - - static F32 mTimeDecodesSpamThreshold; // If mTimeDecodes is on, all this many seconds for each msg decode before spamming - static BOOL mTimeDecodes; // Measure time for all message decodes if TRUE; - - msg_timing_callback mTimingCallback; - void* mTimingCallbackData; - - void init(); // ctor shared initialisation. - - LLHost mLastSender; - LLHost mLastReceivingIF; - S32 mIncomingCompressedSize; // original size of compressed msg (0 if uncomp.) - TPACKETID mCurrentRecvPacketID; // packet ID of current receive packet (for reporting) - - LLMessageBuilder* mMessageBuilder; - LLTemplateMessageBuilder* mTemplateMessageBuilder; - LLSDMessageBuilder* mLLSDMessageBuilder; - LLMessageReaderPointer mMessageReader; - LLTemplateMessageReader* mTemplateMessageReader; - LLSDMessageReader* mLLSDMessageReader; - - friend class LLMessageHandlerBridge; - friend class LockMessageChecker; - - bool callHandler(const char *name, bool trustedSource, - LLMessageSystem* msg); - - - /** Find, create or revive circuit for host as needed */ - LLCircuitData* findCircuit(const LLHost& host, bool resetPacketId); -}; - - -// external hook into messaging system -extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; - -// Implementation of LockMessageChecker depends on definition of -// LLMessageSystem, hence must follow it. -class LockMessageChecker: public LockMessageReader -{ -public: - LockMessageChecker(LLMessageSystem* msgsystem); - - // For convenience, provide forwarding wrappers so you can call (e.g.) - // checkAllMessages() on your LockMessageChecker instance instead of - // passing the instance to LLMessageSystem::checkAllMessages(). Use - // perfect forwarding to avoid having to maintain these wrappers in sync - // with the target methods. - template <typename... ARGS> - bool checkAllMessages(ARGS&&... args) - { - return mMessageSystem->checkAllMessages(*this, std::forward<ARGS>(args)...); - } - - template <typename... ARGS> - bool checkMessages(ARGS&&... args) - { - return mMessageSystem->checkMessages(*this, std::forward<ARGS>(args)...); - } - - template <typename... ARGS> - void processAcks(ARGS&&... args) - { - return mMessageSystem->processAcks(*this, std::forward<ARGS>(args)...); - } - -private: - LLMessageSystem* mMessageSystem; -}; - -// Must specific overall system version, which is used to determine -// if a patch is available in the message template checksum verification. -// Return true if able to initialize system. -bool start_messaging_system( - const std::string& template_name, - U32 port, - S32 version_major, - S32 version_minor, - S32 version_patch, - bool b_dump_prehash_file, - const std::string& secret, - const LLUseCircuitCodeResponder* responder, - bool failure_is_fatal, - const F32 circuit_heartbeat_interval, - const F32 circuit_timeout); - -void end_messaging_system(bool print_summary = true); - -void null_message_callback(LLMessageSystem *msg, void **data); - -// -// Inlines -// - -#if !defined( LL_BIG_ENDIAN ) && !defined( LL_LITTLE_ENDIAN ) -#error Unknown endianness for htolememcpy. Did you miss a common include? -#endif - -static inline void *htolememcpy(void *vs, const void *vct, EMsgVariableType type, size_t n) -{ - char *s = (char *)vs; - const char *ct = (const char *)vct; -#ifdef LL_BIG_ENDIAN - S32 i, length; -#endif - switch(type) - { - case MVT_FIXED: - case MVT_VARIABLE: - case MVT_U8: - case MVT_S8: - case MVT_BOOL: - case MVT_LLUUID: - case MVT_IP_ADDR: // these two are swizzled in the getters and setters - case MVT_IP_PORT: // these two are swizzled in the getters and setters - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ - - case MVT_U16: - case MVT_S16: - if (n != 2) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - *(s + 1) = *(ct); - *(s) = *(ct + 1); - return(vs); -#else - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ -#endif - - case MVT_U32: - case MVT_S32: - case MVT_F32: - if (n != 4) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - *(s + 3) = *(ct); - *(s + 2) = *(ct + 1); - *(s + 1) = *(ct + 2); - *(s) = *(ct + 3); - return(vs); -#else - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ -#endif - - case MVT_U64: - case MVT_S64: - case MVT_F64: - if (n != 8) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - *(s + 7) = *(ct); - *(s + 6) = *(ct + 1); - *(s + 5) = *(ct + 2); - *(s + 4) = *(ct + 3); - *(s + 3) = *(ct + 4); - *(s + 2) = *(ct + 5); - *(s + 1) = *(ct + 6); - *(s) = *(ct + 7); - return(vs); -#else - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ -#endif - - case MVT_LLVector3: - case MVT_LLQuaternion: // We only send x, y, z and infer w (we set x, y, z to ensure that w >= 0) - if (n != 12) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - htolememcpy(s + 8, ct + 8, MVT_F32, 4); - htolememcpy(s + 4, ct + 4, MVT_F32, 4); - return(htolememcpy(s, ct, MVT_F32, 4)); -#else - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ -#endif - - case MVT_LLVector3d: - if (n != 24) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - htolememcpy(s + 16, ct + 16, MVT_F64, 8); - htolememcpy(s + 8, ct + 8, MVT_F64, 8); - return(htolememcpy(s, ct, MVT_F64, 8)); -#else - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ -#endif - - case MVT_LLVector4: - if (n != 16) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - htolememcpy(s + 12, ct + 12, MVT_F32, 4); - htolememcpy(s + 8, ct + 8, MVT_F32, 4); - htolememcpy(s + 4, ct + 4, MVT_F32, 4); - return(htolememcpy(s, ct, MVT_F32, 4)); -#else - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ -#endif - - case MVT_U16Vec3: - if (n != 6) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - htolememcpy(s + 4, ct + 4, MVT_U16, 2); - htolememcpy(s + 2, ct + 2, MVT_U16, 2); - return(htolememcpy(s, ct, MVT_U16, 2)); -#else - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ -#endif - - case MVT_U16Quat: - if (n != 8) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - htolememcpy(s + 6, ct + 6, MVT_U16, 2); - htolememcpy(s + 4, ct + 4, MVT_U16, 2); - htolememcpy(s + 2, ct + 2, MVT_U16, 2); - return(htolememcpy(s, ct, MVT_U16, 2)); -#else - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ -#endif - - case MVT_S16Array: - if (n % 2) - { - LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; - } -#ifdef LL_BIG_ENDIAN - length = n % 2; - for (i = 1; i < length; i++) - { - htolememcpy(s + i*2, ct + i*2, MVT_S16, 2); - } - return(htolememcpy(s, ct, MVT_S16, 2)); -#else - return(memcpy(s,ct,n)); -#endif - - default: - return(memcpy(s,ct,n)); /* Flawfinder: ignore */ - } -} - -inline void *ntohmemcpy(void *s, const void *ct, EMsgVariableType type, size_t n) -{ - return(htolememcpy(s,ct,type, n)); -} - -inline const LLHost& LLMessageSystem::getReceivingInterface() const {return mLastReceivingIF;} - -inline U32 LLMessageSystem::getSenderIP() const -{ - return mLastSender.getAddress(); -} - -inline U32 LLMessageSystem::getSenderPort() const -{ - return mLastSender.getPort(); -} - - -//----------------------------------------------------------------------------- -// Transmission aliases -//----------------------------------------------------------------------------- - -inline S32 LLMessageSystem::sendMessage(const U32 circuit) -{ - return sendMessage(findHost(circuit)); -} - -#endif +/**
+ * @file message.h
+ * @brief LLMessageSystem class header file
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_MESSAGE_H
+#define LL_MESSAGE_H
+
+#include <cstring>
+#include <set>
+
+#if LL_LINUX
+#include <endian.h>
+#include <netinet/in.h>
+#endif
+
+#if LL_WINDOWS
+#include "winsock2.h" // htons etc.
+#endif
+
+#include "llerror.h"
+#include "net.h"
+#include "llstringtable.h"
+#include "llcircuit.h"
+#include "lltimer.h"
+#include "llpacketring.h"
+#include "llhost.h"
+#include "llhttpnode.h"
+//#include "llpacketack.h"
+#include "llsingleton.h"
+#include "message_prehash.h"
+#include "llstl.h"
+#include "llmsgvariabletype.h"
+#include "llmessagesenderinterface.h"
+
+#include "llstoredmessage.h"
+#include "boost/function.hpp"
+#include "llpounceable.h"
+#include "llcoros.h"
+#include LLCOROS_MUTEX_HEADER
+
+const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
+const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
+
+const S32 MESSAGE_MAX_PER_FRAME = 400;
+
+class LLMessageStringTable : public LLSingleton<LLMessageStringTable>
+{
+ LLSINGLETON(LLMessageStringTable);
+ ~LLMessageStringTable();
+
+public:
+ char *getString(const char *str);
+
+ U32 mUsed;
+ bool mEmpty[MESSAGE_NUMBER_OF_HASH_BUCKETS];
+ char mString[MESSAGE_NUMBER_OF_HASH_BUCKETS][MESSAGE_MAX_STRINGS_LENGTH]; /* Flawfinder: ignore */
+};
+
+
+// Individual Messages are described with the following format
+// Note that to ease parsing, keywords are used
+//
+// // Comment (Comment like a C++ single line comment)
+// Comments can only be placed between Messages
+// {
+// MessageName (same naming restrictions as C variable)
+// Frequency ("High", "Medium", or "Low" - determines whether message ID is 8, 16, or 32-bits --
+// there can 254 messages in the first 2 groups, 32K in the last group)
+// (A message can be made up only of the Name if it is only a signal)
+// Trust ("Trusted", "NotTrusted" - determines if a message will be accepted
+// on a circuit. "Trusted" messages are not accepted from NotTrusted circuits
+// while NotTrusted messages are accepted on any circuit. An example of a
+// NotTrusted circuit is any circuit from the viewer.)
+// Encoding ("Zerocoded", "Unencoded" - zerocoded messages attempt to compress sequences of
+// zeros, but if there is no space win, it discards the compression and goes unencoded)
+// {
+// Block Name (same naming restrictions as C variable)
+// Block Type ("Single", "Multiple", or "Variable" - determines if the block is coded once,
+// a known number of times, or has a 8 bit argument encoded to tell the decoder
+// how many times the group is repeated)
+// Block Repeat Number (Optional - used only with the "Multiple" type - tells how many times the field is repeated
+// {
+// Variable 1 Name (same naming restrictions as C variable)
+// Variable Type ("Fixed" or "Variable" - determines if the variable is of fixed size or needs to
+// encode an argument describing the size in bytes)
+// Variable Size (In bytes, either of the "Fixed" variable itself or of the size argument)
+//
+// repeat variables
+//
+// }
+//
+// Repeat for number of variables in block
+// }
+//
+// Repeat for number of blocks in message
+// }
+// Repeat for number of messages in file
+//
+
+// Constants
+const S32 MAX_MESSAGE_INTERNAL_NAME_SIZE = 255;
+const S32 MAX_BUFFER_SIZE = NET_BUFFER_SIZE;
+const S32 MAX_BLOCKS = 255;
+
+const U8 LL_ZERO_CODE_FLAG = 0x80;
+const U8 LL_RELIABLE_FLAG = 0x40;
+const U8 LL_RESENT_FLAG = 0x20;
+const U8 LL_ACK_FLAG = 0x10;
+
+// 1 byte flags, 4 bytes sequence, 1 byte offset + 1 byte message name (high)
+const S32 LL_MINIMUM_VALID_PACKET_SIZE = LL_PACKET_ID_SIZE + 1;
+enum EPacketHeaderLayout
+{
+ PHL_FLAGS = 0,
+ PHL_PACKET_ID = 1,
+ PHL_OFFSET = 5,
+ PHL_NAME = 6
+};
+
+
+const S32 LL_DEFAULT_RELIABLE_RETRIES = 3;
+const F32Seconds LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS(1.f);
+const F32Seconds LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS(1.f);
+const F32Seconds LL_PING_BASED_TIMEOUT_DUMMY(0.0f);
+
+const F32 LL_SEMIRELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping
+const F32 LL_RELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping
+const F32 LL_LOST_TIMEOUT_FACTOR = 16.f; // averaged ping for marking packets "Lost"
+const F32Seconds LL_MAX_LOST_TIMEOUT(5.f); // Maximum amount of time before considering something "lost"
+
+const S32 MAX_MESSAGE_COUNT_NUM = 1024;
+
+// Forward declarations
+class LLVector3;
+class LLVector4;
+class LLVector3d;
+class LLQuaternion;
+class LLSD;
+class LLUUID;
+class LLMessageSystem;
+class LLPumpIO;
+
+// message system exceptional condition handlers.
+enum EMessageException
+{
+ MX_UNREGISTERED_MESSAGE, // message number not part of template
+ MX_PACKET_TOO_SHORT, // invalid packet, shorter than minimum packet size
+ MX_RAN_OFF_END_OF_PACKET, // ran off the end of the packet during decode
+ MX_WROTE_PAST_BUFFER_SIZE // wrote past buffer size in zero code expand
+};
+typedef void (*msg_exception_callback)(LLMessageSystem*,void*,EMessageException);
+
+
+// message data pieces are used to collect the data called for by the message template
+class LLMsgData;
+class LLMsgBlkData;
+class LLMessageTemplate;
+
+class LLMessagePollInfo;
+class LLMessageBuilder;
+class LLTemplateMessageBuilder;
+class LLSDMessageBuilder;
+class LLMessageReader;
+class LLTemplateMessageReader;
+class LLSDMessageReader;
+
+
+
+class LLUseCircuitCodeResponder
+{
+ LOG_CLASS(LLMessageSystem);
+
+public:
+ virtual ~LLUseCircuitCodeResponder();
+ virtual void complete(const LLHost& host, const LLUUID& agent) const = 0;
+};
+
+/**
+ * SL-12204: We've observed crashes when consumer code sets
+ * LLMessageSystem::mMessageReader, assuming that all subsequent processing of
+ * the current message will use the same mMessageReader value -- only to have
+ * a different coroutine sneak in and replace mMessageReader before
+ * completion. This is a limitation of sharing a stateful global resource for
+ * message parsing; instead code receiving a new message should instantiate a
+ * (trivially constructed) local message parser and use that.
+ *
+ * Until then, when one coroutine sets a particular LLMessageReader subclass
+ * as the current message reader, ensure that no other coroutine can replace
+ * it until the first coroutine has finished with its message.
+ *
+ * This is achieved with two helper classes. LLMessageSystem::mMessageReader
+ * is now an LLMessageReaderPointer instance, which can efficiently compare or
+ * dereference its contained LLMessageReader* but which cannot be directly
+ * assigned. To change the value of LLMessageReaderPointer, you must
+ * instantiate LockMessageReader with the LLMessageReader* you wish to make
+ * current. mMessageReader will have that value for the lifetime of the
+ * LockMessageReader instance, then revert to nullptr. Moreover, as its name
+ * implies, LockMessageReader locks the mutex in LLMessageReaderPointer so
+ * that any other coroutine instantiating LockMessageReader will block until
+ * the first coroutine has destroyed its instance.
+ */
+class LLMessageReaderPointer
+{
+public:
+ LLMessageReaderPointer(): mPtr(nullptr) {}
+ // It is essential that comparison and dereferencing must be fast, which
+ // is why we don't check for nullptr when dereferencing.
+ LLMessageReader* operator->() const { return mPtr; }
+ bool operator==(const LLMessageReader* other) const { return mPtr == other; }
+ bool operator!=(const LLMessageReader* other) const { return ! (*this == other); }
+private:
+ // Only LockMessageReader can set mPtr.
+ friend class LockMessageReader;
+ LLMessageReader* mPtr;
+ LLCoros::Mutex mMutex;
+};
+
+/**
+ * To set mMessageReader to nullptr:
+ *
+ * @code
+ * // use an anonymous instance that is destroyed immediately
+ * LockMessageReader(gMessageSystem->mMessageReader, nullptr);
+ * @endcode
+ *
+ * Why do we still require going through LockMessageReader at all? Because it
+ * would be Bad if any coroutine set mMessageReader to nullptr while another
+ * coroutine was still parsing a message.
+ */
+class LockMessageReader
+{
+public:
+ LockMessageReader(LLMessageReaderPointer& var, LLMessageReader* instance):
+ mVar(var.mPtr),
+ mLock(var.mMutex)
+ {
+ mVar = instance;
+ }
+ // Some compilers reportedly fail to suppress generating implicit copy
+ // operations even though we have a move-only LockType data member.
+ LockMessageReader(const LockMessageReader&) = delete;
+ LockMessageReader& operator=(const LockMessageReader&) = delete;
+ ~LockMessageReader()
+ {
+ mVar = nullptr;
+ }
+private:
+ // capture a reference to LLMessageReaderPointer::mPtr
+ decltype(LLMessageReaderPointer::mPtr)& mVar;
+ // while holding a lock on LLMessageReaderPointer::mMutex
+ LLCoros::LockType mLock;
+};
+
+/**
+ * LockMessageReader is great as long as you only need mMessageReader locked
+ * during a single LLMessageSystem function call. However, empirically the
+ * sequence from checkAllMessages() through processAcks() need mMessageReader
+ * locked to LLTemplateMessageReader. Enforce that by making them require an
+ * instance of LockMessageChecker.
+ */
+class LockMessageChecker;
+
+class LLMessageSystem : public LLMessageSenderInterface
+{
+ private:
+ U8 mSendBuffer[MAX_BUFFER_SIZE];
+ S32 mSendSize;
+
+ bool mBlockUntrustedInterface;
+ LLHost mUntrustedInterface;
+
+ public:
+ LLPacketRing mPacketRing;
+ LLReliablePacketParams mReliablePacketParams;
+
+ // Set this flag to true when you want *very* verbose logs.
+ bool mVerboseLog;
+
+ F32 mMessageFileVersionNumber;
+
+ typedef std::map<const char *, LLMessageTemplate*> message_template_name_map_t;
+ typedef std::map<U32, LLMessageTemplate*> message_template_number_map_t;
+
+private:
+ message_template_name_map_t mMessageTemplates;
+ message_template_number_map_t mMessageNumbers;
+
+public:
+ S32 mSystemVersionMajor;
+ S32 mSystemVersionMinor;
+ S32 mSystemVersionPatch;
+ S32 mSystemVersionServer;
+ U32 mVersionFlags;
+
+ bool mbProtected;
+
+ U32 mNumberHighFreqMessages;
+ U32 mNumberMediumFreqMessages;
+ U32 mNumberLowFreqMessages;
+ S32 mPort;
+ S32 mSocket;
+
+ U32 mPacketsIn; // total packets in, including compressed and uncompressed
+ U32 mPacketsOut; // total packets out, including compressed and uncompressed
+
+ U64 mBytesIn; // total bytes in, including compressed and uncompressed
+ U64 mBytesOut; // total bytes out, including compressed and uncompressed
+
+ U32 mCompressedPacketsIn; // total compressed packets in
+ U32 mCompressedPacketsOut; // total compressed packets out
+
+ U32 mReliablePacketsIn; // total reliable packets in
+ U32 mReliablePacketsOut; // total reliable packets out
+
+ U32 mDroppedPackets; // total dropped packets in
+ U32 mResentPackets; // total resent packets out
+ U32 mFailedResendPackets; // total resend failure packets out
+ U32 mOffCircuitPackets; // total # of off-circuit packets rejected
+ U32 mInvalidOnCircuitPackets; // total # of on-circuit but invalid packets rejected
+
+ S64 mUncompressedBytesIn; // total uncompressed size of compressed packets in
+ S64 mUncompressedBytesOut; // total uncompressed size of compressed packets out
+ S64 mCompressedBytesIn; // total compressed size of compressed packets in
+ S64 mCompressedBytesOut; // total compressed size of compressed packets out
+ S64 mTotalBytesIn; // total size of all uncompressed packets in
+ S64 mTotalBytesOut; // total size of all uncompressed packets out
+
+ bool mSendReliable; // does the outgoing message require a pos ack?
+
+ LLCircuit mCircuitInfo;
+ F64Seconds mCircuitPrintTime; // used to print circuit debug info every couple minutes
+ F32Seconds mCircuitPrintFreq;
+
+ std::map<U64, U32> mIPPortToCircuitCode;
+ std::map<U32, U64> mCircuitCodeToIPPort;
+ U32 mOurCircuitCode;
+ S32 mSendPacketFailureCount;
+ S32 mUnackedListDepth;
+ S32 mUnackedListSize;
+ S32 mDSMaxListDepth;
+
+public:
+ // Read file and build message templates
+ LLMessageSystem(const std::string& filename, U32 port, S32 version_major,
+ S32 version_minor, S32 version_patch,
+ bool failure_is_fatal,
+ const F32 circuit_heartbeat_interval, const F32 circuit_timeout);
+
+ ~LLMessageSystem();
+
+ bool isOK() const { return !mbError; }
+ S32 getErrorCode() const { return mErrorCode; }
+
+ // Read file and build message templates filename must point to a
+ // valid string which specifies the path of a valid linden
+ // template.
+ void loadTemplateFile(const std::string& filename, bool failure_is_fatal);
+
+
+ // methods for building, sending, receiving, and handling messages
+ void setHandlerFuncFast(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data = NULL);
+ void setHandlerFunc(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data = NULL)
+ {
+ setHandlerFuncFast(LLMessageStringTable::getInstance()->getString(name), handler_func, user_data);
+ }
+
+ // Set a callback function for a message system exception.
+ void setExceptionFunc(EMessageException exception, msg_exception_callback func, void* data = NULL);
+ // Call the specified exception func, and return true if a
+ // function was found and called. Otherwise return false.
+ bool callExceptionFunc(EMessageException exception);
+
+ // Set a function that will be called once per packet processed with the
+ // hashed message name and the time spent in the processing handler function
+ // measured in seconds. JC
+ typedef void (*msg_timing_callback)(const char* hashed_name, F32 time, void* data);
+ void setTimingFunc(msg_timing_callback func, void* data = NULL);
+ msg_timing_callback getTimingCallback()
+ {
+ return mTimingCallback;
+ }
+ void* getTimingCallbackData()
+ {
+ return mTimingCallbackData;
+ }
+
+ // This method returns true if the code is in the circuit codes map.
+ bool isCircuitCodeKnown(U32 code) const;
+
+ // usually called in response to an AddCircuitCode message, but
+ // may also be called by the login process.
+ bool addCircuitCode(U32 code, const LLUUID& session_id);
+
+ bool poll(F32 seconds); // Number of seconds that we want to block waiting for data, returns if data was received
+ bool checkMessages(LockMessageChecker&, S64 frame_count = 0 );
+ void processAcks(LockMessageChecker&, F32 collect_time = 0.f);
+
+ bool isMessageFast(const char *msg);
+ bool isMessage(const char *msg)
+ {
+ return isMessageFast(LLMessageStringTable::getInstance()->getString(msg));
+ }
+
+ void dumpPacketToLog();
+
+ char *getMessageName();
+
+ const LLHost& getSender() const;
+ U32 getSenderIP() const; // getSender() is preferred
+ U32 getSenderPort() const; // getSender() is preferred
+
+ const LLHost& getReceivingInterface() const;
+
+ // This method returns the uuid associated with the sender. The
+ // UUID will be null if it is not yet known or is a server
+ // circuit.
+ const LLUUID& getSenderID() const;
+
+ // This method returns the session id associated with the last
+ // sender.
+ const LLUUID& getSenderSessionID() const;
+
+ // set & get the session id (useful for viewers for now.)
+ void setMySessionID(const LLUUID& session_id) { mSessionID = session_id; }
+ const LLUUID& getMySessionID() { return mSessionID; }
+
+ void newMessageFast(const char *name);
+ void newMessage(const char *name);
+
+
+public:
+ LLStoredMessagePtr getReceivedMessage() const;
+ LLStoredMessagePtr getBuiltMessage() const;
+ S32 sendMessage(const LLHost &host, LLStoredMessagePtr message);
+
+private:
+ LLSD getReceivedMessageLLSD() const;
+ LLSD getBuiltMessageLLSD() const;
+
+ // NOTE: babbage: Only use to support legacy misuse of the
+ // LLMessageSystem API where values are dangerously written
+ // as one type and read as another. LLSD does not support
+ // dangerous conversions and so converting the message to an
+ // LLSD would result in the reads failing. All code which
+ // misuses the message system in this way should be made safe
+ // but while the unsafe code is run in old processes, this
+ // method should be used to forward unsafe messages.
+ LLSD wrapReceivedTemplateData() const;
+ LLSD wrapBuiltTemplateData() const;
+
+public:
+
+ void copyMessageReceivedToSend();
+ void clearMessage();
+
+ void nextBlockFast(const char *blockname);
+ void nextBlock(const char *blockname);
+
+public:
+ void addBinaryDataFast(const char *varname, const void *data, S32 size);
+ void addBinaryData(const char *varname, const void *data, S32 size);
+
+ void addBOOLFast( const char* varname, bool b); // typed, checks storage space
+ void addBOOL( const char* varname, bool b); // typed, checks storage space
+ void addS8Fast( const char *varname, S8 s); // typed, checks storage space
+ void addS8( const char *varname, S8 s); // typed, checks storage space
+ void addU8Fast( const char *varname, U8 u); // typed, checks storage space
+ void addU8( const char *varname, U8 u); // typed, checks storage space
+ void addS16Fast( const char *varname, S16 i); // typed, checks storage space
+ void addS16( const char *varname, S16 i); // typed, checks storage space
+ void addU16Fast( const char *varname, U16 i); // typed, checks storage space
+ void addU16( const char *varname, U16 i); // typed, checks storage space
+ void addF32Fast( const char *varname, F32 f); // typed, checks storage space
+ void addF32( const char *varname, F32 f); // typed, checks storage space
+ void addS32Fast( const char *varname, S32 s); // typed, checks storage space
+ void addS32( const char *varname, S32 s); // typed, checks storage space
+ void addU32Fast( const char *varname, U32 u); // typed, checks storage space
+ void addU32( const char *varname, U32 u); // typed, checks storage space
+ void addU64Fast( const char *varname, U64 lu); // typed, checks storage space
+ void addU64( const char *varname, U64 lu); // typed, checks storage space
+ void addF64Fast( const char *varname, F64 d); // typed, checks storage space
+ void addF64( const char *varname, F64 d); // typed, checks storage space
+ void addVector3Fast( const char *varname, const LLVector3& vec); // typed, checks storage space
+ void addVector3( const char *varname, const LLVector3& vec); // typed, checks storage space
+ void addVector4Fast( const char *varname, const LLVector4& vec); // typed, checks storage space
+ void addVector4( const char *varname, const LLVector4& vec); // typed, checks storage space
+ void addVector3dFast( const char *varname, const LLVector3d& vec); // typed, checks storage space
+ void addVector3d( const char *varname, const LLVector3d& vec); // typed, checks storage space
+ void addQuatFast( const char *varname, const LLQuaternion& quat); // typed, checks storage space
+ void addQuat( const char *varname, const LLQuaternion& quat); // typed, checks storage space
+ void addUUIDFast( const char *varname, const LLUUID& uuid); // typed, checks storage space
+ void addUUID( const char *varname, const LLUUID& uuid); // typed, checks storage space
+ void addIPAddrFast( const char *varname, const U32 ip); // typed, checks storage space
+ void addIPAddr( const char *varname, const U32 ip); // typed, checks storage space
+ void addIPPortFast( const char *varname, const U16 port); // typed, checks storage space
+ void addIPPort( const char *varname, const U16 port); // typed, checks storage space
+ void addStringFast( const char* varname, const char* s); // typed, checks storage space
+ void addString( const char* varname, const char* s); // typed, checks storage space
+ void addStringFast( const char* varname, const std::string& s); // typed, checks storage space
+ void addString( const char* varname, const std::string& s); // typed, checks storage space
+
+ S32 getCurrentSendTotal() const;
+ TPACKETID getCurrentRecvPacketID() { return mCurrentRecvPacketID; }
+
+ // This method checks for current send total and returns true if
+ // you need to go to the next block type or need to start a new
+ // message. Specify the current blockname to check block counts,
+ // otherwise the method only checks against MTU.
+ bool isSendFull(const char* blockname = NULL);
+ bool isSendFullFast(const char* blockname = NULL);
+
+ bool removeLastBlock();
+
+ //void buildMessage();
+
+ S32 zeroCode(U8 **data, S32 *data_size);
+ S32 zeroCodeExpand(U8 **data, S32 *data_size);
+ S32 zeroCodeAdjustCurrentSendTotal();
+
+ // Uses ping-based retry
+ S32 sendReliable(const LLHost &host);
+
+ // Uses ping-based retry
+ S32 sendReliable(const U32 circuit) { return sendReliable(findHost(circuit)); }
+
+ // Use this one if you DON'T want automatic ping-based retry.
+ S32 sendReliable( const LLHost &host,
+ S32 retries,
+ bool ping_based_retries,
+ F32Seconds timeout,
+ void (*callback)(void **,S32),
+ void ** callback_data);
+
+ S32 sendSemiReliable( const LLHost &host,
+ void (*callback)(void **,S32), void ** callback_data);
+
+ // flush sends a message only if data's been pushed on it.
+ S32 flushSemiReliable( const LLHost &host,
+ void (*callback)(void **,S32), void ** callback_data);
+
+ S32 flushReliable( const LLHost &host );
+
+ void forwardMessage(const LLHost &host);
+ void forwardReliable(const LLHost &host);
+ void forwardReliable(const U32 circuit_code);
+ S32 forwardReliable(
+ const LLHost &host,
+ S32 retries,
+ bool ping_based_timeout,
+ F32Seconds timeout,
+ void (*callback)(void **,S32),
+ void ** callback_data);
+
+ S32 sendMessage(const LLHost &host);
+ S32 sendMessage(const U32 circuit);
+private:
+ S32 sendMessage(const LLHost &host, const char* name,
+ const LLSD& message);
+public:
+ // bool decodeData(const U8 *buffer, const LLHost &host);
+
+ /**
+ gets binary data from the current message.
+
+ @param blockname the name of the block in the message (from the message template)
+
+ @param varname
+
+ @param datap
+
+ @param size expected size - set to zero to get any amount of data up to max_size.
+ Make sure max_size is set in that case!
+
+ @param blocknum
+
+ @param max_size the max number of bytes to read
+ */
+ void getBinaryDataFast(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX);
+ void getBinaryData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX);
+ void getBOOLFast( const char *block, const char *var, bool &data, S32 blocknum = 0);
+ void getBOOL( const char *block, const char *var, bool &data, S32 blocknum = 0);
+ void getS8Fast( const char *block, const char *var, S8 &data, S32 blocknum = 0);
+ void getS8( const char *block, const char *var, S8 &data, S32 blocknum = 0);
+ void getU8Fast( const char *block, const char *var, U8 &data, S32 blocknum = 0);
+ void getU8( const char *block, const char *var, U8 &data, S32 blocknum = 0);
+ void getS16Fast( const char *block, const char *var, S16 &data, S32 blocknum = 0);
+ void getS16( const char *block, const char *var, S16 &data, S32 blocknum = 0);
+ void getU16Fast( const char *block, const char *var, U16 &data, S32 blocknum = 0);
+ void getU16( const char *block, const char *var, U16 &data, S32 blocknum = 0);
+ void getS32Fast( const char *block, const char *var, S32 &data, S32 blocknum = 0);
+ void getS32( const char *block, const char *var, S32 &data, S32 blocknum = 0);
+ void getF32Fast( const char *block, const char *var, F32 &data, S32 blocknum = 0);
+ void getF32( const char *block, const char *var, F32 &data, S32 blocknum = 0);
+ void getU32Fast( const char *block, const char *var, U32 &data, S32 blocknum = 0);
+ void getU32( const char *block, const char *var, U32 &data, S32 blocknum = 0);
+ void getU64Fast( const char *block, const char *var, U64 &data, S32 blocknum = 0);
+ void getU64( const char *block, const char *var, U64 &data, S32 blocknum = 0);
+ void getF64Fast( const char *block, const char *var, F64 &data, S32 blocknum = 0);
+ void getF64( const char *block, const char *var, F64 &data, S32 blocknum = 0);
+ void getVector3Fast( const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0);
+ void getVector3( const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0);
+ void getVector4Fast( const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0);
+ void getVector4( const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0);
+ void getVector3dFast(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0);
+ void getVector3d(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0);
+ void getQuatFast( const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0);
+ void getQuat( const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0);
+ void getUUIDFast( const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0);
+ void getUUID( const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0);
+ void getIPAddrFast( const char *block, const char *var, U32 &ip, S32 blocknum = 0);
+ void getIPAddr( const char *block, const char *var, U32 &ip, S32 blocknum = 0);
+ void getIPPortFast( const char *block, const char *var, U16 &port, S32 blocknum = 0);
+ void getIPPort( const char *block, const char *var, U16 &port, S32 blocknum = 0);
+ void getStringFast( const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0);
+ void getString( const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0);
+ void getStringFast( const char *block, const char *var, std::string& outstr, S32 blocknum = 0);
+ void getString( const char *block, const char *var, std::string& outstr, S32 blocknum = 0);
+
+
+ // Utility functions to generate a replay-resistant digest check
+ // against the shared secret. The window specifies how much of a
+ // time window is allowed - 1 second is good for tight
+ // connections, but multi-process windows might want to be upwards
+ // of 5 seconds. For generateDigest, you want to pass in a
+ // character array of at least MD5HEX_STR_SIZE so that the hex
+ // digest and null termination will fit.
+ bool generateDigestForNumberAndUUIDs(char* digest, const U32 number, const LLUUID &id1, const LLUUID &id2) const;
+ bool generateDigestForWindowAndUUIDs(char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const;
+ bool isMatchingDigestForWindowAndUUIDs(const char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const;
+
+ bool generateDigestForNumber(char* digest, const U32 number) const;
+ bool generateDigestForWindow(char* digest, const S32 window) const;
+ bool isMatchingDigestForWindow(const char* digest, const S32 window) const;
+
+ void showCircuitInfo();
+ void getCircuitInfo(LLSD& info) const;
+
+ U32 getOurCircuitCode();
+
+ void enableCircuit(const LLHost &host, bool trusted);
+ void disableCircuit(const LLHost &host);
+
+ // Use this to establish trust on startup and in response to
+ // DenyTrustedCircuit.
+ void sendCreateTrustedCircuit(const LLHost& host, const LLUUID & id1, const LLUUID & id2);
+
+ // Use this to inform a peer that they aren't currently trusted...
+ // This now enqueues the request so that we can ensure that we only send
+ // one deny per circuit per message loop so that this doesn't become a DoS.
+ // The actual sending is done by reallySendDenyTrustedCircuit()
+ void sendDenyTrustedCircuit(const LLHost &host);
+
+ /** Return false if host is unknown or untrusted */
+ // Note:DaveH/Babbage some trusted messages can be received without a circuit
+ bool isTrustedSender(const LLHost& host) const;
+
+ /** Return true if current message is from trusted source */
+ bool isTrustedSender() const;
+
+ /** Return false true if name is unknown or untrusted */
+ bool isTrustedMessage(const std::string& name) const;
+
+ /** Return false true if name is unknown or trusted */
+ bool isUntrustedMessage(const std::string& name) const;
+
+ // Mark an interface ineligible for trust
+ void setUntrustedInterface( const LLHost host ) { mUntrustedInterface = host; }
+ LLHost getUntrustedInterface() const { return mUntrustedInterface; }
+ void setBlockUntrustedInterface( bool block ) { mBlockUntrustedInterface = block; } // Throw a switch to allow, sending warnings only
+ bool getBlockUntrustedInterface() const { return mBlockUntrustedInterface; }
+
+ // Change this message to be UDP black listed.
+ void banUdpMessage(const std::string& name);
+
+
+private:
+ // A list of the circuits that need to be sent DenyTrustedCircuit messages.
+ typedef std::set<LLHost> host_set_t;
+ host_set_t mDenyTrustedCircuitSet;
+
+ // Really sends the DenyTrustedCircuit message to a given host
+ // related to sendDenyTrustedCircuit()
+ void reallySendDenyTrustedCircuit(const LLHost &host);
+
+public:
+ // Use this to establish trust to and from a host. This blocks
+ // until trust has been established, and probably should only be
+ // used on startup.
+ void establishBidirectionalTrust(const LLHost &host, S64 frame_count = 0);
+
+ // returns whether the given host is on a trusted circuit
+ // Note:DaveH/Babbage some trusted messages can be received without a circuit
+ bool getCircuitTrust(const LLHost &host);
+
+ void setCircuitAllowTimeout(const LLHost &host, bool allow);
+ void setCircuitTimeoutCallback(const LLHost &host, void (*callback_func)(const LLHost &host, void *user_data), void *user_data);
+
+ bool checkCircuitBlocked(const U32 circuit);
+ bool checkCircuitAlive(const U32 circuit);
+ bool checkCircuitAlive(const LLHost &host);
+ void setCircuitProtection(bool b_protect);
+ U32 findCircuitCode(const LLHost &host);
+ LLHost findHost(const U32 circuit_code);
+ void sanityCheck();
+
+ bool has(const char *blockname) const;
+ S32 getNumberOfBlocksFast(const char *blockname) const;
+ S32 getNumberOfBlocks(const char *blockname) const;
+ S32 getSizeFast(const char *blockname, const char *varname) const;
+ S32 getSize(const char *blockname, const char *varname) const;
+ S32 getSizeFast(const char *blockname, S32 blocknum,
+ const char *varname) const; // size in bytes of data
+ S32 getSize(const char *blockname, S32 blocknum, const char *varname) const;
+
+ void resetReceiveCounts(); // resets receive counts for all message types to 0
+ void dumpReceiveCounts(); // dumps receive count for each message type to LL_INFOS()
+ void dumpCircuitInfo(); // Circuit information to LL_INFOS()
+
+ bool isClear() const; // returns mbSClear;
+ S32 flush(const LLHost &host);
+
+ U32 getListenPort( void ) const;
+
+ void startLogging(); // start verbose logging
+ void stopLogging(); // flush and close file
+ void summarizeLogs(std::ostream& str); // log statistics
+
+ S32 getReceiveSize() const;
+ S32 getReceiveCompressedSize() const { return mIncomingCompressedSize; }
+ S32 getReceiveBytes() const;
+
+ S32 getUnackedListSize() const { return mUnackedListSize; }
+
+ //const char* getCurrentSMessageName() const { return mCurrentSMessageName; }
+ //const char* getCurrentSBlockName() const { return mCurrentSBlockName; }
+
+ // friends
+ friend std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg);
+
+ void setMaxMessageTime(const F32 seconds); // Max time to process messages before warning and dumping (neg to disable)
+ void setMaxMessageCounts(const S32 num); // Max number of messages before dumping (neg to disable)
+
+ static U64Microseconds getMessageTimeUsecs(const bool update = false); // Get the current message system time in microseconds
+ static F64Seconds getMessageTimeSeconds(const bool update = false); // Get the current message system time in seconds
+
+ static void setTimeDecodes(bool b);
+ static void setTimeDecodesSpamThreshold(F32 seconds);
+
+ // message handlers internal to the message systesm
+ //static void processAssignCircuitCode(LLMessageSystem* msg, void**);
+ static void processAddCircuitCode(LLMessageSystem* msg, void**);
+ static void processUseCircuitCode(LLMessageSystem* msg, void**);
+ static void processError(LLMessageSystem* msg, void**);
+
+ // dispatch llsd message to http node tree
+ static void dispatch(const std::string& msg_name,
+ const LLSD& message);
+ static void dispatch(const std::string& msg_name,
+ const LLSD& message,
+ LLHTTPNode::ResponsePtr responsep);
+
+ // this is added to support specific legacy messages and is
+ // ***not intended for general use*** Si, Gabriel, 2009
+ static void dispatchTemplate(const std::string& msg_name,
+ const LLSD& message,
+ LLHTTPNode::ResponsePtr responsep);
+
+ void setMessageBans(const LLSD& trusted, const LLSD& untrusted);
+
+ /**
+ * @brief send an error message to the host. This is a helper method.
+ *
+ * @param host Destination host.
+ * @param agent_id Destination agent id (may be null)
+ * @param code An HTTP status compatible error code.
+ * @param token A specific short string based message
+ * @param id The transactionid/uniqueid/sessionid whatever.
+ * @param system The hierarchical path to the system (255 bytes)
+ * @param message Human readable message (1200 bytes)
+ * @param data Extra info.
+ * @return Returns value returned from sendReliable().
+ */
+ S32 sendError(
+ const LLHost& host,
+ const LLUUID& agent_id,
+ S32 code,
+ const std::string& token,
+ const LLUUID& id,
+ const std::string& system,
+ const std::string& message,
+ const LLSD& data);
+
+ // Check UDP messages and pump http_pump to receive HTTP messages.
+ bool checkAllMessages(LockMessageChecker&, S64 frame_count, LLPumpIO* http_pump);
+
+ // Moved to allow access from LLTemplateMessageDispatcher
+ void clearReceiveState();
+
+ // This will cause all trust queries to return true until the next message
+ // is read: use with caution!
+ void receivedMessageFromTrustedSender();
+
+private:
+ typedef boost::function<void(S32)> UntrustedCallback_t;
+ void sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback);
+
+
+ bool mLastMessageFromTrustedMessageService;
+
+ // The mCircuitCodes is a map from circuit codes to session
+ // ids. This allows us to verify sessions on connect.
+ typedef std::map<U32, LLUUID> code_session_map_t;
+ code_session_map_t mCircuitCodes;
+
+ // Viewers need to track a process session in order to make sure
+ // that no one gives them a bad circuit code.
+ LLUUID mSessionID;
+
+ void addTemplate(LLMessageTemplate *templatep);
+ bool decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template );
+
+ void logMsgFromInvalidCircuit( const LLHost& sender, bool recv_reliable );
+ void logTrustedMsgFromUntrustedCircuit( const LLHost& sender );
+ void logValidMsg(LLCircuitData *cdp, const LLHost& sender, bool recv_reliable, bool recv_resent, bool recv_acks );
+ void logRanOffEndOfPacket( const LLHost& sender );
+
+ class LLMessageCountInfo
+ {
+ public:
+ U32 mMessageNum;
+ U32 mMessageBytes;
+ bool mInvalid;
+ };
+
+ LLMessagePollInfo *mPollInfop;
+
+ U8 mEncodedRecvBuffer[MAX_BUFFER_SIZE];
+ U8 mTrueReceiveBuffer[MAX_BUFFER_SIZE];
+ S32 mTrueReceiveSize;
+
+ // Must be valid during decode
+
+ bool mbError;
+ S32 mErrorCode;
+
+ F64Seconds mResendDumpTime; // The last time we dumped resends
+
+ LLMessageCountInfo mMessageCountList[MAX_MESSAGE_COUNT_NUM];
+ S32 mNumMessageCounts;
+ F32Seconds mReceiveTime;
+ F32Seconds mMaxMessageTime; // Max number of seconds for processing messages
+ S32 mMaxMessageCounts; // Max number of messages to process before dumping.
+ F64Seconds mMessageCountTime;
+
+ F64Seconds mCurrentMessageTime; // The current "message system time" (updated the first call to checkMessages after a resetReceiveCount
+
+ // message system exceptions
+ typedef std::pair<msg_exception_callback, void*> exception_t;
+ typedef std::map<EMessageException, exception_t> callbacks_t;
+ callbacks_t mExceptionCallbacks;
+
+ // stuff for logging
+ LLTimer mMessageSystemTimer;
+
+ static F32 mTimeDecodesSpamThreshold; // If mTimeDecodes is on, all this many seconds for each msg decode before spamming
+ static bool mTimeDecodes; // Measure time for all message decodes if true;
+
+ msg_timing_callback mTimingCallback;
+ void* mTimingCallbackData;
+
+ void init(); // ctor shared initialisation.
+
+ LLHost mLastSender;
+ LLHost mLastReceivingIF;
+ S32 mIncomingCompressedSize; // original size of compressed msg (0 if uncomp.)
+ TPACKETID mCurrentRecvPacketID; // packet ID of current receive packet (for reporting)
+
+ LLMessageBuilder* mMessageBuilder;
+ LLTemplateMessageBuilder* mTemplateMessageBuilder;
+ LLSDMessageBuilder* mLLSDMessageBuilder;
+ LLMessageReaderPointer mMessageReader;
+ LLTemplateMessageReader* mTemplateMessageReader;
+ LLSDMessageReader* mLLSDMessageReader;
+
+ friend class LLMessageHandlerBridge;
+ friend class LockMessageChecker;
+
+ bool callHandler(const char *name, bool trustedSource,
+ LLMessageSystem* msg);
+
+
+ /** Find, create or revive circuit for host as needed */
+ LLCircuitData* findCircuit(const LLHost& host, bool resetPacketId);
+};
+
+
+// external hook into messaging system
+extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
+
+// Implementation of LockMessageChecker depends on definition of
+// LLMessageSystem, hence must follow it.
+class LockMessageChecker: public LockMessageReader
+{
+public:
+ LockMessageChecker(LLMessageSystem* msgsystem);
+
+ // For convenience, provide forwarding wrappers so you can call (e.g.)
+ // checkAllMessages() on your LockMessageChecker instance instead of
+ // passing the instance to LLMessageSystem::checkAllMessages(). Use
+ // perfect forwarding to avoid having to maintain these wrappers in sync
+ // with the target methods.
+ template <typename... ARGS>
+ bool checkAllMessages(ARGS&&... args)
+ {
+ return mMessageSystem->checkAllMessages(*this, std::forward<ARGS>(args)...);
+ }
+
+ template <typename... ARGS>
+ bool checkMessages(ARGS&&... args)
+ {
+ return mMessageSystem->checkMessages(*this, std::forward<ARGS>(args)...);
+ }
+
+ template <typename... ARGS>
+ void processAcks(ARGS&&... args)
+ {
+ return mMessageSystem->processAcks(*this, std::forward<ARGS>(args)...);
+ }
+
+private:
+ LLMessageSystem* mMessageSystem;
+};
+
+// Must specific overall system version, which is used to determine
+// if a patch is available in the message template checksum verification.
+// Return true if able to initialize system.
+bool start_messaging_system(
+ const std::string& template_name,
+ U32 port,
+ S32 version_major,
+ S32 version_minor,
+ S32 version_patch,
+ bool b_dump_prehash_file,
+ const std::string& secret,
+ const LLUseCircuitCodeResponder* responder,
+ bool failure_is_fatal,
+ const F32 circuit_heartbeat_interval,
+ const F32 circuit_timeout);
+
+void end_messaging_system(bool print_summary = true);
+
+void null_message_callback(LLMessageSystem *msg, void **data);
+
+//
+// Inlines
+//
+
+#if !defined( LL_BIG_ENDIAN ) && !defined( LL_LITTLE_ENDIAN )
+#error Unknown endianness for htolememcpy. Did you miss a common include?
+#endif
+
+static inline void *htolememcpy(void *vs, const void *vct, EMsgVariableType type, size_t n)
+{
+ char *s = (char *)vs;
+ const char *ct = (const char *)vct;
+#ifdef LL_BIG_ENDIAN
+ S32 i, length;
+#endif
+ switch(type)
+ {
+ case MVT_FIXED:
+ case MVT_VARIABLE:
+ case MVT_U8:
+ case MVT_S8:
+ case MVT_BOOL:
+ case MVT_LLUUID:
+ case MVT_IP_ADDR: // these two are swizzled in the getters and setters
+ case MVT_IP_PORT: // these two are swizzled in the getters and setters
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+
+ case MVT_U16:
+ case MVT_S16:
+ if (n != 2)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ *(s + 1) = *(ct);
+ *(s) = *(ct + 1);
+ return(vs);
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_U32:
+ case MVT_S32:
+ case MVT_F32:
+ if (n != 4)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ *(s + 3) = *(ct);
+ *(s + 2) = *(ct + 1);
+ *(s + 1) = *(ct + 2);
+ *(s) = *(ct + 3);
+ return(vs);
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_U64:
+ case MVT_S64:
+ case MVT_F64:
+ if (n != 8)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ *(s + 7) = *(ct);
+ *(s + 6) = *(ct + 1);
+ *(s + 5) = *(ct + 2);
+ *(s + 4) = *(ct + 3);
+ *(s + 3) = *(ct + 4);
+ *(s + 2) = *(ct + 5);
+ *(s + 1) = *(ct + 6);
+ *(s) = *(ct + 7);
+ return(vs);
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_LLVector3:
+ case MVT_LLQuaternion: // We only send x, y, z and infer w (we set x, y, z to ensure that w >= 0)
+ if (n != 12)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 8, ct + 8, MVT_F32, 4);
+ htolememcpy(s + 4, ct + 4, MVT_F32, 4);
+ return(htolememcpy(s, ct, MVT_F32, 4));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_LLVector3d:
+ if (n != 24)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 16, ct + 16, MVT_F64, 8);
+ htolememcpy(s + 8, ct + 8, MVT_F64, 8);
+ return(htolememcpy(s, ct, MVT_F64, 8));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_LLVector4:
+ if (n != 16)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 12, ct + 12, MVT_F32, 4);
+ htolememcpy(s + 8, ct + 8, MVT_F32, 4);
+ htolememcpy(s + 4, ct + 4, MVT_F32, 4);
+ return(htolememcpy(s, ct, MVT_F32, 4));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_U16Vec3:
+ if (n != 6)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 4, ct + 4, MVT_U16, 2);
+ htolememcpy(s + 2, ct + 2, MVT_U16, 2);
+ return(htolememcpy(s, ct, MVT_U16, 2));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_U16Quat:
+ if (n != 8)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 6, ct + 6, MVT_U16, 2);
+ htolememcpy(s + 4, ct + 4, MVT_U16, 2);
+ htolememcpy(s + 2, ct + 2, MVT_U16, 2);
+ return(htolememcpy(s, ct, MVT_U16, 2));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_S16Array:
+ if (n % 2)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ length = n % 2;
+ for (i = 1; i < length; i++)
+ {
+ htolememcpy(s + i*2, ct + i*2, MVT_S16, 2);
+ }
+ return(htolememcpy(s, ct, MVT_S16, 2));
+#else
+ return(memcpy(s,ct,n));
+#endif
+
+ default:
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+ }
+}
+
+inline void *ntohmemcpy(void *s, const void *ct, EMsgVariableType type, size_t n)
+{
+ return(htolememcpy(s,ct,type, n));
+}
+
+inline const LLHost& LLMessageSystem::getReceivingInterface() const {return mLastReceivingIF;}
+
+inline U32 LLMessageSystem::getSenderIP() const
+{
+ return mLastSender.getAddress();
+}
+
+inline U32 LLMessageSystem::getSenderPort() const
+{
+ return mLastSender.getPort();
+}
+
+
+//-----------------------------------------------------------------------------
+// Transmission aliases
+//-----------------------------------------------------------------------------
+
+inline S32 LLMessageSystem::sendMessage(const U32 circuit)
+{
+ return sendMessage(findHost(circuit));
+}
+
+#endif
diff --git a/indra/llmessage/message_string_table.cpp b/indra/llmessage/message_string_table.cpp index df4bfa29ad..facc8f6cae 100644 --- a/indra/llmessage/message_string_table.cpp +++ b/indra/llmessage/message_string_table.cpp @@ -1,91 +1,91 @@ -/** - * @file message_string_table.cpp - * @brief static string table for message template - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "llerror.h" -#include "message.h" - -inline U32 message_hash_my_string(const char *str) -{ - U32 retval = 0; - while (*str++) - { - retval += *str; - retval <<= 1; - } - return (retval % MESSAGE_NUMBER_OF_HASH_BUCKETS); -} - - - -LLMessageStringTable::LLMessageStringTable() -: mUsed(0) -{ - for (U32 i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++) - { - mEmpty[i] = TRUE; - mString[i][0] = 0; - } -} - - -LLMessageStringTable::~LLMessageStringTable() -{ } - - -char* LLMessageStringTable::getString(const char *str) -{ - U32 hash_value = message_hash_my_string(str); - while (!mEmpty[hash_value]) - { - if (!strncmp(str, mString[hash_value], MESSAGE_MAX_STRINGS_LENGTH)) - { - return mString[hash_value]; - } - else - { - hash_value++; - hash_value %= MESSAGE_NUMBER_OF_HASH_BUCKETS; - } - } - // not found, so add! - strncpy(mString[hash_value], str, MESSAGE_MAX_STRINGS_LENGTH); /* Flawfinder: ignore */ - mString[hash_value][MESSAGE_MAX_STRINGS_LENGTH - 1] = 0; - mEmpty[hash_value] = FALSE; - mUsed++; - if (mUsed >= MESSAGE_NUMBER_OF_HASH_BUCKETS - 1) - { - U32 i; - LL_INFOS() << "Dumping string table before crashing on HashTable full!" << LL_ENDL; - for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++) - { - LL_INFOS() << "Entry #" << i << ": " << mString[i] << LL_ENDL; - } - } - return mString[hash_value]; -} - +/**
+ * @file message_string_table.cpp
+ * @brief static string table for message template
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llerror.h"
+#include "message.h"
+
+inline U32 message_hash_my_string(const char *str)
+{
+ U32 retval = 0;
+ while (*str++)
+ {
+ retval += *str;
+ retval <<= 1;
+ }
+ return (retval % MESSAGE_NUMBER_OF_HASH_BUCKETS);
+}
+
+
+
+LLMessageStringTable::LLMessageStringTable()
+: mUsed(0)
+{
+ for (U32 i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
+ {
+ mEmpty[i] = true;
+ mString[i][0] = 0;
+ }
+}
+
+
+LLMessageStringTable::~LLMessageStringTable()
+{ }
+
+
+char* LLMessageStringTable::getString(const char *str)
+{
+ U32 hash_value = message_hash_my_string(str);
+ while (!mEmpty[hash_value])
+ {
+ if (!strncmp(str, mString[hash_value], MESSAGE_MAX_STRINGS_LENGTH))
+ {
+ return mString[hash_value];
+ }
+ else
+ {
+ hash_value++;
+ hash_value %= MESSAGE_NUMBER_OF_HASH_BUCKETS;
+ }
+ }
+ // not found, so add!
+ strncpy(mString[hash_value], str, MESSAGE_MAX_STRINGS_LENGTH); /* Flawfinder: ignore */
+ mString[hash_value][MESSAGE_MAX_STRINGS_LENGTH - 1] = 0;
+ mEmpty[hash_value] = false;
+ mUsed++;
+ if (mUsed >= MESSAGE_NUMBER_OF_HASH_BUCKETS - 1)
+ {
+ U32 i;
+ LL_INFOS() << "Dumping string table before crashing on HashTable full!" << LL_ENDL;
+ for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
+ {
+ LL_INFOS() << "Entry #" << i << ": " << mString[i] << LL_ENDL;
+ }
+ }
+ return mString[hash_value];
+}
+
diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index c8552b3fb4..833380632c 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -1,663 +1,663 @@ -/** - * @file net.cpp - * @brief Cross-platform routines for sending and receiving packets. - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#include "linden_common.h" - -//#include "net.h" - -// system library includes -#include <stdexcept> - -#if LL_WINDOWS -#include "llwin32headerslean.h" -#else - #include <sys/types.h> - #include <sys/socket.h> - #include <netinet/in.h> - #include <arpa/inet.h> - #include <fcntl.h> - #include <errno.h> -#endif - -// linden library includes -#include "llerror.h" -#include "llhost.h" -#include "lltimer.h" -#include "indra_constants.h" - -// Globals -#if LL_WINDOWS - -SOCKADDR_IN stDstAddr; -SOCKADDR_IN stSrcAddr; -SOCKADDR_IN stLclAddr; -static WSADATA stWSAData; - -#else - -struct sockaddr_in stDstAddr; -struct sockaddr_in stSrcAddr; -struct sockaddr_in stLclAddr; - -#if LL_DARWIN -#ifndef _SOCKLEN_T -#define _SOCKLEN_T -typedef int socklen_t; -#endif -#endif - -#endif - -static U32 gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS; // Address to which datagram was sent - -const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1"; -const char* BROADCAST_ADDRESS_STRING = "255.255.255.255"; - -#if LL_DARWIN - // Mac OS X returns an error when trying to set these to 400000. Smaller values succeed. - const int SEND_BUFFER_SIZE = 200000; - const int RECEIVE_BUFFER_SIZE = 200000; -#else // LL_DARWIN - const int SEND_BUFFER_SIZE = 400000; - const int RECEIVE_BUFFER_SIZE = 400000; -#endif // LL_DARWIN - -// universal functions (cross-platform) - -LLHost get_sender() -{ - return LLHost(stSrcAddr.sin_addr.s_addr, ntohs(stSrcAddr.sin_port)); -} - -U32 get_sender_ip(void) -{ - return stSrcAddr.sin_addr.s_addr; -} - -U32 get_sender_port() -{ - return ntohs(stSrcAddr.sin_port); -} - -LLHost get_receiving_interface() -{ - return LLHost(gsnReceivingIFAddr, INVALID_PORT); -} - -U32 get_receiving_interface_ip(void) -{ - return gsnReceivingIFAddr; -} - -const char* u32_to_ip_string(U32 ip) -{ - static char buffer[MAXADDRSTR]; /* Flawfinder: ignore */ - - // Convert the IP address into a string - in_addr in; - in.s_addr = ip; - char* result = inet_ntoa(in); - - // NULL indicates error in conversion - if (result != NULL) - { - strncpy( buffer, result, MAXADDRSTR ); /* Flawfinder: ignore */ - buffer[MAXADDRSTR-1] = '\0'; - return buffer; - } - else - { - return "(bad IP addr)"; - } -} - - -// Returns ip_string if successful, NULL if not. Copies into ip_string -char *u32_to_ip_string(U32 ip, char *ip_string) -{ - char *result; - in_addr in; - - // Convert the IP address into a string - in.s_addr = ip; - result = inet_ntoa(in); - - // NULL indicates error in conversion - if (result != NULL) - { - //the function signature needs to change to pass in the lengfth of first and last. - strcpy(ip_string, result); /*Flawfinder: ignore*/ - return ip_string; - } - else - { - return NULL; - } -} - - -// Wrapper for inet_addr() -U32 ip_string_to_u32(const char* ip_string) -{ - // *NOTE: Windows doesn't support inet_aton(), so we are using - // inet_addr(). Unfortunately, INADDR_NONE == INADDR_BROADCAST, so - // we have to check whether the input is a broadcast address before - // deciding that @ip_string is invalid. - // - // Also, our definition of INVALID_HOST_IP_ADDRESS doesn't allow us to - // use wildcard addresses. -Ambroff - U32 ip = inet_addr(ip_string); - if (ip == INADDR_NONE - && strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0) - { - LL_WARNS() << "ip_string_to_u32() failed, Error: Invalid IP string '" << ip_string << "'" << LL_ENDL; - return INVALID_HOST_IP_ADDRESS; - } - return ip; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Windows Versions -////////////////////////////////////////////////////////////////////////////////////////// - -#if LL_WINDOWS - -S32 start_net(S32& socket_out, int& nPort) -{ - // Create socket, make non-blocking - // Init WinSock - int nRet; - int hSocket; - - int snd_size = SEND_BUFFER_SIZE; - int rec_size = RECEIVE_BUFFER_SIZE; - int buff_size = 4; - - // Initialize windows specific stuff - if (WSAStartup(0x0202, &stWSAData)) - { - S32 err = WSAGetLastError(); - WSACleanup(); - LL_WARNS("AppInit") << "Windows Sockets initialization failed, err " << err << LL_ENDL; - return 1; - } - - // Get a datagram socket - hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0); - if (hSocket == INVALID_SOCKET) - { - S32 err = WSAGetLastError(); - WSACleanup(); - LL_WARNS("AppInit") << "socket() failed, err " << err << LL_ENDL; - return 2; - } - - // Name the socket (assign the local port number to receive on) - stLclAddr.sin_family = AF_INET; - stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); - stLclAddr.sin_port = htons(nPort); - - S32 attempt_port = nPort; - LL_DEBUGS("AppInit") << "attempting to connect on port " << attempt_port << LL_ENDL; - nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr)); - - if (nRet == SOCKET_ERROR) - { - // If we got an address in use error... - if (WSAGetLastError() == WSAEADDRINUSE) - { - // Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX - for(attempt_port = PORT_DISCOVERY_RANGE_MIN; - attempt_port <= PORT_DISCOVERY_RANGE_MAX; - attempt_port++) - { - stLclAddr.sin_port = htons(attempt_port); - LL_DEBUGS("AppInit") << "trying port " << attempt_port << LL_ENDL; - nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr)); - - if (!(nRet == SOCKET_ERROR && - WSAGetLastError() == WSAEADDRINUSE)) - { - break; - } - } - - if (nRet == SOCKET_ERROR) - { - LL_WARNS("AppInit") << "startNet() : Couldn't find available network port." << LL_ENDL; - // Fail gracefully here in release - return 3; - } - } - else - // Some other socket error - { - LL_WARNS("AppInit") << llformat("bind() port: %d failed, Err: %d\n", nPort, WSAGetLastError()) << LL_ENDL; - // Fail gracefully in release. - return 4; - } - } - - sockaddr_in socket_address; - S32 socket_address_size = sizeof(socket_address); - getsockname(hSocket, (SOCKADDR*) &socket_address, &socket_address_size); - attempt_port = ntohs(socket_address.sin_port); - - LL_INFOS("AppInit") << "connected on port " << attempt_port << LL_ENDL; - nPort = attempt_port; - - // Set socket to be non-blocking - unsigned long argp = 1; - nRet = ioctlsocket (hSocket, FIONBIO, &argp); - if (nRet == SOCKET_ERROR) - { - printf("Failed to set socket non-blocking, Err: %d\n", - WSAGetLastError()); - } - - // set a large receive buffer - nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size); - if (nRet) - { - LL_INFOS("AppInit") << "Can't set receive buffer size!" << LL_ENDL; - } - - nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size); - if (nRet) - { - LL_INFOS("AppInit") << "Can't set send buffer size!" << LL_ENDL; - } - - getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size); - getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size); - - LL_DEBUGS("AppInit") << "startNet - receive buffer size : " << rec_size << LL_ENDL; - LL_DEBUGS("AppInit") << "startNet - send buffer size : " << snd_size << LL_ENDL; - - // Setup a destination address - stDstAddr.sin_family = AF_INET; - stDstAddr.sin_addr.s_addr = INVALID_HOST_IP_ADDRESS; - stDstAddr.sin_port = htons(nPort); - - socket_out = hSocket; - return 0; -} - -void end_net(S32& socket_out) -{ - if (socket_out >= 0) - { - shutdown(socket_out, SD_BOTH); - closesocket(socket_out); - } - WSACleanup(); -} - -S32 receive_packet(int hSocket, char * receiveBuffer) -{ - // Receives data asynchronously from the socket set by initNet(). - // Returns the number of bytes received into dataReceived, or zero - // if there is no data received. - int nRet; - int addr_size = sizeof(struct sockaddr_in); - - nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, 0, (struct sockaddr*)&stSrcAddr, &addr_size); - if (nRet == SOCKET_ERROR ) - { - if (WSAEWOULDBLOCK == WSAGetLastError()) - return 0; - if (WSAECONNRESET == WSAGetLastError()) - return 0; - LL_INFOS() << "receivePacket() failed, Error: " << WSAGetLastError() << LL_ENDL; - } - - return nRet; -} - -// Returns TRUE on success. -BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort) -{ - // Sends a packet to the address set in initNet - // - int nRet = 0; - U32 last_error = 0; - - stDstAddr.sin_addr.s_addr = recipient; - stDstAddr.sin_port = htons(nPort); - do - { - nRet = sendto(hSocket, sendBuffer, size, 0, (struct sockaddr*)&stDstAddr, sizeof(stDstAddr)); - - if (nRet == SOCKET_ERROR ) - { - last_error = WSAGetLastError(); - if (last_error != WSAEWOULDBLOCK) - { - // WSAECONNRESET - I think this is caused by an ICMP "connection refused" - // message being sent back from a Linux box... I'm not finding helpful - // documentation or web pages on this. The question is whether the packet - // actually got sent or not. Based on the structure of this code, I would - // assume it is. JNC 2002.01.18 - if (WSAECONNRESET == WSAGetLastError()) - { - return TRUE; - } - LL_INFOS() << "sendto() failed to " << u32_to_ip_string(recipient) << ":" << nPort - << ", Error " << last_error << LL_ENDL; - } - } - } while ( (nRet == SOCKET_ERROR) - &&(last_error == WSAEWOULDBLOCK)); - - return (nRet != SOCKET_ERROR); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Linux Versions -////////////////////////////////////////////////////////////////////////////////////////// - -#else - -// Create socket, make non-blocking -S32 start_net(S32& socket_out, int& nPort) -{ - int hSocket, nRet; - int snd_size = SEND_BUFFER_SIZE; - int rec_size = RECEIVE_BUFFER_SIZE; - - socklen_t buff_size = 4; - - // Create socket - hSocket = socket(AF_INET, SOCK_DGRAM, 0); - if (hSocket < 0) - { - LL_WARNS() << "socket() failed" << LL_ENDL; - return 1; - } - - if (NET_USE_OS_ASSIGNED_PORT == nPort) - { - // Although bind is not required it will tell us which port we were - // assigned to. - stLclAddr.sin_family = AF_INET; - stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); - stLclAddr.sin_port = htons(0); - LL_INFOS() << "attempting to connect on OS assigned port" << LL_ENDL; - nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr)); - if (nRet < 0) - { - LL_WARNS() << "Failed to bind on an OS assigned port error: " - << nRet << LL_ENDL; - } - else - { - sockaddr_in socket_info; - socklen_t len = sizeof(sockaddr_in); - int err = getsockname(hSocket, (sockaddr*)&socket_info, &len); - LL_INFOS() << "Get socket returned: " << err << " length " << len << LL_ENDL; - nPort = ntohs(socket_info.sin_port); - LL_INFOS() << "Assigned port: " << nPort << LL_ENDL; - - } - } - else - { - // Name the socket (assign the local port number to receive on) - stLclAddr.sin_family = AF_INET; - stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); - stLclAddr.sin_port = htons(nPort); - U32 attempt_port = nPort; - LL_INFOS() << "attempting to connect on port " << attempt_port << LL_ENDL; - - nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr)); - if (nRet < 0) - { - // If we got an address in use error... - if (errno == EADDRINUSE) - { - // Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX - for(attempt_port = PORT_DISCOVERY_RANGE_MIN; - attempt_port <= PORT_DISCOVERY_RANGE_MAX; - attempt_port++) - { - stLclAddr.sin_port = htons(attempt_port); - LL_INFOS() << "trying port " << attempt_port << LL_ENDL; - nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr)); - if (!((nRet < 0) && (errno == EADDRINUSE))) - { - break; - } - } - if (nRet < 0) - { - LL_WARNS() << "startNet() : Couldn't find available network port." << LL_ENDL; - // Fail gracefully in release. - return 3; - } - } - // Some other socket error - else - { - LL_WARNS() << llformat ("bind() port: %d failed, Err: %s\n", nPort, strerror(errno)) << LL_ENDL; - // Fail gracefully in release. - return 4; - } - } - LL_INFOS() << "connected on port " << attempt_port << LL_ENDL; - nPort = attempt_port; - } - // Set socket to be non-blocking - fcntl(hSocket, F_SETFL, O_NONBLOCK); - // set a large receive buffer - nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size); - if (nRet) - { - LL_INFOS() << "Can't set receive size!" << LL_ENDL; - } - nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size); - if (nRet) - { - LL_INFOS() << "Can't set send size!" << LL_ENDL; - } - getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size); - getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size); - - LL_INFOS() << "startNet - receive buffer size : " << rec_size << LL_ENDL; - LL_INFOS() << "startNet - send buffer size : " << snd_size << LL_ENDL; - -#if LL_LINUX - // Turn on recipient address tracking - { - int use_pktinfo = 1; - if( setsockopt( hSocket, SOL_IP, IP_PKTINFO, &use_pktinfo, sizeof(use_pktinfo) ) == -1 ) - { - LL_WARNS() << "No IP_PKTINFO available" << LL_ENDL; - } - else - { - LL_INFOS() << "IP_PKKTINFO enabled" << LL_ENDL; - } - } -#endif - - // Setup a destination address - char achMCAddr[MAXADDRSTR] = "127.0.0.1"; /* Flawfinder: ignore */ - stDstAddr.sin_family = AF_INET; - stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr); - stDstAddr.sin_port = htons(nPort); - - socket_out = hSocket; - return 0; -} - -void end_net(S32& socket_out) -{ - if (socket_out >= 0) - { - close(socket_out); - } -} - -#if LL_LINUX -static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *from, socklen_t *fromlen, U32 *dstip ) -{ - int size; - struct iovec iov[1]; - char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))]; - struct cmsghdr *cmsgptr; - struct msghdr msg = {0}; - - iov[0].iov_base = buf; - iov[0].iov_len = len; - - memset(&msg, 0, sizeof msg); - msg.msg_name = from; - msg.msg_namelen = *fromlen; - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsg; - msg.msg_controllen = sizeof(cmsg); - - size = recvmsg(socket, &msg, 0); - - if (size == -1) - { - return -1; - } - - for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr)) - { - if( cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO ) - { - in_pktinfo *pktinfo = (in_pktinfo *)CMSG_DATA(cmsgptr); - if( pktinfo ) - { - // Two choices. routed and specified. ipi_addr is routed, ipi_spec_dst is - // routed. We should stay with specified until we go to multiple - // interfaces - *dstip = pktinfo->ipi_spec_dst.s_addr; - } - } - } - - return size; -} -#endif - -int receive_packet(int hSocket, char * receiveBuffer) -{ - // Receives data asynchronously from the socket set by initNet(). - // Returns the number of bytes received into dataReceived, or zero - // if there is no data received. - // or -1 if an error occured! - int nRet; - socklen_t addr_size = sizeof(struct sockaddr_in); - - gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS; - -#if LL_LINUX - nRet = recvfrom_destip(hSocket, receiveBuffer, NET_BUFFER_SIZE, (struct sockaddr*)&stSrcAddr, &addr_size, &gsnReceivingIFAddr); -#else - int recv_flags = 0; - nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, recv_flags, (struct sockaddr*)&stSrcAddr, &addr_size); -#endif - - if (nRet == -1) - { - // To maintain consistency with the Windows implementation, return a zero for size on error. - return 0; - } - - // Uncomment for testing if/when implementing for Mac or Windows: - // LL_INFOS() << "Received datagram to in addr " << u32_to_ip_string(get_receiving_interface_ip()) << LL_ENDL; - - return nRet; -} - -BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, int nPort) -{ - int ret; - BOOL success; - BOOL resend; - S32 send_attempts = 0; - - stDstAddr.sin_addr.s_addr = recipient; - stDstAddr.sin_port = htons(nPort); - - do - { - ret = sendto(hSocket, sendBuffer, size, 0, (struct sockaddr*)&stDstAddr, sizeof(stDstAddr)); - send_attempts++; - - if (ret >= 0) - { - // successful send - success = TRUE; - resend = FALSE; - } - else - { - // send failed, check to see if we should resend - success = FALSE; - - if (errno == EAGAIN) - { - // say nothing, just repeat send - LL_INFOS() << "sendto() reported buffer full, resending (attempt " << send_attempts << ")" << LL_ENDL; - LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL; - resend = TRUE; - } - else if (errno == ECONNREFUSED) - { - // response to ICMP connection refused message on earlier send - LL_INFOS() << "sendto() reported connection refused, resending (attempt " << send_attempts << ")" << LL_ENDL; - LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL; - resend = TRUE; - } - else - { - // some other error - LL_INFOS() << "sendto() failed: " << errno << ", " << strerror(errno) << LL_ENDL; - LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL; - resend = FALSE; - } - } - } - while (resend && send_attempts < 3); - - if (send_attempts >= 3) - { - LL_INFOS() << "sendPacket() bailed out of send!" << LL_ENDL; - return FALSE; - } - - return success; -} - -#endif - -//EOF +/**
+ * @file net.cpp
+ * @brief Cross-platform routines for sending and receiving packets.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+//#include "net.h"
+
+// system library includes
+#include <stdexcept>
+
+#if LL_WINDOWS
+#include "llwin32headerslean.h"
+#else
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <fcntl.h>
+ #include <errno.h>
+#endif
+
+// linden library includes
+#include "llerror.h"
+#include "llhost.h"
+#include "lltimer.h"
+#include "indra_constants.h"
+
+// Globals
+#if LL_WINDOWS
+
+SOCKADDR_IN stDstAddr;
+SOCKADDR_IN stSrcAddr;
+SOCKADDR_IN stLclAddr;
+static WSADATA stWSAData;
+
+#else
+
+struct sockaddr_in stDstAddr;
+struct sockaddr_in stSrcAddr;
+struct sockaddr_in stLclAddr;
+
+#if LL_DARWIN
+#ifndef _SOCKLEN_T
+#define _SOCKLEN_T
+typedef int socklen_t;
+#endif
+#endif
+
+#endif
+
+static U32 gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS; // Address to which datagram was sent
+
+const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1";
+const char* BROADCAST_ADDRESS_STRING = "255.255.255.255";
+
+#if LL_DARWIN
+ // macOS returns an error when trying to set these to 400000. Smaller values succeed.
+ const int SEND_BUFFER_SIZE = 200000;
+ const int RECEIVE_BUFFER_SIZE = 200000;
+#else // LL_DARWIN
+ const int SEND_BUFFER_SIZE = 400000;
+ const int RECEIVE_BUFFER_SIZE = 400000;
+#endif // LL_DARWIN
+
+// universal functions (cross-platform)
+
+LLHost get_sender()
+{
+ return LLHost(stSrcAddr.sin_addr.s_addr, ntohs(stSrcAddr.sin_port));
+}
+
+U32 get_sender_ip(void)
+{
+ return stSrcAddr.sin_addr.s_addr;
+}
+
+U32 get_sender_port()
+{
+ return ntohs(stSrcAddr.sin_port);
+}
+
+LLHost get_receiving_interface()
+{
+ return LLHost(gsnReceivingIFAddr, INVALID_PORT);
+}
+
+U32 get_receiving_interface_ip(void)
+{
+ return gsnReceivingIFAddr;
+}
+
+const char* u32_to_ip_string(U32 ip)
+{
+ static char buffer[MAXADDRSTR]; /* Flawfinder: ignore */
+
+ // Convert the IP address into a string
+ in_addr in;
+ in.s_addr = ip;
+ char* result = inet_ntoa(in);
+
+ // NULL indicates error in conversion
+ if (result != NULL)
+ {
+ strncpy( buffer, result, MAXADDRSTR ); /* Flawfinder: ignore */
+ buffer[MAXADDRSTR-1] = '\0';
+ return buffer;
+ }
+ else
+ {
+ return "(bad IP addr)";
+ }
+}
+
+
+// Returns ip_string if successful, NULL if not. Copies into ip_string
+char *u32_to_ip_string(U32 ip, char *ip_string)
+{
+ char *result;
+ in_addr in;
+
+ // Convert the IP address into a string
+ in.s_addr = ip;
+ result = inet_ntoa(in);
+
+ // NULL indicates error in conversion
+ if (result != NULL)
+ {
+ //the function signature needs to change to pass in the lengfth of first and last.
+ strcpy(ip_string, result); /*Flawfinder: ignore*/
+ return ip_string;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+// Wrapper for inet_addr()
+U32 ip_string_to_u32(const char* ip_string)
+{
+ // *NOTE: Windows doesn't support inet_aton(), so we are using
+ // inet_addr(). Unfortunately, INADDR_NONE == INADDR_BROADCAST, so
+ // we have to check whether the input is a broadcast address before
+ // deciding that @ip_string is invalid.
+ //
+ // Also, our definition of INVALID_HOST_IP_ADDRESS doesn't allow us to
+ // use wildcard addresses. -Ambroff
+ U32 ip = inet_addr(ip_string);
+ if (ip == INADDR_NONE
+ && strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0)
+ {
+ LL_WARNS() << "ip_string_to_u32() failed, Error: Invalid IP string '" << ip_string << "'" << LL_ENDL;
+ return INVALID_HOST_IP_ADDRESS;
+ }
+ return ip;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Windows Versions
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#if LL_WINDOWS
+
+S32 start_net(S32& socket_out, int& nPort)
+{
+ // Create socket, make non-blocking
+ // Init WinSock
+ int nRet;
+ int hSocket;
+
+ int snd_size = SEND_BUFFER_SIZE;
+ int rec_size = RECEIVE_BUFFER_SIZE;
+ int buff_size = 4;
+
+ // Initialize windows specific stuff
+ if (WSAStartup(0x0202, &stWSAData))
+ {
+ S32 err = WSAGetLastError();
+ WSACleanup();
+ LL_WARNS("AppInit") << "Windows Sockets initialization failed, err " << err << LL_ENDL;
+ return 1;
+ }
+
+ // Get a datagram socket
+ hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
+ if (hSocket == INVALID_SOCKET)
+ {
+ S32 err = WSAGetLastError();
+ WSACleanup();
+ LL_WARNS("AppInit") << "socket() failed, err " << err << LL_ENDL;
+ return 2;
+ }
+
+ // Name the socket (assign the local port number to receive on)
+ stLclAddr.sin_family = AF_INET;
+ stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ stLclAddr.sin_port = htons(nPort);
+
+ S32 attempt_port = nPort;
+ LL_DEBUGS("AppInit") << "attempting to connect on port " << attempt_port << LL_ENDL;
+ nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
+
+ if (nRet == SOCKET_ERROR)
+ {
+ // If we got an address in use error...
+ if (WSAGetLastError() == WSAEADDRINUSE)
+ {
+ // Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX
+ for(attempt_port = PORT_DISCOVERY_RANGE_MIN;
+ attempt_port <= PORT_DISCOVERY_RANGE_MAX;
+ attempt_port++)
+ {
+ stLclAddr.sin_port = htons(attempt_port);
+ LL_DEBUGS("AppInit") << "trying port " << attempt_port << LL_ENDL;
+ nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
+
+ if (!(nRet == SOCKET_ERROR &&
+ WSAGetLastError() == WSAEADDRINUSE))
+ {
+ break;
+ }
+ }
+
+ if (nRet == SOCKET_ERROR)
+ {
+ LL_WARNS("AppInit") << "startNet() : Couldn't find available network port." << LL_ENDL;
+ // Fail gracefully here in release
+ return 3;
+ }
+ }
+ else
+ // Some other socket error
+ {
+ LL_WARNS("AppInit") << llformat("bind() port: %d failed, Err: %d\n", nPort, WSAGetLastError()) << LL_ENDL;
+ // Fail gracefully in release.
+ return 4;
+ }
+ }
+
+ sockaddr_in socket_address;
+ S32 socket_address_size = sizeof(socket_address);
+ getsockname(hSocket, (SOCKADDR*) &socket_address, &socket_address_size);
+ attempt_port = ntohs(socket_address.sin_port);
+
+ LL_INFOS("AppInit") << "connected on port " << attempt_port << LL_ENDL;
+ nPort = attempt_port;
+
+ // Set socket to be non-blocking
+ unsigned long argp = 1;
+ nRet = ioctlsocket (hSocket, FIONBIO, &argp);
+ if (nRet == SOCKET_ERROR)
+ {
+ printf("Failed to set socket non-blocking, Err: %d\n",
+ WSAGetLastError());
+ }
+
+ // set a large receive buffer
+ nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
+ if (nRet)
+ {
+ LL_INFOS("AppInit") << "Can't set receive buffer size!" << LL_ENDL;
+ }
+
+ nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
+ if (nRet)
+ {
+ LL_INFOS("AppInit") << "Can't set send buffer size!" << LL_ENDL;
+ }
+
+ getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
+ getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);
+
+ LL_DEBUGS("AppInit") << "startNet - receive buffer size : " << rec_size << LL_ENDL;
+ LL_DEBUGS("AppInit") << "startNet - send buffer size : " << snd_size << LL_ENDL;
+
+ // Setup a destination address
+ stDstAddr.sin_family = AF_INET;
+ stDstAddr.sin_addr.s_addr = INVALID_HOST_IP_ADDRESS;
+ stDstAddr.sin_port = htons(nPort);
+
+ socket_out = hSocket;
+ return 0;
+}
+
+void end_net(S32& socket_out)
+{
+ if (socket_out >= 0)
+ {
+ shutdown(socket_out, SD_BOTH);
+ closesocket(socket_out);
+ }
+ WSACleanup();
+}
+
+S32 receive_packet(int hSocket, char * receiveBuffer)
+{
+ // Receives data asynchronously from the socket set by initNet().
+ // Returns the number of bytes received into dataReceived, or zero
+ // if there is no data received.
+ int nRet;
+ int addr_size = sizeof(struct sockaddr_in);
+
+ nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, 0, (struct sockaddr*)&stSrcAddr, &addr_size);
+ if (nRet == SOCKET_ERROR )
+ {
+ if (WSAEWOULDBLOCK == WSAGetLastError())
+ return 0;
+ if (WSAECONNRESET == WSAGetLastError())
+ return 0;
+ LL_INFOS() << "receivePacket() failed, Error: " << WSAGetLastError() << LL_ENDL;
+ }
+
+ return nRet;
+}
+
+// Returns true on success.
+bool send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort)
+{
+ // Sends a packet to the address set in initNet
+ //
+ int nRet = 0;
+ U32 last_error = 0;
+
+ stDstAddr.sin_addr.s_addr = recipient;
+ stDstAddr.sin_port = htons(nPort);
+ do
+ {
+ nRet = sendto(hSocket, sendBuffer, size, 0, (struct sockaddr*)&stDstAddr, sizeof(stDstAddr));
+
+ if (nRet == SOCKET_ERROR )
+ {
+ last_error = WSAGetLastError();
+ if (last_error != WSAEWOULDBLOCK)
+ {
+ // WSAECONNRESET - I think this is caused by an ICMP "connection refused"
+ // message being sent back from a Linux box... I'm not finding helpful
+ // documentation or web pages on this. The question is whether the packet
+ // actually got sent or not. Based on the structure of this code, I would
+ // assume it is. JNC 2002.01.18
+ if (WSAECONNRESET == WSAGetLastError())
+ {
+ return true;
+ }
+ LL_INFOS() << "sendto() failed to " << u32_to_ip_string(recipient) << ":" << nPort
+ << ", Error " << last_error << LL_ENDL;
+ }
+ }
+ } while ( (nRet == SOCKET_ERROR)
+ &&(last_error == WSAEWOULDBLOCK));
+
+ return (nRet != SOCKET_ERROR);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Linux Versions
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#else
+
+// Create socket, make non-blocking
+S32 start_net(S32& socket_out, int& nPort)
+{
+ int hSocket, nRet;
+ int snd_size = SEND_BUFFER_SIZE;
+ int rec_size = RECEIVE_BUFFER_SIZE;
+
+ socklen_t buff_size = 4;
+
+ // Create socket
+ hSocket = socket(AF_INET, SOCK_DGRAM, 0);
+ if (hSocket < 0)
+ {
+ LL_WARNS() << "socket() failed" << LL_ENDL;
+ return 1;
+ }
+
+ if (NET_USE_OS_ASSIGNED_PORT == nPort)
+ {
+ // Although bind is not required it will tell us which port we were
+ // assigned to.
+ stLclAddr.sin_family = AF_INET;
+ stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ stLclAddr.sin_port = htons(0);
+ LL_INFOS() << "attempting to connect on OS assigned port" << LL_ENDL;
+ nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
+ if (nRet < 0)
+ {
+ LL_WARNS() << "Failed to bind on an OS assigned port error: "
+ << nRet << LL_ENDL;
+ }
+ else
+ {
+ sockaddr_in socket_info;
+ socklen_t len = sizeof(sockaddr_in);
+ int err = getsockname(hSocket, (sockaddr*)&socket_info, &len);
+ LL_INFOS() << "Get socket returned: " << err << " length " << len << LL_ENDL;
+ nPort = ntohs(socket_info.sin_port);
+ LL_INFOS() << "Assigned port: " << nPort << LL_ENDL;
+
+ }
+ }
+ else
+ {
+ // Name the socket (assign the local port number to receive on)
+ stLclAddr.sin_family = AF_INET;
+ stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ stLclAddr.sin_port = htons(nPort);
+ U32 attempt_port = nPort;
+ LL_INFOS() << "attempting to connect on port " << attempt_port << LL_ENDL;
+
+ nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
+ if (nRet < 0)
+ {
+ // If we got an address in use error...
+ if (errno == EADDRINUSE)
+ {
+ // Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX
+ for(attempt_port = PORT_DISCOVERY_RANGE_MIN;
+ attempt_port <= PORT_DISCOVERY_RANGE_MAX;
+ attempt_port++)
+ {
+ stLclAddr.sin_port = htons(attempt_port);
+ LL_INFOS() << "trying port " << attempt_port << LL_ENDL;
+ nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
+ if (!((nRet < 0) && (errno == EADDRINUSE)))
+ {
+ break;
+ }
+ }
+ if (nRet < 0)
+ {
+ LL_WARNS() << "startNet() : Couldn't find available network port." << LL_ENDL;
+ // Fail gracefully in release.
+ return 3;
+ }
+ }
+ // Some other socket error
+ else
+ {
+ LL_WARNS() << llformat ("bind() port: %d failed, Err: %s\n", nPort, strerror(errno)) << LL_ENDL;
+ // Fail gracefully in release.
+ return 4;
+ }
+ }
+ LL_INFOS() << "connected on port " << attempt_port << LL_ENDL;
+ nPort = attempt_port;
+ }
+ // Set socket to be non-blocking
+ fcntl(hSocket, F_SETFL, O_NONBLOCK);
+ // set a large receive buffer
+ nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
+ if (nRet)
+ {
+ LL_INFOS() << "Can't set receive size!" << LL_ENDL;
+ }
+ nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
+ if (nRet)
+ {
+ LL_INFOS() << "Can't set send size!" << LL_ENDL;
+ }
+ getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
+ getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);
+
+ LL_INFOS() << "startNet - receive buffer size : " << rec_size << LL_ENDL;
+ LL_INFOS() << "startNet - send buffer size : " << snd_size << LL_ENDL;
+
+#if LL_LINUX
+ // Turn on recipient address tracking
+ {
+ int use_pktinfo = 1;
+ if( setsockopt( hSocket, SOL_IP, IP_PKTINFO, &use_pktinfo, sizeof(use_pktinfo) ) == -1 )
+ {
+ LL_WARNS() << "No IP_PKTINFO available" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "IP_PKKTINFO enabled" << LL_ENDL;
+ }
+ }
+#endif
+
+ // Setup a destination address
+ char achMCAddr[MAXADDRSTR] = "127.0.0.1"; /* Flawfinder: ignore */
+ stDstAddr.sin_family = AF_INET;
+ stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr);
+ stDstAddr.sin_port = htons(nPort);
+
+ socket_out = hSocket;
+ return 0;
+}
+
+void end_net(S32& socket_out)
+{
+ if (socket_out >= 0)
+ {
+ close(socket_out);
+ }
+}
+
+#if LL_LINUX
+static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *from, socklen_t *fromlen, U32 *dstip )
+{
+ int size;
+ struct iovec iov[1];
+ char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
+ struct cmsghdr *cmsgptr;
+ struct msghdr msg = {0};
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+
+ memset(&msg, 0, sizeof msg);
+ msg.msg_name = from;
+ msg.msg_namelen = *fromlen;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &cmsg;
+ msg.msg_controllen = sizeof(cmsg);
+
+ size = recvmsg(socket, &msg, 0);
+
+ if (size == -1)
+ {
+ return -1;
+ }
+
+ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr))
+ {
+ if( cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO )
+ {
+ in_pktinfo *pktinfo = (in_pktinfo *)CMSG_DATA(cmsgptr);
+ if( pktinfo )
+ {
+ // Two choices. routed and specified. ipi_addr is routed, ipi_spec_dst is
+ // routed. We should stay with specified until we go to multiple
+ // interfaces
+ *dstip = pktinfo->ipi_spec_dst.s_addr;
+ }
+ }
+ }
+
+ return size;
+}
+#endif
+
+int receive_packet(int hSocket, char * receiveBuffer)
+{
+ // Receives data asynchronously from the socket set by initNet().
+ // Returns the number of bytes received into dataReceived, or zero
+ // if there is no data received.
+ // or -1 if an error occured!
+ int nRet;
+ socklen_t addr_size = sizeof(struct sockaddr_in);
+
+ gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS;
+
+#if LL_LINUX
+ nRet = recvfrom_destip(hSocket, receiveBuffer, NET_BUFFER_SIZE, (struct sockaddr*)&stSrcAddr, &addr_size, &gsnReceivingIFAddr);
+#else
+ int recv_flags = 0;
+ nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, recv_flags, (struct sockaddr*)&stSrcAddr, &addr_size);
+#endif
+
+ if (nRet == -1)
+ {
+ // To maintain consistency with the Windows implementation, return a zero for size on error.
+ return 0;
+ }
+
+ // Uncomment for testing if/when implementing for Mac or Windows:
+ // LL_INFOS() << "Received datagram to in addr " << u32_to_ip_string(get_receiving_interface_ip()) << LL_ENDL;
+
+ return nRet;
+}
+
+bool send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, int nPort)
+{
+ int ret;
+ bool success;
+ bool resend;
+ S32 send_attempts = 0;
+
+ stDstAddr.sin_addr.s_addr = recipient;
+ stDstAddr.sin_port = htons(nPort);
+
+ do
+ {
+ ret = sendto(hSocket, sendBuffer, size, 0, (struct sockaddr*)&stDstAddr, sizeof(stDstAddr));
+ send_attempts++;
+
+ if (ret >= 0)
+ {
+ // successful send
+ success = true;
+ resend = false;
+ }
+ else
+ {
+ // send failed, check to see if we should resend
+ success = false;
+
+ if (errno == EAGAIN)
+ {
+ // say nothing, just repeat send
+ LL_INFOS() << "sendto() reported buffer full, resending (attempt " << send_attempts << ")" << LL_ENDL;
+ LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL;
+ resend = true;
+ }
+ else if (errno == ECONNREFUSED)
+ {
+ // response to ICMP connection refused message on earlier send
+ LL_INFOS() << "sendto() reported connection refused, resending (attempt " << send_attempts << ")" << LL_ENDL;
+ LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL;
+ resend = true;
+ }
+ else
+ {
+ // some other error
+ LL_INFOS() << "sendto() failed: " << errno << ", " << strerror(errno) << LL_ENDL;
+ LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL;
+ resend = false;
+ }
+ }
+ }
+ while (resend && send_attempts < 3);
+
+ if (send_attempts >= 3)
+ {
+ LL_INFOS() << "sendPacket() bailed out of send!" << LL_ENDL;
+ return false;
+ }
+
+ return success;
+}
+
+#endif
+
+//EOF
diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h index d647da2570..b6040b0a35 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -1,74 +1,74 @@ -/** - * @file net.h - * @brief Cross platform UDP network code. - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#ifndef LL_NET_H -#define LL_NET_H - -class LLTimer; -class LLHost; - -#define NET_BUFFER_SIZE (0x2000) - -// Request a free local port from the operating system -#define NET_USE_OS_ASSIGNED_PORT 0 - -// Returns 0 on success, non-zero on error. -// Sets socket handler/descriptor, changes nPort if port requested is unavailable. -S32 start_net(S32& socket_out, int& nPort); -void end_net(S32& socket_out); - -// returns size of packet or -1 in case of error -S32 receive_packet(int hSocket, char * receiveBuffer); - -BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort); // Returns TRUE on success. - -//void get_sender(char * tmp); -LLHost get_sender(); -U32 get_sender_port(); -U32 get_sender_ip(void); -LLHost get_receiving_interface(); -U32 get_receiving_interface_ip(void); - -const char* u32_to_ip_string(U32 ip); // Returns pointer to internal string buffer, "(bad IP addr)" on failure, cannot nest calls -char* u32_to_ip_string(U32 ip, char *ip_string); // NULL on failure, ip_string on success, you must allocate at least MAXADDRSTR chars -U32 ip_string_to_u32(const char* ip_string); // Wrapper for inet_addr() - -extern const char* LOOPBACK_ADDRESS_STRING; -extern const char* BROADCAST_ADDRESS_STRING; - - -// useful MTU consts - -const S32 MTUBYTES = 1200; // 1500 = standard Ethernet MTU -const S32 ETHERNET_MTU_BYTES = 1500; -const S32 MTUBITS = MTUBYTES*8; -const S32 MTUU32S = MTUBITS/32; - -// For automatic port discovery when running multiple viewers on one host -const U32 PORT_DISCOVERY_RANGE_MIN = 13000; -const U32 PORT_DISCOVERY_RANGE_MAX = PORT_DISCOVERY_RANGE_MIN + 50; - -#endif +/**
+ * @file net.h
+ * @brief Cross platform UDP network code.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#ifndef LL_NET_H
+#define LL_NET_H
+
+class LLTimer;
+class LLHost;
+
+#define NET_BUFFER_SIZE (0x2000)
+
+// Request a free local port from the operating system
+#define NET_USE_OS_ASSIGNED_PORT 0
+
+// Returns 0 on success, non-zero on error.
+// Sets socket handler/descriptor, changes nPort if port requested is unavailable.
+S32 start_net(S32& socket_out, int& nPort);
+void end_net(S32& socket_out);
+
+// returns size of packet or -1 in case of error
+S32 receive_packet(int hSocket, char * receiveBuffer);
+
+bool send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort); // Returns true on success.
+
+//void get_sender(char * tmp);
+LLHost get_sender();
+U32 get_sender_port();
+U32 get_sender_ip(void);
+LLHost get_receiving_interface();
+U32 get_receiving_interface_ip(void);
+
+const char* u32_to_ip_string(U32 ip); // Returns pointer to internal string buffer, "(bad IP addr)" on failure, cannot nest calls
+char* u32_to_ip_string(U32 ip, char *ip_string); // NULL on failure, ip_string on success, you must allocate at least MAXADDRSTR chars
+U32 ip_string_to_u32(const char* ip_string); // Wrapper for inet_addr()
+
+extern const char* LOOPBACK_ADDRESS_STRING;
+extern const char* BROADCAST_ADDRESS_STRING;
+
+
+// useful MTU consts
+
+const S32 MTUBYTES = 1200; // 1500 = standard Ethernet MTU
+const S32 ETHERNET_MTU_BYTES = 1500;
+const S32 MTUBITS = MTUBYTES*8;
+const S32 MTUU32S = MTUBITS/32;
+
+// For automatic port discovery when running multiple viewers on one host
+const U32 PORT_DISCOVERY_RANGE_MIN = 13000;
+const U32 PORT_DISCOVERY_RANGE_MAX = PORT_DISCOVERY_RANGE_MIN + 50;
+
+#endif
diff --git a/indra/llmessage/partsyspacket.cpp b/indra/llmessage/partsyspacket.cpp index 84f3e2cc12..f0af91e7a3 100644 --- a/indra/llmessage/partsyspacket.cpp +++ b/indra/llmessage/partsyspacket.cpp @@ -1,1297 +1,1297 @@ -/** - * @file partsyspacket.cpp - * @brief Object for packing particle system initialization parameters - * before sending them over the network. - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#include "linden_common.h" - -#include "partsyspacket.h" -#include "indra_constants.h" - -// this function is global -void gSetInitDataDefaults(LLPartInitData *setMe) -{ - U32 i; - - //for(i = 0; i < 18; i++) - //{ - // setMe->k[i] = 0.0f; - //} - - //setMe->kill_p[0] = setMe->kill_p[1] = setMe->kill_p[2] = 0.0f; - //setMe->kill_p[3] = -0.2f; // time parameter, die when t= 5.0f - //setMe->kill_p[4] = 1.0f; - //setMe->kill_p[5] = -0.5f; // or radius == 2 (contracting) - - //setMe->bounce_p[0] = setMe->bounce_p[1] = - // setMe->bounce_p[2] = setMe->bounce_p[3] = 0.0f; - //setMe->bounce_p[4] = 1.0f; - - setMe->bounce_b = 1.0f; - // i just changed the meaning of bounce_b - // its now the attenuation from revlecting your velocity across the normal - // set by bounce_p - - //setMe->pos_ranges[0] = setMe->pos_ranges[2] = setMe->pos_ranges[4] = -1.0f; - //setMe->pos_ranges[1] = setMe->pos_ranges[3] = setMe->pos_ranges[5] = 1.0f; - - //setMe->vel_ranges[0] = setMe->vel_ranges[2] = setMe->vel_ranges[4] = -1.0f; - //setMe->vel_ranges[1] = setMe->vel_ranges[3] = setMe->vel_ranges[5] = 1.0f; - - for(i = 0; i < 3; i++) - { - setMe->diffEqAlpha[i] = 0.0f; - setMe->diffEqScale[i] = 0.0f; - } - - setMe->scale_range[0] = 1.00f; - setMe->scale_range[1] = 5.00f; - setMe->scale_range[2] = setMe->scale_range[3] = 0.0f; - - setMe->alpha_range[0] = setMe->alpha_range[1] = 1.0f; - setMe->alpha_range[2] = setMe->alpha_range[3] = 0.0f; - - setMe->vel_offset[0] = 0.0f; - setMe->vel_offset[1] = 0.0f; - setMe->vel_offset[2] = 0.0f; - - // start dropping particles when I'm more then one sim away - setMe->mDistBeginFadeout = 256.0f; - setMe->mDistEndFadeout = 1.414f * 512.0f; - // stop displaying particles when I'm more then two sim diagonals away - - setMe->mImageUuid = IMG_SHOT; - - for(i = 0; i < 8; i++) - { - setMe->mFlags[i] = 0x00; - } - - setMe->createMe = TRUE; - - setMe->maxParticles = 25; - setMe->initialParticles = 25; - - //These defaults are for an explosion - a short lived set of debris affected by gravity. - //Action flags default to PART_SYS_AFFECTED_BY_WIND + PART_SYS_AFFECTED_BY_GRAVITY + PART_SYS_DISTANCE_DEATH - setMe->mFlags[PART_SYS_ACTION_BYTE] = PART_SYS_AFFECTED_BY_WIND | PART_SYS_AFFECTED_BY_GRAVITY | PART_SYS_DISTANCE_DEATH; - setMe->mFlags[PART_SYS_KILL_BYTE] = PART_SYS_DISTANCE_DEATH + PART_SYS_TIME_DEATH; - - setMe->killPlaneNormal[0] = 0.0f;setMe->killPlaneNormal[1] = 0.0f;setMe->killPlaneNormal[2] = 1.0f; //Straight up - setMe->killPlaneZ = 0.0f; //get local ground z as an approximation if turn on PART_SYS_KILL_PLANE - setMe->bouncePlaneNormal[0] = 0.0f;setMe->bouncePlaneNormal[1] = 0.0f;setMe->bouncePlaneNormal[2] = 1.0f; //Straight up - setMe->bouncePlaneZ = 0.0f; //get local ground z as an approximation if turn on PART_SYS_BOUNCE - setMe->spawnRange = 1.0f; - setMe->spawnFrequency = 0.0f; //Create the instant one dies - setMe->spawnFreqencyRange = 0.0f; - setMe->spawnDirection[0] = 0.0f;setMe->spawnDirection[1] = 0.0f;setMe->spawnDirection[2] = 1.0f; //Straight up - setMe->spawnDirectionRange = 1.0f; //global scattering - setMe->spawnVelocity = 0.75f; - setMe->spawnVelocityRange = 0.25f; //velocity +/- 0.25 - setMe->speedLimit = 1.0f; - - setMe->windWeight = 0.5f; //0.0f means looks like a heavy object (if gravity is on), 1.0f means light and fluffy - setMe->currentGravity[0] = 0.0f;setMe->currentGravity[1] = 0.0f;setMe->currentGravity[2] = -9.81f; - //This has to be constant to allow for compression - - setMe->gravityWeight = 0.5f; //0.0f means boyed by air, 1.0f means it's a lead weight - setMe->globalLifetime = 0.0f; //Arbitrary, but default is no global die, so doesn't matter - setMe->individualLifetime = 5.0f; - setMe->individualLifetimeRange = 1.0f; //Particles last 5 secs +/- 1 - setMe->alphaDecay = 1.0f; //normal alpha fadeout - setMe->scaleDecay = 0.0f; //no scale decay - setMe->distanceDeath = 10.0f; //die if hit unit radius - setMe->dampMotionFactor = 0.0f; - - setMe->windDiffusionFactor[0] = 0.0f; - setMe->windDiffusionFactor[1] = 0.0f; - setMe->windDiffusionFactor[2] = 0.0f; -} - -LLPartSysCompressedPacket::LLPartSysCompressedPacket() -{ - // default constructor for mDefaults called implicitly/automatically here - for(int i = 0; i < MAX_PART_SYS_PACKET_SIZE; i++) - { - mData[i] = '\0'; - } - - mNumBytes = 0; - - gSetInitDataDefaults(&mDefaults); -} - -LLPartSysCompressedPacket::~LLPartSysCompressedPacket() -{ - // no dynamic data is stored by this class, do nothing. -} - -void LLPartSysCompressedPacket::writeFlagByte(LLPartInitData *in) -{ - mData[0] = mData[1] = mData[2] = '\0'; - - U32 i; - //for(i = 1; i < 18; i++) { - // if(in->k[i] != mDefaults.k[i]) - // { - // mData[0] |= PART_SYS_K_MASK; - // break; - // } - //} - - if(in->killPlaneZ != mDefaults.killPlaneZ || - in->killPlaneNormal[0] != mDefaults.killPlaneNormal[0] || - in->killPlaneNormal[1] != mDefaults.killPlaneNormal[1] || - in->killPlaneNormal[2] != mDefaults.killPlaneNormal[2] || - in->distanceDeath != mDefaults.distanceDeath) - { - mData[0] |= PART_SYS_KILL_P_MASK; - } - - - - if(in->bouncePlaneZ != mDefaults.bouncePlaneZ || - in->bouncePlaneNormal[0] != mDefaults.bouncePlaneNormal[0] || - in->bouncePlaneNormal[1] != mDefaults.bouncePlaneNormal[1] || - in->bouncePlaneNormal[2] != mDefaults.bouncePlaneNormal[2]) - { - mData[0] |= PART_SYS_BOUNCE_P_MASK; - } - - if(in->bounce_b != mDefaults.bounce_b) - { - mData[0] |= PART_SYS_BOUNCE_B_MASK; - } - - - //if(in->pos_ranges[0] != mDefaults.pos_ranges[0] || in->pos_ranges[1] != mDefaults.pos_ranges[1] || - // in->pos_ranges[2] != mDefaults.pos_ranges[2] || in->pos_ranges[3] != mDefaults.pos_ranges[3] || - // in->pos_ranges[4] != mDefaults.pos_ranges[4] || in->pos_ranges[5] != mDefaults.pos_ranges[5]) - //{ - // mData[0] |= PART_SYS_POS_RANGES_MASK; - //} - - //if(in->vel_ranges[0] != mDefaults.vel_ranges[0] || in->vel_ranges[1] != mDefaults.vel_ranges[1] || - // in->vel_ranges[2] != mDefaults.vel_ranges[2] || in->vel_ranges[3] != mDefaults.vel_ranges[3] || - // in->vel_ranges[4] != mDefaults.vel_ranges[4] || in->vel_ranges[5] != mDefaults.vel_ranges[5]) - //{ -// mData[0] |= PART_SYS_VEL_RANGES_MASK; - //} - - - if(in->diffEqAlpha[0] != mDefaults.diffEqAlpha[0] || - in->diffEqAlpha[1] != mDefaults.diffEqAlpha[1] || - in->diffEqAlpha[2] != mDefaults.diffEqAlpha[2] || - in->diffEqScale[0] != mDefaults.diffEqScale[0] || - in->diffEqScale[1] != mDefaults.diffEqScale[1] || - in->diffEqScale[2] != mDefaults.diffEqScale[2]) - { - mData[0] |= PART_SYS_ALPHA_SCALE_DIFF_MASK; - } - - - if(in->scale_range[0] != mDefaults.scale_range[0] || - in->scale_range[1] != mDefaults.scale_range[1] || - in->scale_range[2] != mDefaults.scale_range[2] || - in->scale_range[3] != mDefaults.scale_range[3]) - { - mData[0] |= PART_SYS_SCALE_RANGE_MASK; - } - - - if(in->alpha_range[0] != mDefaults.alpha_range[0] || - in->alpha_range[1] != mDefaults.alpha_range[1] || - in->alpha_range[2] != mDefaults.alpha_range[2] || - in->alpha_range[3] != mDefaults.alpha_range[3]) - { - mData[2] |= PART_SYS_BYTE_3_ALPHA_MASK; - } - - if(in->vel_offset[0] != mDefaults.vel_offset[0] || - in->vel_offset[1] != mDefaults.vel_offset[1] || - in->vel_offset[2] != mDefaults.vel_offset[2]) - { - mData[0] |= PART_SYS_VEL_OFFSET_MASK; - } - - - if(in->mImageUuid != mDefaults.mImageUuid) - { - mData[0] |= PART_SYS_M_IMAGE_UUID_MASK; - } - - for( i = 0; i < 8; i++) - { - if(in->mFlags[i]) - { - mData[1] |= 1<<i; -// llprintline("Flag \"%x\" gets byte \"%x\"\n", i<<i, in->mFlags[i]); - } - } - - - if(in->spawnRange != mDefaults.spawnRange || - in->spawnFrequency != mDefaults.spawnFrequency || - in->spawnFreqencyRange != mDefaults.spawnFreqencyRange || - in->spawnDirection[0] != mDefaults.spawnDirection[0] || - in->spawnDirection[1] != mDefaults.spawnDirection[1] || - in->spawnDirection[2] != mDefaults.spawnDirection[2] || - in->spawnDirectionRange != mDefaults.spawnDirectionRange || - in->spawnVelocity != mDefaults.spawnVelocity || - in->spawnVelocityRange != mDefaults.spawnVelocityRange) - { - mData[3] |= PART_SYS_BYTE_SPAWN_MASK; - } - - - if(in->windWeight != mDefaults.windWeight || - in->currentGravity[0] != mDefaults.currentGravity[0] || - in->currentGravity[1] != mDefaults.currentGravity[1] || - in->currentGravity[2] != mDefaults.currentGravity[2] || - in->gravityWeight != mDefaults.gravityWeight) - { - mData[3] |= PART_SYS_BYTE_ENVIRONMENT_MASK; - } - - - if(in->globalLifetime != mDefaults.globalLifetime || - in->individualLifetime != mDefaults.individualLifetime || - in->individualLifetimeRange != mDefaults.individualLifetimeRange) - { - mData[3] |= PART_SYS_BYTE_LIFESPAN_MASK; - } - - - if(in->speedLimit != mDefaults.speedLimit || - in->alphaDecay != mDefaults.alphaDecay || - in->scaleDecay != mDefaults.scaleDecay || - in->dampMotionFactor != mDefaults.dampMotionFactor) - { - mData[3] |= PART_SYS_BYTE_DECAY_DAMP_MASK; - } - - if(in->windDiffusionFactor[0] != mDefaults.windDiffusionFactor[0] || - in->windDiffusionFactor[1] != mDefaults.windDiffusionFactor[1] || - in->windDiffusionFactor[2] != mDefaults.windDiffusionFactor[2]) - { - mData[3] |= PART_SYS_BYTE_WIND_DIFF_MASK; - } -} - -F32 floatFromTwoBytes(S8 bMant, S8 bExp) -{ - F32 result = bMant; - while(bExp > 0) - { - result *= 2.0f; - bExp--; - } - while(bExp < 0) - { - result *= 0.5f; - bExp++; - } - return result; -} - -void twoBytesFromFloat(F32 fIn, S8 &bMant, S8 &bExp) -{ - bExp = 0; - if(fIn > 127.0f) - { - fIn = 127.0f; - } - if(fIn < -127.0f) - { - fIn = -127.0f; - } - while(fIn < 64 && fIn > -64 && bExp > -127) - { - fIn *= 2.0f; - bExp--; - } - while((fIn > 128 || fIn < -128) && bExp < 127) - { - fIn *= 0.5f; - bExp++; - } - bMant = (S8)fIn; -} - - - -/* -U32 LLPartSysCompressedPacket::writeK(LLPartInitData *in, U32 startByte) -{ - U32 i, kFlag, i_mod_eight; - S8 bMant, bExp; - - kFlag = startByte; - - startByte += 3; // 3 bytes contain enough room for 18 flag bits - mData[kFlag] = 0x00; -// llprintline("In the writeK\n"); - - i_mod_eight = 0; - for(i = 0; i < 18; i++) - { - if(in->k[i] != mDefaults.k[i]) - { - - mData[kFlag] |= 1<<i_mod_eight; - twoBytesFromFloat(in->k[i], bMant, bExp); - - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - i_mod_eight++; - while(i_mod_eight >= 8) - { - kFlag++; - i_mod_eight -= 8; - } - } - - return startByte; -}*/ - -U32 LLPartSysCompressedPacket::writeKill_p(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - twoBytesFromFloat(in->killPlaneNormal[0], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->killPlaneNormal[1], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->killPlaneNormal[2], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->killPlaneZ, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->distanceDeath, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - -U32 LLPartSysCompressedPacket::writeBounce_p(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - twoBytesFromFloat(in->bouncePlaneNormal[0], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->bouncePlaneNormal[1], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->bouncePlaneNormal[2], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - - twoBytesFromFloat(in->bouncePlaneZ, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - -U32 LLPartSysCompressedPacket::writeBounce_b(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - twoBytesFromFloat(in->bounce_b, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - return startByte; -} - -//U32 LLPartSysCompressedPacket::writePos_ranges(LLPartInitData *in, U32 startByte) -//{ -// S8 tmp; -// int i; -// for(i = 0; i < 6; i++) -// { -// tmp = (S8) in->pos_ranges[i]; // float to int conversion (keep the sign) -// mData[startByte++] = (U8)tmp; // signed to unsigned typecast -// } -// return startByte; -//} - -//U32 LLPartSysCompressedPacket::writeVel_ranges(LLPartInitData *in, U32 startByte) -//{ -// S8 tmp; -// int i; -// for(i = 0; i < 6; i++) -// { -// tmp = (S8) in->vel_ranges[i]; // float to int conversion (keep the sign) -// mData[startByte++] = (U8)tmp; // signed to unsigned typecast -// } -// return startByte; -//} - -U32 LLPartSysCompressedPacket::writeAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->diffEqAlpha[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->diffEqScale[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - return startByte; -} - -U32 LLPartSysCompressedPacket::writeScale_range(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - for(i = 0; i < 4; i++) - { - twoBytesFromFloat(in->scale_range[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - return startByte; -} - - -U32 LLPartSysCompressedPacket::writeAlpha_range(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - for(i = 0; i < 4; i++) - { - twoBytesFromFloat(in->alpha_range[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - return startByte; -} - -U32 LLPartSysCompressedPacket::writeVelocityOffset(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->vel_offset[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - return startByte; -} - -U32 LLPartSysCompressedPacket::writeUUID(LLPartInitData *in, U32 startByte) -{ - U8 * bufPtr = mData + startByte; - if(in->mImageUuid == IMG_SHOT) { - mData[startByte++] = 0x01; - return startByte; - } - - if(in->mImageUuid == IMG_SPARK) { - mData[startByte++] = 0x02; - return startByte; - } - - - if(in->mImageUuid == IMG_BIG_EXPLOSION_1) { - mData[startByte++] = 0x03; - return startByte; - } - - if(in->mImageUuid == IMG_BIG_EXPLOSION_2) { - mData[startByte++] = 0x04; - return startByte; - } - - - if(in->mImageUuid == IMG_SMOKE_POOF) { - mData[startByte++] = 0x05; - return startByte; - } - - if(in->mImageUuid == IMG_FIRE) { - mData[startByte++] = 0x06; - return startByte; - } - - - if(in->mImageUuid == IMG_EXPLOSION) { - mData[startByte++] = 0x07; - return startByte; - } - - if(in->mImageUuid == IMG_EXPLOSION_2) { - mData[startByte++] = 0x08; - return startByte; - } - - - if(in->mImageUuid == IMG_EXPLOSION_3) { - mData[startByte++] = 0x09; - return startByte; - } - - if(in->mImageUuid == IMG_EXPLOSION_4) { - mData[startByte++] = 0x0A; - return startByte; - } - - mData[startByte++] = 0x00; // flag for "read whole UUID" - - memcpy(bufPtr, in->mImageUuid.mData, 16); /* Flawfinder: ignore */ - return (startByte+16); -} - -U32 LLPartSysCompressedPacket::writeSpawn(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - - twoBytesFromFloat(in->spawnRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->spawnFrequency, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->spawnFreqencyRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - - - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->spawnDirection[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - - twoBytesFromFloat(in->spawnDirectionRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->spawnVelocity, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->spawnVelocityRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - -U32 LLPartSysCompressedPacket::writeEnvironment(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - - twoBytesFromFloat(in->windWeight, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->currentGravity[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - - twoBytesFromFloat(in->gravityWeight, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - return startByte; -} - -U32 LLPartSysCompressedPacket::writeLifespan(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - - twoBytesFromFloat(in->globalLifetime, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->individualLifetime, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->individualLifetimeRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - - -U32 LLPartSysCompressedPacket::writeDecayDamp(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - - twoBytesFromFloat(in->speedLimit, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->alphaDecay, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->scaleDecay, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->dampMotionFactor, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - -U32 LLPartSysCompressedPacket::writeWindDiffusionFactor(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - - twoBytesFromFloat(in->windDiffusionFactor[0], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->windDiffusionFactor[1], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->windDiffusionFactor[2], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - - - - - - -/* -U32 LLPartSysCompressedPacket::readK(LLPartInitData *in, U32 startByte) -{ - U32 i, i_mod_eight, kFlag; - S8 bMant, bExp; // 1 bytes mantissa and exponent for a float - kFlag = startByte; - startByte += 3; // 3 bytes has enough room for 18 bits - - i_mod_eight = 0; - for(i = 0; i < 18; i++) - { - if(mData[kFlag]&(1<<i_mod_eight)) - { - - - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - - - in->k[i] = floatFromTwoBytes(bMant, bExp); // much tighter platform-independent - // way to ship floats - - } - i_mod_eight++; - if(i_mod_eight >= 8) - { - i_mod_eight -= 8; - kFlag++; - } - } - - return startByte; -} -*/ - -U32 LLPartSysCompressedPacket::readKill_p(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->killPlaneNormal[0] = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->killPlaneNormal[1] = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->killPlaneNormal[2] = floatFromTwoBytes(bMant, bExp); - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->killPlaneZ = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->distanceDeath = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readBounce_p(LLPartInitData *in, U32 startByte) -{ - - S8 bMant, bExp; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bouncePlaneNormal[0] = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bouncePlaneNormal[1] = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bouncePlaneNormal[2] = floatFromTwoBytes(bMant, bExp); - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bouncePlaneZ = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readBounce_b(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bounce_b = floatFromTwoBytes(bMant, bExp); - return startByte; -} - - -//U32 LLPartSysCompressedPacket::readPos_ranges(LLPartInitData *in, U32 startByte) -//{ -// S8 tmp; -// int i; -// for(i = 0; i < 6; i++) -// { -// tmp = (S8)mData[startByte++]; -// in->pos_ranges[i] = tmp; -// } -// return startByte; -//} - -//U32 LLPartSysCompressedPacket::readVel_ranges(LLPartInitData *in, U32 startByte) -//{ -// S8 tmp; -// int i; -// for(i = 0; i < 6; i++) -// { -// tmp = (S8)mData[startByte++]; -// in->vel_ranges[i] = tmp; -// } -// return startByte; -//} - - - -U32 LLPartSysCompressedPacket::readAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->diffEqAlpha[i] = floatFromTwoBytes(bMant, bExp); - } - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->diffEqScale[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -U32 LLPartSysCompressedPacket::readAlpha_range(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 4; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->alpha_range[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -U32 LLPartSysCompressedPacket::readScale_range(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 4; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->scale_range[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -U32 LLPartSysCompressedPacket::readVelocityOffset(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->vel_offset[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -U32 LLPartSysCompressedPacket::readUUID(LLPartInitData *in, U32 startByte) -{ - U8 * bufPtr = mData + startByte; - - if(mData[startByte] == 0x01) - { - in->mImageUuid = IMG_SHOT; - return startByte+1; - } - if(mData[startByte] == 0x02) - { - in->mImageUuid = IMG_SPARK; - return startByte+1; - } - if(mData[startByte] == 0x03) - { - in->mImageUuid = IMG_BIG_EXPLOSION_1; - return startByte+1; - } - if(mData[startByte] == 0x04) - { - in->mImageUuid = IMG_BIG_EXPLOSION_2; - return startByte+1; - } - if(mData[startByte] == 0x05) - { - in->mImageUuid = IMG_SMOKE_POOF; - return startByte+1; - } - if(mData[startByte] == 0x06) - { - in->mImageUuid = IMG_FIRE; - return startByte+1; - } - if(mData[startByte] == 0x07) - { - in->mImageUuid = IMG_EXPLOSION; - return startByte+1; - } - if(mData[startByte] == 0x08) - { - in->mImageUuid = IMG_EXPLOSION_2; - return startByte+1; - } - if(mData[startByte] == 0x09) - { - in->mImageUuid = IMG_EXPLOSION_3; - return startByte+1; - } - if(mData[startByte] == 0x0A) - { - in->mImageUuid = IMG_EXPLOSION_4; - return startByte+1; - } - - startByte++; // cause we actually have to read the UUID now. - memcpy(in->mImageUuid.mData, bufPtr, 16); /* Flawfinder: ignore */ - return (startByte+16); -} - - - - -U32 LLPartSysCompressedPacket::readSpawn(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - U32 i; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnRange = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnFrequency = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnFreqencyRange = floatFromTwoBytes(bMant, bExp); - - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnDirection[i] = floatFromTwoBytes(bMant, bExp); - } - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnDirectionRange = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnVelocity = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnVelocityRange = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readEnvironment(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - U32 i; - - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->windWeight = floatFromTwoBytes(bMant, bExp); - - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->currentGravity[i] = floatFromTwoBytes(bMant, bExp); - } - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->gravityWeight = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readLifespan(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->globalLifetime = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->individualLifetime = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->individualLifetimeRange = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readDecayDamp(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->speedLimit = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->alphaDecay = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->scaleDecay = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->dampMotionFactor = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readWindDiffusionFactor(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->windDiffusionFactor[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -BOOL LLPartSysCompressedPacket::fromLLPartInitData(LLPartInitData *in, U32 &bytesUsed) -{ - - writeFlagByte(in); - U32 currByte = 4; - -// llprintline("calling \"fromLLPartInitData\"\n"); - - //if(mData[0] & PART_SYS_K_MASK) - //{ - // currByte = writeK(in, 3); // first 3 bytes are reserved for header data - //} - - - - if(mData[0] & PART_SYS_KILL_P_MASK) - { - currByte = writeKill_p(in, currByte); - } - - if(mData[0] & PART_SYS_BOUNCE_P_MASK) - { - currByte = writeBounce_p(in, currByte); - } - - if(mData[0] & PART_SYS_BOUNCE_B_MASK) - { - currByte = writeBounce_b(in, currByte); - } - - //if(mData[0] & PART_SYS_POS_RANGES_MASK) - //{ - // currByte = writePos_ranges(in, currByte); - //} - - //if(mData[0] & PART_SYS_VEL_RANGES_MASK) - //{ - // currByte = writeVel_ranges(in, currByte); - //} - - if(mData[0] & PART_SYS_ALPHA_SCALE_DIFF_MASK) - { - currByte = writeAlphaScaleDiffEqn_range(in, currByte); - } - - if(mData[0] & PART_SYS_SCALE_RANGE_MASK) - { - currByte = writeScale_range(in, currByte); - } - - if(mData[0] & PART_SYS_VEL_OFFSET_MASK) - { - currByte = writeVelocityOffset(in, currByte); - } - - if(mData[0] & PART_SYS_M_IMAGE_UUID_MASK) - { - currByte = writeUUID(in, currByte); - } - - - if(mData[3] & PART_SYS_BYTE_SPAWN_MASK) - { - currByte = writeSpawn(in, currByte); - } - - if(mData[3] & PART_SYS_BYTE_ENVIRONMENT_MASK) - { - currByte = writeEnvironment(in, currByte); - } - - if(mData[3] & PART_SYS_BYTE_LIFESPAN_MASK) - { - currByte = writeLifespan(in, currByte); - } - - if(mData[3] & PART_SYS_BYTE_DECAY_DAMP_MASK) - { - currByte = writeDecayDamp(in, currByte); - } - - if(mData[3] & PART_SYS_BYTE_WIND_DIFF_MASK) - { - currByte = writeWindDiffusionFactor(in, currByte); - } - - - if(mData[2] & PART_SYS_BYTE_3_ALPHA_MASK) - { - currByte = writeAlpha_range(in, currByte); - } - - mData[currByte++] = (U8)in->maxParticles; - mData[currByte++] = (U8)in->initialParticles; - - - U32 flagFlag = 1; // flag indicating which flag bytes are non-zero - // yeah, I know, the name sounds funny - for(U32 i = 0; i < 8; i++) - { - -// llprintline("Flag \"%x\" gets byte \"%x\"\n", flagFlag, in->mFlags[i]); - if(mData[1] & flagFlag) - { - mData[currByte++] = in->mFlags[i]; -// llprintline("and is valid...\n"); - } - flagFlag <<= 1; - } - - bytesUsed = mNumBytes = currByte; - - - -// llprintline("returning from \"fromLLPartInitData\" with %d bytes\n", bytesUsed); - - return TRUE; -} - -BOOL LLPartSysCompressedPacket::toLLPartInitData(LLPartInitData *out, U32 *bytesUsed) -{ - U32 currByte = 4; - - gSetInitDataDefaults(out); - - if(mData[0] & PART_SYS_KILL_P_MASK) - { - currByte = readKill_p(out, currByte); - } - - if(mData[0] & PART_SYS_BOUNCE_P_MASK) - { - currByte = readBounce_p(out, currByte); - } - - if(mData[0] & PART_SYS_BOUNCE_B_MASK) - { - currByte = readBounce_b(out, currByte); - } - - if(mData[0] & PART_SYS_ALPHA_SCALE_DIFF_MASK) - { - currByte = readAlphaScaleDiffEqn_range(out, currByte); - } - - if(mData[0] & PART_SYS_SCALE_RANGE_MASK) - { - currByte = readScale_range(out, currByte); - } - - if(mData[0] & PART_SYS_VEL_OFFSET_MASK) - { - currByte = readVelocityOffset(out, currByte); - } - - if(mData[0] & PART_SYS_M_IMAGE_UUID_MASK) - { - currByte = readUUID(out, currByte); - } - - - if(mData[3] & PART_SYS_BYTE_SPAWN_MASK) - { - currByte = readSpawn(out, currByte); - } - - if(mData[3] & PART_SYS_BYTE_ENVIRONMENT_MASK) - { - currByte = readEnvironment(out, currByte); - } - - if(mData[3] & PART_SYS_BYTE_LIFESPAN_MASK) - { - currByte = readLifespan(out, currByte); - } - - if(mData[3] & PART_SYS_BYTE_DECAY_DAMP_MASK) - { - currByte = readDecayDamp(out, currByte); - } - - if(mData[3] & PART_SYS_BYTE_WIND_DIFF_MASK) - { - currByte = readWindDiffusionFactor(out, currByte); - } - - if(mData[2] & PART_SYS_BYTE_3_ALPHA_MASK) - { - currByte = readAlpha_range(out, currByte); - } - - out->maxParticles = mData[currByte++]; - out->initialParticles = mData[currByte++]; - - U32 flagFlag = 1; // flag indicating which flag bytes are non-zero - // yeah, I know, the name sounds funny - for(U32 i = 0; i < 8; i++) - { - flagFlag = 1<<i; - - if((mData[1] & flagFlag)) - { - out->mFlags[i] = mData[currByte++]; - } - } - - *bytesUsed = currByte; - return TRUE; -} - -BOOL LLPartSysCompressedPacket::fromUnsignedBytes(U8 *in, U32 bytesUsed) -{ - if ((in != NULL) && (bytesUsed <= sizeof(mData))) - { - memcpy(mData, in, bytesUsed); /* Flawfinder: ignore */ - mNumBytes = bytesUsed; - return TRUE; - } - else - { - LL_ERRS() << "NULL input data or number of bytes exceed mData size" << LL_ENDL; - return FALSE; - } -} - - -U32 LLPartSysCompressedPacket::bufferSize() -{ - return mNumBytes; -} - -BOOL LLPartSysCompressedPacket::toUnsignedBytes(U8 *out) -{ - memcpy(out, mData, mNumBytes); /* Flawfinder: ignore */ - return TRUE; -} - -U8 * LLPartSysCompressedPacket::getBytePtr() -{ - return mData; -} - - +/**
+ * @file partsyspacket.cpp
+ * @brief Object for packing particle system initialization parameters
+ * before sending them over the network.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+#include "partsyspacket.h"
+#include "indra_constants.h"
+
+// this function is global
+void gSetInitDataDefaults(LLPartInitData *setMe)
+{
+ U32 i;
+
+ //for(i = 0; i < 18; i++)
+ //{
+ // setMe->k[i] = 0.0f;
+ //}
+
+ //setMe->kill_p[0] = setMe->kill_p[1] = setMe->kill_p[2] = 0.0f;
+ //setMe->kill_p[3] = -0.2f; // time parameter, die when t= 5.0f
+ //setMe->kill_p[4] = 1.0f;
+ //setMe->kill_p[5] = -0.5f; // or radius == 2 (contracting)
+
+ //setMe->bounce_p[0] = setMe->bounce_p[1] =
+ // setMe->bounce_p[2] = setMe->bounce_p[3] = 0.0f;
+ //setMe->bounce_p[4] = 1.0f;
+
+ setMe->bounce_b = 1.0f;
+ // i just changed the meaning of bounce_b
+ // its now the attenuation from revlecting your velocity across the normal
+ // set by bounce_p
+
+ //setMe->pos_ranges[0] = setMe->pos_ranges[2] = setMe->pos_ranges[4] = -1.0f;
+ //setMe->pos_ranges[1] = setMe->pos_ranges[3] = setMe->pos_ranges[5] = 1.0f;
+
+ //setMe->vel_ranges[0] = setMe->vel_ranges[2] = setMe->vel_ranges[4] = -1.0f;
+ //setMe->vel_ranges[1] = setMe->vel_ranges[3] = setMe->vel_ranges[5] = 1.0f;
+
+ for(i = 0; i < 3; i++)
+ {
+ setMe->diffEqAlpha[i] = 0.0f;
+ setMe->diffEqScale[i] = 0.0f;
+ }
+
+ setMe->scale_range[0] = 1.00f;
+ setMe->scale_range[1] = 5.00f;
+ setMe->scale_range[2] = setMe->scale_range[3] = 0.0f;
+
+ setMe->alpha_range[0] = setMe->alpha_range[1] = 1.0f;
+ setMe->alpha_range[2] = setMe->alpha_range[3] = 0.0f;
+
+ setMe->vel_offset[0] = 0.0f;
+ setMe->vel_offset[1] = 0.0f;
+ setMe->vel_offset[2] = 0.0f;
+
+ // start dropping particles when I'm more then one sim away
+ setMe->mDistBeginFadeout = 256.0f;
+ setMe->mDistEndFadeout = 1.414f * 512.0f;
+ // stop displaying particles when I'm more then two sim diagonals away
+
+ setMe->mImageUuid = IMG_SHOT;
+
+ for(i = 0; i < 8; i++)
+ {
+ setMe->mFlags[i] = 0x00;
+ }
+
+ setMe->createMe = true;
+
+ setMe->maxParticles = 25;
+ setMe->initialParticles = 25;
+
+ //These defaults are for an explosion - a short lived set of debris affected by gravity.
+ //Action flags default to PART_SYS_AFFECTED_BY_WIND + PART_SYS_AFFECTED_BY_GRAVITY + PART_SYS_DISTANCE_DEATH
+ setMe->mFlags[PART_SYS_ACTION_BYTE] = PART_SYS_AFFECTED_BY_WIND | PART_SYS_AFFECTED_BY_GRAVITY | PART_SYS_DISTANCE_DEATH;
+ setMe->mFlags[PART_SYS_KILL_BYTE] = PART_SYS_DISTANCE_DEATH + PART_SYS_TIME_DEATH;
+
+ setMe->killPlaneNormal[0] = 0.0f;setMe->killPlaneNormal[1] = 0.0f;setMe->killPlaneNormal[2] = 1.0f; //Straight up
+ setMe->killPlaneZ = 0.0f; //get local ground z as an approximation if turn on PART_SYS_KILL_PLANE
+ setMe->bouncePlaneNormal[0] = 0.0f;setMe->bouncePlaneNormal[1] = 0.0f;setMe->bouncePlaneNormal[2] = 1.0f; //Straight up
+ setMe->bouncePlaneZ = 0.0f; //get local ground z as an approximation if turn on PART_SYS_BOUNCE
+ setMe->spawnRange = 1.0f;
+ setMe->spawnFrequency = 0.0f; //Create the instant one dies
+ setMe->spawnFreqencyRange = 0.0f;
+ setMe->spawnDirection[0] = 0.0f;setMe->spawnDirection[1] = 0.0f;setMe->spawnDirection[2] = 1.0f; //Straight up
+ setMe->spawnDirectionRange = 1.0f; //global scattering
+ setMe->spawnVelocity = 0.75f;
+ setMe->spawnVelocityRange = 0.25f; //velocity +/- 0.25
+ setMe->speedLimit = 1.0f;
+
+ setMe->windWeight = 0.5f; //0.0f means looks like a heavy object (if gravity is on), 1.0f means light and fluffy
+ setMe->currentGravity[0] = 0.0f;setMe->currentGravity[1] = 0.0f;setMe->currentGravity[2] = -9.81f;
+ //This has to be constant to allow for compression
+
+ setMe->gravityWeight = 0.5f; //0.0f means boyed by air, 1.0f means it's a lead weight
+ setMe->globalLifetime = 0.0f; //Arbitrary, but default is no global die, so doesn't matter
+ setMe->individualLifetime = 5.0f;
+ setMe->individualLifetimeRange = 1.0f; //Particles last 5 secs +/- 1
+ setMe->alphaDecay = 1.0f; //normal alpha fadeout
+ setMe->scaleDecay = 0.0f; //no scale decay
+ setMe->distanceDeath = 10.0f; //die if hit unit radius
+ setMe->dampMotionFactor = 0.0f;
+
+ setMe->windDiffusionFactor[0] = 0.0f;
+ setMe->windDiffusionFactor[1] = 0.0f;
+ setMe->windDiffusionFactor[2] = 0.0f;
+}
+
+LLPartSysCompressedPacket::LLPartSysCompressedPacket()
+{
+ // default constructor for mDefaults called implicitly/automatically here
+ for(int i = 0; i < MAX_PART_SYS_PACKET_SIZE; i++)
+ {
+ mData[i] = '\0';
+ }
+
+ mNumBytes = 0;
+
+ gSetInitDataDefaults(&mDefaults);
+}
+
+LLPartSysCompressedPacket::~LLPartSysCompressedPacket()
+{
+ // no dynamic data is stored by this class, do nothing.
+}
+
+void LLPartSysCompressedPacket::writeFlagByte(LLPartInitData *in)
+{
+ mData[0] = mData[1] = mData[2] = '\0';
+
+ U32 i;
+ //for(i = 1; i < 18; i++) {
+ // if(in->k[i] != mDefaults.k[i])
+ // {
+ // mData[0] |= PART_SYS_K_MASK;
+ // break;
+ // }
+ //}
+
+ if(in->killPlaneZ != mDefaults.killPlaneZ ||
+ in->killPlaneNormal[0] != mDefaults.killPlaneNormal[0] ||
+ in->killPlaneNormal[1] != mDefaults.killPlaneNormal[1] ||
+ in->killPlaneNormal[2] != mDefaults.killPlaneNormal[2] ||
+ in->distanceDeath != mDefaults.distanceDeath)
+ {
+ mData[0] |= PART_SYS_KILL_P_MASK;
+ }
+
+
+
+ if(in->bouncePlaneZ != mDefaults.bouncePlaneZ ||
+ in->bouncePlaneNormal[0] != mDefaults.bouncePlaneNormal[0] ||
+ in->bouncePlaneNormal[1] != mDefaults.bouncePlaneNormal[1] ||
+ in->bouncePlaneNormal[2] != mDefaults.bouncePlaneNormal[2])
+ {
+ mData[0] |= PART_SYS_BOUNCE_P_MASK;
+ }
+
+ if(in->bounce_b != mDefaults.bounce_b)
+ {
+ mData[0] |= PART_SYS_BOUNCE_B_MASK;
+ }
+
+
+ //if(in->pos_ranges[0] != mDefaults.pos_ranges[0] || in->pos_ranges[1] != mDefaults.pos_ranges[1] ||
+ // in->pos_ranges[2] != mDefaults.pos_ranges[2] || in->pos_ranges[3] != mDefaults.pos_ranges[3] ||
+ // in->pos_ranges[4] != mDefaults.pos_ranges[4] || in->pos_ranges[5] != mDefaults.pos_ranges[5])
+ //{
+ // mData[0] |= PART_SYS_POS_RANGES_MASK;
+ //}
+
+ //if(in->vel_ranges[0] != mDefaults.vel_ranges[0] || in->vel_ranges[1] != mDefaults.vel_ranges[1] ||
+ // in->vel_ranges[2] != mDefaults.vel_ranges[2] || in->vel_ranges[3] != mDefaults.vel_ranges[3] ||
+ // in->vel_ranges[4] != mDefaults.vel_ranges[4] || in->vel_ranges[5] != mDefaults.vel_ranges[5])
+ //{
+// mData[0] |= PART_SYS_VEL_RANGES_MASK;
+ //}
+
+
+ if(in->diffEqAlpha[0] != mDefaults.diffEqAlpha[0] ||
+ in->diffEqAlpha[1] != mDefaults.diffEqAlpha[1] ||
+ in->diffEqAlpha[2] != mDefaults.diffEqAlpha[2] ||
+ in->diffEqScale[0] != mDefaults.diffEqScale[0] ||
+ in->diffEqScale[1] != mDefaults.diffEqScale[1] ||
+ in->diffEqScale[2] != mDefaults.diffEqScale[2])
+ {
+ mData[0] |= PART_SYS_ALPHA_SCALE_DIFF_MASK;
+ }
+
+
+ if(in->scale_range[0] != mDefaults.scale_range[0] ||
+ in->scale_range[1] != mDefaults.scale_range[1] ||
+ in->scale_range[2] != mDefaults.scale_range[2] ||
+ in->scale_range[3] != mDefaults.scale_range[3])
+ {
+ mData[0] |= PART_SYS_SCALE_RANGE_MASK;
+ }
+
+
+ if(in->alpha_range[0] != mDefaults.alpha_range[0] ||
+ in->alpha_range[1] != mDefaults.alpha_range[1] ||
+ in->alpha_range[2] != mDefaults.alpha_range[2] ||
+ in->alpha_range[3] != mDefaults.alpha_range[3])
+ {
+ mData[2] |= PART_SYS_BYTE_3_ALPHA_MASK;
+ }
+
+ if(in->vel_offset[0] != mDefaults.vel_offset[0] ||
+ in->vel_offset[1] != mDefaults.vel_offset[1] ||
+ in->vel_offset[2] != mDefaults.vel_offset[2])
+ {
+ mData[0] |= PART_SYS_VEL_OFFSET_MASK;
+ }
+
+
+ if(in->mImageUuid != mDefaults.mImageUuid)
+ {
+ mData[0] |= PART_SYS_M_IMAGE_UUID_MASK;
+ }
+
+ for( i = 0; i < 8; i++)
+ {
+ if(in->mFlags[i])
+ {
+ mData[1] |= 1<<i;
+// llprintline("Flag \"%x\" gets byte \"%x\"\n", i<<i, in->mFlags[i]);
+ }
+ }
+
+
+ if(in->spawnRange != mDefaults.spawnRange ||
+ in->spawnFrequency != mDefaults.spawnFrequency ||
+ in->spawnFreqencyRange != mDefaults.spawnFreqencyRange ||
+ in->spawnDirection[0] != mDefaults.spawnDirection[0] ||
+ in->spawnDirection[1] != mDefaults.spawnDirection[1] ||
+ in->spawnDirection[2] != mDefaults.spawnDirection[2] ||
+ in->spawnDirectionRange != mDefaults.spawnDirectionRange ||
+ in->spawnVelocity != mDefaults.spawnVelocity ||
+ in->spawnVelocityRange != mDefaults.spawnVelocityRange)
+ {
+ mData[3] |= PART_SYS_BYTE_SPAWN_MASK;
+ }
+
+
+ if(in->windWeight != mDefaults.windWeight ||
+ in->currentGravity[0] != mDefaults.currentGravity[0] ||
+ in->currentGravity[1] != mDefaults.currentGravity[1] ||
+ in->currentGravity[2] != mDefaults.currentGravity[2] ||
+ in->gravityWeight != mDefaults.gravityWeight)
+ {
+ mData[3] |= PART_SYS_BYTE_ENVIRONMENT_MASK;
+ }
+
+
+ if(in->globalLifetime != mDefaults.globalLifetime ||
+ in->individualLifetime != mDefaults.individualLifetime ||
+ in->individualLifetimeRange != mDefaults.individualLifetimeRange)
+ {
+ mData[3] |= PART_SYS_BYTE_LIFESPAN_MASK;
+ }
+
+
+ if(in->speedLimit != mDefaults.speedLimit ||
+ in->alphaDecay != mDefaults.alphaDecay ||
+ in->scaleDecay != mDefaults.scaleDecay ||
+ in->dampMotionFactor != mDefaults.dampMotionFactor)
+ {
+ mData[3] |= PART_SYS_BYTE_DECAY_DAMP_MASK;
+ }
+
+ if(in->windDiffusionFactor[0] != mDefaults.windDiffusionFactor[0] ||
+ in->windDiffusionFactor[1] != mDefaults.windDiffusionFactor[1] ||
+ in->windDiffusionFactor[2] != mDefaults.windDiffusionFactor[2])
+ {
+ mData[3] |= PART_SYS_BYTE_WIND_DIFF_MASK;
+ }
+}
+
+F32 floatFromTwoBytes(S8 bMant, S8 bExp)
+{
+ F32 result = bMant;
+ while(bExp > 0)
+ {
+ result *= 2.0f;
+ bExp--;
+ }
+ while(bExp < 0)
+ {
+ result *= 0.5f;
+ bExp++;
+ }
+ return result;
+}
+
+void twoBytesFromFloat(F32 fIn, S8 &bMant, S8 &bExp)
+{
+ bExp = 0;
+ if(fIn > 127.0f)
+ {
+ fIn = 127.0f;
+ }
+ if(fIn < -127.0f)
+ {
+ fIn = -127.0f;
+ }
+ while(fIn < 64 && fIn > -64 && bExp > -127)
+ {
+ fIn *= 2.0f;
+ bExp--;
+ }
+ while((fIn > 128 || fIn < -128) && bExp < 127)
+ {
+ fIn *= 0.5f;
+ bExp++;
+ }
+ bMant = (S8)fIn;
+}
+
+
+
+/*
+U32 LLPartSysCompressedPacket::writeK(LLPartInitData *in, U32 startByte)
+{
+ U32 i, kFlag, i_mod_eight;
+ S8 bMant, bExp;
+
+ kFlag = startByte;
+
+ startByte += 3; // 3 bytes contain enough room for 18 flag bits
+ mData[kFlag] = 0x00;
+// llprintline("In the writeK\n");
+
+ i_mod_eight = 0;
+ for(i = 0; i < 18; i++)
+ {
+ if(in->k[i] != mDefaults.k[i])
+ {
+
+ mData[kFlag] |= 1<<i_mod_eight;
+ twoBytesFromFloat(in->k[i], bMant, bExp);
+
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ }
+ i_mod_eight++;
+ while(i_mod_eight >= 8)
+ {
+ kFlag++;
+ i_mod_eight -= 8;
+ }
+ }
+
+ return startByte;
+}*/
+
+U32 LLPartSysCompressedPacket::writeKill_p(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+
+ twoBytesFromFloat(in->killPlaneNormal[0], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->killPlaneNormal[1], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->killPlaneNormal[2], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ twoBytesFromFloat(in->killPlaneZ, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->distanceDeath, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::writeBounce_p(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+
+ twoBytesFromFloat(in->bouncePlaneNormal[0], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->bouncePlaneNormal[1], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->bouncePlaneNormal[2], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+
+ twoBytesFromFloat(in->bouncePlaneZ, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::writeBounce_b(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+ twoBytesFromFloat(in->bounce_b, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ return startByte;
+}
+
+//U32 LLPartSysCompressedPacket::writePos_ranges(LLPartInitData *in, U32 startByte)
+//{
+// S8 tmp;
+// int i;
+// for(i = 0; i < 6; i++)
+// {
+// tmp = (S8) in->pos_ranges[i]; // float to int conversion (keep the sign)
+// mData[startByte++] = (U8)tmp; // signed to unsigned typecast
+// }
+// return startByte;
+//}
+
+//U32 LLPartSysCompressedPacket::writeVel_ranges(LLPartInitData *in, U32 startByte)
+//{
+// S8 tmp;
+// int i;
+// for(i = 0; i < 6; i++)
+// {
+// tmp = (S8) in->vel_ranges[i]; // float to int conversion (keep the sign)
+// mData[startByte++] = (U8)tmp; // signed to unsigned typecast
+// }
+// return startByte;
+//}
+
+U32 LLPartSysCompressedPacket::writeAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+ int i;
+ for(i = 0; i < 3; i++)
+ {
+ twoBytesFromFloat(in->diffEqAlpha[i], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ }
+ for(i = 0; i < 3; i++)
+ {
+ twoBytesFromFloat(in->diffEqScale[i], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ }
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::writeScale_range(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+ int i;
+ for(i = 0; i < 4; i++)
+ {
+ twoBytesFromFloat(in->scale_range[i], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ }
+ return startByte;
+}
+
+
+U32 LLPartSysCompressedPacket::writeAlpha_range(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+ int i;
+ for(i = 0; i < 4; i++)
+ {
+ twoBytesFromFloat(in->alpha_range[i], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ }
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::writeVelocityOffset(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+ int i;
+ for(i = 0; i < 3; i++)
+ {
+ twoBytesFromFloat(in->vel_offset[i], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ }
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::writeUUID(LLPartInitData *in, U32 startByte)
+{
+ U8 * bufPtr = mData + startByte;
+ if(in->mImageUuid == IMG_SHOT) {
+ mData[startByte++] = 0x01;
+ return startByte;
+ }
+
+ if(in->mImageUuid == IMG_SPARK) {
+ mData[startByte++] = 0x02;
+ return startByte;
+ }
+
+
+ if(in->mImageUuid == IMG_BIG_EXPLOSION_1) {
+ mData[startByte++] = 0x03;
+ return startByte;
+ }
+
+ if(in->mImageUuid == IMG_BIG_EXPLOSION_2) {
+ mData[startByte++] = 0x04;
+ return startByte;
+ }
+
+
+ if(in->mImageUuid == IMG_SMOKE_POOF) {
+ mData[startByte++] = 0x05;
+ return startByte;
+ }
+
+ if(in->mImageUuid == IMG_FIRE) {
+ mData[startByte++] = 0x06;
+ return startByte;
+ }
+
+
+ if(in->mImageUuid == IMG_EXPLOSION) {
+ mData[startByte++] = 0x07;
+ return startByte;
+ }
+
+ if(in->mImageUuid == IMG_EXPLOSION_2) {
+ mData[startByte++] = 0x08;
+ return startByte;
+ }
+
+
+ if(in->mImageUuid == IMG_EXPLOSION_3) {
+ mData[startByte++] = 0x09;
+ return startByte;
+ }
+
+ if(in->mImageUuid == IMG_EXPLOSION_4) {
+ mData[startByte++] = 0x0A;
+ return startByte;
+ }
+
+ mData[startByte++] = 0x00; // flag for "read whole UUID"
+
+ memcpy(bufPtr, in->mImageUuid.mData, 16); /* Flawfinder: ignore */
+ return (startByte+16);
+}
+
+U32 LLPartSysCompressedPacket::writeSpawn(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+ int i;
+
+ twoBytesFromFloat(in->spawnRange, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->spawnFrequency, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->spawnFreqencyRange, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+
+
+ for(i = 0; i < 3; i++)
+ {
+ twoBytesFromFloat(in->spawnDirection[i], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ }
+
+ twoBytesFromFloat(in->spawnDirectionRange, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->spawnVelocity, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ twoBytesFromFloat(in->spawnVelocityRange, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::writeEnvironment(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+ int i;
+
+ twoBytesFromFloat(in->windWeight, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ for(i = 0; i < 3; i++)
+ {
+ twoBytesFromFloat(in->currentGravity[i], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ }
+
+ twoBytesFromFloat(in->gravityWeight, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::writeLifespan(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+
+ twoBytesFromFloat(in->globalLifetime, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ twoBytesFromFloat(in->individualLifetime, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ twoBytesFromFloat(in->individualLifetimeRange, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ return startByte;
+}
+
+
+U32 LLPartSysCompressedPacket::writeDecayDamp(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+
+ twoBytesFromFloat(in->speedLimit, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ twoBytesFromFloat(in->alphaDecay, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ twoBytesFromFloat(in->scaleDecay, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ twoBytesFromFloat(in->dampMotionFactor, bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::writeWindDiffusionFactor(LLPartInitData *in, U32 startByte)
+{
+ S8 bExp, bMant;
+
+ twoBytesFromFloat(in->windDiffusionFactor[0], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ twoBytesFromFloat(in->windDiffusionFactor[1], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ twoBytesFromFloat(in->windDiffusionFactor[2], bMant, bExp);
+ mData[startByte++] = bMant;
+ mData[startByte++] = bExp;
+
+ return startByte;
+}
+
+
+
+
+
+
+/*
+U32 LLPartSysCompressedPacket::readK(LLPartInitData *in, U32 startByte)
+{
+ U32 i, i_mod_eight, kFlag;
+ S8 bMant, bExp; // 1 bytes mantissa and exponent for a float
+ kFlag = startByte;
+ startByte += 3; // 3 bytes has enough room for 18 bits
+
+ i_mod_eight = 0;
+ for(i = 0; i < 18; i++)
+ {
+ if(mData[kFlag]&(1<<i_mod_eight))
+ {
+
+
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+
+
+ in->k[i] = floatFromTwoBytes(bMant, bExp); // much tighter platform-independent
+ // way to ship floats
+
+ }
+ i_mod_eight++;
+ if(i_mod_eight >= 8)
+ {
+ i_mod_eight -= 8;
+ kFlag++;
+ }
+ }
+
+ return startByte;
+}
+*/
+
+U32 LLPartSysCompressedPacket::readKill_p(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->killPlaneNormal[0] = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->killPlaneNormal[1] = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->killPlaneNormal[2] = floatFromTwoBytes(bMant, bExp);
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->killPlaneZ = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->distanceDeath = floatFromTwoBytes(bMant, bExp);
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readBounce_p(LLPartInitData *in, U32 startByte)
+{
+
+ S8 bMant, bExp;
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->bouncePlaneNormal[0] = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->bouncePlaneNormal[1] = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->bouncePlaneNormal[2] = floatFromTwoBytes(bMant, bExp);
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->bouncePlaneZ = floatFromTwoBytes(bMant, bExp);
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readBounce_b(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->bounce_b = floatFromTwoBytes(bMant, bExp);
+ return startByte;
+}
+
+
+//U32 LLPartSysCompressedPacket::readPos_ranges(LLPartInitData *in, U32 startByte)
+//{
+// S8 tmp;
+// int i;
+// for(i = 0; i < 6; i++)
+// {
+// tmp = (S8)mData[startByte++];
+// in->pos_ranges[i] = tmp;
+// }
+// return startByte;
+//}
+
+//U32 LLPartSysCompressedPacket::readVel_ranges(LLPartInitData *in, U32 startByte)
+//{
+// S8 tmp;
+// int i;
+// for(i = 0; i < 6; i++)
+// {
+// tmp = (S8)mData[startByte++];
+// in->vel_ranges[i] = tmp;
+// }
+// return startByte;
+//}
+
+
+
+U32 LLPartSysCompressedPacket::readAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte)
+{
+ int i;
+ S8 bMant, bExp;
+ for(i = 0; i < 3; i++)
+ {
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->diffEqAlpha[i] = floatFromTwoBytes(bMant, bExp);
+ }
+ for(i = 0; i < 3; i++)
+ {
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->diffEqScale[i] = floatFromTwoBytes(bMant, bExp);
+ }
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readAlpha_range(LLPartInitData *in, U32 startByte)
+{
+ int i;
+ S8 bMant, bExp;
+ for(i = 0; i < 4; i++)
+ {
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->alpha_range[i] = floatFromTwoBytes(bMant, bExp);
+ }
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readScale_range(LLPartInitData *in, U32 startByte)
+{
+ int i;
+ S8 bMant, bExp;
+ for(i = 0; i < 4; i++)
+ {
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->scale_range[i] = floatFromTwoBytes(bMant, bExp);
+ }
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readVelocityOffset(LLPartInitData *in, U32 startByte)
+{
+ int i;
+ S8 bMant, bExp;
+ for(i = 0; i < 3; i++)
+ {
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->vel_offset[i] = floatFromTwoBytes(bMant, bExp);
+ }
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readUUID(LLPartInitData *in, U32 startByte)
+{
+ U8 * bufPtr = mData + startByte;
+
+ if(mData[startByte] == 0x01)
+ {
+ in->mImageUuid = IMG_SHOT;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x02)
+ {
+ in->mImageUuid = IMG_SPARK;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x03)
+ {
+ in->mImageUuid = IMG_BIG_EXPLOSION_1;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x04)
+ {
+ in->mImageUuid = IMG_BIG_EXPLOSION_2;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x05)
+ {
+ in->mImageUuid = IMG_SMOKE_POOF;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x06)
+ {
+ in->mImageUuid = IMG_FIRE;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x07)
+ {
+ in->mImageUuid = IMG_EXPLOSION;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x08)
+ {
+ in->mImageUuid = IMG_EXPLOSION_2;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x09)
+ {
+ in->mImageUuid = IMG_EXPLOSION_3;
+ return startByte+1;
+ }
+ if(mData[startByte] == 0x0A)
+ {
+ in->mImageUuid = IMG_EXPLOSION_4;
+ return startByte+1;
+ }
+
+ startByte++; // cause we actually have to read the UUID now.
+ memcpy(in->mImageUuid.mData, bufPtr, 16); /* Flawfinder: ignore */
+ return (startByte+16);
+}
+
+
+
+
+U32 LLPartSysCompressedPacket::readSpawn(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+ U32 i;
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->spawnRange = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->spawnFrequency = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->spawnFreqencyRange = floatFromTwoBytes(bMant, bExp);
+
+ for(i = 0; i < 3; i++)
+ {
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->spawnDirection[i] = floatFromTwoBytes(bMant, bExp);
+ }
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->spawnDirectionRange = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->spawnVelocity = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->spawnVelocityRange = floatFromTwoBytes(bMant, bExp);
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readEnvironment(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+ U32 i;
+
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->windWeight = floatFromTwoBytes(bMant, bExp);
+
+ for(i = 0; i < 3; i++)
+ {
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->currentGravity[i] = floatFromTwoBytes(bMant, bExp);
+ }
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->gravityWeight = floatFromTwoBytes(bMant, bExp);
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readLifespan(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->globalLifetime = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->individualLifetime = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->individualLifetimeRange = floatFromTwoBytes(bMant, bExp);
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readDecayDamp(LLPartInitData *in, U32 startByte)
+{
+ S8 bMant, bExp;
+
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->speedLimit = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->alphaDecay = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->scaleDecay = floatFromTwoBytes(bMant, bExp);
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->dampMotionFactor = floatFromTwoBytes(bMant, bExp);
+
+ return startByte;
+}
+
+U32 LLPartSysCompressedPacket::readWindDiffusionFactor(LLPartInitData *in, U32 startByte)
+{
+ int i;
+ S8 bMant, bExp;
+ for(i = 0; i < 3; i++)
+ {
+ bMant = mData[startByte++];
+ bExp = mData[startByte++];
+ in->windDiffusionFactor[i] = floatFromTwoBytes(bMant, bExp);
+ }
+ return startByte;
+}
+
+bool LLPartSysCompressedPacket::fromLLPartInitData(LLPartInitData *in, U32 &bytesUsed)
+{
+
+ writeFlagByte(in);
+ U32 currByte = 4;
+
+// llprintline("calling \"fromLLPartInitData\"\n");
+
+ //if(mData[0] & PART_SYS_K_MASK)
+ //{
+ // currByte = writeK(in, 3); // first 3 bytes are reserved for header data
+ //}
+
+
+
+ if(mData[0] & PART_SYS_KILL_P_MASK)
+ {
+ currByte = writeKill_p(in, currByte);
+ }
+
+ if(mData[0] & PART_SYS_BOUNCE_P_MASK)
+ {
+ currByte = writeBounce_p(in, currByte);
+ }
+
+ if(mData[0] & PART_SYS_BOUNCE_B_MASK)
+ {
+ currByte = writeBounce_b(in, currByte);
+ }
+
+ //if(mData[0] & PART_SYS_POS_RANGES_MASK)
+ //{
+ // currByte = writePos_ranges(in, currByte);
+ //}
+
+ //if(mData[0] & PART_SYS_VEL_RANGES_MASK)
+ //{
+ // currByte = writeVel_ranges(in, currByte);
+ //}
+
+ if(mData[0] & PART_SYS_ALPHA_SCALE_DIFF_MASK)
+ {
+ currByte = writeAlphaScaleDiffEqn_range(in, currByte);
+ }
+
+ if(mData[0] & PART_SYS_SCALE_RANGE_MASK)
+ {
+ currByte = writeScale_range(in, currByte);
+ }
+
+ if(mData[0] & PART_SYS_VEL_OFFSET_MASK)
+ {
+ currByte = writeVelocityOffset(in, currByte);
+ }
+
+ if(mData[0] & PART_SYS_M_IMAGE_UUID_MASK)
+ {
+ currByte = writeUUID(in, currByte);
+ }
+
+
+ if(mData[3] & PART_SYS_BYTE_SPAWN_MASK)
+ {
+ currByte = writeSpawn(in, currByte);
+ }
+
+ if(mData[3] & PART_SYS_BYTE_ENVIRONMENT_MASK)
+ {
+ currByte = writeEnvironment(in, currByte);
+ }
+
+ if(mData[3] & PART_SYS_BYTE_LIFESPAN_MASK)
+ {
+ currByte = writeLifespan(in, currByte);
+ }
+
+ if(mData[3] & PART_SYS_BYTE_DECAY_DAMP_MASK)
+ {
+ currByte = writeDecayDamp(in, currByte);
+ }
+
+ if(mData[3] & PART_SYS_BYTE_WIND_DIFF_MASK)
+ {
+ currByte = writeWindDiffusionFactor(in, currByte);
+ }
+
+
+ if(mData[2] & PART_SYS_BYTE_3_ALPHA_MASK)
+ {
+ currByte = writeAlpha_range(in, currByte);
+ }
+
+ mData[currByte++] = (U8)in->maxParticles;
+ mData[currByte++] = (U8)in->initialParticles;
+
+
+ U32 flagFlag = 1; // flag indicating which flag bytes are non-zero
+ // yeah, I know, the name sounds funny
+ for(U32 i = 0; i < 8; i++)
+ {
+
+// llprintline("Flag \"%x\" gets byte \"%x\"\n", flagFlag, in->mFlags[i]);
+ if(mData[1] & flagFlag)
+ {
+ mData[currByte++] = in->mFlags[i];
+// llprintline("and is valid...\n");
+ }
+ flagFlag <<= 1;
+ }
+
+ bytesUsed = mNumBytes = currByte;
+
+
+
+// llprintline("returning from \"fromLLPartInitData\" with %d bytes\n", bytesUsed);
+
+ return true;
+}
+
+bool LLPartSysCompressedPacket::toLLPartInitData(LLPartInitData *out, U32 *bytesUsed)
+{
+ U32 currByte = 4;
+
+ gSetInitDataDefaults(out);
+
+ if(mData[0] & PART_SYS_KILL_P_MASK)
+ {
+ currByte = readKill_p(out, currByte);
+ }
+
+ if(mData[0] & PART_SYS_BOUNCE_P_MASK)
+ {
+ currByte = readBounce_p(out, currByte);
+ }
+
+ if(mData[0] & PART_SYS_BOUNCE_B_MASK)
+ {
+ currByte = readBounce_b(out, currByte);
+ }
+
+ if(mData[0] & PART_SYS_ALPHA_SCALE_DIFF_MASK)
+ {
+ currByte = readAlphaScaleDiffEqn_range(out, currByte);
+ }
+
+ if(mData[0] & PART_SYS_SCALE_RANGE_MASK)
+ {
+ currByte = readScale_range(out, currByte);
+ }
+
+ if(mData[0] & PART_SYS_VEL_OFFSET_MASK)
+ {
+ currByte = readVelocityOffset(out, currByte);
+ }
+
+ if(mData[0] & PART_SYS_M_IMAGE_UUID_MASK)
+ {
+ currByte = readUUID(out, currByte);
+ }
+
+
+ if(mData[3] & PART_SYS_BYTE_SPAWN_MASK)
+ {
+ currByte = readSpawn(out, currByte);
+ }
+
+ if(mData[3] & PART_SYS_BYTE_ENVIRONMENT_MASK)
+ {
+ currByte = readEnvironment(out, currByte);
+ }
+
+ if(mData[3] & PART_SYS_BYTE_LIFESPAN_MASK)
+ {
+ currByte = readLifespan(out, currByte);
+ }
+
+ if(mData[3] & PART_SYS_BYTE_DECAY_DAMP_MASK)
+ {
+ currByte = readDecayDamp(out, currByte);
+ }
+
+ if(mData[3] & PART_SYS_BYTE_WIND_DIFF_MASK)
+ {
+ currByte = readWindDiffusionFactor(out, currByte);
+ }
+
+ if(mData[2] & PART_SYS_BYTE_3_ALPHA_MASK)
+ {
+ currByte = readAlpha_range(out, currByte);
+ }
+
+ out->maxParticles = mData[currByte++];
+ out->initialParticles = mData[currByte++];
+
+ U32 flagFlag = 1; // flag indicating which flag bytes are non-zero
+ // yeah, I know, the name sounds funny
+ for(U32 i = 0; i < 8; i++)
+ {
+ flagFlag = 1<<i;
+
+ if((mData[1] & flagFlag))
+ {
+ out->mFlags[i] = mData[currByte++];
+ }
+ }
+
+ *bytesUsed = currByte;
+ return true;
+}
+
+bool LLPartSysCompressedPacket::fromUnsignedBytes(U8 *in, U32 bytesUsed)
+{
+ if ((in != NULL) && (bytesUsed <= sizeof(mData)))
+ {
+ memcpy(mData, in, bytesUsed); /* Flawfinder: ignore */
+ mNumBytes = bytesUsed;
+ return true;
+ }
+ else
+ {
+ LL_ERRS() << "NULL input data or number of bytes exceed mData size" << LL_ENDL;
+ return false;
+ }
+}
+
+
+U32 LLPartSysCompressedPacket::bufferSize()
+{
+ return mNumBytes;
+}
+
+bool LLPartSysCompressedPacket::toUnsignedBytes(U8 *out)
+{
+ memcpy(out, mData, mNumBytes); /* Flawfinder: ignore */
+ return true;
+}
+
+U8 * LLPartSysCompressedPacket::getBytePtr()
+{
+ return mData;
+}
+
+
diff --git a/indra/llmessage/partsyspacket.h b/indra/llmessage/partsyspacket.h index 302d3b7cb8..09d0ef76d5 100644 --- a/indra/llmessage/partsyspacket.h +++ b/indra/llmessage/partsyspacket.h @@ -1,261 +1,261 @@ -/** - * @file partsyspacket.h - * @brief Object for packing particle system initialization parameters - * before sending them over the network - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#ifndef LL_PARTSYSPACKET_H -#define LL_PARTSYSPACKET_H - -#include "lluuid.h" - -// Particle system stuff - -const U64 PART_SYS_MAX_TIME_IN_USEC = 1000000; // 1 second, die not quite near instantaneously - - -// this struct is for particle system initialization parameters -// I'm breaking some rules here, but I need a storage structure to hold initialization data -// for these things. Sorry guys, they're not simple enough (yet) to avoid this cleanly -struct LLPartInitData { - // please do not add functions to this class -- data only! - //F32 k[18]; // first 9 --> x,y,z last 9 --> scale, alpha, rot - //F32 kill_p[6]; // last one is for particles that die when they reach a spherical bounding radius - //F32 kill_plane[3]; - //F32 bounce_p[5]; - F32 bounce_b; // recently changed - // no need to store orientation and position here, as they're sent over seperately - //F32 pos_ranges[6]; - //F32 vel_ranges[6]; - F32 scale_range[4]; - F32 alpha_range[4]; - F32 vel_offset[3]; //new - more understandable! - - F32 mDistBeginFadeout; // for fadeout LOD optimization - F32 mDistEndFadeout; - - LLUUID mImageUuid; - //U8 n; // number of particles - U8 mFlags[8]; // for miscellaneous data --> its interpretation can change at my whim! - U8 createMe; // do I need to be created? or has the work allready been done? - //ActionFlag is now mFlags[PART_SYS_ACTION_BYTE] - //Spawn point is initially object creation center - - F32 diffEqAlpha[3]; - F32 diffEqScale[3]; - - U8 maxParticles; - //How many particles exist at any time within the system? - U8 initialParticles; - //How many particles exist when the system is created? - F32 killPlaneZ; - //For simplicity assume the XY plane, so this sets an altitude at which to die - F32 killPlaneNormal[3]; - //Normal if not planar XY - F32 bouncePlaneZ; - //For simplicity assume the XY plane, so this sets an altitude at which to bounce - F32 bouncePlaneNormal[3]; - //Normal if not planar XY - F32 spawnRange; - //Range of emission points about the mSpawnPoint - F32 spawnFrequency; - //Required if the system is to spawn new particles. - //This variable determines the time after a particle dies when it is respawned. - F32 spawnFreqencyRange; - //Determines the random range of time until a new particle is spawned. - F32 spawnDirection[3]; - //Direction vector giving the mean direction in which particles are spawned - F32 spawnDirectionRange; - //Direction limiting the angular range of emissions about the mean direction. 1.0f means everywhere, 0.0f means uni-directional - F32 spawnVelocity; - //The mean speed at which particles are emitted - F32 spawnVelocityRange; - //The range of speeds about the mean at which particles are emitted. - F32 speedLimit; - //Used to constrain particle maximum velocity - F32 windWeight; - //How much of an effect does wind have - F32 currentGravity[3]; - //Gravity direction used in update calculations - F32 gravityWeight; - //How much of an effect does gravity have - F32 globalLifetime; - //If particles re-spawn, a system can exist forever. - //If (ActionFlags & PART_SYS_GLOBAL_DIE) is TRUE this variable is used to determine how long the system lasts. - F32 individualLifetime; - //How long does each particle last if nothing else happens to it - F32 individualLifetimeRange; - //Range of variation in individual lifetimes - F32 alphaDecay; - //By what factor does alpha decrease as the lifetime of a particle is approached. - F32 scaleDecay; - //By what factor does scale decrease as the lifetime of a particle is approached. - F32 distanceDeath; - //With the increased functionality, particle systems can expand to indefinite size - //(e.g. wind can chaotically move particles into a wide spread). - //To avoid particles exceeding normal object size constraints, - //set the PART_SYS_DISTANCE_DEATH flag, and set a distance value here, representing a radius around the spawn point. - F32 dampMotionFactor; - //How much to damp motion - F32 windDiffusionFactor[3]; - //Change the size and alpha of particles as wind speed increases (scale gets bigger, alpha smaller) -}; - -// constants for setting flag values -// BYTES are in range 0-8, bits are in range 2^0 - 2^8 and can only be powers of two -const int PART_SYS_NO_Z_BUFFER_BYTE = 0; // option to turn off z-buffer when rendering -const int PART_SYS_NO_Z_BUFFER_BIT = 2; // particle systems -- -// I advise against using this, as it looks bad in every case I've tried - -const int PART_SYS_SLOW_ANIM_BYTE = 0; // slow animation down by a factor of 10 -const int PART_SYS_SLOW_ANIM_BIT = 1; // useful for tweaking anims during debugging - -const int PART_SYS_FOLLOW_VEL_BYTE = 0; // indicates whether to orient sprites towards -const int PART_SYS_FOLLOW_VEL_BIT = 4; // their velocity vector -- default is FALSE - -const int PART_SYS_IS_LIGHT_BYTE = 0; // indicates whether a particular particle system -const int PART_SYS_IS_LIGHT_BIT = 8; // is also a light object -- for andrew -// should deprecate this once there is a general method for setting light properties of objects - -const int PART_SYS_SPAWN_COPY_BYTE = 0; // indicates whether to spawn baby particle systems on -const int PART_SYS_SPAWN_COPY_BIT = 0x10; // particle death -- intended for smoke trails - -const int PART_SYS_COPY_VEL_BYTE = 0; // indicates whether baby particle systems inherit parents vel -const int PART_SYS_COPY_VEL_BIT = 0x20; // (by default they don't) - -const int PART_SYS_INVISIBLE_BYTE = 0; // optional -- turn off display, just simulate -const int PART_SYS_INVISIBLE_BIT = 0x40; // useful for smoke trails - -const int PART_SYS_ADAPT_TO_FRAMERATE_BYTE = 0; // drop sprites from render call proportionally -const int PART_SYS_ADAPT_TO_FRAMERATE_BIT = 0x80; // to how far we are below 60 fps - - -// 26 September 2001 - not even big enough to hold all changes, so should enlarge anyway -//const U16 MAX_PART_SYS_PACKET_SIZE = 180; -const U16 MAX_PART_SYS_PACKET_SIZE = 256; - -//const U8 PART_SYS_K_MASK = 0x01; -const U8 PART_SYS_KILL_P_MASK = 0x02; -const U8 PART_SYS_BOUNCE_P_MASK = 0x04; -const U8 PART_SYS_BOUNCE_B_MASK = 0x08; -//const U8 PART_SYS_POS_RANGES_MASK = 0x10; -//const U8 PART_SYS_VEL_RANGES_MASK = 0x20; -const U8 PART_SYS_VEL_OFFSET_MASK = 0x10; //re-use one of the original slots now commented out -const U8 PART_SYS_ALPHA_SCALE_DIFF_MASK = 0x20; //re-use one of the original slots now commented out -const U8 PART_SYS_SCALE_RANGE_MASK = 0x40; -const U8 PART_SYS_M_IMAGE_UUID_MASK = 0x80; -const U8 PART_SYS_BYTE_3_ALPHA_MASK = 0x01; // wrapped around, didn't we? - -const U8 PART_SYS_BYTE_SPAWN_MASK = 0x01; -const U8 PART_SYS_BYTE_ENVIRONMENT_MASK = 0x02; -const U8 PART_SYS_BYTE_LIFESPAN_MASK = 0x04; -const U8 PART_SYS_BYTE_DECAY_DAMP_MASK = 0x08; -const U8 PART_SYS_BYTE_WIND_DIFF_MASK = 0x10; - - -// 26 September 2001 - new constants for mActionFlags -const int PART_SYS_ACTION_BYTE = 1; -const U8 PART_SYS_SPAWN = 0x01; -const U8 PART_SYS_BOUNCE = 0x02; -const U8 PART_SYS_AFFECTED_BY_WIND = 0x04; -const U8 PART_SYS_AFFECTED_BY_GRAVITY = 0x08; -const U8 PART_SYS_EVALUATE_WIND_PER_PARTICLE = 0x10; -const U8 PART_SYS_DAMP_MOTION = 0x20; -const U8 PART_SYS_WIND_DIFFUSION = 0x40; - -// 26 September 2001 - new constants for mKillFlags -const int PART_SYS_KILL_BYTE = 2; -const U8 PART_SYS_KILL_PLANE = 0x01; -const U8 PART_SYS_GLOBAL_DIE = 0x02; -const U8 PART_SYS_DISTANCE_DEATH = 0x04; -const U8 PART_SYS_TIME_DEATH = 0x08; - - -// global, because the sim-side also calls it in the LLPartInitDataFactory - - -void gSetInitDataDefaults(LLPartInitData *setMe); - -class LLPartSysCompressedPacket -{ -public: - LLPartSysCompressedPacket(); - ~LLPartSysCompressedPacket(); - BOOL fromLLPartInitData(LLPartInitData *in, U32 &bytesUsed); - BOOL toLLPartInitData(LLPartInitData *out, U32 *bytesUsed); - BOOL fromUnsignedBytes(U8 *in, U32 bytesUsed); - BOOL toUnsignedBytes(U8 *out); - U32 bufferSize(); - U8 *getBytePtr(); - -protected: - U8 mData[MAX_PART_SYS_PACKET_SIZE]; - U32 mNumBytes; - LLPartInitData mDefaults; // this is intended to hold default LLPartInitData values - // please do not modify it - LLPartInitData mWorkingCopy; // uncompressed data I'm working with - -protected: - // private functions (used only to break up code) - void writeFlagByte(LLPartInitData *in); - //U32 writeK(LLPartInitData *in, U32 startByte); - U32 writeKill_p(LLPartInitData *in, U32 startByte); - U32 writeBounce_p(LLPartInitData *in, U32 startByte); - U32 writeBounce_b(LLPartInitData *in, U32 startByte); - //U32 writePos_ranges(LLPartInitData *in, U32 startByte); - //U32 writeVel_ranges(LLPartInitData *in, U32 startByte); - U32 writeAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte); - U32 writeScale_range(LLPartInitData *in, U32 startByte); - U32 writeAlpha_range(LLPartInitData *in, U32 startByte); - U32 writeUUID(LLPartInitData *in, U32 startByte); - - U32 writeVelocityOffset(LLPartInitData *in, U32 startByte); - U32 writeSpawn(LLPartInitData *in, U32 startByte); //all spawn data - U32 writeEnvironment(LLPartInitData *in, U32 startByte); //wind and gravity - U32 writeLifespan(LLPartInitData *in, U32 startByte); //lifespan data - individual and global - U32 writeDecayDamp(LLPartInitData *in, U32 startByte); //alpha and scale, and motion damp - U32 writeWindDiffusionFactor(LLPartInitData *in, U32 startByte); - - - //U32 readK(LLPartInitData *in, U32 startByte); - U32 readKill_p(LLPartInitData *in, U32 startByte); - U32 readBounce_p(LLPartInitData *in, U32 startByte); - U32 readBounce_b(LLPartInitData *in, U32 startByte); - //U32 readPos_ranges(LLPartInitData *in, U32 startByte); - //U32 readVel_ranges(LLPartInitData *in, U32 startByte); - U32 readAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte); - U32 readScale_range(LLPartInitData *in, U32 startByte); - U32 readAlpha_range(LLPartInitData *in, U32 startByte); - U32 readUUID(LLPartInitData *in, U32 startByte); - - U32 readVelocityOffset(LLPartInitData *in, U32 startByte); - U32 readSpawn(LLPartInitData *in, U32 startByte); //all spawn data - U32 readEnvironment(LLPartInitData *in, U32 startByte); //wind and gravity - U32 readLifespan(LLPartInitData *in, U32 startByte); //lifespan data - individual and global - U32 readDecayDamp(LLPartInitData *in, U32 startByte); //alpha and scale, and motion damp - U32 readWindDiffusionFactor(LLPartInitData *in, U32 startByte); -}; - -#endif - +/**
+ * @file partsyspacket.h
+ * @brief Object for packing particle system initialization parameters
+ * before sending them over the network
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#ifndef LL_PARTSYSPACKET_H
+#define LL_PARTSYSPACKET_H
+
+#include "lluuid.h"
+
+// Particle system stuff
+
+const U64 PART_SYS_MAX_TIME_IN_USEC = 1000000; // 1 second, die not quite near instantaneously
+
+
+// this struct is for particle system initialization parameters
+// I'm breaking some rules here, but I need a storage structure to hold initialization data
+// for these things. Sorry guys, they're not simple enough (yet) to avoid this cleanly
+struct LLPartInitData {
+ // please do not add functions to this class -- data only!
+ //F32 k[18]; // first 9 --> x,y,z last 9 --> scale, alpha, rot
+ //F32 kill_p[6]; // last one is for particles that die when they reach a spherical bounding radius
+ //F32 kill_plane[3];
+ //F32 bounce_p[5];
+ F32 bounce_b; // recently changed
+ // no need to store orientation and position here, as they're sent over seperately
+ //F32 pos_ranges[6];
+ //F32 vel_ranges[6];
+ F32 scale_range[4];
+ F32 alpha_range[4];
+ F32 vel_offset[3]; //new - more understandable!
+
+ F32 mDistBeginFadeout; // for fadeout LOD optimization
+ F32 mDistEndFadeout;
+
+ LLUUID mImageUuid;
+ //U8 n; // number of particles
+ U8 mFlags[8]; // for miscellaneous data --> its interpretation can change at my whim!
+ U8 createMe; // do I need to be created? or has the work allready been done?
+ //ActionFlag is now mFlags[PART_SYS_ACTION_BYTE]
+ //Spawn point is initially object creation center
+
+ F32 diffEqAlpha[3];
+ F32 diffEqScale[3];
+
+ U8 maxParticles;
+ //How many particles exist at any time within the system?
+ U8 initialParticles;
+ //How many particles exist when the system is created?
+ F32 killPlaneZ;
+ //For simplicity assume the XY plane, so this sets an altitude at which to die
+ F32 killPlaneNormal[3];
+ //Normal if not planar XY
+ F32 bouncePlaneZ;
+ //For simplicity assume the XY plane, so this sets an altitude at which to bounce
+ F32 bouncePlaneNormal[3];
+ //Normal if not planar XY
+ F32 spawnRange;
+ //Range of emission points about the mSpawnPoint
+ F32 spawnFrequency;
+ //Required if the system is to spawn new particles.
+ //This variable determines the time after a particle dies when it is respawned.
+ F32 spawnFreqencyRange;
+ //Determines the random range of time until a new particle is spawned.
+ F32 spawnDirection[3];
+ //Direction vector giving the mean direction in which particles are spawned
+ F32 spawnDirectionRange;
+ //Direction limiting the angular range of emissions about the mean direction. 1.0f means everywhere, 0.0f means uni-directional
+ F32 spawnVelocity;
+ //The mean speed at which particles are emitted
+ F32 spawnVelocityRange;
+ //The range of speeds about the mean at which particles are emitted.
+ F32 speedLimit;
+ //Used to constrain particle maximum velocity
+ F32 windWeight;
+ //How much of an effect does wind have
+ F32 currentGravity[3];
+ //Gravity direction used in update calculations
+ F32 gravityWeight;
+ //How much of an effect does gravity have
+ F32 globalLifetime;
+ //If particles re-spawn, a system can exist forever.
+ //If (ActionFlags & PART_SYS_GLOBAL_DIE) is true this variable is used to determine how long the system lasts.
+ F32 individualLifetime;
+ //How long does each particle last if nothing else happens to it
+ F32 individualLifetimeRange;
+ //Range of variation in individual lifetimes
+ F32 alphaDecay;
+ //By what factor does alpha decrease as the lifetime of a particle is approached.
+ F32 scaleDecay;
+ //By what factor does scale decrease as the lifetime of a particle is approached.
+ F32 distanceDeath;
+ //With the increased functionality, particle systems can expand to indefinite size
+ //(e.g. wind can chaotically move particles into a wide spread).
+ //To avoid particles exceeding normal object size constraints,
+ //set the PART_SYS_DISTANCE_DEATH flag, and set a distance value here, representing a radius around the spawn point.
+ F32 dampMotionFactor;
+ //How much to damp motion
+ F32 windDiffusionFactor[3];
+ //Change the size and alpha of particles as wind speed increases (scale gets bigger, alpha smaller)
+};
+
+// constants for setting flag values
+// BYTES are in range 0-8, bits are in range 2^0 - 2^8 and can only be powers of two
+const int PART_SYS_NO_Z_BUFFER_BYTE = 0; // option to turn off z-buffer when rendering
+const int PART_SYS_NO_Z_BUFFER_BIT = 2; // particle systems --
+// I advise against using this, as it looks bad in every case I've tried
+
+const int PART_SYS_SLOW_ANIM_BYTE = 0; // slow animation down by a factor of 10
+const int PART_SYS_SLOW_ANIM_BIT = 1; // useful for tweaking anims during debugging
+
+const int PART_SYS_FOLLOW_VEL_BYTE = 0; // indicates whether to orient sprites towards
+const int PART_SYS_FOLLOW_VEL_BIT = 4; // their velocity vector -- default is false
+
+const int PART_SYS_IS_LIGHT_BYTE = 0; // indicates whether a particular particle system
+const int PART_SYS_IS_LIGHT_BIT = 8; // is also a light object -- for andrew
+// should deprecate this once there is a general method for setting light properties of objects
+
+const int PART_SYS_SPAWN_COPY_BYTE = 0; // indicates whether to spawn baby particle systems on
+const int PART_SYS_SPAWN_COPY_BIT = 0x10; // particle death -- intended for smoke trails
+
+const int PART_SYS_COPY_VEL_BYTE = 0; // indicates whether baby particle systems inherit parents vel
+const int PART_SYS_COPY_VEL_BIT = 0x20; // (by default they don't)
+
+const int PART_SYS_INVISIBLE_BYTE = 0; // optional -- turn off display, just simulate
+const int PART_SYS_INVISIBLE_BIT = 0x40; // useful for smoke trails
+
+const int PART_SYS_ADAPT_TO_FRAMERATE_BYTE = 0; // drop sprites from render call proportionally
+const int PART_SYS_ADAPT_TO_FRAMERATE_BIT = 0x80; // to how far we are below 60 fps
+
+
+// 26 September 2001 - not even big enough to hold all changes, so should enlarge anyway
+//const U16 MAX_PART_SYS_PACKET_SIZE = 180;
+const U16 MAX_PART_SYS_PACKET_SIZE = 256;
+
+//const U8 PART_SYS_K_MASK = 0x01;
+const U8 PART_SYS_KILL_P_MASK = 0x02;
+const U8 PART_SYS_BOUNCE_P_MASK = 0x04;
+const U8 PART_SYS_BOUNCE_B_MASK = 0x08;
+//const U8 PART_SYS_POS_RANGES_MASK = 0x10;
+//const U8 PART_SYS_VEL_RANGES_MASK = 0x20;
+const U8 PART_SYS_VEL_OFFSET_MASK = 0x10; //re-use one of the original slots now commented out
+const U8 PART_SYS_ALPHA_SCALE_DIFF_MASK = 0x20; //re-use one of the original slots now commented out
+const U8 PART_SYS_SCALE_RANGE_MASK = 0x40;
+const U8 PART_SYS_M_IMAGE_UUID_MASK = 0x80;
+const U8 PART_SYS_BYTE_3_ALPHA_MASK = 0x01; // wrapped around, didn't we?
+
+const U8 PART_SYS_BYTE_SPAWN_MASK = 0x01;
+const U8 PART_SYS_BYTE_ENVIRONMENT_MASK = 0x02;
+const U8 PART_SYS_BYTE_LIFESPAN_MASK = 0x04;
+const U8 PART_SYS_BYTE_DECAY_DAMP_MASK = 0x08;
+const U8 PART_SYS_BYTE_WIND_DIFF_MASK = 0x10;
+
+
+// 26 September 2001 - new constants for mActionFlags
+const int PART_SYS_ACTION_BYTE = 1;
+const U8 PART_SYS_SPAWN = 0x01;
+const U8 PART_SYS_BOUNCE = 0x02;
+const U8 PART_SYS_AFFECTED_BY_WIND = 0x04;
+const U8 PART_SYS_AFFECTED_BY_GRAVITY = 0x08;
+const U8 PART_SYS_EVALUATE_WIND_PER_PARTICLE = 0x10;
+const U8 PART_SYS_DAMP_MOTION = 0x20;
+const U8 PART_SYS_WIND_DIFFUSION = 0x40;
+
+// 26 September 2001 - new constants for mKillFlags
+const int PART_SYS_KILL_BYTE = 2;
+const U8 PART_SYS_KILL_PLANE = 0x01;
+const U8 PART_SYS_GLOBAL_DIE = 0x02;
+const U8 PART_SYS_DISTANCE_DEATH = 0x04;
+const U8 PART_SYS_TIME_DEATH = 0x08;
+
+
+// global, because the sim-side also calls it in the LLPartInitDataFactory
+
+
+void gSetInitDataDefaults(LLPartInitData *setMe);
+
+class LLPartSysCompressedPacket
+{
+public:
+ LLPartSysCompressedPacket();
+ ~LLPartSysCompressedPacket();
+ bool fromLLPartInitData(LLPartInitData *in, U32 &bytesUsed);
+ bool toLLPartInitData(LLPartInitData *out, U32 *bytesUsed);
+ bool fromUnsignedBytes(U8 *in, U32 bytesUsed);
+ bool toUnsignedBytes(U8 *out);
+ U32 bufferSize();
+ U8 *getBytePtr();
+
+protected:
+ U8 mData[MAX_PART_SYS_PACKET_SIZE];
+ U32 mNumBytes;
+ LLPartInitData mDefaults; // this is intended to hold default LLPartInitData values
+ // please do not modify it
+ LLPartInitData mWorkingCopy; // uncompressed data I'm working with
+
+protected:
+ // private functions (used only to break up code)
+ void writeFlagByte(LLPartInitData *in);
+ //U32 writeK(LLPartInitData *in, U32 startByte);
+ U32 writeKill_p(LLPartInitData *in, U32 startByte);
+ U32 writeBounce_p(LLPartInitData *in, U32 startByte);
+ U32 writeBounce_b(LLPartInitData *in, U32 startByte);
+ //U32 writePos_ranges(LLPartInitData *in, U32 startByte);
+ //U32 writeVel_ranges(LLPartInitData *in, U32 startByte);
+ U32 writeAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte);
+ U32 writeScale_range(LLPartInitData *in, U32 startByte);
+ U32 writeAlpha_range(LLPartInitData *in, U32 startByte);
+ U32 writeUUID(LLPartInitData *in, U32 startByte);
+
+ U32 writeVelocityOffset(LLPartInitData *in, U32 startByte);
+ U32 writeSpawn(LLPartInitData *in, U32 startByte); //all spawn data
+ U32 writeEnvironment(LLPartInitData *in, U32 startByte); //wind and gravity
+ U32 writeLifespan(LLPartInitData *in, U32 startByte); //lifespan data - individual and global
+ U32 writeDecayDamp(LLPartInitData *in, U32 startByte); //alpha and scale, and motion damp
+ U32 writeWindDiffusionFactor(LLPartInitData *in, U32 startByte);
+
+
+ //U32 readK(LLPartInitData *in, U32 startByte);
+ U32 readKill_p(LLPartInitData *in, U32 startByte);
+ U32 readBounce_p(LLPartInitData *in, U32 startByte);
+ U32 readBounce_b(LLPartInitData *in, U32 startByte);
+ //U32 readPos_ranges(LLPartInitData *in, U32 startByte);
+ //U32 readVel_ranges(LLPartInitData *in, U32 startByte);
+ U32 readAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte);
+ U32 readScale_range(LLPartInitData *in, U32 startByte);
+ U32 readAlpha_range(LLPartInitData *in, U32 startByte);
+ U32 readUUID(LLPartInitData *in, U32 startByte);
+
+ U32 readVelocityOffset(LLPartInitData *in, U32 startByte);
+ U32 readSpawn(LLPartInitData *in, U32 startByte); //all spawn data
+ U32 readEnvironment(LLPartInitData *in, U32 startByte); //wind and gravity
+ U32 readLifespan(LLPartInitData *in, U32 startByte); //lifespan data - individual and global
+ U32 readDecayDamp(LLPartInitData *in, U32 startByte); //alpha and scale, and motion damp
+ U32 readWindDiffusionFactor(LLPartInitData *in, U32 startByte);
+};
+
+#endif
+
diff --git a/indra/llmessage/patch_code.cpp b/indra/llmessage/patch_code.cpp index ad5602e391..5c9dc5ad87 100644 --- a/indra/llmessage/patch_code.cpp +++ b/indra/llmessage/patch_code.cpp @@ -1,408 +1,408 @@ -/** - * @file patch_code.cpp - * @brief Encode patch DCT data into bitcode. - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#include "linden_common.h" - -#include "llmath.h" -//#include "vmath.h" -#include "v3math.h" -#include "patch_dct.h" -#include "patch_code.h" -#include "llbitpack.h" - -U32 gPatchSize, gWordBits; - -void init_patch_coding(LLBitPack &bitpack) -{ - bitpack.resetBitPacking(); -} - -void code_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp) -{ -#ifdef LL_BIG_ENDIAN - U8 *stride = (U8 *)&gopp->stride; - bitpack.bitPack(&(stride[1]), 8); - bitpack.bitPack(&(stride[0]), 8); -#else - bitpack.bitPack((U8 *)&gopp->stride, 16); -#endif - bitpack.bitPack((U8 *)&gopp->patch_size, 8); - bitpack.bitPack((U8 *)&gopp->layer_type, 8); - - gPatchSize = gopp->patch_size; -} - -void code_patch_header(LLBitPack &bitpack, LLPatchHeader *ph, S32 *patch) -{ - S32 i, j, temp, patch_size = gPatchSize, wbits = (ph->quant_wbits & 0xf) + 2; - U32 max_wbits = wbits + 5, min_wbits = wbits>>1; - - wbits = min_wbits; - - for (i = 0; i < (int) patch_size*patch_size; i++) - { - temp = patch[i]; - if (temp) - { - if (temp < 0) - temp *= -1; - for (j = max_wbits; j > (int) min_wbits; j--) - { - if (temp & (1<<j)) - { - if (j > wbits) - wbits = j; - break; - } - } - } - } - - wbits += 1; - - ph->quant_wbits &= 0xf0; - - if ( (wbits > 17) - ||(wbits < 2)) - { - LL_ERRS() << "Bits needed per word in code_patch_header out of legal range. Adjust compression quatization." << LL_ENDL; - } - - ph->quant_wbits |= (wbits - 2); - - bitpack.bitPack((U8 *)&ph->quant_wbits, 8); -#ifdef LL_BIG_ENDIAN - U8 *offset = (U8 *)&ph->dc_offset; - bitpack.bitPack(&(offset[3]), 8); - bitpack.bitPack(&(offset[2]), 8); - bitpack.bitPack(&(offset[1]), 8); - bitpack.bitPack(&(offset[0]), 8); -#else - bitpack.bitPack((U8 *)&ph->dc_offset, 32); -#endif -#ifdef LL_BIG_ENDIAN - U8 *range = (U8 *)&ph->range; - bitpack.bitPack(&(range[1]), 8); - bitpack.bitPack(&(range[0]), 8); -#else - bitpack.bitPack((U8 *)&ph->range, 16); -#endif -#ifdef LL_BIG_ENDIAN - U8 *ids = (U8 *)&ph->patchids; - bitpack.bitPack(&(ids[1]), 8); - bitpack.bitPack(&(ids[0]), 2); -#else - bitpack.bitPack((U8 *)&ph->patchids, 10); -#endif - - gWordBits = wbits; -} - -void code_end_of_data(LLBitPack &bitpack) -{ - bitpack.bitPack((U8 *)&END_OF_PATCHES, 8); -} - -void code_patch(LLBitPack &bitpack, S32 *patch, S32 postquant) -{ - S32 i, j, patch_size = gPatchSize, wbits = gWordBits; - S32 temp; - BOOL b_eob; - - if ( (postquant > patch_size*patch_size) - ||(postquant < 0)) - { - LL_ERRS() << "Bad postquant in code_patch!" << LL_ENDL; - } - - if (postquant) - patch[patch_size*patch_size - postquant] = 0; - - for (i = 0; i < patch_size*patch_size; i++) - { - b_eob = FALSE; - temp = patch[i]; - if (!temp) - { - b_eob = TRUE; - for (j = i; j < patch_size*patch_size - postquant; j++) - { - if (patch[j]) - { - b_eob = FALSE; - break; - } - } - if (b_eob) - { - bitpack.bitPack((U8 *)&ZERO_EOB, 2); - return; - } - else - { - bitpack.bitPack((U8 *)&ZERO_CODE, 1); - } - } - else - { - if (temp < 0) - { - temp *= -1; - if (temp > (1<<wbits)) - { - temp = (1<<wbits); -// printf("patch quatization exceeding allowable bits!"); - } - bitpack.bitPack((U8 *)&NEGATIVE_VALUE, 3); - bitpack.bitPack((U8 *)&temp, wbits); - } - else - { - if (temp > (1<<wbits)) - { - temp = (1<<wbits); -// printf("patch quatization exceeding allowable bits!"); - } - bitpack.bitPack((U8 *)&POSITIVE_VALUE, 3); - bitpack.bitPack((U8 *)&temp, wbits); - } - } - } -} - - -void end_patch_coding(LLBitPack &bitpack) -{ - bitpack.flushBitPack(); -} - -void init_patch_decoding(LLBitPack &bitpack) -{ - bitpack.resetBitPacking(); -} - -void decode_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp) -{ - U16 retvalu16; - - retvalu16 = 0; -#ifdef LL_BIG_ENDIAN - U8 *ret = (U8 *)&retvalu16; - bitpack.bitUnpack(&(ret[1]), 8); - bitpack.bitUnpack(&(ret[0]), 8); -#else - bitpack.bitUnpack((U8 *)&retvalu16, 16); -#endif - gopp->stride = retvalu16; - - U8 retvalu8 = 0; - bitpack.bitUnpack(&retvalu8, 8); - gopp->patch_size = retvalu8; - - retvalu8 = 0; - bitpack.bitUnpack(&retvalu8, 8); - gopp->layer_type = retvalu8; - - gPatchSize = gopp->patch_size; -} - -void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph) -{ - U8 retvalu8; - - retvalu8 = 0; - bitpack.bitUnpack(&retvalu8, 8); - ph->quant_wbits = retvalu8; - - if (END_OF_PATCHES == ph->quant_wbits) - { - // End of data, blitz the rest. - ph->dc_offset = 0; - ph->range = 0; - ph->patchids = 0; - return; - } - - U32 retvalu32 = 0; -#ifdef LL_BIG_ENDIAN - U8 *ret = (U8 *)&retvalu32; - bitpack.bitUnpack(&(ret[3]), 8); - bitpack.bitUnpack(&(ret[2]), 8); - bitpack.bitUnpack(&(ret[1]), 8); - bitpack.bitUnpack(&(ret[0]), 8); -#else - bitpack.bitUnpack((U8 *)&retvalu32, 32); -#endif - ph->dc_offset = *(F32 *)&retvalu32; - - U16 retvalu16 = 0; -#ifdef LL_BIG_ENDIAN - ret = (U8 *)&retvalu16; - bitpack.bitUnpack(&(ret[1]), 8); - bitpack.bitUnpack(&(ret[0]), 8); -#else - bitpack.bitUnpack((U8 *)&retvalu16, 16); -#endif - ph->range = retvalu16; - - retvalu16 = 0; -#ifdef LL_BIG_ENDIAN - ret = (U8 *)&retvalu16; - bitpack.bitUnpack(&(ret[1]), 8); - bitpack.bitUnpack(&(ret[0]), 2); -#else - bitpack.bitUnpack((U8 *)&retvalu16, 10); -#endif - ph->patchids = retvalu16; - - gWordBits = (ph->quant_wbits & 0xf) + 2; -} - -void decode_patch(LLBitPack &bitpack, S32 *patches) -{ -#ifdef LL_BIG_ENDIAN - S32 i, j, patch_size = gPatchSize, wbits = gWordBits; - U8 tempu8; - U16 tempu16; - U32 tempu32; - for (i = 0; i < patch_size*patch_size; i++) - { - bitpack.bitUnpack((U8 *)&tempu8, 1); - if (tempu8) - { - // either 0 EOB or Value - bitpack.bitUnpack((U8 *)&tempu8, 1); - if (tempu8) - { - // value - bitpack.bitUnpack((U8 *)&tempu8, 1); - if (tempu8) - { - // negative - patches[i] = -1; - } - else - { - // positive - patches[i] = 1; - } - if (wbits <= 8) - { - bitpack.bitUnpack((U8 *)&tempu8, wbits); - patches[i] *= tempu8; - } - else if (wbits <= 16) - { - tempu16 = 0; - U8 *ret = (U8 *)&tempu16; - bitpack.bitUnpack(&(ret[1]), 8); - bitpack.bitUnpack(&(ret[0]), wbits - 8); - patches[i] *= tempu16; - } - else if (wbits <= 24) - { - tempu32 = 0; - U8 *ret = (U8 *)&tempu32; - bitpack.bitUnpack(&(ret[2]), 8); - bitpack.bitUnpack(&(ret[1]), 8); - bitpack.bitUnpack(&(ret[0]), wbits - 16); - patches[i] *= tempu32; - } - else if (wbits <= 32) - { - tempu32 = 0; - U8 *ret = (U8 *)&tempu32; - bitpack.bitUnpack(&(ret[3]), 8); - bitpack.bitUnpack(&(ret[2]), 8); - bitpack.bitUnpack(&(ret[1]), 8); - bitpack.bitUnpack(&(ret[0]), wbits - 24); - patches[i] *= tempu32; - } - } - else - { - for (j = i; j < patch_size*patch_size; j++) - { - patches[j] = 0; - } - return; - } - } - else - { - patches[i] = 0; - } - } -#else - S32 i, j, patch_size = gPatchSize, wbits = gWordBits; - U32 temp; - for (i = 0; i < patch_size*patch_size; i++) - { - temp = 0; - bitpack.bitUnpack((U8 *)&temp, 1); - if (temp) - { - // either 0 EOB or Value - temp = 0; - bitpack.bitUnpack((U8 *)&temp, 1); - if (temp) - { - // value - temp = 0; - bitpack.bitUnpack((U8 *)&temp, 1); - if (temp) - { - // negative - temp = 0; - bitpack.bitUnpack((U8 *)&temp, wbits); - patches[i] = temp; - patches[i] *= -1; - } - else - { - // positive - temp = 0; - bitpack.bitUnpack((U8 *)&temp, wbits); - patches[i] = temp; - } - } - else - { - for (j = i; j < patch_size*patch_size; j++) - { - patches[j] = 0; - } - return; - } - } - else - { - patches[i] = 0; - } - } -#endif -} - +/**
+ * @file patch_code.cpp
+ * @brief Encode patch DCT data into bitcode.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+#include "llmath.h"
+//#include "vmath.h"
+#include "v3math.h"
+#include "patch_dct.h"
+#include "patch_code.h"
+#include "llbitpack.h"
+
+U32 gPatchSize, gWordBits;
+
+void init_patch_coding(LLBitPack &bitpack)
+{
+ bitpack.resetBitPacking();
+}
+
+void code_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp)
+{
+#ifdef LL_BIG_ENDIAN
+ U8 *stride = (U8 *)&gopp->stride;
+ bitpack.bitPack(&(stride[1]), 8);
+ bitpack.bitPack(&(stride[0]), 8);
+#else
+ bitpack.bitPack((U8 *)&gopp->stride, 16);
+#endif
+ bitpack.bitPack((U8 *)&gopp->patch_size, 8);
+ bitpack.bitPack((U8 *)&gopp->layer_type, 8);
+
+ gPatchSize = gopp->patch_size;
+}
+
+void code_patch_header(LLBitPack &bitpack, LLPatchHeader *ph, S32 *patch)
+{
+ S32 i, j, temp, patch_size = gPatchSize, wbits = (ph->quant_wbits & 0xf) + 2;
+ U32 max_wbits = wbits + 5, min_wbits = wbits>>1;
+
+ wbits = min_wbits;
+
+ for (i = 0; i < (int) patch_size*patch_size; i++)
+ {
+ temp = patch[i];
+ if (temp)
+ {
+ if (temp < 0)
+ temp *= -1;
+ for (j = max_wbits; j > (int) min_wbits; j--)
+ {
+ if (temp & (1<<j))
+ {
+ if (j > wbits)
+ wbits = j;
+ break;
+ }
+ }
+ }
+ }
+
+ wbits += 1;
+
+ ph->quant_wbits &= 0xf0;
+
+ if ( (wbits > 17)
+ ||(wbits < 2))
+ {
+ LL_ERRS() << "Bits needed per word in code_patch_header out of legal range. Adjust compression quatization." << LL_ENDL;
+ }
+
+ ph->quant_wbits |= (wbits - 2);
+
+ bitpack.bitPack((U8 *)&ph->quant_wbits, 8);
+#ifdef LL_BIG_ENDIAN
+ U8 *offset = (U8 *)&ph->dc_offset;
+ bitpack.bitPack(&(offset[3]), 8);
+ bitpack.bitPack(&(offset[2]), 8);
+ bitpack.bitPack(&(offset[1]), 8);
+ bitpack.bitPack(&(offset[0]), 8);
+#else
+ bitpack.bitPack((U8 *)&ph->dc_offset, 32);
+#endif
+#ifdef LL_BIG_ENDIAN
+ U8 *range = (U8 *)&ph->range;
+ bitpack.bitPack(&(range[1]), 8);
+ bitpack.bitPack(&(range[0]), 8);
+#else
+ bitpack.bitPack((U8 *)&ph->range, 16);
+#endif
+#ifdef LL_BIG_ENDIAN
+ U8 *ids = (U8 *)&ph->patchids;
+ bitpack.bitPack(&(ids[1]), 8);
+ bitpack.bitPack(&(ids[0]), 2);
+#else
+ bitpack.bitPack((U8 *)&ph->patchids, 10);
+#endif
+
+ gWordBits = wbits;
+}
+
+void code_end_of_data(LLBitPack &bitpack)
+{
+ bitpack.bitPack((U8 *)&END_OF_PATCHES, 8);
+}
+
+void code_patch(LLBitPack &bitpack, S32 *patch, S32 postquant)
+{
+ S32 i, j, patch_size = gPatchSize, wbits = gWordBits;
+ S32 temp;
+ bool b_eob;
+
+ if ( (postquant > patch_size*patch_size)
+ ||(postquant < 0))
+ {
+ LL_ERRS() << "Bad postquant in code_patch!" << LL_ENDL;
+ }
+
+ if (postquant)
+ patch[patch_size*patch_size - postquant] = 0;
+
+ for (i = 0; i < patch_size*patch_size; i++)
+ {
+ b_eob = false;
+ temp = patch[i];
+ if (!temp)
+ {
+ b_eob = true;
+ for (j = i; j < patch_size*patch_size - postquant; j++)
+ {
+ if (patch[j])
+ {
+ b_eob = false;
+ break;
+ }
+ }
+ if (b_eob)
+ {
+ bitpack.bitPack((U8 *)&ZERO_EOB, 2);
+ return;
+ }
+ else
+ {
+ bitpack.bitPack((U8 *)&ZERO_CODE, 1);
+ }
+ }
+ else
+ {
+ if (temp < 0)
+ {
+ temp *= -1;
+ if (temp > (1<<wbits))
+ {
+ temp = (1<<wbits);
+// printf("patch quatization exceeding allowable bits!");
+ }
+ bitpack.bitPack((U8 *)&NEGATIVE_VALUE, 3);
+ bitpack.bitPack((U8 *)&temp, wbits);
+ }
+ else
+ {
+ if (temp > (1<<wbits))
+ {
+ temp = (1<<wbits);
+// printf("patch quatization exceeding allowable bits!");
+ }
+ bitpack.bitPack((U8 *)&POSITIVE_VALUE, 3);
+ bitpack.bitPack((U8 *)&temp, wbits);
+ }
+ }
+ }
+}
+
+
+void end_patch_coding(LLBitPack &bitpack)
+{
+ bitpack.flushBitPack();
+}
+
+void init_patch_decoding(LLBitPack &bitpack)
+{
+ bitpack.resetBitPacking();
+}
+
+void decode_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp)
+{
+ U16 retvalu16;
+
+ retvalu16 = 0;
+#ifdef LL_BIG_ENDIAN
+ U8 *ret = (U8 *)&retvalu16;
+ bitpack.bitUnpack(&(ret[1]), 8);
+ bitpack.bitUnpack(&(ret[0]), 8);
+#else
+ bitpack.bitUnpack((U8 *)&retvalu16, 16);
+#endif
+ gopp->stride = retvalu16;
+
+ U8 retvalu8 = 0;
+ bitpack.bitUnpack(&retvalu8, 8);
+ gopp->patch_size = retvalu8;
+
+ retvalu8 = 0;
+ bitpack.bitUnpack(&retvalu8, 8);
+ gopp->layer_type = retvalu8;
+
+ gPatchSize = gopp->patch_size;
+}
+
+void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph)
+{
+ U8 retvalu8;
+
+ retvalu8 = 0;
+ bitpack.bitUnpack(&retvalu8, 8);
+ ph->quant_wbits = retvalu8;
+
+ if (END_OF_PATCHES == ph->quant_wbits)
+ {
+ // End of data, blitz the rest.
+ ph->dc_offset = 0;
+ ph->range = 0;
+ ph->patchids = 0;
+ return;
+ }
+
+ U32 retvalu32 = 0;
+#ifdef LL_BIG_ENDIAN
+ U8 *ret = (U8 *)&retvalu32;
+ bitpack.bitUnpack(&(ret[3]), 8);
+ bitpack.bitUnpack(&(ret[2]), 8);
+ bitpack.bitUnpack(&(ret[1]), 8);
+ bitpack.bitUnpack(&(ret[0]), 8);
+#else
+ bitpack.bitUnpack((U8 *)&retvalu32, 32);
+#endif
+ ph->dc_offset = *(F32 *)&retvalu32;
+
+ U16 retvalu16 = 0;
+#ifdef LL_BIG_ENDIAN
+ ret = (U8 *)&retvalu16;
+ bitpack.bitUnpack(&(ret[1]), 8);
+ bitpack.bitUnpack(&(ret[0]), 8);
+#else
+ bitpack.bitUnpack((U8 *)&retvalu16, 16);
+#endif
+ ph->range = retvalu16;
+
+ retvalu16 = 0;
+#ifdef LL_BIG_ENDIAN
+ ret = (U8 *)&retvalu16;
+ bitpack.bitUnpack(&(ret[1]), 8);
+ bitpack.bitUnpack(&(ret[0]), 2);
+#else
+ bitpack.bitUnpack((U8 *)&retvalu16, 10);
+#endif
+ ph->patchids = retvalu16;
+
+ gWordBits = (ph->quant_wbits & 0xf) + 2;
+}
+
+void decode_patch(LLBitPack &bitpack, S32 *patches)
+{
+#ifdef LL_BIG_ENDIAN
+ S32 i, j, patch_size = gPatchSize, wbits = gWordBits;
+ U8 tempu8;
+ U16 tempu16;
+ U32 tempu32;
+ for (i = 0; i < patch_size*patch_size; i++)
+ {
+ bitpack.bitUnpack((U8 *)&tempu8, 1);
+ if (tempu8)
+ {
+ // either 0 EOB or Value
+ bitpack.bitUnpack((U8 *)&tempu8, 1);
+ if (tempu8)
+ {
+ // value
+ bitpack.bitUnpack((U8 *)&tempu8, 1);
+ if (tempu8)
+ {
+ // negative
+ patches[i] = -1;
+ }
+ else
+ {
+ // positive
+ patches[i] = 1;
+ }
+ if (wbits <= 8)
+ {
+ bitpack.bitUnpack((U8 *)&tempu8, wbits);
+ patches[i] *= tempu8;
+ }
+ else if (wbits <= 16)
+ {
+ tempu16 = 0;
+ U8 *ret = (U8 *)&tempu16;
+ bitpack.bitUnpack(&(ret[1]), 8);
+ bitpack.bitUnpack(&(ret[0]), wbits - 8);
+ patches[i] *= tempu16;
+ }
+ else if (wbits <= 24)
+ {
+ tempu32 = 0;
+ U8 *ret = (U8 *)&tempu32;
+ bitpack.bitUnpack(&(ret[2]), 8);
+ bitpack.bitUnpack(&(ret[1]), 8);
+ bitpack.bitUnpack(&(ret[0]), wbits - 16);
+ patches[i] *= tempu32;
+ }
+ else if (wbits <= 32)
+ {
+ tempu32 = 0;
+ U8 *ret = (U8 *)&tempu32;
+ bitpack.bitUnpack(&(ret[3]), 8);
+ bitpack.bitUnpack(&(ret[2]), 8);
+ bitpack.bitUnpack(&(ret[1]), 8);
+ bitpack.bitUnpack(&(ret[0]), wbits - 24);
+ patches[i] *= tempu32;
+ }
+ }
+ else
+ {
+ for (j = i; j < patch_size*patch_size; j++)
+ {
+ patches[j] = 0;
+ }
+ return;
+ }
+ }
+ else
+ {
+ patches[i] = 0;
+ }
+ }
+#else
+ S32 i, j, patch_size = gPatchSize, wbits = gWordBits;
+ U32 temp;
+ for (i = 0; i < patch_size*patch_size; i++)
+ {
+ temp = 0;
+ bitpack.bitUnpack((U8 *)&temp, 1);
+ if (temp)
+ {
+ // either 0 EOB or Value
+ temp = 0;
+ bitpack.bitUnpack((U8 *)&temp, 1);
+ if (temp)
+ {
+ // value
+ temp = 0;
+ bitpack.bitUnpack((U8 *)&temp, 1);
+ if (temp)
+ {
+ // negative
+ temp = 0;
+ bitpack.bitUnpack((U8 *)&temp, wbits);
+ patches[i] = temp;
+ patches[i] *= -1;
+ }
+ else
+ {
+ // positive
+ temp = 0;
+ bitpack.bitUnpack((U8 *)&temp, wbits);
+ patches[i] = temp;
+ }
+ }
+ else
+ {
+ for (j = i; j < patch_size*patch_size; j++)
+ {
+ patches[j] = 0;
+ }
+ return;
+ }
+ }
+ else
+ {
+ patches[i] = 0;
+ }
+ }
+#endif
+}
+
diff --git a/indra/llmessage/patch_dct.cpp b/indra/llmessage/patch_dct.cpp index 66cb256529..10b3e5dd77 100644 --- a/indra/llmessage/patch_dct.cpp +++ b/indra/llmessage/patch_dct.cpp @@ -1,769 +1,769 @@ -/** - * @file patch_dct.cpp - * @brief DCT patch. - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#include "linden_common.h" - -#include "llmath.h" -//#include "vmath.h" -#include "v3math.h" -#include "patch_dct.h" - -typedef struct s_patch_compress_global_data -{ - S32 patch_size; - S32 patch_stride; - U32 charptr; - S32 layer_type; -} PCGD; - -PCGD gPatchCompressGlobalData; - -void reset_patch_compressor(void) -{ - PCGD *pcp = &gPatchCompressGlobalData; - - pcp->charptr = 0; -} - -S32 gCurrentSize = 0; - -F32 gPatchQuantizeTable[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - -void build_patch_quantize_table(S32 size) -{ - S32 i, j; - for (j = 0; j < size; j++) - { - for (i = 0; i < size; i++) - { - gPatchQuantizeTable[j*size + i] = 1.f/(1.f + 2.f*(i+j)); - } - } -} - -F32 gPatchCosines[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - -void setup_patch_cosines(S32 size) -{ - S32 n, u; - F32 oosob = F_PI*0.5f/size; - - for (u = 0; u < size; u++) - { - for (n = 0; n < size; n++) - { - gPatchCosines[u*size+n] = cosf((2.f*n+1.f)*u*oosob); - } - } -} - -S32 gCopyMatrix[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - -void build_copy_matrix(S32 size) -{ - S32 i, j, count; - BOOL b_diag = FALSE; - BOOL b_right = TRUE; - - i = 0; - j = 0; - count = 0; - - while ( (i < size) - &&(j < size)) - { - gCopyMatrix[j*size + i] = count; - - count++; - - if (!b_diag) - { - if (b_right) - { - if (i < size - 1) - i++; - else - j++; - b_right = FALSE; - b_diag = TRUE; - } - else - { - if (j < size - 1) - j++; - else - i++; - b_right = TRUE; - b_diag = TRUE; - } - } - else - { - if (b_right) - { - i++; - j--; - if ( (i == size - 1) - ||(j == 0)) - { - b_diag = FALSE; - } - } - else - { - i--; - j++; - if ( (i == 0) - ||(j == size - 1)) - { - b_diag = FALSE; - } - } - } - } -} - - -void init_patch_compressor(S32 patch_size, S32 patch_stride, S32 layer_type) -{ - PCGD *pcp = &gPatchCompressGlobalData; - - pcp->charptr = 0; - - pcp->patch_size = patch_size; - pcp->patch_stride = patch_stride; - pcp->layer_type = layer_type; - - if (patch_size != gCurrentSize) - { - gCurrentSize = patch_size; - build_patch_quantize_table(patch_size); - setup_patch_cosines(patch_size); - build_copy_matrix(patch_size); - } -} - -void prescan_patch(F32 *patch, LLPatchHeader *php, F32 &zmax, F32 &zmin) -{ - S32 i, j; - PCGD *pcp = &gPatchCompressGlobalData; - S32 stride = pcp->patch_stride; - S32 size = pcp->patch_size; - S32 jstride; - - zmax = -99999999.f; - zmin = 99999999.f; - - for (j = 0; j < size; j++) - { - jstride = j*stride; - for (i = 0; i < size; i++) - { - if (*(patch + jstride + i) > zmax) - { - zmax = *(patch + jstride + i); - } - if (*(patch + jstride + i) < zmin) - { - zmin = *(patch + jstride + i); - } - } - } - - php->dc_offset = zmin; - php->range = (U16) ((zmax - zmin) + 1.f); -} - -void dct_line(F32 *linein, F32 *lineout, S32 line) -{ - S32 u; - F32 total; - F32 *pcp = gPatchCosines; - S32 line_size = line*NORMAL_PATCH_SIZE; - -#ifdef _PATCH_SIZE_16_AND_32_ONLY - F32 *tlinein, *tpcp; - - tlinein = linein + line_size; - - total = *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein); - - *(lineout + line_size) = OO_SQRT2*total; - - for (u = 1; u < NORMAL_PATCH_SIZE; u++) - { - tlinein = linein + line_size; - tpcp = pcp + (u<<4); - - total = *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein)*(*tpcp); - - *(lineout + line_size + u) = total; - } -#else - S32 n; - S32 size = gPatchCompressGlobalData.patch_size; - total = 0.f; - for (n = 0; n < size; n++) - { - total += linein[line_size + n]; - } - lineout[line_size] = OO_SQRT2*total; - - for (u = 1; u < size; u++) - { - total = 0.f; - for (n = 0; n < size; n++) - { - total += linein[line_size + n]*pcp[u*size+n]; - } - lineout[line_size + u] = total; - } -#endif -} - -void dct_line_large(F32 *linein, F32 *lineout, S32 line) -{ - S32 u; - F32 total; - F32 *pcp = gPatchCosines; - S32 line_size = line*LARGE_PATCH_SIZE; - - F32 *tlinein, *tpcp; - - tlinein = linein + line_size; - - total = *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein++); - total += *(tlinein); - - *(lineout + line_size) = OO_SQRT2*total; - - for (u = 1; u < LARGE_PATCH_SIZE; u++) - { - tlinein = linein + line_size; - tpcp = pcp + (u<<5); - - total = *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein++)*(*(tpcp++)); - total += *(tlinein)*(*tpcp); - - *(lineout + line_size + u) = total; - } -} - -inline void dct_column(F32 *linein, S32 *lineout, S32 column) -{ - S32 u; - F32 total; - F32 oosob = 2.f/16.f; - F32 *pcp = gPatchCosines; - S32 *copy_matrix = gCopyMatrix; - F32 *qt = gPatchQuantizeTable; - -#ifdef _PATCH_SIZE_16_AND_32_ONLY - F32 *tlinein, *tpcp; - S32 sizeu; - - tlinein = linein + column; - - total = *(tlinein); - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - total += *(tlinein += NORMAL_PATCH_SIZE); - - *(lineout + *(copy_matrix + column)) = (S32)(OO_SQRT2*total*oosob*(*(qt + column))); - - for (u = 1; u < NORMAL_PATCH_SIZE; u++) - { - tlinein = linein + column; - tpcp = pcp + (u<<4); - - total = *(tlinein)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp)); - - sizeu = NORMAL_PATCH_SIZE*u + column; - - *(lineout + *(copy_matrix + sizeu)) = (S32)(total*oosob*(*(qt+sizeu))); - } -#else - S32 size = gPatchCompressGlobalData.patch_size; - F32 oosob = 2.f/size; - S32 n; - total = 0.f; - for (n = 0; n < size; n++) - { - total += linein[size*n + column]; - } - lineout[copy_matrix[column]] = OO_SQRT2*total*oosob*qt[column]; - - for (u = 1; u < size; u++) - { - total = 0.f; - for (n = 0; n < size; n++) - { - total += linein[size*n + column]*pcp[u*size+n]; - } - lineout[copy_matrix[size*u + column]] = total*oosob*qt[size*u + column]; - } -#endif -} - -inline void dct_column_large(F32 *linein, S32 *lineout, S32 column) -{ - S32 u; - F32 total; - F32 oosob = 2.f/32.f; - F32 *pcp = gPatchCosines; - S32 *copy_matrix = gCopyMatrix; - F32 *qt = gPatchQuantizeTable; - - F32 *tlinein, *tpcp; - S32 sizeu; - - tlinein = linein + column; - - total = *(tlinein); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - total += *(tlinein += LARGE_PATCH_SIZE); - - *(lineout + *(copy_matrix + column)) = (S32)(OO_SQRT2*total*oosob*(*(qt + column))); - - for (u = 1; u < LARGE_PATCH_SIZE; u++) - { - tlinein = linein + column; - tpcp = pcp + (u<<5); - - total = *(tlinein)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp)); - - sizeu = LARGE_PATCH_SIZE*u + column; - - *(lineout + *(copy_matrix + sizeu)) = (S32)(total*oosob*(*(qt+sizeu))); - } -} - -inline void dct_patch(F32 *block, S32 *cpatch) -{ - F32 temp[NORMAL_PATCH_SIZE*NORMAL_PATCH_SIZE]; - -#ifdef _PATCH_SIZE_16_AND_32_ONLY - dct_line(block, temp, 0); - dct_line(block, temp, 1); - dct_line(block, temp, 2); - dct_line(block, temp, 3); - - dct_line(block, temp, 4); - dct_line(block, temp, 5); - dct_line(block, temp, 6); - dct_line(block, temp, 7); - - dct_line(block, temp, 8); - dct_line(block, temp, 9); - dct_line(block, temp, 10); - dct_line(block, temp, 11); - - dct_line(block, temp, 12); - dct_line(block, temp, 13); - dct_line(block, temp, 14); - dct_line(block, temp, 15); - - dct_column(temp, cpatch, 0); - dct_column(temp, cpatch, 1); - dct_column(temp, cpatch, 2); - dct_column(temp, cpatch, 3); - - dct_column(temp, cpatch, 4); - dct_column(temp, cpatch, 5); - dct_column(temp, cpatch, 6); - dct_column(temp, cpatch, 7); - - dct_column(temp, cpatch, 8); - dct_column(temp, cpatch, 9); - dct_column(temp, cpatch, 10); - dct_column(temp, cpatch, 11); - - dct_column(temp, cpatch, 12); - dct_column(temp, cpatch, 13); - dct_column(temp, cpatch, 14); - dct_column(temp, cpatch, 15); -#else - S32 i; - S32 size = gPatchCompressGlobalData.patch_size; - for (i = 0; i < size; i++) - { - dct_line(block, temp, i); - } - for (i = 0; i < size; i++) - { - dct_column(temp, cpatch, i); - } -#endif -} - -inline void dct_patch_large(F32 *block, S32 *cpatch) -{ - F32 temp[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - - dct_line_large(block, temp, 0); - dct_line_large(block, temp, 1); - dct_line_large(block, temp, 2); - dct_line_large(block, temp, 3); - - dct_line_large(block, temp, 4); - dct_line_large(block, temp, 5); - dct_line_large(block, temp, 6); - dct_line_large(block, temp, 7); - - dct_line_large(block, temp, 8); - dct_line_large(block, temp, 9); - dct_line_large(block, temp, 10); - dct_line_large(block, temp, 11); - - dct_line_large(block, temp, 12); - dct_line_large(block, temp, 13); - dct_line_large(block, temp, 14); - dct_line_large(block, temp, 15); - - dct_line_large(block, temp, 16); - dct_line_large(block, temp, 17); - dct_line_large(block, temp, 18); - dct_line_large(block, temp, 19); - - dct_line_large(block, temp, 20); - dct_line_large(block, temp, 21); - dct_line_large(block, temp, 22); - dct_line_large(block, temp, 23); - - dct_line_large(block, temp, 24); - dct_line_large(block, temp, 25); - dct_line_large(block, temp, 26); - dct_line_large(block, temp, 27); - - dct_line_large(block, temp, 28); - dct_line_large(block, temp, 29); - dct_line_large(block, temp, 30); - dct_line_large(block, temp, 31); - - dct_column_large(temp, cpatch, 0); - dct_column_large(temp, cpatch, 1); - dct_column_large(temp, cpatch, 2); - dct_column_large(temp, cpatch, 3); - - dct_column_large(temp, cpatch, 4); - dct_column_large(temp, cpatch, 5); - dct_column_large(temp, cpatch, 6); - dct_column_large(temp, cpatch, 7); - - dct_column_large(temp, cpatch, 8); - dct_column_large(temp, cpatch, 9); - dct_column_large(temp, cpatch, 10); - dct_column_large(temp, cpatch, 11); - - dct_column_large(temp, cpatch, 12); - dct_column_large(temp, cpatch, 13); - dct_column_large(temp, cpatch, 14); - dct_column_large(temp, cpatch, 15); - - dct_column_large(temp, cpatch, 16); - dct_column_large(temp, cpatch, 17); - dct_column_large(temp, cpatch, 18); - dct_column_large(temp, cpatch, 19); - - dct_column_large(temp, cpatch, 20); - dct_column_large(temp, cpatch, 21); - dct_column_large(temp, cpatch, 22); - dct_column_large(temp, cpatch, 23); - - dct_column_large(temp, cpatch, 24); - dct_column_large(temp, cpatch, 25); - dct_column_large(temp, cpatch, 26); - dct_column_large(temp, cpatch, 27); - - dct_column_large(temp, cpatch, 28); - dct_column_large(temp, cpatch, 29); - dct_column_large(temp, cpatch, 30); - dct_column_large(temp, cpatch, 31); -} - -void compress_patch(F32 *patch, S32 *cpatch, LLPatchHeader *php, S32 prequant) -{ - S32 i, j; - PCGD *pcp = &gPatchCompressGlobalData; - S32 stride = pcp->patch_stride; - S32 size = pcp->patch_size; - F32 block[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE], *tblock; - F32 *tpatch; - - S32 wordsize = prequant; - F32 oozrange = 1.f/php->range; - - F32 dc = php->dc_offset; - - S32 range = (1<<prequant); - F32 premult = oozrange*range; -// F32 sub = (F32)(1<<(prequant - 1)); - F32 sub = (F32)(1<<(prequant - 1)) + dc*premult; - - php->quant_wbits = wordsize - 2; - php->quant_wbits |= (prequant - 2)<<4; - - for (j = 0; j < size; j++) - { - tblock = block + j*size; - tpatch = patch + j*stride; - for (i = 0; i < size; i++) - { -// block[j*size + i] = (patch[j*stride + i] - dc)*premult - sub; - *(tblock++) = *(tpatch++)*premult - sub; - } - } - - if (size == 16) - dct_patch(block, cpatch); - else - dct_patch_large(block, cpatch); -} - -void get_patch_group_header(LLGroupHeader *gopp) -{ - PCGD *pcp = &gPatchCompressGlobalData; - gopp->stride = pcp->patch_stride; - gopp->patch_size = pcp->patch_size; - gopp->layer_type = pcp->layer_type; -} +/**
+ * @file patch_dct.cpp
+ * @brief DCT patch.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+#include "llmath.h"
+//#include "vmath.h"
+#include "v3math.h"
+#include "patch_dct.h"
+
+typedef struct s_patch_compress_global_data
+{
+ S32 patch_size;
+ S32 patch_stride;
+ U32 charptr;
+ S32 layer_type;
+} PCGD;
+
+PCGD gPatchCompressGlobalData;
+
+void reset_patch_compressor(void)
+{
+ PCGD *pcp = &gPatchCompressGlobalData;
+
+ pcp->charptr = 0;
+}
+
+S32 gCurrentSize = 0;
+
+F32 gPatchQuantizeTable[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+
+void build_patch_quantize_table(S32 size)
+{
+ S32 i, j;
+ for (j = 0; j < size; j++)
+ {
+ for (i = 0; i < size; i++)
+ {
+ gPatchQuantizeTable[j*size + i] = 1.f/(1.f + 2.f*(i+j));
+ }
+ }
+}
+
+F32 gPatchCosines[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+
+void setup_patch_cosines(S32 size)
+{
+ S32 n, u;
+ F32 oosob = F_PI*0.5f/size;
+
+ for (u = 0; u < size; u++)
+ {
+ for (n = 0; n < size; n++)
+ {
+ gPatchCosines[u*size+n] = cosf((2.f*n+1.f)*u*oosob);
+ }
+ }
+}
+
+S32 gCopyMatrix[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+
+void build_copy_matrix(S32 size)
+{
+ S32 i, j, count;
+ bool b_diag = false;
+ bool b_right = true;
+
+ i = 0;
+ j = 0;
+ count = 0;
+
+ while ( (i < size)
+ &&(j < size))
+ {
+ gCopyMatrix[j*size + i] = count;
+
+ count++;
+
+ if (!b_diag)
+ {
+ if (b_right)
+ {
+ if (i < size - 1)
+ i++;
+ else
+ j++;
+ b_right = false;
+ b_diag = true;
+ }
+ else
+ {
+ if (j < size - 1)
+ j++;
+ else
+ i++;
+ b_right = true;
+ b_diag = true;
+ }
+ }
+ else
+ {
+ if (b_right)
+ {
+ i++;
+ j--;
+ if ( (i == size - 1)
+ ||(j == 0))
+ {
+ b_diag = false;
+ }
+ }
+ else
+ {
+ i--;
+ j++;
+ if ( (i == 0)
+ ||(j == size - 1))
+ {
+ b_diag = false;
+ }
+ }
+ }
+ }
+}
+
+
+void init_patch_compressor(S32 patch_size, S32 patch_stride, S32 layer_type)
+{
+ PCGD *pcp = &gPatchCompressGlobalData;
+
+ pcp->charptr = 0;
+
+ pcp->patch_size = patch_size;
+ pcp->patch_stride = patch_stride;
+ pcp->layer_type = layer_type;
+
+ if (patch_size != gCurrentSize)
+ {
+ gCurrentSize = patch_size;
+ build_patch_quantize_table(patch_size);
+ setup_patch_cosines(patch_size);
+ build_copy_matrix(patch_size);
+ }
+}
+
+void prescan_patch(F32 *patch, LLPatchHeader *php, F32 &zmax, F32 &zmin)
+{
+ S32 i, j;
+ PCGD *pcp = &gPatchCompressGlobalData;
+ S32 stride = pcp->patch_stride;
+ S32 size = pcp->patch_size;
+ S32 jstride;
+
+ zmax = -99999999.f;
+ zmin = 99999999.f;
+
+ for (j = 0; j < size; j++)
+ {
+ jstride = j*stride;
+ for (i = 0; i < size; i++)
+ {
+ if (*(patch + jstride + i) > zmax)
+ {
+ zmax = *(patch + jstride + i);
+ }
+ if (*(patch + jstride + i) < zmin)
+ {
+ zmin = *(patch + jstride + i);
+ }
+ }
+ }
+
+ php->dc_offset = zmin;
+ php->range = (U16) ((zmax - zmin) + 1.f);
+}
+
+void dct_line(F32 *linein, F32 *lineout, S32 line)
+{
+ S32 u;
+ F32 total;
+ F32 *pcp = gPatchCosines;
+ S32 line_size = line*NORMAL_PATCH_SIZE;
+
+#ifdef _PATCH_SIZE_16_AND_32_ONLY
+ F32 *tlinein, *tpcp;
+
+ tlinein = linein + line_size;
+
+ total = *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein);
+
+ *(lineout + line_size) = OO_SQRT2*total;
+
+ for (u = 1; u < NORMAL_PATCH_SIZE; u++)
+ {
+ tlinein = linein + line_size;
+ tpcp = pcp + (u<<4);
+
+ total = *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein)*(*tpcp);
+
+ *(lineout + line_size + u) = total;
+ }
+#else
+ S32 n;
+ S32 size = gPatchCompressGlobalData.patch_size;
+ total = 0.f;
+ for (n = 0; n < size; n++)
+ {
+ total += linein[line_size + n];
+ }
+ lineout[line_size] = OO_SQRT2*total;
+
+ for (u = 1; u < size; u++)
+ {
+ total = 0.f;
+ for (n = 0; n < size; n++)
+ {
+ total += linein[line_size + n]*pcp[u*size+n];
+ }
+ lineout[line_size + u] = total;
+ }
+#endif
+}
+
+void dct_line_large(F32 *linein, F32 *lineout, S32 line)
+{
+ S32 u;
+ F32 total;
+ F32 *pcp = gPatchCosines;
+ S32 line_size = line*LARGE_PATCH_SIZE;
+
+ F32 *tlinein, *tpcp;
+
+ tlinein = linein + line_size;
+
+ total = *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein++);
+ total += *(tlinein);
+
+ *(lineout + line_size) = OO_SQRT2*total;
+
+ for (u = 1; u < LARGE_PATCH_SIZE; u++)
+ {
+ tlinein = linein + line_size;
+ tpcp = pcp + (u<<5);
+
+ total = *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein++)*(*(tpcp++));
+ total += *(tlinein)*(*tpcp);
+
+ *(lineout + line_size + u) = total;
+ }
+}
+
+inline void dct_column(F32 *linein, S32 *lineout, S32 column)
+{
+ S32 u;
+ F32 total;
+ F32 oosob = 2.f/16.f;
+ F32 *pcp = gPatchCosines;
+ S32 *copy_matrix = gCopyMatrix;
+ F32 *qt = gPatchQuantizeTable;
+
+#ifdef _PATCH_SIZE_16_AND_32_ONLY
+ F32 *tlinein, *tpcp;
+ S32 sizeu;
+
+ tlinein = linein + column;
+
+ total = *(tlinein);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+ total += *(tlinein += NORMAL_PATCH_SIZE);
+
+ *(lineout + *(copy_matrix + column)) = (S32)(OO_SQRT2*total*oosob*(*(qt + column)));
+
+ for (u = 1; u < NORMAL_PATCH_SIZE; u++)
+ {
+ tlinein = linein + column;
+ tpcp = pcp + (u<<4);
+
+ total = *(tlinein)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp));
+
+ sizeu = NORMAL_PATCH_SIZE*u + column;
+
+ *(lineout + *(copy_matrix + sizeu)) = (S32)(total*oosob*(*(qt+sizeu)));
+ }
+#else
+ S32 size = gPatchCompressGlobalData.patch_size;
+ F32 oosob = 2.f/size;
+ S32 n;
+ total = 0.f;
+ for (n = 0; n < size; n++)
+ {
+ total += linein[size*n + column];
+ }
+ lineout[copy_matrix[column]] = OO_SQRT2*total*oosob*qt[column];
+
+ for (u = 1; u < size; u++)
+ {
+ total = 0.f;
+ for (n = 0; n < size; n++)
+ {
+ total += linein[size*n + column]*pcp[u*size+n];
+ }
+ lineout[copy_matrix[size*u + column]] = total*oosob*qt[size*u + column];
+ }
+#endif
+}
+
+inline void dct_column_large(F32 *linein, S32 *lineout, S32 column)
+{
+ S32 u;
+ F32 total;
+ F32 oosob = 2.f/32.f;
+ F32 *pcp = gPatchCosines;
+ S32 *copy_matrix = gCopyMatrix;
+ F32 *qt = gPatchQuantizeTable;
+
+ F32 *tlinein, *tpcp;
+ S32 sizeu;
+
+ tlinein = linein + column;
+
+ total = *(tlinein);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+ total += *(tlinein += LARGE_PATCH_SIZE);
+
+ *(lineout + *(copy_matrix + column)) = (S32)(OO_SQRT2*total*oosob*(*(qt + column)));
+
+ for (u = 1; u < LARGE_PATCH_SIZE; u++)
+ {
+ tlinein = linein + column;
+ tpcp = pcp + (u<<5);
+
+ total = *(tlinein)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp++));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp));
+
+ sizeu = LARGE_PATCH_SIZE*u + column;
+
+ *(lineout + *(copy_matrix + sizeu)) = (S32)(total*oosob*(*(qt+sizeu)));
+ }
+}
+
+inline void dct_patch(F32 *block, S32 *cpatch)
+{
+ F32 temp[NORMAL_PATCH_SIZE*NORMAL_PATCH_SIZE];
+
+#ifdef _PATCH_SIZE_16_AND_32_ONLY
+ dct_line(block, temp, 0);
+ dct_line(block, temp, 1);
+ dct_line(block, temp, 2);
+ dct_line(block, temp, 3);
+
+ dct_line(block, temp, 4);
+ dct_line(block, temp, 5);
+ dct_line(block, temp, 6);
+ dct_line(block, temp, 7);
+
+ dct_line(block, temp, 8);
+ dct_line(block, temp, 9);
+ dct_line(block, temp, 10);
+ dct_line(block, temp, 11);
+
+ dct_line(block, temp, 12);
+ dct_line(block, temp, 13);
+ dct_line(block, temp, 14);
+ dct_line(block, temp, 15);
+
+ dct_column(temp, cpatch, 0);
+ dct_column(temp, cpatch, 1);
+ dct_column(temp, cpatch, 2);
+ dct_column(temp, cpatch, 3);
+
+ dct_column(temp, cpatch, 4);
+ dct_column(temp, cpatch, 5);
+ dct_column(temp, cpatch, 6);
+ dct_column(temp, cpatch, 7);
+
+ dct_column(temp, cpatch, 8);
+ dct_column(temp, cpatch, 9);
+ dct_column(temp, cpatch, 10);
+ dct_column(temp, cpatch, 11);
+
+ dct_column(temp, cpatch, 12);
+ dct_column(temp, cpatch, 13);
+ dct_column(temp, cpatch, 14);
+ dct_column(temp, cpatch, 15);
+#else
+ S32 i;
+ S32 size = gPatchCompressGlobalData.patch_size;
+ for (i = 0; i < size; i++)
+ {
+ dct_line(block, temp, i);
+ }
+ for (i = 0; i < size; i++)
+ {
+ dct_column(temp, cpatch, i);
+ }
+#endif
+}
+
+inline void dct_patch_large(F32 *block, S32 *cpatch)
+{
+ F32 temp[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+
+ dct_line_large(block, temp, 0);
+ dct_line_large(block, temp, 1);
+ dct_line_large(block, temp, 2);
+ dct_line_large(block, temp, 3);
+
+ dct_line_large(block, temp, 4);
+ dct_line_large(block, temp, 5);
+ dct_line_large(block, temp, 6);
+ dct_line_large(block, temp, 7);
+
+ dct_line_large(block, temp, 8);
+ dct_line_large(block, temp, 9);
+ dct_line_large(block, temp, 10);
+ dct_line_large(block, temp, 11);
+
+ dct_line_large(block, temp, 12);
+ dct_line_large(block, temp, 13);
+ dct_line_large(block, temp, 14);
+ dct_line_large(block, temp, 15);
+
+ dct_line_large(block, temp, 16);
+ dct_line_large(block, temp, 17);
+ dct_line_large(block, temp, 18);
+ dct_line_large(block, temp, 19);
+
+ dct_line_large(block, temp, 20);
+ dct_line_large(block, temp, 21);
+ dct_line_large(block, temp, 22);
+ dct_line_large(block, temp, 23);
+
+ dct_line_large(block, temp, 24);
+ dct_line_large(block, temp, 25);
+ dct_line_large(block, temp, 26);
+ dct_line_large(block, temp, 27);
+
+ dct_line_large(block, temp, 28);
+ dct_line_large(block, temp, 29);
+ dct_line_large(block, temp, 30);
+ dct_line_large(block, temp, 31);
+
+ dct_column_large(temp, cpatch, 0);
+ dct_column_large(temp, cpatch, 1);
+ dct_column_large(temp, cpatch, 2);
+ dct_column_large(temp, cpatch, 3);
+
+ dct_column_large(temp, cpatch, 4);
+ dct_column_large(temp, cpatch, 5);
+ dct_column_large(temp, cpatch, 6);
+ dct_column_large(temp, cpatch, 7);
+
+ dct_column_large(temp, cpatch, 8);
+ dct_column_large(temp, cpatch, 9);
+ dct_column_large(temp, cpatch, 10);
+ dct_column_large(temp, cpatch, 11);
+
+ dct_column_large(temp, cpatch, 12);
+ dct_column_large(temp, cpatch, 13);
+ dct_column_large(temp, cpatch, 14);
+ dct_column_large(temp, cpatch, 15);
+
+ dct_column_large(temp, cpatch, 16);
+ dct_column_large(temp, cpatch, 17);
+ dct_column_large(temp, cpatch, 18);
+ dct_column_large(temp, cpatch, 19);
+
+ dct_column_large(temp, cpatch, 20);
+ dct_column_large(temp, cpatch, 21);
+ dct_column_large(temp, cpatch, 22);
+ dct_column_large(temp, cpatch, 23);
+
+ dct_column_large(temp, cpatch, 24);
+ dct_column_large(temp, cpatch, 25);
+ dct_column_large(temp, cpatch, 26);
+ dct_column_large(temp, cpatch, 27);
+
+ dct_column_large(temp, cpatch, 28);
+ dct_column_large(temp, cpatch, 29);
+ dct_column_large(temp, cpatch, 30);
+ dct_column_large(temp, cpatch, 31);
+}
+
+void compress_patch(F32 *patch, S32 *cpatch, LLPatchHeader *php, S32 prequant)
+{
+ S32 i, j;
+ PCGD *pcp = &gPatchCompressGlobalData;
+ S32 stride = pcp->patch_stride;
+ S32 size = pcp->patch_size;
+ F32 block[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE], *tblock;
+ F32 *tpatch;
+
+ S32 wordsize = prequant;
+ F32 oozrange = 1.f/php->range;
+
+ F32 dc = php->dc_offset;
+
+ S32 range = (1<<prequant);
+ F32 premult = oozrange*range;
+// F32 sub = (F32)(1<<(prequant - 1));
+ F32 sub = (F32)(1<<(prequant - 1)) + dc*premult;
+
+ php->quant_wbits = wordsize - 2;
+ php->quant_wbits |= (prequant - 2)<<4;
+
+ for (j = 0; j < size; j++)
+ {
+ tblock = block + j*size;
+ tpatch = patch + j*stride;
+ for (i = 0; i < size; i++)
+ {
+// block[j*size + i] = (patch[j*stride + i] - dc)*premult - sub;
+ *(tblock++) = *(tpatch++)*premult - sub;
+ }
+ }
+
+ if (size == 16)
+ dct_patch(block, cpatch);
+ else
+ dct_patch_large(block, cpatch);
+}
+
+void get_patch_group_header(LLGroupHeader *gopp)
+{
+ PCGD *pcp = &gPatchCompressGlobalData;
+ gopp->stride = pcp->patch_stride;
+ gopp->patch_size = pcp->patch_size;
+ gopp->layer_type = pcp->layer_type;
+}
diff --git a/indra/llmessage/patch_idct.cpp b/indra/llmessage/patch_idct.cpp index 230b73726c..c5320e22e3 100644 --- a/indra/llmessage/patch_idct.cpp +++ b/indra/llmessage/patch_idct.cpp @@ -1,684 +1,684 @@ -/** - * @file patch_idct.cpp - * @brief IDCT patch. - * - * $LicenseInfo:firstyear=2000&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$ - */ - -#include "linden_common.h" - -#include "llmath.h" -//#include "vmath.h" -#include "v3math.h" -#include "patch_dct.h" - -LLGroupHeader *gGOPP; - -void set_group_of_patch_header(LLGroupHeader *gopp) -{ - gGOPP = gopp; -} - -F32 gPatchDequantizeTable[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; -void build_patch_dequantize_table(S32 size) -{ - S32 i, j; - for (j = 0; j < size; j++) - { - for (i = 0; i < size; i++) - { - gPatchDequantizeTable[j*size + i] = (1.f + 2.f*(i+j)); - } - } -} - -S32 gCurrentDeSize = 0; - -F32 gPatchICosines[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - -void setup_patch_icosines(S32 size) -{ - S32 n, u; - F32 oosob = F_PI*0.5f/size; - - for (u = 0; u < size; u++) - { - for (n = 0; n < size; n++) - { - gPatchICosines[u*size+n] = cosf((2.f*n+1.f)*u*oosob); - } - } -} - -S32 gDeCopyMatrix[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - -void build_decopy_matrix(S32 size) -{ - S32 i, j, count; - BOOL b_diag = FALSE; - BOOL b_right = TRUE; - - i = 0; - j = 0; - count = 0; - - while ( (i < size) - &&(j < size)) - { - gDeCopyMatrix[j*size + i] = count; - - count++; - - if (!b_diag) - { - if (b_right) - { - if (i < size - 1) - i++; - else - j++; - b_right = FALSE; - b_diag = TRUE; - } - else - { - if (j < size - 1) - j++; - else - i++; - b_right = TRUE; - b_diag = TRUE; - } - } - else - { - if (b_right) - { - i++; - j--; - if ( (i == size - 1) - ||(j == 0)) - { - b_diag = FALSE; - } - } - else - { - i--; - j++; - if ( (i == 0) - ||(j == size - 1)) - { - b_diag = FALSE; - } - } - } - } -} - -void init_patch_decompressor(S32 size) -{ - if (size != gCurrentDeSize) - { - gCurrentDeSize = size; - build_patch_dequantize_table(size); - setup_patch_icosines(size); - build_decopy_matrix(size); - } -} - -inline void idct_line(F32 *linein, F32 *lineout, S32 line) -{ - S32 n; - F32 total; - F32 *pcp = gPatchICosines; - -#ifdef _PATCH_SIZE_16_AND_32_ONLY - F32 oosob = 2.f/16.f; - S32 line_size = line*NORMAL_PATCH_SIZE; - F32 *tlinein, *tpcp; - - - for (n = 0; n < NORMAL_PATCH_SIZE; n++) - { - tpcp = pcp + n; - tlinein = linein + line_size; - - total = OO_SQRT2*(*(tlinein++)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein)*(*(tpcp += NORMAL_PATCH_SIZE)); - - *(lineout + line_size + n) = total*oosob; - } -#else - F32 oosob = 2.f/size; - S32 size = gGOPP->patch_size; - S32 line_size = line*size; - S32 u; - for (n = 0; n < size; n++) - { - total = OO_SQRT2*linein[line_size]; - for (u = 1; u < size; u++) - { - total += linein[line_size + u]*pcp[u*size+n]; - } - lineout[line_size + n] = total*oosob; - } -#endif -} - -inline void idct_line_large_slow(F32 *linein, F32 *lineout, S32 line) -{ - S32 n; - F32 total; - F32 *pcp = gPatchICosines; - - F32 oosob = 2.f/32.f; - S32 line_size = line*LARGE_PATCH_SIZE; - F32 *tlinein, *tpcp; - - - for (n = 0; n < LARGE_PATCH_SIZE; n++) - { - tpcp = pcp + n; - tlinein = linein + line_size; - - total = OO_SQRT2*(*(tlinein++)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein)*(*(tpcp += LARGE_PATCH_SIZE)); - - *(lineout + line_size + n) = total*oosob; - } -} - -// Nota Bene: assumes that coefficients beyond 128 are 0! - -void idct_line_large(F32 *linein, F32 *lineout, S32 line) -{ - S32 n; - F32 total; - F32 *pcp = gPatchICosines; - - F32 oosob = 2.f/32.f; - S32 line_size = line*LARGE_PATCH_SIZE; - F32 *tlinein, *tpcp; - F32 *baselinein = linein + line_size; - F32 *baselineout = lineout + line_size; - - - for (n = 0; n < LARGE_PATCH_SIZE; n++) - { - tpcp = pcp++; - tlinein = baselinein; - - total = OO_SQRT2*(*(tlinein++)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein)*(*(tpcp)); - - *baselineout++ = total*oosob; - } -} - -inline void idct_column(F32 *linein, F32 *lineout, S32 column) -{ - S32 n; - F32 total; - F32 *pcp = gPatchICosines; - -#ifdef _PATCH_SIZE_16_AND_32_ONLY - F32 *tlinein, *tpcp; - - for (n = 0; n < NORMAL_PATCH_SIZE; n++) - { - tpcp = pcp + n; - tlinein = linein + column; - - total = OO_SQRT2*(*tlinein); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE)); - - *(lineout + (n<<4) + column) = total; - } - -#else - S32 size = gGOPP->patch_size; - S32 u; - S32 u_size; - - for (n = 0; n < size; n++) - { - total = OO_SQRT2*linein[column]; - for (u = 1; u < size; u++) - { - u_size = u*size; - total += linein[u_size + column]*pcp[u_size+n]; - } - lineout[size*n + column] = total; - } -#endif -} - -inline void idct_column_large_slow(F32 *linein, F32 *lineout, S32 column) -{ - S32 n; - F32 total; - F32 *pcp = gPatchICosines; - - F32 *tlinein, *tpcp; - - for (n = 0; n < LARGE_PATCH_SIZE; n++) - { - tpcp = pcp + n; - tlinein = linein + column; - - total = OO_SQRT2*(*tlinein); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - *(lineout + (n<<5) + column) = total; - } -} - -// Nota Bene: assumes that coefficients beyond 128 are 0! - -void idct_column_large(F32 *linein, F32 *lineout, S32 column) -{ - S32 n, m; - F32 total; - F32 *pcp = gPatchICosines; - - F32 *tlinein, *tpcp; - F32 *baselinein = linein + column; - F32 *baselineout = lineout + column; - - for (n = 0; n < LARGE_PATCH_SIZE; n++) - { - tpcp = pcp++; - tlinein = baselinein; - - total = OO_SQRT2*(*tlinein); - for (m = 1; m < NORMAL_PATCH_SIZE; m++) - total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE)); - - *(baselineout + (n<<5)) = total; - } -} - -inline void idct_patch(F32 *block) -{ - F32 temp[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - -#ifdef _PATCH_SIZE_16_AND_32_ONLY - idct_column(block, temp, 0); - idct_column(block, temp, 1); - idct_column(block, temp, 2); - idct_column(block, temp, 3); - - idct_column(block, temp, 4); - idct_column(block, temp, 5); - idct_column(block, temp, 6); - idct_column(block, temp, 7); - - idct_column(block, temp, 8); - idct_column(block, temp, 9); - idct_column(block, temp, 10); - idct_column(block, temp, 11); - - idct_column(block, temp, 12); - idct_column(block, temp, 13); - idct_column(block, temp, 14); - idct_column(block, temp, 15); - - idct_line(temp, block, 0); - idct_line(temp, block, 1); - idct_line(temp, block, 2); - idct_line(temp, block, 3); - - idct_line(temp, block, 4); - idct_line(temp, block, 5); - idct_line(temp, block, 6); - idct_line(temp, block, 7); - - idct_line(temp, block, 8); - idct_line(temp, block, 9); - idct_line(temp, block, 10); - idct_line(temp, block, 11); - - idct_line(temp, block, 12); - idct_line(temp, block, 13); - idct_line(temp, block, 14); - idct_line(temp, block, 15); -#else - S32 i; - S32 size = gGOPP->patch_size; - for (i = 0; i < size; i++) - { - idct_column(block, temp, i); - } - for (i = 0; i < size; i++) - { - idct_line(temp, block, i); - } -#endif -} - -inline void idct_patch_large(F32 *block) -{ - F32 temp[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - - idct_column_large_slow(block, temp, 0); - idct_column_large_slow(block, temp, 1); - idct_column_large_slow(block, temp, 2); - idct_column_large_slow(block, temp, 3); - - idct_column_large_slow(block, temp, 4); - idct_column_large_slow(block, temp, 5); - idct_column_large_slow(block, temp, 6); - idct_column_large_slow(block, temp, 7); - - idct_column_large_slow(block, temp, 8); - idct_column_large_slow(block, temp, 9); - idct_column_large_slow(block, temp, 10); - idct_column_large_slow(block, temp, 11); - - idct_column_large_slow(block, temp, 12); - idct_column_large_slow(block, temp, 13); - idct_column_large_slow(block, temp, 14); - idct_column_large_slow(block, temp, 15); - - idct_column_large_slow(block, temp, 16); - idct_column_large_slow(block, temp, 17); - idct_column_large_slow(block, temp, 18); - idct_column_large_slow(block, temp, 19); - - idct_column_large_slow(block, temp, 20); - idct_column_large_slow(block, temp, 21); - idct_column_large_slow(block, temp, 22); - idct_column_large_slow(block, temp, 23); - - idct_column_large_slow(block, temp, 24); - idct_column_large_slow(block, temp, 25); - idct_column_large_slow(block, temp, 26); - idct_column_large_slow(block, temp, 27); - - idct_column_large_slow(block, temp, 28); - idct_column_large_slow(block, temp, 29); - idct_column_large_slow(block, temp, 30); - idct_column_large_slow(block, temp, 31); - - idct_line_large_slow(temp, block, 0); - idct_line_large_slow(temp, block, 1); - idct_line_large_slow(temp, block, 2); - idct_line_large_slow(temp, block, 3); - - idct_line_large_slow(temp, block, 4); - idct_line_large_slow(temp, block, 5); - idct_line_large_slow(temp, block, 6); - idct_line_large_slow(temp, block, 7); - - idct_line_large_slow(temp, block, 8); - idct_line_large_slow(temp, block, 9); - idct_line_large_slow(temp, block, 10); - idct_line_large_slow(temp, block, 11); - - idct_line_large_slow(temp, block, 12); - idct_line_large_slow(temp, block, 13); - idct_line_large_slow(temp, block, 14); - idct_line_large_slow(temp, block, 15); - - idct_line_large_slow(temp, block, 16); - idct_line_large_slow(temp, block, 17); - idct_line_large_slow(temp, block, 18); - idct_line_large_slow(temp, block, 19); - - idct_line_large_slow(temp, block, 20); - idct_line_large_slow(temp, block, 21); - idct_line_large_slow(temp, block, 22); - idct_line_large_slow(temp, block, 23); - - idct_line_large_slow(temp, block, 24); - idct_line_large_slow(temp, block, 25); - idct_line_large_slow(temp, block, 26); - idct_line_large_slow(temp, block, 27); - - idct_line_large_slow(temp, block, 28); - idct_line_large_slow(temp, block, 29); - idct_line_large_slow(temp, block, 30); - idct_line_large_slow(temp, block, 31); -} - -S32 gDitherNoise = 128; - -void decompress_patch(F32 *patch, S32 *cpatch, LLPatchHeader *ph) -{ - S32 i, j; - - F32 block[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE], *tblock = block; - F32 *tpatch; - - LLGroupHeader *gopp = gGOPP; - S32 size = gopp->patch_size; - F32 range = ph->range; - S32 prequant = (ph->quant_wbits >> 4) + 2; - S32 quantize = 1<<prequant; - F32 hmin = ph->dc_offset; - S32 stride = gopp->stride; - - F32 ooq = 1.f/(F32)quantize; - F32 *dq = gPatchDequantizeTable; - S32 *decopy_matrix = gDeCopyMatrix; - - F32 mult = ooq*range; - F32 addval = mult*(F32)(1<<(prequant - 1))+hmin; - - for (i = 0; i < size*size; i++) - { - *(tblock++) = *(cpatch + *(decopy_matrix++))*(*dq++); - } - - if (size == 16) - { - idct_patch(block); - } - else - { - idct_patch_large(block); - } - - for (j = 0; j < size; j++) - { - tpatch = patch + j*stride; - tblock = block + j*size; - for (i = 0; i < size; i++) - { - *(tpatch++) = *(tblock++)*mult+addval; - } - } -} - - -void decompress_patchv(LLVector3 *v, S32 *cpatch, LLPatchHeader *ph) -{ - S32 i, j; - - F32 block[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE], *tblock = block; - LLVector3 *tvec; - - LLGroupHeader *gopp = gGOPP; - S32 size = gopp->patch_size; - F32 range = ph->range; - S32 prequant = (ph->quant_wbits >> 4) + 2; - S32 quantize = 1<<prequant; - F32 hmin = ph->dc_offset; - S32 stride = gopp->stride; - - F32 ooq = 1.f/(F32)quantize; - F32 *dq = gPatchDequantizeTable; - S32 *decopy_matrix = gDeCopyMatrix; - - F32 mult = ooq*range; - F32 addval = mult*(F32)(1<<(prequant - 1))+hmin; - -// BOOL b_diag = FALSE; -// BOOL b_right = TRUE; - - for (i = 0; i < size*size; i++) - { - *(tblock++) = *(cpatch + *(decopy_matrix++))*(*dq++); - } - - if (size == 16) - idct_patch(block); - else - idct_patch_large(block); - - for (j = 0; j < size; j++) - { - tvec = v + j*stride; - tblock = block + j*size; - for (i = 0; i < size; i++) - { - (*tvec++).mV[VZ] = *(tblock++)*mult+addval; - } - } -} - +/**
+ * @file patch_idct.cpp
+ * @brief IDCT patch.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+#include "llmath.h"
+//#include "vmath.h"
+#include "v3math.h"
+#include "patch_dct.h"
+
+LLGroupHeader *gGOPP;
+
+void set_group_of_patch_header(LLGroupHeader *gopp)
+{
+ gGOPP = gopp;
+}
+
+F32 gPatchDequantizeTable[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+void build_patch_dequantize_table(S32 size)
+{
+ S32 i, j;
+ for (j = 0; j < size; j++)
+ {
+ for (i = 0; i < size; i++)
+ {
+ gPatchDequantizeTable[j*size + i] = (1.f + 2.f*(i+j));
+ }
+ }
+}
+
+S32 gCurrentDeSize = 0;
+
+F32 gPatchICosines[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+
+void setup_patch_icosines(S32 size)
+{
+ S32 n, u;
+ F32 oosob = F_PI*0.5f/size;
+
+ for (u = 0; u < size; u++)
+ {
+ for (n = 0; n < size; n++)
+ {
+ gPatchICosines[u*size+n] = cosf((2.f*n+1.f)*u*oosob);
+ }
+ }
+}
+
+S32 gDeCopyMatrix[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+
+void build_decopy_matrix(S32 size)
+{
+ S32 i, j, count;
+ bool b_diag = false;
+ bool b_right = true;
+
+ i = 0;
+ j = 0;
+ count = 0;
+
+ while ( (i < size)
+ &&(j < size))
+ {
+ gDeCopyMatrix[j*size + i] = count;
+
+ count++;
+
+ if (!b_diag)
+ {
+ if (b_right)
+ {
+ if (i < size - 1)
+ i++;
+ else
+ j++;
+ b_right = false;
+ b_diag = true;
+ }
+ else
+ {
+ if (j < size - 1)
+ j++;
+ else
+ i++;
+ b_right = true;
+ b_diag = true;
+ }
+ }
+ else
+ {
+ if (b_right)
+ {
+ i++;
+ j--;
+ if ( (i == size - 1)
+ ||(j == 0))
+ {
+ b_diag = false;
+ }
+ }
+ else
+ {
+ i--;
+ j++;
+ if ( (i == 0)
+ ||(j == size - 1))
+ {
+ b_diag = false;
+ }
+ }
+ }
+ }
+}
+
+void init_patch_decompressor(S32 size)
+{
+ if (size != gCurrentDeSize)
+ {
+ gCurrentDeSize = size;
+ build_patch_dequantize_table(size);
+ setup_patch_icosines(size);
+ build_decopy_matrix(size);
+ }
+}
+
+inline void idct_line(F32 *linein, F32 *lineout, S32 line)
+{
+ S32 n;
+ F32 total;
+ F32 *pcp = gPatchICosines;
+
+#ifdef _PATCH_SIZE_16_AND_32_ONLY
+ F32 oosob = 2.f/16.f;
+ S32 line_size = line*NORMAL_PATCH_SIZE;
+ F32 *tlinein, *tpcp;
+
+
+ for (n = 0; n < NORMAL_PATCH_SIZE; n++)
+ {
+ tpcp = pcp + n;
+ tlinein = linein + line_size;
+
+ total = OO_SQRT2*(*(tlinein++));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein)*(*(tpcp += NORMAL_PATCH_SIZE));
+
+ *(lineout + line_size + n) = total*oosob;
+ }
+#else
+ F32 oosob = 2.f/size;
+ S32 size = gGOPP->patch_size;
+ S32 line_size = line*size;
+ S32 u;
+ for (n = 0; n < size; n++)
+ {
+ total = OO_SQRT2*linein[line_size];
+ for (u = 1; u < size; u++)
+ {
+ total += linein[line_size + u]*pcp[u*size+n];
+ }
+ lineout[line_size + n] = total*oosob;
+ }
+#endif
+}
+
+inline void idct_line_large_slow(F32 *linein, F32 *lineout, S32 line)
+{
+ S32 n;
+ F32 total;
+ F32 *pcp = gPatchICosines;
+
+ F32 oosob = 2.f/32.f;
+ S32 line_size = line*LARGE_PATCH_SIZE;
+ F32 *tlinein, *tpcp;
+
+
+ for (n = 0; n < LARGE_PATCH_SIZE; n++)
+ {
+ tpcp = pcp + n;
+ tlinein = linein + line_size;
+
+ total = OO_SQRT2*(*(tlinein++));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ *(lineout + line_size + n) = total*oosob;
+ }
+}
+
+// Nota Bene: assumes that coefficients beyond 128 are 0!
+
+void idct_line_large(F32 *linein, F32 *lineout, S32 line)
+{
+ S32 n;
+ F32 total;
+ F32 *pcp = gPatchICosines;
+
+ F32 oosob = 2.f/32.f;
+ S32 line_size = line*LARGE_PATCH_SIZE;
+ F32 *tlinein, *tpcp;
+ F32 *baselinein = linein + line_size;
+ F32 *baselineout = lineout + line_size;
+
+
+ for (n = 0; n < LARGE_PATCH_SIZE; n++)
+ {
+ tpcp = pcp++;
+ tlinein = baselinein;
+
+ total = OO_SQRT2*(*(tlinein++));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein++)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein)*(*(tpcp));
+
+ *baselineout++ = total*oosob;
+ }
+}
+
+inline void idct_column(F32 *linein, F32 *lineout, S32 column)
+{
+ S32 n;
+ F32 total;
+ F32 *pcp = gPatchICosines;
+
+#ifdef _PATCH_SIZE_16_AND_32_ONLY
+ F32 *tlinein, *tpcp;
+
+ for (n = 0; n < NORMAL_PATCH_SIZE; n++)
+ {
+ tpcp = pcp + n;
+ tlinein = linein + column;
+
+ total = OO_SQRT2*(*tlinein);
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+ total += *(tlinein += NORMAL_PATCH_SIZE)*(*(tpcp += NORMAL_PATCH_SIZE));
+
+ *(lineout + (n<<4) + column) = total;
+ }
+
+#else
+ S32 size = gGOPP->patch_size;
+ S32 u;
+ S32 u_size;
+
+ for (n = 0; n < size; n++)
+ {
+ total = OO_SQRT2*linein[column];
+ for (u = 1; u < size; u++)
+ {
+ u_size = u*size;
+ total += linein[u_size + column]*pcp[u_size+n];
+ }
+ lineout[size*n + column] = total;
+ }
+#endif
+}
+
+inline void idct_column_large_slow(F32 *linein, F32 *lineout, S32 column)
+{
+ S32 n;
+ F32 total;
+ F32 *pcp = gPatchICosines;
+
+ F32 *tlinein, *tpcp;
+
+ for (n = 0; n < LARGE_PATCH_SIZE; n++)
+ {
+ tpcp = pcp + n;
+ tlinein = linein + column;
+
+ total = OO_SQRT2*(*tlinein);
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ *(lineout + (n<<5) + column) = total;
+ }
+}
+
+// Nota Bene: assumes that coefficients beyond 128 are 0!
+
+void idct_column_large(F32 *linein, F32 *lineout, S32 column)
+{
+ S32 n, m;
+ F32 total;
+ F32 *pcp = gPatchICosines;
+
+ F32 *tlinein, *tpcp;
+ F32 *baselinein = linein + column;
+ F32 *baselineout = lineout + column;
+
+ for (n = 0; n < LARGE_PATCH_SIZE; n++)
+ {
+ tpcp = pcp++;
+ tlinein = baselinein;
+
+ total = OO_SQRT2*(*tlinein);
+ for (m = 1; m < NORMAL_PATCH_SIZE; m++)
+ total += *(tlinein += LARGE_PATCH_SIZE)*(*(tpcp += LARGE_PATCH_SIZE));
+
+ *(baselineout + (n<<5)) = total;
+ }
+}
+
+inline void idct_patch(F32 *block)
+{
+ F32 temp[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+
+#ifdef _PATCH_SIZE_16_AND_32_ONLY
+ idct_column(block, temp, 0);
+ idct_column(block, temp, 1);
+ idct_column(block, temp, 2);
+ idct_column(block, temp, 3);
+
+ idct_column(block, temp, 4);
+ idct_column(block, temp, 5);
+ idct_column(block, temp, 6);
+ idct_column(block, temp, 7);
+
+ idct_column(block, temp, 8);
+ idct_column(block, temp, 9);
+ idct_column(block, temp, 10);
+ idct_column(block, temp, 11);
+
+ idct_column(block, temp, 12);
+ idct_column(block, temp, 13);
+ idct_column(block, temp, 14);
+ idct_column(block, temp, 15);
+
+ idct_line(temp, block, 0);
+ idct_line(temp, block, 1);
+ idct_line(temp, block, 2);
+ idct_line(temp, block, 3);
+
+ idct_line(temp, block, 4);
+ idct_line(temp, block, 5);
+ idct_line(temp, block, 6);
+ idct_line(temp, block, 7);
+
+ idct_line(temp, block, 8);
+ idct_line(temp, block, 9);
+ idct_line(temp, block, 10);
+ idct_line(temp, block, 11);
+
+ idct_line(temp, block, 12);
+ idct_line(temp, block, 13);
+ idct_line(temp, block, 14);
+ idct_line(temp, block, 15);
+#else
+ S32 i;
+ S32 size = gGOPP->patch_size;
+ for (i = 0; i < size; i++)
+ {
+ idct_column(block, temp, i);
+ }
+ for (i = 0; i < size; i++)
+ {
+ idct_line(temp, block, i);
+ }
+#endif
+}
+
+inline void idct_patch_large(F32 *block)
+{
+ F32 temp[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
+
+ idct_column_large_slow(block, temp, 0);
+ idct_column_large_slow(block, temp, 1);
+ idct_column_large_slow(block, temp, 2);
+ idct_column_large_slow(block, temp, 3);
+
+ idct_column_large_slow(block, temp, 4);
+ idct_column_large_slow(block, temp, 5);
+ idct_column_large_slow(block, temp, 6);
+ idct_column_large_slow(block, temp, 7);
+
+ idct_column_large_slow(block, temp, 8);
+ idct_column_large_slow(block, temp, 9);
+ idct_column_large_slow(block, temp, 10);
+ idct_column_large_slow(block, temp, 11);
+
+ idct_column_large_slow(block, temp, 12);
+ idct_column_large_slow(block, temp, 13);
+ idct_column_large_slow(block, temp, 14);
+ idct_column_large_slow(block, temp, 15);
+
+ idct_column_large_slow(block, temp, 16);
+ idct_column_large_slow(block, temp, 17);
+ idct_column_large_slow(block, temp, 18);
+ idct_column_large_slow(block, temp, 19);
+
+ idct_column_large_slow(block, temp, 20);
+ idct_column_large_slow(block, temp, 21);
+ idct_column_large_slow(block, temp, 22);
+ idct_column_large_slow(block, temp, 23);
+
+ idct_column_large_slow(block, temp, 24);
+ idct_column_large_slow(block, temp, 25);
+ idct_column_large_slow(block, temp, 26);
+ idct_column_large_slow(block, temp, 27);
+
+ idct_column_large_slow(block, temp, 28);
+ idct_column_large_slow(block, temp, 29);
+ idct_column_large_slow(block, temp, 30);
+ idct_column_large_slow(block, temp, 31);
+
+ idct_line_large_slow(temp, block, 0);
+ idct_line_large_slow(temp, block, 1);
+ idct_line_large_slow(temp, block, 2);
+ idct_line_large_slow(temp, block, 3);
+
+ idct_line_large_slow(temp, block, 4);
+ idct_line_large_slow(temp, block, 5);
+ idct_line_large_slow(temp, block, 6);
+ idct_line_large_slow(temp, block, 7);
+
+ idct_line_large_slow(temp, block, 8);
+ idct_line_large_slow(temp, block, 9);
+ idct_line_large_slow(temp, block, 10);
+ idct_line_large_slow(temp, block, 11);
+
+ idct_line_large_slow(temp, block, 12);
+ idct_line_large_slow(temp, block, 13);
+ idct_line_large_slow(temp, block, 14);
+ idct_line_large_slow(temp, block, 15);
+
+ idct_line_large_slow(temp, block, 16);
+ idct_line_large_slow(temp, block, 17);
+ idct_line_large_slow(temp, block, 18);
+ idct_line_large_slow(temp, block, 19);
+
+ idct_line_large_slow(temp, block, 20);
+ idct_line_large_slow(temp, block, 21);
+ idct_line_large_slow(temp, block, 22);
+ idct_line_large_slow(temp, block, 23);
+
+ idct_line_large_slow(temp, block, 24);
+ idct_line_large_slow(temp, block, 25);
+ idct_line_large_slow(temp, block, 26);
+ idct_line_large_slow(temp, block, 27);
+
+ idct_line_large_slow(temp, block, 28);
+ idct_line_large_slow(temp, block, 29);
+ idct_line_large_slow(temp, block, 30);
+ idct_line_large_slow(temp, block, 31);
+}
+
+S32 gDitherNoise = 128;
+
+void decompress_patch(F32 *patch, S32 *cpatch, LLPatchHeader *ph)
+{
+ S32 i, j;
+
+ F32 block[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE], *tblock = block;
+ F32 *tpatch;
+
+ LLGroupHeader *gopp = gGOPP;
+ S32 size = gopp->patch_size;
+ F32 range = ph->range;
+ S32 prequant = (ph->quant_wbits >> 4) + 2;
+ S32 quantize = 1<<prequant;
+ F32 hmin = ph->dc_offset;
+ S32 stride = gopp->stride;
+
+ F32 ooq = 1.f/(F32)quantize;
+ F32 *dq = gPatchDequantizeTable;
+ S32 *decopy_matrix = gDeCopyMatrix;
+
+ F32 mult = ooq*range;
+ F32 addval = mult*(F32)(1<<(prequant - 1))+hmin;
+
+ for (i = 0; i < size*size; i++)
+ {
+ *(tblock++) = *(cpatch + *(decopy_matrix++))*(*dq++);
+ }
+
+ if (size == 16)
+ {
+ idct_patch(block);
+ }
+ else
+ {
+ idct_patch_large(block);
+ }
+
+ for (j = 0; j < size; j++)
+ {
+ tpatch = patch + j*stride;
+ tblock = block + j*size;
+ for (i = 0; i < size; i++)
+ {
+ *(tpatch++) = *(tblock++)*mult+addval;
+ }
+ }
+}
+
+
+void decompress_patchv(LLVector3 *v, S32 *cpatch, LLPatchHeader *ph)
+{
+ S32 i, j;
+
+ F32 block[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE], *tblock = block;
+ LLVector3 *tvec;
+
+ LLGroupHeader *gopp = gGOPP;
+ S32 size = gopp->patch_size;
+ F32 range = ph->range;
+ S32 prequant = (ph->quant_wbits >> 4) + 2;
+ S32 quantize = 1<<prequant;
+ F32 hmin = ph->dc_offset;
+ S32 stride = gopp->stride;
+
+ F32 ooq = 1.f/(F32)quantize;
+ F32 *dq = gPatchDequantizeTable;
+ S32 *decopy_matrix = gDeCopyMatrix;
+
+ F32 mult = ooq*range;
+ F32 addval = mult*(F32)(1<<(prequant - 1))+hmin;
+
+// bool b_diag = false;
+// bool b_right = true;
+
+ for (i = 0; i < size*size; i++)
+ {
+ *(tblock++) = *(cpatch + *(decopy_matrix++))*(*dq++);
+ }
+
+ if (size == 16)
+ idct_patch(block);
+ else
+ idct_patch_large(block);
+
+ for (j = 0; j < size; j++)
+ {
+ tvec = v + j*stride;
+ tblock = block + j*size;
+ for (i = 0; i < size; i++)
+ {
+ (*tvec++).mV[VZ] = *(tblock++)*mult+addval;
+ }
+ }
+}
+
diff --git a/indra/llmessage/tests/llmockhttpclient.h b/indra/llmessage/tests/llmockhttpclient.h deleted file mode 100644 index 1611ab7bd8..0000000000 --- a/indra/llmessage/tests/llmockhttpclient.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * @brief - * - * $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$ - */ - -/* 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/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp index 911aef827d..d0a34d720a 100644 --- a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp +++ b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp @@ -1,160 +1,160 @@ -/** - * @file lltrustedmessageservice_test.cpp - * @brief LLTrustedMessageService unit tests - * - * $LicenseInfo:firstyear=2009&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$ - */ - -#include "lltemplatemessagedispatcher.h" -#include "lltut.h" - -#include "llhttpnode.h" -#include "llhost.h" -#include "message.h" -#include "llsd.h" -#include "llpounceable.h" - -#include "llhost.cpp" // Needed for copy operator -#include "net.cpp" // Needed by LLHost. - -LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; - -// sensor test doubles -bool gClearRecvWasCalled = false; -void LLMessageSystem::clearReceiveState(void) -{ - gClearRecvWasCalled = true; -} - -char gUdpDispatchedData[MAX_BUFFER_SIZE]; -bool gUdpDispatchWasCalled = false; -BOOL LLTemplateMessageReader::readMessage(const U8* data,class LLHost const &) -{ - gUdpDispatchWasCalled = true; - strcpy(gUdpDispatchedData, reinterpret_cast<const char*>(data)); - return true; -} - -BOOL gValidateMessage = FALSE; -BOOL LLTemplateMessageReader::validateMessage(const U8*, S32 buffer_size, LLHost const &sender, bool trusted) -{ - return gValidateMessage; -} - -LLHost host; -const LLHost& LLMessageSystem::getSender() const -{ - return host; -} - -const char* gBinaryTemplateData = "BINARYTEMPLATEDATA"; -void fillVector(std::vector<U8>& vector_data, const char* data) -{ - vector_data.resize(strlen(data) + 1); - strcpy(reinterpret_cast<char*>(&vector_data[0]), data); -} - -namespace tut -{ - static LLTemplateMessageReader::message_template_number_map_t numberMap; - - struct LLTemplateMessageDispatcherData - { - LLTemplateMessageDispatcherData() - { - mMessageName = "MessageName"; - gUdpDispatchWasCalled = false; - gClearRecvWasCalled = false; - gValidateMessage = FALSE; - mMessage["body"]["binary-template-data"] = std::vector<U8>(); - } - - LLSD mMessage; - LLHTTPNode::ResponsePtr mResponsePtr; - std::string mMessageName; - }; - - typedef test_group<LLTemplateMessageDispatcherData> factory; - typedef factory::object object; -} - -namespace -{ - tut::factory tf("LLTemplateMessageDispatcher"); -} - -namespace tut -{ - // does an empty message stop processing? - template<> template<> - void object::test<1>() - { - LLTemplateMessageReader* pReader = NULL; - LLTemplateMessageDispatcher t(*pReader); - t.dispatch(mMessageName, mMessage, mResponsePtr); - ensure(! gUdpDispatchWasCalled); - ensure(! gClearRecvWasCalled); - } - - // does the disaptch invoke the udp send method? - template<> template<> - void object::test<2>() - { - LLTemplateMessageReader* pReader = NULL; - LLTemplateMessageDispatcher t(*pReader); - gValidateMessage = TRUE; - std::vector<U8> vector_data; - fillVector(vector_data, gBinaryTemplateData); - mMessage["body"]["binary-template-data"] = vector_data; - t.dispatch(mMessageName, mMessage, mResponsePtr); - ensure("udp dispatch was called", gUdpDispatchWasCalled); - } - - // what if the message wasn't valid? We would hope the message gets cleared! - template<> template<> - void object::test<3>() - { - LLTemplateMessageReader* pReader = NULL; - LLTemplateMessageDispatcher t(*pReader); - std::vector<U8> vector_data; - fillVector(vector_data, gBinaryTemplateData); - mMessage["body"]["binary-template-data"] = vector_data; - gValidateMessage = FALSE; - t.dispatch(mMessageName, mMessage, mResponsePtr); - ensure("clear received message was called", gClearRecvWasCalled); - } - - // is the binary data passed through correctly? - template<> template<> - void object::test<4>() - { - LLTemplateMessageReader* pReader = NULL; - LLTemplateMessageDispatcher t(*pReader); - gValidateMessage = TRUE; - std::vector<U8> vector_data; - fillVector(vector_data, gBinaryTemplateData); - mMessage["body"]["binary-template-data"] = vector_data; - t.dispatch(mMessageName, mMessage, mResponsePtr); - ensure("data couriered correctly", strcmp(gBinaryTemplateData, gUdpDispatchedData) == 0); - } -} - +/**
+ * @file lltrustedmessageservice_test.cpp
+ * @brief LLTrustedMessageService unit tests
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#include "lltemplatemessagedispatcher.h"
+#include "lltut.h"
+
+#include "llhttpnode.h"
+#include "llhost.h"
+#include "message.h"
+#include "llsd.h"
+#include "llpounceable.h"
+
+#include "llhost.cpp" // Needed for copy operator
+#include "net.cpp" // Needed by LLHost.
+
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
+
+// sensor test doubles
+bool gClearRecvWasCalled = false;
+void LLMessageSystem::clearReceiveState(void)
+{
+ gClearRecvWasCalled = true;
+}
+
+char gUdpDispatchedData[MAX_BUFFER_SIZE];
+bool gUdpDispatchWasCalled = false;
+bool LLTemplateMessageReader::readMessage(const U8* data,class LLHost const &)
+{
+ gUdpDispatchWasCalled = true;
+ strcpy(gUdpDispatchedData, reinterpret_cast<const char*>(data));
+ return true;
+}
+
+bool gValidateMessage = false;
+bool LLTemplateMessageReader::validateMessage(const U8*, S32 buffer_size, LLHost const &sender, bool trusted)
+{
+ return gValidateMessage;
+}
+
+LLHost host;
+const LLHost& LLMessageSystem::getSender() const
+{
+ return host;
+}
+
+const char* gBinaryTemplateData = "BINARYTEMPLATEDATA";
+void fillVector(std::vector<U8>& vector_data, const char* data)
+{
+ vector_data.resize(strlen(data) + 1);
+ strcpy(reinterpret_cast<char*>(&vector_data[0]), data);
+}
+
+namespace tut
+{
+ static LLTemplateMessageReader::message_template_number_map_t numberMap;
+
+ struct LLTemplateMessageDispatcherData
+ {
+ LLTemplateMessageDispatcherData()
+ {
+ mMessageName = "MessageName";
+ gUdpDispatchWasCalled = false;
+ gClearRecvWasCalled = false;
+ gValidateMessage = false;
+ mMessage["body"]["binary-template-data"] = std::vector<U8>();
+ }
+
+ LLSD mMessage;
+ LLHTTPNode::ResponsePtr mResponsePtr;
+ std::string mMessageName;
+ };
+
+ typedef test_group<LLTemplateMessageDispatcherData> factory;
+ typedef factory::object object;
+}
+
+namespace
+{
+ tut::factory tf("LLTemplateMessageDispatcher");
+}
+
+namespace tut
+{
+ // does an empty message stop processing?
+ template<> template<>
+ void object::test<1>()
+ {
+ LLTemplateMessageReader* pReader = NULL;
+ LLTemplateMessageDispatcher t(*pReader);
+ t.dispatch(mMessageName, mMessage, mResponsePtr);
+ ensure(! gUdpDispatchWasCalled);
+ ensure(! gClearRecvWasCalled);
+ }
+
+ // does the disaptch invoke the udp send method?
+ template<> template<>
+ void object::test<2>()
+ {
+ LLTemplateMessageReader* pReader = NULL;
+ LLTemplateMessageDispatcher t(*pReader);
+ gValidateMessage = true;
+ std::vector<U8> vector_data;
+ fillVector(vector_data, gBinaryTemplateData);
+ mMessage["body"]["binary-template-data"] = vector_data;
+ t.dispatch(mMessageName, mMessage, mResponsePtr);
+ ensure("udp dispatch was called", gUdpDispatchWasCalled);
+ }
+
+ // what if the message wasn't valid? We would hope the message gets cleared!
+ template<> template<>
+ void object::test<3>()
+ {
+ LLTemplateMessageReader* pReader = NULL;
+ LLTemplateMessageDispatcher t(*pReader);
+ std::vector<U8> vector_data;
+ fillVector(vector_data, gBinaryTemplateData);
+ mMessage["body"]["binary-template-data"] = vector_data;
+ gValidateMessage = false;
+ t.dispatch(mMessageName, mMessage, mResponsePtr);
+ ensure("clear received message was called", gClearRecvWasCalled);
+ }
+
+ // is the binary data passed through correctly?
+ template<> template<>
+ void object::test<4>()
+ {
+ LLTemplateMessageReader* pReader = NULL;
+ LLTemplateMessageDispatcher t(*pReader);
+ gValidateMessage = true;
+ std::vector<U8> vector_data;
+ fillVector(vector_data, gBinaryTemplateData);
+ mMessage["body"]["binary-template-data"] = vector_data;
+ t.dispatch(mMessageName, mMessage, mResponsePtr);
+ ensure("data couriered correctly", strcmp(gBinaryTemplateData, gUdpDispatchedData) == 0);
+ }
+}
+
diff --git a/indra/llmessage/tests/llxfer_file_test.cpp b/indra/llmessage/tests/llxfer_file_test.cpp index af0cc5b5ab..6a2e0566df 100644 --- a/indra/llmessage/tests/llxfer_file_test.cpp +++ b/indra/llmessage/tests/llxfer_file_test.cpp @@ -1,58 +1,58 @@ -/** - * @file llxfer_test.cpp - * @author Moss - * @date 2007-04-17 - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "linden_common.h" - -#include "../llxfer_file.h" - -#include "../test/lltut.h" - -namespace tut -{ - struct llxfer_data - { - }; - typedef test_group<llxfer_data> llxfer_test; - typedef llxfer_test::object llxfer_object; - tut::llxfer_test llxfer("LLXferFile"); - - template<> template<> - void llxfer_object::test<1>() - { - // test that we handle an oversized filename correctly. - std::string oversized_filename; - U32 i; - for (i=0; i<LL_MAX_PATH*2; ++i) // create oversized filename - { - oversized_filename += 'X'; - } - - LLXfer_File xff(oversized_filename, FALSE, 1); - ensure("oversized local_filename nul-terminated", - xff.getFileName().length() < LL_MAX_PATH); - } -} +/**
+ * @file llxfer_test.cpp
+ * @author Moss
+ * @date 2007-04-17
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+
+#include "../llxfer_file.h"
+
+#include "../test/lltut.h"
+
+namespace tut
+{
+ struct llxfer_data
+ {
+ };
+ typedef test_group<llxfer_data> llxfer_test;
+ typedef llxfer_test::object llxfer_object;
+ tut::llxfer_test llxfer("LLXferFile");
+
+ template<> template<>
+ void llxfer_object::test<1>()
+ {
+ // test that we handle an oversized filename correctly.
+ std::string oversized_filename;
+ U32 i;
+ for (i=0; i<LL_MAX_PATH*2; ++i) // create oversized filename
+ {
+ oversized_filename += 'X';
+ }
+
+ LLXfer_File xff(oversized_filename, false, 1);
+ ensure("oversized local_filename nul-terminated",
+ xff.getFileName().length() < LL_MAX_PATH);
+ }
+}
|