diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/llmessage | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/llmessage')
179 files changed, 43257 insertions, 43257 deletions
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index dd63724039..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/llavatarname.cpp b/indra/llmessage/llavatarname.cpp index 7e1246f885..650a76860a 100644 --- a/indra/llmessage/llavatarname.cpp +++ b/indra/llmessage/llavatarname.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llavatarname.cpp * @brief Represents name-related data for an avatar, such as the * username/SLID ("bobsmith123" or "james.linden") and the display @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,222 +48,222 @@ bool LLAvatarName::sUseUsernames = true; // Minimum time-to-live (in seconds) for a name entry. // Avatar name should always guarantee to expire reasonably soon by default -// so if the failure to get a valid expiration time was due to something temporary +// so if the failure to get a valid expiration time was due to something temporary // we will eventually request and get the right data. const F64 MIN_ENTRY_LIFETIME = 60.0; LLAvatarName::LLAvatarName() -: mUsername(), - mDisplayName(), - mLegacyFirstName(), - mLegacyLastName(), - mIsDisplayNameDefault(false), - mIsTemporaryName(false), - mExpires(F64_MAX), - mNextUpdate(0.0) +: mUsername(), + mDisplayName(), + mLegacyFirstName(), + mLegacyLastName(), + mIsDisplayNameDefault(false), + mIsTemporaryName(false), + mExpires(F64_MAX), + mNextUpdate(0.0) { } bool LLAvatarName::operator<(const LLAvatarName& rhs) const { - if (mUsername == rhs.mUsername) - return mDisplayName < rhs.mDisplayName; - else - return mUsername < rhs.mUsername; + if (mUsername == rhs.mUsername) + return mDisplayName < rhs.mDisplayName; + else + return mUsername < rhs.mUsername; } -//static +//static void LLAvatarName::setUseDisplayNames(bool use) { - sUseDisplayNames = use; + sUseDisplayNames = use; } -//static -bool LLAvatarName::useDisplayNames() -{ - return sUseDisplayNames; +//static +bool LLAvatarName::useDisplayNames() +{ + return sUseDisplayNames; } void LLAvatarName::setUseUsernames(bool use) { - sUseUsernames = use; + sUseUsernames = use; } bool LLAvatarName::useUsernames() { - return sUseUsernames; + return sUseUsernames; } LLSD LLAvatarName::asLLSD() const { - LLSD sd; - sd[USERNAME] = mUsername; - sd[DISPLAY_NAME] = mDisplayName; - sd[LEGACY_FIRST_NAME] = mLegacyFirstName; - sd[LEGACY_LAST_NAME] = mLegacyLastName; - sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault; - sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires); - sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate); - return sd; + LLSD sd; + sd[USERNAME] = mUsername; + sd[DISPLAY_NAME] = mDisplayName; + sd[LEGACY_FIRST_NAME] = mLegacyFirstName; + sd[LEGACY_LAST_NAME] = mLegacyLastName; + sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault; + sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires); + sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate); + return sd; } void LLAvatarName::fromLLSD(const LLSD& sd) { - mUsername = sd[USERNAME].asString(); - mDisplayName = sd[DISPLAY_NAME].asString(); - mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString(); - mLegacyLastName = sd[LEGACY_LAST_NAME].asString(); - mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean(); - LLDate expires = sd[DISPLAY_NAME_EXPIRES]; - mExpires = expires.secondsSinceEpoch(); - LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE]; - mNextUpdate = next_update.secondsSinceEpoch(); - - // Some avatars don't have explicit display names set. Force a legible display name here. - if (mDisplayName.empty()) - { - mDisplayName = mUsername; - } + mUsername = sd[USERNAME].asString(); + mDisplayName = sd[DISPLAY_NAME].asString(); + mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString(); + mLegacyLastName = sd[LEGACY_LAST_NAME].asString(); + mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean(); + LLDate expires = sd[DISPLAY_NAME_EXPIRES]; + mExpires = expires.secondsSinceEpoch(); + LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE]; + mNextUpdate = next_update.secondsSinceEpoch(); + + // Some avatars don't have explicit display names set. Force a legible display name here. + if (mDisplayName.empty()) + { + mDisplayName = mUsername; + } } // Transform a string (typically provided by the legacy service) into a decent // avatar name instance. void LLAvatarName::fromString(const std::string& full_name) { - mDisplayName = full_name; - std::string::size_type index = full_name.find(' '); - if (index != std::string::npos) - { - // The name is in 2 parts (first last) - mLegacyFirstName = full_name.substr(0, index); - mLegacyLastName = full_name.substr(index+1); - if (mLegacyLastName != "Resident") - { - mUsername = mLegacyFirstName + "." + mLegacyLastName; - mDisplayName = full_name; - LLStringUtil::toLower(mUsername); - } - else - { - // Very old names do have a dummy "Resident" last name - // that we choose to hide from users. - mUsername = mLegacyFirstName; - mDisplayName = mLegacyFirstName; - } - } - else - { - mLegacyFirstName = full_name; - mLegacyLastName = ""; - mUsername = full_name; - mDisplayName = full_name; - } - mIsDisplayNameDefault = true; - mIsTemporaryName = true; - setExpires(MIN_ENTRY_LIFETIME); + mDisplayName = full_name; + std::string::size_type index = full_name.find(' '); + if (index != std::string::npos) + { + // The name is in 2 parts (first last) + mLegacyFirstName = full_name.substr(0, index); + mLegacyLastName = full_name.substr(index+1); + if (mLegacyLastName != "Resident") + { + mUsername = mLegacyFirstName + "." + mLegacyLastName; + mDisplayName = full_name; + LLStringUtil::toLower(mUsername); + } + else + { + // Very old names do have a dummy "Resident" last name + // that we choose to hide from users. + mUsername = mLegacyFirstName; + mDisplayName = mLegacyFirstName; + } + } + else + { + mLegacyFirstName = full_name; + mLegacyLastName = ""; + mUsername = full_name; + mDisplayName = full_name; + } + mIsDisplayNameDefault = true; + mIsTemporaryName = true; + setExpires(MIN_ENTRY_LIFETIME); } void LLAvatarName::setExpires(F64 expires) { - mExpires = LLFrameTimer::getTotalSeconds() + expires; + mExpires = LLFrameTimer::getTotalSeconds() + expires; } std::string LLAvatarName::getCompleteName(bool use_parentheses, bool force_use_complete_name) const { - std::string name; - if (sUseDisplayNames || force_use_complete_name) - { - if (mUsername.empty() || mIsDisplayNameDefault) - { - // If this particular display name is defaulted (i.e. based on user name), - // then display only the easier to read instance of the person's name. - name = mDisplayName; - } - else - { - name = mDisplayName; - if(sUseUsernames || force_use_complete_name) - { - if(use_parentheses) - { - name += " (" + mUsername + ")"; - } - else - { - name += " [ " + mUsername + " ]"; - } - } - } - } - else - { - name = getUserName(); - } - return name; + std::string name; + if (sUseDisplayNames || force_use_complete_name) + { + if (mUsername.empty() || mIsDisplayNameDefault) + { + // If this particular display name is defaulted (i.e. based on user name), + // then display only the easier to read instance of the person's name. + name = mDisplayName; + } + else + { + name = mDisplayName; + if(sUseUsernames || force_use_complete_name) + { + if(use_parentheses) + { + name += " (" + mUsername + ")"; + } + else + { + name += " [ " + mUsername + " ]"; + } + } + } + } + else + { + name = getUserName(); + } + return name; } std::string LLAvatarName::getLegacyName() const { - if (mLegacyFirstName.empty() && mLegacyLastName.empty()) // display names disabled? - { - return mDisplayName; - } + if (mLegacyFirstName.empty() && mLegacyLastName.empty()) // display names disabled? + { + return mDisplayName; + } - std::string name; - name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() ); - name = mLegacyFirstName; - name += " "; - name += mLegacyLastName; - return name; + std::string name; + name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() ); + name = mLegacyFirstName; + name += " "; + name += mLegacyLastName; + return name; } std::string LLAvatarName::getDisplayName(bool force_use_display_name) const { - if (sUseDisplayNames || force_use_display_name) - { - return mDisplayName; - } - else - { - return getUserName(); - } + if (sUseDisplayNames || force_use_display_name) + { + return mDisplayName; + } + else + { + return getUserName(); + } } std::string LLAvatarName::getUserName(bool lowercase) const { - std::string name; - if (mLegacyLastName.empty() || (mLegacyLastName == "Resident")) - { - if (mLegacyFirstName.empty()) - { - // If we cannot create a user name from the legacy strings, use the display name - name = mDisplayName; - } - else - { - // The last name might be empty if it defaulted to "Resident" - name = mLegacyFirstName; - } - } - else - { - if(lowercase) - { - name = mLegacyFirstName + "." + mLegacyLastName; - LLStringUtil::toLower(name); - } - else - { - name = mLegacyFirstName + " " + mLegacyLastName; - } - } - return name; + std::string name; + if (mLegacyLastName.empty() || (mLegacyLastName == "Resident")) + { + if (mLegacyFirstName.empty()) + { + // If we cannot create a user name from the legacy strings, use the display name + name = mDisplayName; + } + else + { + // The last name might be empty if it defaulted to "Resident" + name = mLegacyFirstName; + } + } + else + { + if(lowercase) + { + name = mLegacyFirstName + "." + mLegacyLastName; + LLStringUtil::toLower(name); + } + else + { + name = mLegacyFirstName + " " + mLegacyLastName; + } + } + return name; } void LLAvatarName::dump() const { - LL_DEBUGS("AvNameCache") << "LLAvatarName: " - << "user '" << mUsername << "' " - << "display '" << mDisplayName << "' " - << "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds" - << LL_ENDL; + LL_DEBUGS("AvNameCache") << "LLAvatarName: " + << "user '" << mUsername << "' " + << "display '" << mDisplayName << "' " + << "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds" + << LL_ENDL; } diff --git a/indra/llmessage/llavatarname.h b/indra/llmessage/llavatarname.h index 20f7140797..eec966d51b 100644 --- a/indra/llmessage/llavatarname.h +++ b/indra/llmessage/llavatarname.h @@ -1,4 +1,4 @@ -/** +/** * @file llavatarname.h * @brief Represents name-related data for an avatar, such as the * username/SLID ("bobsmith123" or "james.linden") and the display @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,105 +35,105 @@ class LLSD; class LL_COMMON_API LLAvatarName { public: - LLAvatarName(); - - bool operator<(const LLAvatarName& rhs) const; - - // Conversion to and from LLSD (cache file or server response) - LLSD asLLSD() const; - void fromLLSD(const LLSD& sd); - - // Used only in legacy mode when the display name capability is not provided server side - // or to otherwise create a temporary valid item. - void fromString(const std::string& full_name); - - // Set the name object to become invalid in "expires" seconds from now - void setExpires(F64 expires); - - // Set and get the display name flag set by the user in preferences. - static void setUseDisplayNames(bool use); - static bool useDisplayNames(); - - static void setUseUsernames(bool use); - static bool useUsernames(); - - // A name object is valid if not temporary and not yet expired (default is expiration not checked) - bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); } - - // Return true if the name is made up from legacy or temporary data - bool isDisplayNameDefault() const { return mIsDisplayNameDefault; } - - // For normal names, returns "James Linden (james.linden)" - // When display names are disabled returns just "James Linden" - std::string getCompleteName(bool use_parentheses = true, bool force_use_complete_name = false) const; - - // Returns "James Linden" or "bobsmith123 Resident" for backwards - // compatibility with systems like voice and muting - // *TODO: Eliminate this in favor of username only - std::string getLegacyName() const; - - // "José Sanchez" or "James Linden", UTF-8 encoded Unicode - // Takes the display name preference into account. This is truly the name that should - // be used for all UI where an avatar name has to be used unless we truly want something else (rare) - std::string getDisplayName(bool force_use_display_name = false) const; - - // Returns "James Linden" or "bobsmith123 Resident" - // Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name - // Also used for backwards compatibility with systems like voice and muting - std::string getUserName(bool lowercase = false) const; - - // Returns "james.linden" or the legacy name for very old names - std::string getAccountName() const { return mUsername; } - - // Debug print of the object - void dump() const; - - // Names can change, so need to keep track of when name was - // last checked. - // Unix time-from-epoch seconds for efficiency - F64 mExpires; - - // You can only change your name every N hours, so record - // when the next update is allowed - // Unix time-from-epoch seconds - F64 mNextUpdate; - + LLAvatarName(); + + bool operator<(const LLAvatarName& rhs) const; + + // Conversion to and from LLSD (cache file or server response) + LLSD asLLSD() const; + void fromLLSD(const LLSD& sd); + + // Used only in legacy mode when the display name capability is not provided server side + // or to otherwise create a temporary valid item. + void fromString(const std::string& full_name); + + // Set the name object to become invalid in "expires" seconds from now + void setExpires(F64 expires); + + // Set and get the display name flag set by the user in preferences. + static void setUseDisplayNames(bool use); + static bool useDisplayNames(); + + static void setUseUsernames(bool use); + static bool useUsernames(); + + // A name object is valid if not temporary and not yet expired (default is expiration not checked) + bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); } + + // Return true if the name is made up from legacy or temporary data + bool isDisplayNameDefault() const { return mIsDisplayNameDefault; } + + // For normal names, returns "James Linden (james.linden)" + // When display names are disabled returns just "James Linden" + std::string getCompleteName(bool use_parentheses = true, bool force_use_complete_name = false) const; + + // Returns "James Linden" or "bobsmith123 Resident" for backwards + // compatibility with systems like voice and muting + // *TODO: Eliminate this in favor of username only + std::string getLegacyName() const; + + // "José Sanchez" or "James Linden", UTF-8 encoded Unicode + // Takes the display name preference into account. This is truly the name that should + // be used for all UI where an avatar name has to be used unless we truly want something else (rare) + std::string getDisplayName(bool force_use_display_name = false) const; + + // Returns "James Linden" or "bobsmith123 Resident" + // Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name + // Also used for backwards compatibility with systems like voice and muting + std::string getUserName(bool lowercase = false) const; + + // Returns "james.linden" or the legacy name for very old names + std::string getAccountName() const { return mUsername; } + + // Debug print of the object + void dump() const; + + // Names can change, so need to keep track of when name was + // last checked. + // Unix time-from-epoch seconds for efficiency + F64 mExpires; + + // You can only change your name every N hours, so record + // when the next update is allowed + // Unix time-from-epoch seconds + F64 mNextUpdate; + private: - // "bobsmith123" or "james.linden", US-ASCII only - std::string mUsername; - - // "José Sanchez" or "James Linden", UTF-8 encoded Unicode - // Contains data whether or not user has explicitly set - // a display name; may duplicate their username. - std::string mDisplayName; - - // For "James Linden", "James" - // For "bobsmith123", "bobsmith123" - // Used to communicate with legacy systems like voice and muting which - // rely on old-style names. - // *TODO: Eliminate this in favor of username only - std::string mLegacyFirstName; - - // For "James Linden", "Linden" - // For "bobsmith123", "Resident" - // see above for rationale - std::string mLegacyLastName; - - // If true, both display name and SLID were generated from - // a legacy first and last name, like "James Linden (james.linden)" - bool mIsDisplayNameDefault; - - // Under error conditions, we may insert "dummy" records with - // names like "???" into caches as placeholders. These can be - // shown in UI, but are not serialized. - bool mIsTemporaryName; - - // Global flag indicating if display name should be used or not - // This will affect the output of the high level "get" methods - static bool sUseDisplayNames; - - // Flag indicating if username should be shown after display name or not - static bool sUseUsernames; + // "bobsmith123" or "james.linden", US-ASCII only + std::string mUsername; + + // "José Sanchez" or "James Linden", UTF-8 encoded Unicode + // Contains data whether or not user has explicitly set + // a display name; may duplicate their username. + std::string mDisplayName; + + // For "James Linden", "James" + // For "bobsmith123", "bobsmith123" + // Used to communicate with legacy systems like voice and muting which + // rely on old-style names. + // *TODO: Eliminate this in favor of username only + std::string mLegacyFirstName; + + // For "James Linden", "Linden" + // For "bobsmith123", "Resident" + // see above for rationale + std::string mLegacyLastName; + + // If true, both display name and SLID were generated from + // a legacy first and last name, like "James Linden (james.linden)" + bool mIsDisplayNameDefault; + + // Under error conditions, we may insert "dummy" records with + // names like "???" into caches as placeholders. These can be + // shown in UI, but are not serialized. + bool mIsTemporaryName; + + // Global flag indicating if display name should be used or not + // This will affect the output of the high level "get" methods + static bool sUseDisplayNames; + + // Flag indicating if username should be shown after display name or not + static bool sUseUsernames; }; #endif diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index f7a9f55685..a0cd6f93c1 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llavatarnamecache.cpp * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names * ("James Cook") from avatar UUIDs. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,7 +28,7 @@ #include "llavatarnamecache.h" -#include "llcachename.h" // we wrap this system +#include "llcachename.h" // we wrap this system #include "llframetimer.h" #include "llsd.h" #include "llsdserialize.h" @@ -60,10 +60,10 @@ const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0; static LLFrameTimer sRequestTimer; // static to avoid unnessesary dependencies -LLCore::HttpRequest::ptr_t sHttpRequest; -LLCore::HttpHeaders::ptr_t sHttpHeaders; -LLCore::HttpOptions::ptr_t sHttpOptions; -LLCore::HttpRequest::policy_t sHttpPolicy; +LLCore::HttpRequest::ptr_t sHttpRequest; +LLCore::HttpHeaders::ptr_t sHttpHeaders; +LLCore::HttpOptions::ptr_t sHttpOptions; +LLCore::HttpRequest::policy_t sHttpPolicy; /* Sample response: <?xml version="1.0"?> @@ -104,7 +104,7 @@ LLCore::HttpRequest::policy_t sHttpPolicy; </llsd> */ -// Coroutine for sending and processing avatar name cache requests. +// Coroutine for sending and processing avatar name cache requests. // Do not call directly. See documentation in lleventcoro.h and llcoro.h for // further explanation. @@ -180,7 +180,7 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU if (LLAvatarNameCache::instanceExists()) { if (!success) - { // on any sort of failure add dummy records for any agent IDs + { // on any sort of failure add dummy records for any agent IDs // in this request that we do not have cached already std::vector<LLUUID>::const_iterator it = agentIds.begin(); for (; it != agentIds.end(); ++it) @@ -268,16 +268,16 @@ void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &h // Provide some fallback for agents that return errors void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) { - std::map<LLUUID,LLAvatarName>::iterator existing = mCache.find(agent_id); - if (existing == mCache.end()) + std::map<LLUUID,LLAvatarName>::iterator existing = mCache.find(agent_id); + if (existing == mCache.end()) { // there is no existing cache entry, so make a temporary name from legacy LL_DEBUGS("AvNameCache") << "LLAvatarNameCache get legacy for agent " - << agent_id << LL_ENDL; + << agent_id << LL_ENDL; gCacheName->get(agent_id, false, // legacy compatibility boost::bind(&LLAvatarNameCache::legacyNameFetch, _1, _2, _3)); } - else + else { // we have a cached (but probably expired) entry - since that would have // been returned by the get method, there is no need to signal anyone @@ -287,19 +287,19 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) LLAvatarName& av_name = existing->second; LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " << agent_id << LL_ENDL; - av_name.dump(); + av_name.dump(); - // Reset expiry time so we don't constantly rerequest. - av_name.setExpires(TEMP_CACHE_ENTRY_LIFETIME); + // Reset expiry time so we don't constantly rerequest. + av_name.setExpires(TEMP_CACHE_ENTRY_LIFETIME); } } void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& av_name) { - if (agent_id.isNull()) - { - return; - } + if (agent_id.isNull()) + { + return; + } bool updated_account = true; // assume obsolete value for new arrivals by default @@ -310,175 +310,175 @@ void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& updated_account = false; } - // Add to the cache - mCache[agent_id] = av_name; + // Add to the cache + mCache[agent_id] = av_name; - // Suppress request from the queue - mPendingQueue.erase(agent_id); + // Suppress request from the queue + mPendingQueue.erase(agent_id); - // notify mute list about changes + // notify mute list about changes if (updated_account && mAccountNameChangedCallback) { mAccountNameChangedCallback(agent_id, av_name); } - // Signal everyone waiting on this name - signal_map_t::iterator sig_it = mSignalMap.find(agent_id); - if (sig_it != mSignalMap.end()) - { - callback_signal_t* signal = sig_it->second; - (*signal)(agent_id, av_name); + // Signal everyone waiting on this name + signal_map_t::iterator sig_it = mSignalMap.find(agent_id); + if (sig_it != mSignalMap.end()) + { + callback_signal_t* signal = sig_it->second; + (*signal)(agent_id, av_name); - mSignalMap.erase(agent_id); + mSignalMap.erase(agent_id); - delete signal; - signal = NULL; - } + delete signal; + signal = NULL; + } } void LLAvatarNameCache::requestNamesViaCapability() { - F64 now = LLFrameTimer::getTotalSeconds(); - - // URL format is like: - // http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0 - // - // Apache can handle URLs of 4096 chars, but let's be conservative - static const U32 NAME_URL_MAX = 4096; - static const U32 NAME_URL_SEND_THRESHOLD = 3500; - - std::string url; - url.reserve(NAME_URL_MAX); - - std::vector<LLUUID> agent_ids; - agent_ids.reserve(128); - - U32 ids = 0; - ask_queue_t::const_iterator it; - while(!mAskQueue.empty()) - { - it = mAskQueue.begin(); - LLUUID agent_id = *it; - mAskQueue.erase(it); - - if (url.empty()) - { - // ...starting new request - url += mNameLookupURL; - url += "?ids="; - ids = 1; - } - else - { - // ...continuing existing request - url += "&ids="; - ids++; - } - url += agent_id.asString(); - agent_ids.push_back(agent_id); - - // mark request as pending - mPendingQueue[agent_id] = now; - - if (url.size() > NAME_URL_SEND_THRESHOLD) - { - break; - } - } + F64 now = LLFrameTimer::getTotalSeconds(); + + // URL format is like: + // http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0 + // + // Apache can handle URLs of 4096 chars, but let's be conservative + static const U32 NAME_URL_MAX = 4096; + static const U32 NAME_URL_SEND_THRESHOLD = 3500; + + std::string url; + url.reserve(NAME_URL_MAX); + + std::vector<LLUUID> agent_ids; + agent_ids.reserve(128); + + U32 ids = 0; + ask_queue_t::const_iterator it; + while(!mAskQueue.empty()) + { + it = mAskQueue.begin(); + LLUUID agent_id = *it; + mAskQueue.erase(it); + + if (url.empty()) + { + // ...starting new request + url += mNameLookupURL; + url += "?ids="; + ids = 1; + } + else + { + // ...continuing existing request + url += "&ids="; + ids++; + } + url += agent_id.asString(); + agent_ids.push_back(agent_id); + + // mark request as pending + mPendingQueue[agent_id] = now; + + if (url.size() > NAME_URL_SEND_THRESHOLD) + { + break; + } + } if (!url.empty()) { LL_DEBUGS("AvNameCache") << "requested " << ids << " ids" << LL_ENDL; - std::string coroname = + std::string coroname = LLCoros::instance().launch("LLAvatarNameCache::requestAvatarNameCache_", boost::bind(&LLAvatarNameCache::requestAvatarNameCache_, url, agent_ids)); LL_DEBUGS("AvNameCache") << coroname << " with url '" << url << "', agent_ids.size()=" << agent_ids.size() << LL_ENDL; - } + } } void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, - const std::string& full_name, - bool is_group) + const std::string& full_name, + bool is_group) { - // Put the received data in the cache - legacyNameFetch(agent_id, full_name, is_group); - - // Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy - // protocol, we do not get an expiration date for each name and there's no reason to ask the - // data again and again so we set the expiration time to the largest value admissible. - std::map<LLUUID,LLAvatarName>::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id); - LLAvatarName& av_name = av_record->second; - av_name.setExpires(MAX_UNREFRESHED_TIME); + // Put the received data in the cache + legacyNameFetch(agent_id, full_name, is_group); + + // Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy + // protocol, we do not get an expiration date for each name and there's no reason to ask the + // data again and again so we set the expiration time to the largest value admissible. + std::map<LLUUID,LLAvatarName>::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id); + LLAvatarName& av_name = av_record->second; + av_name.setExpires(MAX_UNREFRESHED_TIME); } void LLAvatarNameCache::legacyNameFetch(const LLUUID& agent_id, - const std::string& full_name, - bool is_group) -{ - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache agent " << agent_id << " " - << "full name '" << full_name << "'" - << ( is_group ? " [group]" : "" ) - << LL_ENDL; - - // Construct an av_name record from this name. - LLAvatarName av_name; - av_name.fromString(full_name); - - // Add to cache: we're still using the new cache even if we're using the old (legacy) protocol. - LLAvatarNameCache::getInstance()->processName(agent_id, av_name); + const std::string& full_name, + bool is_group) +{ + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache agent " << agent_id << " " + << "full name '" << full_name << "'" + << ( is_group ? " [group]" : "" ) + << LL_ENDL; + + // Construct an av_name record from this name. + LLAvatarName av_name; + av_name.fromString(full_name); + + // Add to cache: we're still using the new cache even if we're using the old (legacy) protocol. + LLAvatarNameCache::getInstance()->processName(agent_id, av_name); } void LLAvatarNameCache::requestNamesViaLegacy() { - static const S32 MAX_REQUESTS = 100; - F64 now = LLFrameTimer::getTotalSeconds(); - std::string full_name; - ask_queue_t::const_iterator it; - for (S32 requests = 0; !mAskQueue.empty() && requests < MAX_REQUESTS; ++requests) - { - it = mAskQueue.begin(); - LLUUID agent_id = *it; - mAskQueue.erase(it); + static const S32 MAX_REQUESTS = 100; + F64 now = LLFrameTimer::getTotalSeconds(); + std::string full_name; + ask_queue_t::const_iterator it; + for (S32 requests = 0; !mAskQueue.empty() && requests < MAX_REQUESTS; ++requests) + { + it = mAskQueue.begin(); + LLUUID agent_id = *it; + mAskQueue.erase(it); - // Mark as pending first, just in case the callback is immediately - // invoked below. This should never happen in practice. - mPendingQueue[agent_id] = now; + // Mark as pending first, just in case the callback is immediately + // invoked below. This should never happen in practice. + mPendingQueue[agent_id] = now; - LL_DEBUGS("AvNameCache") << "agent " << agent_id << LL_ENDL; + LL_DEBUGS("AvNameCache") << "agent " << agent_id << LL_ENDL; - gCacheName->get(agent_id, false, // legacy compatibility - boost::bind(&LLAvatarNameCache::legacyNameCallback, _1, _2, _3)); - } + gCacheName->get(agent_id, false, // legacy compatibility + boost::bind(&LLAvatarNameCache::legacyNameCallback, _1, _2, _3)); + } } bool LLAvatarNameCache::importFile(std::istream& istr) { - LLSD data; - if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(data, istr)) - { + LLSD data; + if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(data, istr)) + { LL_WARNS("AvNameCache") << "avatar name cache data xml parse failed" << LL_ENDL; - return false; - } - - // by convention LLSD storage is a map - // we only store one entry in the map - LLSD agents = data["agents"]; - - LLUUID agent_id; - LLAvatarName av_name; - LLSD::map_const_iterator it = agents.beginMap(); - for ( ; it != agents.endMap(); ++it) - { - agent_id.set(it->first); - av_name.fromLLSD( it->second ); - mCache[agent_id] = av_name; - } + return false; + } + + // by convention LLSD storage is a map + // we only store one entry in the map + LLSD agents = data["agents"]; + + LLUUID agent_id; + LLAvatarName av_name; + LLSD::map_const_iterator it = agents.beginMap(); + for ( ; it != agents.endMap(); ++it) + { + agent_id.set(it->first); + av_name.fromLLSD( it->second ); + mCache[agent_id] = av_name; + } LL_INFOS("AvNameCache") << "LLAvatarNameCache loaded " << mCache.size() << LL_ENDL; - // Some entries may have expired since the cache was stored, + // Some entries may have expired since the cache was stored, // but they will be flushed in the first call to eraseUnrefreshed // from LLAvatarNameResponder::idle @@ -487,35 +487,35 @@ bool LLAvatarNameCache::importFile(std::istream& istr) void LLAvatarNameCache::exportFile(std::ostream& ostr) { - LLSD agents; - F64 max_unrefreshed = LLFrameTimer::getTotalSeconds() - MAX_UNREFRESHED_TIME; + LLSD agents; + F64 max_unrefreshed = LLFrameTimer::getTotalSeconds() - MAX_UNREFRESHED_TIME; LL_INFOS("AvNameCache") << "LLAvatarNameCache at exit cache has " << mCache.size() << LL_ENDL; - cache_t::const_iterator it = mCache.begin(); - for ( ; it != mCache.end(); ++it) - { - const LLUUID& agent_id = it->first; - const LLAvatarName& av_name = it->second; - // Do not write temporary or expired entries to the stored cache - if (av_name.isValidName(max_unrefreshed)) - { - // key must be a string - agents[agent_id.asString()] = av_name.asLLSD(); - } - } + cache_t::const_iterator it = mCache.begin(); + for ( ; it != mCache.end(); ++it) + { + const LLUUID& agent_id = it->first; + const LLAvatarName& av_name = it->second; + // Do not write temporary or expired entries to the stored cache + if (av_name.isValidName(max_unrefreshed)) + { + // key must be a string + agents[agent_id.asString()] = av_name.asLLSD(); + } + } LL_INFOS("AvNameCache") << "LLAvatarNameCache returning " << agents.size() << LL_ENDL; - LLSD data; - data["agents"] = agents; - LLSDSerialize::toPrettyXML(data, ostr); + LLSD data; + data["agents"] = agents; + LLSDSerialize::toPrettyXML(data, ostr); } void LLAvatarNameCache::setNameLookupURL(const std::string& name_lookup_url) { - mNameLookupURL = name_lookup_url; + mNameLookupURL = name_lookup_url; } bool LLAvatarNameCache::hasNameLookupURL() { - return !mNameLookupURL.empty(); + return !mNameLookupURL.empty(); } void LLAvatarNameCache::setUsePeopleAPI(bool use_api) @@ -525,25 +525,25 @@ void LLAvatarNameCache::setUsePeopleAPI(bool use_api) bool LLAvatarNameCache::usePeopleAPI() { - return hasNameLookupURL() && mUsePeopleAPI; + return hasNameLookupURL() && mUsePeopleAPI; } void LLAvatarNameCache::idle() { - // By convention, start running at first idle() call - mRunning = true; + // By convention, start running at first idle() call + mRunning = true; - // *TODO: Possibly re-enabled this based on People API load measurements - // 100 ms is the threshold for "user speed" operations, so we can - // stall for about that long to batch up requests. - const F32 SECS_BETWEEN_REQUESTS = 0.1f; - if (!sRequestTimer.hasExpired()) - { - return; - } + // *TODO: Possibly re-enabled this based on People API load measurements + // 100 ms is the threshold for "user speed" operations, so we can + // stall for about that long to batch up requests. + const F32 SECS_BETWEEN_REQUESTS = 0.1f; + if (!sRequestTimer.hasExpired()) + { + return; + } - if (!mAskQueue.empty()) - { + if (!mAskQueue.empty()) + { if (usePeopleAPI()) { requestNamesViaCapability(); @@ -553,13 +553,13 @@ void LLAvatarNameCache::idle() LL_WARNS_ONCE("AvNameCache") << "LLAvatarNameCache still using legacy api" << LL_ENDL; requestNamesViaLegacy(); } - } + } - if (mAskQueue.empty()) - { - // cleared the list, reset the request timer. - sRequestTimer.resetWithExpiry(SECS_BETWEEN_REQUESTS); - } + if (mAskQueue.empty()) + { + // cleared the list, reset the request timer. + sRequestTimer.resetWithExpiry(SECS_BETWEEN_REQUESTS); + } // erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME eraseUnrefreshed(); @@ -567,23 +567,23 @@ void LLAvatarNameCache::idle() bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id) { - bool isPending = false; - const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; + bool isPending = false; + const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; - pending_queue_t::const_iterator it = mPendingQueue.find(agent_id); - if (it != mPendingQueue.end()) - { - // in the list of requests in flight, retry if too old - F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; - isPending = (it->second > expire_time); - } - return isPending; + pending_queue_t::const_iterator it = mPendingQueue.find(agent_id); + if (it != mPendingQueue.end()) + { + // in the list of requests in flight, retry if too old + F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; + isPending = (it->second > expire_time); + } + return isPending; } void LLAvatarNameCache::eraseUnrefreshed() { - F64 now = LLFrameTimer::getTotalSeconds(); - F64 max_unrefreshed = now - MAX_UNREFRESHED_TIME; + F64 now = LLFrameTimer::getTotalSeconds(); + F64 max_unrefreshed = now - MAX_UNREFRESHED_TIME; if (!mLastExpireCheck || mLastExpireCheck < max_unrefreshed) { @@ -594,21 +594,21 @@ void LLAvatarNameCache::eraseUnrefreshed() const LLAvatarName& av_name = it->second; if (av_name.mExpires < max_unrefreshed) { - LL_DEBUGS("AvNameCacheExpired") << "LLAvatarNameCache " << it->first + LL_DEBUGS("AvNameCacheExpired") << "LLAvatarNameCache " << it->first << " user '" << av_name.getAccountName() << "' " << "expired " << now - av_name.mExpires << " secs ago" << LL_ENDL; mCache.erase(it++); expired++; } - else - { - ++it; - } + else + { + ++it; + } } LL_INFOS("AvNameCache") << "LLAvatarNameCache expired " << expired << " cached avatar names, " << mCache.size() << " remaining" << LL_ENDL; - } + } } //static, wrapper @@ -620,45 +620,45 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) // returns bool specifying if av_name was filled, false otherwise bool LLAvatarNameCache::getName(const LLUUID& agent_id, LLAvatarName *av_name) { - if (mRunning) - { - // ...only do immediate lookups when cache is running - std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id); - if (it != mCache.end()) - { - *av_name = it->second; - - // re-request name if entry is expired - if (av_name->mExpires < LLFrameTimer::getTotalSeconds()) - { - if (!isRequestPending(agent_id)) - { - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache refresh agent " << agent_id - << LL_ENDL; - mAskQueue.insert(agent_id); - } - } - - return true; - } - } - - if (!isRequestPending(agent_id)) - { - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache queue request for agent " << agent_id << LL_ENDL; - mAskQueue.insert(agent_id); - } - - return false; + if (mRunning) + { + // ...only do immediate lookups when cache is running + std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id); + if (it != mCache.end()) + { + *av_name = it->second; + + // re-request name if entry is expired + if (av_name->mExpires < LLFrameTimer::getTotalSeconds()) + { + if (!isRequestPending(agent_id)) + { + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache refresh agent " << agent_id + << LL_ENDL; + mAskQueue.insert(agent_id); + } + } + + return true; + } + } + + if (!isRequestPending(agent_id)) + { + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache queue request for agent " << agent_id << LL_ENDL; + mAskQueue.insert(agent_id); + } + + return false; } void LLAvatarNameCache::fireSignal(const LLUUID& agent_id, - const callback_slot_t& slot, - const LLAvatarName& av_name) + const callback_slot_t& slot, + const LLAvatarName& av_name) { - callback_signal_t signal; - signal.connect(slot); - signal(agent_id, av_name); + callback_signal_t signal; + signal.connect(slot); + signal(agent_id, av_name); } // static, wrapper @@ -669,78 +669,78 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag LLAvatarNameCache::callback_connection_t LLAvatarNameCache::getNameCallback(const LLUUID& agent_id, callback_slot_t slot) { - callback_connection_t connection; - - if (mRunning) - { - // ...only do immediate lookups when cache is running - std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id); - if (it != mCache.end()) - { - const LLAvatarName& av_name = it->second; - - if (av_name.mExpires > LLFrameTimer::getTotalSeconds()) - { - // ...name already exists in cache, fire callback now - fireSignal(agent_id, slot, av_name); - return connection; - } - } - } - - // schedule a request - if (!isRequestPending(agent_id)) - { - mAskQueue.insert(agent_id); - } - - // always store additional callback, even if request is pending - signal_map_t::iterator sig_it = mSignalMap.find(agent_id); - if (sig_it == mSignalMap.end()) - { - // ...new callback for this id - callback_signal_t* signal = new callback_signal_t(); - connection = signal->connect(slot); - mSignalMap[agent_id] = signal; - } - else - { - // ...existing callback, bind additional slot - callback_signal_t* signal = sig_it->second; - connection = signal->connect(slot); - } - - return connection; + callback_connection_t connection; + + if (mRunning) + { + // ...only do immediate lookups when cache is running + std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id); + if (it != mCache.end()) + { + const LLAvatarName& av_name = it->second; + + if (av_name.mExpires > LLFrameTimer::getTotalSeconds()) + { + // ...name already exists in cache, fire callback now + fireSignal(agent_id, slot, av_name); + return connection; + } + } + } + + // schedule a request + if (!isRequestPending(agent_id)) + { + mAskQueue.insert(agent_id); + } + + // always store additional callback, even if request is pending + signal_map_t::iterator sig_it = mSignalMap.find(agent_id); + if (sig_it == mSignalMap.end()) + { + // ...new callback for this id + callback_signal_t* signal = new callback_signal_t(); + connection = signal->connect(slot); + mSignalMap[agent_id] = signal; + } + else + { + // ...existing callback, bind additional slot + callback_signal_t* signal = sig_it->second; + connection = signal->connect(slot); + } + + return connection; } void LLAvatarNameCache::setUseDisplayNames(bool use) { - if (use != LLAvatarName::useDisplayNames()) - { - LLAvatarName::setUseDisplayNames(use); - mUseDisplayNamesSignal(); - } + if (use != LLAvatarName::useDisplayNames()) + { + LLAvatarName::setUseDisplayNames(use); + mUseDisplayNamesSignal(); + } } void LLAvatarNameCache::setUseUsernames(bool use) { - if (use != LLAvatarName::useUsernames()) - { - LLAvatarName::setUseUsernames(use); - mUseDisplayNamesSignal(); - } + if (use != LLAvatarName::useUsernames()) + { + LLAvatarName::setUseUsernames(use); + mUseDisplayNamesSignal(); + } } void LLAvatarNameCache::erase(const LLUUID& agent_id) { - mCache.erase(agent_id); + mCache.erase(agent_id); } void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name) { - // *TODO: update timestamp if zero? - mCache[agent_id] = av_name; + // *TODO: update timestamp if zero? + mCache[agent_id] = av_name; } LLUUID LLAvatarNameCache::findIdByName(const std::string& name) @@ -789,7 +789,7 @@ bool LLAvatarNameCache::expirationFromCacheControl(LLCore::HttpHeaders *headers, // Allow the header to override the default const std::string *cache_control; - + cache_control = headers->find(HTTP_IN_HEADER_CACHE_CONTROL); if (cache_control && !cache_control->empty()) @@ -811,53 +811,53 @@ bool LLAvatarNameCache::expirationFromCacheControl(LLCore::HttpHeaders *headers, #else F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers) { - F64 expires = 0.0; - if (expirationFromCacheControl(headers, &expires)) - { - return expires; - } - else - { - // With no expiration info, default to an hour - const F64 DEFAULT_EXPIRES = 60.0 * 60.0; - F64 now = LLFrameTimer::getTotalSeconds(); - return now + DEFAULT_EXPIRES; - } + F64 expires = 0.0; + if (expirationFromCacheControl(headers, &expires)) + { + return expires; + } + else + { + // With no expiration info, default to an hour + const F64 DEFAULT_EXPIRES = 60.0 * 60.0; + F64 now = LLFrameTimer::getTotalSeconds(); + return now + DEFAULT_EXPIRES; + } } bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *expires) { - bool fromCacheControl = false; - F64 now = LLFrameTimer::getTotalSeconds(); - - // Allow the header to override the default - std::string cache_control; - if (headers.has(HTTP_IN_HEADER_CACHE_CONTROL)) - { - cache_control = headers[HTTP_IN_HEADER_CACHE_CONTROL].asString(); - } - - if (!cache_control.empty()) - { - S32 max_age = 0; - if (max_age_from_cache_control(cache_control, &max_age)) - { - *expires = now + (F64)max_age; - fromCacheControl = true; - } - } - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache " - << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) - << "in " << *expires - now << " seconds" - << LL_ENDL; - - return fromCacheControl; + bool fromCacheControl = false; + F64 now = LLFrameTimer::getTotalSeconds(); + + // Allow the header to override the default + std::string cache_control; + if (headers.has(HTTP_IN_HEADER_CACHE_CONTROL)) + { + cache_control = headers[HTTP_IN_HEADER_CACHE_CONTROL].asString(); + } + + if (!cache_control.empty()) + { + S32 max_age = 0; + if (max_age_from_cache_control(cache_control, &max_age)) + { + *expires = now + (F64)max_age; + fromCacheControl = true; + } + } + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache " + << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) + << "in " << *expires - now << " seconds" + << LL_ENDL; + + return fromCacheControl; } #endif -void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb) -{ - mUseDisplayNamesSignal.connect(cb); +void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb) +{ + mUseDisplayNamesSignal.connect(cb); } @@ -867,55 +867,55 @@ static const boost::char_separator<char> COMMA_SEPARATOR(","); bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age) { - // Split the string on "," to get a list of directives - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - tokenizer directives(cache_control, COMMA_SEPARATOR); - - tokenizer::iterator token_it = directives.begin(); - for ( ; token_it != directives.end(); ++token_it) - { - // Tokens may have leading or trailing whitespace - std::string token = *token_it; - LLStringUtil::trim(token); - - if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) - { - // ...this token starts with max-age, so let's chop it up by "=" - tokenizer subtokens(token, EQUALS_SEPARATOR); - tokenizer::iterator subtoken_it = subtokens.begin(); - - // Must have a token - if (subtoken_it == subtokens.end()) return false; - std::string subtoken = *subtoken_it; - - // Must exactly equal "max-age" - LLStringUtil::trim(subtoken); - if (subtoken != MAX_AGE) return false; - - // Must have another token - ++subtoken_it; - if (subtoken_it == subtokens.end()) return false; - subtoken = *subtoken_it; - - // Must be a valid integer - // *NOTE: atoi() returns 0 for invalid values, so we have to - // check the string first. - // *TODO: Do servers ever send "0000" for zero? We don't handle it - LLStringUtil::trim(subtoken); - if (subtoken == "0") - { - *max_age = 0; - return true; - } - S32 val = atoi( subtoken.c_str() ); - if (val > 0 && val < S32_MAX) - { - *max_age = val; - return true; - } - return false; - } - } - return false; + // Split the string on "," to get a list of directives + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + tokenizer directives(cache_control, COMMA_SEPARATOR); + + tokenizer::iterator token_it = directives.begin(); + for ( ; token_it != directives.end(); ++token_it) + { + // Tokens may have leading or trailing whitespace + std::string token = *token_it; + LLStringUtil::trim(token); + + if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) + { + // ...this token starts with max-age, so let's chop it up by "=" + tokenizer subtokens(token, EQUALS_SEPARATOR); + tokenizer::iterator subtoken_it = subtokens.begin(); + + // Must have a token + if (subtoken_it == subtokens.end()) return false; + std::string subtoken = *subtoken_it; + + // Must exactly equal "max-age" + LLStringUtil::trim(subtoken); + if (subtoken != MAX_AGE) return false; + + // Must have another token + ++subtoken_it; + if (subtoken_it == subtokens.end()) return false; + subtoken = *subtoken_it; + + // Must be a valid integer + // *NOTE: atoi() returns 0 for invalid values, so we have to + // check the string first. + // *TODO: Do servers ever send "0000" for zero? We don't handle it + LLStringUtil::trim(subtoken); + if (subtoken == "0") + { + *max_age = 0; + return true; + } + S32 val = atoi( subtoken.c_str() ); + if (val > 0 && val < S32_MAX) + { + *max_age = val; + return true; + } + return false; + } + } + return false; } diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 549d1703fa..fe51355207 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -1,4 +1,4 @@ -/** +/** * @file llavatarnamecache.h * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names * ("James Cook") from avatar UUIDs. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,7 +28,7 @@ #ifndef LLAVATARNAMECACHE_H #define LLAVATARNAMECACHE_H -#include "llavatarname.h" // for convenience +#include "llavatarname.h" // for convenience #include "llsingleton.h" #include <boost/signals2.hpp> #include <set> @@ -38,71 +38,71 @@ class LLUUID; class LLAvatarNameCache : public LLSingleton<LLAvatarNameCache> { - LLSINGLETON(LLAvatarNameCache); - ~LLAvatarNameCache(); + LLSINGLETON(LLAvatarNameCache); + ~LLAvatarNameCache(); public: - typedef boost::signals2::signal<void (void)> use_display_name_signal_t; - typedef boost::function<void (const LLUUID id, const LLAvatarName& av_name)> account_name_changed_callback_t; - - // Import/export the name cache to file. - bool importFile(std::istream& istr); - void exportFile(std::ostream& ostr); - - // On the viewer, usually a simulator capabilities. - // If empty, name cache will fall back to using legacy name lookup system. - void setNameLookupURL(const std::string& name_lookup_url); - - // Do we have a valid lookup URL, i.e. are we trying to use the - // more recent display name lookup system? - bool hasNameLookupURL(); - void setUsePeopleAPI(bool use_api); - bool usePeopleAPI(); - - // Periodically makes a batch request for display names not already in - // cache. Called once per frame. - void idle(); - - // If name is in cache, returns true and fills in provided LLAvatarName - // otherwise returns false. - static bool get(const LLUUID& agent_id, LLAvatarName *av_name); - bool getName(const LLUUID& agent_id, LLAvatarName *av_name); - - // Callback types for get() below - typedef boost::signals2::signal< - void (const LLUUID& agent_id, const LLAvatarName& av_name)> - callback_signal_t; - typedef callback_signal_t::slot_type callback_slot_t; - typedef boost::signals2::connection callback_connection_t; - - // Fetches name information and calls callbacks. - // If name information is in cache, callbacks will be called immediately. - static callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot); - callback_connection_t getNameCallback(const LLUUID& agent_id, callback_slot_t slot); - - // Set display name: flips the switch and triggers the callbacks. - void setUseDisplayNames(bool use); - - void setUseUsernames(bool use); - - void insert(const LLUUID& agent_id, const LLAvatarName& av_name); - void erase(const LLUUID& agent_id); - - // A way to find agent id by UUID, very slow, also unreliable - // since it doesn't request names, just serch exsisting ones - // that are likely not in cache. - // - // Todo: Find a way to remove this. - // Curently this method is used for chat history and in some cases notices. - LLUUID findIdByName(const std::string& name); - - /// Provide some fallback for agents that return errors. - void handleAgentError(const LLUUID& agent_id); - - // Compute name expiration time from HTTP Cache-Control header, - // or return default value, in seconds from epoch. + typedef boost::signals2::signal<void (void)> use_display_name_signal_t; + typedef boost::function<void (const LLUUID id, const LLAvatarName& av_name)> account_name_changed_callback_t; + + // Import/export the name cache to file. + bool importFile(std::istream& istr); + void exportFile(std::ostream& ostr); + + // On the viewer, usually a simulator capabilities. + // If empty, name cache will fall back to using legacy name lookup system. + void setNameLookupURL(const std::string& name_lookup_url); + + // Do we have a valid lookup URL, i.e. are we trying to use the + // more recent display name lookup system? + bool hasNameLookupURL(); + void setUsePeopleAPI(bool use_api); + bool usePeopleAPI(); + + // Periodically makes a batch request for display names not already in + // cache. Called once per frame. + void idle(); + + // If name is in cache, returns true and fills in provided LLAvatarName + // otherwise returns false. + static bool get(const LLUUID& agent_id, LLAvatarName *av_name); + bool getName(const LLUUID& agent_id, LLAvatarName *av_name); + + // Callback types for get() below + typedef boost::signals2::signal< + void (const LLUUID& agent_id, const LLAvatarName& av_name)> + callback_signal_t; + typedef callback_signal_t::slot_type callback_slot_t; + typedef boost::signals2::connection callback_connection_t; + + // Fetches name information and calls callbacks. + // If name information is in cache, callbacks will be called immediately. + static callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot); + callback_connection_t getNameCallback(const LLUUID& agent_id, callback_slot_t slot); + + // Set display name: flips the switch and triggers the callbacks. + void setUseDisplayNames(bool use); + + void setUseUsernames(bool use); + + void insert(const LLUUID& agent_id, const LLAvatarName& av_name); + void erase(const LLUUID& agent_id); + + // A way to find agent id by UUID, very slow, also unreliable + // since it doesn't request names, just serch exsisting ones + // that are likely not in cache. + // + // Todo: Find a way to remove this. + // Curently this method is used for chat history and in some cases notices. + LLUUID findIdByName(const std::string& name); + + /// Provide some fallback for agents that return errors. + void handleAgentError(const LLUUID& agent_id); + + // Compute name expiration time from HTTP Cache-Control header, + // or return default value, in seconds from epoch. F64 nameExpirationFromHeaders(const LLSD& headers); - void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); + void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); void setAccountNameChangedCallback(const account_name_changed_callback_t& cb) { mAccountNameChangedCallback = cb; } diff --git a/indra/llmessage/llblowfishcipher.cpp b/indra/llmessage/llblowfishcipher.cpp index 949d4cc0c7..ed036e396d 100644 --- a/indra/llmessage/llblowfishcipher.cpp +++ b/indra/llmessage/llblowfishcipher.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llblowfishcipher.cpp * @brief Wrapper around OpenSSL Blowfish encryption algorithm. * * $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$ */ @@ -30,28 +30,28 @@ LLBlowfishCipher::LLBlowfishCipher(const U8* secret, size_t secret_size) -: LLCipher() +: LLCipher() { - llassert(secret); + llassert(secret); - mSecretSize = secret_size; - mSecret = new U8[mSecretSize]; - memcpy(mSecret, secret, mSecretSize); + mSecretSize = secret_size; + mSecret = new U8[mSecretSize]; + memcpy(mSecret, secret, mSecretSize); } LLBlowfishCipher::~LLBlowfishCipher() { - delete [] mSecret; - mSecret = NULL; + delete [] mSecret; + mSecret = NULL; } // virtual U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) { - if (!src || !src_len || !dst || !dst_len) return 0; - if (src_len > dst_len) return 0; + if (!src || !src_len || !dst || !dst_len) return 0; + if (src_len > dst_len) return 0; - // OpenSSL uses "cipher contexts" to hold encryption parameters. + // OpenSSL uses "cipher contexts" to hold encryption parameters. EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new(); if (!context) { @@ -59,71 +59,71 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) return 0; } - // We want a blowfish cyclic block chain cipher, but need to set - // the key length before we pass in a key, so call EncryptInit - // first with NULLs. - EVP_EncryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize); - - // Complete initialization. Per EVP_EncryptInit man page, the - // cipher pointer must be NULL. Apparently initial_vector must - // be 8 bytes for blowfish, as this is the block size. + // We want a blowfish cyclic block chain cipher, but need to set + // the key length before we pass in a key, so call EncryptInit + // first with NULLs. + EVP_EncryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize); + + // Complete initialization. Per EVP_EncryptInit man page, the + // cipher pointer must be NULL. Apparently initial_vector must + // be 8 bytes for blowfish, as this is the block size. unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - EVP_EncryptInit_ex(context, NULL, NULL, mSecret, initial_vector); + EVP_EncryptInit_ex(context, NULL, NULL, mSecret, initial_vector); int blocksize = EVP_CIPHER_CTX_block_size(context); int keylen = EVP_CIPHER_CTX_key_length(context); int iv_length = EVP_CIPHER_CTX_iv_length(context); LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize - << " keylen " << keylen - << " iv_len " << iv_length - << LL_ENDL; - - int output_len = 0; - int temp_len = 0; - if (!EVP_EncryptUpdate(context, - dst, - &output_len, - src, - src_len)) - { - LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptUpdate failure" << LL_ENDL; - goto ERROR; - } - - // There may be some final data left to encrypt if the input is - // not an exact multiple of the block size. - if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len)) - { - LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL; - goto ERROR; - } - output_len += temp_len; - - EVP_CIPHER_CTX_free(context); - return output_len; + << " keylen " << keylen + << " iv_len " << iv_length + << LL_ENDL; + + int output_len = 0; + int temp_len = 0; + if (!EVP_EncryptUpdate(context, + dst, + &output_len, + src, + src_len)) + { + LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptUpdate failure" << LL_ENDL; + goto ERROR; + } + + // There may be some final data left to encrypt if the input is + // not an exact multiple of the block size. + if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len)) + { + LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL; + goto ERROR; + } + output_len += temp_len; + + EVP_CIPHER_CTX_free(context); + return output_len; ERROR: - EVP_CIPHER_CTX_free(context); - return 0; + EVP_CIPHER_CTX_free(context); + return 0; } // virtual U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) { - LL_ERRS() << "LLBlowfishCipher decrypt unsupported" << LL_ENDL; - return 0; + LL_ERRS() << "LLBlowfishCipher decrypt unsupported" << LL_ENDL; + return 0; } // virtual U32 LLBlowfishCipher::requiredEncryptionSpace(U32 len) const { - // *HACK: We know blowfish uses an 8 byte block size. - // Oddly, sometimes EVP_Encrypt produces an extra block - // if the input is an exact multiple of the block size. - // So round up. - const U32 BLOCK_SIZE = 8; - len += BLOCK_SIZE; - len -= (len % BLOCK_SIZE); - return len; + // *HACK: We know blowfish uses an 8 byte block size. + // Oddly, sometimes EVP_Encrypt produces an extra block + // if the input is an exact multiple of the block size. + // So round up. + const U32 BLOCK_SIZE = 8; + len += BLOCK_SIZE; + len -= (len % BLOCK_SIZE); + return len; } diff --git a/indra/llmessage/llblowfishcipher.h b/indra/llmessage/llblowfishcipher.h index 65228df11f..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/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index cfe38605ad..dc7115b167 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llbuffer.cpp * @author Phoenix * @date 2005-09-20 @@ -7,21 +7,21 @@ * $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$ */ @@ -37,20 +37,20 @@ #define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED() llassert(!mMutexp || mMutexp->isSelfLocked()) -/** +/** * LLSegment */ LLSegment::LLSegment() : - mChannel(0), - mData(NULL), - mSize(0) + mChannel(0), + mData(NULL), + mSize(0) { } LLSegment::LLSegment(S32 channel, U8* data, S32 data_len) : - mChannel(channel), - mData(data), - mSize(data_len) + mChannel(channel), + mData(data), + mSize(data_len) { } @@ -60,849 +60,849 @@ LLSegment::~LLSegment() bool LLSegment::isOnChannel(S32 channel) const { - return (mChannel == channel); + return (mChannel == channel); } S32 LLSegment::getChannel() const { - return mChannel; + return mChannel; } void LLSegment::setChannel(S32 channel) { - mChannel = channel; + mChannel = channel; } U8* LLSegment::data() const { - return mData; + return mData; } S32 LLSegment::size() const { - return mSize; + return mSize; } bool LLSegment::operator==(const LLSegment& rhs) const { - if((mData != rhs.mData)||(mSize != rhs.mSize)||(mChannel != rhs.mChannel)) - { - return false; - } - return true; + if((mData != rhs.mData)||(mSize != rhs.mSize)||(mChannel != rhs.mChannel)) + { + return false; + } + return true; } -/** +/** * LLHeapBuffer */ LLHeapBuffer::LLHeapBuffer() : - mBuffer(NULL), - mSize(0), - mNextFree(NULL), - mReclaimedBytes(0) + mBuffer(NULL), + mSize(0), + mNextFree(NULL), + mReclaimedBytes(0) { - const S32 DEFAULT_HEAP_BUFFER_SIZE = 16384; - allocate(DEFAULT_HEAP_BUFFER_SIZE); + const S32 DEFAULT_HEAP_BUFFER_SIZE = 16384; + allocate(DEFAULT_HEAP_BUFFER_SIZE); } LLHeapBuffer::LLHeapBuffer(S32 size) : - mBuffer(NULL), - mSize(0), - mNextFree(NULL), - mReclaimedBytes(0) + mBuffer(NULL), + mSize(0), + mNextFree(NULL), + mReclaimedBytes(0) { - allocate(size); + allocate(size); } LLHeapBuffer::LLHeapBuffer(const U8* src, S32 len) : - mBuffer(NULL), - mSize(0), - mNextFree(NULL), - mReclaimedBytes(0) + mBuffer(NULL), + mSize(0), + mNextFree(NULL), + mReclaimedBytes(0) { - if((len > 0) && src) - { - allocate(len); - if(mBuffer) - { - memcpy(mBuffer, src, len); /*Flawfinder: ignore*/ - } - } + if((len > 0) && src) + { + allocate(len); + if(mBuffer) + { + memcpy(mBuffer, src, len); /*Flawfinder: ignore*/ + } + } } // virtual LLHeapBuffer::~LLHeapBuffer() { - delete[] mBuffer; - mBuffer = NULL; - mSize = 0; - mNextFree = NULL; + delete[] mBuffer; + mBuffer = NULL; + mSize = 0; + mNextFree = NULL; } S32 LLHeapBuffer::bytesLeft() const { - return (mSize - (mNextFree - mBuffer)); + return (mSize - (mNextFree - mBuffer)); } // virtual bool LLHeapBuffer::createSegment( - S32 channel, - S32 size, - LLSegment& segment) + S32 channel, + S32 size, + LLSegment& segment) { - // get actual size of the segment. - S32 actual_size = llmin(size, (mSize - S32(mNextFree - mBuffer))); + // get actual size of the segment. + S32 actual_size = llmin(size, (mSize - S32(mNextFree - mBuffer))); - // bail if we cannot build a valid segment - if(actual_size <= 0) - { - return false; - } + // bail if we cannot build a valid segment + if(actual_size <= 0) + { + return false; + } - // Yay, we're done. - segment = LLSegment(channel, mNextFree, actual_size); - mNextFree += actual_size; - return true; + // Yay, we're done. + segment = LLSegment(channel, mNextFree, actual_size); + mNextFree += actual_size; + return true; } // virtual bool LLHeapBuffer::reclaimSegment(const LLSegment& segment) { - if(containsSegment(segment)) - { - mReclaimedBytes += segment.size(); - if(mReclaimedBytes == mSize) - { - // We have reclaimed all of the memory from this - // buffer. Therefore, we can reset the mNextFree to the - // start of the buffer, and reset the reclaimed bytes. - mReclaimedBytes = 0; - mNextFree = mBuffer; - } - else if(mReclaimedBytes > mSize) - { - LL_WARNS() << "LLHeapBuffer reclaimed more memory than allocated." - << " This is probably programmer error." << LL_ENDL; - } - return true; - } - return false; + if(containsSegment(segment)) + { + mReclaimedBytes += segment.size(); + if(mReclaimedBytes == mSize) + { + // We have reclaimed all of the memory from this + // buffer. Therefore, we can reset the mNextFree to the + // start of the buffer, and reset the reclaimed bytes. + mReclaimedBytes = 0; + mNextFree = mBuffer; + } + else if(mReclaimedBytes > mSize) + { + LL_WARNS() << "LLHeapBuffer reclaimed more memory than allocated." + << " This is probably programmer error." << LL_ENDL; + } + return true; + } + return false; } // virtual bool LLHeapBuffer::containsSegment(const LLSegment& segment) const { - // *NOTE: this check is fairly simple because heap buffers are - // simple contiguous chunks of heap memory. - if((mBuffer > segment.data()) - || ((mBuffer + mSize) < (segment.data() + segment.size()))) - { - return false; - } - return true; + // *NOTE: this check is fairly simple because heap buffers are + // simple contiguous chunks of heap memory. + if((mBuffer > segment.data()) + || ((mBuffer + mSize) < (segment.data() + segment.size()))) + { + return false; + } + return true; } void LLHeapBuffer::allocate(S32 size) { - mReclaimedBytes = 0; - mBuffer = new U8[size]; - if(mBuffer) - { - mSize = size; - mNextFree = mBuffer; - } + mReclaimedBytes = 0; + mBuffer = new U8[size]; + if(mBuffer) + { + mSize = size; + mNextFree = mBuffer; + } } -/** +/** * LLBufferArray */ LLBufferArray::LLBufferArray() : - mNextBaseChannel(0), - mMutexp(NULL) + mNextBaseChannel(0), + mMutexp(NULL) { } LLBufferArray::~LLBufferArray() { - std::for_each(mBuffers.begin(), mBuffers.end(), DeletePointer()); - mBuffers.clear(); - delete mMutexp; + std::for_each(mBuffers.begin(), mBuffers.end(), DeletePointer()); + mBuffers.clear(); + delete mMutexp; } // static LLChannelDescriptors LLBufferArray::makeChannelConsumer( - const LLChannelDescriptors& channels) + const LLChannelDescriptors& channels) { - LLChannelDescriptors rv(channels.out()); - return rv; + LLChannelDescriptors rv(channels.out()); + return rv; } void LLBufferArray::lock() { - if(mMutexp) - { - mMutexp->lock() ; - } + if(mMutexp) + { + mMutexp->lock() ; + } } void LLBufferArray::unlock() { - if(mMutexp) - { - mMutexp->unlock() ; - } + if(mMutexp) + { + mMutexp->unlock() ; + } } LLMutex* LLBufferArray::getMutex() { - return mMutexp ; + return mMutexp ; } void LLBufferArray::setThreaded(bool threaded) { - if(threaded) - { - if(!mMutexp) - { - mMutexp = new LLMutex(); - } - } - else - { - if(mMutexp) - { - delete mMutexp ; - mMutexp = NULL ; - } - } + if(threaded) + { + if(!mMutexp) + { + mMutexp = new LLMutex(); + } + } + else + { + if(mMutexp) + { + delete mMutexp ; + mMutexp = NULL ; + } + } } LLChannelDescriptors LLBufferArray::nextChannel() { - LLChannelDescriptors rv(mNextBaseChannel++); - return rv; + LLChannelDescriptors rv(mNextBaseChannel++); + return rv; } //mMutexp should be locked before calling this. S32 LLBufferArray::capacity() const { - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - S32 total = 0; - const_buffer_iterator_t iter = mBuffers.begin(); - const_buffer_iterator_t end = mBuffers.end(); - for(; iter != end; ++iter) - { - total += (*iter)->capacity(); - } - return total; + S32 total = 0; + const_buffer_iterator_t iter = mBuffers.begin(); + const_buffer_iterator_t end = mBuffers.end(); + for(; iter != end; ++iter) + { + total += (*iter)->capacity(); + } + return total; } bool LLBufferArray::append(S32 channel, const U8* src, S32 len) { - LLMutexLock lock(mMutexp) ; + LLMutexLock lock(mMutexp) ; - std::vector<LLSegment> segments; - if(copyIntoBuffers(channel, src, len, segments)) - { - mSegments.insert(mSegments.end(), segments.begin(), segments.end()); - return true; - } - return false; + std::vector<LLSegment> segments; + if(copyIntoBuffers(channel, src, len, segments)) + { + mSegments.insert(mSegments.end(), segments.begin(), segments.end()); + return true; + } + return false; } //mMutexp should be locked before calling this. bool LLBufferArray::prepend(S32 channel, const U8* src, S32 len) { - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - std::vector<LLSegment> segments; - if(copyIntoBuffers(channel, src, len, segments)) - { - mSegments.insert(mSegments.begin(), segments.begin(), segments.end()); - return true; - } - return false; + std::vector<LLSegment> segments; + if(copyIntoBuffers(channel, src, len, segments)) + { + mSegments.insert(mSegments.begin(), segments.begin(), segments.end()); + return true; + } + return false; } bool LLBufferArray::insertAfter( - segment_iterator_t segment, - S32 channel, - const U8* src, - S32 len) -{ - std::vector<LLSegment> segments; - - LLMutexLock lock(mMutexp) ; - if(mSegments.end() != segment) - { - ++segment; - } - if(copyIntoBuffers(channel, src, len, segments)) - { - mSegments.insert(segment, segments.begin(), segments.end()); - return true; - } - return false; + segment_iterator_t segment, + S32 channel, + const U8* src, + S32 len) +{ + std::vector<LLSegment> segments; + + LLMutexLock lock(mMutexp) ; + if(mSegments.end() != segment) + { + ++segment; + } + if(copyIntoBuffers(channel, src, len, segments)) + { + mSegments.insert(segment, segments.begin(), segments.end()); + return true; + } + return false; } //mMutexp should be locked before calling this. LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address) { - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - - segment_iterator_t end = mSegments.end(); - segment_iterator_t it = getSegment(address); - if(it == end) - { - return end; - } - - // We have the location and the segment. - U8* base = (*it).data(); - S32 size = (*it).size(); - if(address == (base + size)) - { - // No need to split, since this is the last byte of the - // segment. We do not want to have zero length segments, since - // that will only incur processing overhead with no advantage. - return it; - } - S32 channel = (*it).getChannel(); - LLSegment segment1(channel, base, (address - base) + 1); - *it = segment1; - segment_iterator_t rv = it; - ++it; - LLSegment segment2(channel, address + 1, size - (address - base) - 1); - mSegments.insert(it, segment2); - return rv; -} - + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + + segment_iterator_t end = mSegments.end(); + segment_iterator_t it = getSegment(address); + if(it == end) + { + return end; + } + + // We have the location and the segment. + U8* base = (*it).data(); + S32 size = (*it).size(); + if(address == (base + size)) + { + // No need to split, since this is the last byte of the + // segment. We do not want to have zero length segments, since + // that will only incur processing overhead with no advantage. + return it; + } + S32 channel = (*it).getChannel(); + LLSegment segment1(channel, base, (address - base) + 1); + *it = segment1; + segment_iterator_t rv = it; + ++it; + LLSegment segment2(channel, address + 1, size - (address - base) - 1); + mSegments.insert(it, segment2); + return rv; +} + //mMutexp should be locked before calling this. LLBufferArray::segment_iterator_t LLBufferArray::beginSegment() { - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - return mSegments.begin(); + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + return mSegments.begin(); } //mMutexp should be locked before calling this. LLBufferArray::segment_iterator_t LLBufferArray::endSegment() { - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - return mSegments.end(); + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + return mSegments.end(); } //mMutexp should be locked before calling this. LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter( - U8* address, - LLSegment& segment) -{ - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - segment_iterator_t rv = mSegments.begin(); - segment_iterator_t end = mSegments.end(); - if(!address) - { - if(rv != end) - { - segment = (*rv); - } - } - else - { - // we have an address - find the segment it is in. - for( ; rv != end; ++rv) - { - if((address >= (*rv).data()) - && (address < ((*rv).data() + (*rv).size()))) - { - if((++address) < ((*rv).data() + (*rv).size())) - { - // it's in this segment - construct an appropriate - // sub-segment. - segment = LLSegment( - (*rv).getChannel(), - address, - (*rv).size() - (address - (*rv).data())); - } - else - { - ++rv; - if(rv != end) - { - segment = (*rv); - } - } - break; - } - } - } - if(rv == end) - { - segment = LLSegment(); - } - return rv; + U8* address, + LLSegment& segment) +{ + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + segment_iterator_t rv = mSegments.begin(); + segment_iterator_t end = mSegments.end(); + if(!address) + { + if(rv != end) + { + segment = (*rv); + } + } + else + { + // we have an address - find the segment it is in. + for( ; rv != end; ++rv) + { + if((address >= (*rv).data()) + && (address < ((*rv).data() + (*rv).size()))) + { + if((++address) < ((*rv).data() + (*rv).size())) + { + // it's in this segment - construct an appropriate + // sub-segment. + segment = LLSegment( + (*rv).getChannel(), + address, + (*rv).size() - (address - (*rv).data())); + } + else + { + ++rv; + if(rv != end) + { + segment = (*rv); + } + } + break; + } + } + } + if(rv == end) + { + segment = LLSegment(); + } + return rv; } //mMutexp should be locked before calling this. LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address) { - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - segment_iterator_t end = mSegments.end(); - if(!address) - { - return end; - } - segment_iterator_t it = mSegments.begin(); - for( ; it != end; ++it) - { - if((address >= (*it).data())&&(address < (*it).data() + (*it).size())) - { - // found it. - return it; - } - } - return end; + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + segment_iterator_t end = mSegments.end(); + if(!address) + { + return end; + } + segment_iterator_t it = mSegments.begin(); + for( ; it != end; ++it) + { + if((address >= (*it).data())&&(address < (*it).data() + (*it).size())) + { + // found it. + return it; + } + } + return end; } //mMutexp should be locked before calling this. LLBufferArray::const_segment_iterator_t LLBufferArray::getSegment( - U8* address) const -{ - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - const_segment_iterator_t end = mSegments.end(); - if(!address) - { - return end; - } - const_segment_iterator_t it = mSegments.begin(); - for( ; it != end; ++it) - { - if((address >= (*it).data()) - && (address < (*it).data() + (*it).size())) - { - // found it. - return it; - } - } - return end; + U8* address) const +{ + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + const_segment_iterator_t end = mSegments.end(); + if(!address) + { + return end; + } + const_segment_iterator_t it = mSegments.begin(); + for( ; it != end; ++it) + { + if((address >= (*it).data()) + && (address < (*it).data() + (*it).size())) + { + // found it. + return it; + } + } + return end; } /* -U8* LLBufferArray::getAddressAfter(U8* address) -{ - U8* rv = NULL; - segment_iterator_t it = getSegment(address); - segment_iterator_t end = mSegments.end(); - if(it != end) - { - if(++address < ((*it).data() + (*it).size())) - { - // it's in the same segment - rv = address; - } - else - { - // it's in the next segment - if(++it != end) - { - rv = (*it).data(); - } - } - } - return rv; +U8* LLBufferArray::getAddressAfter(U8* address) +{ + U8* rv = NULL; + segment_iterator_t it = getSegment(address); + segment_iterator_t end = mSegments.end(); + if(it != end) + { + if(++address < ((*it).data() + (*it).size())) + { + // it's in the same segment + rv = address; + } + else + { + // it's in the next segment + if(++it != end) + { + rv = (*it).data(); + } + } + } + return rv; } */ S32 LLBufferArray::countAfter(S32 channel, U8* start) const { - S32 count = 0; - S32 offset = 0; - const_segment_iterator_t it; - - LLMutexLock lock(mMutexp) ; - const_segment_iterator_t end = mSegments.end(); - if(start) - { - it = getSegment(start); - if(it == end) - { - return count; - } - if(++start < ((*it).data() + (*it).size())) - { - // it's in the same segment - offset = start - (*it).data(); - } - else if(++it == end) - { - // it's in the next segment - return count; - } - } - else - { - it = mSegments.begin(); - } - while(it != end) - { - if((*it).isOnChannel(channel)) - { - count += (*it).size() - offset; - } - offset = 0; - ++it; - } - return count; + S32 count = 0; + S32 offset = 0; + const_segment_iterator_t it; + + LLMutexLock lock(mMutexp) ; + const_segment_iterator_t end = mSegments.end(); + if(start) + { + it = getSegment(start); + if(it == end) + { + return count; + } + if(++start < ((*it).data() + (*it).size())) + { + // it's in the same segment + offset = start - (*it).data(); + } + else if(++it == end) + { + // it's in the next segment + return count; + } + } + else + { + it = mSegments.begin(); + } + while(it != end) + { + if((*it).isOnChannel(channel)) + { + count += (*it).size() - offset; + } + offset = 0; + ++it; + } + return count; } U8* LLBufferArray::readAfter( - S32 channel, - U8* start, - U8* dest, - S32& len) const -{ - U8* rv = start; - if(!dest || len <= 0) - { - return rv; - } - S32 bytes_left = len; - len = 0; - S32 bytes_to_copy = 0; - const_segment_iterator_t it; - - LLMutexLock lock(mMutexp) ; - const_segment_iterator_t end = mSegments.end(); - if(start) - { - it = getSegment(start); - if(it == end) - { - return rv; - } - if((++start < ((*it).data() + (*it).size())) - && (*it).isOnChannel(channel)) - { - // copy the data out of this segment - S32 bytes_in_segment = (*it).size() - (start - (*it).data()); - bytes_to_copy = llmin(bytes_left, bytes_in_segment); - memcpy(dest, start, bytes_to_copy); /*Flawfinder: ignore*/ - len += bytes_to_copy; - bytes_left -= bytes_to_copy; - rv = start + bytes_to_copy - 1; - ++it; - } - else - { - ++it; - } - } - else - { - it = mSegments.begin(); - } - while(bytes_left && (it != end)) - { - if(!((*it).isOnChannel(channel))) - { - ++it; - continue; - } - bytes_to_copy = llmin(bytes_left, (*it).size()); - memcpy(dest + len, (*it).data(), bytes_to_copy); /*Flawfinder: ignore*/ - len += bytes_to_copy; - bytes_left -= bytes_to_copy; - rv = (*it).data() + bytes_to_copy - 1; - ++it; - } - return rv; + S32 channel, + U8* start, + U8* dest, + S32& len) const +{ + U8* rv = start; + if(!dest || len <= 0) + { + return rv; + } + S32 bytes_left = len; + len = 0; + S32 bytes_to_copy = 0; + const_segment_iterator_t it; + + LLMutexLock lock(mMutexp) ; + const_segment_iterator_t end = mSegments.end(); + if(start) + { + it = getSegment(start); + if(it == end) + { + return rv; + } + if((++start < ((*it).data() + (*it).size())) + && (*it).isOnChannel(channel)) + { + // copy the data out of this segment + S32 bytes_in_segment = (*it).size() - (start - (*it).data()); + bytes_to_copy = llmin(bytes_left, bytes_in_segment); + memcpy(dest, start, bytes_to_copy); /*Flawfinder: ignore*/ + len += bytes_to_copy; + bytes_left -= bytes_to_copy; + rv = start + bytes_to_copy - 1; + ++it; + } + else + { + ++it; + } + } + else + { + it = mSegments.begin(); + } + while(bytes_left && (it != end)) + { + if(!((*it).isOnChannel(channel))) + { + ++it; + continue; + } + bytes_to_copy = llmin(bytes_left, (*it).size()); + memcpy(dest + len, (*it).data(), bytes_to_copy); /*Flawfinder: ignore*/ + len += bytes_to_copy; + bytes_left -= bytes_to_copy; + rv = (*it).data() + bytes_to_copy - 1; + ++it; + } + return rv; } U8* LLBufferArray::seek( - S32 channel, - U8* start, - S32 delta) const -{ - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - const_segment_iterator_t it; - const_segment_iterator_t end = mSegments.end(); - U8* rv = start; - if(0 == delta) - { - if((U8*)npos == start) - { - // someone is looking for end of data. - segment_list_t::const_reverse_iterator rit = mSegments.rbegin(); - segment_list_t::const_reverse_iterator rend = mSegments.rend(); - while(rit != rend) - { - if(!((*rit).isOnChannel(channel))) - { - ++rit; - continue; - } - rv = (*rit).data() + (*rit).size(); - break; - } - } - else if(start) - { - // This is sort of a weird case - check if zero bytes away - // from current position is on channel and return start if - // that is true. Otherwise, return NULL. - it = getSegment(start); - if((it == end) || !(*it).isOnChannel(channel)) - { - rv = NULL; - } - } - else - { - // Start is NULL, so return the very first byte on the - // channel, or NULL. - it = mSegments.begin(); - while((it != end) && !(*it).isOnChannel(channel)) - { - ++it; - } - if(it != end) - { - rv = (*it).data(); - } - } - return rv; - } - if(start) - { - it = getSegment(start); - if((it != end) && (*it).isOnChannel(channel)) - { - if(delta > 0) - { - S32 bytes_in_segment = (*it).size() - (start - (*it).data()); - S32 local_delta = llmin(delta, bytes_in_segment); - rv += local_delta; - delta -= local_delta; - ++it; - } - else - { - S32 bytes_in_segment = start - (*it).data(); - S32 local_delta = llmin(llabs(delta), bytes_in_segment); - rv -= local_delta; - delta += local_delta; - } - } - } - else if(delta < 0) - { - // start is NULL, and delta indicates seeking backwards - - // return NULL. - return NULL; - } - else - { - // start is NULL and delta > 0 - it = mSegments.begin(); - } - if(delta > 0) - { - // At this point, we have an iterator into the segments, and - // are seeking forward until delta is zero or we run out - while(delta && (it != end)) - { - if(!((*it).isOnChannel(channel))) - { - ++it; - continue; - } - if(delta <= (*it).size()) - { - // it's in this segment - rv = (*it).data() + delta; - } - delta -= (*it).size(); - ++it; - } - if(delta && (it == end)) - { - // Whoops - sought past end. - rv = NULL; - } - } - else //if(delta < 0) - { - // We are at the beginning of a segment, and need to search - // backwards. - segment_list_t::const_reverse_iterator rit(it); - segment_list_t::const_reverse_iterator rend = mSegments.rend(); - while(delta && (rit != rend)) - { - if(!((*rit).isOnChannel(channel))) - { - ++rit; - continue; - } - if(llabs(delta) <= (*rit).size()) - { - // it's in this segment. - rv = (*rit).data() + (*rit).size() + delta; - delta = 0; - } - else - { - delta += (*rit).size(); - } - ++rit; - } - if(delta && (rit == rend)) - { - // sought past the beginning. - rv = NULL; - } - } - return rv; + S32 channel, + U8* start, + S32 delta) const +{ + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + const_segment_iterator_t it; + const_segment_iterator_t end = mSegments.end(); + U8* rv = start; + if(0 == delta) + { + if((U8*)npos == start) + { + // someone is looking for end of data. + segment_list_t::const_reverse_iterator rit = mSegments.rbegin(); + segment_list_t::const_reverse_iterator rend = mSegments.rend(); + while(rit != rend) + { + if(!((*rit).isOnChannel(channel))) + { + ++rit; + continue; + } + rv = (*rit).data() + (*rit).size(); + break; + } + } + else if(start) + { + // This is sort of a weird case - check if zero bytes away + // from current position is on channel and return start if + // that is true. Otherwise, return NULL. + it = getSegment(start); + if((it == end) || !(*it).isOnChannel(channel)) + { + rv = NULL; + } + } + else + { + // Start is NULL, so return the very first byte on the + // channel, or NULL. + it = mSegments.begin(); + while((it != end) && !(*it).isOnChannel(channel)) + { + ++it; + } + if(it != end) + { + rv = (*it).data(); + } + } + return rv; + } + if(start) + { + it = getSegment(start); + if((it != end) && (*it).isOnChannel(channel)) + { + if(delta > 0) + { + S32 bytes_in_segment = (*it).size() - (start - (*it).data()); + S32 local_delta = llmin(delta, bytes_in_segment); + rv += local_delta; + delta -= local_delta; + ++it; + } + else + { + S32 bytes_in_segment = start - (*it).data(); + S32 local_delta = llmin(llabs(delta), bytes_in_segment); + rv -= local_delta; + delta += local_delta; + } + } + } + else if(delta < 0) + { + // start is NULL, and delta indicates seeking backwards - + // return NULL. + return NULL; + } + else + { + // start is NULL and delta > 0 + it = mSegments.begin(); + } + if(delta > 0) + { + // At this point, we have an iterator into the segments, and + // are seeking forward until delta is zero or we run out + while(delta && (it != end)) + { + if(!((*it).isOnChannel(channel))) + { + ++it; + continue; + } + if(delta <= (*it).size()) + { + // it's in this segment + rv = (*it).data() + delta; + } + delta -= (*it).size(); + ++it; + } + if(delta && (it == end)) + { + // Whoops - sought past end. + rv = NULL; + } + } + else //if(delta < 0) + { + // We are at the beginning of a segment, and need to search + // backwards. + segment_list_t::const_reverse_iterator rit(it); + segment_list_t::const_reverse_iterator rend = mSegments.rend(); + while(delta && (rit != rend)) + { + if(!((*rit).isOnChannel(channel))) + { + ++rit; + continue; + } + if(llabs(delta) <= (*rit).size()) + { + // it's in this segment. + rv = (*rit).data() + (*rit).size() + delta; + delta = 0; + } + else + { + delta += (*rit).size(); + } + ++rit; + } + if(delta && (rit == rend)) + { + // sought past the beginning. + rv = NULL; + } + } + return rv; } //test use only bool LLBufferArray::takeContents(LLBufferArray& source) { - LLMutexLock lock(mMutexp); - source.lock(); + LLMutexLock lock(mMutexp); + source.lock(); - std::copy( - source.mBuffers.begin(), - source.mBuffers.end(), - std::back_insert_iterator<buffer_list_t>(mBuffers)); - source.mBuffers.clear(); - std::copy( - source.mSegments.begin(), - source.mSegments.end(), - std::back_insert_iterator<segment_list_t>(mSegments)); - source.mSegments.clear(); - source.mNextBaseChannel = 0; - source.unlock(); + std::copy( + source.mBuffers.begin(), + source.mBuffers.end(), + std::back_insert_iterator<buffer_list_t>(mBuffers)); + source.mBuffers.clear(); + std::copy( + source.mSegments.begin(), + source.mSegments.end(), + std::back_insert_iterator<segment_list_t>(mSegments)); + source.mSegments.clear(); + source.mNextBaseChannel = 0; + source.unlock(); - return true; + return true; } //mMutexp should be locked before calling this. LLBufferArray::segment_iterator_t LLBufferArray::makeSegment( - S32 channel, - S32 len) -{ - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - // start at the end of the buffers, because it is the most likely - // to have free space. - LLSegment segment; - buffer_list_t::reverse_iterator it = mBuffers.rbegin(); - buffer_list_t::reverse_iterator end = mBuffers.rend(); - bool made_segment = false; - for(; it != end; ++it) - { - if((*it)->createSegment(channel, len, segment)) - { - made_segment = true; - break; - } - } - segment_iterator_t send = mSegments.end(); - if(!made_segment) - { - LLBuffer* buf = new LLHeapBuffer; - mBuffers.push_back(buf); - if(!buf->createSegment(channel, len, segment)) - { - // failed. this should never happen. - return send; - } - } - - // store and return the newly made segment - mSegments.insert(send, segment); - std::list<LLSegment>::reverse_iterator rv = mSegments.rbegin(); - ++rv; - send = rv.base(); - return send; + S32 channel, + S32 len) +{ + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + // start at the end of the buffers, because it is the most likely + // to have free space. + LLSegment segment; + buffer_list_t::reverse_iterator it = mBuffers.rbegin(); + buffer_list_t::reverse_iterator end = mBuffers.rend(); + bool made_segment = false; + for(; it != end; ++it) + { + if((*it)->createSegment(channel, len, segment)) + { + made_segment = true; + break; + } + } + segment_iterator_t send = mSegments.end(); + if(!made_segment) + { + LLBuffer* buf = new LLHeapBuffer; + mBuffers.push_back(buf); + if(!buf->createSegment(channel, len, segment)) + { + // failed. this should never happen. + return send; + } + } + + // store and return the newly made segment + mSegments.insert(send, segment); + std::list<LLSegment>::reverse_iterator rv = mSegments.rbegin(); + ++rv; + send = rv.base(); + return send; } //mMutexp should be locked before calling this. bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter) { - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - - // Find out which buffer contains the segment, and if it is found, - // ask it to reclaim the memory. - bool rv = false; - LLSegment segment(*erase_iter); - buffer_iterator_t iter = mBuffers.begin(); - buffer_iterator_t end = mBuffers.end(); - for(; iter != end; ++iter) - { - // We can safely call reclaimSegment on every buffer, and once - // it returns true, the segment was found. - if((*iter)->reclaimSegment(segment)) - { - rv = true; - break; - } - } - - // No need to get the return value since we are not interested in - // the interator retured by the call. - (void)mSegments.erase(erase_iter); - return rv; + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + + // Find out which buffer contains the segment, and if it is found, + // ask it to reclaim the memory. + bool rv = false; + LLSegment segment(*erase_iter); + buffer_iterator_t iter = mBuffers.begin(); + buffer_iterator_t end = mBuffers.end(); + for(; iter != end; ++iter) + { + // We can safely call reclaimSegment on every buffer, and once + // it returns true, the segment was found. + if((*iter)->reclaimSegment(segment)) + { + rv = true; + break; + } + } + + // No need to get the return value since we are not interested in + // the interator retured by the call. + (void)mSegments.erase(erase_iter); + return rv; } //mMutexp should be locked before calling this. bool LLBufferArray::copyIntoBuffers( - S32 channel, - const U8* src, - S32 len, - std::vector<LLSegment>& segments) -{ - ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); - if(!src || !len) return false; - S32 copied = 0; - LLSegment segment; - buffer_iterator_t it = mBuffers.begin(); - buffer_iterator_t end = mBuffers.end(); - for(; it != end;) - { - if(!(*it)->createSegment(channel, len, segment)) - { - ++it; - continue; - } - segments.push_back(segment); - S32 bytes = llmin(segment.size(), len); - memcpy(segment.data(), src + copied, bytes); /* Flawfinder: Ignore */ - copied += bytes; - len -= bytes; - if(0 == len) - { - break; - } - } - while(len) - { - LLBuffer* buf = new LLHeapBuffer; - mBuffers.push_back(buf); - if(!buf->createSegment(channel, len, segment)) - { - // this totally failed - bail. This is the weird corner - // case were we 'leak' memory. No worries about an actual - // leak - we will still reclaim the memory later, but this - // particular buffer array is hosed for some reason. - // This should never happen. - return false; - } - segments.push_back(segment); - memcpy(segment.data(), src + copied, segment.size()); /*Flawfinder: ignore*/ - copied += segment.size(); - len -= segment.size(); - } - return true; + S32 channel, + const U8* src, + S32 len, + std::vector<LLSegment>& segments) +{ + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED(); + if(!src || !len) return false; + S32 copied = 0; + LLSegment segment; + buffer_iterator_t it = mBuffers.begin(); + buffer_iterator_t end = mBuffers.end(); + for(; it != end;) + { + if(!(*it)->createSegment(channel, len, segment)) + { + ++it; + continue; + } + segments.push_back(segment); + S32 bytes = llmin(segment.size(), len); + memcpy(segment.data(), src + copied, bytes); /* Flawfinder: Ignore */ + copied += bytes; + len -= bytes; + if(0 == len) + { + break; + } + } + while(len) + { + LLBuffer* buf = new LLHeapBuffer; + mBuffers.push_back(buf); + if(!buf->createSegment(channel, len, segment)) + { + // this totally failed - bail. This is the weird corner + // case were we 'leak' memory. No worries about an actual + // leak - we will still reclaim the memory later, but this + // particular buffer array is hosed for some reason. + // This should never happen. + return false; + } + segments.push_back(segment); + memcpy(segment.data(), src + copied, segment.size()); /*Flawfinder: ignore*/ + copied += segment.size(); + len -= segment.size(); + } + return true; } diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h index ccdb9fa7ee..89229ea9d1 100644 --- a/indra/llmessage/llbuffer.h +++ b/indra/llmessage/llbuffer.h @@ -1,4 +1,4 @@ -/** +/** * @file llbuffer.h * @author Phoenix * @date 2005-09-20 @@ -7,21 +7,21 @@ * $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$ */ @@ -40,26 +40,26 @@ #include <vector> class LLMutex; -/** +/** * @class LLChannelDescriptors * @brief A way simple interface to accesss channels inside a buffer */ class LLChannelDescriptors { public: - // enumeration for segmenting the channel information - enum { E_CHANNEL_COUNT = 3 }; - LLChannelDescriptors() : mBaseChannel(0) {} - explicit LLChannelDescriptors(S32 base) : mBaseChannel(base) {} - S32 in() const { return mBaseChannel; } - S32 out() const { return mBaseChannel + 1; } - //S32 err() const { return mBaseChannel + 2; } + // enumeration for segmenting the channel information + enum { E_CHANNEL_COUNT = 3 }; + LLChannelDescriptors() : mBaseChannel(0) {} + explicit LLChannelDescriptors(S32 base) : mBaseChannel(base) {} + S32 in() const { return mBaseChannel; } + S32 out() const { return mBaseChannel + 1; } + //S32 err() const { return mBaseChannel + 2; } protected: - S32 mBaseChannel; + S32 mBaseChannel; }; -/** +/** * @class LLSegment * @brief A segment is a single, contiguous chunk of memory in a buffer * @@ -70,62 +70,62 @@ protected: * as necessary. * This is the preferred interface for working with memory blocks, * since it is the only way to safely, inexpensively, and directly - * access linear blocks of memory. + * access linear blocks of memory. */ class LLSegment { public: - LLSegment(); - LLSegment(S32 channel, U8* data, S32 data_len); - ~LLSegment(); - - /** - * @brief Check if this segment is on the given channel. - * - */ - bool isOnChannel(S32 channel) const; - - /** - * @brief Get the channel - */ - S32 getChannel() const; - - /** - * @brief Set the channel - */ - void setChannel(S32 channel); - - /** - * @brief Return a raw pointer to the current data set. - * - * The pointer returned can be used for reading or even adjustment - * if you are a bit crazy up to size() bytes into memory. - * @return A potentially NULL pointer to the raw buffer data - */ - U8* data() const; - - /** - * @brief Return the size of the segment - */ - S32 size() const; - - /** - * @brief Check if two segments are the same. - * - * Two segments are considered equal if they are on the same - * channel and cover the exact same address range. - * @param rhs the segment to compare with this segment. - * @return Returns true if they are equal. - */ - bool operator==(const LLSegment& rhs) const; + LLSegment(); + LLSegment(S32 channel, U8* data, S32 data_len); + ~LLSegment(); + + /** + * @brief Check if this segment is on the given channel. + * + */ + bool isOnChannel(S32 channel) const; + + /** + * @brief Get the channel + */ + S32 getChannel() const; + + /** + * @brief Set the channel + */ + void setChannel(S32 channel); + + /** + * @brief Return a raw pointer to the current data set. + * + * The pointer returned can be used for reading or even adjustment + * if you are a bit crazy up to size() bytes into memory. + * @return A potentially NULL pointer to the raw buffer data + */ + U8* data() const; + + /** + * @brief Return the size of the segment + */ + S32 size() const; + + /** + * @brief Check if two segments are the same. + * + * Two segments are considered equal if they are on the same + * channel and cover the exact same address range. + * @param rhs the segment to compare with this segment. + * @return Returns true if they are equal. + */ + bool operator==(const LLSegment& rhs) const; protected: - S32 mChannel; - U8* mData; - S32 mSize; + S32 mChannel; + U8* mData; + S32 mSize; }; -/** +/** * @class LLBuffer * @brief Abstract base class for buffers * @@ -136,58 +136,58 @@ protected: class LLBuffer { public: - /** - * @brief The buffer base class should have no responsibilities - * other than an interface. - */ - virtual ~LLBuffer() {} - - /** - * @brief Generate a segment for this buffer. - * - * The segment returned is always contiguous memory. This call can - * fail if no contiguous memory is available, eg, offset is past - * the end. The segment returned may be smaller than the requested - * size. The segment will never be larger than the requested size. - * @param channel The channel for the segment. - * @param offset The offset from zero in the buffer. - * @param size The requested size of the segment. - * @param segment[out] The out-value from the operation - * @return Returns true if a segment was found. - */ - virtual bool createSegment(S32 channel, S32 size, LLSegment& segment) = 0; - - /** - * @brief Reclaim a segment from this buffer. - * - * This method is called on a buffer object when a caller is done - * with a contiguous segment of memory inside this buffer. Since - * segments can be cut arbitrarily outside of the control of the - * buffer, this segment may not match any segment returned from - * <code>createSegment()</code>. - * @param segment The contiguous buffer segment to reclaim. - * @return Returns true if the call was successful. - */ - virtual bool reclaimSegment(const LLSegment& segment) = 0; - - /** - * @brief Test if a segment is inside this buffer. - * - * @param segment The contiguous buffer segment to test. - * @return Returns true if the segment is in the bufffer. - */ - virtual bool containsSegment(const LLSegment& segment) const = 0; - - /** - * @brief Return the current number of bytes allocated. - * - * This was implemented as a debugging tool, and it is not - * necessarily a good idea to use it for anything else. - */ - virtual S32 capacity() const = 0; + /** + * @brief The buffer base class should have no responsibilities + * other than an interface. + */ + virtual ~LLBuffer() {} + + /** + * @brief Generate a segment for this buffer. + * + * The segment returned is always contiguous memory. This call can + * fail if no contiguous memory is available, eg, offset is past + * the end. The segment returned may be smaller than the requested + * size. The segment will never be larger than the requested size. + * @param channel The channel for the segment. + * @param offset The offset from zero in the buffer. + * @param size The requested size of the segment. + * @param segment[out] The out-value from the operation + * @return Returns true if a segment was found. + */ + virtual bool createSegment(S32 channel, S32 size, LLSegment& segment) = 0; + + /** + * @brief Reclaim a segment from this buffer. + * + * This method is called on a buffer object when a caller is done + * with a contiguous segment of memory inside this buffer. Since + * segments can be cut arbitrarily outside of the control of the + * buffer, this segment may not match any segment returned from + * <code>createSegment()</code>. + * @param segment The contiguous buffer segment to reclaim. + * @return Returns true if the call was successful. + */ + virtual bool reclaimSegment(const LLSegment& segment) = 0; + + /** + * @brief Test if a segment is inside this buffer. + * + * @param segment The contiguous buffer segment to test. + * @return Returns true if the segment is in the bufffer. + */ + virtual bool containsSegment(const LLSegment& segment) const = 0; + + /** + * @brief Return the current number of bytes allocated. + * + * This was implemented as a debugging tool, and it is not + * necessarily a good idea to use it for anything else. + */ + virtual S32 capacity() const = 0; }; -/** +/** * @class LLHeapBuffer * @brief A large contiguous buffer allocated on the heap with new[]. * @@ -198,99 +198,99 @@ public: class LLHeapBuffer : public LLBuffer { public: - /** - * @brief Construct a heap buffer with a reasonable default size. - */ - LLHeapBuffer(); - - /** - * @brief Construct a heap buffer with a specified size. - * - * @param size The minimum size of the buffer. - */ - explicit LLHeapBuffer(S32 size); - - /** - * @brief Construct a heap buffer of minimum size len, and copy from src. - * - * @param src The source of the data to be copied. - * @param len The minimum size of the buffer. - */ - LLHeapBuffer(const U8* src, S32 len); - - /** - * @brief Simple destruction. - */ - virtual ~LLHeapBuffer(); - - /** - * @brief Get the number of bytes left in the buffer. - * - * Note that this is not a virtual function, and only available in - * the LLHeapBuffer as a debugging aid. - * @return Returns the number of bytes left. - */ - S32 bytesLeft() const; - - /** - * @brief Generate a segment for this buffer. - * - * The segment returned is always contiguous memory. This call can - * fail if no contiguous memory is available, eg, offset is past - * the end. The segment returned may be smaller than the requested - * size. It is up to the caller to delete the segment returned. - * @param channel The channel for the segment. - * @param offset The offset from zero in the buffer - * @param size The requested size of the segment - * @param segment[out] The out-value from the operation - * @return Returns true if a segment was found. - */ - virtual bool createSegment(S32 channel, S32 size, LLSegment& segment); - - /** - * @brief reclaim a segment from this buffer. - * - * This method is called on a buffer object when a caller is done - * with a contiguous segment of memory inside this buffer. Since - * segments can be cut arbitrarily outside of the control of the - * buffer, this segment may not match any segment returned from - * <code>createSegment()</code>. - * This call will fail if the segment passed in is note completely - * inside the buffer, eg, if the segment starts before this buffer - * in memory or ends after it. - * @param segment The contiguous buffer segment to reclaim. - * @return Returns true if the call was successful. - */ - virtual bool reclaimSegment(const LLSegment& segment); - - /** - * @brief Test if a segment is inside this buffer. - * - * @param segment The contiguous buffer segment to test. - * @return Returns true if the segment is in the bufffer. - */ - virtual bool containsSegment(const LLSegment& segment) const; - - /** - * @brief Return the current number of bytes allocated. - */ - virtual S32 capacity() const { return mSize; } + /** + * @brief Construct a heap buffer with a reasonable default size. + */ + LLHeapBuffer(); + + /** + * @brief Construct a heap buffer with a specified size. + * + * @param size The minimum size of the buffer. + */ + explicit LLHeapBuffer(S32 size); + + /** + * @brief Construct a heap buffer of minimum size len, and copy from src. + * + * @param src The source of the data to be copied. + * @param len The minimum size of the buffer. + */ + LLHeapBuffer(const U8* src, S32 len); + + /** + * @brief Simple destruction. + */ + virtual ~LLHeapBuffer(); + + /** + * @brief Get the number of bytes left in the buffer. + * + * Note that this is not a virtual function, and only available in + * the LLHeapBuffer as a debugging aid. + * @return Returns the number of bytes left. + */ + S32 bytesLeft() const; + + /** + * @brief Generate a segment for this buffer. + * + * The segment returned is always contiguous memory. This call can + * fail if no contiguous memory is available, eg, offset is past + * the end. The segment returned may be smaller than the requested + * size. It is up to the caller to delete the segment returned. + * @param channel The channel for the segment. + * @param offset The offset from zero in the buffer + * @param size The requested size of the segment + * @param segment[out] The out-value from the operation + * @return Returns true if a segment was found. + */ + virtual bool createSegment(S32 channel, S32 size, LLSegment& segment); + + /** + * @brief reclaim a segment from this buffer. + * + * This method is called on a buffer object when a caller is done + * with a contiguous segment of memory inside this buffer. Since + * segments can be cut arbitrarily outside of the control of the + * buffer, this segment may not match any segment returned from + * <code>createSegment()</code>. + * This call will fail if the segment passed in is note completely + * inside the buffer, eg, if the segment starts before this buffer + * in memory or ends after it. + * @param segment The contiguous buffer segment to reclaim. + * @return Returns true if the call was successful. + */ + virtual bool reclaimSegment(const LLSegment& segment); + + /** + * @brief Test if a segment is inside this buffer. + * + * @param segment The contiguous buffer segment to test. + * @return Returns true if the segment is in the bufffer. + */ + virtual bool containsSegment(const LLSegment& segment) const; + + /** + * @brief Return the current number of bytes allocated. + */ + virtual S32 capacity() const { return mSize; } protected: - U8* mBuffer; - S32 mSize; - U8* mNextFree; - S32 mReclaimedBytes; + U8* mBuffer; + S32 mSize; + U8* mNextFree; + S32 mReclaimedBytes; private: - /** - * @brief Helper method to allocate a buffer and correctly set - * intertnal state of this buffer. - */ - void allocate(S32 size); + /** + * @brief Helper method to allocate a buffer and correctly set + * intertnal state of this buffer. + */ + void allocate(S32 size); }; -/** +/** * @class LLBufferArray * @brief Class to represent scattered memory buffers and in-order segments * of that buffered data. @@ -300,326 +300,326 @@ private: class LLBufferArray { public: - typedef std::vector<LLBuffer*> buffer_list_t; - typedef buffer_list_t::iterator buffer_iterator_t; - typedef buffer_list_t::const_iterator const_buffer_iterator_t; - typedef std::list<LLSegment> segment_list_t; - typedef segment_list_t::const_iterator const_segment_iterator_t; - typedef segment_list_t::iterator segment_iterator_t; - enum { npos = 0xffffffff }; - - LLBufferArray(); - ~LLBufferArray(); - - /* @name Channel methods - */ - //@{ - /** - * @brief Generate the a channel descriptor which consumes the - * output for the channel passed in. - */ - static LLChannelDescriptors makeChannelConsumer( - const LLChannelDescriptors& channels); - - /** - * @brief Generate the next channel descriptor for this buffer array. - * - * The channel descriptor interface is how the buffer array - * clients can know where to read and write data. Use this - * interface to get the 'next' channel set for usage. This is a - * bit of a simple hack until it's utility indicates it should be - * extended. - * @return Returns a valid channel descriptor set for input and output. - */ - LLChannelDescriptors nextChannel(); - //@} - - /* @name Data methods - */ - //@{ - - /** - * @brief Return the sum of all allocated bytes. - */ - S32 capacity() const; - - // These methods will be useful once there is any kind of buffer - // besides a heap buffer. - //bool append(EBufferChannel channel, LLBuffer* data); - //bool prepend(EBufferChannel channel, LLBuffer* data); - //bool insertAfter( - // segment_iterator_t segment, - // EBufferChannel channel, - // LLBuffer* data); - - /** - * @brief Put data on a channel at the end of this buffer array. - * - * The data is copied from src into the buffer array. At least one - * new segment is created and put on the end of the array. This - * object will internally allocate new buffers if necessary. - * @param channel The channel for this data - * @param src The start of memory for the data to be copied - * @param len The number of bytes of data to copy - * @return Returns true if the method worked. - */ - bool append(S32 channel, const U8* src, S32 len); - - /** - * @brief Put data on a channel at the front of this buffer array. - * - * The data is copied from src into the buffer array. At least one - * new segment is created and put in the front of the array. This - * object will internally allocate new buffers if necessary. - * @param channel The channel for this data - * @param src The start of memory for the data to be copied - * @param len The number of bytes of data to copy - * @return Returns true if the method worked. - */ - bool prepend(S32 channel, const U8* src, S32 len); - - /** - * @brief Insert data into a buffer array after a particular segment. - * - * The data is copied from src into the buffer array. At least one - * new segment is created and put in the array. This object will - * internally allocate new buffers if necessary. - * @param segment The segment in front of the new segments location - * @param channel The channel for this data - * @param src The start of memory for the data to be copied - * @param len The number of bytes of data to copy - * @return Returns true if the method worked. - */ - bool insertAfter( - segment_iterator_t segment, - S32 channel, - const U8* src, - S32 len); - - /** - * @brief Count bytes in the buffer array on the specified channel - * - * @param channel The channel to count. - * @param start The start address in the array for counting. You - * can specify NULL to start at the beginning. - * @return Returns the number of bytes in the channel after start - */ - S32 countAfter(S32 channel, U8* start) const; - - /** - * @brief Count all bytes on channel. - * - * Helper method which just calls countAfter(). - * @param channel The channel to count. - * @return Returns the number of bytes in the channel. - */ - S32 count(S32 channel) const - { - return countAfter(channel, NULL); - } - - /** - * @brief Read bytes in the buffer array on the specified channel - * - * You should prefer iterating over segments is possible since - * this method requires you to allocate large buffers - precisely - * what this class is trying to prevent. This method will skip - * any segments which are not on the given channel, so this method - * would usually be used to read a channel and copy that to a log - * or a socket buffer or something. - * @param channel The channel to read. - * @param start The start address in the array for reading. You - * can specify NULL to start at the beginning. - * @param dest The destination of the data read. This must be at - * least len bytes long. - * @param len[in,out] <b>in</b> How many bytes to read. <b>out</b> How - * many bytes were read. - * @return Returns the address of the last read byte. - */ - U8* readAfter(S32 channel, U8* start, U8* dest, S32& len) const; - - /** - * @brief Find an address in a buffer array - * - * @param channel The channel to seek in. - * @param start The start address in the array for the seek - * operation. You can specify NULL to start the seek at the - * beginning, or pass in npos to start at the end. - * @param delta How many bytes to seek through the array. - * @return Returns the address of the last read byte. - */ - U8* seek(S32 channel, U8* start, S32 delta) const; - //@} - - /* @name Buffer interaction - */ - //@{ - /** - * @brief Take the contents of another buffer array - * - * This method simply strips the contents out of the source - * buffery array - segments, buffers, etc, and appends them to - * this instance. After this operation, the source is empty and - * ready for reuse. - * @param source The source buffer - * @return Returns true if the operation succeeded. - */ - bool takeContents(LLBufferArray& source); - //@} - - /* @name Segment methods - */ - //@{ - /** - * @brief Split a segments so that address is the last address of - * one segment, and the rest of the original segment becomes - * another segment on the same channel. - * - * After this method call, - * <code>getLastSegmentAddress(*getSegment(address)) == - * address</code> should be true. This call will only create a new - * segment if the statement above is false before the call. Since - * you usually call splitAfter() to change a segment property, use - * getSegment() to perform those operations. - * @param address The address which will become the last address - * of the segment it is in. - * @return Returns an iterator to the segment which contains - * <code>address</code> which is <code>endSegment()</code> on - * failure. - */ - segment_iterator_t splitAfter(U8* address); - - /** - * @brief Get the first segment in the buffer array. - * - * @return Returns the segment if there is one. - */ - segment_iterator_t beginSegment(); - - /** - * @brief Get the one-past-the-end segment in the buffer array - * - * @return Returns the iterator for an invalid segment location. - */ - segment_iterator_t endSegment(); - - /** - * @brief Get the segment which holds the given address. - * - * As opposed to some methods, passing a NULL will result in - * returning the end segment. - * @param address An address in the middle of the sought segment. - * @return Returns the iterator for the segment or endSegment() on - * failure. - */ - const_segment_iterator_t getSegment(U8* address) const; - - /** - * @brief Get the segment which holds the given address. - * - * As opposed to some methods, passing a NULL will result in - * returning the end segment. - * @param address An address in the middle of the sought segment. - * @return Returns the iterator for the segment or endSegment() on - * failure. - */ - segment_iterator_t getSegment(U8* address); - - /** - * @brief Get a segment iterator after address, and a constructed - * segment to represent the next linear block of memory. - * - * This method is a helper by giving you the largest segment - * possible in the out-value param after the address provided. The - * iterator will be useful for iteration, while the segment can be - * used for direct access to memory after address if the return - * values isnot end. Passing in NULL will return beginSegment() - * which may be endSegment(). The segment returned will only be - * zero length if the return value equals end. - * This is really just a helper method, since all the information - * returned could be constructed through other methods. - * @param address An address in the middle of the sought segment. - * @param segment[out] segment to be used for reading or writing - * @return Returns an iterator which contains at least segment or - * endSegment() on failure. - */ - segment_iterator_t constructSegmentAfter(U8* address, LLSegment& segment); - - /** - * @brief Make a new segment at the end of buffer array - * - * This method will attempt to create a new and empty segment of - * the specified length. The segment created may be shorter than - * requested. - * @param channel[in] The channel for the newly created segment. - * @param length[in] The requested length of the segment. - * @return Returns an iterator which contains at least segment or - * endSegment() on failure. - */ - segment_iterator_t makeSegment(S32 channel, S32 length); - - /** - * @brief Erase the segment if it is in the buffer array. - * - * @param iter An iterator referring to the segment to erase. - * @return Returns true on success. - */ - bool eraseSegment(const segment_iterator_t& iter); - - /** - * @brief Lock the mutex if it exists - * This method locks mMutexp to make accessing LLBufferArray thread-safe - */ - void lock(); - - /** - * @brief Unlock the mutex if it exists - */ - void unlock(); - - /** - * @brief Return mMutexp - */ - LLMutex* getMutex(); - - /** - * @brief Set LLBufferArray to be shared across threads or not - * This method is to create mMutexp if is threaded. - * @param threaded Indicates this LLBufferArray instance is shared across threads if true. - */ - void setThreaded(bool threaded); - //@} + typedef std::vector<LLBuffer*> buffer_list_t; + typedef buffer_list_t::iterator buffer_iterator_t; + typedef buffer_list_t::const_iterator const_buffer_iterator_t; + typedef std::list<LLSegment> segment_list_t; + typedef segment_list_t::const_iterator const_segment_iterator_t; + typedef segment_list_t::iterator segment_iterator_t; + enum { npos = 0xffffffff }; + + LLBufferArray(); + ~LLBufferArray(); + + /* @name Channel methods + */ + //@{ + /** + * @brief Generate the a channel descriptor which consumes the + * output for the channel passed in. + */ + static LLChannelDescriptors makeChannelConsumer( + const LLChannelDescriptors& channels); + + /** + * @brief Generate the next channel descriptor for this buffer array. + * + * The channel descriptor interface is how the buffer array + * clients can know where to read and write data. Use this + * interface to get the 'next' channel set for usage. This is a + * bit of a simple hack until it's utility indicates it should be + * extended. + * @return Returns a valid channel descriptor set for input and output. + */ + LLChannelDescriptors nextChannel(); + //@} + + /* @name Data methods + */ + //@{ + + /** + * @brief Return the sum of all allocated bytes. + */ + S32 capacity() const; + + // These methods will be useful once there is any kind of buffer + // besides a heap buffer. + //bool append(EBufferChannel channel, LLBuffer* data); + //bool prepend(EBufferChannel channel, LLBuffer* data); + //bool insertAfter( + // segment_iterator_t segment, + // EBufferChannel channel, + // LLBuffer* data); + + /** + * @brief Put data on a channel at the end of this buffer array. + * + * The data is copied from src into the buffer array. At least one + * new segment is created and put on the end of the array. This + * object will internally allocate new buffers if necessary. + * @param channel The channel for this data + * @param src The start of memory for the data to be copied + * @param len The number of bytes of data to copy + * @return Returns true if the method worked. + */ + bool append(S32 channel, const U8* src, S32 len); + + /** + * @brief Put data on a channel at the front of this buffer array. + * + * The data is copied from src into the buffer array. At least one + * new segment is created and put in the front of the array. This + * object will internally allocate new buffers if necessary. + * @param channel The channel for this data + * @param src The start of memory for the data to be copied + * @param len The number of bytes of data to copy + * @return Returns true if the method worked. + */ + bool prepend(S32 channel, const U8* src, S32 len); + + /** + * @brief Insert data into a buffer array after a particular segment. + * + * The data is copied from src into the buffer array. At least one + * new segment is created and put in the array. This object will + * internally allocate new buffers if necessary. + * @param segment The segment in front of the new segments location + * @param channel The channel for this data + * @param src The start of memory for the data to be copied + * @param len The number of bytes of data to copy + * @return Returns true if the method worked. + */ + bool insertAfter( + segment_iterator_t segment, + S32 channel, + const U8* src, + S32 len); + + /** + * @brief Count bytes in the buffer array on the specified channel + * + * @param channel The channel to count. + * @param start The start address in the array for counting. You + * can specify NULL to start at the beginning. + * @return Returns the number of bytes in the channel after start + */ + S32 countAfter(S32 channel, U8* start) const; + + /** + * @brief Count all bytes on channel. + * + * Helper method which just calls countAfter(). + * @param channel The channel to count. + * @return Returns the number of bytes in the channel. + */ + S32 count(S32 channel) const + { + return countAfter(channel, NULL); + } + + /** + * @brief Read bytes in the buffer array on the specified channel + * + * You should prefer iterating over segments is possible since + * this method requires you to allocate large buffers - precisely + * what this class is trying to prevent. This method will skip + * any segments which are not on the given channel, so this method + * would usually be used to read a channel and copy that to a log + * or a socket buffer or something. + * @param channel The channel to read. + * @param start The start address in the array for reading. You + * can specify NULL to start at the beginning. + * @param dest The destination of the data read. This must be at + * least len bytes long. + * @param len[in,out] <b>in</b> How many bytes to read. <b>out</b> How + * many bytes were read. + * @return Returns the address of the last read byte. + */ + U8* readAfter(S32 channel, U8* start, U8* dest, S32& len) const; + + /** + * @brief Find an address in a buffer array + * + * @param channel The channel to seek in. + * @param start The start address in the array for the seek + * operation. You can specify NULL to start the seek at the + * beginning, or pass in npos to start at the end. + * @param delta How many bytes to seek through the array. + * @return Returns the address of the last read byte. + */ + U8* seek(S32 channel, U8* start, S32 delta) const; + //@} + + /* @name Buffer interaction + */ + //@{ + /** + * @brief Take the contents of another buffer array + * + * This method simply strips the contents out of the source + * buffery array - segments, buffers, etc, and appends them to + * this instance. After this operation, the source is empty and + * ready for reuse. + * @param source The source buffer + * @return Returns true if the operation succeeded. + */ + bool takeContents(LLBufferArray& source); + //@} + + /* @name Segment methods + */ + //@{ + /** + * @brief Split a segments so that address is the last address of + * one segment, and the rest of the original segment becomes + * another segment on the same channel. + * + * After this method call, + * <code>getLastSegmentAddress(*getSegment(address)) == + * address</code> should be true. This call will only create a new + * segment if the statement above is false before the call. Since + * you usually call splitAfter() to change a segment property, use + * getSegment() to perform those operations. + * @param address The address which will become the last address + * of the segment it is in. + * @return Returns an iterator to the segment which contains + * <code>address</code> which is <code>endSegment()</code> on + * failure. + */ + segment_iterator_t splitAfter(U8* address); + + /** + * @brief Get the first segment in the buffer array. + * + * @return Returns the segment if there is one. + */ + segment_iterator_t beginSegment(); + + /** + * @brief Get the one-past-the-end segment in the buffer array + * + * @return Returns the iterator for an invalid segment location. + */ + segment_iterator_t endSegment(); + + /** + * @brief Get the segment which holds the given address. + * + * As opposed to some methods, passing a NULL will result in + * returning the end segment. + * @param address An address in the middle of the sought segment. + * @return Returns the iterator for the segment or endSegment() on + * failure. + */ + const_segment_iterator_t getSegment(U8* address) const; + + /** + * @brief Get the segment which holds the given address. + * + * As opposed to some methods, passing a NULL will result in + * returning the end segment. + * @param address An address in the middle of the sought segment. + * @return Returns the iterator for the segment or endSegment() on + * failure. + */ + segment_iterator_t getSegment(U8* address); + + /** + * @brief Get a segment iterator after address, and a constructed + * segment to represent the next linear block of memory. + * + * This method is a helper by giving you the largest segment + * possible in the out-value param after the address provided. The + * iterator will be useful for iteration, while the segment can be + * used for direct access to memory after address if the return + * values isnot end. Passing in NULL will return beginSegment() + * which may be endSegment(). The segment returned will only be + * zero length if the return value equals end. + * This is really just a helper method, since all the information + * returned could be constructed through other methods. + * @param address An address in the middle of the sought segment. + * @param segment[out] segment to be used for reading or writing + * @return Returns an iterator which contains at least segment or + * endSegment() on failure. + */ + segment_iterator_t constructSegmentAfter(U8* address, LLSegment& segment); + + /** + * @brief Make a new segment at the end of buffer array + * + * This method will attempt to create a new and empty segment of + * the specified length. The segment created may be shorter than + * requested. + * @param channel[in] The channel for the newly created segment. + * @param length[in] The requested length of the segment. + * @return Returns an iterator which contains at least segment or + * endSegment() on failure. + */ + segment_iterator_t makeSegment(S32 channel, S32 length); + + /** + * @brief Erase the segment if it is in the buffer array. + * + * @param iter An iterator referring to the segment to erase. + * @return Returns true on success. + */ + bool eraseSegment(const segment_iterator_t& iter); + + /** + * @brief Lock the mutex if it exists + * This method locks mMutexp to make accessing LLBufferArray thread-safe + */ + void lock(); + + /** + * @brief Unlock the mutex if it exists + */ + void unlock(); + + /** + * @brief Return mMutexp + */ + LLMutex* getMutex(); + + /** + * @brief Set LLBufferArray to be shared across threads or not + * This method is to create mMutexp if is threaded. + * @param threaded Indicates this LLBufferArray instance is shared across threads if true. + */ + void setThreaded(bool threaded); + //@} protected: - /** - * @brief Optimally put data in buffers, and reutrn segments. - * - * This is an internal function used to create buffers as - * necessary, and sequence the segments appropriately for the - * various ways to copy data from src into this. - * If this method fails, it may actually leak some space inside - * buffers, but I am not too worried about the slim possibility - * that we may have some 'dead' space which will be recovered when - * the buffer (which we will not lose) is deleted. Addressing this - * weakness will make the buffers almost as complex as a general - * memory management system. - * @param channel The channel for this data - * @param src The start of memory for the data to be copied - * @param len The number of bytes of data to copy - * @param segments Out-value for the segments created. - * @return Returns true if the method worked. - */ - bool copyIntoBuffers( - S32 channel, - const U8* src, - S32 len, - std::vector<LLSegment>& segments); + /** + * @brief Optimally put data in buffers, and reutrn segments. + * + * This is an internal function used to create buffers as + * necessary, and sequence the segments appropriately for the + * various ways to copy data from src into this. + * If this method fails, it may actually leak some space inside + * buffers, but I am not too worried about the slim possibility + * that we may have some 'dead' space which will be recovered when + * the buffer (which we will not lose) is deleted. Addressing this + * weakness will make the buffers almost as complex as a general + * memory management system. + * @param channel The channel for this data + * @param src The start of memory for the data to be copied + * @param len The number of bytes of data to copy + * @param segments Out-value for the segments created. + * @return Returns true if the method worked. + */ + bool copyIntoBuffers( + S32 channel, + const U8* src, + S32 len, + std::vector<LLSegment>& segments); protected: - S32 mNextBaseChannel; - buffer_list_t mBuffers; - segment_list_t mSegments; - LLMutex* mMutexp; + S32 mNextBaseChannel; + buffer_list_t mBuffers; + segment_list_t mSegments; + LLMutex* mMutexp; }; #endif // LL_LLBUFFER_H diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp index 39508c1c52..e51b489813 100644 --- a/indra/llmessage/llbufferstream.cpp +++ b/indra/llmessage/llbufferstream.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llbufferstream.cpp * @author Phoenix * @date 2005-10-10 @@ -7,21 +7,21 @@ * $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$ */ @@ -39,291 +39,291 @@ static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4; * LLBufferStreamBuf */ LLBufferStreamBuf::LLBufferStreamBuf( - const LLChannelDescriptors& channels, - LLBufferArray* buffer) : - mChannels(channels), - mBuffer(buffer) + const LLChannelDescriptors& channels, + LLBufferArray* buffer) : + mChannels(channels), + mBuffer(buffer) { } LLBufferStreamBuf::~LLBufferStreamBuf() { - sync(); + sync(); } // virtual int LLBufferStreamBuf::underflow() { - //LL_DEBUGS() << "LLBufferStreamBuf::underflow()" << LL_ENDL; - if(!mBuffer) - { - return EOF; - } + //LL_DEBUGS() << "LLBufferStreamBuf::underflow()" << LL_ENDL; + if(!mBuffer) + { + return EOF; + } - LLMutexLock lock(mBuffer->getMutex()); - LLBufferArray::segment_iterator_t iter; - LLBufferArray::segment_iterator_t end = mBuffer->endSegment(); - U8* last_pos = (U8*)gptr(); - LLSegment segment; - if(last_pos) - { - // Back up into a piece of memory we know that we have - // allocated so that calls for the next segment based on - // 'after' will succeed. - --last_pos; - iter = mBuffer->splitAfter(last_pos); - if(iter != end) - { - // We need to clear the read segment just in case we have - // an early exit in the function and never collect the - // next segment. Calling eraseSegment() with the same - // segment twice is just like double deleting -- nothing - // good comes from it. - mBuffer->eraseSegment(iter++); - if(iter != end) segment = (*iter); - } - else - { - // This should never really happen, but somehow, the - // istream is telling the buf that it just finished - // reading memory that is not in the buf. I think this - // would only happen if there were a bug in the c++ stream - // class. Just bail. - // *TODO: can we set the fail bit on the stream somehow? - return EOF; - } - } - else - { - // Get iterator to full segment containing last_pos - // and construct sub-segment starting at last_pos. - // Note: segment may != *it at this point - iter = mBuffer->constructSegmentAfter(last_pos, segment); - } - if(iter == end) - { - return EOF; - } + LLMutexLock lock(mBuffer->getMutex()); + LLBufferArray::segment_iterator_t iter; + LLBufferArray::segment_iterator_t end = mBuffer->endSegment(); + U8* last_pos = (U8*)gptr(); + LLSegment segment; + if(last_pos) + { + // Back up into a piece of memory we know that we have + // allocated so that calls for the next segment based on + // 'after' will succeed. + --last_pos; + iter = mBuffer->splitAfter(last_pos); + if(iter != end) + { + // We need to clear the read segment just in case we have + // an early exit in the function and never collect the + // next segment. Calling eraseSegment() with the same + // segment twice is just like double deleting -- nothing + // good comes from it. + mBuffer->eraseSegment(iter++); + if(iter != end) segment = (*iter); + } + else + { + // This should never really happen, but somehow, the + // istream is telling the buf that it just finished + // reading memory that is not in the buf. I think this + // would only happen if there were a bug in the c++ stream + // class. Just bail. + // *TODO: can we set the fail bit on the stream somehow? + return EOF; + } + } + else + { + // Get iterator to full segment containing last_pos + // and construct sub-segment starting at last_pos. + // Note: segment may != *it at this point + iter = mBuffer->constructSegmentAfter(last_pos, segment); + } + if(iter == end) + { + return EOF; + } - // Iterate through segments to find a non-empty segment on input channel. - while((!segment.isOnChannel(mChannels.in()) || (segment.size() == 0))) - { - ++iter; - if(iter == end) - { - return EOF; - } + // Iterate through segments to find a non-empty segment on input channel. + while((!segment.isOnChannel(mChannels.in()) || (segment.size() == 0))) + { + ++iter; + if(iter == end) + { + return EOF; + } - segment = *(iter); - } + segment = *(iter); + } - // set up the stream to read from the next segment. - char* start = (char*)segment.data(); - setg(start, start, start + segment.size()); - return *gptr(); + // set up the stream to read from the next segment. + char* start = (char*)segment.data(); + setg(start, start, start + segment.size()); + return *gptr(); } // virtual int LLBufferStreamBuf::overflow(int c) { - if(!mBuffer) - { - return EOF; - } - if(EOF == c) - { - // if someone puts an EOF, I suppose we should sync and return - // success. - if(0 == sync()) - { - return 1; - } - else - { - return EOF; - } - } + if(!mBuffer) + { + return EOF; + } + if(EOF == c) + { + // if someone puts an EOF, I suppose we should sync and return + // success. + if(0 == sync()) + { + return 1; + } + else + { + return EOF; + } + } - // since we got here, we have a buffer, and we have a character to - // put on it. - LLBufferArray::segment_iterator_t it; - LLMutexLock lock(mBuffer->getMutex()); - it = mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE); - if(it != mBuffer->endSegment()) - { - char* start = (char*)(*it).data(); - (*start) = (char)(c); - setp(start + 1, start + (*it).size()); - return c; - } - else - { - return EOF; - } + // since we got here, we have a buffer, and we have a character to + // put on it. + LLBufferArray::segment_iterator_t it; + LLMutexLock lock(mBuffer->getMutex()); + it = mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE); + if(it != mBuffer->endSegment()) + { + char* start = (char*)(*it).data(); + (*start) = (char)(c); + setp(start + 1, start + (*it).size()); + return c; + } + else + { + return EOF; + } } // virtual int LLBufferStreamBuf::sync() { - int return_value = -1; - if(!mBuffer) - { - return return_value; - } + int return_value = -1; + if(!mBuffer) + { + return return_value; + } - // This chunk of code is not necessary because typically, users of - // the stream will read until EOF. Therefore, underflow was called - // and the segment was discarded before the sync() was called in - // the destructor. Theoretically, we could keep some more data - // around and detect the rare case where an istream was deleted - // before reading to the end, but that will only leave behind some - // unavailable but still referenced memory. Also, if another - // istream is constructed, it will re-read that segment, and then - // discard it. - //U8* last_pos = (U8*)gptr(); - //if(last_pos) - //{ - // // Looks like we read something. Discard what we have read. - // // gptr() actually returns the currrent position, but we call - // // it last_pos because of how it is used in the split call - // // below. - // --last_pos; - // LLBufferArray::segment_iterator_t iter; - // iter = mBuffer->splitAfter(last_pos); - // if(iter != mBuffer->endSegment()) - // { - // // We need to clear the read segment just in case we have - // // an early exit in the function and never collect the - // // next segment. Calling eraseSegment() with the same - // // segment twice is just like double deleting -- nothing - // // good comes from it. - // mBuffer->eraseSegment(iter); - // } - //} + // This chunk of code is not necessary because typically, users of + // the stream will read until EOF. Therefore, underflow was called + // and the segment was discarded before the sync() was called in + // the destructor. Theoretically, we could keep some more data + // around and detect the rare case where an istream was deleted + // before reading to the end, but that will only leave behind some + // unavailable but still referenced memory. Also, if another + // istream is constructed, it will re-read that segment, and then + // discard it. + //U8* last_pos = (U8*)gptr(); + //if(last_pos) + //{ + // // Looks like we read something. Discard what we have read. + // // gptr() actually returns the currrent position, but we call + // // it last_pos because of how it is used in the split call + // // below. + // --last_pos; + // LLBufferArray::segment_iterator_t iter; + // iter = mBuffer->splitAfter(last_pos); + // if(iter != mBuffer->endSegment()) + // { + // // We need to clear the read segment just in case we have + // // an early exit in the function and never collect the + // // next segment. Calling eraseSegment() with the same + // // segment twice is just like double deleting -- nothing + // // good comes from it. + // mBuffer->eraseSegment(iter); + // } + //} - // set the put pointer so that we force an overflow on the next - // write. - U8* address = (U8*)pptr(); - setp(NULL, NULL); + // set the put pointer so that we force an overflow on the next + // write. + U8* address = (U8*)pptr(); + setp(NULL, NULL); - // *NOTE: I bet we could just --address if address is not NULL. - // Need to think about that. - LLMutexLock lock(mBuffer->getMutex()); - address = mBuffer->seek(mChannels.out(), address, -1); - if(address) - { - LLBufferArray::segment_iterator_t it; - it = mBuffer->splitAfter(address); - LLBufferArray::segment_iterator_t end = mBuffer->endSegment(); - if(it != end) - { - ++it; - if(it != end) - { - mBuffer->eraseSegment(it); - } - return_value = 0; - } - } - else - { - // nothing was put on the buffer, so the sync() is a no-op. - return_value = 0; - } - return return_value; + // *NOTE: I bet we could just --address if address is not NULL. + // Need to think about that. + LLMutexLock lock(mBuffer->getMutex()); + address = mBuffer->seek(mChannels.out(), address, -1); + if(address) + { + LLBufferArray::segment_iterator_t it; + it = mBuffer->splitAfter(address); + LLBufferArray::segment_iterator_t end = mBuffer->endSegment(); + if(it != end) + { + ++it; + if(it != end) + { + mBuffer->eraseSegment(it); + } + return_value = 0; + } + } + else + { + // nothing was put on the buffer, so the sync() is a no-op. + return_value = 0; + } + return return_value; } // virtual #if( LL_WINDOWS || __GNUC__ > 2) LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff( - LLBufferStreamBuf::off_type off, - std::ios::seekdir way, - std::ios::openmode which) + LLBufferStreamBuf::off_type off, + std::ios::seekdir way, + std::ios::openmode which) #else streampos LLBufferStreamBuf::seekoff( - streamoff off, - std::ios::seekdir way, - std::ios::openmode which) + streamoff off, + std::ios::seekdir way, + std::ios::openmode which) #endif { - if(!mBuffer - || ((way == std::ios::beg) && (off < 0)) - || ((way == std::ios::end) && (off > 0))) - { - return -1; - } - U8* address = NULL; - if(which & std::ios::in) - { - U8* base_addr = NULL; - switch(way) - { - case std::ios::end: - base_addr = (U8*)LLBufferArray::npos; - break; - case std::ios::cur: - // get the current get pointer and adjust it for buffer - // array semantics. - base_addr = (U8*)gptr(); - break; - case std::ios::beg: - default: - // NULL is fine - break; - } + if(!mBuffer + || ((way == std::ios::beg) && (off < 0)) + || ((way == std::ios::end) && (off > 0))) + { + return -1; + } + U8* address = NULL; + if(which & std::ios::in) + { + U8* base_addr = NULL; + switch(way) + { + case std::ios::end: + base_addr = (U8*)LLBufferArray::npos; + break; + case std::ios::cur: + // get the current get pointer and adjust it for buffer + // array semantics. + base_addr = (U8*)gptr(); + break; + case std::ios::beg: + default: + // NULL is fine + break; + } - LLMutexLock lock(mBuffer->getMutex()); - address = mBuffer->seek(mChannels.in(), base_addr, off); - if(address) - { - LLBufferArray::segment_iterator_t iter; - iter = mBuffer->getSegment(address); - char* start = (char*)(*iter).data(); - setg(start, (char*)address, start + (*iter).size()); - } - else - { - address = (U8*)(-1); - } - } - if(which & std::ios::out) - { - U8* base_addr = NULL; - switch(way) - { - case std::ios::end: - base_addr = (U8*)LLBufferArray::npos; - break; - case std::ios::cur: - // get the current put pointer and adjust it for buffer - // array semantics. - base_addr = (U8*)pptr(); - break; - case std::ios::beg: - default: - // NULL is fine - break; - } + LLMutexLock lock(mBuffer->getMutex()); + address = mBuffer->seek(mChannels.in(), base_addr, off); + if(address) + { + LLBufferArray::segment_iterator_t iter; + iter = mBuffer->getSegment(address); + char* start = (char*)(*iter).data(); + setg(start, (char*)address, start + (*iter).size()); + } + else + { + address = (U8*)(-1); + } + } + if(which & std::ios::out) + { + U8* base_addr = NULL; + switch(way) + { + case std::ios::end: + base_addr = (U8*)LLBufferArray::npos; + break; + case std::ios::cur: + // get the current put pointer and adjust it for buffer + // array semantics. + base_addr = (U8*)pptr(); + break; + case std::ios::beg: + default: + // NULL is fine + break; + } - LLMutexLock lock(mBuffer->getMutex()); - address = mBuffer->seek(mChannels.out(), base_addr, off); - if(address) - { - LLBufferArray::segment_iterator_t iter; - iter = mBuffer->getSegment(address); - setp((char*)address, (char*)(*iter).data() + (*iter).size()); - } - else - { - address = (U8*)(-1); - } - } + LLMutexLock lock(mBuffer->getMutex()); + address = mBuffer->seek(mChannels.out(), base_addr, off); + if(address) + { + LLBufferArray::segment_iterator_t iter; + iter = mBuffer->getSegment(address); + setp((char*)address, (char*)(*iter).data() + (*iter).size()); + } + else + { + address = (U8*)(-1); + } + } #if( LL_WINDOWS || __GNUC__ > 2 ) - S32 rv = (S32)(intptr_t)address; - return (pos_type)rv; + S32 rv = (S32)(intptr_t)address; + return (pos_type)rv; #else - return (streampos)address; + return (streampos)address; #endif } @@ -332,10 +332,10 @@ streampos LLBufferStreamBuf::seekoff( * LLBufferStream */ LLBufferStream::LLBufferStream( - const LLChannelDescriptors& channels, - LLBufferArray* buffer) : - std::iostream(&mStreamBuf), - mStreamBuf(channels, buffer) + const LLChannelDescriptors& channels, + LLBufferArray* buffer) : + std::iostream(&mStreamBuf), + mStreamBuf(channels, buffer) { } diff --git a/indra/llmessage/llbufferstream.h b/indra/llmessage/llbufferstream.h index 19749612f3..ac1aa49e81 100644 --- a/indra/llmessage/llbufferstream.h +++ b/indra/llmessage/llbufferstream.h @@ -1,4 +1,4 @@ -/** +/** * @file llbufferstream.h * @author Phoenix * @date 2005-10-10 @@ -7,21 +7,21 @@ * $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$ */ @@ -33,7 +33,7 @@ #include <iostream> #include "llbuffer.h" -/** +/** * @class LLBufferStreamBuf * @brief This implements the buffer wrapper for an istream * @@ -42,92 +42,92 @@ class LLBufferStreamBuf : public std::streambuf { public: - LLBufferStreamBuf( - const LLChannelDescriptors& channels, - LLBufferArray* buffer); - virtual ~LLBufferStreamBuf(); + LLBufferStreamBuf( + const LLChannelDescriptors& channels, + LLBufferArray* buffer); + virtual ~LLBufferStreamBuf(); protected: #if( LL_WINDOWS || __GNUC__ > 2 ) - typedef std::streambuf::pos_type pos_type; - typedef std::streambuf::off_type off_type; + typedef std::streambuf::pos_type pos_type; + typedef std::streambuf::off_type off_type; #endif - /* @name streambuf vrtual implementations - */ - //@{ - /* - * @brief called when we hit the end of input - * - * @return Returns the character at the current position or EOF. - */ - virtual int underflow(); - - /* - * @brief called when we hit the end of output - * - * @param c The character to store at the current put position - * @return Returns EOF if the function failed. Any other value on success. - */ - virtual int overflow(int c); - - /* - * @brief synchronize the buffer - * - * @return Returns 0 on success or -1 on failure. - */ - virtual int sync(); - - /* - * @brief Seek to an offset position in a stream. - * - * @param off Offset value relative to way paramter - * @param way The seek direction. One of ios::beg, ios::cur, and ios::end. - * @param which Which pointer to modify. One of ios::in, ios::out, - * or both masked together. - * @return Returns the new position or an invalid position on failure. - */ + /* @name streambuf vrtual implementations + */ + //@{ + /* + * @brief called when we hit the end of input + * + * @return Returns the character at the current position or EOF. + */ + virtual int underflow(); + + /* + * @brief called when we hit the end of output + * + * @param c The character to store at the current put position + * @return Returns EOF if the function failed. Any other value on success. + */ + virtual int overflow(int c); + + /* + * @brief synchronize the buffer + * + * @return Returns 0 on success or -1 on failure. + */ + virtual int sync(); + + /* + * @brief Seek to an offset position in a stream. + * + * @param off Offset value relative to way paramter + * @param way The seek direction. One of ios::beg, ios::cur, and ios::end. + * @param which Which pointer to modify. One of ios::in, ios::out, + * or both masked together. + * @return Returns the new position or an invalid position on failure. + */ #if( LL_WINDOWS || __GNUC__ > 2) - virtual pos_type seekoff( - off_type off, - std::ios::seekdir way, - std::ios::openmode which); + virtual pos_type seekoff( + off_type off, + std::ios::seekdir way, + std::ios::openmode which); #else - virtual streampos seekoff( - streamoff off, - std::ios::seekdir way, - std::ios::openmode which); + virtual streampos seekoff( + streamoff off, + std::ios::seekdir way, + std::ios::openmode which); #endif - /* - * @brief Get s sequence of characters from the input - * - * @param dst Pointer to a block of memory to accept the characters - * @param length Number of characters to be read - * @return Returns the number of characters read - */ - //virtual streamsize xsgetn(char* dst, streamsize length); - - /* - * @brief Write some characters to output - * - * @param src Pointer to a sequence of characters to be output - * @param length Number of characters to be put - * @return Returns the number of characters written - */ - //virtual streamsize xsputn(char* src, streamsize length); - //@} + /* + * @brief Get s sequence of characters from the input + * + * @param dst Pointer to a block of memory to accept the characters + * @param length Number of characters to be read + * @return Returns the number of characters read + */ + //virtual streamsize xsgetn(char* dst, streamsize length); + + /* + * @brief Write some characters to output + * + * @param src Pointer to a sequence of characters to be output + * @param length Number of characters to be put + * @return Returns the number of characters written + */ + //virtual streamsize xsputn(char* src, streamsize length); + //@} protected: - // This channels we are working on. - LLChannelDescriptors mChannels; + // This channels we are working on. + LLChannelDescriptors mChannels; - // The buffer we work on - LLBufferArray* mBuffer; + // The buffer we work on + LLBufferArray* mBuffer; }; -/** +/** * @class LLBufferStream * @brief This implements an istream based wrapper around an LLBufferArray. * @@ -139,13 +139,13 @@ protected: class LLBufferStream : public std::iostream { public: - LLBufferStream( - const LLChannelDescriptors& channels, - LLBufferArray* buffer); - ~LLBufferStream(); + LLBufferStream( + const LLChannelDescriptors& channels, + LLBufferArray* buffer); + ~LLBufferStream(); protected: - LLBufferStreamBuf mStreamBuf; + LLBufferStreamBuf mStreamBuf; }; diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 5b4f9aded7..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(); } -}; - -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 8091248151..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 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 +/**
+ * @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/llchainio.cpp b/indra/llmessage/llchainio.cpp index bcda6746a1..78dff246cb 100644 --- a/indra/llmessage/llchainio.cpp +++ b/indra/llmessage/llchainio.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llchainio.cpp * @author Phoenix * @date 2005-08-04 @@ -7,21 +7,21 @@ * $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$ */ @@ -38,20 +38,20 @@ */ // static bool LLDeferredChain::addToPump( - LLPumpIO* pump, - F32 in_seconds, - const LLPumpIO::chain_t& deferred_chain, - F32 chain_timeout) + LLPumpIO* pump, + F32 in_seconds, + const LLPumpIO::chain_t& deferred_chain, + F32 chain_timeout) { - if(!pump) return false; - LLPumpIO::chain_t sleep_chain; - sleep_chain.push_back(LLIOPipe::ptr_t(new LLIOSleep(in_seconds))); - sleep_chain.push_back( - LLIOPipe::ptr_t(new LLIOAddChain(deferred_chain, chain_timeout))); + if(!pump) return false; + LLPumpIO::chain_t sleep_chain; + sleep_chain.push_back(LLIOPipe::ptr_t(new LLIOSleep(in_seconds))); + sleep_chain.push_back( + LLIOPipe::ptr_t(new LLIOAddChain(deferred_chain, chain_timeout))); - // give it a litle bit of padding. - pump->addChain(sleep_chain, in_seconds + 10.0f); - return true; + // give it a litle bit of padding. + pump->addChain(sleep_chain, in_seconds + 10.0f); + return true; } /** @@ -69,20 +69,20 @@ LLChainIOFactory::~LLChainIOFactory() #if 0 bool LLChainIOFactory::build(LLIOPipe* in, LLIOPipe* out) const { - if(!in || !out) - { - return false; - } - LLIOPipe* first = NULL; - LLIOPipe* last = NULL; - if(build_impl(first, last) && first && last) - { - in->connect(first); - last->connect(out); - return true; - } - LLIOPipe::ptr_t foo(first); - LLIOPipe::ptr_t bar(last); - return false; + if(!in || !out) + { + return false; + } + LLIOPipe* first = NULL; + LLIOPipe* last = NULL; + if(build_impl(first, last) && first && last) + { + in->connect(first); + last->connect(out); + return true; + } + LLIOPipe::ptr_t foo(first); + LLIOPipe::ptr_t bar(last); + return false; } #endif diff --git a/indra/llmessage/llchainio.h b/indra/llmessage/llchainio.h index 6e4d6c2013..3f12189214 100644 --- a/indra/llmessage/llchainio.h +++ b/indra/llmessage/llchainio.h @@ -1,4 +1,4 @@ -/** +/** * @file llchainio.h * @author Phoenix * @date 2005-08-04 @@ -7,21 +7,21 @@ * $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$ */ @@ -31,7 +31,7 @@ #include "llpumpio.h" -/** +/** * @class LLDeferredChain * @brief This class allows easy addition of a chain which will sleep * and then process another chain. @@ -39,23 +39,23 @@ class LLDeferredChain { public: - /** - * @brief Add a chain to a pump in a finite # of seconds - * - * @prarm pump The pump to work on. - * @prarm in_seconds The number of seconds from now when chain should start. - * @prarm chain The chain to add in in_seconds seconds. - * @prarm chain_timeout timeout for chain on the pump. - * @return Returns true if the operation was queued. - */ - static bool addToPump( - LLPumpIO* pump, - F32 in_seconds, - const LLPumpIO::chain_t& chain, - F32 chain_timeout); + /** + * @brief Add a chain to a pump in a finite # of seconds + * + * @prarm pump The pump to work on. + * @prarm in_seconds The number of seconds from now when chain should start. + * @prarm chain The chain to add in in_seconds seconds. + * @prarm chain_timeout timeout for chain on the pump. + * @return Returns true if the operation was queued. + */ + static bool addToPump( + LLPumpIO* pump, + F32 in_seconds, + const LLPumpIO::chain_t& chain, + F32 chain_timeout); }; -/** +/** * @class LLChainIOFactory * @brief This class is an abstract base class for building io chains. * @@ -71,29 +71,29 @@ public: class LLChainIOFactory { public: - // Constructor - LLChainIOFactory(); + // Constructor + LLChainIOFactory(); - // Destructor - virtual ~LLChainIOFactory(); + // Destructor + virtual ~LLChainIOFactory(); - /** - * @brief Build the chian with in as the first and end as the last - * - * The caller of the LLChainIOFactory is responsible for managing - * the memory of the in pipe. All of the chains generated by the - * factory will be ref counted as usual, so the caller will also - * need to break the links in the chain. - * @param chain The chain which will have new pipes appended - * @param context A context for use by this factory if you choose - * @retrun Returns true if the call was successful. - */ - virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const = 0; + /** + * @brief Build the chian with in as the first and end as the last + * + * The caller of the LLChainIOFactory is responsible for managing + * the memory of the in pipe. All of the chains generated by the + * factory will be ref counted as usual, so the caller will also + * need to break the links in the chain. + * @param chain The chain which will have new pipes appended + * @param context A context for use by this factory if you choose + * @retrun Returns true if the call was successful. + */ + virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const = 0; protected: }; -/** +/** * @class LLSimpleIOFactory * @brief Basic implementation for making a factory that returns a * 'chain' of one object @@ -102,14 +102,14 @@ template<class Pipe> class LLSimpleIOFactory : public LLChainIOFactory { public: - virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const - { - chain.push_back(LLIOPipe::ptr_t(new Pipe)); - return true; - } + virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const + { + chain.push_back(LLIOPipe::ptr_t(new Pipe)); + return true; + } }; -/** +/** * @class LLCloneIOFactory * @brief Implementation for a facory which copies a particular pipe. */ @@ -117,19 +117,19 @@ template<class Pipe> class LLCloneIOFactory : public LLChainIOFactory { public: - LLCloneIOFactory(Pipe* original) : - mHandle(original), - mOriginal(original) {} + LLCloneIOFactory(Pipe* original) : + mHandle(original), + mOriginal(original) {} - virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const - { - chain.push_back(LLIOPipe::ptr_t(new Pipe(*mOriginal))); - return true; - } + virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const + { + chain.push_back(LLIOPipe::ptr_t(new Pipe(*mOriginal))); + return true; + } protected: - LLIOPipe::ptr_t mHandle; - Pipe* mOriginal; + LLIOPipe::ptr_t mHandle; + Pipe* mOriginal; }; #endif // LL_LLCHAINIO_H diff --git a/indra/llmessage/llcipher.h b/indra/llmessage/llcipher.h index b3f142c001..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 a0bf999dee..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 95e470b543..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 bf8c9171a7..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 9298b90357..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/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index c0a5e361b1..959cfb2762 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -41,7 +41,7 @@ //========================================================================= // Map of pool sizes for known pools static const std::map<std::string, U32> DefaultPoolSizes{ - {std::string("Upload"), 1}, + {std::string("Upload"), 1}, {std::string("AIS"), 1}, // *TODO: Rider for the moment keep AIS calls serialized otherwise the COF will tend to get out of sync. }; @@ -61,11 +61,11 @@ public: LLCoprocedurePool(const std::string &name, size_t size); ~LLCoprocedurePool(); - /// Places the coprocedure on the queue for processing. - /// + /// Places the coprocedure on the queue for processing. + /// /// @param name Is used for debugging and should identify this coroutine. - /// @param proc Is a bound function to be executed - /// + /// @param proc Is a bound function to be executed + /// /// @return This method returns a UUID that can be used later to cancel execution. LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc); @@ -91,7 +91,7 @@ public: } void close(); - + private: struct QueuedCoproc { @@ -108,7 +108,7 @@ private: CoProcedure_t mProc; }; - // we use a buffered_channel here rather than unbuffered_channel since we want to be able to + // we use a buffered_channel here rather than unbuffered_channel since we want to be able to // push values without blocking,even if there's currently no one calling a pop operation (due to // fiber running right now) typedef boost::fibers::buffered_channel<QueuedCoproc::ptr_t> CoprocQueue_t; @@ -167,7 +167,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) if (size == 0) { - // if not found grab the know default... if there is no known + // if not found grab the know default... if there is no known // default use a reasonable number like 5. auto it = DefaultPoolSizes.find(poolName); size = (it != DefaultPoolSizes.end()) ? it->second : DEFAULT_POOL_SIZE; @@ -190,7 +190,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) //------------------------------------------------------------------------- LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc) { - // Attempt to find the pool and enqueue the procedure. If the pool does + // Attempt to find the pool and enqueue the procedure. If the pool does // not exist, create it. poolMap_t::iterator it = mPoolMap.find(pool); @@ -355,7 +355,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL; } -LLCoprocedurePool::~LLCoprocedurePool() +LLCoprocedurePool::~LLCoprocedurePool() { } diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h index c5bc37dd0e..6c6e506654 100644 --- a/indra/llmessage/llcoproceduremanager.h +++ b/indra/llmessage/llcoproceduremanager.h @@ -46,15 +46,15 @@ public: typedef boost::function<void(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, const LLUUID &id)> CoProcedure_t; - /// Places the coprocedure on the queue for processing. - /// + /// Places the coprocedure on the queue for processing. + /// /// @param name Is used for debugging and should identify this coroutine. - /// @param proc Is a bound function to be executed - /// + /// @param proc Is a bound function to be executed + /// /// @return This method returns a UUID that can be used later to cancel execution. LLUUID enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc); - /// Cancel a coprocedure. If the coprocedure is already being actively executed + /// Cancel a coprocedure. If the coprocedure is already being actively executed /// this method calls cancelYieldingOperation() on the associated HttpAdapter /// If it has not yet been dequeued it is simply removed from the queue. //void cancelCoprocedure(const LLUUID &id); @@ -80,7 +80,7 @@ public: void close(const std::string &pool); void initializePool(const std::string &poolName); - + private: typedef std::shared_ptr<LLCoprocedurePool> poolPtr_t; diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index fc561c6b0f..45b673b9d5 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -1,4 +1,4 @@ -/** +/** * @file llcorehttputil.h * @date 2014-08-25 * @brief 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$ */ @@ -75,20 +75,20 @@ extern const F32 HTTP_REQUEST_EXPIRY_SECS; /// the output LLSD object, out_llsd, is written with the /// result and true is returned. /// -/// @arg response Response object as returned in -/// in an HttpHandler onCompleted() callback. -/// @arg log If true, LLSD parser will emit errors -/// as LL_INFOS-level messages as it parses. -/// Otherwise, it *should* be a quiet parse. -/// @arg out_llsd Output LLSD object written only upon -/// successful parse of the response object. +/// @arg response Response object as returned in +/// in an HttpHandler onCompleted() callback. +/// @arg log If true, LLSD parser will emit errors +/// as LL_INFOS-level messages as it parses. +/// Otherwise, it *should* be a quiet parse. +/// @arg out_llsd Output LLSD object written only upon +/// successful parse of the response object. /// -/// @return Returns true (and writes to out_llsd) if -/// parse was successful. False otherwise. +/// @return Returns true (and writes to out_llsd) if +/// parse was successful. False otherwise. /// bool responseToLLSD(LLCore::HttpResponse * response, - bool log, - LLSD & out_llsd); + bool log, + LLSD & out_llsd); /// Create a std::string representation of a response object /// suitable for logging. Mainly intended for logging of @@ -104,15 +104,15 @@ std::string responseToString(LLCore::HttpResponse * response); /// One will not be provided by this call. You might look after /// the 'Accept:' header as well. /// -/// @return If request is successfully issued, the -/// HttpHandle representing the request. -/// On error, LLCORE_HTTP_HANDLE_INVALID -/// is returned and caller can fetch detailed -/// status with the getStatus() method on the -/// request object. In case of error, no -/// request is queued and caller may need to -/// perform additional cleanup such as freeing -/// a now-useless HttpHandler object. +/// @return If request is successfully issued, the +/// HttpHandle representing the request. +/// On error, LLCORE_HTTP_HANDLE_INVALID +/// is returned and caller can fetch detailed +/// status with the getStatus() method on the +/// request object. In case of error, no +/// request is queued and caller may need to +/// perform additional cleanup such as freeing +/// a now-useless HttpHandler object. /// LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request, LLCore::HttpRequest::policy_t policy_id, @@ -123,11 +123,11 @@ LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request, const LLCore::HttpHandler::ptr_t &handler); inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request, - LLCore::HttpRequest::policy_t policy_id, - const std::string & url, - const LLSD & body, - const LLCore::HttpOptions::ptr_t & options, - const LLCore::HttpHeaders::ptr_t & headers, + LLCore::HttpRequest::policy_t policy_id, + const std::string & url, + const LLSD & body, + const LLCore::HttpOptions::ptr_t & options, + const LLCore::HttpHeaders::ptr_t & headers, const LLCore::HttpHandler::ptr_t & handler) { return requestPostWithLLSD(request.get(), policy_id, @@ -154,30 +154,30 @@ inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & reque /// an HttpHeaders object with a correct 'Content-Type:' header. /// One will not be provided by this call. /// -/// @return If request is successfully issued, the -/// HttpHandle representing the request. -/// On error, LLCORE_HTTP_HANDLE_INVALID -/// is returned and caller can fetch detailed -/// status with the getStatus() method on the -/// request object. In case of error, no -/// request is queued and caller may need to -/// perform additional cleanup such as freeing -/// a now-useless HttpHandler object. +/// @return If request is successfully issued, the +/// HttpHandle representing the request. +/// On error, LLCORE_HTTP_HANDLE_INVALID +/// is returned and caller can fetch detailed +/// status with the getStatus() method on the +/// request object. In case of error, no +/// request is queued and caller may need to +/// perform additional cleanup such as freeing +/// a now-useless HttpHandler object. /// LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request, - LLCore::HttpRequest::policy_t policy_id, - const std::string & url, - const LLSD & body, - const LLCore::HttpOptions::ptr_t &options, - const LLCore::HttpHeaders::ptr_t &headers, + LLCore::HttpRequest::policy_t policy_id, + const std::string & url, + const LLSD & body, + const LLCore::HttpOptions::ptr_t &options, + const LLCore::HttpHeaders::ptr_t &headers, const LLCore::HttpHandler::ptr_t &handler); inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request, - LLCore::HttpRequest::policy_t policy_id, - const std::string & url, - const LLSD & body, - const LLCore::HttpOptions::ptr_t & options, - const LLCore::HttpHeaders::ptr_t & headers, + LLCore::HttpRequest::policy_t policy_id, + const std::string & url, + const LLSD & body, + const LLCore::HttpOptions::ptr_t & options, + const LLCore::HttpHeaders::ptr_t & headers, LLCore::HttpHandler::ptr_t handler) { return requestPutWithLLSD(request.get(), policy_id, @@ -203,15 +203,15 @@ inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & reques /// an HttpHeaders object with a correct 'Content-Type:' header. /// One will not be provided by this call. /// -/// @return If request is successfully issued, the -/// HttpHandle representing the request. -/// On error, LLCORE_HTTP_HANDLE_INVALID -/// is returned and caller can fetch detailed -/// status with the getStatus() method on the -/// request object. In case of error, no -/// request is queued and caller may need to -/// perform additional cleanup such as freeing -/// a now-useless HttpHandler object. +/// @return If request is successfully issued, the +/// HttpHandle representing the request. +/// On error, LLCORE_HTTP_HANDLE_INVALID +/// is returned and caller can fetch detailed +/// status with the getStatus() method on the +/// request object. In case of error, no +/// request is queued and caller may need to +/// perform additional cleanup such as freeing +/// a now-useless HttpHandler object. /// LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest * request, LLCore::HttpRequest::policy_t policy_id, @@ -247,10 +247,10 @@ inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & requ } //========================================================================= -/// The HttpCoroHandler is a specialization of the LLCore::HttpHandler for -/// interacting with coroutines. When the request is completed the response +/// The HttpCoroHandler 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. -/// +/// /// 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 @@ -258,7 +258,7 @@ inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & requ /// +- ["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 HttpCoroHandler : public LLCore::HttpHandler { public: @@ -289,21 +289,21 @@ private: }; //========================================================================= -/// An adapter to handle some of the boilerplate code surrounding HTTP and coroutine +/// An adapter to handle some of the boilerplate code surrounding HTTP and coroutine /// interaction. -/// -/// Construct an HttpCoroutineAdapter giving it a name and policy Id. After -/// any application specific setup call the post, put or get method. The request +/// +/// Construct an HttpCoroutineAdapter giving it a name and policy Id. After +/// any application specific setup call the post, put or get method. The request /// will be automatically pumped and the method will return with an LLSD describing -/// the result of the operation. See HttpCoroHandler for a description of the +/// the result of the operation. See HttpCoroHandler for a description of the /// decoration done to the returned LLSD. -/// -/// Posting through the adapter will automatically add the following headers to -/// the request if they have not been previously specified in a supplied +/// +/// Posting through the adapter will automatically add the following headers to +/// the request if they have not been previously specified in a supplied /// HttpHeaders object: /// "Accept=application/llsd+xml" /// "X-SecondLife-UDP-Listen-Port=###" -/// +/// class HttpCoroutineAdapter { public: @@ -323,9 +323,9 @@ public: HttpCoroutineAdapter(const std::string &name, LLCore::HttpRequest::policy_t policyId); ~HttpCoroutineAdapter(); - /// Execute a Post transaction on the supplied URL and yield execution of - /// the coroutine until a result is available. - /// + /// Execute a Post transaction on the supplied URL and yield execution of + /// the coroutine until a result is available. + /// /// @Note: the request's smart pointer is passed by value so that it will /// not be deallocated during the yield. LLSD postAndSuspend(LLCore::HttpRequest::ptr_t request, @@ -407,9 +407,9 @@ public: - /// Execute a Put transaction on the supplied URL and yield execution of + /// Execute a Put transaction on the supplied URL and yield execution of /// the coroutine until a result is available. - /// + /// /// @Note: the request's smart pointer is passed by value so that it will /// not be deallocated during the yield. LLSD putAndSuspend(LLCore::HttpRequest::ptr_t request, @@ -437,12 +437,12 @@ public: LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); } - /// Execute a Get transaction on the supplied URL and yield execution of + /// Execute a Get transaction on the supplied URL and yield execution of /// the coroutine until a result is available. - /// + /// /// @Note: the request's smart pointer is passed by value so that it will /// not be deallocated during the yield. - /// + /// LLSD getAndSuspend(LLCore::HttpRequest::ptr_t request, const std::string & url, LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), @@ -467,9 +467,9 @@ public: headers); } - /// These methods have the same behavior as @getAndSuspend() however they are - /// expecting the server to return the results formatted in a JSON string. - /// On a successful GET call the JSON results will be converted into LLSD + /// These methods have the same behavior as @getAndSuspend() however they are + /// expecting the server to return the results formatted in a JSON string. + /// On a successful GET call the JSON results will be converted into LLSD /// before being returned to the caller. LLSD getJsonAndSuspend(LLCore::HttpRequest::ptr_t request, const std::string & url, @@ -484,9 +484,9 @@ public: } - /// Execute a DELETE transaction on the supplied URL and yield execution of + /// Execute a DELETE transaction on the supplied URL and yield execution of /// the coroutine until a result is available. - /// + /// /// @Note: the request's smart pointer is passed by value so that it will /// not be deallocated during the yield. LLSD deleteAndSuspend(LLCore::HttpRequest::ptr_t request, @@ -501,9 +501,9 @@ public: headers); } - /// These methods have the same behavior as @deleteAndSuspend() however they are - /// expecting the server to return any results formatted in a JSON string. - /// On a successful DELETE call the JSON results will be converted into LLSD + /// These methods have the same behavior as @deleteAndSuspend() however they are + /// expecting the server to return any results formatted in a JSON string. + /// On a successful DELETE call the JSON results will be converted into LLSD /// before being returned to the caller. LLSD deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request, const std::string & url, @@ -518,9 +518,9 @@ public: } - /// Execute a PATCH transaction on the supplied URL and yield execution of - /// the coroutine until a result is available. - /// + /// Execute a PATCH transaction on the supplied URL and yield execution of + /// the coroutine until a result is available. + /// /// @Note: the request's smart pointer is passed by value so that it will /// not be deallocated during the yield. LLSD patchAndSuspend(LLCore::HttpRequest::ptr_t request, @@ -535,12 +535,12 @@ public: LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); } - /// Execute a COPY transaction on the supplied URL and yield execution of - /// the coroutine until a result is available. - /// + /// Execute a COPY transaction on the supplied URL and yield execution of + /// the coroutine until a result is available. + /// /// @Note: The destination is passed through the HTTP pipe as a header /// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination"); - /// + /// /// @Note: the request's smart pointer is passed by value so that it will /// not be deallocated during the yield. LLSD copyAndSuspend(LLCore::HttpRequest::ptr_t request, @@ -555,12 +555,12 @@ public: LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); } - /// Execute a MOVE transaction on the supplied URL and yield execution of - /// the coroutine until a result is available. - /// + /// Execute a MOVE transaction on the supplied URL and yield execution of + /// the coroutine until a result is available. + /// /// @Note: The destination is passed through the HTTP pipe in the headers. /// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination"); - /// + /// /// @Note: the request's smart pointer is passed by value so that it will /// not be deallocated during the yield. LLSD moveAndSuspend(LLCore::HttpRequest::ptr_t request, @@ -580,7 +580,7 @@ public: static LLCore::HttpStatus getStatusFromLLSD(const LLSD &httpResults); - /// The convenience routines below can be provided with callback functors + /// The convenience routines below can be provided with callback functors /// which will be invoked in the case of success or failure. These callbacks /// should match this form. /// @sa callbackHttpGet @@ -603,9 +603,9 @@ public: /// Generic Get and post routines for HTTP via coroutines. /// These static methods do all required setup for the GET or POST operation. - /// When the operation completes successfully they will put the success message in the log at INFO level, + /// When the operation completes successfully they will put the success message in the log at INFO level, /// If the operation fails the failure message is written to the log at WARN level. - /// + /// static void messageHttpGet(const std::string &url, const std::string &success = std::string(), const std::string &failure = std::string()); static void messageHttpPost(const std::string &url, const LLSD &postData, const std::string &success, const std::string &failure); @@ -638,7 +638,7 @@ private: HttpCoroHandler::ptr_t &handler); LLSD getAndSuspend_(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); LLSD deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request, @@ -651,7 +651,7 @@ private: HttpCoroHandler::ptr_t &handler); LLSD 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); diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 1545443798..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 8e980d8611..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/lldbstrings.h b/indra/llmessage/lldbstrings.h index e23d17d5b6..cca407b03d 100644 --- a/indra/llmessage/lldbstrings.h +++ b/indra/llmessage/lldbstrings.h @@ -1,25 +1,25 @@ -/** +/** * @file lldbstrings.h * @brief Database String Lengths. * * $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$ */ @@ -32,25 +32,25 @@ * the size of the buffer large enough to hold each one) */ -// asset.name varchar(63) +// asset.name varchar(63) // -also- -// user_inventory_item.name varchar(63) +// user_inventory_item.name varchar(63) // -also- -// user_inventory_folder.name varchar(63) was CAT_NAME_SIZE +// user_inventory_folder.name varchar(63) was CAT_NAME_SIZE // Must be >= DB_FULL_NAME_STR_LEN so that calling cards work -const S32 DB_INV_ITEM_NAME_STR_LEN = 63; // was MAX_ASSET_NAME_LENGTH -const S32 DB_INV_ITEM_NAME_BUF_SIZE = 64; // was ITEM_NAME_SIZE +const S32 DB_INV_ITEM_NAME_STR_LEN = 63; // was MAX_ASSET_NAME_LENGTH +const S32 DB_INV_ITEM_NAME_BUF_SIZE = 64; // was ITEM_NAME_SIZE -// asset.description varchar(127) +// asset.description varchar(127) // -also- -// user_inventory_item.description varchar(127) -const S32 DB_INV_ITEM_DESC_STR_LEN = 127; // was MAX_ASSET_DESCRIPTION_LENGTH -const S32 DB_INV_ITEM_DESC_BUF_SIZE = 128; // was ITEM_DESC_SIZE +// user_inventory_item.description varchar(127) +const S32 DB_INV_ITEM_DESC_STR_LEN = 127; // was MAX_ASSET_DESCRIPTION_LENGTH +const S32 DB_INV_ITEM_DESC_BUF_SIZE = 128; // was ITEM_DESC_SIZE -// groups.name varchar(35) -const S32 DB_GROUP_NAME_STR_LEN = 35; -const S32 DB_GROUP_NAME_BUF_SIZE = 36; -const S32 DB_GROUP_NAME_MIN_LEN = 4; +// groups.name varchar(35) +const S32 DB_GROUP_NAME_STR_LEN = 35; +const S32 DB_GROUP_NAME_BUF_SIZE = 36; +const S32 DB_GROUP_NAME_MIN_LEN = 4; //group_roles.name const U32 DB_GROUP_ROLE_NAME_STR_LEN = 20; @@ -61,154 +61,154 @@ const U32 DB_GROUP_ROLE_TITLE_STR_LEN = 20; const U32 DB_GROUP_ROLE_TITLE_BUF_SIZE = DB_GROUP_ROLE_TITLE_STR_LEN + 1; -// group.charter text -const S32 DB_GROUP_CHARTER_STR_LEN = 511; -const S32 DB_GROUP_CHARTER_BUF_SIZE = 512; +// group.charter text +const S32 DB_GROUP_CHARTER_STR_LEN = 511; +const S32 DB_GROUP_CHARTER_BUF_SIZE = 512; -// group.officer_title varchar(20) +// group.officer_title varchar(20) // -also- -// group.member_title varchar(20) -const S32 DB_GROUP_TITLE_STR_LEN = 20; -const S32 DB_GROUP_TITLE_BUF_SIZE = 21; +// group.member_title varchar(20) +const S32 DB_GROUP_TITLE_STR_LEN = 20; +const S32 DB_GROUP_TITLE_BUF_SIZE = 21; // Since chat and im both dump into the database text message log, // they derive their max size from the same constant. const S32 MAX_MSG_STR_LEN = 1023; const S32 MAX_MSG_BUF_SIZE = 1024; -// instant_message.message text -const S32 DB_IM_MSG_STR_LEN = MAX_MSG_STR_LEN; -const S32 DB_IM_MSG_BUF_SIZE = MAX_MSG_BUF_SIZE; +// instant_message.message text +const S32 DB_IM_MSG_STR_LEN = MAX_MSG_STR_LEN; +const S32 DB_IM_MSG_BUF_SIZE = MAX_MSG_BUF_SIZE; // groupnotices -const S32 DB_GROUP_NOTICE_SUBJ_STR_LEN = 63; -const S32 DB_GROUP_NOTICE_SUBJ_STR_SIZE = 64; -const S32 DB_GROUP_NOTICE_MSG_STR_LEN = MAX_MSG_STR_LEN - DB_GROUP_NOTICE_SUBJ_STR_LEN; -const S32 DB_GROUP_NOTICE_MSG_STR_SIZE = MAX_MSG_BUF_SIZE - DB_GROUP_NOTICE_SUBJ_STR_SIZE; - -// log_text_message.message text -const S32 DB_CHAT_MSG_STR_LEN = MAX_MSG_STR_LEN; -const S32 DB_CHAT_MSG_BUF_SIZE = MAX_MSG_BUF_SIZE; - -// money_stipend.description varchar(254) -const S32 DB_STIPEND_DESC_STR_LEN = 254; -const S32 DB_STIPEND_DESC_BUF_SIZE = 255; - -// script_email_message.from_email varchar(78) -const S32 DB_EMAIL_FROM_STR_LEN = 78; -const S32 DB_EMAIL_FROM_BUF_SIZE = 79; - -// script_email_message.subject varchar(72) -const S32 DB_EMAIL_SUBJECT_STR_LEN = 72; -const S32 DB_EMAIL_SUBJECT_BUF_SIZE = 73; - -// system_globals.motd varchar(254) -const S32 DB_MOTD_STR_LEN = 254; -const S32 DB_MOTD_BUF_SIZE = 255; - -// Must be <= user_inventory_item.name so that calling cards work +const S32 DB_GROUP_NOTICE_SUBJ_STR_LEN = 63; +const S32 DB_GROUP_NOTICE_SUBJ_STR_SIZE = 64; +const S32 DB_GROUP_NOTICE_MSG_STR_LEN = MAX_MSG_STR_LEN - DB_GROUP_NOTICE_SUBJ_STR_LEN; +const S32 DB_GROUP_NOTICE_MSG_STR_SIZE = MAX_MSG_BUF_SIZE - DB_GROUP_NOTICE_SUBJ_STR_SIZE; + +// log_text_message.message text +const S32 DB_CHAT_MSG_STR_LEN = MAX_MSG_STR_LEN; +const S32 DB_CHAT_MSG_BUF_SIZE = MAX_MSG_BUF_SIZE; + +// money_stipend.description varchar(254) +const S32 DB_STIPEND_DESC_STR_LEN = 254; +const S32 DB_STIPEND_DESC_BUF_SIZE = 255; + +// script_email_message.from_email varchar(78) +const S32 DB_EMAIL_FROM_STR_LEN = 78; +const S32 DB_EMAIL_FROM_BUF_SIZE = 79; + +// script_email_message.subject varchar(72) +const S32 DB_EMAIL_SUBJECT_STR_LEN = 72; +const S32 DB_EMAIL_SUBJECT_BUF_SIZE = 73; + +// system_globals.motd varchar(254) +const S32 DB_MOTD_STR_LEN = 254; +const S32 DB_MOTD_BUF_SIZE = 255; + +// Must be <= user_inventory_item.name so that calling cards work // First name + " " + last name...or a system assigned "from" name -// instant_message.from_agent_name varchar(63) +// instant_message.from_agent_name varchar(63) // -also- -// user_mute.mute_agent_name varchar(63) -const S32 DB_FULL_NAME_STR_LEN = 63; -const S32 DB_FULL_NAME_BUF_SIZE = 64; // was USER_NAME_SIZE +// user_mute.mute_agent_name varchar(63) +const S32 DB_FULL_NAME_STR_LEN = 63; +const S32 DB_FULL_NAME_BUF_SIZE = 64; // was USER_NAME_SIZE -// user.username varchar(31) -const S32 DB_FIRST_NAME_STR_LEN = 31; -const S32 DB_FIRST_NAME_BUF_SIZE = 32; // was MAX_FIRST_NAME +// user.username varchar(31) +const S32 DB_FIRST_NAME_STR_LEN = 31; +const S32 DB_FIRST_NAME_BUF_SIZE = 32; // was MAX_FIRST_NAME -// user_last_name.name varchar(31) -const S32 DB_LAST_NAME_STR_LEN = 31; -const S32 DB_LAST_NAME_BUF_SIZE = 32; // was MAX_LAST_NAME +// user_last_name.name varchar(31) +const S32 DB_LAST_NAME_STR_LEN = 31; +const S32 DB_LAST_NAME_BUF_SIZE = 32; // was MAX_LAST_NAME -// user.password varchar(100) -const S32 DB_USER_PASSWORD_STR_LEN = 100; -const S32 DB_USER_PASSWORD_BUF_SIZE = 101; // was MAX_PASSWORD +// user.password varchar(100) +const S32 DB_USER_PASSWORD_STR_LEN = 100; +const S32 DB_USER_PASSWORD_BUF_SIZE = 101; // was MAX_PASSWORD -// user.email varchar(254) -const S32 DB_USER_EMAIL_ADDR_STR_LEN = 254; -const S32 DB_USER_EMAIL_ADDR_BUF_SIZE = 255; +// user.email varchar(254) +const S32 DB_USER_EMAIL_ADDR_STR_LEN = 254; +const S32 DB_USER_EMAIL_ADDR_BUF_SIZE = 255; -// user.about text -const S32 DB_USER_ABOUT_STR_LEN = 511; -const S32 DB_USER_ABOUT_BUF_SIZE = 512; +// user.about text +const S32 DB_USER_ABOUT_STR_LEN = 511; +const S32 DB_USER_ABOUT_BUF_SIZE = 512; -// user.fl_about_text text +// user.fl_about_text text // Must be 255 not 256 as gets packed into message Variable 1 -const S32 DB_USER_FL_ABOUT_STR_LEN = 254; -const S32 DB_USER_FL_ABOUT_BUF_SIZE = 255; +const S32 DB_USER_FL_ABOUT_STR_LEN = 254; +const S32 DB_USER_FL_ABOUT_BUF_SIZE = 255; -// user.profile_url text +// user.profile_url text // Must be 255 not 256 as gets packed into message Variable 1 -const S32 DB_USER_PROFILE_URL_STR_LEN = 254; -const S32 DB_USER_PROFILE_URL_BUF_SIZE = 255; +const S32 DB_USER_PROFILE_URL_STR_LEN = 254; +const S32 DB_USER_PROFILE_URL_BUF_SIZE = 255; -// user.want_to varchar(254) -const S32 DB_USER_WANT_TO_STR_LEN = 254; -const S32 DB_USER_WANT_TO_BUF_SIZE = 255; +// user.want_to varchar(254) +const S32 DB_USER_WANT_TO_STR_LEN = 254; +const S32 DB_USER_WANT_TO_BUF_SIZE = 255; -// user.skills varchar(254) -const S32 DB_USER_SKILLS_STR_LEN = 254; -const S32 DB_USER_SKILLS_BUF_SIZE = 255; +// user.skills varchar(254) +const S32 DB_USER_SKILLS_STR_LEN = 254; +const S32 DB_USER_SKILLS_BUF_SIZE = 255; -// user_nv.name varchar(128) -const S32 DB_NV_NAME_STR_LEN = 128; -const S32 DB_NV_NAME_BUF_SIZE = 129; +// user_nv.name varchar(128) +const S32 DB_NV_NAME_STR_LEN = 128; +const S32 DB_NV_NAME_BUF_SIZE = 129; -// user_start_location.location_name varchar(254) -const S32 DB_START_LOCATION_STR_LEN = 254; -const S32 DB_START_LOCATION_BUF_SIZE = 255; +// user_start_location.location_name varchar(254) +const S32 DB_START_LOCATION_STR_LEN = 254; +const S32 DB_START_LOCATION_BUF_SIZE = 255; -// money_tax_assessment.sim varchar(100) -//const S32 DB_SIM_NAME_STR_LEN = 100; -//const S32 DB_SIM_NAME_BUF_SIZE = 101; +// money_tax_assessment.sim varchar(100) +//const S32 DB_SIM_NAME_STR_LEN = 100; +//const S32 DB_SIM_NAME_BUF_SIZE = 101; -// born on date date -const S32 DB_BORN_STR_LEN = 15; -const S32 DB_BORN_BUF_SIZE = 16; +// born on date date +const S32 DB_BORN_STR_LEN = 15; +const S32 DB_BORN_BUF_SIZE = 16; // place.name -const S32 DB_PLACE_NAME_LEN = 63; -const S32 DB_PLACE_NAME_SIZE = 64; -const S32 DB_PARCEL_NAME_LEN = 63; -const S32 DB_PARCEL_NAME_SIZE = 64; +const S32 DB_PLACE_NAME_LEN = 63; +const S32 DB_PLACE_NAME_SIZE = 64; +const S32 DB_PARCEL_NAME_LEN = 63; +const S32 DB_PARCEL_NAME_SIZE = 64; // place.desc -const S32 DB_PLACE_DESC_LEN = 255; -const S32 DB_PLACE_DESC_SIZE = 256; -const S32 DB_PARCEL_DESC_LEN = 255; -const S32 DB_PARCEL_DESC_SIZE = 256; -const S32 DB_PARCEL_MUSIC_URL_LEN = 255; -const S32 DB_PARCEL_MEDIA_URL_LEN = 255; -const S32 DB_PARCEL_MUSIC_URL_SIZE = 256; +const S32 DB_PLACE_DESC_LEN = 255; +const S32 DB_PLACE_DESC_SIZE = 256; +const S32 DB_PARCEL_DESC_LEN = 255; +const S32 DB_PARCEL_DESC_SIZE = 256; +const S32 DB_PARCEL_MUSIC_URL_LEN = 255; +const S32 DB_PARCEL_MEDIA_URL_LEN = 255; +const S32 DB_PARCEL_MUSIC_URL_SIZE = 256; // date time that is easily human readable -const S32 DB_DATETIME_STR_LEN = 35; -const S32 DB_DATETIME_BUF_SIZE = 36; +const S32 DB_DATETIME_STR_LEN = 35; +const S32 DB_DATETIME_BUF_SIZE = 36; // date time that isn't easily human readable -const S32 DB_TERSE_DATETIME_STR_LEN = 15; -const S32 DB_TERSE_DATETIME_BUF_SIZE = 16; +const S32 DB_TERSE_DATETIME_STR_LEN = 15; +const S32 DB_TERSE_DATETIME_BUF_SIZE = 16; // indra.simulator constants -const S32 DB_SIM_NAME_STR_LEN = 35; -const S32 DB_SIM_NAME_BUF_SIZE = 36; -const S32 DB_HOST_NAME_STR_LEN = 100; -const S32 DB_HOST_NAME_BUF_SIZE = 101; -const S32 DB_ESTATE_NAME_STR_LEN = 63; -const S32 DB_ESTATE_NAME_BUF_SIZE = DB_ESTATE_NAME_STR_LEN + 1; +const S32 DB_SIM_NAME_STR_LEN = 35; +const S32 DB_SIM_NAME_BUF_SIZE = 36; +const S32 DB_HOST_NAME_STR_LEN = 100; +const S32 DB_HOST_NAME_BUF_SIZE = 101; +const S32 DB_ESTATE_NAME_STR_LEN = 63; +const S32 DB_ESTATE_NAME_BUF_SIZE = DB_ESTATE_NAME_STR_LEN + 1; // user_note.note -const S32 DB_USER_NOTE_LEN = 1023; -const S32 DB_USER_NOTE_SIZE = 1024; +const S32 DB_USER_NOTE_LEN = 1023; +const S32 DB_USER_NOTE_SIZE = 1024; // pick.name -const S32 DB_PICK_NAME_LEN = 63; -const S32 DB_PICK_NAME_SIZE = 64; +const S32 DB_PICK_NAME_LEN = 63; +const S32 DB_PICK_NAME_SIZE = 64; // pick.desc -const S32 DB_PICK_DESC_LEN = 1023; -const S32 DB_PICK_DESC_SIZE = 1024; +const S32 DB_PICK_DESC_LEN = 1023; +const S32 DB_PICK_DESC_SIZE = 1024; #endif // LL_LLDBSTRINGS_H diff --git a/indra/llmessage/lldispatcher.cpp b/indra/llmessage/lldispatcher.cpp index 717ef10f70..f02a5fd37f 100644 --- a/indra/llmessage/lldispatcher.cpp +++ b/indra/llmessage/lldispatcher.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldispatcher.cpp * @brief Implementation of the dispatcher object. * * $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$ */ @@ -48,55 +48,55 @@ LLDispatcher::~LLDispatcher() bool LLDispatcher::isHandlerPresent(const key_t& name) const { - if(mHandlers.find(name) != mHandlers.end()) - { - return true; - } - return false; + if(mHandlers.find(name) != mHandlers.end()) + { + return true; + } + return false; } void LLDispatcher::copyAllHandlerNames(keys_t& names) const { - // copy the names onto the vector we are given - std::transform( - mHandlers.begin(), - mHandlers.end(), - std::back_insert_iterator<keys_t>(names), - llselect1st<dispatch_map_t::value_type>()); + // copy the names onto the vector we are given + std::transform( + mHandlers.begin(), + mHandlers.end(), + std::back_insert_iterator<keys_t>(names), + llselect1st<dispatch_map_t::value_type>()); } bool LLDispatcher::dispatch( - const key_t& name, - const LLUUID& invoice, - const sparam_t& strings) const + const key_t& name, + const LLUUID& invoice, + const sparam_t& strings) const { - dispatch_map_t::const_iterator it = mHandlers.find(name); - if(it != mHandlers.end()) - { - LLDispatchHandler* func = (*it).second; - return (*func)(this, name, invoice, strings); - } - LL_WARNS() << "Unable to find handler for Generic message: " << name << LL_ENDL; - return false; + dispatch_map_t::const_iterator it = mHandlers.find(name); + if(it != mHandlers.end()) + { + LLDispatchHandler* func = (*it).second; + return (*func)(this, name, invoice, strings); + } + LL_WARNS() << "Unable to find handler for Generic message: " << name << LL_ENDL; + return false; } LLDispatchHandler* LLDispatcher::addHandler( - const key_t& name, LLDispatchHandler* func) + const key_t& name, LLDispatchHandler* func) { - dispatch_map_t::iterator it = mHandlers.find(name); - LLDispatchHandler* old_handler = NULL; - if(it != mHandlers.end()) - { - old_handler = (*it).second; - mHandlers.erase(it); - } - if(func) - { - // only non-null handlers so that we don't have to worry about - // it later. - mHandlers.insert(dispatch_map_t::value_type(name, func)); - } - return old_handler; + dispatch_map_t::iterator it = mHandlers.find(name); + LLDispatchHandler* old_handler = NULL; + if(it != mHandlers.end()) + { + old_handler = (*it).second; + mHandlers.erase(it); + } + if(func) + { + // only non-null handlers so that we don't have to worry about + // it later. + mHandlers.insert(dispatch_map_t::value_type(name, func)); + } + return old_handler; } // static @@ -106,14 +106,14 @@ bool LLDispatcher::unpackMessage( LLUUID& invoice, LLDispatcher::sparam_t& parameters) { - char buf[MAX_STRING]; /*Flawfinder: ignore*/ + char buf[MAX_STRING]; /*Flawfinder: ignore*/ msg->getStringFast(_PREHASH_MethodData, _PREHASH_Method, method); msg->getUUIDFast(_PREHASH_MethodData, _PREHASH_Invoice, invoice); S32 size; S32 count = msg->getNumberOfBlocksFast(_PREHASH_ParamList); for (S32 i = 0; i < count; ++i) { - // we treat the SParam as binary data (since it might be an + // we treat the SParam as binary data (since it might be an // LLUUID in compressed form which may have embedded \0's,) size = msg->getSizeFast(_PREHASH_ParamList, i, _PREHASH_Parameter); if (size >= 0) @@ -137,7 +137,7 @@ bool LLDispatcher::unpackMessage( } else { - // This is either a NULL string, or a string that was packed + // This is either a NULL string, or a string that was packed // incorrectly as binary data, without the usual trailing '\0'. std::string string_data(buf, size); parameters.push_back(string_data); @@ -160,7 +160,7 @@ bool LLDispatcher::unpackLargeMessage( for (S32 i = 0; i < count; ++i) { // This method treats all Parameter List params as strings and unpacks - // them regardless of length. If there is binary data it is the callers + // them regardless of length. If there is binary data it is the callers // responsibility to decode it. std::string param; msg->getStringFast(_PREHASH_ParamList, _PREHASH_Parameter, param, i); diff --git a/indra/llmessage/lldispatcher.h b/indra/llmessage/lldispatcher.h index 43c63ac4df..87b029b8a4 100644 --- a/indra/llmessage/lldispatcher.h +++ b/indra/llmessage/lldispatcher.h @@ -1,25 +1,25 @@ -/** +/** * @file lldispatcher.h * @brief LLDispatcher class header file. * * $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$ */ @@ -46,16 +46,16 @@ class LLUUID; class LLDispatchHandler { public: - typedef std::vector<std::string> sparam_t; - //typedef std::vector<S32> iparam_t; - LLDispatchHandler() {} - virtual ~LLDispatchHandler() {} - virtual bool operator()( - const LLDispatcher* dispatcher, - const std::string& key, - const LLUUID& invoice, - const sparam_t& string) = 0; - //const iparam_t& integers) = 0; + typedef std::vector<std::string> sparam_t; + //typedef std::vector<S32> iparam_t; + LLDispatchHandler() {} + virtual ~LLDispatchHandler() {} + virtual bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& string) = 0; + //const iparam_t& integers) = 0; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -67,43 +67,43 @@ public: class LLDispatcher { public: - typedef std::string key_t; - typedef std::vector<std::string> keys_t; - typedef std::vector<std::string> sparam_t; - //typedef std::vector<S32> iparam_t; + typedef std::string key_t; + typedef std::vector<std::string> keys_t; + typedef std::vector<std::string> sparam_t; + //typedef std::vector<S32> iparam_t; - // construct a dispatcher. - LLDispatcher(); - virtual ~LLDispatcher(); + // construct a dispatcher. + LLDispatcher(); + virtual ~LLDispatcher(); - // Returns if they keyed handler exists in this dispatcher. - bool isHandlerPresent(const key_t& name) const; + // Returns if they keyed handler exists in this dispatcher. + bool isHandlerPresent(const key_t& name) const; - // copy all known keys onto keys_t structure - void copyAllHandlerNames(keys_t& names) const; + // copy all known keys onto keys_t structure + void copyAllHandlerNames(keys_t& names) const; - // Call this method with the name of the request that has come - // in. If the handler is present, it is called with the params and - // returns the return value from - bool dispatch( - const key_t& name, - const LLUUID& invoice, - const sparam_t& strings) const; - //const iparam_t& itegers) const; + // Call this method with the name of the request that has come + // in. If the handler is present, it is called with the params and + // returns the return value from + bool dispatch( + const key_t& name, + const LLUUID& invoice, + const sparam_t& strings) const; + //const iparam_t& itegers) const; - // Add a handler. If one with the same key already exists, its - // pointer is returned, otherwise returns NULL. This object does - // not do memory management of the LLDispatchHandler, and relies - // on the caller to delete the object if necessary. - LLDispatchHandler* addHandler(const key_t& name, LLDispatchHandler* func); + // Add a handler. If one with the same key already exists, its + // pointer is returned, otherwise returns NULL. This object does + // not do memory management of the LLDispatchHandler, and relies + // on the caller to delete the object if necessary. + LLDispatchHandler* addHandler(const key_t& name, LLDispatchHandler* func); - // Helper method to unpack the dispatcher message bus - // format. Returns true on success. - static bool unpackMessage( - LLMessageSystem* msg, - key_t& method, - LLUUID& invoice, - sparam_t& parameters); + // Helper method to unpack the dispatcher message bus + // format. Returns true on success. + static bool unpackMessage( + LLMessageSystem* msg, + key_t& method, + LLUUID& invoice, + sparam_t& parameters); static bool unpackLargeMessage( LLMessageSystem* msg, @@ -112,8 +112,8 @@ public: sparam_t& parameters); protected: - typedef std::map<key_t, LLDispatchHandler*> dispatch_map_t; - dispatch_map_t mHandlers; + typedef std::map<key_t, LLDispatchHandler*> dispatch_map_t; + dispatch_map_t mHandlers; }; #endif // LL_LLDISPATCHER_H diff --git a/indra/llmessage/lleventflags.h b/indra/llmessage/lleventflags.h index 75d79071b1..e1b0f9f460 100644 --- a/indra/llmessage/lleventflags.h +++ b/indra/llmessage/lleventflags.h @@ -1,25 +1,25 @@ -/** +/** * @file lleventflags.h * @brief Flags for events. * * $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$ */ diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index db22ad2ea3..b5d0c93376 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llexperiencecache.cpp * @brief llexperiencecache and related class definitions * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, 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$ */ @@ -40,7 +40,7 @@ //========================================================================= namespace LLExperienceCacheImpl { - void mapKeys(const LLSD& legacyKeys); + void mapKeys(const LLSD& legacyKeys); F64 getErrorRetryDeltaTime(S32 status, LLSD headers); bool maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age); @@ -57,32 +57,32 @@ namespace LLExperienceCacheImpl } //========================================================================= -const std::string LLExperienceCache::PRIVATE_KEY = "private_id"; -const std::string LLExperienceCache::MISSING = "DoesNotExist"; +const std::string LLExperienceCache::PRIVATE_KEY = "private_id"; +const std::string LLExperienceCache::MISSING = "DoesNotExist"; const std::string LLExperienceCache::AGENT_ID = "agent_id"; const std::string LLExperienceCache::GROUP_ID = "group_id"; -const std::string LLExperienceCache::EXPERIENCE_ID = "public_id"; -const std::string LLExperienceCache::NAME = "name"; -const std::string LLExperienceCache::PROPERTIES = "properties"; -const std::string LLExperienceCache::EXPIRES = "expiration"; -const std::string LLExperienceCache::DESCRIPTION = "description"; -const std::string LLExperienceCache::QUOTA = "quota"; +const std::string LLExperienceCache::EXPERIENCE_ID = "public_id"; +const std::string LLExperienceCache::NAME = "name"; +const std::string LLExperienceCache::PROPERTIES = "properties"; +const std::string LLExperienceCache::EXPIRES = "expiration"; +const std::string LLExperienceCache::DESCRIPTION = "description"; +const std::string LLExperienceCache::QUOTA = "quota"; const std::string LLExperienceCache::MATURITY = "maturity"; const std::string LLExperienceCache::METADATA = "extended_metadata"; -const std::string LLExperienceCache::SLURL = "slurl"; +const std::string LLExperienceCache::SLURL = "slurl"; // should be in sync with experience-api/experiences/models.py -const int LLExperienceCache::PROPERTY_INVALID = 1 << 0; -const int LLExperienceCache::PROPERTY_PRIVILEGED = 1 << 3; -const int LLExperienceCache::PROPERTY_GRID = 1 << 4; -const int LLExperienceCache::PROPERTY_PRIVATE = 1 << 5; -const int LLExperienceCache::PROPERTY_DISABLED = 1 << 6; -const int LLExperienceCache::PROPERTY_SUSPENDED = 1 << 7; +const int LLExperienceCache::PROPERTY_INVALID = 1 << 0; +const int LLExperienceCache::PROPERTY_PRIVILEGED = 1 << 3; +const int LLExperienceCache::PROPERTY_GRID = 1 << 4; +const int LLExperienceCache::PROPERTY_PRIVATE = 1 << 5; +const int LLExperienceCache::PROPERTY_DISABLED = 1 << 6; +const int LLExperienceCache::PROPERTY_SUSPENDED = 1 << 7; // default values -const F64 LLExperienceCache::DEFAULT_EXPIRATION = 600.0; -const S32 LLExperienceCache::DEFAULT_QUOTA = 128; // this is megabytes +const F64 LLExperienceCache::DEFAULT_EXPIRATION = 600.0; +const S32 LLExperienceCache::DEFAULT_QUOTA = 128; // this is megabytes const int LLExperienceCache::SEARCH_PAGE_SIZE = 30; bool LLExperienceCache::sShutdown = false; @@ -170,7 +170,7 @@ void LLExperienceCache::exportFile(std::ostream& ostr) const // *TODO$: Rider: This method does not seem to be used... it may be useful in testing. void LLExperienceCache::bootstrap(const LLSD& legacyKeys, int initialExpiration) { - LLExperienceCacheImpl::mapKeys(legacyKeys); + LLExperienceCacheImpl::mapKeys(legacyKeys); LLSD::array_const_iterator it = legacyKeys.beginArray(); for (/**/; it != legacyKeys.endArray(); ++it) { @@ -215,33 +215,33 @@ void LLExperienceCache::processExperience(const LLUUID& public_key, const LLSD& { LL_INFOS("ExperienceCache") << "Processing experience \"" << experience[NAME] << "\" with key " << public_key.asString() << LL_ENDL; - mCache[public_key]=experience; - LLSD & row = mCache[public_key]; + mCache[public_key]=experience; + LLSD & row = mCache[public_key]; - if(row.has(EXPIRES)) - { - row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds(); - } + if(row.has(EXPIRES)) + { + row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds(); + } - if(row.has(EXPERIENCE_ID)) - { - mPendingQueue.erase(row[EXPERIENCE_ID].asUUID()); - } + if(row.has(EXPERIENCE_ID)) + { + mPendingQueue.erase(row[EXPERIENCE_ID].asUUID()); + } - //signal - signal_map_t::iterator sig_it = mSignalMap.find(public_key); - if (sig_it != mSignalMap.end()) - { - signal_ptr signal = sig_it->second; - (*signal)(experience); + //signal + signal_map_t::iterator sig_it = mSignalMap.find(public_key); + if (sig_it != mSignalMap.end()) + { + signal_ptr signal = sig_it->second; + (*signal)(experience); - mSignalMap.erase(public_key); - } + mSignalMap.erase(public_key); + } } const LLExperienceCache::cache_t& LLExperienceCache::getCached() { - return mCache; + return mCache; } void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, std::string url, RequestQueue_t requests) @@ -251,7 +251,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap //LL_INFOS("requestExperiencesCoro") << "url: " << url << LL_ENDL; LLSD result = httpAdapter->getAndSuspend(httpRequest, url); - + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -282,8 +282,8 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap } LLSD experiences = result["experience_keys"]; - - for (LLSD::array_const_iterator it = experiences.beginArray(); + + for (LLSD::array_const_iterator it = experiences.beginArray(); it != experiences.endArray(); ++it) { const LLSD& row = *it; @@ -296,8 +296,8 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap } LLSD error_ids = result["error_ids"]; - - for (LLSD::array_const_iterator errIt = error_ids.beginArray(); + + for (LLSD::array_const_iterator errIt = error_ids.beginArray(); errIt != error_ids.endArray(); ++errIt) { LLUUID id = errIt->asUUID(); @@ -337,7 +337,7 @@ void LLExperienceCache::requestExperiences() urlBase += "id/"; - F64 now = LLFrameTimer::getTotalSeconds(); + F64 now = LLFrameTimer::getTotalSeconds(); const U32 EXP_URL_SEND_THRESHOLD = 3000; const U32 PAGE_SIZE1 = EXP_URL_SEND_THRESHOLD / UUID_STR_LENGTH; @@ -355,7 +355,7 @@ void LLExperienceCache::requestExperiences() ostr << "&" << EXPERIENCE_ID << "=" << key.asString(); mPendingQueue[key] = now; - + if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD)) { // request is placed in the coprocedure pool for the ExpCache cache. Throttling is done by the pool itself. LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "RequestExperiences", @@ -372,18 +372,18 @@ void LLExperienceCache::requestExperiences() bool LLExperienceCache::isRequestPending(const LLUUID& public_key) { - bool isPending = false; - const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; + bool isPending = false; + const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; PendingQueue_t::const_iterator it = mPendingQueue.find(public_key); - if(it != mPendingQueue.end()) - { - F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; - isPending = (it->second > expire_time); - } + if(it != mPendingQueue.end()) + { + F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; + isPending = (it->second > expire_time); + } - return isPending; + return isPending; } void LLExperienceCache::setCapabilityQuery(LLExperienceCache::CapabilityQuery_t queryfn) @@ -398,7 +398,7 @@ void LLExperienceCache::idleCoro() const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds LL_INFOS("ExperienceCache") << "Launching Experience cache idle coro." << LL_ENDL; - do + do { if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) { @@ -420,116 +420,116 @@ void LLExperienceCache::idleCoro() void LLExperienceCache::erase(const LLUUID& key) { - cache_t::iterator it = mCache.find(key); - - if(it != mCache.end()) - { - mCache.erase(it); - } + cache_t::iterator it = mCache.find(key); + + if(it != mCache.end()) + { + mCache.erase(it); + } } void LLExperienceCache::eraseExpired() { - F64 now = LLFrameTimer::getTotalSeconds(); - cache_t::iterator it = mCache.begin(); - while (it != mCache.end()) - { - cache_t::iterator cur = it; - LLSD& exp = cur->second; - ++it; + F64 now = LLFrameTimer::getTotalSeconds(); + cache_t::iterator it = mCache.begin(); + while (it != mCache.end()) + { + cache_t::iterator cur = it; + LLSD& exp = cur->second; + ++it; //LL_INFOS("ExperienceCache") << "Testing experience \"" << exp[NAME] << "\" with exp time " << exp[EXPIRES].asReal() << "(now = " << now << ")" << LL_ENDL; - if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now) - { + if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now) + { if(!exp.has(EXPERIENCE_ID)) - { + { LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ; mCache.erase(cur); - } + } else { LLUUID id = exp[EXPERIENCE_ID].asUUID(); LLUUID private_key = exp.has(LLExperienceCache::PRIVATE_KEY) ? exp[LLExperienceCache::PRIVATE_KEY].asUUID():LLUUID::null; if(private_key.notNull() || !exp.has("DoesNotExist")) - { - fetch(id, true); - } - else - { + { + fetch(id, true); + } + else + { LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ; - mCache.erase(cur); - } - } - } - } + mCache.erase(cur); + } + } + } + } } - + bool LLExperienceCache::fetch(const LLUUID& key, bool refresh/* = true*/) { - if(!key.isNull() && !isRequestPending(key) && (refresh || mCache.find(key)==mCache.end())) - { - LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL; + if(!key.isNull() && !isRequestPending(key) && (refresh || mCache.find(key)==mCache.end())) + { + LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL; mRequestQueue.insert(key); - return true; - } - return false; + return true; + } + return false; } void LLExperienceCache::insert(const LLSD& experience_data) { - if(experience_data.has(EXPERIENCE_ID)) - { + if(experience_data.has(EXPERIENCE_ID)) + { processExperience(experience_data[EXPERIENCE_ID].asUUID(), experience_data); - } - else - { - LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL; - } + } + else + { + LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL; + } } const LLSD& LLExperienceCache::get(const LLUUID& key) { - static const LLSD empty; - - if(key.isNull()) - return empty; - cache_t::const_iterator it = mCache.find(key); - - if (it != mCache.end()) - { - return it->second; - } - fetch(key); - - return empty; + static const LLSD empty; + + if(key.isNull()) + return empty; + cache_t::const_iterator it = mCache.find(key); + + if (it != mCache.end()) + { + return it->second; + } + fetch(key); + + return empty; } void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::ExperienceGetFn_t slot) { - if(key.isNull()) - return; - - cache_t::const_iterator it = mCache.find(key); - if (it != mCache.end()) - { - // ...name already exists in cache, fire callback now - callback_signal_t signal; - signal.connect(slot); - - signal(it->second); - return; - } - - fetch(key); - - signal_ptr signal = signal_ptr(new callback_signal_t()); - - std::pair<signal_map_t::iterator, bool> result = mSignalMap.insert(signal_map_t::value_type(key, signal)); - if (!result.second) - signal = (*result.first).second; - signal->connect(slot); + if(key.isNull()) + return; + + cache_t::const_iterator it = mCache.find(key); + if (it != mCache.end()) + { + // ...name already exists in cache, fire callback now + callback_signal_t signal; + signal.connect(slot); + + signal(it->second); + return; + } + + fetch(key); + + signal_ptr signal = signal_ptr(new callback_signal_t()); + + std::pair<signal_map_t::iterator, bool> result = mSignalMap.insert(signal_map_t::value_type(key, signal)); + if (!result.second) + signal = (*result.first).second; + signal->connect(slot); } //========================================================================= @@ -592,7 +592,7 @@ void LLExperienceCache::fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCorout failure["error"] = (LLSD::Integer)status.getType(); failure["message"] = status.getMessage(); } - else + else { failure["error"] = -1; failure["message"] = "no experience"; @@ -747,7 +747,7 @@ void LLExperienceCache::getExperiencePermission(const LLUUID &experienceId, Expe } std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString(); - + permissionInvoker_fn invoker(boost::bind( // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> @@ -903,15 +903,15 @@ void LLExperienceCache::updateExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapte //========================================================================= void LLExperienceCacheImpl::mapKeys(const LLSD& legacyKeys) { - LLSD::array_const_iterator exp = legacyKeys.beginArray(); - for (/**/; exp != legacyKeys.endArray(); ++exp) - { + LLSD::array_const_iterator exp = legacyKeys.beginArray(); + for (/**/; exp != legacyKeys.endArray(); ++exp) + { if (exp->has(LLExperienceCacheImpl::EXPERIENCE_ID) && exp->has(LLExperienceCacheImpl::PRIVATE_KEY)) - { - LLExperienceCacheImpl::privateToPublicKeyMap[(*exp)[LLExperienceCacheImpl::PRIVATE_KEY].asUUID()] = + { + LLExperienceCacheImpl::privateToPublicKeyMap[(*exp)[LLExperienceCacheImpl::PRIVATE_KEY].asUUID()] = (*exp)[LLExperienceCacheImpl::EXPERIENCE_ID].asUUID(); - } - } + } + } } // Return time to retry a request that generated an error, based on @@ -972,56 +972,56 @@ F64 LLExperienceCacheImpl::getErrorRetryDeltaTime(S32 status, LLSD headers) bool LLExperienceCacheImpl::maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age) { - // Split the string on "," to get a list of directives - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - tokenizer directives(cache_control, COMMA_SEPARATOR); - - tokenizer::iterator token_it = directives.begin(); - for ( ; token_it != directives.end(); ++token_it) - { - // Tokens may have leading or trailing whitespace - std::string token = *token_it; - LLStringUtil::trim(token); - - if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) - { - // ...this token starts with max-age, so let's chop it up by "=" - tokenizer subtokens(token, EQUALS_SEPARATOR); - tokenizer::iterator subtoken_it = subtokens.begin(); - - // Must have a token - if (subtoken_it == subtokens.end()) return false; - std::string subtoken = *subtoken_it; - - // Must exactly equal "max-age" - LLStringUtil::trim(subtoken); - if (subtoken != MAX_AGE) return false; - - // Must have another token - ++subtoken_it; - if (subtoken_it == subtokens.end()) return false; - subtoken = *subtoken_it; - - // Must be a valid integer - // *NOTE: atoi() returns 0 for invalid values, so we have to - // check the string first. - // *TODO: Do servers ever send "0000" for zero? We don't handle it - LLStringUtil::trim(subtoken); - if (subtoken == "0") - { - *max_age = 0; - return true; - } - S32 val = atoi( subtoken.c_str() ); - if (val > 0 && val < S32_MAX) - { - *max_age = val; - return true; - } - return false; - } - } - return false; + // Split the string on "," to get a list of directives + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + tokenizer directives(cache_control, COMMA_SEPARATOR); + + tokenizer::iterator token_it = directives.begin(); + for ( ; token_it != directives.end(); ++token_it) + { + // Tokens may have leading or trailing whitespace + std::string token = *token_it; + LLStringUtil::trim(token); + + if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) + { + // ...this token starts with max-age, so let's chop it up by "=" + tokenizer subtokens(token, EQUALS_SEPARATOR); + tokenizer::iterator subtoken_it = subtokens.begin(); + + // Must have a token + if (subtoken_it == subtokens.end()) return false; + std::string subtoken = *subtoken_it; + + // Must exactly equal "max-age" + LLStringUtil::trim(subtoken); + if (subtoken != MAX_AGE) return false; + + // Must have another token + ++subtoken_it; + if (subtoken_it == subtokens.end()) return false; + subtoken = *subtoken_it; + + // Must be a valid integer + // *NOTE: atoi() returns 0 for invalid values, so we have to + // check the string first. + // *TODO: Do servers ever send "0000" for zero? We don't handle it + LLStringUtil::trim(subtoken); + if (subtoken == "0") + { + *max_age = 0; + return true; + } + S32 val = atoi( subtoken.c_str() ); + if (val > 0 && val < S32_MAX) + { + *max_age = val; + return true; + } + return false; + } + } + return false; } diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h index 3ee45da2e7..81e904107f 100644 --- a/indra/llmessage/llexperiencecache.h +++ b/indra/llmessage/llexperiencecache.h @@ -1,25 +1,25 @@ -/** +/** * @file llexperiencecache.h * @brief Caches information relating to experience keys * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, 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$ */ @@ -53,7 +53,7 @@ public: void cleanup(); //------------------------------------------- - // Cache methods + // Cache methods void erase(const LLUUID& key); bool fetch(const LLUUID& key, bool refresh = false); void insert(const LLSD& experience_data); @@ -68,7 +68,7 @@ public: void findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn); void getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn); - // the Get/Set Region Experiences take a CapabilityQuery to get the capability since + // the Get/Set Region Experiences take a CapabilityQuery to get the capability since // the region being queried may not be the region that the agent is standing on. void getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn); void setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn); @@ -81,13 +81,13 @@ public: void updateExperience(LLSD updateData, ExperienceGetFn_t fn); //------------------------------------------- - static const std::string NAME; // "name" - static const std::string EXPERIENCE_ID; // "public_id" + static const std::string NAME; // "name" + static const std::string EXPERIENCE_ID; // "public_id" static const std::string AGENT_ID; // "agent_id" static const std::string GROUP_ID; // "group_id" - static const std::string PROPERTIES; // "properties" - static const std::string EXPIRES; // "expiration" - static const std::string DESCRIPTION; // "description" + static const std::string PROPERTIES; // "properties" + static const std::string EXPIRES; // "expiration" + static const std::string DESCRIPTION; // "description" static const std::string QUOTA; // "quota" static const std::string MATURITY; // "maturity" static const std::string METADATA; // "extended_metadata" @@ -96,12 +96,12 @@ public: static const std::string MISSING; // "DoesNotExist" // should be in sync with experience-api/experiences/models.py - static const int PROPERTY_INVALID; // 1 << 0 - static const int PROPERTY_PRIVILEGED; // 1 << 3 - static const int PROPERTY_GRID; // 1 << 4 - static const int PROPERTY_PRIVATE; // 1 << 5 - static const int PROPERTY_DISABLED; // 1 << 6 - static const int PROPERTY_SUSPENDED; // 1 << 7 + static const int PROPERTY_INVALID; // 1 << 0 + static const int PROPERTY_PRIVILEGED; // 1 << 3 + static const int PROPERTY_GRID; // 1 << 4 + static const int PROPERTY_PRIVATE; // 1 << 5 + static const int PROPERTY_DISABLED; // 1 << 6 + static const int PROPERTY_SUSPENDED; // 1 << 7 private: virtual ~LLExperienceCache(); @@ -110,33 +110,33 @@ private: typedef boost::function<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLCore::HttpRequest::ptr_t, std::string)> permissionInvoker_fn; - // Callback types for get() + // Callback types for get() typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t; - typedef std::shared_ptr<callback_signal_t> signal_ptr; - // May have multiple callbacks for a single ID, which are - // represented as multiple slots bound to the signal. - // Avoid copying signals via pointers. - typedef std::map<LLUUID, signal_ptr> signal_map_t; - typedef std::map<LLUUID, LLSD> cache_t; - - typedef std::set<LLUUID> RequestQueue_t; + typedef std::shared_ptr<callback_signal_t> signal_ptr; + // May have multiple callbacks for a single ID, which are + // represented as multiple slots bound to the signal. + // Avoid copying signals via pointers. + typedef std::map<LLUUID, signal_ptr> signal_map_t; + typedef std::map<LLUUID, LLSD> cache_t; + + typedef std::set<LLUUID> RequestQueue_t; typedef std::map<LLUUID, F64> PendingQueue_t; - //-------------------------------------------- - static const std::string PRIVATE_KEY; // "private_id" - - // default values - static const F64 DEFAULT_EXPIRATION; // 600.0 - static const S32 DEFAULT_QUOTA; // 128 this is megabytes + //-------------------------------------------- + static const std::string PRIVATE_KEY; // "private_id" + + // default values + static const F64 DEFAULT_EXPIRATION; // 600.0 + static const S32 DEFAULT_QUOTA; // 128 this is megabytes static const int SEARCH_PAGE_SIZE; - + //-------------------------------------------- void processExperience(const LLUUID& public_key, const LLSD& experience); //-------------------------------------------- - cache_t mCache; - signal_map_t mSignalMap; - RequestQueue_t mRequestQueue; + cache_t mCache; + signal_map_t mSignalMap; + RequestQueue_t mRequestQueue; PendingQueue_t mPendingQueue; LLFrameTimer mEraseExpiredTimer; // Periodically clean out expired entries from the cache @@ -145,7 +145,7 @@ private: static bool sShutdown; // control for coroutines, they exist out of LLExperienceCache's scope, so they need a static control void idleCoro(); - void eraseExpired(); + void eraseExpired(); void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t); void requestExperiences(); @@ -161,11 +161,11 @@ private: void exportFile(std::ostream& ostr) const; void importFile(std::istream& istr); - // - const cache_t& getCached(); + // + const cache_t& getCached(); - // maps an experience private key to the experience id - LLUUID getExperienceId(const LLUUID& private_key, bool null_if_not_found=false); + // maps an experience private key to the experience id + LLUUID getExperienceId(const LLUUID& private_key, bool null_if_not_found=false); //===================================================================== inline friend std::ostream &operator << (std::ostream &os, const LLExperienceCache &cache) diff --git a/indra/llmessage/llextendedstatus.h b/indra/llmessage/llextendedstatus.h index 2a53dced80..ed8338daa3 100644 --- a/indra/llmessage/llextendedstatus.h +++ b/indra/llmessage/llextendedstatus.h @@ -1,4 +1,4 @@ -/** +/** * @file llextendedstatus.h * @date August 2007 * @brief extended status codes for curl/resident asset storage and delivery @@ -6,21 +6,21 @@ * $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$ */ @@ -30,33 +30,33 @@ enum class LLExtStat: uint32_t { - // Status provider groups - Top bits indicate which status type it is - // Zero is common status code (next section) - CURL_RESULT = 1UL<<30, // serviced by curl - use 1L if we really implement the below - RES_RESULT = 2UL<<30, // serviced by resident copy - CACHE_RESULT = 3UL<<30, // serviced by cache - - - // Common Status Codes - // - NONE = 0x00000, // No extra info here - sorry! - NULL_UUID = 0x10001, // null asset ID - NO_UPSTREAM = 0x10002, // attempt to upload without a valid upstream method/provider - REQUEST_DROPPED = 0x10003, // request was dropped unserviced - NONEXISTENT_FILE= 0x10004, // trying to upload a file that doesn't exist - BLOCKED_FILE = 0x10005, // trying to upload a file that we can't open - - // curl status codes: - // - // Mask off CURL_RESULT for original result and - // see: libraries/include/curl/curl.h - - // Memory-Resident status codes: - // None at present - - // CACHE status codes: - CACHE_CACHED = CACHE_RESULT | 0x0001, - CACHE_CORRUPT = CACHE_RESULT | 0x0002, + // Status provider groups - Top bits indicate which status type it is + // Zero is common status code (next section) + CURL_RESULT = 1UL<<30, // serviced by curl - use 1L if we really implement the below + RES_RESULT = 2UL<<30, // serviced by resident copy + CACHE_RESULT = 3UL<<30, // serviced by cache + + + // Common Status Codes + // + NONE = 0x00000, // No extra info here - sorry! + NULL_UUID = 0x10001, // null asset ID + NO_UPSTREAM = 0x10002, // attempt to upload without a valid upstream method/provider + REQUEST_DROPPED = 0x10003, // request was dropped unserviced + NONEXISTENT_FILE= 0x10004, // trying to upload a file that doesn't exist + BLOCKED_FILE = 0x10005, // trying to upload a file that we can't open + + // curl status codes: + // + // Mask off CURL_RESULT for original result and + // see: libraries/include/curl/curl.h + + // Memory-Resident status codes: + // None at present + + // CACHE status codes: + CACHE_CACHED = CACHE_RESULT | 0x0001, + CACHE_CORRUPT = CACHE_RESULT | 0x0002, }; diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp index c63ce5f441..df78652361 100644 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ b/indra/llmessage/llfiltersd2xmlrpc.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llfiltersd2xmlrpc.cpp * @author Phoenix * @date 2005-04-26 @@ -6,27 +6,27 @@ * $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$ */ -/** - * xml rpc request: +/** + * xml rpc request: * <code> * <?xml version="1.0"?> * <methodCall><methodName>examples.getStateName</methodName> @@ -57,17 +57,17 @@ * <code> * { 'method':'...', 'parameter':...]} * </code> - * + * * llsd rpc response: * <code> * { 'response':... } * </code> - * - * llsd rpc fault: + * + * llsd rpc fault: * <code> * { 'fault': {'code':i..., 'description':'...'} } * </code> - * + * */ #include "linden_common.h" @@ -132,174 +132,174 @@ LLFilterSD2XMLRPC::~LLFilterSD2XMLRPC() std::string xml_escape_string(const std::string& in) { - std::ostringstream out; - std::string::const_iterator it = in.begin(); - std::string::const_iterator end = in.end(); - for(; it != end; ++it) - { - switch((*it)) - { - case '<': - out << "<"; - break; - case '>': - out << ">"; - break; - case '&': - out << "&"; - break; - case '\'': - out << "'"; - break; - case '"': - out << """; - break; - default: - out << (*it); - break; - } - } - return out.str(); + std::ostringstream out; + std::string::const_iterator it = in.begin(); + std::string::const_iterator end = in.end(); + for(; it != end; ++it) + { + switch((*it)) + { + case '<': + out << "<"; + break; + case '>': + out << ">"; + break; + case '&': + out << "&"; + break; + case '\'': + out << "'"; + break; + case '"': + out << """; + break; + default: + out << (*it); + break; + } + } + return out.str(); } void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) { - ostr << "<value>"; - switch(sd.type()) - { - case LLSD::TypeMap: - { + ostr << "<value>"; + switch(sd.type()) + { + case LLSD::TypeMap: + { #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(map) BEGIN" << LL_ENDL; + LL_INFOS() << "streamOut(map) BEGIN" << LL_ENDL; #endif - ostr << "<struct>"; - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing struct" << LL_ENDL; - } - LLSD::map_const_iterator it = sd.beginMap(); - LLSD::map_const_iterator end = sd.endMap(); - for(; it != end; ++it) - { - ostr << "<member><name>" << xml_escape_string((*it).first) - << "</name>"; - streamOut(ostr, (*it).second); - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing '" << (*it).first - << "' with sd type " << (*it).second.type() << LL_ENDL; - } - ostr << "</member>"; - } - ostr << "</struct>"; + ostr << "<struct>"; + if(ostr.fail()) + { + LL_INFOS() << "STREAM FAILURE writing struct" << LL_ENDL; + } + LLSD::map_const_iterator it = sd.beginMap(); + LLSD::map_const_iterator end = sd.endMap(); + for(; it != end; ++it) + { + ostr << "<member><name>" << xml_escape_string((*it).first) + << "</name>"; + streamOut(ostr, (*it).second); + if(ostr.fail()) + { + LL_INFOS() << "STREAM FAILURE writing '" << (*it).first + << "' with sd type " << (*it).second.type() << LL_ENDL; + } + ostr << "</member>"; + } + ostr << "</struct>"; #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(map) END" << LL_ENDL; + LL_INFOS() << "streamOut(map) END" << LL_ENDL; #endif - break; - } - case LLSD::TypeArray: - { + break; + } + case LLSD::TypeArray: + { #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(array) BEGIN" << LL_ENDL; + LL_INFOS() << "streamOut(array) BEGIN" << LL_ENDL; #endif - ostr << "<array><data>"; - LLSD::array_const_iterator it = sd.beginArray(); - LLSD::array_const_iterator end = sd.endArray(); - for(; it != end; ++it) - { - streamOut(ostr, *it); - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing array element sd type " - << (*it).type() << LL_ENDL; - } - } + ostr << "<array><data>"; + LLSD::array_const_iterator it = sd.beginArray(); + LLSD::array_const_iterator end = sd.endArray(); + for(; it != end; ++it) + { + streamOut(ostr, *it); + if(ostr.fail()) + { + LL_INFOS() << "STREAM FAILURE writing array element sd type " + << (*it).type() << LL_ENDL; + } + } #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(array) END" << LL_ENDL; + LL_INFOS() << "streamOut(array) END" << LL_ENDL; #endif - ostr << "</data></array>"; - break; - } - case LLSD::TypeUndefined: - // treat undefined as a bool with a false value. - case LLSD::TypeBoolean: + ostr << "</data></array>"; + break; + } + case LLSD::TypeUndefined: + // treat undefined as a bool with a false value. + case LLSD::TypeBoolean: #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(bool)" << LL_ENDL; + LL_INFOS() << "streamOut(bool)" << LL_ENDL; #endif - ostr << "<boolean>" << (sd.asBoolean() ? "1" : "0") << "</boolean>"; - break; - case LLSD::TypeInteger: + ostr << "<boolean>" << (sd.asBoolean() ? "1" : "0") << "</boolean>"; + break; + case LLSD::TypeInteger: #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(int)" << LL_ENDL; + LL_INFOS() << "streamOut(int)" << LL_ENDL; #endif - ostr << "<i4>" << sd.asInteger() << "</i4>"; - break; - case LLSD::TypeReal: + ostr << "<i4>" << sd.asInteger() << "</i4>"; + break; + case LLSD::TypeReal: #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(real)" << LL_ENDL; + LL_INFOS() << "streamOut(real)" << LL_ENDL; #endif - ostr << "<double>" << sd.asReal() << "</double>"; - break; - case LLSD::TypeString: + ostr << "<double>" << sd.asReal() << "</double>"; + break; + case LLSD::TypeString: #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(string)" << LL_ENDL; + LL_INFOS() << "streamOut(string)" << LL_ENDL; #endif - ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>"; - break; - case LLSD::TypeUUID: + ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>"; + break; + case LLSD::TypeUUID: #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(uuid)" << LL_ENDL; + LL_INFOS() << "streamOut(uuid)" << LL_ENDL; #endif - // serialize it as a string - ostr << "<string>" << sd.asString() << "</string>"; - break; - case LLSD::TypeURI: - { + // serialize it as a string + ostr << "<string>" << sd.asString() << "</string>"; + break; + case LLSD::TypeURI: + { #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(uri)" << LL_ENDL; + LL_INFOS() << "streamOut(uri)" << LL_ENDL; #endif - // serialize it as a string - ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>"; - break; - } - case LLSD::TypeBinary: - { + // serialize it as a string + ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>"; + break; + } + case LLSD::TypeBinary: + { #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(binary)" << LL_ENDL; + LL_INFOS() << "streamOut(binary)" << LL_ENDL; #endif - // this is pretty inefficient, but we'll deal with that - // problem when it becomes one. - ostr << "<base64>"; - LLSD::Binary buffer = sd.asBinary(); - if(!buffer.empty()) - { - // *TODO: convert to LLBase64 - int b64_buffer_length = apr_base64_encode_len(buffer.size()); - char* b64_buffer = new char[b64_buffer_length]; - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - &buffer[0], - buffer.size()); - ostr.write(b64_buffer, b64_buffer_length - 1); - delete[] b64_buffer; - } - ostr << "</base64>"; - break; - } - case LLSD::TypeDate: + // this is pretty inefficient, but we'll deal with that + // problem when it becomes one. + ostr << "<base64>"; + LLSD::Binary buffer = sd.asBinary(); + if(!buffer.empty()) + { + // *TODO: convert to LLBase64 + int b64_buffer_length = apr_base64_encode_len(buffer.size()); + char* b64_buffer = new char[b64_buffer_length]; + b64_buffer_length = apr_base64_encode_binary( + b64_buffer, + &buffer[0], + buffer.size()); + ostr.write(b64_buffer, b64_buffer_length - 1); + delete[] b64_buffer; + } + ostr << "</base64>"; + break; + } + case LLSD::TypeDate: #if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(date)" << LL_ENDL; + LL_INFOS() << "streamOut(date)" << LL_ENDL; #endif - // no need to escape this since it will be alpha-numeric. - ostr << "<dateTime.iso8601>" << sd.asString() << "</dateTime.iso8601>"; - break; - default: - // unhandled type - LL_WARNS() << "Unhandled structured data type: " << sd.type() - << LL_ENDL; - break; - } - ostr << "</value>"; + // no need to escape this since it will be alpha-numeric. + ostr << "<dateTime.iso8601>" << sd.asString() << "</dateTime.iso8601>"; + break; + default: + // unhandled type + LL_WARNS() << "Unhandled structured data type: " << sd.type() + << LL_ENDL; + break; + } + ostr << "</value>"; } /** @@ -317,59 +317,59 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse() // virtual LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; - // This pipe does not work if it does not have everyting. This - // could be addressed by making a stream parser for llsd which - // handled partial information. - if(!eos) - { - return STATUS_BREAK; - } - - PUMP_DEBUG; - // we have everyting in the buffer, so turn the structure data rpc - // response into an xml rpc response. - LLBufferStream stream(channels, buffer.get()); - stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER; - LLSD sd; - LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); - - PUMP_DEBUG; - LLIOPipe::EStatus rv = STATUS_ERROR; - if(sd.has("response")) - { - PUMP_DEBUG; - // it is a normal response. pack it up and ship it out. - stream.precision(DEFAULT_PRECISION); - stream << XMLRPC_RESPONSE_HEADER; - streamOut(stream, sd["response"]); - stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER; - rv = STATUS_DONE; - } - else if(sd.has("fault")) - { - PUMP_DEBUG; - // it is a fault. - stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger() - << XMLRPC_FAULT_2 - << xml_escape_string(sd["fault"]["description"].asString()) - << XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER; - rv = STATUS_DONE; - } - else - { - LL_WARNS() << "Unable to determine the type of LLSD response." << LL_ENDL; - } - PUMP_DEBUG; - return rv; + PUMP_DEBUG; + // This pipe does not work if it does not have everyting. This + // could be addressed by making a stream parser for llsd which + // handled partial information. + if(!eos) + { + return STATUS_BREAK; + } + + PUMP_DEBUG; + // we have everyting in the buffer, so turn the structure data rpc + // response into an xml rpc response. + LLBufferStream stream(channels, buffer.get()); + stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER; + LLSD sd; + LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); + + PUMP_DEBUG; + LLIOPipe::EStatus rv = STATUS_ERROR; + if(sd.has("response")) + { + PUMP_DEBUG; + // it is a normal response. pack it up and ship it out. + stream.precision(DEFAULT_PRECISION); + stream << XMLRPC_RESPONSE_HEADER; + streamOut(stream, sd["response"]); + stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER; + rv = STATUS_DONE; + } + else if(sd.has("fault")) + { + PUMP_DEBUG; + // it is a fault. + stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger() + << XMLRPC_FAULT_2 + << xml_escape_string(sd["fault"]["description"].asString()) + << XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER; + rv = STATUS_DONE; + } + else + { + LL_WARNS() << "Unable to determine the type of LLSD response." << LL_ENDL; + } + PUMP_DEBUG; + return rv; } /** @@ -381,10 +381,10 @@ LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest() LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest(const char* method) { - if(method) - { - mMethod.assign(method); - } + if(method) + { + mMethod.assign(method); + } } LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest() @@ -393,103 +393,103 @@ LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest() // virtual LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - // This pipe does not work if it does not have everyting. This - // could be addressed by making a stream parser for llsd which - // handled partial information. - PUMP_DEBUG; - if(!eos) - { - LL_INFOS() << "!eos" << LL_ENDL; - return STATUS_BREAK; - } - - // See if we can parse it - LLBufferStream stream(channels, buffer.get()); - LLSD sd; - LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); - if(stream.fail()) - { - LL_INFOS() << "STREAM FAILURE reading structure data." << LL_ENDL; - } - - PUMP_DEBUG; - // We can get the method and parameters from either the member - // function or passed in via the buffer. We prefer the buffer if - // we found a parameter and a method, or fall back to using - // mMethod and putting everyting in the buffer into the parameter. - std::string method; - LLSD param_sd; - if(sd.has("method") && sd.has("parameter")) - { - method = sd["method"].asString(); - param_sd = sd["parameter"]; - } - else - { - method = mMethod; - param_sd = sd; - } - if(method.empty()) - { - LL_WARNS() << "SD -> XML Request no method found." << LL_ENDL; - return STATUS_ERROR; - } - - PUMP_DEBUG; - // We have a method, and some kind of parameter, so package it up - // and send it out. - LLBufferStream ostream(channels, buffer.get()); - ostream.precision(DEFAULT_PRECISION); - if(ostream.fail()) - { - LL_INFOS() << "STREAM FAILURE setting precision" << LL_ENDL; - } - ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1 - << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2; - if(ostream.fail()) - { - LL_INFOS() << "STREAM FAILURE writing method headers" << LL_ENDL; - } - switch(param_sd.type()) - { - case LLSD::TypeMap: - // If the params are a map, then we do not want to iterate - // through them since the iterators returned will be map - // ordered un-named values, which will lose the names, and - // only stream the values, turning it into an array. - ostream << "<param>"; - streamOut(ostream, param_sd); - ostream << "</param>"; - break; - case LLSD::TypeArray: - { - - LLSD::array_iterator it = param_sd.beginArray(); - LLSD::array_iterator end = param_sd.endArray(); - for(; it != end; ++it) - { - ostream << "<param>"; - streamOut(ostream, *it); - ostream << "</param>"; - } - break; - } - default: - ostream << "<param>"; - streamOut(ostream, param_sd); - ostream << "</param>"; - break; - } - - stream << XMLRPC_REQUEST_FOOTER; - return STATUS_DONE; + // This pipe does not work if it does not have everyting. This + // could be addressed by making a stream parser for llsd which + // handled partial information. + PUMP_DEBUG; + if(!eos) + { + LL_INFOS() << "!eos" << LL_ENDL; + return STATUS_BREAK; + } + + // See if we can parse it + LLBufferStream stream(channels, buffer.get()); + LLSD sd; + LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); + if(stream.fail()) + { + LL_INFOS() << "STREAM FAILURE reading structure data." << LL_ENDL; + } + + PUMP_DEBUG; + // We can get the method and parameters from either the member + // function or passed in via the buffer. We prefer the buffer if + // we found a parameter and a method, or fall back to using + // mMethod and putting everyting in the buffer into the parameter. + std::string method; + LLSD param_sd; + if(sd.has("method") && sd.has("parameter")) + { + method = sd["method"].asString(); + param_sd = sd["parameter"]; + } + else + { + method = mMethod; + param_sd = sd; + } + if(method.empty()) + { + LL_WARNS() << "SD -> XML Request no method found." << LL_ENDL; + return STATUS_ERROR; + } + + PUMP_DEBUG; + // We have a method, and some kind of parameter, so package it up + // and send it out. + LLBufferStream ostream(channels, buffer.get()); + ostream.precision(DEFAULT_PRECISION); + if(ostream.fail()) + { + LL_INFOS() << "STREAM FAILURE setting precision" << LL_ENDL; + } + ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1 + << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2; + if(ostream.fail()) + { + LL_INFOS() << "STREAM FAILURE writing method headers" << LL_ENDL; + } + switch(param_sd.type()) + { + case LLSD::TypeMap: + // If the params are a map, then we do not want to iterate + // through them since the iterators returned will be map + // ordered un-named values, which will lose the names, and + // only stream the values, turning it into an array. + ostream << "<param>"; + streamOut(ostream, param_sd); + ostream << "</param>"; + break; + case LLSD::TypeArray: + { + + LLSD::array_iterator it = param_sd.beginArray(); + LLSD::array_iterator end = param_sd.endArray(); + for(; it != end; ++it) + { + ostream << "<param>"; + streamOut(ostream, *it); + ostream << "</param>"; + } + break; + } + default: + ostream << "<param>"; + streamOut(ostream, param_sd); + ostream << "</param>"; + break; + } + + stream << XMLRPC_REQUEST_FOOTER; + return STATUS_DONE; } /** @@ -500,92 +500,92 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( // parameters. LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value) { - XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value); - LLIOPipe::EStatus status = LLIOPipe::STATUS_OK; - switch(type) - { - case xmlrpc_type_base64: - { - S32 len = XMLRPC_GetValueStringLen(value); - const char* buf = XMLRPC_GetValueBase64(value); - ostr << " b("; - if((len > 0) && buf) - { - ostr << len << ")\""; - ostr.write(buf, len); - ostr << "\""; - } - else - { - ostr << "0)\"\""; - } - break; - } - case xmlrpc_type_boolean: - //LL_DEBUGS() << "stream_out() bool" << LL_ENDL; - ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false"); - break; - case xmlrpc_type_datetime: - ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\""; - break; - case xmlrpc_type_double: - ostr << " r" << XMLRPC_GetValueDouble(value); - //LL_DEBUGS() << "stream_out() double" << XMLRPC_GetValueDouble(value) - // << LL_ENDL; - break; - case xmlrpc_type_int: - ostr << " i" << XMLRPC_GetValueInt(value); - //LL_DEBUGS() << "stream_out() integer:" << XMLRPC_GetValueInt(value) - // << LL_ENDL; - break; - case xmlrpc_type_string: - //LL_DEBUGS() << "stream_out() string: " << str << LL_ENDL; - ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'" - << XMLRPC_GetValueString(value) << "'"; - break; - case xmlrpc_type_array: // vector - case xmlrpc_type_mixed: // vector - { - //LL_DEBUGS() << "stream_out() array" << LL_ENDL; - ostr << " ["; - U32 needs_comma = 0; - XMLRPC_VALUE current = XMLRPC_VectorRewind(value); - while(current && (LLIOPipe::STATUS_OK == status)) - { - if(needs_comma++) ostr << ","; - status = stream_out(ostr, current); - current = XMLRPC_VectorNext(value); - } - ostr << "]"; - break; - } - case xmlrpc_type_struct: // still vector - { - //LL_DEBUGS() << "stream_out() struct" << LL_ENDL; - ostr << " {"; - std::string name; - U32 needs_comma = 0; - XMLRPC_VALUE current = XMLRPC_VectorRewind(value); - while(current && (LLIOPipe::STATUS_OK == status)) - { - if(needs_comma++) ostr << ","; - name.assign(XMLRPC_GetValueID(current)); - ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':"; - status = stream_out(ostr, current); - current = XMLRPC_VectorNext(value); - } - ostr << "}"; - break; - } - case xmlrpc_type_empty: - case xmlrpc_type_none: - default: - status = LLIOPipe::STATUS_ERROR; - LL_WARNS() << "Found an empty xmlrpc type.." << LL_ENDL; - // not much we can do here... - break; - }; - return status; + XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value); + LLIOPipe::EStatus status = LLIOPipe::STATUS_OK; + switch(type) + { + case xmlrpc_type_base64: + { + S32 len = XMLRPC_GetValueStringLen(value); + const char* buf = XMLRPC_GetValueBase64(value); + ostr << " b("; + if((len > 0) && buf) + { + ostr << len << ")\""; + ostr.write(buf, len); + ostr << "\""; + } + else + { + ostr << "0)\"\""; + } + break; + } + case xmlrpc_type_boolean: + //LL_DEBUGS() << "stream_out() bool" << LL_ENDL; + ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false"); + break; + case xmlrpc_type_datetime: + ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\""; + break; + case xmlrpc_type_double: + ostr << " r" << XMLRPC_GetValueDouble(value); + //LL_DEBUGS() << "stream_out() double" << XMLRPC_GetValueDouble(value) + // << LL_ENDL; + break; + case xmlrpc_type_int: + ostr << " i" << XMLRPC_GetValueInt(value); + //LL_DEBUGS() << "stream_out() integer:" << XMLRPC_GetValueInt(value) + // << LL_ENDL; + break; + case xmlrpc_type_string: + //LL_DEBUGS() << "stream_out() string: " << str << LL_ENDL; + ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'" + << XMLRPC_GetValueString(value) << "'"; + break; + case xmlrpc_type_array: // vector + case xmlrpc_type_mixed: // vector + { + //LL_DEBUGS() << "stream_out() array" << LL_ENDL; + ostr << " ["; + U32 needs_comma = 0; + XMLRPC_VALUE current = XMLRPC_VectorRewind(value); + while(current && (LLIOPipe::STATUS_OK == status)) + { + if(needs_comma++) ostr << ","; + status = stream_out(ostr, current); + current = XMLRPC_VectorNext(value); + } + ostr << "]"; + break; + } + case xmlrpc_type_struct: // still vector + { + //LL_DEBUGS() << "stream_out() struct" << LL_ENDL; + ostr << " {"; + std::string name; + U32 needs_comma = 0; + XMLRPC_VALUE current = XMLRPC_VectorRewind(value); + while(current && (LLIOPipe::STATUS_OK == status)) + { + if(needs_comma++) ostr << ","; + name.assign(XMLRPC_GetValueID(current)); + ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':"; + status = stream_out(ostr, current); + current = XMLRPC_VectorNext(value); + } + ostr << "}"; + break; + } + case xmlrpc_type_empty: + case xmlrpc_type_none: + default: + status = LLIOPipe::STATUS_ERROR; + LL_WARNS() << "Found an empty xmlrpc type.." << LL_ENDL; + // not much we can do here... + break; + }; + return status; } LLFilterXMLRPCResponse2LLSD::LLFilterXMLRPCResponse2LLSD() @@ -597,76 +597,76 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD() } LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; - if(!eos) return STATUS_BREAK; - if(!buffer) return STATUS_ERROR; - - PUMP_DEBUG; - // *FIX: This technique for reading data is far from optimal. We - // need to have some kind of istream interface into the xml - // parser... - S32 bytes = buffer->countAfter(channels.in(), NULL); - if(!bytes) return STATUS_ERROR; - char* buf = new char[bytes + 1]; - buf[bytes] = '\0'; - buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); - - //LL_DEBUGS() << "xmlrpc response: " << buf << LL_ENDL; - - PUMP_DEBUG; - XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML( - buf, - bytes, - NULL); - if(!response) - { - LL_WARNS() << "XML -> SD Response unable to parse xml." << LL_ENDL; - delete[] buf; - return STATUS_ERROR; - } - - PUMP_DEBUG; - LLBufferStream stream(channels, buffer.get()); - stream.precision(DEFAULT_PRECISION); - if(XMLRPC_ResponseIsFault(response)) - { - PUMP_DEBUG; - stream << LLSDRPC_FAULT_HADER_1 - << XMLRPC_GetResponseFaultCode(response) - << LLSDRPC_FAULT_HADER_2; - const char* fault_str = XMLRPC_GetResponseFaultString(response); - std::string fault_string; - if(fault_str) - { - fault_string.assign(fault_str); - } - stream << "'" << LLSDNotationFormatter::escapeString(fault_string) - << "'" <<LLSDRPC_FAULT_FOOTER; - } - else - { - PUMP_DEBUG; - stream << LLSDRPC_RESPONSE_HEADER; - XMLRPC_VALUE param = XMLRPC_RequestGetData(response); - if(param) - { - stream_out(stream, param); - } - stream << LLSDRPC_RESPONSE_FOOTER; - } - PUMP_DEBUG; - XMLRPC_RequestFree(response, 1); - delete[] buf; - PUMP_DEBUG; - return STATUS_DONE; + PUMP_DEBUG; + if(!eos) return STATUS_BREAK; + if(!buffer) return STATUS_ERROR; + + PUMP_DEBUG; + // *FIX: This technique for reading data is far from optimal. We + // need to have some kind of istream interface into the xml + // parser... + S32 bytes = buffer->countAfter(channels.in(), NULL); + if(!bytes) return STATUS_ERROR; + char* buf = new char[bytes + 1]; + buf[bytes] = '\0'; + buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); + + //LL_DEBUGS() << "xmlrpc response: " << buf << LL_ENDL; + + PUMP_DEBUG; + XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML( + buf, + bytes, + NULL); + if(!response) + { + LL_WARNS() << "XML -> SD Response unable to parse xml." << LL_ENDL; + delete[] buf; + return STATUS_ERROR; + } + + PUMP_DEBUG; + LLBufferStream stream(channels, buffer.get()); + stream.precision(DEFAULT_PRECISION); + if(XMLRPC_ResponseIsFault(response)) + { + PUMP_DEBUG; + stream << LLSDRPC_FAULT_HADER_1 + << XMLRPC_GetResponseFaultCode(response) + << LLSDRPC_FAULT_HADER_2; + const char* fault_str = XMLRPC_GetResponseFaultString(response); + std::string fault_string; + if(fault_str) + { + fault_string.assign(fault_str); + } + stream << "'" << LLSDNotationFormatter::escapeString(fault_string) + << "'" <<LLSDRPC_FAULT_FOOTER; + } + else + { + PUMP_DEBUG; + stream << LLSDRPC_RESPONSE_HEADER; + XMLRPC_VALUE param = XMLRPC_RequestGetData(response); + if(param) + { + stream_out(stream, param); + } + stream << LLSDRPC_RESPONSE_FOOTER; + } + PUMP_DEBUG; + XMLRPC_RequestFree(response, 1); + delete[] buf; + PUMP_DEBUG; + return STATUS_DONE; } /** @@ -681,98 +681,98 @@ LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD() } LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; - if(!eos) return STATUS_BREAK; - if(!buffer) return STATUS_ERROR; - - PUMP_DEBUG; - // *FIX: This technique for reading data is far from optimal. We - // need to have some kind of istream interface into the xml - // parser... - S32 bytes = buffer->countAfter(channels.in(), NULL); - if(!bytes) return STATUS_ERROR; - char* buf = new char[bytes + 1]; - buf[bytes] = '\0'; - buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); - - //LL_DEBUGS() << "xmlrpc request: " << buf << LL_ENDL; - - // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if - // values that are less than 0x20 are passed to it, except - // 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage - U8* cur_pBuf = (U8*)buf; + PUMP_DEBUG; + if(!eos) return STATUS_BREAK; + if(!buffer) return STATUS_ERROR; + + PUMP_DEBUG; + // *FIX: This technique for reading data is far from optimal. We + // need to have some kind of istream interface into the xml + // parser... + S32 bytes = buffer->countAfter(channels.in(), NULL); + if(!bytes) return STATUS_ERROR; + char* buf = new char[bytes + 1]; + buf[bytes] = '\0'; + buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); + + //LL_DEBUGS() << "xmlrpc request: " << buf << LL_ENDL; + + // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if + // values that are less than 0x20 are passed to it, except + // 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage + U8* cur_pBuf = (U8*)buf; U8 cur_char; - for (S32 i=0; i<bytes; i++) - { + for (S32 i=0; i<bytes; i++) + { cur_char = *cur_pBuf; - if ( cur_char < 0x20 + if ( cur_char < 0x20 && 0x09 != cur_char && 0x0a != cur_char && 0x0d != cur_char ) { - *cur_pBuf = '?'; + *cur_pBuf = '?'; + } + ++cur_pBuf; + } + + PUMP_DEBUG; + XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML( + buf, + bytes, + NULL); + if(!request) + { + LL_WARNS() << "XML -> SD Request process parse error." << LL_ENDL; + delete[] buf; + return STATUS_ERROR; + } + + PUMP_DEBUG; + LLBufferStream stream(channels, buffer.get()); + stream.precision(DEFAULT_PRECISION); + const char* name = XMLRPC_RequestGetMethodName(request); + stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "") + << LLSDRPC_REQUEST_HEADER_2; + XMLRPC_VALUE param = XMLRPC_RequestGetData(request); + if(param) + { + PUMP_DEBUG; + S32 size = XMLRPC_VectorSize(param); + if(size > 1) + { + // if there are multiple parameters, stuff the values into + // an array so that the next step in the chain can read them. + stream << "["; + } + XMLRPC_VALUE current = XMLRPC_VectorRewind(param); + bool needs_comma = false; + while(current) + { + if(needs_comma) + { + stream << ","; + } + needs_comma = true; + stream_out(stream, current); + current = XMLRPC_VectorNext(param); + } + if(size > 1) + { + // close the array + stream << "]"; } - ++cur_pBuf; - } - - PUMP_DEBUG; - XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML( - buf, - bytes, - NULL); - if(!request) - { - LL_WARNS() << "XML -> SD Request process parse error." << LL_ENDL; - delete[] buf; - return STATUS_ERROR; - } - - PUMP_DEBUG; - LLBufferStream stream(channels, buffer.get()); - stream.precision(DEFAULT_PRECISION); - const char* name = XMLRPC_RequestGetMethodName(request); - stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "") - << LLSDRPC_REQUEST_HEADER_2; - XMLRPC_VALUE param = XMLRPC_RequestGetData(request); - if(param) - { - PUMP_DEBUG; - S32 size = XMLRPC_VectorSize(param); - if(size > 1) - { - // if there are multiple parameters, stuff the values into - // an array so that the next step in the chain can read them. - stream << "["; - } - XMLRPC_VALUE current = XMLRPC_VectorRewind(param); - bool needs_comma = false; - while(current) - { - if(needs_comma) - { - stream << ","; - } - needs_comma = true; - stream_out(stream, current); - current = XMLRPC_VectorNext(param); - } - if(size > 1) - { - // close the array - stream << "]"; - } - } - stream << LLSDRPC_REQUEST_FOOTER; - XMLRPC_RequestFree(request, 1); - delete[] buf; - PUMP_DEBUG; - return STATUS_DONE; + } + stream << LLSDRPC_REQUEST_FOOTER; + XMLRPC_RequestFree(request, 1); + delete[] buf; + PUMP_DEBUG; + return STATUS_DONE; } diff --git a/indra/llmessage/llfiltersd2xmlrpc.h b/indra/llmessage/llfiltersd2xmlrpc.h index 0c9a0dc95b..55938d3e2b 100644 --- a/indra/llmessage/llfiltersd2xmlrpc.h +++ b/indra/llmessage/llfiltersd2xmlrpc.h @@ -1,4 +1,4 @@ -/** +/** * @file llfiltersd2xmlrpc.h * @author Phoenix * @date 2005-04-26 @@ -6,21 +6,21 @@ * $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$ */ @@ -38,9 +38,9 @@ #include <iosfwd> #include "lliopipe.h" -/** +/** * @class LLFilterSD2XMLRPC - * @brief Filter from serialized LLSD to an XMLRPC method call + * @brief Filter from serialized LLSD to an XMLRPC method call * * This clas provides common functionality for the LLFilterSD2XMLRPRC * request and response classes. @@ -48,19 +48,19 @@ class LLFilterSD2XMLRPC : public LLIOPipe { public: - LLFilterSD2XMLRPC(); - virtual ~LLFilterSD2XMLRPC(); + LLFilterSD2XMLRPC(); + virtual ~LLFilterSD2XMLRPC(); protected: - /** - * @brief helper method - */ - void streamOut(std::ostream& ostr, const LLSD& sd); + /** + * @brief helper method + */ + void streamOut(std::ostream& ostr, const LLSD& sd); }; -/** +/** * @class LLFilterSD2XMLRPCResponse - * @brief Filter from serialized LLSD to an XMLRPC response + * @brief Filter from serialized LLSD to an XMLRPC response * * This class filters a serialized LLSD object to an xmlrpc * repsonse. Since resonses are limited to a single param, the xmlrprc @@ -85,31 +85,31 @@ protected: class LLFilterSD2XMLRPCResponse : public LLFilterSD2XMLRPC { public: - // constructor - LLFilterSD2XMLRPCResponse(); + // constructor + LLFilterSD2XMLRPCResponse(); - // destructor - virtual ~LLFilterSD2XMLRPCResponse(); + // destructor + virtual ~LLFilterSD2XMLRPCResponse(); - /* @name LLIOPipe virtual implementations - */ - //@{ + /* @name LLIOPipe virtual implementations + */ + //@{ protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /** + * @brief Process the data in buffer. + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} }; -/** +/** * @class LLFilterSD2XMLRPCRequest - * @brief Filter from serialized LLSD to an XMLRPC method call + * @brief Filter from serialized LLSD to an XMLRPC method call * * This class will accept any kind of serialized LLSD object, but you * probably want to have an array on the outer boundary since this @@ -141,38 +141,38 @@ protected: class LLFilterSD2XMLRPCRequest : public LLFilterSD2XMLRPC { public: - // constructor - LLFilterSD2XMLRPCRequest(); + // constructor + LLFilterSD2XMLRPCRequest(); - // constructor - LLFilterSD2XMLRPCRequest(const char* method); + // constructor + LLFilterSD2XMLRPCRequest(const char* method); - // destructor - virtual ~LLFilterSD2XMLRPCRequest(); + // destructor + virtual ~LLFilterSD2XMLRPCRequest(); - /* @name LLIOPipe virtual implementations - */ - //@{ + /* @name LLIOPipe virtual implementations + */ + //@{ protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /** + * @brief Process the data in buffer. + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - // The method name of this request. - std::string mMethod; + // The method name of this request. + std::string mMethod; }; -/** +/** * @class LLFilterXMLRPCResponse2LLSD - * @brief Filter from serialized XMLRPC method response to LLSD + * @brief Filter from serialized XMLRPC method response to LLSD * * The xmlrpc spec states that responses can only have one element * which can be of any supported type. @@ -188,33 +188,33 @@ protected: class LLFilterXMLRPCResponse2LLSD : public LLIOPipe { public: - // constructor - LLFilterXMLRPCResponse2LLSD(); + // constructor + LLFilterXMLRPCResponse2LLSD(); - // destructor - virtual ~LLFilterXMLRPCResponse2LLSD(); + // destructor + virtual ~LLFilterXMLRPCResponse2LLSD(); - /* @name LLIOPipe virtual implementations - */ - //@{ + /* @name LLIOPipe virtual implementations + */ + //@{ protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /** + * @brief Process the data in buffer. + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: }; -/** +/** * @class LLFilterXMLRPCRequest2LLSD - * @brief Filter from serialized XMLRPC method call to LLSD + * @brief Filter from serialized XMLRPC method call to LLSD * * This takes in xml of the form: * <code> @@ -231,26 +231,26 @@ protected: class LLFilterXMLRPCRequest2LLSD : public LLIOPipe { public: - // constructor - LLFilterXMLRPCRequest2LLSD(); + // constructor + LLFilterXMLRPCRequest2LLSD(); - // destructor - virtual ~LLFilterXMLRPCRequest2LLSD(); + // destructor + virtual ~LLFilterXMLRPCRequest2LLSD(); - /* @name LLIOPipe virtual implementations - */ - //@{ + /* @name LLIOPipe virtual implementations + */ + //@{ protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /** + * @brief Process the data in buffer. + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: }; diff --git a/indra/llmessage/llfollowcamparams.h b/indra/llmessage/llfollowcamparams.h index 25208031db..f24b362c08 100644 --- a/indra/llmessage/llfollowcamparams.h +++ b/indra/llmessage/llfollowcamparams.h @@ -1,25 +1,25 @@ -/** +/** * @file llfollowcamparams.h * @brief Follow camera parameters. * * $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$ */ @@ -30,30 +30,30 @@ //Ventrella Follow Cam Script Stuff enum EFollowCamAttributes { - FOLLOWCAM_PITCH = 0, - FOLLOWCAM_FOCUS_OFFSET, - FOLLOWCAM_FOCUS_OFFSET_X, //this HAS to come after FOLLOWCAM_FOCUS_OFFSET in this list - FOLLOWCAM_FOCUS_OFFSET_Y, - FOLLOWCAM_FOCUS_OFFSET_Z, - FOLLOWCAM_POSITION_LAG, - FOLLOWCAM_FOCUS_LAG, - FOLLOWCAM_DISTANCE, - FOLLOWCAM_BEHINDNESS_ANGLE, - FOLLOWCAM_BEHINDNESS_LAG, - FOLLOWCAM_POSITION_THRESHOLD, - FOLLOWCAM_FOCUS_THRESHOLD, - FOLLOWCAM_ACTIVE, - FOLLOWCAM_POSITION, - FOLLOWCAM_POSITION_X, //this HAS to come after FOLLOWCAM_POSITION in this list - FOLLOWCAM_POSITION_Y, - FOLLOWCAM_POSITION_Z, - FOLLOWCAM_FOCUS, - FOLLOWCAM_FOCUS_X, //this HAS to come after FOLLOWCAM_FOCUS in this list - FOLLOWCAM_FOCUS_Y, - FOLLOWCAM_FOCUS_Z, - FOLLOWCAM_POSITION_LOCKED, - FOLLOWCAM_FOCUS_LOCKED, - NUM_FOLLOWCAM_ATTRIBUTES + FOLLOWCAM_PITCH = 0, + FOLLOWCAM_FOCUS_OFFSET, + FOLLOWCAM_FOCUS_OFFSET_X, //this HAS to come after FOLLOWCAM_FOCUS_OFFSET in this list + FOLLOWCAM_FOCUS_OFFSET_Y, + FOLLOWCAM_FOCUS_OFFSET_Z, + FOLLOWCAM_POSITION_LAG, + FOLLOWCAM_FOCUS_LAG, + FOLLOWCAM_DISTANCE, + FOLLOWCAM_BEHINDNESS_ANGLE, + FOLLOWCAM_BEHINDNESS_LAG, + FOLLOWCAM_POSITION_THRESHOLD, + FOLLOWCAM_FOCUS_THRESHOLD, + FOLLOWCAM_ACTIVE, + FOLLOWCAM_POSITION, + FOLLOWCAM_POSITION_X, //this HAS to come after FOLLOWCAM_POSITION in this list + FOLLOWCAM_POSITION_Y, + FOLLOWCAM_POSITION_Z, + FOLLOWCAM_FOCUS, + FOLLOWCAM_FOCUS_X, //this HAS to come after FOLLOWCAM_FOCUS in this list + FOLLOWCAM_FOCUS_Y, + FOLLOWCAM_FOCUS_Z, + FOLLOWCAM_POSITION_LOCKED, + FOLLOWCAM_FOCUS_LOCKED, + NUM_FOLLOWCAM_ATTRIBUTES }; //end Ventrella diff --git a/indra/llmessage/llgenericstreamingmessage.cpp b/indra/llmessage/llgenericstreamingmessage.cpp index 8627675c54..d7f4860a5f 100644 --- a/indra/llmessage/llgenericstreamingmessage.cpp +++ b/indra/llmessage/llgenericstreamingmessage.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, 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$ */ diff --git a/indra/llmessage/llgenericstreamingmessage.h b/indra/llmessage/llgenericstreamingmessage.h index 9ac9719ea1..a24e6435bd 100644 --- a/indra/llmessage/llgenericstreamingmessage.h +++ b/indra/llmessage/llgenericstreamingmessage.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, 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$ */ diff --git a/indra/llmessage/llhost.cpp b/indra/llmessage/llhost.cpp index 30e4109729..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 dd12e381d4..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/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 6e9598a0a3..65bdfaff7e 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llhttpnode.cpp * @brief Implementation of classes for generic HTTP/LSL/REST handling. * * $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$ */ @@ -44,77 +44,77 @@ const std::string CONTEXT_WILDCARD("wildcard"); /** * LLHTTPNode */ - + class LLHTTPNode::Impl { public: - typedef std::map<std::string, LLHTTPNode*> ChildMap; - - ChildMap mNamedChildren; - LLHTTPNode* mWildcardChild; - std::string mWildcardName; - std::string mWildcardKey; - LLHTTPNode* mParentNode; - - Impl() : mWildcardChild(NULL), mParentNode(NULL) { } - - LLHTTPNode* findNamedChild(const std::string& name) const; + typedef std::map<std::string, LLHTTPNode*> ChildMap; + + ChildMap mNamedChildren; + LLHTTPNode* mWildcardChild; + std::string mWildcardName; + std::string mWildcardKey; + LLHTTPNode* mParentNode; + + Impl() : mWildcardChild(NULL), mParentNode(NULL) { } + + LLHTTPNode* findNamedChild(const std::string& name) const; }; LLHTTPNode* LLHTTPNode::Impl::findNamedChild(const std::string& name) const { - LLHTTPNode* child = get_ptr_in_map(mNamedChildren, name); + LLHTTPNode* child = get_ptr_in_map(mNamedChildren, name); - if (!child && ((name[0] == '*') || (name == mWildcardName))) - { - child = mWildcardChild; - } - - return child; + if (!child && ((name[0] == '*') || (name == mWildcardName))) + { + child = mWildcardChild; + } + + return child; } LLHTTPNode::LLHTTPNode() - : impl(* new Impl) + : impl(* new Impl) { } // virtual LLHTTPNode::~LLHTTPNode() { - std::for_each(impl.mNamedChildren.begin(), impl.mNamedChildren.end(), DeletePairedPointer()); - impl.mNamedChildren.clear(); + std::for_each(impl.mNamedChildren.begin(), impl.mNamedChildren.end(), DeletePairedPointer()); + impl.mNamedChildren.clear(); + + delete impl.mWildcardChild; - delete impl.mWildcardChild; - - delete &impl; + delete &impl; } namespace { - struct NotImplemented: public LLException - { - NotImplemented(): LLException("LLHTTPNode::NotImplemented") {} - }; + struct NotImplemented: public LLException + { + NotImplemented(): LLException("LLHTTPNode::NotImplemented") {} + }; } // virtual LLSD LLHTTPNode::simpleGet() const { - LLTHROW(NotImplemented()); + LLTHROW(NotImplemented()); } // virtual LLSD LLHTTPNode::simplePut(const LLSD& input) const { - LLTHROW(NotImplemented()); + LLTHROW(NotImplemented()); } // virtual LLSD LLHTTPNode::simplePost(const LLSD& input) const { - LLTHROW(NotImplemented()); + LLTHROW(NotImplemented()); } @@ -122,42 +122,42 @@ LLSD LLHTTPNode::simplePost(const LLSD& input) const void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const { LL_PROFILE_ZONE_SCOPED; - try - { - response->result(simpleGet()); - } - catch (NotImplemented&) - { - response->methodNotAllowed(); - } + try + { + response->result(simpleGet()); + } + catch (NotImplemented&) + { + response->methodNotAllowed(); + } } // virtual void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { LL_PROFILE_ZONE_SCOPED; - try - { - response->result(simplePut(input)); - } - catch (NotImplemented&) - { - response->methodNotAllowed(); - } + try + { + response->result(simplePut(input)); + } + catch (NotImplemented&) + { + response->methodNotAllowed(); + } } // virtual void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { LL_PROFILE_ZONE_SCOPED; - try - { - response->result(simplePost(input)); - } - catch (NotImplemented&) - { - response->methodNotAllowed(); - } + try + { + response->result(simplePost(input)); + } + catch (NotImplemented&) + { + response->methodNotAllowed(); + } } // virtual @@ -166,11 +166,11 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons LL_PROFILE_ZONE_SCOPED; try { - response->result(simpleDel(context)); + response->result(simpleDel(context)); } catch (NotImplemented&) { - response->methodNotAllowed(); + response->methodNotAllowed(); } } @@ -178,218 +178,218 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons // virtual LLSD LLHTTPNode::simpleDel(const LLSD&) const { - LLTHROW(NotImplemented()); + LLTHROW(NotImplemented()); } // virtual void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const { - //LL_INFOS() << "options context: " << context << LL_ENDL; - LL_DEBUGS("LLHTTPNode") << "context: " << context << LL_ENDL; + //LL_INFOS() << "options context: " << context << LL_ENDL; + LL_DEBUGS("LLHTTPNode") << "context: " << context << LL_ENDL; - // default implementation constructs an url to the documentation. - // *TODO: Check for 'Host' header instead of 'host' header? - std::string host( - context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_IN_HEADER_HOST].asString()); - if(host.empty()) - { - response->status(HTTP_BAD_REQUEST, "Bad Request -- need Host header"); - return; - } - std::ostringstream ostr; - ostr << "http://" << host << "/web/server/api"; - ostr << context[CONTEXT_REQUEST][CONTEXT_PATH].asString(); - static const std::string DOC_HEADER("X-Documentation-URL"); - response->addHeader(DOC_HEADER, ostr.str()); - response->status(HTTP_OK, "OK"); + // default implementation constructs an url to the documentation. + // *TODO: Check for 'Host' header instead of 'host' header? + std::string host( + context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_IN_HEADER_HOST].asString()); + if(host.empty()) + { + response->status(HTTP_BAD_REQUEST, "Bad Request -- need Host header"); + return; + } + std::ostringstream ostr; + ostr << "http://" << host << "/web/server/api"; + ostr << context[CONTEXT_REQUEST][CONTEXT_PATH].asString(); + static const std::string DOC_HEADER("X-Documentation-URL"); + response->addHeader(DOC_HEADER, ostr.str()); + response->status(HTTP_OK, "OK"); } // virtual LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const { - LLHTTPNode* namedChild = get_ptr_in_map(impl.mNamedChildren, name); - if (namedChild) - { - return namedChild; - } - - if (impl.mWildcardChild - && impl.mWildcardChild->validate(name, context)) - { - context[CONTEXT_REQUEST][CONTEXT_WILDCARD][impl.mWildcardKey] = name; - return impl.mWildcardChild; - } - - return NULL; + LLHTTPNode* namedChild = get_ptr_in_map(impl.mNamedChildren, name); + if (namedChild) + { + return namedChild; + } + + if (impl.mWildcardChild + && impl.mWildcardChild->validate(name, context)) + { + context[CONTEXT_REQUEST][CONTEXT_WILDCARD][impl.mWildcardKey] = name; + return impl.mWildcardChild; + } + + return NULL; } // virtual bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const { - return remainder.size() == 0; + return remainder.size() == 0; } // virtual bool LLHTTPNode::validate(const std::string& name, LLSD& context) const { - return false; + return false; } const LLHTTPNode* LLHTTPNode::traverse( - const std::string& path, LLSD& context) const + const std::string& path, LLSD& context) const { - typedef boost::tokenizer< boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("/", "", boost::drop_empty_tokens); - tokenizer tokens(path, sep); - tokenizer::iterator iter = tokens.begin(); - tokenizer::iterator end = tokens.end(); + typedef boost::tokenizer< boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("/", "", boost::drop_empty_tokens); + tokenizer tokens(path, sep); + tokenizer::iterator iter = tokens.begin(); + tokenizer::iterator end = tokens.end(); - const LLHTTPNode* node = this; - for(; iter != end; ++iter) - { - LLHTTPNode* child = node->getChild(*iter, context); - if(!child) - { - LL_DEBUGS() << "LLHTTPNode::traverse: Couldn't find '" << *iter << "'" << LL_ENDL; - break; - } - LL_DEBUGS() << "LLHTTPNode::traverse: Found '" << *iter << "'" << LL_ENDL; - - node = child; - } + const LLHTTPNode* node = this; + for(; iter != end; ++iter) + { + LLHTTPNode* child = node->getChild(*iter, context); + if(!child) + { + LL_DEBUGS() << "LLHTTPNode::traverse: Couldn't find '" << *iter << "'" << LL_ENDL; + break; + } + LL_DEBUGS() << "LLHTTPNode::traverse: Found '" << *iter << "'" << LL_ENDL; + + node = child; + } - LLSD& remainder = context[CONTEXT_REQUEST]["remainder"]; - for(; iter != end; ++iter) - { - remainder.append(*iter); - } + LLSD& remainder = context[CONTEXT_REQUEST]["remainder"]; + for(; iter != end; ++iter) + { + remainder.append(*iter); + } - return node->handles(remainder, context) ? node : NULL; + return node->handles(remainder, context) ? node : NULL; } void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd) { - typedef boost::tokenizer< boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("/", "", boost::drop_empty_tokens); - tokenizer tokens(path, sep); - tokenizer::iterator iter = tokens.begin(); - tokenizer::iterator end = tokens.end(); - - LLHTTPNode* node = this; - for(; iter != end; ++iter) - { - LLHTTPNode* child = node->impl.findNamedChild(*iter); - if (!child) { break; } - node = child; - } - - if (iter == end) - { - LL_WARNS() << "LLHTTPNode::addNode: already a node that handles " - << path << LL_ENDL; - return; - } - - while (true) - { - std::string pathPart = *iter; - - ++iter; - bool lastOne = iter == end; - - LLHTTPNode* nextNode = lastOne ? nodeToAdd : new LLHTTPNode(); - - switch (pathPart[0]) - { - case '<': - // *NOTE: This should really validate that it is of - // the proper form: <wildcardkey> so that the substr() - // generates the correct key name. - node->impl.mWildcardChild = nextNode; - node->impl.mWildcardName = pathPart; - if(node->impl.mWildcardKey.empty()) - { - node->impl.mWildcardKey = pathPart.substr( - 1, - pathPart.size() - 2); - } - break; - case '*': - node->impl.mWildcardChild = nextNode; - if(node->impl.mWildcardName.empty()) - { - node->impl.mWildcardName = pathPart; - } - break; - - default: - node->impl.mNamedChildren[pathPart] = nextNode; - } - nextNode->impl.mParentNode = node; - - if (lastOne) break; - node = nextNode; - } + typedef boost::tokenizer< boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("/", "", boost::drop_empty_tokens); + tokenizer tokens(path, sep); + tokenizer::iterator iter = tokens.begin(); + tokenizer::iterator end = tokens.end(); + + LLHTTPNode* node = this; + for(; iter != end; ++iter) + { + LLHTTPNode* child = node->impl.findNamedChild(*iter); + if (!child) { break; } + node = child; + } + + if (iter == end) + { + LL_WARNS() << "LLHTTPNode::addNode: already a node that handles " + << path << LL_ENDL; + return; + } + + while (true) + { + std::string pathPart = *iter; + + ++iter; + bool lastOne = iter == end; + + LLHTTPNode* nextNode = lastOne ? nodeToAdd : new LLHTTPNode(); + + switch (pathPart[0]) + { + case '<': + // *NOTE: This should really validate that it is of + // the proper form: <wildcardkey> so that the substr() + // generates the correct key name. + node->impl.mWildcardChild = nextNode; + node->impl.mWildcardName = pathPart; + if(node->impl.mWildcardKey.empty()) + { + node->impl.mWildcardKey = pathPart.substr( + 1, + pathPart.size() - 2); + } + break; + case '*': + node->impl.mWildcardChild = nextNode; + if(node->impl.mWildcardName.empty()) + { + node->impl.mWildcardName = pathPart; + } + break; + + default: + node->impl.mNamedChildren[pathPart] = nextNode; + } + nextNode->impl.mParentNode = node; + + if (lastOne) break; + node = nextNode; + } } static void append_node_paths(LLSD& result, - const std::string& name, const LLHTTPNode* node) + const std::string& name, const LLHTTPNode* node) { - result.append(name); - - LLSD paths = node->allNodePaths(); - LLSD::array_const_iterator i = paths.beginArray(); - LLSD::array_const_iterator end = paths.endArray(); - - for (; i != end; ++i) - { - result.append(name + "/" + (*i).asString()); - } + result.append(name); + + LLSD paths = node->allNodePaths(); + LLSD::array_const_iterator i = paths.beginArray(); + LLSD::array_const_iterator end = paths.endArray(); + + for (; i != end; ++i) + { + result.append(name + "/" + (*i).asString()); + } } LLSD LLHTTPNode::allNodePaths() const { - LLSD result; - - Impl::ChildMap::const_iterator i = impl.mNamedChildren.begin(); - Impl::ChildMap::const_iterator end = impl.mNamedChildren.end(); - for (; i != end; ++i) - { - append_node_paths(result, i->first, i->second); - } - - if (impl.mWildcardChild) - { - append_node_paths(result, impl.mWildcardName, impl.mWildcardChild); - } - - return result; + LLSD result; + + Impl::ChildMap::const_iterator i = impl.mNamedChildren.begin(); + Impl::ChildMap::const_iterator end = impl.mNamedChildren.end(); + for (; i != end; ++i) + { + append_node_paths(result, i->first, i->second); + } + + if (impl.mWildcardChild) + { + append_node_paths(result, impl.mWildcardName, impl.mWildcardChild); + } + + return result; } const LLHTTPNode* LLHTTPNode::rootNode() const { - const LLHTTPNode* node = this; - - while (true) - { - const LLHTTPNode* next = node->impl.mParentNode; - if (!next) - { - return node; - } - node = next; - } + const LLHTTPNode* node = this; + + while (true) + { + const LLHTTPNode* next = node->impl.mParentNode; + if (!next) + { + return node; + } + node = next; + } } const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const { - return impl.findNamedChild(name); + return impl.findNamedChild(name); } LLHTTPNode::Response::~Response() @@ -398,40 +398,40 @@ LLHTTPNode::Response::~Response() void LLHTTPNode::Response::statusUnknownError(S32 code) { - status(code, "Unknown Error"); + status(code, "Unknown Error"); } void LLHTTPNode::Response::notFound(const std::string& message) { - status(HTTP_NOT_FOUND, message); + status(HTTP_NOT_FOUND, message); } void LLHTTPNode::Response::notFound() { - status(HTTP_NOT_FOUND, "Not Found"); + status(HTTP_NOT_FOUND, "Not Found"); } void LLHTTPNode::Response::methodNotAllowed() { - status(HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed"); + status(HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed"); } void LLHTTPNode::Response::addHeader( - const std::string& name, - const std::string& value) + const std::string& name, + const std::string& value) { - mHeaders[name] = value; + mHeaders[name] = value; } void LLHTTPNode::describe(Description& desc) const { - desc.shortInfo("unknown service (missing describe() method)"); + desc.shortInfo("unknown service (missing describe() method)"); } const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const { - return NULL; + return NULL; } @@ -439,7 +439,7 @@ const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const namespace { typedef std::map<std::string, LLHTTPRegistrar::NodeFactory*> FactoryMap; - + FactoryMap& factoryMap() { static FactoryMap theMap; @@ -452,27 +452,27 @@ LLHTTPRegistrar::NodeFactory::~NodeFactory() { } void LLHTTPRegistrar::registerFactory( const std::string& path, NodeFactory& factory) { - factoryMap()[path] = &factory; + factoryMap()[path] = &factory; } void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root) { const FactoryMap& map = factoryMap(); - + FactoryMap::const_iterator i = map.begin(); FactoryMap::const_iterator end = map.end(); for (; i != end; ++i) { - LL_DEBUGS("AppInit") << "LLHTTPRegistrar::buildAllServices adding node for path " - << i->first << LL_ENDL; - + LL_DEBUGS("AppInit") << "LLHTTPRegistrar::buildAllServices adding node for path " + << i->first << LL_ENDL; + root.addNode(i->first, i->second->build()); } } LLPointer<LLSimpleResponse> LLSimpleResponse::create() { - return new LLSimpleResponse(); + return new LLSimpleResponse(); } LLSimpleResponse::~LLSimpleResponse() @@ -481,33 +481,33 @@ LLSimpleResponse::~LLSimpleResponse() void LLSimpleResponse::result(const LLSD& result) { - status(HTTP_OK, "OK"); + status(HTTP_OK, "OK"); } void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const LLSD& headers) { - status(code,body); + status(code,body); } void LLSimpleResponse::extendedResult(S32 code, const LLSD& r, const LLSD& headers) { - status(code,"(LLSD)"); + status(code,"(LLSD)"); } void LLSimpleResponse::status(S32 code, const std::string& message) { - mCode = code; - mMessage = message; + mCode = code; + mMessage = message; } void LLSimpleResponse::print(std::ostream& out) const { - out << mCode << " " << mMessage; + out << mCode << " " << mMessage; } std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp) { - resp.print(out); - return out; + resp.print(out); + return out; } diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h index 1144d88be1..b7b6053f48 100644 --- a/indra/llmessage/llhttpnode.h +++ b/indra/llmessage/llhttpnode.h @@ -1,25 +1,25 @@ -/** +/** * @file llhttpnode.h * @brief Declaration of classes for generic HTTP/LSL/REST handling. * * $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$ */ @@ -47,16 +47,16 @@ class LLChainIOFactory; /** * These classes represent the HTTP framework: The URL tree, and the LLSD * REST interface that such nodes implement. - * + * * To implement a service, in most cases, subclass LLHTTPNode, implement * get() or post(), and create a global instance of LLHTTPRegistration<>. * This can all be done in a .cpp file, with no publically declared parts. - * + * * To implement a server see lliohttpserver.h * @see LLHTTPWireServer */ -/** +/** * @class LLHTTPNode * @brief Base class which handles url traversal, response routing * and support for standard LLSD services @@ -74,226 +74,226 @@ class LLHTTPNode protected: LOG_CLASS(LLHTTPNode); public: - LLHTTPNode(); - virtual ~LLHTTPNode(); - - /** @name Responses - Most subclasses override one or more of these methods to provide - the service. By default, the rest of the LLHTTPNode architecture - will handle requests, create the needed LLIOPump, parse the input - to LLSD, and format the LLSD result to the output. - - The default implementation of each of these is to call - response->methodNotAllowed(); The "simple" versions can be - overridden instead in those cases where the service can return - an immediately computed response. - */ - //@{ -public: - - virtual LLSD simpleGet() const; - virtual LLSD simplePut(const LLSD& input) const; - virtual LLSD simplePost(const LLSD& input) const; - virtual LLSD simpleDel(const LLSD& context) const; - - /** - * @brief Abstract Base Class declaring Response interface. - */ - class Response : public LLRefCount - { - protected: - virtual ~Response(); - - public: - /** - * @brief Return the LLSD content and a 200 OK. - */ - virtual void result(const LLSD&) = 0; - - /** - * @brief return status code and message with headers. - */ - virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers = LLSD()) = 0; - - /** - * @brief return status code and LLSD result with headers. - */ - virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers = LLSD()) = 0; - - /** - * @brief return status code and reason string on http header, - * but do not return a payload. - */ - virtual void status(S32 code, const std::string& message) = 0; - - /** - * @brief Return no body, just status code and 'UNKNOWN ERROR'. - */ - virtual void statusUnknownError(S32 code); - - virtual void notFound(const std::string& message); - virtual void notFound(); - virtual void methodNotAllowed(); - - /** - * @brief Add a name: value http header. - * - * No effort is made to ensure the response is a valid http - * header. - * The headers are stored as a map of header name : value. - * Though HTTP allows the same header name to be transmitted - * more than once, this implementation only stores a header - * name once. - * @param name The name of the header, eg, "Content-Encoding" - * @param value The value of the header, eg, "gzip" - */ - virtual void addHeader(const std::string& name, const std::string& value); - - protected: - /** - * @brief Headers to be sent back with the HTTP response. - * - * Protected class membership since derived classes are - * expected to use it and there is no use case yet for other - * uses. If such a use case arises, I suggest making a - * headers() public method, and moving this member data into - * private. - */ - LLSD mHeaders; - }; - - typedef LLPointer<Response> ResponsePtr; - - virtual void get(ResponsePtr, const LLSD& context) const; - virtual void put( - ResponsePtr, - const LLSD& context, - const LLSD& input) const; - virtual void post( - ResponsePtr, - const LLSD& context, - const LLSD& input) const; - virtual void del(ResponsePtr, const LLSD& context) const; - virtual void options(ResponsePtr, const LLSD& context) const; - //@} - - - /** @name URL traversal - The tree is traversed by calling getChild() with successive - path components, on successive results. When getChild() returns - null, or there are no more components, the last child responds to - the request. - - The default behavior is generally correct, though wildcard nodes - will want to implement validate(). - */ - //@{ + LLHTTPNode(); + virtual ~LLHTTPNode(); + + /** @name Responses + Most subclasses override one or more of these methods to provide + the service. By default, the rest of the LLHTTPNode architecture + will handle requests, create the needed LLIOPump, parse the input + to LLSD, and format the LLSD result to the output. + + The default implementation of each of these is to call + response->methodNotAllowed(); The "simple" versions can be + overridden instead in those cases where the service can return + an immediately computed response. + */ + //@{ +public: + + virtual LLSD simpleGet() const; + virtual LLSD simplePut(const LLSD& input) const; + virtual LLSD simplePost(const LLSD& input) const; + virtual LLSD simpleDel(const LLSD& context) const; + + /** + * @brief Abstract Base Class declaring Response interface. + */ + class Response : public LLRefCount + { + protected: + virtual ~Response(); + + public: + /** + * @brief Return the LLSD content and a 200 OK. + */ + virtual void result(const LLSD&) = 0; + + /** + * @brief return status code and message with headers. + */ + virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers = LLSD()) = 0; + + /** + * @brief return status code and LLSD result with headers. + */ + virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers = LLSD()) = 0; + + /** + * @brief return status code and reason string on http header, + * but do not return a payload. + */ + virtual void status(S32 code, const std::string& message) = 0; + + /** + * @brief Return no body, just status code and 'UNKNOWN ERROR'. + */ + virtual void statusUnknownError(S32 code); + + virtual void notFound(const std::string& message); + virtual void notFound(); + virtual void methodNotAllowed(); + + /** + * @brief Add a name: value http header. + * + * No effort is made to ensure the response is a valid http + * header. + * The headers are stored as a map of header name : value. + * Though HTTP allows the same header name to be transmitted + * more than once, this implementation only stores a header + * name once. + * @param name The name of the header, eg, "Content-Encoding" + * @param value The value of the header, eg, "gzip" + */ + virtual void addHeader(const std::string& name, const std::string& value); + + protected: + /** + * @brief Headers to be sent back with the HTTP response. + * + * Protected class membership since derived classes are + * expected to use it and there is no use case yet for other + * uses. If such a use case arises, I suggest making a + * headers() public method, and moving this member data into + * private. + */ + LLSD mHeaders; + }; + + typedef LLPointer<Response> ResponsePtr; + + virtual void get(ResponsePtr, const LLSD& context) const; + virtual void put( + ResponsePtr, + const LLSD& context, + const LLSD& input) const; + virtual void post( + ResponsePtr, + const LLSD& context, + const LLSD& input) const; + virtual void del(ResponsePtr, const LLSD& context) const; + virtual void options(ResponsePtr, const LLSD& context) const; + //@} + + + /** @name URL traversal + The tree is traversed by calling getChild() with successive + path components, on successive results. When getChild() returns + null, or there are no more components, the last child responds to + the request. + + The default behavior is generally correct, though wildcard nodes + will want to implement validate(). + */ + //@{ public: - virtual LLHTTPNode* getChild(const std::string& name, LLSD& context) const; - /**< returns a child node, if any, at the given name - default looks at children and wildcard child (see below) - */ - - virtual bool handles(const LLSD& remainder, LLSD& context) const; - /**< return true if this node can service the remaining components; - default returns true if there are no remaining components - */ - - virtual bool validate(const std::string& name, LLSD& context) const; - /**< called only on wildcard nodes, to check if they will handle - the name; default is false; overrides will want to check - name, and return true if the name will construct to a valid url. - For convenience, the <code>getChild()</code> method above will - automatically insert the name in - context[CONTEXT_REQUEST][CONTEXT_WILDCARD][key] if this method returns true. - For example, the node "agent/<agent_id>/detail" will set - context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["agent_id"] eqaul to the value - found during traversal. - */ - - const LLHTTPNode* traverse(const std::string& path, LLSD& context) const; - /**< find a node, if any, that can service this path - set up context[CONTEXT_REQUEST] information - */ - //@} - - /** @name Child Nodes - The standard node can have any number of child nodes under - fixed names, and optionally one "wildcard" node that can - handle all other names. - - Usually, child nodes are add through LLHTTPRegistration, not - by calling this interface directly. - - The added node will be now owned by the parent node. - */ - //@{ - - virtual void addNode(const std::string& path, LLHTTPNode* nodeToAdd); - - LLSD allNodePaths() const; - ///< Returns an arrary of node paths at and under this node - - const LLHTTPNode* rootNode() const; - const LLHTTPNode* findNode(const std::string& name) const; - - - enum EHTTPNodeContentType - { - CONTENT_TYPE_LLSD, - CONTENT_TYPE_TEXT - }; - - virtual EHTTPNodeContentType getContentType() const { return CONTENT_TYPE_LLSD; } - //@} - - /* @name Description system - The Description object contains information about a service. - All subclasses of LLHTTPNode should override describe() and use - the methods of the Description class to set the various properties. - */ - //@{ - class Description - { - public: - void shortInfo(const std::string& s){ mInfo["description"] = s; } - void longInfo(const std::string& s) { mInfo["details"] = s; } - - // Call this method when the service supports the specified verb. - void getAPI() { mInfo["api"].append("GET"); } - void putAPI() { mInfo["api"].append("PUT"); } - void postAPI() { mInfo["api"].append("POST"); } - void delAPI() { mInfo["api"].append("DELETE"); } - - void input(const std::string& s) { mInfo["input"] = s; } - void output(const std::string& s) { mInfo["output"] = s; } - void source(const char* f, int l) { mInfo["__file__"] = f; - mInfo["__line__"] = l; } - - LLSD getInfo() const { return mInfo; } - - private: - LLSD mInfo; - }; - - virtual void describe(Description&) const; - - //@} - - - virtual const LLChainIOFactory* getProtocolHandler() const; - /**< Return a factory object for handling wire protocols. - * The base class returns NULL, as it doesn't know about - * wire protocols at all. This is okay for most nodes - * as LLIOHTTPServer is smart enough to use a default - * wire protocol for HTTP for such nodes. Specialized - * subclasses that handle things like XML-RPC will want - * to implement this. (See LLXMLSDRPCServerFactory.) - */ + virtual LLHTTPNode* getChild(const std::string& name, LLSD& context) const; + /**< returns a child node, if any, at the given name + default looks at children and wildcard child (see below) + */ + + virtual bool handles(const LLSD& remainder, LLSD& context) const; + /**< return true if this node can service the remaining components; + default returns true if there are no remaining components + */ + + virtual bool validate(const std::string& name, LLSD& context) const; + /**< called only on wildcard nodes, to check if they will handle + the name; default is false; overrides will want to check + name, and return true if the name will construct to a valid url. + For convenience, the <code>getChild()</code> method above will + automatically insert the name in + context[CONTEXT_REQUEST][CONTEXT_WILDCARD][key] if this method returns true. + For example, the node "agent/<agent_id>/detail" will set + context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["agent_id"] eqaul to the value + found during traversal. + */ + + const LLHTTPNode* traverse(const std::string& path, LLSD& context) const; + /**< find a node, if any, that can service this path + set up context[CONTEXT_REQUEST] information + */ + //@} + + /** @name Child Nodes + The standard node can have any number of child nodes under + fixed names, and optionally one "wildcard" node that can + handle all other names. + + Usually, child nodes are add through LLHTTPRegistration, not + by calling this interface directly. + + The added node will be now owned by the parent node. + */ + //@{ + + virtual void addNode(const std::string& path, LLHTTPNode* nodeToAdd); + + LLSD allNodePaths() const; + ///< Returns an arrary of node paths at and under this node + + const LLHTTPNode* rootNode() const; + const LLHTTPNode* findNode(const std::string& name) const; + + + enum EHTTPNodeContentType + { + CONTENT_TYPE_LLSD, + CONTENT_TYPE_TEXT + }; + + virtual EHTTPNodeContentType getContentType() const { return CONTENT_TYPE_LLSD; } + //@} + + /* @name Description system + The Description object contains information about a service. + All subclasses of LLHTTPNode should override describe() and use + the methods of the Description class to set the various properties. + */ + //@{ + class Description + { + public: + void shortInfo(const std::string& s){ mInfo["description"] = s; } + void longInfo(const std::string& s) { mInfo["details"] = s; } + + // Call this method when the service supports the specified verb. + void getAPI() { mInfo["api"].append("GET"); } + void putAPI() { mInfo["api"].append("PUT"); } + void postAPI() { mInfo["api"].append("POST"); } + void delAPI() { mInfo["api"].append("DELETE"); } + + void input(const std::string& s) { mInfo["input"] = s; } + void output(const std::string& s) { mInfo["output"] = s; } + void source(const char* f, int l) { mInfo["__file__"] = f; + mInfo["__line__"] = l; } + + LLSD getInfo() const { return mInfo; } + + private: + LLSD mInfo; + }; + + virtual void describe(Description&) const; + + //@} + + + virtual const LLChainIOFactory* getProtocolHandler() const; + /**< Return a factory object for handling wire protocols. + * The base class returns NULL, as it doesn't know about + * wire protocols at all. This is okay for most nodes + * as LLIOHTTPServer is smart enough to use a default + * wire protocol for HTTP for such nodes. Specialized + * subclasses that handle things like XML-RPC will want + * to implement this. (See LLXMLSDRPCServerFactory.) + */ private: - class Impl; - Impl& impl; + class Impl; + Impl& impl; }; @@ -301,20 +301,20 @@ private: class LLSimpleResponse : public LLHTTPNode::Response { public: - static LLPointer<LLSimpleResponse> create(); - - void result(const LLSD& result); - void extendedResult(S32 code, const std::string& body, const LLSD& headers); - void extendedResult(S32 code, const LLSD& result, const LLSD& headers); - void status(S32 code, const std::string& message); + static LLPointer<LLSimpleResponse> create(); + + void result(const LLSD& result); + void extendedResult(S32 code, const std::string& body, const LLSD& headers); + void extendedResult(S32 code, const LLSD& result, const LLSD& headers); + void status(S32 code, const std::string& message); - void print(std::ostream& out) const; + void print(std::ostream& out) const; - S32 mCode; - std::string mMessage; + S32 mCode; + std::string mMessage; protected: - ~LLSimpleResponse(); + ~LLSimpleResponse(); private: LLSimpleResponse() : mCode(0) {} // Must be accessed through LLPointer. @@ -324,13 +324,13 @@ std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp); -/** - * @name Automatic LLHTTPNode registration +/** + * @name Automatic LLHTTPNode registration * * To register a node type at a particular url path, construct a global instance * of LLHTTPRegistration: * - * LLHTTPRegistration<LLMyNodeType> gHTTPServiceAlphaBeta("/alpha/beta"); + * LLHTTPRegistration<LLMyNodeType> gHTTPServiceAlphaBeta("/alpha/beta"); * * (Note the naming convention carefully.) This object must be global and not * static. However, it needn't be declared in your .h file. It can exist @@ -340,68 +340,68 @@ std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp); * When constructing a web server, use LLHTTPRegistrar to add all the registered * nodes to the url tree: * - * LLHTTPRegistrar::buidlAllServices(mRootNode); + * LLHTTPRegistrar::buidlAllServices(mRootNode); */ //@{ class LLHTTPRegistrar { public: - class NodeFactory - { - public: - virtual ~NodeFactory(); - virtual LLHTTPNode* build() const = 0; - }; + class NodeFactory + { + public: + virtual ~NodeFactory(); + virtual LLHTTPNode* build() const = 0; + }; - static void buildAllServices(LLHTTPNode& root); + static void buildAllServices(LLHTTPNode& root); - static void registerFactory(const std::string& path, NodeFactory& factory); - ///< construct an LLHTTPRegistration below to call this + static void registerFactory(const std::string& path, NodeFactory& factory); + ///< construct an LLHTTPRegistration below to call this }; template < class NodeType > class LLHTTPRegistration { public: - LLHTTPRegistration(const std::string& path) - { - LLHTTPRegistrar::registerFactory(path, mFactory); - } + LLHTTPRegistration(const std::string& path) + { + LLHTTPRegistrar::registerFactory(path, mFactory); + } private: - class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory - { - public: - virtual LLHTTPNode* build() const { return new NodeType; } - }; - - ThisNodeFactory mFactory; + class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory + { + public: + virtual LLHTTPNode* build() const { return new NodeType; } + }; + + ThisNodeFactory mFactory; }; template < class NodeType> class LLHTTPParamRegistration { public: - LLHTTPParamRegistration(const std::string& path, LLSD params) : - mFactory(params) - { - LLHTTPRegistrar::registerFactory(path, mFactory); - } + LLHTTPParamRegistration(const std::string& path, LLSD params) : + mFactory(params) + { + LLHTTPRegistrar::registerFactory(path, mFactory); + } private: - class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory - { - public: - ThisNodeFactory(LLSD params) : mParams(params) {} - virtual LLHTTPNode* build() const { return new NodeType(mParams); } - private: - LLSD mParams; - }; - - ThisNodeFactory mFactory; + class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory + { + public: + ThisNodeFactory(LLSD params) : mParams(params) {} + virtual LLHTTPNode* build() const { return new NodeType(mParams); } + private: + LLSD mParams; + }; + + ThisNodeFactory mFactory; }; - + //@} #endif // LL_LLHTTPNODE_H diff --git a/indra/llmessage/llhttpnodeadapter.h b/indra/llmessage/llhttpnodeadapter.h index 22984c4478..436de6224f 100644 --- a/indra/llmessage/llhttpnodeadapter.h +++ b/indra/llmessage/llhttpnodeadapter.h @@ -5,21 +5,21 @@ * $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$ */ @@ -34,19 +34,19 @@ class LLHTTPNodeAdapter : public LLHTTPNode { public: - virtual bool validate(const std::string& name, LLSD& context) const - { - T node; - return node.validate(name, context); - } - - virtual void post(LLHTTPNode::ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - T node; - return node.post(response, context, input); - } + virtual bool validate(const std::string& name, LLSD& context) const + { + T node; + return node.validate(name, context); + } + + virtual void post(LLHTTPNode::ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + T node; + return node.post(response, context, input); + } }; #endif // LL_HTTP_NODE_ADAPTER_H diff --git a/indra/llmessage/llhttpsdhandler.cpp b/indra/llmessage/llhttpsdhandler.cpp index 648bc5cfd8..1c5928e187 100644 --- a/indra/llmessage/llhttpsdhandler.cpp +++ b/indra/llmessage/llhttpsdhandler.cpp @@ -42,36 +42,36 @@ LLHttpSDHandler::LLHttpSDHandler() void LLHttpSDHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) { - LLCore::HttpStatus status = response->getStatus(); + LLCore::HttpStatus status = response->getStatus(); - if (!status) - { - this->onFailure(response, status); - } - else - { - LLSD resplsd; - const bool emit_parse_errors = false; + if (!status) + { + this->onFailure(response, status); + } + else + { + LLSD resplsd; + const bool emit_parse_errors = false; - bool parsed = !((response->getBodySize() == 0) || - !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, resplsd)); + bool parsed = !((response->getBodySize() == 0) || + !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, resplsd)); - if (!parsed) - { - // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' - LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); - const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL; + if (!parsed) + { + // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' + LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); + const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL; - if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType)) - { - std::string thebody = LLCoreHttpUtil::responseToString(response); + if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType)) + { + std::string thebody = LLCoreHttpUtil::responseToString(response); - LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] " - << " body: " << thebody << LL_ENDL; - } - } + LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] " + << " body: " << thebody << LL_ENDL; + } + } - this->onSuccess(response, resplsd); - } + this->onSuccess(response, resplsd); + } } diff --git a/indra/llmessage/llhttpsdhandler.h b/indra/llmessage/llhttpsdhandler.h index ce40bdfc08..6390073339 100644 --- a/indra/llmessage/llhttpsdhandler.h +++ b/indra/llmessage/llhttpsdhandler.h @@ -24,30 +24,30 @@ * $/LicenseInfo$ */ -#ifndef _LLHTTPSDHANDLER_H_ -#define _LLHTTPSDHANDLER_H_ +#ifndef _LLHTTPSDHANDLER_H_ +#define _LLHTTPSDHANDLER_H_ #include "httpcommon.h" #include "httphandler.h" #include "lluri.h" -/// Handler class LLCore's HTTP library. Splitting with separate success and -/// failure routines and parsing the result body into LLSD on success. It +/// Handler class LLCore's HTTP library. Splitting with separate success and +/// failure routines and parsing the result body into LLSD on success. It /// is intended to be subclassed for specific capability handling. -/// -// *TODO: This class self deletes at the end of onCompleted method. This is +/// +// *TODO: This class self deletes at the end of onCompleted method. This is // less than ideal and should be revisited. class LLHttpSDHandler : public LLCore::HttpHandler //, // public std::enable_shared_from_this<LLHttpSDHandler> { public: - virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); - + virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + protected: LLHttpSDHandler(); - virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0; - virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0; + virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0; + virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0; }; diff --git a/indra/llmessage/llinstantmessage.cpp b/indra/llmessage/llinstantmessage.cpp index 52102e55c8..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 383fe2591a..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/llinvite.h b/indra/llmessage/llinvite.h index e5d573c1e3..8655f79982 100644 --- a/indra/llmessage/llinvite.h +++ b/indra/llmessage/llinvite.h @@ -1,25 +1,25 @@ -/** +/** * @file llinvite.h * @brief Constants used for inviting users to join groups. * * $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$ */ @@ -27,7 +27,7 @@ #ifndef LL_LLINVITE_H #define LL_LLINVITE_H -const S32 INVITE_LIST_STR_LEN = 324; // Would be larger, but we don't have much room in the CreateGroupRequest msg. -const S32 INVITE_LIST_BUF_SIZE = 325; +const S32 INVITE_LIST_STR_LEN = 324; // Would be larger, but we don't have much room in the CreateGroupRequest msg. +const S32 INVITE_LIST_BUF_SIZE = 325; #endif // LL_LLINVITE_H diff --git a/indra/llmessage/lliobuffer.cpp b/indra/llmessage/lliobuffer.cpp index bbd7b8777d..4f5821b15f 100644 --- a/indra/llmessage/lliobuffer.cpp +++ b/indra/llmessage/lliobuffer.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lliobuffer.cpp * @author Phoenix * @date 2005-05-04 @@ -7,21 +7,21 @@ * $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$ */ @@ -33,82 +33,82 @@ // LLIOBuffer // LLIOBuffer::LLIOBuffer() : - mBuffer(NULL), - mBufferSize(0L), - mReadHead(NULL), - mWriteHead(NULL) + mBuffer(NULL), + mBufferSize(0L), + mReadHead(NULL), + mWriteHead(NULL) { } LLIOBuffer::~LLIOBuffer() { - if(mBuffer) - { - delete[] mBuffer; - } + if(mBuffer) + { + delete[] mBuffer; + } } U8* LLIOBuffer::data() const { - return mBuffer; + return mBuffer; } S64 LLIOBuffer::size() const { - return mBufferSize; + return mBufferSize; } U8* LLIOBuffer::current() const { - return mReadHead; + return mReadHead; } S64 LLIOBuffer::bytesLeft() const { - return mWriteHead - mReadHead; + return mWriteHead - mReadHead; } void LLIOBuffer::clear() { - mReadHead = mBuffer; - mWriteHead = mBuffer; + mReadHead = mBuffer; + mWriteHead = mBuffer; } LLIOPipe::EStatus LLIOBuffer::seek(LLIOBuffer::EHead head, S64 delta) { - LLIOPipe::EStatus status = STATUS_ERROR; - switch(head) - { - case READ: - if(((delta >= 0) && ((mReadHead + delta) <= mWriteHead)) - || ((delta < 0) && ((mReadHead + delta) >= mBuffer))) - { - mReadHead += delta; - status = STATUS_OK; - } - break; - case WRITE: - if(((delta >= 0) && ((mWriteHead + delta) < (mBuffer + mBufferSize))) - || ((delta < 0) && ((mWriteHead + delta) > mReadHead))) - { - mWriteHead += delta; - status = STATUS_OK; - } - default: - break; - } - return status; + LLIOPipe::EStatus status = STATUS_ERROR; + switch(head) + { + case READ: + if(((delta >= 0) && ((mReadHead + delta) <= mWriteHead)) + || ((delta < 0) && ((mReadHead + delta) >= mBuffer))) + { + mReadHead += delta; + status = STATUS_OK; + } + break; + case WRITE: + if(((delta >= 0) && ((mWriteHead + delta) < (mBuffer + mBufferSize))) + || ((delta < 0) && ((mWriteHead + delta) > mReadHead))) + { + mWriteHead += delta; + status = STATUS_OK; + } + default: + break; + } + return status; } // virtual LLIOPipe::EStatus LLIOBuffer::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { - // no-op (I think) - LL_WARNS() << "You are using an LLIOBuffer which is deprecated." << LL_ENDL; - return STATUS_OK; + // no-op (I think) + LL_WARNS() << "You are using an LLIOBuffer which is deprecated." << LL_ENDL; + return STATUS_OK; } diff --git a/indra/llmessage/lliobuffer.h b/indra/llmessage/lliobuffer.h index 3349848947..4d4fab5fe4 100644 --- a/indra/llmessage/lliobuffer.h +++ b/indra/llmessage/lliobuffer.h @@ -1,4 +1,4 @@ -/** +/** * @file lliobuffer.h * @author Phoenix * @date 2005-05-04 @@ -7,21 +7,21 @@ * $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$ */ @@ -31,7 +31,7 @@ #include "lliopipe.h" -/** +/** * @class LLIOBuffer * @brief This class is an io class that represents an automtically * resizing io buffer. @@ -46,90 +46,90 @@ class LLIOBuffer : public LLIOPipe { public: - LLIOBuffer(); - virtual ~LLIOBuffer(); + LLIOBuffer(); + virtual ~LLIOBuffer(); - /** - * @brief Return a raw pointer to the current data set. - * - * The pointer returned can be used for reading or even adjustment - * if you are a bit crazy up to size() bytes into memory. - * @return A potentially NULL pointer to the raw buffer data - */ - U8* data() const; + /** + * @brief Return a raw pointer to the current data set. + * + * The pointer returned can be used for reading or even adjustment + * if you are a bit crazy up to size() bytes into memory. + * @return A potentially NULL pointer to the raw buffer data + */ + U8* data() const; - /** - * @brief Return the size of the buffer - */ - S64 size() const; + /** + * @brief Return the size of the buffer + */ + S64 size() const; - /** - * @brief Return a raw pointer to the current read position in the data. - * - * The pointer returned can be used for reading or even adjustment - * if you are a bit crazy up to bytesLeft() bytes into memory. - * @return A potentially NULL pointer to the buffer data starting - * at the read point - */ - U8* current() const; + /** + * @brief Return a raw pointer to the current read position in the data. + * + * The pointer returned can be used for reading or even adjustment + * if you are a bit crazy up to bytesLeft() bytes into memory. + * @return A potentially NULL pointer to the buffer data starting + * at the read point + */ + U8* current() const; - /** - * @brief Return the number of unprocessed bytes in buffer. - */ - S64 bytesLeft() const; + /** + * @brief Return the number of unprocessed bytes in buffer. + */ + S64 bytesLeft() const; - /** - * @brief Move the buffer offsets back to the beginning. - * - * This method effectively clears what has been stored here, - * without mucking around with memory allocation. - */ - void clear(); + /** + * @brief Move the buffer offsets back to the beginning. + * + * This method effectively clears what has been stored here, + * without mucking around with memory allocation. + */ + void clear(); - /** - * @brief Enumeration passed into the seek function - * - * The READ head is used for where to start processing data for - * the next link in the chain, while the WRITE head specifies - * where new data processed from the previous link in the chain - * will be written. - */ - enum EHead - { - READ, - WRITE - }; + /** + * @brief Enumeration passed into the seek function + * + * The READ head is used for where to start processing data for + * the next link in the chain, while the WRITE head specifies + * where new data processed from the previous link in the chain + * will be written. + */ + enum EHead + { + READ, + WRITE + }; - /** - * @brief Seek to a place in the buffer - * - * @param head The READ or WRITE head. - * @param delta The offset from the current position to seek. - * @return The status of the operation. status >= if head moved. - */ - EStatus seek(EHead head, S64 delta); + /** + * @brief Seek to a place in the buffer + * + * @param head The READ or WRITE head. + * @param delta The offset from the current position to seek. + * @return The status of the operation. status >= if head moved. + */ + EStatus seek(EHead head, S64 delta); public: - /* @name LLIOPipe virtual implementations - */ - //@{ + /* @name LLIOPipe virtual implementations + */ + //@{ protected: - /** - * @brief Process the data in buffer - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /** + * @brief Process the data in buffer + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - U8* mBuffer; - S64 mBufferSize; - U8* mReadHead; - U8* mWriteHead; + U8* mBuffer; + S64 mBufferSize; + U8* mReadHead; + U8* mWriteHead; }; #endif // LL_LLIOBUFFER_H diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index e302dd2b5e..9791a20743 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lliohttpserver.cpp * @author Phoenix * @date 2005-10-05 @@ -7,21 +7,21 @@ * $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$ */ @@ -58,89 +58,89 @@ static void* sTimingCallbackData = NULL; class LLHTTPPipe : public LLIOPipe { public: - LLHTTPPipe(const LLHTTPNode& node) - : mNode(node), - mResponse(NULL), - mState(STATE_INVOKE), - mChainLock(0), - mLockedPump(NULL), - mStatusCode(0) - { } - virtual ~LLHTTPPipe() - { - if (mResponse.notNull()) - { - mResponse->nullPipe(); - } - } + LLHTTPPipe(const LLHTTPNode& node) + : mNode(node), + mResponse(NULL), + mState(STATE_INVOKE), + mChainLock(0), + mLockedPump(NULL), + mStatusCode(0) + { } + virtual ~LLHTTPPipe() + { + if (mResponse.notNull()) + { + mResponse->nullPipe(); + } + } private: - // LLIOPipe API implementation. - virtual EStatus process_impl( + // LLIOPipe API implementation. + virtual EStatus process_impl( const LLChannelDescriptors& channels, LLIOPipe::buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump); - const LLHTTPNode& mNode; - - class Response : public LLHTTPNode::Response - { - public: - - static LLPointer<Response> create(LLHTTPPipe* pipe); - virtual ~Response(); - - // from LLHTTPNode::Response - virtual void result(const LLSD&); - virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers); - virtual void extendedResult(S32 code, const LLSD& body, const LLSD& headers); - virtual void status(S32 code, const std::string& message); - - void nullPipe(); - - private: - Response() : mPipe(NULL) {} // Must be accessed through LLPointer. - LLHTTPPipe* mPipe; - }; - friend class Response; - - LLPointer<Response> mResponse; - - enum State - { - STATE_INVOKE, - STATE_DELAYED, - STATE_LOCKED, - STATE_GOOD_RESULT, - STATE_STATUS_RESULT, - STATE_EXTENDED_RESULT, - STATE_EXTENDED_LLSD_RESULT - }; - State mState; - - S32 mChainLock; - LLPumpIO* mLockedPump; - - void lockChain(LLPumpIO*); - void unlockChain(); - - LLSD mResult; - S32 mStatusCode; - std::string mStatusMessage; - LLSD mHeaders; + const LLHTTPNode& mNode; + + class Response : public LLHTTPNode::Response + { + public: + + static LLPointer<Response> create(LLHTTPPipe* pipe); + virtual ~Response(); + + // from LLHTTPNode::Response + virtual void result(const LLSD&); + virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers); + virtual void extendedResult(S32 code, const LLSD& body, const LLSD& headers); + virtual void status(S32 code, const std::string& message); + + void nullPipe(); + + private: + Response() : mPipe(NULL) {} // Must be accessed through LLPointer. + LLHTTPPipe* mPipe; + }; + friend class Response; + + LLPointer<Response> mResponse; + + enum State + { + STATE_INVOKE, + STATE_DELAYED, + STATE_LOCKED, + STATE_GOOD_RESULT, + STATE_STATUS_RESULT, + STATE_EXTENDED_RESULT, + STATE_EXTENDED_LLSD_RESULT + }; + State mState; + + S32 mChainLock; + LLPumpIO* mLockedPump; + + void lockChain(LLPumpIO*); + void unlockChain(); + + LLSD mResult; + S32 mStatusCode; + std::string mStatusMessage; + LLSD mHeaders; }; LLIOPipe::EStatus LLHTTPPipe::process_impl( - const LLChannelDescriptors& channels, + const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; + PUMP_DEBUG; LL_DEBUGS() << "LLSDHTTPServer::process_impl" << LL_ENDL; // Once we have all the data, We need to read the sd on @@ -149,166 +149,166 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( if(!eos) return STATUS_BREAK; if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET; - PUMP_DEBUG; - if (mState == STATE_INVOKE) - { - PUMP_DEBUG; - mState = STATE_DELAYED; - // assume deferred unless mResponse does otherwise - mResponse = Response::create(this); - - // *TODO: Babbage: Parameterize parser? - // *TODO: We should look at content-type and do the right - // thing. Phoenix 2007-12-31 - LLBufferStream istr(channels, buffer.get()); - - static LLTimer timer; - timer.reset(); - - std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB]; - if(verb == HTTP_VERB_GET) - { - mNode.get(LLHTTPNode::ResponsePtr(mResponse), context); - } - else if(verb == HTTP_VERB_PUT) - { - LLSD input; - if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) - { - LLSDSerialize::fromXML(input, istr); - } - else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT) - { - std::ostringstream strstrm; - strstrm << istr.rdbuf(); - input = strstrm.str(); - } - mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input); - } - else if(verb == HTTP_VERB_POST) - { - LLSD input; - if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) - { - LLSDSerialize::fromXML(input, istr); - } - else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT) - { - std::ostringstream strstrm; - strstrm << istr.rdbuf(); - input = strstrm.str(); - } - mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input); - } - else if(verb == HTTP_VERB_DELETE) - { - mNode.del(LLHTTPNode::ResponsePtr(mResponse), context); - } - else if(verb == HTTP_VERB_OPTIONS) - { - mNode.options(LLHTTPNode::ResponsePtr(mResponse), context); - } - else - { - mResponse->methodNotAllowed(); - } - - F32 delta = timer.getElapsedTimeF32(); - if (sTimingCallback) - { - LLHTTPNode::Description desc; - mNode.describe(desc); - LLSD info = desc.getInfo(); - std::string timing_name = info["description"]; - timing_name += " "; - timing_name += verb; - sTimingCallback(timing_name.c_str(), delta, sTimingCallbackData); - } - - // Log all HTTP transactions. - // TODO: Add a way to log these to their own file instead of indra.log - // It is just too spammy to be in indra.log. - LL_DEBUGS() << verb << " " << context[CONTEXT_REQUEST][CONTEXT_PATH].asString() - << " " << mStatusCode << " " << mStatusMessage << " " << delta - << "s" << LL_ENDL; - - // Log Internal Server Errors - //if(mStatusCode == HTTP_INTERNAL_SERVER_ERROR) - //{ - // LL_WARNS() << "LLHTTPPipe::process_impl:500:Internal Server Error" - // << LL_ENDL; - //} - } - - PUMP_DEBUG; - switch (mState) - { - case STATE_DELAYED: - lockChain(pump); - mState = STATE_LOCKED; - return STATUS_BREAK; - - case STATE_LOCKED: - // should never ever happen! - return STATUS_ERROR; - - case STATE_GOOD_RESULT: - { - LLSD headers = mHeaders; - headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; - context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; - LLBufferStream ostr(channels, buffer.get()); - LLSDSerialize::toXML(mResult, ostr); - - return STATUS_DONE; - } - - case STATE_STATUS_RESULT: - { - LLSD headers = mHeaders; - headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_TEXT_PLAIN; - context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; - context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; - context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage; - LLBufferStream ostr(channels, buffer.get()); - ostr << mStatusMessage; - - return STATUS_DONE; - } - case STATE_EXTENDED_RESULT: - { - context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = mHeaders; - context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; - LLBufferStream ostr(channels, buffer.get()); - ostr << mStatusMessage; - - return STATUS_DONE; - } - case STATE_EXTENDED_LLSD_RESULT: - { - LLSD headers = mHeaders; - headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; - context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; - context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; - LLBufferStream ostr(channels, buffer.get()); - LLSDSerialize::toXML(mResult, ostr); - - return STATUS_DONE; - } - default: - LL_WARNS() << "LLHTTPPipe::process_impl: unexpected state " - << mState << LL_ENDL; - - return STATUS_BREAK; - } -// PUMP_DEBUG; // unreachable + PUMP_DEBUG; + if (mState == STATE_INVOKE) + { + PUMP_DEBUG; + mState = STATE_DELAYED; + // assume deferred unless mResponse does otherwise + mResponse = Response::create(this); + + // *TODO: Babbage: Parameterize parser? + // *TODO: We should look at content-type and do the right + // thing. Phoenix 2007-12-31 + LLBufferStream istr(channels, buffer.get()); + + static LLTimer timer; + timer.reset(); + + std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB]; + if(verb == HTTP_VERB_GET) + { + mNode.get(LLHTTPNode::ResponsePtr(mResponse), context); + } + else if(verb == HTTP_VERB_PUT) + { + LLSD input; + if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) + { + LLSDSerialize::fromXML(input, istr); + } + else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT) + { + std::ostringstream strstrm; + strstrm << istr.rdbuf(); + input = strstrm.str(); + } + mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input); + } + else if(verb == HTTP_VERB_POST) + { + LLSD input; + if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) + { + LLSDSerialize::fromXML(input, istr); + } + else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT) + { + std::ostringstream strstrm; + strstrm << istr.rdbuf(); + input = strstrm.str(); + } + mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input); + } + else if(verb == HTTP_VERB_DELETE) + { + mNode.del(LLHTTPNode::ResponsePtr(mResponse), context); + } + else if(verb == HTTP_VERB_OPTIONS) + { + mNode.options(LLHTTPNode::ResponsePtr(mResponse), context); + } + else + { + mResponse->methodNotAllowed(); + } + + F32 delta = timer.getElapsedTimeF32(); + if (sTimingCallback) + { + LLHTTPNode::Description desc; + mNode.describe(desc); + LLSD info = desc.getInfo(); + std::string timing_name = info["description"]; + timing_name += " "; + timing_name += verb; + sTimingCallback(timing_name.c_str(), delta, sTimingCallbackData); + } + + // Log all HTTP transactions. + // TODO: Add a way to log these to their own file instead of indra.log + // It is just too spammy to be in indra.log. + LL_DEBUGS() << verb << " " << context[CONTEXT_REQUEST][CONTEXT_PATH].asString() + << " " << mStatusCode << " " << mStatusMessage << " " << delta + << "s" << LL_ENDL; + + // Log Internal Server Errors + //if(mStatusCode == HTTP_INTERNAL_SERVER_ERROR) + //{ + // LL_WARNS() << "LLHTTPPipe::process_impl:500:Internal Server Error" + // << LL_ENDL; + //} + } + + PUMP_DEBUG; + switch (mState) + { + case STATE_DELAYED: + lockChain(pump); + mState = STATE_LOCKED; + return STATUS_BREAK; + + case STATE_LOCKED: + // should never ever happen! + return STATUS_ERROR; + + case STATE_GOOD_RESULT: + { + LLSD headers = mHeaders; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; + context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; + LLBufferStream ostr(channels, buffer.get()); + LLSDSerialize::toXML(mResult, ostr); + + return STATUS_DONE; + } + + case STATE_STATUS_RESULT: + { + LLSD headers = mHeaders; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_TEXT_PLAIN; + context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; + context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; + context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage; + LLBufferStream ostr(channels, buffer.get()); + ostr << mStatusMessage; + + return STATUS_DONE; + } + case STATE_EXTENDED_RESULT: + { + context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = mHeaders; + context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; + LLBufferStream ostr(channels, buffer.get()); + ostr << mStatusMessage; + + return STATUS_DONE; + } + case STATE_EXTENDED_LLSD_RESULT: + { + LLSD headers = mHeaders; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; + context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; + context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; + LLBufferStream ostr(channels, buffer.get()); + LLSDSerialize::toXML(mResult, ostr); + + return STATUS_DONE; + } + default: + LL_WARNS() << "LLHTTPPipe::process_impl: unexpected state " + << mState << LL_ENDL; + + return STATUS_BREAK; + } +// PUMP_DEBUG; // unreachable } LLPointer<LLHTTPPipe::Response> LLHTTPPipe::Response::create(LLHTTPPipe* pipe) { - LLPointer<Response> result = new Response(); - result->mPipe = pipe; - return result; + LLPointer<Response> result = new Response(); + result->mPipe = pipe; + return result; } // virtual @@ -318,93 +318,93 @@ LLHTTPPipe::Response::~Response() void LLHTTPPipe::Response::nullPipe() { - mPipe = NULL; + mPipe = NULL; } // virtual void LLHTTPPipe::Response::result(const LLSD& r) { - if(! mPipe) - { - LL_WARNS() << "LLHTTPPipe::Response::result: NULL pipe" << LL_ENDL; - return; - } - - mPipe->mStatusCode = HTTP_OK; - mPipe->mStatusMessage = "OK"; - mPipe->mResult = r; - mPipe->mState = STATE_GOOD_RESULT; - mPipe->mHeaders = mHeaders; - mPipe->unlockChain(); + if(! mPipe) + { + LL_WARNS() << "LLHTTPPipe::Response::result: NULL pipe" << LL_ENDL; + return; + } + + mPipe->mStatusCode = HTTP_OK; + mPipe->mStatusMessage = "OK"; + mPipe->mResult = r; + mPipe->mState = STATE_GOOD_RESULT; + mPipe->mHeaders = mHeaders; + mPipe->unlockChain(); } void LLHTTPPipe::Response::extendedResult(S32 code, const LLSD& r, const LLSD& headers) { - if(! mPipe) - { - LL_WARNS() << "LLHTTPPipe::Response::extendedResult: NULL pipe" << LL_ENDL; - return; - } - - mPipe->mStatusCode = code; - mPipe->mStatusMessage = "(LLSD)"; - mPipe->mResult = r; - mPipe->mHeaders = headers; - mPipe->mState = STATE_EXTENDED_LLSD_RESULT; - mPipe->unlockChain(); + if(! mPipe) + { + LL_WARNS() << "LLHTTPPipe::Response::extendedResult: NULL pipe" << LL_ENDL; + return; + } + + mPipe->mStatusCode = code; + mPipe->mStatusMessage = "(LLSD)"; + mPipe->mResult = r; + mPipe->mHeaders = headers; + mPipe->mState = STATE_EXTENDED_LLSD_RESULT; + mPipe->unlockChain(); } void LLHTTPPipe::Response::extendedResult(S32 code, const std::string& body, const LLSD& headers) { - if(! mPipe) - { - LL_WARNS() << "LLHTTPPipe::Response::status: NULL pipe" << LL_ENDL; - return; - } - - mPipe->mStatusCode = code; - mPipe->mStatusMessage = body; - mPipe->mHeaders = headers; - mPipe->mState = STATE_EXTENDED_RESULT; - mPipe->unlockChain(); + if(! mPipe) + { + LL_WARNS() << "LLHTTPPipe::Response::status: NULL pipe" << LL_ENDL; + return; + } + + mPipe->mStatusCode = code; + mPipe->mStatusMessage = body; + mPipe->mHeaders = headers; + mPipe->mState = STATE_EXTENDED_RESULT; + mPipe->unlockChain(); } // virtual void LLHTTPPipe::Response::status(S32 code, const std::string& message) { - if(! mPipe) - { - LL_WARNS() << "LLHTTPPipe::Response::status: NULL pipe" << LL_ENDL; - return; - } - - mPipe->mStatusCode = code; - mPipe->mStatusMessage = message; - mPipe->mState = STATE_STATUS_RESULT; - mPipe->mHeaders = mHeaders; - mPipe->unlockChain(); + if(! mPipe) + { + LL_WARNS() << "LLHTTPPipe::Response::status: NULL pipe" << LL_ENDL; + return; + } + + mPipe->mStatusCode = code; + mPipe->mStatusMessage = message; + mPipe->mState = STATE_STATUS_RESULT; + mPipe->mHeaders = mHeaders; + mPipe->unlockChain(); } void LLHTTPPipe::lockChain(LLPumpIO* pump) { - if (mChainLock != 0) { return; } + if (mChainLock != 0) { return; } - mLockedPump = pump; - mChainLock = pump->setLock(); + mLockedPump = pump; + mChainLock = pump->setLock(); } void LLHTTPPipe::unlockChain() { - if (mChainLock == 0) { return; } + if (mChainLock == 0) { return; } - mLockedPump->clearLock(mChainLock); - mLockedPump = NULL; - mChainLock = 0; + mLockedPump->clearLock(mChainLock); + mLockedPump = NULL; + mChainLock = 0; } -/** +/** * @class LLHTTPResponseHeader * @brief Class which correctly builds HTTP headers on a pipe * @see LLIOPipe @@ -418,26 +418,26 @@ void LLHTTPPipe::unlockChain() class LLHTTPResponseHeader : public LLIOPipe { public: - LLHTTPResponseHeader() : mCode(0) {} - virtual ~LLHTTPResponseHeader() {} + LLHTTPResponseHeader() : mCode(0) {} + virtual ~LLHTTPResponseHeader() {} protected: - /* @name LLIOPipe virtual implementations - */ - //@{ - /** - * @brief Process the data in buffer - */ - EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Process the data in buffer + */ + EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - S32 mCode; + S32 mCode; }; @@ -447,66 +447,66 @@ protected: // virtual LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; - if(eos) - { - PUMP_DEBUG; - //mGotEOS = true; - std::ostringstream ostr; - std::string message = context[CONTEXT_RESPONSE]["statusMessage"]; - - int code = context[CONTEXT_RESPONSE]["statusCode"]; - if (code < HTTP_OK) - { - code = HTTP_OK; - message = "OK"; - } - - ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n"; - - S32 content_length = buffer->countAfter(channels.in(), NULL); - if(0 < content_length) - { - ostr << HTTP_OUT_HEADER_CONTENT_LENGTH << ": " << content_length << "\r\n"; - } - // *NOTE: This guard can go away once the LLSD static map - // iterator is available. Phoenix. 2008-05-09 - LLSD headers = context[CONTEXT_RESPONSE][CONTEXT_HEADERS]; - if(headers.isDefined()) - { - LLSD::map_iterator iter = headers.beginMap(); - LLSD::map_iterator end = headers.endMap(); - for(; iter != end; ++iter) - { - ostr << (*iter).first << ": " << (*iter).second.asString() - << "\r\n"; - } - } - ostr << "\r\n"; - - LLChangeChannel change(channels.in(), channels.out()); - std::for_each(buffer->beginSegment(), buffer->endSegment(), change); - std::string header = ostr.str(); - buffer->prepend(channels.out(), (U8*)header.c_str(), header.size()); - PUMP_DEBUG; - return STATUS_DONE; - } - PUMP_DEBUG; - return STATUS_OK; + PUMP_DEBUG; + if(eos) + { + PUMP_DEBUG; + //mGotEOS = true; + std::ostringstream ostr; + std::string message = context[CONTEXT_RESPONSE]["statusMessage"]; + + int code = context[CONTEXT_RESPONSE]["statusCode"]; + if (code < HTTP_OK) + { + code = HTTP_OK; + message = "OK"; + } + + ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n"; + + S32 content_length = buffer->countAfter(channels.in(), NULL); + if(0 < content_length) + { + ostr << HTTP_OUT_HEADER_CONTENT_LENGTH << ": " << content_length << "\r\n"; + } + // *NOTE: This guard can go away once the LLSD static map + // iterator is available. Phoenix. 2008-05-09 + LLSD headers = context[CONTEXT_RESPONSE][CONTEXT_HEADERS]; + if(headers.isDefined()) + { + LLSD::map_iterator iter = headers.beginMap(); + LLSD::map_iterator end = headers.endMap(); + for(; iter != end; ++iter) + { + ostr << (*iter).first << ": " << (*iter).second.asString() + << "\r\n"; + } + } + ostr << "\r\n"; + + LLChangeChannel change(channels.in(), channels.out()); + std::for_each(buffer->beginSegment(), buffer->endSegment(), change); + std::string header = ostr.str(); + buffer->prepend(channels.out(), (U8*)header.c_str(), header.size()); + PUMP_DEBUG; + return STATUS_DONE; + } + PUMP_DEBUG; + return STATUS_OK; } -/** +/** * @class LLHTTPResponder - * @brief This class + * @brief This class * @see LLIOPipe * * <b>NOTE:</b> You should not need to create or use one of these, the @@ -515,464 +515,464 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( class LLHTTPResponder : public LLIOPipe { public: - LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx); - ~LLHTTPResponder(); + LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx); + ~LLHTTPResponder(); protected: - /** - * @brief Read data off of CHANNEL_IN keeping track of last read position. - * - * This is a quick little hack to read headers. It is not IO - * optimal, but it makes it easier for me to implement the header - * parsing. Plus, there should never be more than a few headers. - * This method will tend to read more than necessary, find the - * newline, make the front part of dest look like a c string, and - * move the read head back to where the newline was found. Thus, - * the next read will pick up on the next line. - * @param channel The channel to read in the buffer - * @param buffer The heap array of processed data - * @param dest Destination for the data to be read - * @param[in,out] len <b>in</b> The size of the buffer. <b>out</b> how - * much was read. This value is not useful for determining where to - * seek orfor string assignment. - * @returns Returns true if a line was found. - */ - bool readHeaderLine( - const LLChannelDescriptors& channels, - buffer_ptr_t buffer, - U8* dest, - S32& len); - - /** - * @brief Mark the request as bad, and handle appropriately - * - * @param channels The channels to use in the buffer. - * @param buffer The heap array of processed data. - */ - void markBad(const LLChannelDescriptors& channels, buffer_ptr_t buffer); + /** + * @brief Read data off of CHANNEL_IN keeping track of last read position. + * + * This is a quick little hack to read headers. It is not IO + * optimal, but it makes it easier for me to implement the header + * parsing. Plus, there should never be more than a few headers. + * This method will tend to read more than necessary, find the + * newline, make the front part of dest look like a c string, and + * move the read head back to where the newline was found. Thus, + * the next read will pick up on the next line. + * @param channel The channel to read in the buffer + * @param buffer The heap array of processed data + * @param dest Destination for the data to be read + * @param[in,out] len <b>in</b> The size of the buffer. <b>out</b> how + * much was read. This value is not useful for determining where to + * seek orfor string assignment. + * @returns Returns true if a line was found. + */ + bool readHeaderLine( + const LLChannelDescriptors& channels, + buffer_ptr_t buffer, + U8* dest, + S32& len); + + /** + * @brief Mark the request as bad, and handle appropriately + * + * @param channels The channels to use in the buffer. + * @param buffer The heap array of processed data. + */ + void markBad(const LLChannelDescriptors& channels, buffer_ptr_t buffer); protected: - /* @name LLIOPipe virtual implementations - */ - //@{ - /** - * @brief Process the data in buffer - */ - EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Process the data in buffer + */ + EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - enum EState - { - STATE_NOTHING, - STATE_READING_HEADERS, - STATE_LOOKING_FOR_EOS, - STATE_DONE, - STATE_SHORT_CIRCUIT - }; - - LLSD mBuildContext; - EState mState; - U8* mLastRead; - std::string mVerb; - std::string mAbsPathAndQuery; - std::string mPath; - std::string mQuery; - std::string mVersion; - S32 mContentLength; - LLSD mHeaders; - - // handle the urls - const LLHTTPNode& mRootNode; + enum EState + { + STATE_NOTHING, + STATE_READING_HEADERS, + STATE_LOOKING_FOR_EOS, + STATE_DONE, + STATE_SHORT_CIRCUIT + }; + + LLSD mBuildContext; + EState mState; + U8* mLastRead; + std::string mVerb; + std::string mAbsPathAndQuery; + std::string mPath; + std::string mQuery; + std::string mVersion; + S32 mContentLength; + LLSD mHeaders; + + // handle the urls + const LLHTTPNode& mRootNode; }; LLHTTPResponder::LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx) : - mBuildContext(ctx), - mState(STATE_NOTHING), - mLastRead(NULL), - mContentLength(0), - mRootNode(tree) + mBuildContext(ctx), + mState(STATE_NOTHING), + mLastRead(NULL), + mContentLength(0), + mRootNode(tree) { } // virtual LLHTTPResponder::~LLHTTPResponder() { - //LL_DEBUGS() << "destroying LLHTTPResponder" << LL_ENDL; + //LL_DEBUGS() << "destroying LLHTTPResponder" << LL_ENDL; } bool LLHTTPResponder::readHeaderLine( - const LLChannelDescriptors& channels, - buffer_ptr_t buffer, - U8* dest, - S32& len) + const LLChannelDescriptors& channels, + buffer_ptr_t buffer, + U8* dest, + S32& len) { - --len; - U8* last = buffer->readAfter(channels.in(), mLastRead, dest, len); - dest[len] = '\0'; - U8* newline = (U8*)strchr((char*)dest, '\n'); - if(!newline) - { - if(len) - { - LL_DEBUGS() << "readLine failed - too long maybe?" << LL_ENDL; - markBad(channels, buffer); - } - return false; - } - S32 offset = -((len - 1) - (newline - dest)); - ++newline; - *newline = '\0'; - mLastRead = buffer->seek(channels.in(), last, offset); - return true; + --len; + U8* last = buffer->readAfter(channels.in(), mLastRead, dest, len); + dest[len] = '\0'; + U8* newline = (U8*)strchr((char*)dest, '\n'); + if(!newline) + { + if(len) + { + LL_DEBUGS() << "readLine failed - too long maybe?" << LL_ENDL; + markBad(channels, buffer); + } + return false; + } + S32 offset = -((len - 1) - (newline - dest)); + ++newline; + *newline = '\0'; + mLastRead = buffer->seek(channels.in(), last, offset); + return true; } void LLHTTPResponder::markBad( - const LLChannelDescriptors& channels, - buffer_ptr_t buffer) + const LLChannelDescriptors& channels, + buffer_ptr_t buffer) { - mState = STATE_SHORT_CIRCUIT; - LLBufferStream out(channels, buffer.get()); - out << HTTP_VERSION_STR << " 400 Bad Request\r\n\r\n<html>\n" - << "<title>Bad Request</title>\n<body>\nBad Request.\n" - << "</body>\n</html>\n"; + mState = STATE_SHORT_CIRCUIT; + LLBufferStream out(channels, buffer.get()); + out << HTTP_VERSION_STR << " 400 Bad Request\r\n\r\n<html>\n" + << "<title>Bad Request</title>\n<body>\nBad Request.\n" + << "</body>\n</html>\n"; } // virtual LLIOPipe::EStatus LLHTTPResponder::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; - LLIOPipe::EStatus status = STATUS_OK; - - // parsing headers - if((STATE_NOTHING == mState) || (STATE_READING_HEADERS == mState)) - { - PUMP_DEBUG; - status = STATUS_BREAK; - mState = STATE_READING_HEADERS; - const S32 HEADER_BUFFER_SIZE = 1024; - char buf[HEADER_BUFFER_SIZE + 1]; /*Flawfinder: ignore*/ - S32 len = HEADER_BUFFER_SIZE; + PUMP_DEBUG; + LLIOPipe::EStatus status = STATUS_OK; + + // parsing headers + if((STATE_NOTHING == mState) || (STATE_READING_HEADERS == mState)) + { + PUMP_DEBUG; + status = STATUS_BREAK; + mState = STATE_READING_HEADERS; + const S32 HEADER_BUFFER_SIZE = 1024; + char buf[HEADER_BUFFER_SIZE + 1]; /*Flawfinder: ignore*/ + S32 len = HEADER_BUFFER_SIZE; #if 0 - if(true) - { - LLBufferArray::segment_iterator_t seg_iter = buffer->beginSegment(); - char buf[1024]; /*Flawfinder: ignore*/ - while(seg_iter != buffer->endSegment()) - { - memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/ - buf[(*seg_iter).size()] = '\0'; - LL_INFOS() << (*seg_iter).getChannel() << ": " << buf - << LL_ENDL; - ++seg_iter; - } - } + if(true) + { + LLBufferArray::segment_iterator_t seg_iter = buffer->beginSegment(); + char buf[1024]; /*Flawfinder: ignore*/ + while(seg_iter != buffer->endSegment()) + { + memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/ + buf[(*seg_iter).size()] = '\0'; + LL_INFOS() << (*seg_iter).getChannel() << ": " << buf + << LL_ENDL; + ++seg_iter; + } + } #endif - - PUMP_DEBUG; - if(readHeaderLine(channels, buffer, (U8*)buf, len)) - { - bool read_next_line = false; - bool parse_all = true; - if(mVerb.empty()) - { - read_next_line = true; - LLMemoryStream header((U8*)buf, len); - header >> mVerb; - - if((HTTP_VERB_GET == mVerb) - || (HTTP_VERB_POST == mVerb) - || (HTTP_VERB_PUT == mVerb) - || (HTTP_VERB_DELETE == mVerb) - || (HTTP_VERB_OPTIONS == mVerb)) - { - header >> mAbsPathAndQuery; - header >> mVersion; - - LL_DEBUGS() << "http request: " - << mVerb - << " " << mAbsPathAndQuery - << " " << mVersion << LL_ENDL; - - std::string::size_type delimiter - = mAbsPathAndQuery.find('?'); - if (delimiter == std::string::npos) - { - mPath = mAbsPathAndQuery; - mQuery = ""; - } - else - { - mPath = mAbsPathAndQuery.substr(0, delimiter); - mQuery = mAbsPathAndQuery.substr(delimiter+1); - } - - if(!mAbsPathAndQuery.empty()) - { - if(mVersion.empty()) - { - // simple request. - parse_all = false; - mState = STATE_DONE; - mVersion.assign("HTTP/1.0"); - } - } - } - else - { - read_next_line = false; - parse_all = false; - LL_DEBUGS() << "unknown http verb: " << mVerb << LL_ENDL; - markBad(channels, buffer); - } - } - if(parse_all) - { - bool keep_parsing = true; - while(keep_parsing) - { - if(read_next_line) - { - len = HEADER_BUFFER_SIZE; - if (!readHeaderLine(channels, buffer, (U8*)buf, len)) - { - // Failed to read the header line, probably too long. - // readHeaderLine already marked the channel/buffer as bad. - keep_parsing = false; - break; - } - } - if(0 == len) - { - return status; - } - if(buf[0] == '\r' && buf[1] == '\n') - { - // end-o-headers - keep_parsing = false; - mState = STATE_LOOKING_FOR_EOS; - break; - } - char* pos_colon = strchr(buf, ':'); - if(NULL == pos_colon) - { - keep_parsing = false; - LL_DEBUGS() << "bad header: " << buf << LL_ENDL; - markBad(channels, buffer); - break; - } - // we've found a header - read_next_line = true; - std::string name(buf, pos_colon - buf); - std::string value(pos_colon + 2); - LLStringUtil::toLower(name); - if(HTTP_IN_HEADER_CONTENT_LENGTH == name) - { - LL_DEBUGS() << "Content-Length: " << value << LL_ENDL; - mContentLength = atoi(value.c_str()); - } - else - { - LLStringUtil::trimTail(value); - mHeaders[name] = value; - } - } - } - } - } - - PUMP_DEBUG; - // look for the end of stream based on - if(STATE_LOOKING_FOR_EOS == mState) - { - if(0 == mContentLength) - { - mState = STATE_DONE; - } - else if(buffer->countAfter(channels.in(), mLastRead) >= mContentLength) - { - mState = STATE_DONE; - } - // else more bytes should be coming. - } - - PUMP_DEBUG; - if(STATE_DONE == mState) - { - // hey, hey, we should have everything now, so we pass it to - // a content handler. - context[CONTEXT_REQUEST][CONTEXT_VERB] = mVerb; - const LLHTTPNode* node = mRootNode.traverse(mPath, context); - if(node) - { - //LL_INFOS() << "LLHTTPResponder::process_impl found node for " - // << mAbsPathAndQuery << LL_ENDL; - - // Copy everything after mLast read to the out. - LLBufferArray::segment_iterator_t seg_iter; - - buffer->lock(); - seg_iter = buffer->splitAfter(mLastRead); - if(seg_iter != buffer->endSegment()) - { - LLChangeChannel change(channels.in(), channels.out()); - ++seg_iter; - std::for_each(seg_iter, buffer->endSegment(), change); + + PUMP_DEBUG; + if(readHeaderLine(channels, buffer, (U8*)buf, len)) + { + bool read_next_line = false; + bool parse_all = true; + if(mVerb.empty()) + { + read_next_line = true; + LLMemoryStream header((U8*)buf, len); + header >> mVerb; + + if((HTTP_VERB_GET == mVerb) + || (HTTP_VERB_POST == mVerb) + || (HTTP_VERB_PUT == mVerb) + || (HTTP_VERB_DELETE == mVerb) + || (HTTP_VERB_OPTIONS == mVerb)) + { + header >> mAbsPathAndQuery; + header >> mVersion; + + LL_DEBUGS() << "http request: " + << mVerb + << " " << mAbsPathAndQuery + << " " << mVersion << LL_ENDL; + + std::string::size_type delimiter + = mAbsPathAndQuery.find('?'); + if (delimiter == std::string::npos) + { + mPath = mAbsPathAndQuery; + mQuery = ""; + } + else + { + mPath = mAbsPathAndQuery.substr(0, delimiter); + mQuery = mAbsPathAndQuery.substr(delimiter+1); + } + + if(!mAbsPathAndQuery.empty()) + { + if(mVersion.empty()) + { + // simple request. + parse_all = false; + mState = STATE_DONE; + mVersion.assign("HTTP/1.0"); + } + } + } + else + { + read_next_line = false; + parse_all = false; + LL_DEBUGS() << "unknown http verb: " << mVerb << LL_ENDL; + markBad(channels, buffer); + } + } + if(parse_all) + { + bool keep_parsing = true; + while(keep_parsing) + { + if(read_next_line) + { + len = HEADER_BUFFER_SIZE; + if (!readHeaderLine(channels, buffer, (U8*)buf, len)) + { + // Failed to read the header line, probably too long. + // readHeaderLine already marked the channel/buffer as bad. + keep_parsing = false; + break; + } + } + if(0 == len) + { + return status; + } + if(buf[0] == '\r' && buf[1] == '\n') + { + // end-o-headers + keep_parsing = false; + mState = STATE_LOOKING_FOR_EOS; + break; + } + char* pos_colon = strchr(buf, ':'); + if(NULL == pos_colon) + { + keep_parsing = false; + LL_DEBUGS() << "bad header: " << buf << LL_ENDL; + markBad(channels, buffer); + break; + } + // we've found a header + read_next_line = true; + std::string name(buf, pos_colon - buf); + std::string value(pos_colon + 2); + LLStringUtil::toLower(name); + if(HTTP_IN_HEADER_CONTENT_LENGTH == name) + { + LL_DEBUGS() << "Content-Length: " << value << LL_ENDL; + mContentLength = atoi(value.c_str()); + } + else + { + LLStringUtil::trimTail(value); + mHeaders[name] = value; + } + } + } + } + } + + PUMP_DEBUG; + // look for the end of stream based on + if(STATE_LOOKING_FOR_EOS == mState) + { + if(0 == mContentLength) + { + mState = STATE_DONE; + } + else if(buffer->countAfter(channels.in(), mLastRead) >= mContentLength) + { + mState = STATE_DONE; + } + // else more bytes should be coming. + } + + PUMP_DEBUG; + if(STATE_DONE == mState) + { + // hey, hey, we should have everything now, so we pass it to + // a content handler. + context[CONTEXT_REQUEST][CONTEXT_VERB] = mVerb; + const LLHTTPNode* node = mRootNode.traverse(mPath, context); + if(node) + { + //LL_INFOS() << "LLHTTPResponder::process_impl found node for " + // << mAbsPathAndQuery << LL_ENDL; + + // Copy everything after mLast read to the out. + LLBufferArray::segment_iterator_t seg_iter; + + buffer->lock(); + seg_iter = buffer->splitAfter(mLastRead); + if(seg_iter != buffer->endSegment()) + { + LLChangeChannel change(channels.in(), channels.out()); + ++seg_iter; + std::for_each(seg_iter, buffer->endSegment(), change); #if 0 - seg_iter = buffer->beginSegment(); - char buf[1024]; /*Flawfinder: ignore*/ - while(seg_iter != buffer->endSegment()) - { - memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/ - buf[(*seg_iter).size()] = '\0'; - LL_INFOS() << (*seg_iter).getChannel() << ": " << buf - << LL_ENDL; - ++seg_iter; - } + seg_iter = buffer->beginSegment(); + char buf[1024]; /*Flawfinder: ignore*/ + while(seg_iter != buffer->endSegment()) + { + memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/ + buf[(*seg_iter).size()] = '\0'; + LL_INFOS() << (*seg_iter).getChannel() << ": " << buf + << LL_ENDL; + ++seg_iter; + } #endif - } - buffer->unlock(); - // - // *FIX: get rid of extra bytes off the end - // - - // Set up a chain which will prepend a content length and - // HTTP headers. - LLPumpIO::chain_t chain; - chain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); - context[CONTEXT_REQUEST][CONTEXT_PATH] = mPath; - context[CONTEXT_REQUEST][CONTEXT_QUERY_STRING] = mQuery; - context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST] - = mBuildContext[CONTEXT_REMOTE_HOST]; - context[CONTEXT_REQUEST][CONTEXT_REMOTE_PORT] - = mBuildContext[CONTEXT_REMOTE_PORT]; - context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders; - - const LLChainIOFactory* protocolHandler - = node->getProtocolHandler(); - if (protocolHandler) - { - LL_DEBUGS() << "HTTP context: " << context << LL_ENDL; - protocolHandler->build(chain, context); - } - else - { - // this is a simple LLHTTPNode, so use LLHTTPPipe - chain.push_back(LLIOPipe::ptr_t(new LLHTTPPipe(*node))); - } - - // Add the header - which needs to have the same - // channel information as the link before it since it - // is part of the response. - LLIOPipe* header = new LLHTTPResponseHeader; - chain.push_back(LLIOPipe::ptr_t(header)); - - // We need to copy all of the pipes _after_ this so - // that the response goes out correctly. - LLPumpIO::links_t current_links; - pump->copyCurrentLinkInfo(current_links); - LLPumpIO::links_t::iterator link_iter = current_links.begin(); - LLPumpIO::links_t::iterator links_end = current_links.end(); - bool after_this = false; - for(; link_iter < links_end; ++link_iter) - { - if(after_this) - { - chain.push_back((*link_iter).mPipe); - } - else if(this == (*link_iter).mPipe.get()) - { - after_this = true; - } - } - - // Do the final build of the chain, and send it on - // it's way. - LLChannelDescriptors chnl = channels; - LLPumpIO::LLLinkInfo link; - LLPumpIO::links_t links; - LLPumpIO::chain_t::iterator it = chain.begin(); - LLPumpIO::chain_t::iterator end = chain.end(); - while(it != end) - { - link.mPipe = *it; - link.mChannels = chnl; - links.push_back(link); - chnl = LLBufferArray::makeChannelConsumer(chnl); - ++it; - } - pump->addChain( - links, - buffer, - context, - DEFAULT_CHAIN_EXPIRY_SECS); - - status = STATUS_STOP; - } - else - { - LL_WARNS() << "LLHTTPResponder::process_impl didn't find a node for " - << mAbsPathAndQuery << LL_ENDL; - LLBufferStream str(channels, buffer.get()); - mState = STATE_SHORT_CIRCUIT; - str << HTTP_VERSION_STR << " 404 Not Found\r\n\r\n<html>\n" - << "<title>Not Found</title>\n<body>\nNode '" << mAbsPathAndQuery - << "' not found.\n</body>\n</html>\n"; - } - } - - if(STATE_SHORT_CIRCUIT == mState) - { - //status = mNext->process(buffer, true, pump, context); - status = STATUS_DONE; - } - PUMP_DEBUG; - return status; + } + buffer->unlock(); + // + // *FIX: get rid of extra bytes off the end + // + + // Set up a chain which will prepend a content length and + // HTTP headers. + LLPumpIO::chain_t chain; + chain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); + context[CONTEXT_REQUEST][CONTEXT_PATH] = mPath; + context[CONTEXT_REQUEST][CONTEXT_QUERY_STRING] = mQuery; + context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST] + = mBuildContext[CONTEXT_REMOTE_HOST]; + context[CONTEXT_REQUEST][CONTEXT_REMOTE_PORT] + = mBuildContext[CONTEXT_REMOTE_PORT]; + context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders; + + const LLChainIOFactory* protocolHandler + = node->getProtocolHandler(); + if (protocolHandler) + { + LL_DEBUGS() << "HTTP context: " << context << LL_ENDL; + protocolHandler->build(chain, context); + } + else + { + // this is a simple LLHTTPNode, so use LLHTTPPipe + chain.push_back(LLIOPipe::ptr_t(new LLHTTPPipe(*node))); + } + + // Add the header - which needs to have the same + // channel information as the link before it since it + // is part of the response. + LLIOPipe* header = new LLHTTPResponseHeader; + chain.push_back(LLIOPipe::ptr_t(header)); + + // We need to copy all of the pipes _after_ this so + // that the response goes out correctly. + LLPumpIO::links_t current_links; + pump->copyCurrentLinkInfo(current_links); + LLPumpIO::links_t::iterator link_iter = current_links.begin(); + LLPumpIO::links_t::iterator links_end = current_links.end(); + bool after_this = false; + for(; link_iter < links_end; ++link_iter) + { + if(after_this) + { + chain.push_back((*link_iter).mPipe); + } + else if(this == (*link_iter).mPipe.get()) + { + after_this = true; + } + } + + // Do the final build of the chain, and send it on + // it's way. + LLChannelDescriptors chnl = channels; + LLPumpIO::LLLinkInfo link; + LLPumpIO::links_t links; + LLPumpIO::chain_t::iterator it = chain.begin(); + LLPumpIO::chain_t::iterator end = chain.end(); + while(it != end) + { + link.mPipe = *it; + link.mChannels = chnl; + links.push_back(link); + chnl = LLBufferArray::makeChannelConsumer(chnl); + ++it; + } + pump->addChain( + links, + buffer, + context, + DEFAULT_CHAIN_EXPIRY_SECS); + + status = STATUS_STOP; + } + else + { + LL_WARNS() << "LLHTTPResponder::process_impl didn't find a node for " + << mAbsPathAndQuery << LL_ENDL; + LLBufferStream str(channels, buffer.get()); + mState = STATE_SHORT_CIRCUIT; + str << HTTP_VERSION_STR << " 404 Not Found\r\n\r\n<html>\n" + << "<title>Not Found</title>\n<body>\nNode '" << mAbsPathAndQuery + << "' not found.\n</body>\n</html>\n"; + } + } + + if(STATE_SHORT_CIRCUIT == mState) + { + //status = mNext->process(buffer, true, pump, context); + status = STATUS_DONE; + } + PUMP_DEBUG; + return status; } -// static -void LLIOHTTPServer::createPipe(LLPumpIO::chain_t& chain, +// static +void LLIOHTTPServer::createPipe(LLPumpIO::chain_t& chain, const LLHTTPNode& root, const LLSD& ctx) { - chain.push_back(LLIOPipe::ptr_t(new LLHTTPResponder(root, ctx))); + chain.push_back(LLIOPipe::ptr_t(new LLHTTPResponder(root, ctx))); } class LLHTTPResponseFactory : public LLChainIOFactory { public: - bool build(LLPumpIO::chain_t& chain, LLSD ctx) const - { - LLIOHTTPServer::createPipe(chain, mTree, ctx); - return true; - } + bool build(LLPumpIO::chain_t& chain, LLSD ctx) const + { + LLIOHTTPServer::createPipe(chain, mTree, ctx); + return true; + } - LLHTTPNode& getRootNode() { return mTree; } + LLHTTPNode& getRootNode() { return mTree; } private: - LLHTTPNode mTree; + LLHTTPNode mTree; }; // static LLHTTPNode& LLIOHTTPServer::create( - apr_pool_t* pool, LLPumpIO& pump, U16 port) + apr_pool_t* pool, LLPumpIO& pump, U16 port) { - LLSocket::ptr_t socket = LLSocket::create( + LLSocket::ptr_t socket = LLSocket::create( pool, LLSocket::STREAM_TCP, port); @@ -982,21 +982,21 @@ LLHTTPNode& LLIOHTTPServer::create( } LLHTTPResponseFactory* factory = new LLHTTPResponseFactory; - std::shared_ptr<LLChainIOFactory> factory_ptr(factory); + std::shared_ptr<LLChainIOFactory> factory_ptr(factory); LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr); - LLPumpIO::chain_t chain; + LLPumpIO::chain_t chain; chain.push_back(LLIOPipe::ptr_t(server)); pump.addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - return factory->getRootNode(); + return factory->getRootNode(); } // static void LLIOHTTPServer::setTimingCallback(timing_callback_t callback, - void* data) + void* data) { - sTimingCallback = callback; - sTimingCallbackData = data; + sTimingCallback = callback; + sTimingCallbackData = data; } diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h index a23eafe58a..a1ae8736b7 100644 --- a/indra/llmessage/lliohttpserver.h +++ b/indra/llmessage/lliohttpserver.h @@ -1,4 +1,4 @@ -/** +/** * @file lliohttpserver.h * @brief Declaration of function for creating an HTTP wire server * @see LLIOServerSocket, LLPumpIO @@ -6,21 +6,21 @@ * $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$ */ @@ -36,38 +36,38 @@ class LLPumpIO; class LLIOHTTPServer { public: - typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data); - - static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port); - /**< Creates an HTTP wire server on the pump for the given TCP port. - * - * Returns the root node of the new server. Add LLHTTPNode instances - * to this root. - * - * Nodes that return NULL for getProtocolHandler(), will use the - * default handler that interprets HTTP on the wire and converts - * it into calls to get(), put(), post(), del() with appropriate - * LLSD arguments and results. - * - * To have nodes that implement some other wire protocol (XML-RPC - * for example), use the helper templates below. - */ - - static void createPipe(LLPumpIO::chain_t& chain, + typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data); + + static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port); + /**< Creates an HTTP wire server on the pump for the given TCP port. + * + * Returns the root node of the new server. Add LLHTTPNode instances + * to this root. + * + * Nodes that return NULL for getProtocolHandler(), will use the + * default handler that interprets HTTP on the wire and converts + * it into calls to get(), put(), post(), del() with appropriate + * LLSD arguments and results. + * + * To have nodes that implement some other wire protocol (XML-RPC + * for example), use the helper templates below. + */ + + static void createPipe(LLPumpIO::chain_t& chain, const LLHTTPNode& root, const LLSD& ctx); - /**< Create a pipe on the chain that handles HTTP requests. - * The requests are served by the node tree given at root. - * - * This is primarily useful for unit testing. - */ - - static void setTimingCallback(timing_callback_t callback, void* data); - /**< Register a callback function that will be called every time - * a GET, PUT, POST, or DELETE is handled. - * - * This is used to time the LLHTTPNode handler code, which often hits - * the database or does other, slow operations. JC - */ + /**< Create a pipe on the chain that handles HTTP requests. + * The requests are served by the node tree given at root. + * + * This is primarily useful for unit testing. + */ + + static void setTimingCallback(timing_callback_t callback, void* data); + /**< Register a callback function that will be called every time + * a GET, PUT, POST, or DELETE is handled. + * + * This is used to time the LLHTTPNode handler code, which often hits + * the database or does other, slow operations. JC + */ }; /* @name Helper Templates @@ -80,14 +80,14 @@ public: * * The templates are: * - * LLChainIOFactoryForPipe - * - a simple factory that builds instances of a pipe + * LLChainIOFactoryForPipe + * - a simple factory that builds instances of a pipe * - * LLHTTPNodeForFacotry - * - a HTTP node that uses a factory as the protocol handler + * LLHTTPNodeForFacotry + * - a HTTP node that uses a factory as the protocol handler * - * LLHTTPNodeForPipe - * - a HTTP node that uses a simple factory based on a pipe + * LLHTTPNodeForPipe + * - a HTTP node that uses a simple factory based on a pipe */ //@{ @@ -95,22 +95,22 @@ template<class Pipe> class LLChainIOFactoryForPipe : public LLChainIOFactory { public: - virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const - { - chain.push_back(LLIOPipe::ptr_t(new Pipe)); - return true; - } + virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const + { + chain.push_back(LLIOPipe::ptr_t(new Pipe)); + return true; + } }; template<class Factory> class LLHTTPNodeForFactory : public LLHTTPNode { public: - const LLChainIOFactory* getProtocolHandler() const - { return &mProtocolHandler; } + const LLChainIOFactory* getProtocolHandler() const + { return &mProtocolHandler; } private: - Factory mProtocolHandler; + Factory mProtocolHandler; }; //@} @@ -118,7 +118,7 @@ private: template<class Pipe> class LLHTTPNodeForPipe : public LLHTTPNodeForFactory< - LLChainIOFactoryForPipe<Pipe> > + LLChainIOFactoryForPipe<Pipe> > { }; diff --git a/indra/llmessage/lliopipe.cpp b/indra/llmessage/lliopipe.cpp index 4676a9a8f0..75811bf3ce 100644 --- a/indra/llmessage/lliopipe.cpp +++ b/indra/llmessage/lliopipe.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lliopipe.cpp * @author Phoenix * @date 2004-11-19 @@ -7,21 +7,21 @@ * $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$ */ @@ -33,32 +33,32 @@ static const std::string STATUS_SUCCESS_NAMES[LLIOPipe::STATUS_SUCCESS_COUNT] = { - std::string("STATUS_OK"), - std::string("STATUS_STOP"), - std::string("STATUS_DONE"), - std::string("STATUS_BREAK"), - std::string("STATUS_NEED_PROCESS"), + std::string("STATUS_OK"), + std::string("STATUS_STOP"), + std::string("STATUS_DONE"), + std::string("STATUS_BREAK"), + std::string("STATUS_NEED_PROCESS"), }; static const std::string STATUS_ERROR_NAMES[LLIOPipe::STATUS_ERROR_COUNT] = { - std::string("STATUS_ERROR"), - std::string("STATUS_NOT_IMPLEMENTED"), - std::string("STATUS_PRECONDITION_NOT_MET"), - std::string("STATUS_NO_CONNECTION"), - std::string("STATUS_LOST_CONNECTION"), - std::string("STATUS_EXPIRED"), + std::string("STATUS_ERROR"), + std::string("STATUS_NOT_IMPLEMENTED"), + std::string("STATUS_PRECONDITION_NOT_MET"), + std::string("STATUS_NO_CONNECTION"), + std::string("STATUS_LOST_CONNECTION"), + std::string("STATUS_EXPIRED"), }; #ifdef LL_DEBUG_PUMPS // Debugging schmutz for deadlock -const char *gPumpFile = ""; -S32 gPumpLine = 0; +const char *gPumpFile = ""; +S32 gPumpLine = 0; void pump_debug(const char *file, S32 line) { - gPumpFile = file; - gPumpLine = line; + gPumpFile = file; + gPumpLine = line; } #endif /* LL_DEBUG_PUMPS */ @@ -66,55 +66,55 @@ void pump_debug(const char *file, S32 line) * LLIOPipe */ LLIOPipe::LLIOPipe() : - mReferenceCount(0) + mReferenceCount(0) { } LLIOPipe::~LLIOPipe() { - //LL_DEBUGS() << "destroying LLIOPipe" << LL_ENDL; + //LL_DEBUGS() << "destroying LLIOPipe" << LL_ENDL; } -//virtual -bool LLIOPipe::isValid() +//virtual +bool LLIOPipe::isValid() { - return true ; + return true ; } // static std::string LLIOPipe::lookupStatusString(EStatus status) { - if((status >= 0) && (status < STATUS_SUCCESS_COUNT)) - { - return STATUS_SUCCESS_NAMES[status]; - } - else - { - S32 error_code = ((S32)status * -1) - 1; - if(error_code < STATUS_ERROR_COUNT) - { - return STATUS_ERROR_NAMES[error_code]; - } - } - std::string rv; - return rv; + if((status >= 0) && (status < STATUS_SUCCESS_COUNT)) + { + return STATUS_SUCCESS_NAMES[status]; + } + else + { + S32 error_code = ((S32)status * -1) - 1; + if(error_code < STATUS_ERROR_COUNT) + { + return STATUS_ERROR_NAMES[error_code]; + } + } + std::string rv; + return rv; } LLIOPipe::EStatus LLIOPipe::process( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { - return process_impl(channels, buffer, eos, context, pump); + return process_impl(channels, buffer, eos, context, pump); } // virtual LLIOPipe::EStatus LLIOPipe::handleError( - LLIOPipe::EStatus status, - LLPumpIO* pump) + LLIOPipe::EStatus status, + LLPumpIO* pump) { - // by default, the error is not handled. - return status; + // by default, the error is not handled. + return status; } diff --git a/indra/llmessage/lliopipe.h b/indra/llmessage/lliopipe.h index e6ac8ebfc2..a58ee045c2 100644 --- a/indra/llmessage/lliopipe.h +++ b/indra/llmessage/lliopipe.h @@ -1,4 +1,4 @@ -/** +/** * @file lliopipe.h * @author Phoenix * @date 2004-11-18 @@ -7,21 +7,21 @@ * $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$ */ @@ -59,7 +59,7 @@ void pump_debug(const char *file, S32 line); void intrusive_ptr_add_ref(LLIOPipe* p); void intrusive_ptr_release(LLIOPipe* p); -/** +/** * @class LLIOPipe * @brief This class is an abstract base class for data processing units * @see LLPumpIO @@ -78,191 +78,191 @@ void intrusive_ptr_release(LLIOPipe* p); class LLIOPipe { public: - /** - * @brief I have decided that IO objects should have a reference - * count. In general, you can pass bald LLIOPipe pointers around - * as you need, but if you need to maintain a reference to one, - * you need to hold a ptr_t. - */ - typedef boost::intrusive_ptr<LLIOPipe> ptr_t; - - /** - * @brief Scattered memory container. - */ - typedef std::shared_ptr<LLBufferArray> buffer_ptr_t; - - /** - * @brief Enumeration for IO return codes - * - * A status code a positive integer value is considered a success, - * but may indicate special handling for future calls, for - * example, issuing a STATUS_STOP to an LLIOSocketReader instance - * will tell the instance to stop reading the socket. A status - * code with a negative value means that a problem has been - * encountered which will require further action on the caller or - * a developer to correct. Some mechanisms, such as the LLPumpIO - * may depend on this definition of success and failure. - */ - enum EStatus - { - // Processing occurred normally, future calls will be accepted. - STATUS_OK = 0, - - // Processing occured normally, but stop unsolicited calls to - // process. - STATUS_STOP = 1, - - // This pipe is done with the processing. Future calls to - // process will be accepted as long as new data is available. - STATUS_DONE = 2, - - // This pipe is requesting that it become the head in a process. - STATUS_BREAK = 3, - - // This pipe is requesting that it become the head in a process. - STATUS_NEED_PROCESS = 4, - - // Keep track of the highest number of success codes here. - STATUS_SUCCESS_COUNT = 5, - - // A generic error code. - STATUS_ERROR = -1, - - // This method has not yet been implemented. This usually - // indicates the programmer working on the pipe is not yet - // done. - STATUS_NOT_IMPLEMENTED = -2, - - // This indicates that a pipe precondition was not met. For - // example, many pipes require an element to appear after them - // in a chain (ie, mNext is not null) and will return this in - // response to method calls. To recover from this, it will - // require the caller to adjust the pipe state or may require - // a dev to adjust the code to satisfy the preconditions. - STATUS_PRECONDITION_NOT_MET = -3, - - // This means we could not connect to a remote host. - STATUS_NO_CONNECTION = -4, - - // The connection was lost. - STATUS_LOST_CONNECTION = -5, - - // The totoal process time has exceeded the timeout. - STATUS_EXPIRED = -6, - - // Keep track of the count of codes here. - STATUS_ERROR_COUNT = 6, - }; - - /** - * @brief Helper function to check status. - * - * When writing code to check status codes, if you do not - * specifically check a particular value, use this method for - * checking an error condition. - * @param status The status to check. - * @return Returns true if the code indicates an error occurred. - */ - inline static bool isError(EStatus status) - { - return ((S32)status < 0); - } - - /** - * @brief Helper function to check status. - * - * When writing code to check status codes, if you do not - * specifically check a particular value, use this method for - * checking an error condition. - * @param status The status to check. - * @return Returns true if the code indicates no error was generated. - */ - inline static bool isSuccess(EStatus status) - { - return ((S32)status >= 0); - } - - /** - * @brief Helper function to turn status into a string. - * - * @param status The status to check. - * @return Returns the name of the status code or empty string on failure. - */ - static std::string lookupStatusString(EStatus status); - - /** - * @brief Process the data in buffer. - * - * @param data The data processed - * @param eos True if this function call is the last because end of stream. - * @param pump The pump which is calling process. May be NULL. - * @param context Shared meta-data for the process. - * @return Returns a status code from the operation. - */ - EStatus process( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - - /** - * @brief Give this pipe a chance to handle a generated error - * - * If this pipe is in a chain being processed by a pump, and one - * of the pipes generates an error, the pump will rewind through - * the chain to see if any of the links can handle the error. For - * example, if a connection is refused in a socket connection, the - * socket client can try to find a new destination host. Return an - * error code if this pipe does not handle the error passed in. - * @param status The status code for the error - * @param pump The pump which was calling process before the error - * was generated. - * @return Returns a status code from the operation. Returns an - * error code if the error passed in was not handled. Returns - * STATUS_OK to indicate the error has been handled. - */ - virtual EStatus handleError(EStatus status, LLPumpIO* pump); - - /** - * @brief Base Destructor - do not call <code>delete</code> directly. - */ - virtual ~LLIOPipe(); - - virtual bool isValid() ; + /** + * @brief I have decided that IO objects should have a reference + * count. In general, you can pass bald LLIOPipe pointers around + * as you need, but if you need to maintain a reference to one, + * you need to hold a ptr_t. + */ + typedef boost::intrusive_ptr<LLIOPipe> ptr_t; + + /** + * @brief Scattered memory container. + */ + typedef std::shared_ptr<LLBufferArray> buffer_ptr_t; + + /** + * @brief Enumeration for IO return codes + * + * A status code a positive integer value is considered a success, + * but may indicate special handling for future calls, for + * example, issuing a STATUS_STOP to an LLIOSocketReader instance + * will tell the instance to stop reading the socket. A status + * code with a negative value means that a problem has been + * encountered which will require further action on the caller or + * a developer to correct. Some mechanisms, such as the LLPumpIO + * may depend on this definition of success and failure. + */ + enum EStatus + { + // Processing occurred normally, future calls will be accepted. + STATUS_OK = 0, + + // Processing occured normally, but stop unsolicited calls to + // process. + STATUS_STOP = 1, + + // This pipe is done with the processing. Future calls to + // process will be accepted as long as new data is available. + STATUS_DONE = 2, + + // This pipe is requesting that it become the head in a process. + STATUS_BREAK = 3, + + // This pipe is requesting that it become the head in a process. + STATUS_NEED_PROCESS = 4, + + // Keep track of the highest number of success codes here. + STATUS_SUCCESS_COUNT = 5, + + // A generic error code. + STATUS_ERROR = -1, + + // This method has not yet been implemented. This usually + // indicates the programmer working on the pipe is not yet + // done. + STATUS_NOT_IMPLEMENTED = -2, + + // This indicates that a pipe precondition was not met. For + // example, many pipes require an element to appear after them + // in a chain (ie, mNext is not null) and will return this in + // response to method calls. To recover from this, it will + // require the caller to adjust the pipe state or may require + // a dev to adjust the code to satisfy the preconditions. + STATUS_PRECONDITION_NOT_MET = -3, + + // This means we could not connect to a remote host. + STATUS_NO_CONNECTION = -4, + + // The connection was lost. + STATUS_LOST_CONNECTION = -5, + + // The totoal process time has exceeded the timeout. + STATUS_EXPIRED = -6, + + // Keep track of the count of codes here. + STATUS_ERROR_COUNT = 6, + }; + + /** + * @brief Helper function to check status. + * + * When writing code to check status codes, if you do not + * specifically check a particular value, use this method for + * checking an error condition. + * @param status The status to check. + * @return Returns true if the code indicates an error occurred. + */ + inline static bool isError(EStatus status) + { + return ((S32)status < 0); + } + + /** + * @brief Helper function to check status. + * + * When writing code to check status codes, if you do not + * specifically check a particular value, use this method for + * checking an error condition. + * @param status The status to check. + * @return Returns true if the code indicates no error was generated. + */ + inline static bool isSuccess(EStatus status) + { + return ((S32)status >= 0); + } + + /** + * @brief Helper function to turn status into a string. + * + * @param status The status to check. + * @return Returns the name of the status code or empty string on failure. + */ + static std::string lookupStatusString(EStatus status); + + /** + * @brief Process the data in buffer. + * + * @param data The data processed + * @param eos True if this function call is the last because end of stream. + * @param pump The pump which is calling process. May be NULL. + * @param context Shared meta-data for the process. + * @return Returns a status code from the operation. + */ + EStatus process( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + + /** + * @brief Give this pipe a chance to handle a generated error + * + * If this pipe is in a chain being processed by a pump, and one + * of the pipes generates an error, the pump will rewind through + * the chain to see if any of the links can handle the error. For + * example, if a connection is refused in a socket connection, the + * socket client can try to find a new destination host. Return an + * error code if this pipe does not handle the error passed in. + * @param status The status code for the error + * @param pump The pump which was calling process before the error + * was generated. + * @return Returns a status code from the operation. Returns an + * error code if the error passed in was not handled. Returns + * STATUS_OK to indicate the error has been handled. + */ + virtual EStatus handleError(EStatus status, LLPumpIO* pump); + + /** + * @brief Base Destructor - do not call <code>delete</code> directly. + */ + virtual ~LLIOPipe(); + + virtual bool isValid() ; protected: - /** - * @brief Base Constructor. - */ - LLIOPipe(); - - /** - * @brief Process the data in buffer - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) = 0; + /** + * @brief Base Constructor. + */ + LLIOPipe(); + + /** + * @brief Process the data in buffer + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) = 0; private: - friend void intrusive_ptr_add_ref(LLIOPipe* p); - friend void intrusive_ptr_release(LLIOPipe* p); - U32 mReferenceCount; + friend void intrusive_ptr_add_ref(LLIOPipe* p); + friend void intrusive_ptr_release(LLIOPipe* p); + U32 mReferenceCount; }; inline void intrusive_ptr_add_ref(LLIOPipe* p) { - ++p->mReferenceCount; + ++p->mReferenceCount; } inline void intrusive_ptr_release(LLIOPipe* p) { - if(p && 0 == --p->mReferenceCount) - { - delete p; - } + if(p && 0 == --p->mReferenceCount) + { + delete p; + } } #endif // LL_LLIOPIPE_H diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 321d7286eb..a14d10fe5f 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lliosocket.cpp * @author Phoenix * @date 2005-07-31 @@ -7,21 +7,21 @@ * $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$ */ @@ -50,15 +50,15 @@ static const S32 LL_RECV_BUFFER_SIZE = 40000; //static const U16 LL_PORT_DISCOVERY_RANGE_MAX = 13050; // -// local methods +// local methods // bool is_addr_in_use(apr_status_t status) { #if LL_WINDOWS - return (WSAEADDRINUSE == APR_TO_OS_ERROR(status)); + return (WSAEADDRINUSE == APR_TO_OS_ERROR(status)); #else - return (EADDRINUSE == APR_TO_OS_ERROR(status)); + return (EADDRINUSE == APR_TO_OS_ERROR(status)); #endif } @@ -71,28 +71,28 @@ bool is_addr_in_use(apr_status_t status) #endif -// Quick function +// Quick function void ll_debug_socket(const char* msg, apr_socket_t* apr_sock) { #if LL_DEBUG_SOCKET_FILE_DESCRIPTORS - if(!apr_sock) - { - LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << ": no socket." << LL_ENDL; - return; - } - // *TODO: Why doesn't this work? - //apr_os_sock_t os_sock; - int os_sock; - if(APR_SUCCESS == apr_os_sock_get(&os_sock, apr_sock)) - { - LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << " on fd " << os_sock - << " at " << apr_sock << LL_ENDL; - } - else - { - LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << " no fd " - << " at " << apr_sock << LL_ENDL; - } + if(!apr_sock) + { + LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << ": no socket." << LL_ENDL; + return; + } + // *TODO: Why doesn't this work? + //apr_os_sock_t os_sock; + int os_sock; + if(APR_SUCCESS == apr_os_sock_get(&os_sock, apr_sock)) + { + LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << " on fd " << os_sock + << " at " << apr_sock << LL_ENDL; + } + else + { + LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << " no fd " + << " at " << apr_sock << LL_ENDL; + } #endif } @@ -103,162 +103,162 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock) // static LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port, const char *hostname) { - LLSocket::ptr_t rv; - apr_socket_t* socket = NULL; - apr_pool_t* new_pool = NULL; - apr_status_t status = APR_EGENERAL; - - // create a pool for the socket - status = apr_pool_create(&new_pool, pool); - if(ll_apr_warn_status(status)) - { - if(new_pool) apr_pool_destroy(new_pool); - return rv; - } - - if(STREAM_TCP == type) - { - status = apr_socket_create( - &socket, - APR_INET, - SOCK_STREAM, - APR_PROTO_TCP, - new_pool); - } - else if(DATAGRAM_UDP == type) - { - status = apr_socket_create( - &socket, - APR_INET, - SOCK_DGRAM, - APR_PROTO_UDP, - new_pool); - } - else - { - if(new_pool) apr_pool_destroy(new_pool); - return rv; - } - if(ll_apr_warn_status(status)) - { - if(new_pool) apr_pool_destroy(new_pool); - return rv; - } - // At this point, the new LLSocket instance takes ownership of new_pool, - // which is why no early return below this call explicitly destroys it: it - // is instead cleaned up by ~LLSocket(). - rv = ptr_t(new LLSocket(socket, new_pool)); - if(port > 0) - { - apr_sockaddr_t* sa = NULL; - status = apr_sockaddr_info_get( - &sa, - hostname, - APR_UNSPEC, - port, - 0, - new_pool); - if(ll_apr_warn_status(status)) - { - rv.reset(); - return rv; - } - // This allows us to reuse the address on quick down/up. This - // is unlikely to create problems. - ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1)); - status = apr_socket_bind(socket, sa); - if(ll_apr_warn_status(status)) - { - rv.reset(); - return rv; - } - LL_DEBUGS() << "Bound " << ((DATAGRAM_UDP == type) ? "udp" : "tcp") - << " socket to port: " << sa->port << LL_ENDL; - if(STREAM_TCP == type) - { - // If it's a stream based socket, we need to tell the OS - // to keep a queue of incoming connections for ACCEPT. - LL_DEBUGS() << "Setting listen state for socket." << LL_ENDL; - status = apr_socket_listen( - socket, - LL_DEFAULT_LISTEN_BACKLOG); - if(ll_apr_warn_status(status)) - { - rv.reset(); - return rv; - } - } - } - else // port <= 0 - { - // we need to indicate that we have an ephemeral port if the - // previous calls were successful. It will - port = PORT_EPHEMERAL; - } - rv->mPort = port; - rv->setNonBlocking(); - return rv; + LLSocket::ptr_t rv; + apr_socket_t* socket = NULL; + apr_pool_t* new_pool = NULL; + apr_status_t status = APR_EGENERAL; + + // create a pool for the socket + status = apr_pool_create(&new_pool, pool); + if(ll_apr_warn_status(status)) + { + if(new_pool) apr_pool_destroy(new_pool); + return rv; + } + + if(STREAM_TCP == type) + { + status = apr_socket_create( + &socket, + APR_INET, + SOCK_STREAM, + APR_PROTO_TCP, + new_pool); + } + else if(DATAGRAM_UDP == type) + { + status = apr_socket_create( + &socket, + APR_INET, + SOCK_DGRAM, + APR_PROTO_UDP, + new_pool); + } + else + { + if(new_pool) apr_pool_destroy(new_pool); + return rv; + } + if(ll_apr_warn_status(status)) + { + if(new_pool) apr_pool_destroy(new_pool); + return rv; + } + // At this point, the new LLSocket instance takes ownership of new_pool, + // which is why no early return below this call explicitly destroys it: it + // is instead cleaned up by ~LLSocket(). + rv = ptr_t(new LLSocket(socket, new_pool)); + if(port > 0) + { + apr_sockaddr_t* sa = NULL; + status = apr_sockaddr_info_get( + &sa, + hostname, + APR_UNSPEC, + port, + 0, + new_pool); + if(ll_apr_warn_status(status)) + { + rv.reset(); + return rv; + } + // This allows us to reuse the address on quick down/up. This + // is unlikely to create problems. + ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1)); + status = apr_socket_bind(socket, sa); + if(ll_apr_warn_status(status)) + { + rv.reset(); + return rv; + } + LL_DEBUGS() << "Bound " << ((DATAGRAM_UDP == type) ? "udp" : "tcp") + << " socket to port: " << sa->port << LL_ENDL; + if(STREAM_TCP == type) + { + // If it's a stream based socket, we need to tell the OS + // to keep a queue of incoming connections for ACCEPT. + LL_DEBUGS() << "Setting listen state for socket." << LL_ENDL; + status = apr_socket_listen( + socket, + LL_DEFAULT_LISTEN_BACKLOG); + if(ll_apr_warn_status(status)) + { + rv.reset(); + return rv; + } + } + } + else // port <= 0 + { + // we need to indicate that we have an ephemeral port if the + // previous calls were successful. It will + port = PORT_EPHEMERAL; + } + rv->mPort = port; + rv->setNonBlocking(); + return rv; } // static LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool) { - LLSocket::ptr_t rv; - if(!socket) - { - return rv; - } - rv = ptr_t(new LLSocket(socket, pool)); - rv->mPort = PORT_EPHEMERAL; - rv->setNonBlocking(); - return rv; + LLSocket::ptr_t rv; + if(!socket) + { + return rv; + } + rv = ptr_t(new LLSocket(socket, pool)); + rv->mPort = PORT_EPHEMERAL; + rv->setNonBlocking(); + return rv; } bool LLSocket::blockingConnect(const LLHost& host) { - if(!mSocket) return false; - apr_sockaddr_t* sa = NULL; - std::string ip_address; - ip_address = host.getIPString(); - if(ll_apr_warn_status(apr_sockaddr_info_get( - &sa, - ip_address.c_str(), - APR_UNSPEC, - host.getPort(), - 0, - mPool))) - { - return false; - } - setBlocking(1000); - ll_debug_socket("Blocking connect", mSocket); - if(ll_apr_warn_status(apr_socket_connect(mSocket, sa))) return false; - setNonBlocking(); - return true; + if(!mSocket) return false; + apr_sockaddr_t* sa = NULL; + std::string ip_address; + ip_address = host.getIPString(); + if(ll_apr_warn_status(apr_sockaddr_info_get( + &sa, + ip_address.c_str(), + APR_UNSPEC, + host.getPort(), + 0, + mPool))) + { + return false; + } + setBlocking(1000); + ll_debug_socket("Blocking connect", mSocket); + if(ll_apr_warn_status(apr_socket_connect(mSocket, sa))) return false; + setNonBlocking(); + return true; } LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) : - mSocket(socket), - mPool(pool), - mPort(PORT_INVALID) + mSocket(socket), + mPool(pool), + mPort(PORT_INVALID) { - ll_debug_socket("Constructing wholely formed socket", mSocket); + ll_debug_socket("Constructing wholely formed socket", mSocket); } LLSocket::~LLSocket() { - // *FIX: clean up memory we are holding. - if(mSocket) - { - ll_debug_socket("Destroying socket", mSocket); - apr_socket_close(mSocket); - mSocket = NULL; - } - if(mPool) - { - apr_pool_destroy(mPool); - } + // *FIX: clean up memory we are holding. + if(mSocket) + { + ll_debug_socket("Destroying socket", mSocket); + apr_socket_close(mSocket); + mSocket = NULL; + } + if(mPool) + { + apr_pool_destroy(mPool); + } } // See http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4 @@ -267,21 +267,21 @@ LLSocket::~LLSocket() void LLSocket::setBlocking(S32 timeout) { - // set up the socket options - ll_apr_warn_status(apr_socket_timeout_set(mSocket, timeout)); // Sets both receive and send timeout SO_RCVTIMEO, SO_SNDTIMEO - ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 0)); - ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE)); - ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE)); + // set up the socket options + ll_apr_warn_status(apr_socket_timeout_set(mSocket, timeout)); // Sets both receive and send timeout SO_RCVTIMEO, SO_SNDTIMEO + ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 0)); + ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE)); + ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE)); } void LLSocket::setNonBlocking() { - // set up the socket options - ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0)); - ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 1)); - ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE)); - ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE)); + // set up the socket options + ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0)); + ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 1)); + ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE)); + ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE)); } @@ -290,96 +290,96 @@ void LLSocket::setNonBlocking() /// LLIOSocketReader::LLIOSocketReader(LLSocket::ptr_t socket) : - mSource(socket), - mInitialized(false) + mSource(socket), + mInitialized(false) { } LLIOSocketReader::~LLIOSocketReader() { - //LL_DEBUGS() << "Destroying LLIOSocketReader" << LL_ENDL; + //LL_DEBUGS() << "Destroying LLIOSocketReader" << LL_ENDL; } // virtual LLIOPipe::EStatus LLIOSocketReader::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; - if(!mSource) return STATUS_PRECONDITION_NOT_MET; - if(!mInitialized) - { - PUMP_DEBUG; - // Since the read will not block, it's ok to initialize and - // attempt to read off the descriptor immediately. - mInitialized = true; - if(pump) - { - PUMP_DEBUG; - LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketReader." - << LL_ENDL; - apr_pollfd_t poll_fd; - poll_fd.p = NULL; - poll_fd.desc_type = APR_POLL_SOCKET; - poll_fd.reqevents = APR_POLLIN; - poll_fd.rtnevents = 0x0; - poll_fd.desc.s = mSource->getSocket(); - poll_fd.client_data = NULL; - pump->setConditional(this, &poll_fd); - } - } - //if(!buffer) - //{ - // buffer = new LLBufferArray; - //} - PUMP_DEBUG; - const apr_size_t READ_BUFFER_SIZE = 1024; - char read_buf[READ_BUFFER_SIZE]; /*Flawfinder: ignore*/ - apr_size_t len; - apr_status_t status = APR_SUCCESS; - do - { - PUMP_DEBUG; - len = READ_BUFFER_SIZE; - status = apr_socket_recv(mSource->getSocket(), read_buf, &len); - buffer->append(channels.out(), (U8*)read_buf, len); - } while((APR_SUCCESS == status) && (READ_BUFFER_SIZE == len)); - LL_DEBUGS() << "socket read status: " << status << LL_ENDL; - LLIOPipe::EStatus rv = STATUS_OK; - - PUMP_DEBUG; - // *FIX: Also need to check for broken pipe - if(APR_STATUS_IS_EOF(status)) - { - // *FIX: Should we shut down the socket read? - if(pump) - { - pump->setConditional(this, NULL); - } - rv = STATUS_DONE; - eos = true; - } - else if(APR_STATUS_IS_EAGAIN(status)) - { + PUMP_DEBUG; + if(!mSource) return STATUS_PRECONDITION_NOT_MET; + if(!mInitialized) + { + PUMP_DEBUG; + // Since the read will not block, it's ok to initialize and + // attempt to read off the descriptor immediately. + mInitialized = true; + if(pump) + { + PUMP_DEBUG; + LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketReader." + << LL_ENDL; + apr_pollfd_t poll_fd; + poll_fd.p = NULL; + poll_fd.desc_type = APR_POLL_SOCKET; + poll_fd.reqevents = APR_POLLIN; + poll_fd.rtnevents = 0x0; + poll_fd.desc.s = mSource->getSocket(); + poll_fd.client_data = NULL; + pump->setConditional(this, &poll_fd); + } + } + //if(!buffer) + //{ + // buffer = new LLBufferArray; + //} + PUMP_DEBUG; + const apr_size_t READ_BUFFER_SIZE = 1024; + char read_buf[READ_BUFFER_SIZE]; /*Flawfinder: ignore*/ + apr_size_t len; + apr_status_t status = APR_SUCCESS; + do + { + PUMP_DEBUG; + len = READ_BUFFER_SIZE; + status = apr_socket_recv(mSource->getSocket(), read_buf, &len); + buffer->append(channels.out(), (U8*)read_buf, len); + } while((APR_SUCCESS == status) && (READ_BUFFER_SIZE == len)); + LL_DEBUGS() << "socket read status: " << status << LL_ENDL; + LLIOPipe::EStatus rv = STATUS_OK; + + PUMP_DEBUG; + // *FIX: Also need to check for broken pipe + if(APR_STATUS_IS_EOF(status)) + { + // *FIX: Should we shut down the socket read? + if(pump) + { + pump->setConditional(this, NULL); + } + rv = STATUS_DONE; + eos = true; + } + else if(APR_STATUS_IS_EAGAIN(status)) + { /*Commented out by Aura 9-9-8 for DEV-19961. - // everything is fine, but we can terminate this process pump. - - rv = STATUS_BREAK; + // everything is fine, but we can terminate this process pump. + + rv = STATUS_BREAK; */ - } - else - { - if(ll_apr_warn_status(status)) - { - rv = STATUS_ERROR; - } - } - PUMP_DEBUG; - return rv; + } + else + { + if(ll_apr_warn_status(status)) + { + rv = STATUS_ERROR; + } + } + PUMP_DEBUG; + return rv; } /// @@ -387,143 +387,143 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl( /// LLIOSocketWriter::LLIOSocketWriter(LLSocket::ptr_t socket) : - mDestination(socket), - mLastWritten(NULL), - mInitialized(false) + mDestination(socket), + mLastWritten(NULL), + mInitialized(false) { } LLIOSocketWriter::~LLIOSocketWriter() { - //LL_DEBUGS() << "Destroying LLIOSocketWriter" << LL_ENDL; + //LL_DEBUGS() << "Destroying LLIOSocketWriter" << LL_ENDL; } // virtual LLIOPipe::EStatus LLIOSocketWriter::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; - if(!mDestination) return STATUS_PRECONDITION_NOT_MET; - if(!mInitialized) - { - PUMP_DEBUG; - // Since the write will not block, it's ok to initialize and - // attempt to write immediately. - mInitialized = true; - if(pump) - { - PUMP_DEBUG; - LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketWriter." - << LL_ENDL; - apr_pollfd_t poll_fd; - poll_fd.p = NULL; - poll_fd.desc_type = APR_POLL_SOCKET; - poll_fd.reqevents = APR_POLLOUT; - poll_fd.rtnevents = 0x0; - poll_fd.desc.s = mDestination->getSocket(); - poll_fd.client_data = NULL; - pump->setConditional(this, &poll_fd); - } - } - - PUMP_DEBUG; - // *FIX: Some sort of writev implementation would be much more - // efficient - not only because writev() is better, but also - // because we won't have to do as much work to find the start - // address. - buffer->lock(); - LLBufferArray::segment_iterator_t it; - LLBufferArray::segment_iterator_t end = buffer->endSegment(); - LLSegment segment; - it = buffer->constructSegmentAfter(mLastWritten, segment); - /* - if(NULL == mLastWritten) - { - it = buffer->beginSegment(); - segment = (*it); - } - else - { - it = buffer->getSegment(mLastWritten); - segment = (*it); - S32 size = segment.size(); - U8* data = segment.data(); - if((data + size) == mLastWritten) - { - ++it; - segment = (*it); - } - else - { - // *FIX: check the math on this one - segment = LLSegment( - (*it).getChannelMask(), - mLastWritten + 1, - size - (mLastWritten - data)); - } - } - */ - - PUMP_DEBUG; - apr_size_t len; - bool done = false; - apr_status_t status = APR_SUCCESS; - while(it != end) - { - - PUMP_DEBUG; - if((*it).isOnChannel(channels.in())) - { - PUMP_DEBUG; - len = (apr_size_t)segment.size(); - status = apr_socket_send( - mDestination->getSocket(), - (const char*)segment.data(), - &len); - // We sometimes get a 'non-blocking socket operation could not be - // completed immediately' error from apr_socket_send. In this - // case we break and the data will be sent the next time the chain - // is pumped. - if(APR_STATUS_IS_EAGAIN(status)) - { - ll_apr_warn_status(status); - break; - } - - mLastWritten = segment.data() + len - 1; - - PUMP_DEBUG; - if((S32)len < segment.size()) - { - break; - } - - } - - ++it; - if(it != end) - { - segment = (*it); - } - else - { - done = true; - } - - } - buffer->unlock(); - - PUMP_DEBUG; - if(done && eos) - { - return STATUS_DONE; - } - return STATUS_OK; + PUMP_DEBUG; + if(!mDestination) return STATUS_PRECONDITION_NOT_MET; + if(!mInitialized) + { + PUMP_DEBUG; + // Since the write will not block, it's ok to initialize and + // attempt to write immediately. + mInitialized = true; + if(pump) + { + PUMP_DEBUG; + LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketWriter." + << LL_ENDL; + apr_pollfd_t poll_fd; + poll_fd.p = NULL; + poll_fd.desc_type = APR_POLL_SOCKET; + poll_fd.reqevents = APR_POLLOUT; + poll_fd.rtnevents = 0x0; + poll_fd.desc.s = mDestination->getSocket(); + poll_fd.client_data = NULL; + pump->setConditional(this, &poll_fd); + } + } + + PUMP_DEBUG; + // *FIX: Some sort of writev implementation would be much more + // efficient - not only because writev() is better, but also + // because we won't have to do as much work to find the start + // address. + buffer->lock(); + LLBufferArray::segment_iterator_t it; + LLBufferArray::segment_iterator_t end = buffer->endSegment(); + LLSegment segment; + it = buffer->constructSegmentAfter(mLastWritten, segment); + /* + if(NULL == mLastWritten) + { + it = buffer->beginSegment(); + segment = (*it); + } + else + { + it = buffer->getSegment(mLastWritten); + segment = (*it); + S32 size = segment.size(); + U8* data = segment.data(); + if((data + size) == mLastWritten) + { + ++it; + segment = (*it); + } + else + { + // *FIX: check the math on this one + segment = LLSegment( + (*it).getChannelMask(), + mLastWritten + 1, + size - (mLastWritten - data)); + } + } + */ + + PUMP_DEBUG; + apr_size_t len; + bool done = false; + apr_status_t status = APR_SUCCESS; + while(it != end) + { + + PUMP_DEBUG; + if((*it).isOnChannel(channels.in())) + { + PUMP_DEBUG; + len = (apr_size_t)segment.size(); + status = apr_socket_send( + mDestination->getSocket(), + (const char*)segment.data(), + &len); + // We sometimes get a 'non-blocking socket operation could not be + // completed immediately' error from apr_socket_send. In this + // case we break and the data will be sent the next time the chain + // is pumped. + if(APR_STATUS_IS_EAGAIN(status)) + { + ll_apr_warn_status(status); + break; + } + + mLastWritten = segment.data() + len - 1; + + PUMP_DEBUG; + if((S32)len < segment.size()) + { + break; + } + + } + + ++it; + if(it != end) + { + segment = (*it); + } + else + { + done = true; + } + + } + buffer->unlock(); + + PUMP_DEBUG; + if(done && eos) + { + return STATUS_DONE; + } + return STATUS_OK; } @@ -532,166 +532,166 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl( /// LLIOServerSocket::LLIOServerSocket( - apr_pool_t* pool, - LLIOServerSocket::socket_t listener, - factory_t factory) : - mPool(pool), - mListenSocket(listener), - mReactor(factory), - mInitialized(false), - mResponseTimeout(DEFAULT_CHAIN_EXPIRY_SECS) + apr_pool_t* pool, + LLIOServerSocket::socket_t listener, + factory_t factory) : + mPool(pool), + mListenSocket(listener), + mReactor(factory), + mInitialized(false), + mResponseTimeout(DEFAULT_CHAIN_EXPIRY_SECS) { } LLIOServerSocket::~LLIOServerSocket() { - //LL_DEBUGS() << "Destroying LLIOServerSocket" << LL_ENDL; + //LL_DEBUGS() << "Destroying LLIOServerSocket" << LL_ENDL; } void LLIOServerSocket::setResponseTimeout(F32 timeout_secs) { - mResponseTimeout = timeout_secs; + mResponseTimeout = timeout_secs; } // virtual LLIOPipe::EStatus LLIOServerSocket::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - PUMP_DEBUG; - if(!pump) - { - LL_WARNS() << "Need a pump for server socket." << LL_ENDL; - return STATUS_ERROR; - } - if(!mInitialized) - { - PUMP_DEBUG; - // This segment sets up the pump so that we do not call - // process again until we have an incoming read, aka connect() - // from a remote host. - LL_DEBUGS() << "Initializing poll descriptor for LLIOServerSocket." - << LL_ENDL; - apr_pollfd_t poll_fd; - poll_fd.p = NULL; - poll_fd.desc_type = APR_POLL_SOCKET; - poll_fd.reqevents = APR_POLLIN; - poll_fd.rtnevents = 0x0; - poll_fd.desc.s = mListenSocket->getSocket(); - poll_fd.client_data = NULL; - pump->setConditional(this, &poll_fd); - mInitialized = true; - return STATUS_OK; - } - - // we are initialized, and told to process, so we must have a - // socket waiting for a connection. - LL_DEBUGS() << "accepting socket" << LL_ENDL; - - PUMP_DEBUG; - apr_pool_t* new_pool = NULL; - apr_status_t status = apr_pool_create(&new_pool, mPool); - if(ll_apr_warn_status(status)) - { - if(new_pool) - { - apr_pool_destroy(new_pool); - } - return STATUS_ERROR; - } - - apr_socket_t* socket = NULL; - status = apr_socket_accept( - &socket, - mListenSocket->getSocket(), - new_pool); - LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool)); - //EStatus rv = STATUS_ERROR; - if(llsocket) - { - PUMP_DEBUG; - - apr_sockaddr_t* remote_addr; - apr_socket_addr_get(&remote_addr, APR_REMOTE, socket); - - char* remote_host_string; - apr_sockaddr_ip_get(&remote_host_string, remote_addr); - - LLSD context; - context[CONTEXT_REMOTE_HOST] = remote_host_string; - context[CONTEXT_REMOTE_PORT] = remote_addr->port; - - LLPumpIO::chain_t chain; - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(llsocket))); - if(mReactor->build(chain, context)) - { - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket))); - pump->addChain(chain, mResponseTimeout); - status = STATUS_OK; - } - else - { - LL_WARNS() << "Unable to build reactor to socket." << LL_ENDL; - } - } - else - { - LL_WARNS() << "Unable to create linden socket." << LL_ENDL; - } - - PUMP_DEBUG; - // This needs to always return success, lest it get removed from - // the pump. - return STATUS_OK; + PUMP_DEBUG; + if(!pump) + { + LL_WARNS() << "Need a pump for server socket." << LL_ENDL; + return STATUS_ERROR; + } + if(!mInitialized) + { + PUMP_DEBUG; + // This segment sets up the pump so that we do not call + // process again until we have an incoming read, aka connect() + // from a remote host. + LL_DEBUGS() << "Initializing poll descriptor for LLIOServerSocket." + << LL_ENDL; + apr_pollfd_t poll_fd; + poll_fd.p = NULL; + poll_fd.desc_type = APR_POLL_SOCKET; + poll_fd.reqevents = APR_POLLIN; + poll_fd.rtnevents = 0x0; + poll_fd.desc.s = mListenSocket->getSocket(); + poll_fd.client_data = NULL; + pump->setConditional(this, &poll_fd); + mInitialized = true; + return STATUS_OK; + } + + // we are initialized, and told to process, so we must have a + // socket waiting for a connection. + LL_DEBUGS() << "accepting socket" << LL_ENDL; + + PUMP_DEBUG; + apr_pool_t* new_pool = NULL; + apr_status_t status = apr_pool_create(&new_pool, mPool); + if(ll_apr_warn_status(status)) + { + if(new_pool) + { + apr_pool_destroy(new_pool); + } + return STATUS_ERROR; + } + + apr_socket_t* socket = NULL; + status = apr_socket_accept( + &socket, + mListenSocket->getSocket(), + new_pool); + LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool)); + //EStatus rv = STATUS_ERROR; + if(llsocket) + { + PUMP_DEBUG; + + apr_sockaddr_t* remote_addr; + apr_socket_addr_get(&remote_addr, APR_REMOTE, socket); + + char* remote_host_string; + apr_sockaddr_ip_get(&remote_host_string, remote_addr); + + LLSD context; + context[CONTEXT_REMOTE_HOST] = remote_host_string; + context[CONTEXT_REMOTE_PORT] = remote_addr->port; + + LLPumpIO::chain_t chain; + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(llsocket))); + if(mReactor->build(chain, context)) + { + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket))); + pump->addChain(chain, mResponseTimeout); + status = STATUS_OK; + } + else + { + LL_WARNS() << "Unable to build reactor to socket." << LL_ENDL; + } + } + else + { + LL_WARNS() << "Unable to create linden socket." << LL_ENDL; + } + + PUMP_DEBUG; + // This needs to always return success, lest it get removed from + // the pump. + return STATUS_OK; } #if 0 LLIODataSocket::LLIODataSocket( - U16 suggested_port, - U16 start_discovery_port, - apr_pool_t* pool) : - mSocket(NULL) + U16 suggested_port, + U16 start_discovery_port, + apr_pool_t* pool) : + mSocket(NULL) { - if(!pool || (PORT_INVALID == suggested_port)) return; - if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return; - apr_sockaddr_t* sa = NULL; - if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return; - apr_status_t status = apr_socket_bind(mSocket, sa); - if((start_discovery_port > 0) && is_addr_in_use(status)) - { - const U16 MAX_ATTEMPT_PORTS = 50; - for(U16 attempt_port = start_discovery_port; - attempt_port < (start_discovery_port + MAX_ATTEMPT_PORTS); - ++attempt_port) - { - sa->port = attempt_port; - sa->sa.sin.sin_port = htons(attempt_port); - status = apr_socket_bind(mSocket, sa); - if(APR_SUCCESS == status) break; - if(is_addr_in_use(status)) continue; - (void)ll_apr_warn_status(status); - } - } - if(ll_apr_warn_status(status)) return; - if(sa->port) - { - LL_DEBUGS() << "Bound datagram socket to port: " << sa->port << LL_ENDL; - mPort = sa->port; - } - else - { - mPort = LLIOSocket::PORT_EPHEMERAL; - } - - // set up the socket options options - ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0)); - ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE)); - ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE)); + if(!pool || (PORT_INVALID == suggested_port)) return; + if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return; + apr_sockaddr_t* sa = NULL; + if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return; + apr_status_t status = apr_socket_bind(mSocket, sa); + if((start_discovery_port > 0) && is_addr_in_use(status)) + { + const U16 MAX_ATTEMPT_PORTS = 50; + for(U16 attempt_port = start_discovery_port; + attempt_port < (start_discovery_port + MAX_ATTEMPT_PORTS); + ++attempt_port) + { + sa->port = attempt_port; + sa->sa.sin.sin_port = htons(attempt_port); + status = apr_socket_bind(mSocket, sa); + if(APR_SUCCESS == status) break; + if(is_addr_in_use(status)) continue; + (void)ll_apr_warn_status(status); + } + } + if(ll_apr_warn_status(status)) return; + if(sa->port) + { + LL_DEBUGS() << "Bound datagram socket to port: " << sa->port << LL_ENDL; + mPort = sa->port; + } + else + { + mPort = LLIOSocket::PORT_EPHEMERAL; + } + + // set up the socket options options + ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0)); + ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE)); + ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE)); } LLIODataSocket::~LLIODataSocket() diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index a62b3c0204..0a3f2617e6 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -1,4 +1,4 @@ -/** +/** * @file lliosocket.h * @author Phoenix * @date 2005-07-31 @@ -7,21 +7,21 @@ * $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$ */ @@ -29,7 +29,7 @@ #ifndef LL_LLIOSOCKET_H #define LL_LLIOSOCKET_H -/** +/** * The socket interface provided here is a simple wraper around apr * sockets, with a pipe source and sink to read and write off of the * socket. Every socket only performs non-blocking operations except @@ -48,7 +48,7 @@ extern const std::string CONTEXT_REMOTE_PORT; class LLHost; -/** +/** * @class LLSocket * @brief Implementation of a wrapper around a socket. * @@ -62,134 +62,134 @@ class LLHost; class LLSocket { public: - /** - * @brief Reference counted shared pointers to sockets. - */ - typedef std::shared_ptr<LLSocket> ptr_t; - - /** - * @brief Type of socket to create. - */ - enum EType - { - STREAM_TCP, - DATAGRAM_UDP, - }; - - /** - * @brief Anonymous enumeration to help identify ports - */ - enum - { - PORT_INVALID = (U16)-1, - PORT_EPHEMERAL = 0, - }; - - /** - * @brief Create a socket. - * - * This is the call you would use if you intend to create a listen - * socket. If you intend the socket to be known to external - * clients without prior port notification, do not use - * PORT_EPHEMERAL. - * @param pool The apr pool to use. A child pool will be created - * and associated with the socket. - * @param type The type of socket to create - * @param port The port for the socket - * @param hostname e.g. APR_ANYADDR to listen openly, or "127.0.0.1" - * @return A valid socket shared pointer if the call worked. - */ - static ptr_t create( - apr_pool_t* pool, - EType type, - U16 port = PORT_EPHEMERAL, - const char *hostname = APR_ANYADDR); - - /** - * @brief Create a LLSocket when you already have an apr socket. - * - * This method assumes an ephemeral port. This is typically used - * by calls which spawn a socket such as a call to - * <code>accept()</code> as in the server socket. This call should - * not fail if you have a valid apr socket. - * Because of the nature of how accept() works, you are expected - * to create a new pool for the socket, use that pool for the - * accept, and pass it in here where it will be bound with the - * socket and destroyed at the same time. - * @param socket The apr socket to use - * @param pool The pool used to create the socket. *NOTE: The pool - * passed in will be DESTROYED. - * @return A valid socket shared pointer if the call worked. - */ - static ptr_t create(apr_socket_t* socket, apr_pool_t* pool); - - /** - * @brief Perform a blocking connect to a host. Do not use in production. - * - * @param host The host to connect this socket to. - * @return Returns true if the connect was successful. - */ - bool blockingConnect(const LLHost& host); - - /** - * @brief Get the type of socket - */ - //EType getType() const { return mType; } - - /** - * @brief Get the port. - * - * This will return PORT_EPHEMERAL if bind was never called. - * @return Returns the port associated with this socket. - */ - U16 getPort() const { return mPort; } - - /** - * @brief Get the apr socket implementation. - * - * @return Returns the raw apr socket. - */ - apr_socket_t* getSocket() const { return mSocket; } - - /** - * @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us. - * @param timeout Number of microseconds to wait on this socket. Any - * negative number means block-forever. TIMEOUT OF 0 IS NON-PORTABLE. - */ - void setBlocking(S32 timeout); - - /** - * @brief Set default socket options, with SO_NONBLOCK = 1 and timeout = 0. - */ - void setNonBlocking(); + /** + * @brief Reference counted shared pointers to sockets. + */ + typedef std::shared_ptr<LLSocket> ptr_t; + + /** + * @brief Type of socket to create. + */ + enum EType + { + STREAM_TCP, + DATAGRAM_UDP, + }; + + /** + * @brief Anonymous enumeration to help identify ports + */ + enum + { + PORT_INVALID = (U16)-1, + PORT_EPHEMERAL = 0, + }; + + /** + * @brief Create a socket. + * + * This is the call you would use if you intend to create a listen + * socket. If you intend the socket to be known to external + * clients without prior port notification, do not use + * PORT_EPHEMERAL. + * @param pool The apr pool to use. A child pool will be created + * and associated with the socket. + * @param type The type of socket to create + * @param port The port for the socket + * @param hostname e.g. APR_ANYADDR to listen openly, or "127.0.0.1" + * @return A valid socket shared pointer if the call worked. + */ + static ptr_t create( + apr_pool_t* pool, + EType type, + U16 port = PORT_EPHEMERAL, + const char *hostname = APR_ANYADDR); + + /** + * @brief Create a LLSocket when you already have an apr socket. + * + * This method assumes an ephemeral port. This is typically used + * by calls which spawn a socket such as a call to + * <code>accept()</code> as in the server socket. This call should + * not fail if you have a valid apr socket. + * Because of the nature of how accept() works, you are expected + * to create a new pool for the socket, use that pool for the + * accept, and pass it in here where it will be bound with the + * socket and destroyed at the same time. + * @param socket The apr socket to use + * @param pool The pool used to create the socket. *NOTE: The pool + * passed in will be DESTROYED. + * @return A valid socket shared pointer if the call worked. + */ + static ptr_t create(apr_socket_t* socket, apr_pool_t* pool); + + /** + * @brief Perform a blocking connect to a host. Do not use in production. + * + * @param host The host to connect this socket to. + * @return Returns true if the connect was successful. + */ + bool blockingConnect(const LLHost& host); + + /** + * @brief Get the type of socket + */ + //EType getType() const { return mType; } + + /** + * @brief Get the port. + * + * This will return PORT_EPHEMERAL if bind was never called. + * @return Returns the port associated with this socket. + */ + U16 getPort() const { return mPort; } + + /** + * @brief Get the apr socket implementation. + * + * @return Returns the raw apr socket. + */ + apr_socket_t* getSocket() const { return mSocket; } + + /** + * @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us. + * @param timeout Number of microseconds to wait on this socket. Any + * negative number means block-forever. TIMEOUT OF 0 IS NON-PORTABLE. + */ + void setBlocking(S32 timeout); + + /** + * @brief Set default socket options, with SO_NONBLOCK = 1 and timeout = 0. + */ + void setNonBlocking(); protected: - /** - * @brief Protected constructor since should only make sockets - * with one of the two <code>create()</code> calls. - */ - LLSocket(apr_socket_t* socket, apr_pool_t* pool); + /** + * @brief Protected constructor since should only make sockets + * with one of the two <code>create()</code> calls. + */ + LLSocket(apr_socket_t* socket, apr_pool_t* pool); public: - /** - * @brief Do not call this directly. - */ - ~LLSocket(); + /** + * @brief Do not call this directly. + */ + ~LLSocket(); protected: - // The apr socket. - apr_socket_t* mSocket; + // The apr socket. + apr_socket_t* mSocket; - // our memory pool - apr_pool_t* mPool; + // our memory pool + apr_pool_t* mPool; - // The port if we know it. - U16 mPort; + // The port if we know it. + U16 mPort; - //EType mType; + //EType mType; }; -/** +/** * @class LLIOSocketReader * @brief An LLIOPipe implementation which reads from a socket. * @see LLIOPipe @@ -201,44 +201,44 @@ protected: class LLIOSocketReader : public LLIOPipe { public: - LLIOSocketReader(LLSocket::ptr_t socket); - ~LLIOSocketReader(); + LLIOSocketReader(LLSocket::ptr_t socket); + ~LLIOSocketReader(); protected: - /* @name LLIOPipe virtual implementations - */ - //@{ - /** - * @brief Process the data coming in the socket. - * - * Since the socket and next pipe must exist for process to make - * any sense, this method will return STATUS_PRECONDITION_NOT_MET - * unless if they are not known. - * If a STATUS_STOP returned by the next link in the chain, this - * reader will turn of the socket polling. - * @param buffer Pointer to a buffer which needs processing. Probably NULL. - * @param bytes Number of bytes to in buffer to process. Probably 0. - * @param eos True if this function is the last. Almost always false. - * @param read Number of bytes actually processed. - * @param pump The pump which is calling process. May be NULL. - * @param context A data structure to pass structured data - * @return STATUS_OK unless the preconditions are not met. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Process the data coming in the socket. + * + * Since the socket and next pipe must exist for process to make + * any sense, this method will return STATUS_PRECONDITION_NOT_MET + * unless if they are not known. + * If a STATUS_STOP returned by the next link in the chain, this + * reader will turn of the socket polling. + * @param buffer Pointer to a buffer which needs processing. Probably NULL. + * @param bytes Number of bytes to in buffer to process. Probably 0. + * @param eos True if this function is the last. Almost always false. + * @param read Number of bytes actually processed. + * @param pump The pump which is calling process. May be NULL. + * @param context A data structure to pass structured data + * @return STATUS_OK unless the preconditions are not met. + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - LLSocket::ptr_t mSource; - std::vector<U8> mBuffer; - bool mInitialized; + LLSocket::ptr_t mSource; + std::vector<U8> mBuffer; + bool mInitialized; }; -/** +/** * @class LLIOSocketWriter * @brief An LLIOPipe implementation which writes to a socket * @see LLIOPipe @@ -249,42 +249,42 @@ protected: class LLIOSocketWriter : public LLIOPipe { public: - LLIOSocketWriter(LLSocket::ptr_t socket); - ~LLIOSocketWriter(); + LLIOSocketWriter(LLSocket::ptr_t socket); + ~LLIOSocketWriter(); protected: - /* @name LLIOPipe virtual implementations - */ - //@{ - /** - * @brief Write the data in buffer to the socket. - * - * Since the socket pipe must exist for process to make any sense, - * this method will return STATUS_PRECONDITION_NOT_MET if it is - * not known. - * @param buffer Pointer to a buffer which needs processing. - * @param bytes Number of bytes to in buffer to process. - * @param eos True if this function is the last. - * @param read Number of bytes actually processed. - * @param pump The pump which is calling process. May be NULL. - * @param context A data structure to pass structured data - * @return A return code for the write. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Write the data in buffer to the socket. + * + * Since the socket pipe must exist for process to make any sense, + * this method will return STATUS_PRECONDITION_NOT_MET if it is + * not known. + * @param buffer Pointer to a buffer which needs processing. + * @param bytes Number of bytes to in buffer to process. + * @param eos True if this function is the last. + * @param read Number of bytes actually processed. + * @param pump The pump which is calling process. May be NULL. + * @param context A data structure to pass structured data + * @return A return code for the write. + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - LLSocket::ptr_t mDestination; - U8* mLastWritten; - bool mInitialized; + LLSocket::ptr_t mDestination; + U8* mLastWritten; + bool mInitialized; }; -/** +/** * @class LLIOServerSocket * @brief An IOPipe implementation which listens and spawns connected * sockets. @@ -304,49 +304,49 @@ protected: class LLIOServerSocket : public LLIOPipe { public: - typedef LLSocket::ptr_t socket_t; - typedef std::shared_ptr<LLChainIOFactory> factory_t; - LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor); - virtual ~LLIOServerSocket(); - - /** - * @brief Set the timeout for the generated chains. - * - * This value is passed directly to the LLPumpIO::addChain() - * method. The default on construction is set to - * DEFAULT_CHAIN_EXPIRY_SECS which is a reasonable value for most - * applications based on this library. Avoid passing in - * NEVER_CHAIN_EXPIRY_SECS unless you have another method of - * harvesting chains. - * @param timeout_secs The seconds before timeout for the response chain. - */ - void setResponseTimeout(F32 timeout_secs); - - /* @name LLIOPipe virtual implementations - */ - //@{ + typedef LLSocket::ptr_t socket_t; + typedef std::shared_ptr<LLChainIOFactory> factory_t; + LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor); + virtual ~LLIOServerSocket(); + + /** + * @brief Set the timeout for the generated chains. + * + * This value is passed directly to the LLPumpIO::addChain() + * method. The default on construction is set to + * DEFAULT_CHAIN_EXPIRY_SECS which is a reasonable value for most + * applications based on this library. Avoid passing in + * NEVER_CHAIN_EXPIRY_SECS unless you have another method of + * harvesting chains. + * @param timeout_secs The seconds before timeout for the response chain. + */ + void setResponseTimeout(F32 timeout_secs); + + /* @name LLIOPipe virtual implementations + */ + //@{ protected: - /** - * @brief Process the data in buffer - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /** + * @brief Process the data in buffer + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - apr_pool_t* mPool; - socket_t mListenSocket; - factory_t mReactor; - bool mInitialized; - F32 mResponseTimeout; + apr_pool_t* mPool; + socket_t mListenSocket; + factory_t mReactor; + bool mInitialized; + F32 mResponseTimeout; }; #if 0 -/** +/** * @class LLIODataSocket * @brief BRIEF_DESC * @@ -355,31 +355,31 @@ protected: class LLIODataSocket : public LLIOSocket { public: - /** - * @brief Construct a datagram socket. - * - * If you pass in LLIOSocket::PORT_EPHEMERAL as the suggested - * port, The socket will not be in a 'listen' mode, but can still - * read data sent back to it's port. When suggested_port is not - * ephemeral or invalid and bind fails, the port discovery - * algorithm will search through a limited set of ports to - * try to find an open port. If that process fails, getPort() will - * return LLIOSocket::PORT_INVALID - * @param suggested_port The port you would like to bind. Use - * LLIOSocket::PORT_EPHEMERAL for an unspecified port. - * @param start_discovery_port The start range for - * @param pool The pool to use for allocation. - */ - LLIODataSocket( - U16 suggested_port, - U16 start_discovery_port, - apr_pool_t* pool); - virtual ~LLIODataSocket(); + /** + * @brief Construct a datagram socket. + * + * If you pass in LLIOSocket::PORT_EPHEMERAL as the suggested + * port, The socket will not be in a 'listen' mode, but can still + * read data sent back to it's port. When suggested_port is not + * ephemeral or invalid and bind fails, the port discovery + * algorithm will search through a limited set of ports to + * try to find an open port. If that process fails, getPort() will + * return LLIOSocket::PORT_INVALID + * @param suggested_port The port you would like to bind. Use + * LLIOSocket::PORT_EPHEMERAL for an unspecified port. + * @param start_discovery_port The start range for + * @param pool The pool to use for allocation. + */ + LLIODataSocket( + U16 suggested_port, + U16 start_discovery_port, + apr_pool_t* pool); + virtual ~LLIODataSocket(); protected: private: - apr_socket_t* mSocket; + apr_socket_t* mSocket; }; #endif diff --git a/indra/llmessage/llioutil.cpp b/indra/llmessage/llioutil.cpp index 850bc2a616..a1bf6332b4 100644 --- a/indra/llmessage/llioutil.cpp +++ b/indra/llmessage/llioutil.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llioutil.cpp * @author Phoenix * @date 2005-10-05 @@ -7,21 +7,21 @@ * $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$ */ @@ -34,65 +34,65 @@ * LLIOFlush */ LLIOPipe::EStatus LLIOFlush::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { - eos = true; - return STATUS_OK; + eos = true; + return STATUS_OK; } -/** +/** * @class LLIOSleep */ LLIOPipe::EStatus LLIOSleep::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - if(mSeconds > 0.0) - { - if(pump) pump->sleepChain(mSeconds); - mSeconds = 0.0; - return STATUS_BREAK; - } - return STATUS_DONE; + if(mSeconds > 0.0) + { + if(pump) pump->sleepChain(mSeconds); + mSeconds = 0.0; + return STATUS_BREAK; + } + return STATUS_DONE; } -/** +/** * @class LLIOAddChain */ LLIOPipe::EStatus LLIOAddChain::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) { LL_PROFILE_ZONE_SCOPED; - pump->addChain(mChain, mTimeout); - return STATUS_DONE; + pump->addChain(mChain, mTimeout); + return STATUS_DONE; } /** * LLChangeChannel */ LLChangeChannel::LLChangeChannel(S32 is, S32 becomes) : - mIs(is), - mBecomes(becomes) + mIs(is), + mBecomes(becomes) { } void LLChangeChannel::operator()(LLSegment& segment) { - if(segment.isOnChannel(mIs)) - { - segment.setChannel(mBecomes); - } + if(segment.isOnChannel(mIs)) + { + segment.setChannel(mBecomes); + } } diff --git a/indra/llmessage/llioutil.h b/indra/llmessage/llioutil.h index c404a98bed..b6a4a9242f 100644 --- a/indra/llmessage/llioutil.h +++ b/indra/llmessage/llioutil.h @@ -1,4 +1,4 @@ -/** +/** * @file llioutil.h * @author Phoenix * @date 2005-10-05 @@ -7,21 +7,21 @@ * $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$ */ @@ -33,7 +33,7 @@ #include "lliopipe.h" #include "llpumpio.h" -/** +/** * @class LLIOFlush * @brief This class is used as a mini chain head which drains the buffer. * @see LLIOPipe @@ -44,27 +44,27 @@ class LLIOFlush : public LLIOPipe { public: - LLIOFlush() {} - virtual ~LLIOFlush() {} + LLIOFlush() {} + virtual ~LLIOFlush() {} protected: - /* @name LLIOPipe virtual implementations - */ - //@{ - /** - * @brief Process the data in buffer - */ - EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Process the data in buffer + */ + EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: }; -/** +/** * @class LLIOSleep * @brief This is a simple helper class which will hold a chain and * process it later using pump mechanisms @@ -73,28 +73,28 @@ protected: class LLIOSleep : public LLIOPipe { public: - LLIOSleep(F64 sleep_seconds) : mSeconds(sleep_seconds) {} - virtual ~LLIOSleep() {} + LLIOSleep(F64 sleep_seconds) : mSeconds(sleep_seconds) {} + virtual ~LLIOSleep() {} protected: - /* @name LLIOPipe virtual implementations - */ - //@{ - /** - * @brief Process the data in buffer - */ - EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Process the data in buffer + */ + EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - F64 mSeconds; + F64 mSeconds; }; -/** +/** * @class LLIOAddChain * @brief Simple pipe that just adds a chain to a pump. * @see LLIOPipe @@ -102,33 +102,33 @@ protected: class LLIOAddChain : public LLIOPipe { public: - LLIOAddChain(const LLPumpIO::chain_t& chain, F32 timeout) : - mChain(chain), - mTimeout(timeout) - {} - virtual ~LLIOAddChain() {} + LLIOAddChain(const LLPumpIO::chain_t& chain, F32 timeout) : + mChain(chain), + mTimeout(timeout) + {} + virtual ~LLIOAddChain() {} protected: - /* @name LLIOPipe virtual implementations - */ - //@{ - /** - * @brief Process the data in buffer - */ - EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Process the data in buffer + */ + EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} protected: - LLPumpIO::chain_t mChain; - F32 mTimeout; + LLPumpIO::chain_t mChain; + F32 mTimeout; }; -/** +/** * @class LLChangeChannel * @brief This class changes the channel of segments in the buffer * @see LLBufferArray @@ -150,22 +150,22 @@ protected: class LLChangeChannel { public: - /** - * @brief Constructor for iterating over a segment range to change channel. - * - * @param is The channel to match when looking at a segment. - * @param becomes The channel to set the segment when a match is found. - */ - LLChangeChannel(S32 is, S32 becomes); + /** + * @brief Constructor for iterating over a segment range to change channel. + * + * @param is The channel to match when looking at a segment. + * @param becomes The channel to set the segment when a match is found. + */ + LLChangeChannel(S32 is, S32 becomes); - /** - * @brief Do the work of changing the channel - */ - void operator()(LLSegment& segment); + /** + * @brief Do the work of changing the channel + */ + void operator()(LLSegment& segment); protected: - S32 mIs; - S32 mBecomes; + S32 mIs; + S32 mBecomes; }; diff --git a/indra/llmessage/llloginflags.h b/indra/llmessage/llloginflags.h index 45833fc914..a4d709888c 100644 --- a/indra/llmessage/llloginflags.h +++ b/indra/llmessage/llloginflags.h @@ -1,25 +1,25 @@ -/** +/** * @file llloginflags.h * @brief Login flag constants. * * $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$ */ @@ -28,20 +28,20 @@ #define LL_LLLOGINFLAGS_H // Is this your first login to Second Life? -const U32 LOGIN_FLAG_FIRST_LOGIN = (1 << 0); +const U32 LOGIN_FLAG_FIRST_LOGIN = (1 << 0); // Is this a trial account? -const U32 LOGIN_FLAG_TRIAL = (1 << 1); +const U32 LOGIN_FLAG_TRIAL = (1 << 1); // Stipend paid since last login? -const U32 LOGIN_FLAG_STIPEND_SINCE_LOGIN = (1 << 2); +const U32 LOGIN_FLAG_STIPEND_SINCE_LOGIN = (1 << 2); // Is your account enabled? -const U32 LOGIN_FLAG_ENABLED = (1 << 3); +const U32 LOGIN_FLAG_ENABLED = (1 << 3); // Is the Pacific Time zone (aka the server time zone) // currently observing daylight savings time? -const U32 LOGIN_FLAG_PACIFIC_DAYLIGHT_TIME = (1 << 4); +const U32 LOGIN_FLAG_PACIFIC_DAYLIGHT_TIME = (1 << 4); // Does the avatar have wearables or not const U32 LOGIN_FLAG_GENDERED = (1 << 5); diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 6414c2c016..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 f97a443c47..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.cpp b/indra/llmessage/llmessagebuilder.cpp index e2ed968a57..2bac3bffee 100644 --- a/indra/llmessage/llmessagebuilder.cpp +++ b/indra/llmessage/llmessagebuilder.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmessagebuilder.cpp * @brief LLMessageBuilder class 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$ */ @@ -31,6 +31,6 @@ //virtual LLMessageBuilder::~LLMessageBuilder() { - // even abstract base classes need a concrete destructor + // even abstract base classes need a concrete destructor } diff --git a/indra/llmessage/llmessagebuilder.h b/indra/llmessage/llmessagebuilder.h index 75bd5f5cc7..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/llmessageconfig.cpp b/indra/llmessage/llmessageconfig.cpp index 64e79d6767..e611688155 100644 --- a/indra/llmessage/llmessageconfig.cpp +++ b/indra/llmessage/llmessageconfig.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmessageconfig.cpp * @brief Live file handling for messaging * * $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$ */ @@ -47,107 +47,107 @@ static LLSD sMessages; class LLMessageConfigFile : public LLLiveFile { public: - LLMessageConfigFile() : - LLLiveFile(filename(), messageConfigRefreshRate), - mMaxQueuedEvents(0) + LLMessageConfigFile() : + LLLiveFile(filename(), messageConfigRefreshRate), + mMaxQueuedEvents(0) { } - static std::string filename(); + static std::string filename(); + + LLSD mMessages; + std::string mServerDefault; - LLSD mMessages; - std::string mServerDefault; - - static LLMessageConfigFile& instance(); - // return the singleton configuration file + static LLMessageConfigFile& instance(); + // return the singleton configuration file - /* virtual */ bool loadFile(); - void loadServerDefaults(const LLSD& data); - void loadMaxQueuedEvents(const LLSD& data); - void loadMessages(const LLSD& data); - void loadCapBans(const LLSD& blacklist); - void loadMessageBans(const LLSD& blacklist); - bool isCapBanned(const std::string& cap_name) const; + /* virtual */ bool loadFile(); + void loadServerDefaults(const LLSD& data); + void loadMaxQueuedEvents(const LLSD& data); + void loadMessages(const LLSD& data); + void loadCapBans(const LLSD& blacklist); + void loadMessageBans(const LLSD& blacklist); + bool isCapBanned(const std::string& cap_name) const; public: - LLSD mCapBans; - S32 mMaxQueuedEvents; + LLSD mCapBans; + S32 mMaxQueuedEvents; private: - static const S32 DEFAULT_MAX_QUEUED_EVENTS = 100; + static const S32 DEFAULT_MAX_QUEUED_EVENTS = 100; }; std::string LLMessageConfigFile::filename() { std::ostringstream ostr; - ostr << sConfigDir//gAppSimp->getOption("configdir").asString() - << "/" << messageConfigFileName; - return ostr.str(); + ostr << sConfigDir//gAppSimp->getOption("configdir").asString() + << "/" << messageConfigFileName; + return ostr.str(); } LLMessageConfigFile& LLMessageConfigFile::instance() { - static LLMessageConfigFile the_file; - the_file.checkAndReload(); - return the_file; + static LLMessageConfigFile the_file; + the_file.checkAndReload(); + return the_file; } // virtual bool LLMessageConfigFile::loadFile() { - LLSD data; + LLSD data; { llifstream file(filename().c_str()); - + if (file.is_open()) { - LL_DEBUGS("AppInit") << "Loading message.xml file at " << filename() << LL_ENDL; + LL_DEBUGS("AppInit") << "Loading message.xml file at " << filename() << LL_ENDL; LLSDSerialize::fromXML(data, file); } if (data.isUndefined()) { LL_INFOS("AppInit") << "LLMessageConfigFile::loadFile: file missing," - " ill-formed, or simply undefined; not changing the" - " file" << LL_ENDL; + " ill-formed, or simply undefined; not changing the" + " file" << LL_ENDL; return false; } } - loadServerDefaults(data); - loadMaxQueuedEvents(data); - loadMessages(data); - loadCapBans(data); - loadMessageBans(data); - return true; + loadServerDefaults(data); + loadMaxQueuedEvents(data); + loadMessages(data); + loadCapBans(data); + loadMessageBans(data); + return true; } void LLMessageConfigFile::loadServerDefaults(const LLSD& data) { - mServerDefault = data["serverDefaults"][sServerName].asString(); + mServerDefault = data["serverDefaults"][sServerName].asString(); } void LLMessageConfigFile::loadMaxQueuedEvents(const LLSD& data) { - if (data.has("maxQueuedEvents")) - { - mMaxQueuedEvents = data["maxQueuedEvents"].asInteger(); - } - else - { - mMaxQueuedEvents = DEFAULT_MAX_QUEUED_EVENTS; - } + if (data.has("maxQueuedEvents")) + { + mMaxQueuedEvents = data["maxQueuedEvents"].asInteger(); + } + else + { + mMaxQueuedEvents = DEFAULT_MAX_QUEUED_EVENTS; + } } void LLMessageConfigFile::loadMessages(const LLSD& data) { - mMessages = data["messages"]; + mMessages = data["messages"]; #ifdef DEBUG - std::ostringstream out; - LLSDXMLFormatter *formatter = new LLSDXMLFormatter; - formatter->format(mMessages, out); - LL_INFOS() << "loading ... " << out.str() - << " LLMessageConfigFile::loadMessages loaded " - << mMessages.size() << " messages" << LL_ENDL; + std::ostringstream out; + LLSDXMLFormatter *formatter = new LLSDXMLFormatter; + formatter->format(mMessages, out); + LL_INFOS() << "loading ... " << out.str() + << " LLMessageConfigFile::loadMessages loaded " + << mMessages.size() << " messages" << LL_ENDL; #endif } @@ -160,9 +160,9 @@ void LLMessageConfigFile::loadCapBans(const LLSD& data) << LL_ENDL; return; } - - mCapBans = bans; - + + mCapBans = bans; + LL_DEBUGS("AppInit") << "LLMessageConfigFile::loadCapBans: " << bans.size() << " ban tests" << LL_ENDL; } @@ -176,13 +176,13 @@ void LLMessageConfigFile::loadMessageBans(const LLSD& data) << LL_ENDL; return; } - - gMessageSystem->setMessageBans(bans["trusted"], bans["untrusted"]); + + gMessageSystem->setMessageBans(bans["trusted"], bans["untrusted"]); } bool LLMessageConfigFile::isCapBanned(const std::string& cap_name) const { - LL_DEBUGS() << "mCapBans is " << LLSDNotationStreamer(mCapBans) << LL_ENDL; + LL_DEBUGS() << "mCapBans is " << LLSDNotationStreamer(mCapBans) << LL_ENDL; return mCapBans[cap_name]; } @@ -192,99 +192,99 @@ bool LLMessageConfigFile::isCapBanned(const std::string& cap_name) const //static void LLMessageConfig::initClass(const std::string& server_name, - const std::string& config_dir) + const std::string& config_dir) { - sServerName = server_name; - sConfigDir = config_dir; - (void) LLMessageConfigFile::instance(); - LL_DEBUGS("AppInit") << "LLMessageConfig::initClass config file " - << config_dir << "/" << messageConfigFileName << LL_ENDL; + sServerName = server_name; + sConfigDir = config_dir; + (void) LLMessageConfigFile::instance(); + LL_DEBUGS("AppInit") << "LLMessageConfig::initClass config file " + << config_dir << "/" << messageConfigFileName << LL_ENDL; } //static void LLMessageConfig::useConfig(const LLSD& config) { - LLMessageConfigFile &the_file = LLMessageConfigFile::instance(); - the_file.loadServerDefaults(config); - the_file.loadMaxQueuedEvents(config); - the_file.loadMessages(config); - the_file.loadCapBans(config); - the_file.loadMessageBans(config); + LLMessageConfigFile &the_file = LLMessageConfigFile::instance(); + the_file.loadServerDefaults(config); + the_file.loadMaxQueuedEvents(config); + the_file.loadMessages(config); + the_file.loadCapBans(config); + the_file.loadMessageBans(config); } //static LLMessageConfig::Flavor LLMessageConfig::getServerDefaultFlavor() { - LLMessageConfigFile& file = LLMessageConfigFile::instance(); - if (file.mServerDefault == "llsd") - { - return LLSD_FLAVOR; - } - if (file.mServerDefault == "template") - { - return TEMPLATE_FLAVOR; - } - return NO_FLAVOR; + LLMessageConfigFile& file = LLMessageConfigFile::instance(); + if (file.mServerDefault == "llsd") + { + return LLSD_FLAVOR; + } + if (file.mServerDefault == "template") + { + return TEMPLATE_FLAVOR; + } + return NO_FLAVOR; } //static S32 LLMessageConfig::getMaxQueuedEvents() { - LLMessageConfigFile& file = LLMessageConfigFile::instance(); - return file.mMaxQueuedEvents; + LLMessageConfigFile& file = LLMessageConfigFile::instance(); + return file.mMaxQueuedEvents; } //static LLMessageConfig::Flavor LLMessageConfig::getMessageFlavor(const std::string& msg_name) { - LLMessageConfigFile& file = LLMessageConfigFile::instance(); - LLSD config = file.mMessages[msg_name]; - if (config["flavor"].asString() == "llsd") - { - return LLSD_FLAVOR; - } - if (config["flavor"].asString() == "template") - { - return TEMPLATE_FLAVOR; - } - return NO_FLAVOR; + LLMessageConfigFile& file = LLMessageConfigFile::instance(); + LLSD config = file.mMessages[msg_name]; + if (config["flavor"].asString() == "llsd") + { + return LLSD_FLAVOR; + } + if (config["flavor"].asString() == "template") + { + return TEMPLATE_FLAVOR; + } + return NO_FLAVOR; } //static LLMessageConfig::SenderTrust LLMessageConfig::getSenderTrustedness( - const std::string& msg_name) + const std::string& msg_name) { - LLMessageConfigFile& file = LLMessageConfigFile::instance(); - LLSD config = file.mMessages[msg_name]; - if (config.has("trusted-sender")) - { - return config["trusted-sender"].asBoolean() ? TRUSTED : UNTRUSTED; - } - return NOT_SET; + LLMessageConfigFile& file = LLMessageConfigFile::instance(); + LLSD config = file.mMessages[msg_name]; + if (config.has("trusted-sender")) + { + return config["trusted-sender"].asBoolean() ? TRUSTED : UNTRUSTED; + } + return NOT_SET; } //static bool LLMessageConfig::isValidMessage(const std::string& msg_name) { - if (sServerName.empty()) - { - LL_ERRS() << "LLMessageConfig::initClass() not called" << LL_ENDL; - } - LLMessageConfigFile& file = LLMessageConfigFile::instance(); - return file.mMessages.has(msg_name); + if (sServerName.empty()) + { + LL_ERRS() << "LLMessageConfig::initClass() not called" << LL_ENDL; + } + LLMessageConfigFile& file = LLMessageConfigFile::instance(); + return file.mMessages.has(msg_name); } //static bool LLMessageConfig::onlySendLatest(const std::string& msg_name) { - LLMessageConfigFile& file = LLMessageConfigFile::instance(); - LLSD config = file.mMessages[msg_name]; - return config["only-send-latest"].asBoolean(); + LLMessageConfigFile& file = LLMessageConfigFile::instance(); + LLSD config = file.mMessages[msg_name]; + return config["only-send-latest"].asBoolean(); } bool LLMessageConfig::isCapBanned(const std::string& cap_name) { - return LLMessageConfigFile::instance().isCapBanned(cap_name); + return LLMessageConfigFile::instance().isCapBanned(cap_name); } // return the web-service path to use for a given @@ -292,13 +292,13 @@ bool LLMessageConfig::isCapBanned(const std::string& cap_name) // in simulator.xml! LLSD LLMessageConfig::getConfigForMessage(const std::string& msg_name) { - if (sServerName.empty()) - { - LL_ERRS() << "LLMessageConfig::isMessageTrusted(name) before" - << " LLMessageConfig::initClass()" << LL_ENDL; - } - LLMessageConfigFile& file = LLMessageConfigFile::instance(); - // LLSD for the CamelCase message name - LLSD config = file.mMessages[msg_name]; - return config; + if (sServerName.empty()) + { + LL_ERRS() << "LLMessageConfig::isMessageTrusted(name) before" + << " LLMessageConfig::initClass()" << LL_ENDL; + } + LLMessageConfigFile& file = LLMessageConfigFile::instance(); + // LLSD for the CamelCase message name + LLSD config = file.mMessages[msg_name]; + return config; } diff --git a/indra/llmessage/llmessageconfig.h b/indra/llmessage/llmessageconfig.h index 1b39c386ca..ce308faa1b 100644 --- a/indra/llmessage/llmessageconfig.h +++ b/indra/llmessage/llmessageconfig.h @@ -1,25 +1,25 @@ -/** +/** * @file llmessageconfig.h * @brief Live file handling for messaging * * $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$ */ @@ -35,22 +35,22 @@ class LLSD; class LLMessageConfig { public: - enum Flavor { NO_FLAVOR=0, LLSD_FLAVOR=1, TEMPLATE_FLAVOR=2 }; - enum SenderTrust { NOT_SET=0, UNTRUSTED=1, TRUSTED=2 }; - - static void initClass(const std::string& server_name, - const std::string& config_dir); - static void useConfig(const LLSD& config); + enum Flavor { NO_FLAVOR=0, LLSD_FLAVOR=1, TEMPLATE_FLAVOR=2 }; + enum SenderTrust { NOT_SET=0, UNTRUSTED=1, TRUSTED=2 }; + + static void initClass(const std::string& server_name, + const std::string& config_dir); + static void useConfig(const LLSD& config); - static Flavor getServerDefaultFlavor(); - static S32 getMaxQueuedEvents(); + static Flavor getServerDefaultFlavor(); + static S32 getMaxQueuedEvents(); - // For individual messages - static Flavor getMessageFlavor(const std::string& msg_name); - static SenderTrust getSenderTrustedness(const std::string& msg_name); - static bool isValidMessage(const std::string& msg_name); - static bool onlySendLatest(const std::string& msg_name); - static bool isCapBanned(const std::string& cap_name); - static LLSD getConfigForMessage(const std::string& msg_name); + // For individual messages + static Flavor getMessageFlavor(const std::string& msg_name); + static SenderTrust getSenderTrustedness(const std::string& msg_name); + static bool isValidMessage(const std::string& msg_name); + static bool onlySendLatest(const std::string& msg_name); + static bool isCapBanned(const std::string& cap_name); + static LLSD getConfigForMessage(const std::string& msg_name); }; #endif // LL_MESSAGECONFIG_H diff --git a/indra/llmessage/llmessagereader.cpp b/indra/llmessage/llmessagereader.cpp index 4a6f5145b3..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 2f64371f63..42d8906e16 100644 --- a/indra/llmessage/llmessagereader.h +++ b/indra/llmessage/llmessagereader.h @@ -1,94 +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/llmessagesenderinterface.h b/indra/llmessage/llmessagesenderinterface.h index ac0f9f7edb..51f03841c3 100644 --- a/indra/llmessage/llmessagesenderinterface.h +++ b/indra/llmessage/llmessagesenderinterface.h @@ -1,25 +1,25 @@ -/** +/** * @file llmessagesenderinterface.h - * @brief + * @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$ */ @@ -35,8 +35,8 @@ class LLSD; class LLMessageSenderInterface { public: - virtual ~LLMessageSenderInterface() {} - virtual S32 sendMessage(const LLHost& host, LLStoredMessagePtr message) = 0; + virtual ~LLMessageSenderInterface() {} + virtual S32 sendMessage(const LLHost& host, LLStoredMessagePtr message) = 0; }; diff --git a/indra/llmessage/llmessagetemplate.cpp b/indra/llmessage/llmessagetemplate.cpp index e70e259436..8d2c1bf87a 100644 --- a/indra/llmessage/llmessagetemplate.cpp +++ b/indra/llmessage/llmessagetemplate.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmessagetemplate.cpp * @brief Implementation of 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$ */ @@ -32,161 +32,161 @@ void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S32 data_size) { - mSize = size; - mDataSize = data_size; - if ( (type != MVT_VARIABLE) && (type != MVT_FIXED) - && (mType != MVT_VARIABLE) && (mType != MVT_FIXED)) - { - if (mType != type) - { - LL_WARNS() << "Type mismatch in LLMsgVarData::addData for " << mName - << LL_ENDL; - } - } - if(size) - { - delete[] mData; // Delete it if it already exists - mData = new U8[size]; - htolememcpy(mData, data, mType, size); - } + mSize = size; + mDataSize = data_size; + if ( (type != MVT_VARIABLE) && (type != MVT_FIXED) + && (mType != MVT_VARIABLE) && (mType != MVT_FIXED)) + { + if (mType != type) + { + LL_WARNS() << "Type mismatch in LLMsgVarData::addData for " << mName + << LL_ENDL; + } + } + if(size) + { + delete[] mData; // Delete it if it already exists + mData = new U8[size]; + htolememcpy(mData, data, mType, size); + } } void LLMsgData::addDataFast(char *blockname, char *varname, const void *data, S32 size, EMsgVariableType type, S32 data_size) { - // remember that if the blocknumber is > 0 then the number is appended to the name - char *namep = (char *)blockname; - LLMsgBlkData* block_data = mMemberBlocks[namep]; - if (block_data->mBlockNumber) - { - namep += block_data->mBlockNumber; - block_data->addData(varname, data, size, type, data_size); - } - else - { - block_data->addData(varname, data, size, type, data_size); - } + // remember that if the blocknumber is > 0 then the number is appended to the name + char *namep = (char *)blockname; + LLMsgBlkData* block_data = mMemberBlocks[namep]; + if (block_data->mBlockNumber) + { + namep += block_data->mBlockNumber; + block_data->addData(varname, data, size, type, data_size); + } + else + { + block_data->addData(varname, data, size, type, data_size); + } } // LLMessageVariable functions and friends std::ostream& operator<<(std::ostream& s, LLMessageVariable &msg) { - s << "\t\t" << msg.mName << " ("; - switch (msg.mType) - { - case MVT_FIXED: - s << "Fixed, " << msg.mSize << " bytes total)\n"; - break; - case MVT_VARIABLE: - s << "Variable, " << msg.mSize << " bytes of size info)\n"; - break; - default: - s << "Unknown\n"; - break; - } - return s; + s << "\t\t" << msg.mName << " ("; + switch (msg.mType) + { + case MVT_FIXED: + s << "Fixed, " << msg.mSize << " bytes total)\n"; + break; + case MVT_VARIABLE: + s << "Variable, " << msg.mSize << " bytes of size info)\n"; + break; + default: + s << "Unknown\n"; + break; + } + return s; } // LLMessageBlock functions and friends std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg) { - s << "\t" << msg.mName << " ("; - switch (msg.mType) - { - case MBT_SINGLE: - s << "Fixed"; - break; - case MBT_MULTIPLE: - s << "Multiple - " << msg.mNumber << " copies"; - break; - case MBT_VARIABLE: - s << "Variable"; - break; - default: - s << "Unknown"; - break; - } - if (msg.mTotalSize != -1) - { - s << ", " << msg.mTotalSize << " bytes each, " << msg.mNumber*msg.mTotalSize << " bytes total)\n"; - } - else - { - s << ")\n"; - } - - - for (LLMessageBlock::message_variable_map_t::iterator iter = msg.mMemberVariables.begin(); - iter != msg.mMemberVariables.end(); iter++) - { - LLMessageVariable& ci = *(*iter); - s << ci; - } - - return s; + s << "\t" << msg.mName << " ("; + switch (msg.mType) + { + case MBT_SINGLE: + s << "Fixed"; + break; + case MBT_MULTIPLE: + s << "Multiple - " << msg.mNumber << " copies"; + break; + case MBT_VARIABLE: + s << "Variable"; + break; + default: + s << "Unknown"; + break; + } + if (msg.mTotalSize != -1) + { + s << ", " << msg.mTotalSize << " bytes each, " << msg.mNumber*msg.mTotalSize << " bytes total)\n"; + } + else + { + s << ")\n"; + } + + + for (LLMessageBlock::message_variable_map_t::iterator iter = msg.mMemberVariables.begin(); + iter != msg.mMemberVariables.end(); iter++) + { + LLMessageVariable& ci = *(*iter); + s << ci; + } + + return s; } // LLMessageTemplate functions and friends std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg) { - switch (msg.mFrequency) - { - case MFT_HIGH: - s << "========================================\n" << "Message #" << msg.mMessageNumber << "\n" << msg.mName << " ("; - s << "High"; - break; - case MFT_MEDIUM: - s << "========================================\n" << "Message #"; - s << (msg.mMessageNumber & 0xFF) << "\n" << msg.mName << " ("; - s << "Medium"; - break; - case MFT_LOW: - s << "========================================\n" << "Message #"; - s << (msg.mMessageNumber & 0xFFFF) << "\n" << msg.mName << " ("; - s << "Low"; - break; - default: - s << "Unknown"; - break; - } - - if (msg.mTotalSize != -1) - { - s << ", " << msg.mTotalSize << " bytes total)\n"; - } - else - { - s << ")\n"; - } - - for (LLMessageTemplate::message_block_map_t::iterator iter = msg.mMemberBlocks.begin(); - iter != msg.mMemberBlocks.end(); iter++) - { - LLMessageBlock* ci = *iter; - s << *ci; - } - - return s; + switch (msg.mFrequency) + { + case MFT_HIGH: + s << "========================================\n" << "Message #" << msg.mMessageNumber << "\n" << msg.mName << " ("; + s << "High"; + break; + case MFT_MEDIUM: + s << "========================================\n" << "Message #"; + s << (msg.mMessageNumber & 0xFF) << "\n" << msg.mName << " ("; + s << "Medium"; + break; + case MFT_LOW: + s << "========================================\n" << "Message #"; + s << (msg.mMessageNumber & 0xFFFF) << "\n" << msg.mName << " ("; + s << "Low"; + break; + default: + s << "Unknown"; + break; + } + + if (msg.mTotalSize != -1) + { + s << ", " << msg.mTotalSize << " bytes total)\n"; + } + else + { + s << ")\n"; + } + + for (LLMessageTemplate::message_block_map_t::iterator iter = msg.mMemberBlocks.begin(); + iter != msg.mMemberBlocks.end(); iter++) + { + LLMessageBlock* ci = *iter; + s << *ci; + } + + return s; } void LLMessageTemplate::banUdp() { - static const char* deprecation[] = { - "NotDeprecated", - "Deprecated", - "UDPDeprecated", - "UDPBlackListed" - }; - if (mDeprecation != MD_DEPRECATED) - { - LL_INFOS() << "Setting " << mName << " to UDPBlackListed was " << deprecation[mDeprecation] << LL_ENDL; - mDeprecation = MD_UDPBLACKLISTED; - } - else - { - LL_INFOS() << mName << " is already more deprecated than UDPBlackListed" << LL_ENDL; - } + static const char* deprecation[] = { + "NotDeprecated", + "Deprecated", + "UDPDeprecated", + "UDPBlackListed" + }; + if (mDeprecation != MD_DEPRECATED) + { + LL_INFOS() << "Setting " << mName << " to UDPBlackListed was " << deprecation[mDeprecation] << LL_ENDL; + mDeprecation = MD_UDPBLACKLISTED; + } + else + { + LL_INFOS() << mName << " is already more deprecated than UDPBlackListed" << LL_ENDL; + } } diff --git a/indra/llmessage/llmessagetemplate.h b/indra/llmessage/llmessagetemplate.h index 41aca4ab91..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 4b61272454..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/llmessagetemplateparser.h b/indra/llmessage/llmessagetemplateparser.h index 372a2b292d..83ed608429 100644 --- a/indra/llmessage/llmessagetemplateparser.h +++ b/indra/llmessage/llmessagetemplateparser.h @@ -1,25 +1,25 @@ -/** +/** * @file llmessagetemplateparser.h * @brief Classes to parse message template. * * $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$ */ @@ -33,48 +33,48 @@ class LLTemplateTokenizer { public: - LLTemplateTokenizer(const std::string & contents); + LLTemplateTokenizer(const std::string & contents); - U32 line() const; - bool atEOF() const; - std::string next(); + U32 line() const; + bool atEOF() const; + std::string next(); - bool want(const std::string & token); - bool wantEOF(); + bool want(const std::string & token); + bool wantEOF(); private: - void inc(); - void dec(); - std::string get() const; - void error(std::string message = "generic") const; + void inc(); + void dec(); + std::string get() const; + void error(std::string message = "generic") const; - struct positioned_token - { - std::string str; - U32 line; - }; - - bool mStarted; - std::list<positioned_token> mTokens; - std::list<positioned_token>::const_iterator mCurrent; + struct positioned_token + { + std::string str; + U32 line; + }; + + bool mStarted; + std::list<positioned_token> mTokens; + std::list<positioned_token>::const_iterator mCurrent; }; class LLTemplateParser { public: - typedef std::list<LLMessageTemplate *>::const_iterator message_iterator; - - static LLMessageTemplate * parseMessage(LLTemplateTokenizer & tokens); - static LLMessageBlock * parseBlock(LLTemplateTokenizer & tokens); - static LLMessageVariable * parseVariable(LLTemplateTokenizer & tokens); + typedef std::list<LLMessageTemplate *>::const_iterator message_iterator; + + static LLMessageTemplate * parseMessage(LLTemplateTokenizer & tokens); + static LLMessageBlock * parseBlock(LLTemplateTokenizer & tokens); + static LLMessageVariable * parseVariable(LLTemplateTokenizer & tokens); + + LLTemplateParser(LLTemplateTokenizer & tokens); + message_iterator getMessagesBegin() const; + message_iterator getMessagesEnd() const; + F32 getVersion() const; - LLTemplateParser(LLTemplateTokenizer & tokens); - message_iterator getMessagesBegin() const; - message_iterator getMessagesEnd() const; - F32 getVersion() const; - private: - F32 mVersion; - std::list<LLMessageTemplate *> mMessages; + F32 mVersion; + std::list<LLMessageTemplate *> mMessages; }; #endif diff --git a/indra/llmessage/llmessagethrottle.cpp b/indra/llmessage/llmessagethrottle.cpp index bddb9e14d6..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 ae62b43920..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/llmsgvariabletype.h b/indra/llmessage/llmsgvariabletype.h index c4de822b46..74575f3a53 100644 --- a/indra/llmessage/llmsgvariabletype.h +++ b/indra/llmessage/llmsgvariabletype.h @@ -1,25 +1,25 @@ -/** +/** * @file llmsgvariabletype.h * @brief Declaration of the EMsgVariableType enumeration. * * $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$ */ @@ -29,31 +29,31 @@ typedef enum e_message_variable_type { - MVT_NULL, - MVT_FIXED, - MVT_VARIABLE, - MVT_U8, - MVT_U16, - MVT_U32, - MVT_U64, - MVT_S8, - MVT_S16, - MVT_S32, - MVT_S64, - MVT_F32, - MVT_F64, - MVT_LLVector3, - MVT_LLVector3d, - MVT_LLVector4, - MVT_LLQuaternion, - MVT_LLUUID, - MVT_BOOL, - MVT_IP_ADDR, - MVT_IP_PORT, - MVT_U16Vec3, - MVT_U16Quat, - MVT_S16Array, - MVT_EOL + MVT_NULL, + MVT_FIXED, + MVT_VARIABLE, + MVT_U8, + MVT_U16, + MVT_U32, + MVT_U64, + MVT_S8, + MVT_S16, + MVT_S32, + MVT_S64, + MVT_F32, + MVT_F64, + MVT_LLVector3, + MVT_LLVector3d, + MVT_LLVector4, + MVT_LLQuaternion, + MVT_LLUUID, + MVT_BOOL, + MVT_IP_ADDR, + MVT_IP_PORT, + MVT_U16Vec3, + MVT_U16Quat, + MVT_S16Array, + MVT_EOL } EMsgVariableType; #endif // LL_LLMSGVARIABLETYPE_H diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp index 761e990c76..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 92b20284ef..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/llnullcipher.cpp b/indra/llmessage/llnullcipher.cpp index b32e7e6fa6..47230f58d4 100644 --- a/indra/llmessage/llnullcipher.cpp +++ b/indra/llmessage/llnullcipher.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llnullcipher.cpp * @brief Implementation of a cipher which does not encrypt. * * $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$ */ @@ -34,25 +34,25 @@ U32 LLNullCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) { - if((src_len == dst_len) && src && dst) - { - memmove(dst, src, src_len); - return src_len; - } - return 0; + if((src_len == dst_len) && src && dst) + { + memmove(dst, src, src_len); + return src_len; + } + return 0; } U32 LLNullCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) { - if((src_len == dst_len) && src && dst) - { - memmove(dst, src, src_len); - return src_len; - } - return 0; + if((src_len == dst_len) && src && dst) + { + memmove(dst, src, src_len); + return src_len; + } + return 0; } U32 LLNullCipher::requiredEncryptionSpace(U32 len) const { - return len; + return len; } diff --git a/indra/llmessage/llnullcipher.h b/indra/llmessage/llnullcipher.h index a9f9a1ce03..8b397d46cf 100644 --- a/indra/llmessage/llnullcipher.h +++ b/indra/llmessage/llnullcipher.h @@ -1,24 +1,24 @@ -/** +/** * @file llnullcipher.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$ */ @@ -38,11 +38,11 @@ class LLNullCipher : public LLCipher { public: - LLNullCipher() {} - virtual ~LLNullCipher() {} - 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; + LLNullCipher() {} + virtual ~LLNullCipher() {} + 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; }; #endif diff --git a/indra/llmessage/llpacketack.cpp b/indra/llmessage/llpacketack.cpp index 8e04934286..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 76e2e43acb..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/llpacketbuffer.cpp b/indra/llmessage/llpacketbuffer.cpp index ccf991b1a7..dc5c7a73cb 100644 --- a/indra/llmessage/llpacketbuffer.cpp +++ b/indra/llmessage/llpacketbuffer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpacketbuffer.cpp * @brief implementation of LLPacketBuffer 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$ */ @@ -36,27 +36,27 @@ LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32 size) : mHost(host) { - mSize = 0; - mData[0] = '!'; + mSize = 0; + mData[0] = '!'; + + if (size > NET_BUFFER_SIZE) + { + LL_ERRS() << "Sending packet > " << NET_BUFFER_SIZE << " of size " << size << LL_ENDL; + } + else + { + if (datap != NULL) + { + memcpy(mData, datap, size); + mSize = size; + } + } - if (size > NET_BUFFER_SIZE) - { - LL_ERRS() << "Sending packet > " << NET_BUFFER_SIZE << " of size " << size << LL_ENDL; - } - else - { - if (datap != NULL) - { - memcpy(mData, datap, size); - mSize = size; - } - } - } LLPacketBuffer::LLPacketBuffer (S32 hSocket) { - init(hSocket); + init(hSocket); } /////////////////////////////////////////////////////////// @@ -69,8 +69,8 @@ LLPacketBuffer::~LLPacketBuffer () void LLPacketBuffer::init (S32 hSocket) { - mSize = receive_packet(hSocket, mData); - mHost = ::get_sender(); - mReceivingIF = ::get_receiving_interface(); + mSize = receive_packet(hSocket, mData); + mHost = ::get_sender(); + mReceivingIF = ::get_receiving_interface(); } diff --git a/indra/llmessage/llpacketbuffer.h b/indra/llmessage/llpacketbuffer.h index 14b6f9d5d2..a2d2973fb0 100644 --- a/indra/llmessage/llpacketbuffer.h +++ b/indra/llmessage/llpacketbuffer.h @@ -1,4 +1,4 @@ -/** +/** * @file llpacketbuffer.h * @brief definition of LLPacketBuffer class for implementing a * resend, drop, or delay in packet transmissions. @@ -6,21 +6,21 @@ * $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$ */ @@ -28,27 +28,27 @@ #ifndef LL_LLPACKETBUFFER_H #define LL_LLPACKETBUFFER_H -#include "net.h" // for NET_BUFFER_SIZE +#include "net.h" // for NET_BUFFER_SIZE #include "llhost.h" class LLPacketBuffer { public: - LLPacketBuffer(const LLHost &host, const char *datap, const S32 size); - LLPacketBuffer(S32 hSocket); // receive a packet - ~LLPacketBuffer(); + LLPacketBuffer(const LLHost &host, const char *datap, const S32 size); + LLPacketBuffer(S32 hSocket); // receive a packet + ~LLPacketBuffer(); - S32 getSize() const { return mSize; } - const char *getData() const { return mData; } - LLHost getHost() const { return mHost; } - LLHost getReceivingInterface() const { return mReceivingIF; } - void init(S32 hSocket); + S32 getSize() const { return mSize; } + const char *getData() const { return mData; } + LLHost getHost() const { return mHost; } + LLHost getReceivingInterface() const { return mReceivingIF; } + void init(S32 hSocket); protected: - char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */ - S32 mSize; // size of buffer in bytes - LLHost mHost; // source/dest IP and port - LLHost mReceivingIF; // source/dest IP and port + char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */ + S32 mSize; // size of buffer in bytes + LLHost mHost; // source/dest IP and port + LLHost mReceivingIF; // source/dest IP and port }; #endif diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 8e098bfc8c..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 888ee927b5..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 a4852cefba..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 c61e411a23..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/llproxy.cpp b/indra/llmessage/llproxy.cpp index 749e599c66..3e1e5daa02 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, 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$ */ @@ -48,15 +48,15 @@ static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel LLProxy::LLProxy(): - mHTTPProxyEnabled(false), - mProxyMutex(), - mUDPProxy(), - mTCPProxy(), - mHTTPProxy(), - mProxyType(LLPROXY_SOCKS), - mAuthMethodSelected(METHOD_NOAUTH), - mSocksUsername(), - mSocksPassword() + mHTTPProxyEnabled(false), + mProxyMutex(), + mUDPProxy(), + mTCPProxy(), + mHTTPProxy(), + mProxyType(LLPROXY_SOCKS), + mAuthMethodSelected(METHOD_NOAUTH), + mSocksUsername(), + mSocksPassword() {} LLProxy::~LLProxy() @@ -88,112 +88,112 @@ void LLProxy::initSingleton() */ S32 LLProxy::proxyHandshake(LLHost proxy) { - S32 result; - - /* SOCKS 5 Auth request */ - socks_auth_request_t socks_auth_request; - socks_auth_response_t socks_auth_response; - - socks_auth_request.version = SOCKS_VERSION; // SOCKS version 5 - socks_auth_request.num_methods = 1; // Sending 1 method. - socks_auth_request.methods = getSelectedAuthMethod(); // Send only the selected method. - - result = tcp_blocking_handshake(mProxyControlChannel, - static_cast<char*>(static_cast<void*>(&socks_auth_request)), - sizeof(socks_auth_request), - static_cast<char*>(static_cast<void*>(&socks_auth_response)), - sizeof(socks_auth_response)); - if (result != APR_SUCCESS) - { - LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL; - stopSOCKSProxy(); - return SOCKS_CONNECT_ERROR; - } - - if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE) - { - LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods." << LL_ENDL; - stopSOCKSProxy(); - return SOCKS_NOT_ACCEPTABLE; - } - - /* SOCKS 5 USERNAME/PASSWORD authentication */ - if (socks_auth_response.method == METHOD_PASSWORD) - { - // The server has requested a username/password combination - std::string socks_username(getSocksUser()); - std::string socks_password(getSocksPwd()); - U32 request_size = socks_username.size() + socks_password.size() + 3; - char * password_auth = new char[request_size]; - password_auth[0] = 0x01; - password_auth[1] = (char)(socks_username.size()); - memcpy(&password_auth[2], socks_username.c_str(), socks_username.size()); - password_auth[socks_username.size() + 2] = (char)(socks_password.size()); - memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size()); - - authmethod_password_reply_t password_reply; - - result = tcp_blocking_handshake(mProxyControlChannel, - password_auth, - request_size, - static_cast<char*>(static_cast<void*>(&password_reply)), - sizeof(password_reply)); - delete[] password_auth; - - if (result != APR_SUCCESS) - { - LL_WARNS("Proxy") << "SOCKS authentication failed, error on TCP control channel : " << result << LL_ENDL; - stopSOCKSProxy(); - return SOCKS_CONNECT_ERROR; - } - - if (password_reply.status != AUTH_SUCCESS) - { - LL_WARNS("Proxy") << "SOCKS authentication failed" << LL_ENDL; - stopSOCKSProxy(); - return SOCKS_AUTH_FAIL; - } - } - - /* SOCKS5 connect request */ - - socks_command_request_t connect_request; - socks_command_response_t connect_reply; - - connect_request.version = SOCKS_VERSION; // SOCKS V5 - connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP - connect_request.reserved = FIELD_RESERVED; - connect_request.atype = ADDRESS_IPV4; - connect_request.address = htonl(0); // 0.0.0.0 - connect_request.port = htons(0); // 0 - // "If the client is not in possession of the information at the time of the UDP ASSOCIATE, - // the client MUST use a port number and address of all zeros. RFC 1928" - - result = tcp_blocking_handshake(mProxyControlChannel, - static_cast<char*>(static_cast<void*>(&connect_request)), - sizeof(connect_request), - static_cast<char*>(static_cast<void*>(&connect_reply)), - sizeof(connect_reply)); - if (result != APR_SUCCESS) - { - LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL; - stopSOCKSProxy(); - return SOCKS_CONNECT_ERROR; - } - - if (connect_reply.reply != REPLY_REQUEST_GRANTED) - { - LL_WARNS("Proxy") << "Connection to SOCKS 5 server failed, UDP forward request not granted" << LL_ENDL; - stopSOCKSProxy(); - return SOCKS_UDP_FWD_NOT_GRANTED; - } - - mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order - mUDPProxy.setAddress(proxy.getAddress()); - // The connection was successful. We now have the UDP port to send requests that need forwarding to. - LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL; - - return SOCKS_OK; + S32 result; + + /* SOCKS 5 Auth request */ + socks_auth_request_t socks_auth_request; + socks_auth_response_t socks_auth_response; + + socks_auth_request.version = SOCKS_VERSION; // SOCKS version 5 + socks_auth_request.num_methods = 1; // Sending 1 method. + socks_auth_request.methods = getSelectedAuthMethod(); // Send only the selected method. + + result = tcp_blocking_handshake(mProxyControlChannel, + static_cast<char*>(static_cast<void*>(&socks_auth_request)), + sizeof(socks_auth_request), + static_cast<char*>(static_cast<void*>(&socks_auth_response)), + sizeof(socks_auth_response)); + if (result != APR_SUCCESS) + { + LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL; + stopSOCKSProxy(); + return SOCKS_CONNECT_ERROR; + } + + if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE) + { + LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods." << LL_ENDL; + stopSOCKSProxy(); + return SOCKS_NOT_ACCEPTABLE; + } + + /* SOCKS 5 USERNAME/PASSWORD authentication */ + if (socks_auth_response.method == METHOD_PASSWORD) + { + // The server has requested a username/password combination + std::string socks_username(getSocksUser()); + std::string socks_password(getSocksPwd()); + U32 request_size = socks_username.size() + socks_password.size() + 3; + char * password_auth = new char[request_size]; + password_auth[0] = 0x01; + password_auth[1] = (char)(socks_username.size()); + memcpy(&password_auth[2], socks_username.c_str(), socks_username.size()); + password_auth[socks_username.size() + 2] = (char)(socks_password.size()); + memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size()); + + authmethod_password_reply_t password_reply; + + result = tcp_blocking_handshake(mProxyControlChannel, + password_auth, + request_size, + static_cast<char*>(static_cast<void*>(&password_reply)), + sizeof(password_reply)); + delete[] password_auth; + + if (result != APR_SUCCESS) + { + LL_WARNS("Proxy") << "SOCKS authentication failed, error on TCP control channel : " << result << LL_ENDL; + stopSOCKSProxy(); + return SOCKS_CONNECT_ERROR; + } + + if (password_reply.status != AUTH_SUCCESS) + { + LL_WARNS("Proxy") << "SOCKS authentication failed" << LL_ENDL; + stopSOCKSProxy(); + return SOCKS_AUTH_FAIL; + } + } + + /* SOCKS5 connect request */ + + socks_command_request_t connect_request; + socks_command_response_t connect_reply; + + connect_request.version = SOCKS_VERSION; // SOCKS V5 + connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP + connect_request.reserved = FIELD_RESERVED; + connect_request.atype = ADDRESS_IPV4; + connect_request.address = htonl(0); // 0.0.0.0 + connect_request.port = htons(0); // 0 + // "If the client is not in possession of the information at the time of the UDP ASSOCIATE, + // the client MUST use a port number and address of all zeros. RFC 1928" + + result = tcp_blocking_handshake(mProxyControlChannel, + static_cast<char*>(static_cast<void*>(&connect_request)), + sizeof(connect_request), + static_cast<char*>(static_cast<void*>(&connect_reply)), + sizeof(connect_reply)); + if (result != APR_SUCCESS) + { + LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL; + stopSOCKSProxy(); + return SOCKS_CONNECT_ERROR; + } + + if (connect_reply.reply != REPLY_REQUEST_GRANTED) + { + LL_WARNS("Proxy") << "Connection to SOCKS 5 server failed, UDP forward request not granted" << LL_ENDL; + stopSOCKSProxy(); + return SOCKS_UDP_FWD_NOT_GRANTED; + } + + mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order + mUDPProxy.setAddress(proxy.getAddress()); + // The connection was successful. We now have the UDP port to send requests that need forwarding to. + LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL; + + return SOCKS_OK; } /** @@ -209,38 +209,38 @@ S32 LLProxy::proxyHandshake(LLHost proxy) */ S32 LLProxy::startSOCKSProxy(LLHost host) { - if (host.isOk()) - { - mTCPProxy = host; - } - else - { - return SOCKS_INVALID_HOST; - } - - // Close any running SOCKS connection. - stopSOCKSProxy(); - - mProxyControlChannel = tcp_open_channel(mTCPProxy); - if (!mProxyControlChannel) - { - return SOCKS_HOST_CONNECT_FAILED; - } - - S32 status = proxyHandshake(mTCPProxy); - - if (status != SOCKS_OK) - { - // Shut down the proxy if any of the above steps failed. - stopSOCKSProxy(); - } - else - { - // Connection was successful. - sUDPProxyEnabled = true; - } - - return status; + if (host.isOk()) + { + mTCPProxy = host; + } + else + { + return SOCKS_INVALID_HOST; + } + + // Close any running SOCKS connection. + stopSOCKSProxy(); + + mProxyControlChannel = tcp_open_channel(mTCPProxy); + if (!mProxyControlChannel) + { + return SOCKS_HOST_CONNECT_FAILED; + } + + S32 status = proxyHandshake(mTCPProxy); + + if (status != SOCKS_OK) + { + // Shut down the proxy if any of the above steps failed. + stopSOCKSProxy(); + } + else + { + // Connection was successful. + sUDPProxyEnabled = true; + } + + return status; } /** @@ -252,21 +252,21 @@ S32 LLProxy::startSOCKSProxy(LLHost host) */ void LLProxy::stopSOCKSProxy() { - sUDPProxyEnabled = false; + sUDPProxyEnabled = false; - // If the SOCKS proxy is requested to stop and we are using that for HTTP as well - // then we must shut down any HTTP proxy operations. But it is allowable if web - // proxy is being used to continue proxying HTTP. + // If the SOCKS proxy is requested to stop and we are using that for HTTP as well + // then we must shut down any HTTP proxy operations. But it is allowable if web + // proxy is being used to continue proxying HTTP. - if (LLPROXY_SOCKS == getHTTPProxyType()) - { - disableHTTPProxy(); - } + if (LLPROXY_SOCKS == getHTTPProxyType()) + { + disableHTTPProxy(); + } - if (mProxyControlChannel) - { - tcp_close_channel(&mProxyControlChannel); - } + if (mProxyControlChannel) + { + tcp_close_channel(&mProxyControlChannel); + } } /** @@ -274,9 +274,9 @@ void LLProxy::stopSOCKSProxy() */ void LLProxy::setAuthNone() { - LLMutexLock lock(&mProxyMutex); + LLMutexLock lock(&mProxyMutex); - mAuthMethodSelected = METHOD_NOAUTH; + mAuthMethodSelected = METHOD_NOAUTH; } /** @@ -286,27 +286,27 @@ void LLProxy::setAuthNone() * and password conform to the lengths allowed by the * SOCKS protocol. * - * @param username The SOCKS username to send. - * @param password The SOCKS password to send. + * @param username The SOCKS username to send. + * @param password The SOCKS password to send. * @return Return true if applying the settings was successful. No changes are made if false. * */ bool LLProxy::setAuthPassword(const std::string &username, const std::string &password) { - if (username.length() > SOCKSMAXUSERNAMELEN || password.length() > SOCKSMAXPASSWORDLEN || - username.length() < SOCKSMINUSERNAMELEN || password.length() < SOCKSMINPASSWORDLEN) - { - LL_WARNS("Proxy") << "Invalid SOCKS 5 password or username length." << LL_ENDL; - return false; - } + if (username.length() > SOCKSMAXUSERNAMELEN || password.length() > SOCKSMAXPASSWORDLEN || + username.length() < SOCKSMINUSERNAMELEN || password.length() < SOCKSMINPASSWORDLEN) + { + LL_WARNS("Proxy") << "Invalid SOCKS 5 password or username length." << LL_ENDL; + return false; + } - LLMutexLock lock(&mProxyMutex); + LLMutexLock lock(&mProxyMutex); - mAuthMethodSelected = METHOD_PASSWORD; - mSocksUsername = username; - mSocksPassword = password; + mAuthMethodSelected = METHOD_PASSWORD; + mSocksUsername = username; + mSocksPassword = password; - return true; + return true; } /** @@ -320,20 +320,20 @@ bool LLProxy::setAuthPassword(const std::string &username, const std::string &pa */ bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type) { - if (!httpHost.isOk()) - { - LL_WARNS("Proxy") << "Invalid SOCKS 5 Server" << LL_ENDL; - return false; - } + if (!httpHost.isOk()) + { + LL_WARNS("Proxy") << "Invalid SOCKS 5 Server" << LL_ENDL; + return false; + } - LLMutexLock lock(&mProxyMutex); + LLMutexLock lock(&mProxyMutex); - mHTTPProxy = httpHost; - mProxyType = type; + mHTTPProxy = httpHost; + mProxyType = type; - mHTTPProxyEnabled = true; + mHTTPProxyEnabled = true; - return true; + return true; } /** @@ -345,17 +345,17 @@ bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type) */ bool LLProxy::enableHTTPProxy() { - bool ok; + bool ok; - LLMutexLock lock(&mProxyMutex); + LLMutexLock lock(&mProxyMutex); - ok = (mHTTPProxy.isOk()); - if (ok) - { - mHTTPProxyEnabled = true; - } + ok = (mHTTPProxy.isOk()); + if (ok) + { + mHTTPProxyEnabled = true; + } - return ok; + return ok; } /** @@ -363,9 +363,9 @@ bool LLProxy::enableHTTPProxy() */ void LLProxy::disableHTTPProxy() { - LLMutexLock lock(&mProxyMutex); + LLMutexLock lock(&mProxyMutex); - mHTTPProxyEnabled = false; + mHTTPProxyEnabled = false; } /** @@ -373,8 +373,8 @@ void LLProxy::disableHTTPProxy() */ LLHttpProxyType LLProxy::getHTTPProxyType() const { - LLMutexLock lock(&mProxyMutex); - return mProxyType; + LLMutexLock lock(&mProxyMutex); + return mProxyType; } /** @@ -382,8 +382,8 @@ LLHttpProxyType LLProxy::getHTTPProxyType() const */ std::string LLProxy::getSocksPwd() const { - LLMutexLock lock(&mProxyMutex); - return mSocksPassword; + LLMutexLock lock(&mProxyMutex); + return mSocksPassword; } /** @@ -391,8 +391,8 @@ std::string LLProxy::getSocksPwd() const */ std::string LLProxy::getSocksUser() const { - LLMutexLock lock(&mProxyMutex); - return mSocksUsername; + LLMutexLock lock(&mProxyMutex); + return mSocksUsername; } /** @@ -402,8 +402,8 @@ std::string LLProxy::getSocksUser() const */ LLSocks5AuthType LLProxy::getSelectedAuthMethod() const { - LLMutexLock lock(&mProxyMutex); - return mAuthMethodSelected; + LLMutexLock lock(&mProxyMutex); + return mAuthMethodSelected; } /** @@ -434,32 +434,32 @@ void LLProxy::cleanupClass() */ void LLProxy::applyProxySettings(CURL* handle) { - // Do a faster unlocked check to see if we are supposed to proxy. - if (sProxyInstance && sProxyInstance->mHTTPProxyEnabled) - { - // We think we should proxy, lock the proxy mutex. sProxyInstance is not protected by mutex - LLMutexLock lock(&sProxyInstance->mProxyMutex); - // Now test again to verify that the proxy wasn't disabled between the first check and the lock. - if (sProxyInstance->mHTTPProxyEnabled) - { - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, sProxyInstance->mHTTPProxy.getIPString().c_str()), CURLOPT_PROXY); - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, sProxyInstance->mHTTPProxy.getPort()), CURLOPT_PROXYPORT); - - if (sProxyInstance->mProxyType == LLPROXY_SOCKS) - { - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5), CURLOPT_PROXYTYPE); - if (sProxyInstance->mAuthMethodSelected == METHOD_PASSWORD) - { - std::string auth_string = sProxyInstance->mSocksUsername + ":" + sProxyInstance->mSocksPassword; - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()), CURLOPT_PROXYUSERPWD); - } - } - else - { - LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP), CURLOPT_PROXYTYPE); - } - } - } + // Do a faster unlocked check to see if we are supposed to proxy. + if (sProxyInstance && sProxyInstance->mHTTPProxyEnabled) + { + // We think we should proxy, lock the proxy mutex. sProxyInstance is not protected by mutex + LLMutexLock lock(&sProxyInstance->mProxyMutex); + // Now test again to verify that the proxy wasn't disabled between the first check and the lock. + if (sProxyInstance->mHTTPProxyEnabled) + { + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, sProxyInstance->mHTTPProxy.getIPString().c_str()), CURLOPT_PROXY); + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, sProxyInstance->mHTTPProxy.getPort()), CURLOPT_PROXYPORT); + + if (sProxyInstance->mProxyType == LLPROXY_SOCKS) + { + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5), CURLOPT_PROXYTYPE); + if (sProxyInstance->mAuthMethodSelected == METHOD_PASSWORD) + { + std::string auth_string = sProxyInstance->mSocksUsername + ":" + sProxyInstance->mSocksPassword; + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()), CURLOPT_PROXYUSERPWD); + } + } + else + { + LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP), CURLOPT_PROXYTYPE); + } + } + } } /** @@ -468,59 +468,59 @@ void LLProxy::applyProxySettings(CURL* handle) * This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking * operation would impact the operation of the viewer. * - * @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP. - * @param dataout Data to send. - * @param outlen Length of dataout. - * @param datain Buffer for received data. Undefined if return value is not APR_SUCCESS. - * @param maxinlen Maximum possible length of received data. Short reads are allowed. - * @return Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received. + * @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP. + * @param dataout Data to send. + * @param outlen Length of dataout. + * @param datain Buffer for received data. Undefined if return value is not APR_SUCCESS. + * @param maxinlen Maximum possible length of received data. Short reads are allowed. + * @return Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received. */ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen) { - apr_socket_t* apr_socket = handle->getSocket(); - apr_status_t rv = APR_SUCCESS; - - apr_size_t expected_len = outlen; - - handle->setBlocking(1000); - - rv = apr_socket_send(apr_socket, dataout, &outlen); - if (APR_SUCCESS != rv) - { - char buf[MAX_STRING]; - LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL; - ll_apr_warn_status(rv); - } - else if (expected_len != outlen) - { - LL_WARNS("Proxy") << "Incorrect data length sent. Expected: " << expected_len << - " Sent: " << outlen << LL_ENDL; - rv = -1; - } - - ms_sleep(1); - - if (APR_SUCCESS == rv) - { - expected_len = maxinlen; - rv = apr_socket_recv(apr_socket, datain, &maxinlen); - if (rv != APR_SUCCESS) - { - char buf[MAX_STRING]; - LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL; - ll_apr_warn_status(rv); - } - else if (expected_len < maxinlen) - { - LL_WARNS("Proxy") << "Incorrect data length received. Expected: " << expected_len << - " Received: " << maxinlen << LL_ENDL; - rv = -1; - } - } - - handle->setNonBlocking(); - - return rv; + apr_socket_t* apr_socket = handle->getSocket(); + apr_status_t rv = APR_SUCCESS; + + apr_size_t expected_len = outlen; + + handle->setBlocking(1000); + + rv = apr_socket_send(apr_socket, dataout, &outlen); + if (APR_SUCCESS != rv) + { + char buf[MAX_STRING]; + LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL; + ll_apr_warn_status(rv); + } + else if (expected_len != outlen) + { + LL_WARNS("Proxy") << "Incorrect data length sent. Expected: " << expected_len << + " Sent: " << outlen << LL_ENDL; + rv = -1; + } + + ms_sleep(1); + + if (APR_SUCCESS == rv) + { + expected_len = maxinlen; + rv = apr_socket_recv(apr_socket, datain, &maxinlen); + if (rv != APR_SUCCESS) + { + char buf[MAX_STRING]; + LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL; + ll_apr_warn_status(rv); + } + else if (expected_len < maxinlen) + { + LL_WARNS("Proxy") << "Incorrect data length received. Expected: " << expected_len << + " Received: " << maxinlen << LL_ENDL; + rv = -1; + } + } + + handle->setNonBlocking(); + + return rv; } /** @@ -528,19 +528,19 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou * * Checks for a successful connection, and makes sure the connection is closed if it fails. * - * @param host The host to open the connection to. - * @return The created socket. Will evaluate as NULL if the connection is unsuccessful. + * @param host The host to open the connection to. + * @return The created socket. Will evaluate as NULL if the connection is unsuccessful. */ static LLSocket::ptr_t tcp_open_channel(LLHost host) { - LLSocket::ptr_t socket = LLSocket::create(NULL, LLSocket::STREAM_TCP); - bool connected = socket->blockingConnect(host); - if (!connected) - { - tcp_close_channel(&socket); - } - - return socket; + LLSocket::ptr_t socket = LLSocket::create(NULL, LLSocket::STREAM_TCP); + bool connected = socket->blockingConnect(host); + if (!connected) + { + tcp_close_channel(&socket); + } + + return socket; } /** @@ -550,6 +550,6 @@ static LLSocket::ptr_t tcp_open_channel(LLHost host) */ static void tcp_close_channel(LLSocket::ptr_t* handle_ptr) { - LL_DEBUGS("Proxy") << "Resetting proxy LLSocket handle, use_count == " << handle_ptr->use_count() << LL_ENDL; - handle_ptr->reset(); + LL_DEBUGS("Proxy") << "Resetting proxy LLSocket handle, use_count == " << handle_ptr->use_count() << LL_ENDL; + handle_ptr->reset(); } diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index 8a64cdbfaa..10d4911c60 100644 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, 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$ */ @@ -47,7 +47,7 @@ #define SOCKS_INVALID_HOST (-7) #ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */ +#define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */ #endif #define SOCKSMAXUSERNAMELEN 255 @@ -68,8 +68,8 @@ // Lets just use our own ipv4 struct rather than dragging in system // specific headers union ipv4_address_t { - U8 octets[4]; - U32 addr32; + U8 octets[4]; + U32 addr32; }; // SOCKS 5 control channel commands @@ -98,22 +98,22 @@ union ipv4_address_t { // SOCKS 5 command packet struct socks_command_request_t { - U8 version; - U8 command; - U8 reserved; - U8 atype; - U32 address; - U16 port; + U8 version; + U8 command; + U8 reserved; + U8 atype; + U32 address; + U16 port; }; // Standard SOCKS 5 reply packet struct socks_command_response_t { - U8 version; - U8 reply; - U8 reserved; - U8 atype; - U8 add_bytes[4]; - U16 port; + U8 version; + U8 reply; + U8 reserved; + U8 atype; + U8 add_bytes[4]; + U16 port; }; #define AUTH_NOT_ACCEPTABLE 0xFF // reply if preferred methods are not available @@ -121,30 +121,30 @@ struct socks_command_response_t { // SOCKS 5 authentication request, stating which methods the client supports struct socks_auth_request_t { - U8 version; - U8 num_methods; - U8 methods; // We are only using a single method currently + U8 version; + U8 num_methods; + U8 methods; // We are only using a single method currently }; // SOCKS 5 authentication response packet, stating server preferred method struct socks_auth_response_t { - U8 version; - U8 method; + U8 version; + U8 method; }; // SOCKS 5 password reply packet struct authmethod_password_reply_t { - U8 version; - U8 status; + U8 version; + U8 status; }; // SOCKS 5 UDP packet header struct proxywrap_t { - U16 rsv; - U8 frag; - U8 atype; - U32 addr; - U16 port; + U16 rsv; + U8 frag; + U8 atype; + U32 addr; + U16 port; }; #pragma pack(pop) /* restore original alignment from stack */ @@ -153,16 +153,16 @@ struct proxywrap_t { // Currently selected HTTP proxy type enum LLHttpProxyType { - LLPROXY_SOCKS = 0, - LLPROXY_HTTP = 1 + LLPROXY_SOCKS = 0, + LLPROXY_HTTP = 1 }; // Auth types enum LLSocks5AuthType { - METHOD_NOAUTH = 0x00, // Client supports no auth - METHOD_GSSAPI = 0x01, // Client supports GSSAPI (Not currently supported) - METHOD_PASSWORD = 0x02 // Client supports username/password + METHOD_NOAUTH = 0x00, // Client supports no auth + METHOD_GSSAPI = 0x01, // Client supports GSSAPI (Not currently supported) + METHOD_PASSWORD = 0x02 // Client supports username/password }; /** @@ -213,139 +213,139 @@ enum LLSocks5AuthType * * To ensure thread safety, all LLProxy members that relate to the HTTP * proxy require the LLProxyMutex to be locked before accessing. - * + * * *TODO$: This should be moved into the LLCore::Http space. - * + * */ class LLProxy: public LLSingleton<LLProxy> { - /*########################################################################################### - METHODS THAT DO NOT LOCK mProxyMutex! - ###########################################################################################*/ - // Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only. - LLSINGLETON(LLProxy); - LOG_CLASS(LLProxy); + /*########################################################################################### + METHODS THAT DO NOT LOCK mProxyMutex! + ###########################################################################################*/ + // Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only. + LLSINGLETON(LLProxy); + LOG_CLASS(LLProxy); /*virtual*/ void initSingleton() override; public: - // Static check for enabled status for UDP packets. Call from main thread only. - static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; } + // Static check for enabled status for UDP packets. Call from main thread only. + static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; } - // Get the UDP proxy address and port. Call from main thread only. - LLHost getUDPProxy() const { return mUDPProxy; } + // Get the UDP proxy address and port. Call from main thread only. + LLHost getUDPProxy() const { return mUDPProxy; } - /*########################################################################################### - END OF NON-LOCKING METHODS - ###########################################################################################*/ + /*########################################################################################### + END OF NON-LOCKING METHODS + ###########################################################################################*/ - /*########################################################################################### - METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! - ###########################################################################################*/ + /*########################################################################################### + METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! + ###########################################################################################*/ private: - // Destructor, closes open connections. Do not call directly, use cleanupClass(). - ~LLProxy(); + // Destructor, closes open connections. Do not call directly, use cleanupClass(). + ~LLProxy(); public: - // Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be - // destroyed before the call to apr_terminate. Call from main thread only. - static void cleanupClass(); + // Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be + // destroyed before the call to apr_terminate. Call from main thread only. + static void cleanupClass(); - // Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. - // Safe to call from any thread. - static void applyProxySettings(CURL* handle); - // Start a connection to the SOCKS 5 proxy. Call from main thread only. - S32 startSOCKSProxy(LLHost host); + // Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. + // Safe to call from any thread. + static void applyProxySettings(CURL* handle); + // Start a connection to the SOCKS 5 proxy. Call from main thread only. + S32 startSOCKSProxy(LLHost host); - // Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only. - void stopSOCKSProxy(); + // Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only. + void stopSOCKSProxy(); - // Use Password auth when connecting to the SOCKS proxy. Call from main thread only. - bool setAuthPassword(const std::string &username, const std::string &password); + // Use Password auth when connecting to the SOCKS proxy. Call from main thread only. + bool setAuthPassword(const std::string &username, const std::string &password); - // Disable authentication when connecting to the SOCKS proxy. Call from main thread only. - void setAuthNone(); + // Disable authentication when connecting to the SOCKS proxy. Call from main thread only. + void setAuthNone(); - // Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy. - // as specified in type. Call from main thread only. - bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type); - bool enableHTTPProxy(); + // Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy. + // as specified in type. Call from main thread only. + bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type); + bool enableHTTPProxy(); - // Stop proxying HTTP packets. Call from main thread only. - void disableHTTPProxy(); + // Stop proxying HTTP packets. Call from main thread only. + void disableHTTPProxy(); - /*########################################################################################### - END OF LOCKING METHODS - ###########################################################################################*/ + /*########################################################################################### + END OF LOCKING METHODS + ###########################################################################################*/ private: - /*########################################################################################### - METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! - ###########################################################################################*/ + /*########################################################################################### + METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! + ###########################################################################################*/ - // Perform a SOCKS 5 authentication and UDP association with the proxy server. - S32 proxyHandshake(LLHost proxy); + // Perform a SOCKS 5 authentication and UDP association with the proxy server. + S32 proxyHandshake(LLHost proxy); - // Get the currently selected auth method. - LLSocks5AuthType getSelectedAuthMethod() const; + // Get the currently selected auth method. + LLSocks5AuthType getSelectedAuthMethod() const; - // Get the currently selected HTTP proxy type - LLHttpProxyType getHTTPProxyType() const; + // Get the currently selected HTTP proxy type + LLHttpProxyType getHTTPProxyType() const; - std::string getSocksPwd() const; - std::string getSocksUser() const; + std::string getSocksPwd() const; + std::string getSocksUser() const; - /*########################################################################################### - END OF LOCKING METHODS - ###########################################################################################*/ + /*########################################################################################### + END OF LOCKING METHODS + ###########################################################################################*/ private: - // Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly. - // Instead use enableHTTPProxy() and disableHTTPProxy() instead. - mutable LLAtomicBool mHTTPProxyEnabled; + // Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly. + // Instead use enableHTTPProxy() and disableHTTPProxy() instead. + mutable LLAtomicBool mHTTPProxyEnabled; - // Mutex to protect shared members in non-main thread calls to applyProxySettings(). - mutable LLMutex mProxyMutex; + // Mutex to protect shared members in non-main thread calls to applyProxySettings(). + mutable LLMutex mProxyMutex; - /*########################################################################################### - MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! - ###########################################################################################*/ + /*########################################################################################### + MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! + ###########################################################################################*/ - // Is the UDP proxy enabled? - static bool sUDPProxyEnabled; + // Is the UDP proxy enabled? + static bool sUDPProxyEnabled; - // UDP proxy address and port - LLHost mUDPProxy; - // TCP proxy control channel address and port - LLHost mTCPProxy; + // UDP proxy address and port + LLHost mUDPProxy; + // TCP proxy control channel address and port + LLHost mTCPProxy; - // socket handle to proxy TCP control channel - LLSocket::ptr_t mProxyControlChannel; + // socket handle to proxy TCP control channel + LLSocket::ptr_t mProxyControlChannel; - /*########################################################################################### - END OF UNSHARED MEMBERS - ###########################################################################################*/ + /*########################################################################################### + END OF UNSHARED MEMBERS + ###########################################################################################*/ - /*########################################################################################### - MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! - ###########################################################################################*/ + /*########################################################################################### + MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! + ###########################################################################################*/ - // HTTP proxy address and port - LLHost mHTTPProxy; + // HTTP proxy address and port + LLHost mHTTPProxy; - // Currently selected HTTP proxy type. Can be web or socks. - LLHttpProxyType mProxyType; + // Currently selected HTTP proxy type. Can be web or socks. + LLHttpProxyType mProxyType; - // SOCKS 5 selected authentication method. - LLSocks5AuthType mAuthMethodSelected; + // SOCKS 5 selected authentication method. + LLSocks5AuthType mAuthMethodSelected; - // SOCKS 5 username - std::string mSocksUsername; - // SOCKS 5 password - std::string mSocksPassword; + // SOCKS 5 username + std::string mSocksUsername; + // SOCKS 5 password + std::string mSocksPassword; - /*########################################################################################### - END OF SHARED MEMBERS - ###########################################################################################*/ + /*########################################################################################### + END OF SHARED MEMBERS + ###########################################################################################*/ // A hack to get arround getInstance() and capture_dependency() which are unsafe to use inside threads // set/reset on init/cleanup, strictly for use in applyProxySettings diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index 52e6be6f98..646f8aa2ca 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -1,1150 +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 != 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); - } -} +/**
+ * @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/llpumpio.h b/indra/llmessage/llpumpio.h index b9eabee710..67e317ed2d 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -1,4 +1,4 @@ -/** +/** * @file llpumpio.h * @author Phoenix * @date 2004-11-19 @@ -7,21 +7,21 @@ * $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$ */ @@ -45,7 +45,7 @@ extern const F32 DEFAULT_CHAIN_EXPIRY_SECS; extern const F32 SHORT_CHAIN_EXPIRY_SECS; extern const F32 NEVER_CHAIN_EXPIRY_SECS; -/** +/** * @class LLPumpIO * @brief Class to manage sets of io chains. * @@ -73,367 +73,367 @@ extern const F32 NEVER_CHAIN_EXPIRY_SECS; class LLPumpIO { public: - /** - * @brief Constructor. - */ - LLPumpIO(apr_pool_t* pool); - - /** - * @brief Destructor. - */ - ~LLPumpIO(); - - /** - * @brief Prepare this pump for usage. - * - * If you fail to call this method prior to use, the pump will - * try to work, but will not come with any thread locking - * mechanisms. - * @param pool The apr pool to use. - * @return Returns true if the pump is primed. - */ - bool prime(apr_pool_t* pool); - - /** - * @brief Typedef for having a chain of pipes. - */ - typedef std::vector<LLIOPipe::ptr_t> chain_t; - - /** - * @brief Add a chain to this pump and process in the next cycle. - * - * This method will automatically generate a buffer and assign - * each link in the chain as if it were the consumer to the - * previous. - * @param chain The pipes for the chain - * @param timeout The number of seconds in the future to - * expire. Pass in 0.0f to never expire. - * @param has_curl_request The chain contains LLURLRequest if true. - * @return Returns true if anything was added to the pump. - */ - bool addChain(const chain_t& chain, F32 timeout, bool has_curl_request = false); - - /** - * @brief Struct to associate a pipe with it's buffer io indexes. - */ - struct LLLinkInfo - { - LLIOPipe::ptr_t mPipe; - LLChannelDescriptors mChannels; - }; - - /** - * @brief Typedef for having a chain of <code>LLLinkInfo</code> - * instances. - */ - typedef std::vector<LLLinkInfo> links_t; - - /** - * @brief Add a chain to this pump and process in the next cycle. - * - * This method provides a slightly more sophisticated method for - * adding a chain where the caller can specify which link elements - * are on what channels. This method will fail if no buffer is - * provided since any calls to generate new channels for the - * buffers will cause unpredictable interleaving of data. - * @param links The pipes and io indexes for the chain - * @param data Shared pointer to data buffer - * @param context Potentially undefined context meta-data for chain. - * @param timeout The number of seconds in the future to - * expire. Pass in 0.0f to never expire. - * @return Returns true if anything was added to the pump. - */ - bool addChain( - const links_t& links, - LLIOPipe::buffer_ptr_t data, - LLSD context, - F32 timeout); - - /** - * @brief Set or clear a timeout for the running chain - * - * @param timeout The number of seconds in the future to - * expire. Pass in 0.0f to never expire. - * @return Returns true if the timer was set. - */ - bool setTimeoutSeconds(F32 timeout); - - /** - * @brief Adjust the timeout of the running chain. - * - * This method has no effect if there is no timeout on the chain. - * @param delta The number of seconds to add to/remove from the timeout. - */ - void adjustTimeoutSeconds(F32 delta); - - /** - * @brief Set up file descriptors for for the running chain. - * @see rebuildPollset() - * - * There is currently a limit of one conditional per pipe. - * *NOTE: The internal mechanism for building a pollset based on - * pipe/pollfd/chain generates an epoll error on linux (and - * probably behaves similarly on other platforms) because the - * pollset rebuilder will add each apr_pollfd_t serially. This - * does not matter for pipes on the same chain, since any - * signalled pipe will eventually invoke a call to process(), but - * is a problem if the same apr_pollfd_t is on different - * chains. Once we have more than just network i/o on the pump, - * this might matter. - * *FIX: Given the structure of the pump and pipe relationship, - * this should probably go through a different mechanism than the - * pump. I think it would be best if the pipe had some kind of - * controller which was passed into <code>process()</code> rather - * than the pump which exposed this interface. - * @param pipe The pipe which is setting a conditional - * @param poll The entire socket and read/write condition - null to remove - * @return Returns true if the poll state was set. - */ - bool setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll); - - /** - * @brief Lock the current chain. - * @see sleepChain() since it relies on the implementation of this method. - * - * This locks the currently running chain so that no more calls to - * <code>process()</code> until you call <code>clearLock()</code> - * with the lock identifier. - * *FIX: Given the structure of the pump and pipe relationship, - * this should probably go through a different mechanism than the - * pump. I think it would be best if the pipe had some kind of - * controller which was passed into <code>process()</code> rather - * than the pump which exposed this interface. - * @return Returns the lock identifer to be used in - * <code>clearLock()</code> or 0 on failure. - */ - S32 setLock(); - - /** - * @brief Clears the identified lock. - * - * @param links A container for the links which will be appended - */ - void clearLock(S32 key); - - /** - * @brief Stop processing a chain for a while. - * @see setLock() - * - * This method will <em>not</em> update the timeout for this - * chain, so it is possible to sleep the chain until it is - * collected by the pump during a timeout cleanup. - * @param seconds The number of seconds in the future to - * resume processing. - * @return Returns true if the - */ - bool sleepChain(F64 seconds); - - /** - * @brief Copy the currently running chain link info - * - * *FIX: Given the structure of the pump and pipe relationship, - * this should probably go through a different mechanism than the - * pump. I think it would be best if the pipe had some kind of - * controller which was passed into <code>process()</code> rather - * than the pump which exposed this interface. - * @param links A container for the links which will be appended - * @return Returns true if the currently running chain was copied. - */ - bool copyCurrentLinkInfo(links_t& links) const; - - /** - * @brief Call this method to call process on all running chains. - * - * This method iterates through the running chains, and if all - * pipe on a chain are unconditionally ready or if any pipe has - * any conditional processiong condition then process will be - * called on every chain which has requested processing. that - * chain has a file descriptor ready, <code>process()</code> will - * be called for all pipes which have requested it. - */ - void pump(const S32& poll_timeout); - void pump(); - - /** - * @brief Add a chain to a special queue which will be called - * during the next call to <code>callback()</code> and then - * dropped from the queue. - * - * @param chain The IO chain that will get one <code>process()</code>. - */ - //void respond(const chain_t& pipes); - - /** - * @brief Add pipe to a special queue which will be called - * during the next call to <code>callback()</code> and then dropped - * from the queue. - * - * This call will add a single pipe, with no buffer, context, or - * channel information to the callback queue. It will be called - * once, and then dropped. - * @param pipe A single io pipe which will be called - * @return Returns true if anything was added to the pump. - */ - bool respond(LLIOPipe* pipe); - - /** - * @brief Add a chain to a special queue which will be called - * during the next call to <code>callback()</code> and then - * dropped from the queue. - * - * It is important to remember that you should not add a data - * buffer or context which may still be in another chain - that - * will almost certainly lead to a problems. Ensure that you are - * done reading and writing to those parameters, have new - * generated, or empty pointers. - * @param links The pipes and io indexes for the chain - * @param data Shared pointer to data buffer - * @param context Potentially undefined context meta-data for chain. - * @return Returns true if anything was added to the pump. - */ - bool respond( - const links_t& links, - LLIOPipe::buffer_ptr_t data, - LLSD context); - - /** - * @brief Run through the callback queue and call <code>process()</code>. - * - * This call will process all prending responses and call process - * on each. This method will then drop all processed callback - * requests which may lead to deleting the referenced objects. - */ - void callback(); - - /** - * @brief Enumeration to send commands to the pump. - */ - enum EControl - { - PAUSE, - RESUME, - }; - - /** - * @brief Send a command to the pump. - * - * @param op What control to send to the pump. - */ - void control(EControl op); + /** + * @brief Constructor. + */ + LLPumpIO(apr_pool_t* pool); + + /** + * @brief Destructor. + */ + ~LLPumpIO(); + + /** + * @brief Prepare this pump for usage. + * + * If you fail to call this method prior to use, the pump will + * try to work, but will not come with any thread locking + * mechanisms. + * @param pool The apr pool to use. + * @return Returns true if the pump is primed. + */ + bool prime(apr_pool_t* pool); + + /** + * @brief Typedef for having a chain of pipes. + */ + typedef std::vector<LLIOPipe::ptr_t> chain_t; + + /** + * @brief Add a chain to this pump and process in the next cycle. + * + * This method will automatically generate a buffer and assign + * each link in the chain as if it were the consumer to the + * previous. + * @param chain The pipes for the chain + * @param timeout The number of seconds in the future to + * expire. Pass in 0.0f to never expire. + * @param has_curl_request The chain contains LLURLRequest if true. + * @return Returns true if anything was added to the pump. + */ + bool addChain(const chain_t& chain, F32 timeout, bool has_curl_request = false); + + /** + * @brief Struct to associate a pipe with it's buffer io indexes. + */ + struct LLLinkInfo + { + LLIOPipe::ptr_t mPipe; + LLChannelDescriptors mChannels; + }; + + /** + * @brief Typedef for having a chain of <code>LLLinkInfo</code> + * instances. + */ + typedef std::vector<LLLinkInfo> links_t; + + /** + * @brief Add a chain to this pump and process in the next cycle. + * + * This method provides a slightly more sophisticated method for + * adding a chain where the caller can specify which link elements + * are on what channels. This method will fail if no buffer is + * provided since any calls to generate new channels for the + * buffers will cause unpredictable interleaving of data. + * @param links The pipes and io indexes for the chain + * @param data Shared pointer to data buffer + * @param context Potentially undefined context meta-data for chain. + * @param timeout The number of seconds in the future to + * expire. Pass in 0.0f to never expire. + * @return Returns true if anything was added to the pump. + */ + bool addChain( + const links_t& links, + LLIOPipe::buffer_ptr_t data, + LLSD context, + F32 timeout); + + /** + * @brief Set or clear a timeout for the running chain + * + * @param timeout The number of seconds in the future to + * expire. Pass in 0.0f to never expire. + * @return Returns true if the timer was set. + */ + bool setTimeoutSeconds(F32 timeout); + + /** + * @brief Adjust the timeout of the running chain. + * + * This method has no effect if there is no timeout on the chain. + * @param delta The number of seconds to add to/remove from the timeout. + */ + void adjustTimeoutSeconds(F32 delta); + + /** + * @brief Set up file descriptors for for the running chain. + * @see rebuildPollset() + * + * There is currently a limit of one conditional per pipe. + * *NOTE: The internal mechanism for building a pollset based on + * pipe/pollfd/chain generates an epoll error on linux (and + * probably behaves similarly on other platforms) because the + * pollset rebuilder will add each apr_pollfd_t serially. This + * does not matter for pipes on the same chain, since any + * signalled pipe will eventually invoke a call to process(), but + * is a problem if the same apr_pollfd_t is on different + * chains. Once we have more than just network i/o on the pump, + * this might matter. + * *FIX: Given the structure of the pump and pipe relationship, + * this should probably go through a different mechanism than the + * pump. I think it would be best if the pipe had some kind of + * controller which was passed into <code>process()</code> rather + * than the pump which exposed this interface. + * @param pipe The pipe which is setting a conditional + * @param poll The entire socket and read/write condition - null to remove + * @return Returns true if the poll state was set. + */ + bool setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll); + + /** + * @brief Lock the current chain. + * @see sleepChain() since it relies on the implementation of this method. + * + * This locks the currently running chain so that no more calls to + * <code>process()</code> until you call <code>clearLock()</code> + * with the lock identifier. + * *FIX: Given the structure of the pump and pipe relationship, + * this should probably go through a different mechanism than the + * pump. I think it would be best if the pipe had some kind of + * controller which was passed into <code>process()</code> rather + * than the pump which exposed this interface. + * @return Returns the lock identifer to be used in + * <code>clearLock()</code> or 0 on failure. + */ + S32 setLock(); + + /** + * @brief Clears the identified lock. + * + * @param links A container for the links which will be appended + */ + void clearLock(S32 key); + + /** + * @brief Stop processing a chain for a while. + * @see setLock() + * + * This method will <em>not</em> update the timeout for this + * chain, so it is possible to sleep the chain until it is + * collected by the pump during a timeout cleanup. + * @param seconds The number of seconds in the future to + * resume processing. + * @return Returns true if the + */ + bool sleepChain(F64 seconds); + + /** + * @brief Copy the currently running chain link info + * + * *FIX: Given the structure of the pump and pipe relationship, + * this should probably go through a different mechanism than the + * pump. I think it would be best if the pipe had some kind of + * controller which was passed into <code>process()</code> rather + * than the pump which exposed this interface. + * @param links A container for the links which will be appended + * @return Returns true if the currently running chain was copied. + */ + bool copyCurrentLinkInfo(links_t& links) const; + + /** + * @brief Call this method to call process on all running chains. + * + * This method iterates through the running chains, and if all + * pipe on a chain are unconditionally ready or if any pipe has + * any conditional processiong condition then process will be + * called on every chain which has requested processing. that + * chain has a file descriptor ready, <code>process()</code> will + * be called for all pipes which have requested it. + */ + void pump(const S32& poll_timeout); + void pump(); + + /** + * @brief Add a chain to a special queue which will be called + * during the next call to <code>callback()</code> and then + * dropped from the queue. + * + * @param chain The IO chain that will get one <code>process()</code>. + */ + //void respond(const chain_t& pipes); + + /** + * @brief Add pipe to a special queue which will be called + * during the next call to <code>callback()</code> and then dropped + * from the queue. + * + * This call will add a single pipe, with no buffer, context, or + * channel information to the callback queue. It will be called + * once, and then dropped. + * @param pipe A single io pipe which will be called + * @return Returns true if anything was added to the pump. + */ + bool respond(LLIOPipe* pipe); + + /** + * @brief Add a chain to a special queue which will be called + * during the next call to <code>callback()</code> and then + * dropped from the queue. + * + * It is important to remember that you should not add a data + * buffer or context which may still be in another chain - that + * will almost certainly lead to a problems. Ensure that you are + * done reading and writing to those parameters, have new + * generated, or empty pointers. + * @param links The pipes and io indexes for the chain + * @param data Shared pointer to data buffer + * @param context Potentially undefined context meta-data for chain. + * @return Returns true if anything was added to the pump. + */ + bool respond( + const links_t& links, + LLIOPipe::buffer_ptr_t data, + LLSD context); + + /** + * @brief Run through the callback queue and call <code>process()</code>. + * + * This call will process all prending responses and call process + * on each. This method will then drop all processed callback + * requests which may lead to deleting the referenced objects. + */ + void callback(); + + /** + * @brief Enumeration to send commands to the pump. + */ + enum EControl + { + PAUSE, + RESUME, + }; + + /** + * @brief Send a command to the pump. + * + * @param op What control to send to the pump. + */ + void control(EControl op); protected: - /** - * @brief State of the pump - */ - enum EState - { - NORMAL, - PAUSING, - PAUSED - }; - - // instance data - EState mState; - bool mRebuildPollset; - apr_pollset_t* mPollset; - S32 mPollsetClientID; - S32 mNextLock; - std::set<S32> mClearLocks; - - // This is the pump's runnable scheduler used for handling - // expiring locks. - LLRunner mRunner; - - // This structure is the stuff we track while running chains. - struct LLChainInfo - { - // methods - LLChainInfo(); - void setTimeoutSeconds(F32 timeout); - void adjustTimeoutSeconds(F32 delta); - - // basic member data - bool mInit; - bool mEOS; - bool mHasCurlRequest; - S32 mLock; - LLFrameTimer mTimer; - links_t::iterator mHead; - links_t mChainLinks; - LLIOPipe::buffer_ptr_t mData; - LLSD mContext; - - // tracking inside the pump - typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t; - typedef std::vector<pipe_conditional_t> conditionals_t; - conditionals_t mDescriptors; - }; - - // All the running chains & info - typedef std::vector<LLChainInfo> pending_chains_t; - pending_chains_t mPendingChains; - typedef std::list<LLChainInfo> running_chains_t; - running_chains_t mRunningChains; - - typedef running_chains_t::iterator current_chain_t; - current_chain_t mCurrentChain; - - // structures necessary for doing callbacks - // since the callbacks only get one chance to run, we do not have - // to maintain a list. - typedef std::vector<LLChainInfo> callbacks_t; - callbacks_t mPendingCallbacks; - callbacks_t mCallbacks; - - // memory allocator for pollsets & mutexes. - apr_pool_t* mPool; - apr_pool_t* mCurrentPool; - S32 mCurrentPoolReallocCount; + /** + * @brief State of the pump + */ + enum EState + { + NORMAL, + PAUSING, + PAUSED + }; + + // instance data + EState mState; + bool mRebuildPollset; + apr_pollset_t* mPollset; + S32 mPollsetClientID; + S32 mNextLock; + std::set<S32> mClearLocks; + + // This is the pump's runnable scheduler used for handling + // expiring locks. + LLRunner mRunner; + + // This structure is the stuff we track while running chains. + struct LLChainInfo + { + // methods + LLChainInfo(); + void setTimeoutSeconds(F32 timeout); + void adjustTimeoutSeconds(F32 delta); + + // basic member data + bool mInit; + bool mEOS; + bool mHasCurlRequest; + S32 mLock; + LLFrameTimer mTimer; + links_t::iterator mHead; + links_t mChainLinks; + LLIOPipe::buffer_ptr_t mData; + LLSD mContext; + + // tracking inside the pump + typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t; + typedef std::vector<pipe_conditional_t> conditionals_t; + conditionals_t mDescriptors; + }; + + // All the running chains & info + typedef std::vector<LLChainInfo> pending_chains_t; + pending_chains_t mPendingChains; + typedef std::list<LLChainInfo> running_chains_t; + running_chains_t mRunningChains; + + typedef running_chains_t::iterator current_chain_t; + current_chain_t mCurrentChain; + + // structures necessary for doing callbacks + // since the callbacks only get one chance to run, we do not have + // to maintain a list. + typedef std::vector<LLChainInfo> callbacks_t; + callbacks_t mPendingCallbacks; + callbacks_t mCallbacks; + + // memory allocator for pollsets & mutexes. + apr_pool_t* mPool; + apr_pool_t* mCurrentPool; + S32 mCurrentPoolReallocCount; protected: - void initialize(apr_pool_t* pool); - void cleanup(); - current_chain_t removeRunningChain(current_chain_t& chain) ; - /** - * @brief Given the internal state of the chains, rebuild the pollset - * @see setConditional() - */ - void rebuildPollset(); - - /** - * @brief Process the chain passed in. - * - * This method will potentially modify the internals of the - * chain. On end, the chain.mHead will equal - * chain.mChainLinks.end(). - * @param chain The LLChainInfo object to work on. - */ - void processChain(LLChainInfo& chain); - - /** - * @brief Rewind through the chain to try to recover from an error. - * - * This method will potentially modify the internals of the - * chain. - * @param chain The LLChainInfo object to work on. - * @return Retuns true if someone handled the error - */ - bool handleChainError(LLChainInfo& chain, LLIOPipe::EStatus error); - - //if the chain is expired, remove it - bool isChainExpired(LLChainInfo& chain) ; + void initialize(apr_pool_t* pool); + void cleanup(); + current_chain_t removeRunningChain(current_chain_t& chain) ; + /** + * @brief Given the internal state of the chains, rebuild the pollset + * @see setConditional() + */ + void rebuildPollset(); + + /** + * @brief Process the chain passed in. + * + * This method will potentially modify the internals of the + * chain. On end, the chain.mHead will equal + * chain.mChainLinks.end(). + * @param chain The LLChainInfo object to work on. + */ + void processChain(LLChainInfo& chain); + + /** + * @brief Rewind through the chain to try to recover from an error. + * + * This method will potentially modify the internals of the + * chain. + * @param chain The LLChainInfo object to work on. + * @return Retuns true if someone handled the error + */ + bool handleChainError(LLChainInfo& chain, LLIOPipe::EStatus error); + + //if the chain is expired, remove it + bool isChainExpired(LLChainInfo& chain) ; public: - /** - * @brief Return number of running chains. - * - * *NOTE: This is only used in debugging and not considered - * efficient or safe enough for production use. - */ - running_chains_t::size_type runningChains() const - { - return mRunningChains.size(); - } + /** + * @brief Return number of running chains. + * + * *NOTE: This is only used in debugging and not considered + * efficient or safe enough for production use. + */ + running_chains_t::size_type runningChains() const + { + return mRunningChains.size(); + } }; diff --git a/indra/llmessage/llqueryflags.h b/indra/llmessage/llqueryflags.h index 14a62de04f..227d28ba5c 100644 --- a/indra/llmessage/llqueryflags.h +++ b/indra/llmessage/llqueryflags.h @@ -1,25 +1,25 @@ -/** +/** * @file llqueryflags.h * @brief Flags for directory queries * * $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$ */ @@ -30,73 +30,73 @@ // Binary flags used for Find queries, shared between viewer and dataserver. // DirFindQuery flags -const U32 DFQ_PEOPLE = 0x1 << 0; -const U32 DFQ_ONLINE = 0x1 << 1; -//const U32 DFQ_PLACES = 0x1 << 2; -const U32 DFQ_EVENTS = 0x1 << 3; // This is not set by the 1.21 viewer, but I don't know about older versions. JC -const U32 DFQ_GROUPS = 0x1 << 4; -const U32 DFQ_DATE_EVENTS = 0x1 << 5; +const U32 DFQ_PEOPLE = 0x1 << 0; +const U32 DFQ_ONLINE = 0x1 << 1; +//const U32 DFQ_PLACES = 0x1 << 2; +const U32 DFQ_EVENTS = 0x1 << 3; // This is not set by the 1.21 viewer, but I don't know about older versions. JC +const U32 DFQ_GROUPS = 0x1 << 4; +const U32 DFQ_DATE_EVENTS = 0x1 << 5; -const U32 DFQ_AGENT_OWNED = 0x1 << 6; -const U32 DFQ_FOR_SALE = 0x1 << 7; -const U32 DFQ_GROUP_OWNED = 0x1 << 8; -//const U32 DFQ_AUCTION = 0x1 << 9; -const U32 DFQ_DWELL_SORT = 0x1 << 10; -const U32 DFQ_PG_SIMS_ONLY = 0x1 << 11; -const U32 DFQ_PICTURES_ONLY = 0x1 << 12; -const U32 DFQ_PG_EVENTS_ONLY = 0x1 << 13; +const U32 DFQ_AGENT_OWNED = 0x1 << 6; +const U32 DFQ_FOR_SALE = 0x1 << 7; +const U32 DFQ_GROUP_OWNED = 0x1 << 8; +//const U32 DFQ_AUCTION = 0x1 << 9; +const U32 DFQ_DWELL_SORT = 0x1 << 10; +const U32 DFQ_PG_SIMS_ONLY = 0x1 << 11; +const U32 DFQ_PICTURES_ONLY = 0x1 << 12; +const U32 DFQ_PG_EVENTS_ONLY = 0x1 << 13; const U32 DFQ_MATURE_SIMS_ONLY = 0x1 << 14; -const U32 DFQ_SORT_ASC = 0x1 << 15; -const U32 DFQ_PRICE_SORT = 0x1 << 16; -const U32 DFQ_PER_METER_SORT = 0x1 << 17; -const U32 DFQ_AREA_SORT = 0x1 << 18; -const U32 DFQ_NAME_SORT = 0x1 << 19; +const U32 DFQ_SORT_ASC = 0x1 << 15; +const U32 DFQ_PRICE_SORT = 0x1 << 16; +const U32 DFQ_PER_METER_SORT = 0x1 << 17; +const U32 DFQ_AREA_SORT = 0x1 << 18; +const U32 DFQ_NAME_SORT = 0x1 << 19; -const U32 DFQ_LIMIT_BY_PRICE = 0x1 << 20; -const U32 DFQ_LIMIT_BY_AREA = 0x1 << 21; +const U32 DFQ_LIMIT_BY_PRICE = 0x1 << 20; +const U32 DFQ_LIMIT_BY_AREA = 0x1 << 21; -const U32 DFQ_FILTER_MATURE = 0x1 << 22; -const U32 DFQ_PG_PARCELS_ONLY = 0x1 << 23; +const U32 DFQ_FILTER_MATURE = 0x1 << 22; +const U32 DFQ_PG_PARCELS_ONLY = 0x1 << 23; -const U32 DFQ_INC_PG = 0x1 << 24; // Flags appear in 1.23 viewer or later -const U32 DFQ_INC_MATURE = 0x1 << 25; -const U32 DFQ_INC_ADULT = 0x1 << 26; -const U32 DFQ_INC_NEW_VIEWER = (DFQ_INC_PG | DFQ_INC_MATURE | DFQ_INC_ADULT); // Indicates 1.23 viewer or later +const U32 DFQ_INC_PG = 0x1 << 24; // Flags appear in 1.23 viewer or later +const U32 DFQ_INC_MATURE = 0x1 << 25; +const U32 DFQ_INC_ADULT = 0x1 << 26; +const U32 DFQ_INC_NEW_VIEWER = (DFQ_INC_PG | DFQ_INC_MATURE | DFQ_INC_ADULT); // Indicates 1.23 viewer or later -const U32 DFQ_ADULT_SIMS_ONLY = 0x1 << 27; +const U32 DFQ_ADULT_SIMS_ONLY = 0x1 << 27; // Sell Type flags -const U32 ST_AUCTION = 0x1 << 1; -const U32 ST_NEWBIE = 0x1 << 2; -const U32 ST_MAINLAND = 0x1 << 3; -const U32 ST_ESTATE = 0x1 << 4; +const U32 ST_AUCTION = 0x1 << 1; +const U32 ST_NEWBIE = 0x1 << 2; +const U32 ST_MAINLAND = 0x1 << 3; +const U32 ST_ESTATE = 0x1 << 4; -const U32 ST_ALL = 0xFFFFFFFF; +const U32 ST_ALL = 0xFFFFFFFF; // status flags embedded in search replay messages of classifieds, events, groups, and places. // Places -const U32 STATUS_SEARCH_PLACES_NONE = 0x0; -const U32 STATUS_SEARCH_PLACES_BANNEDWORD = 0x1 << 0; -const U32 STATUS_SEARCH_PLACES_SHORTSTRING = 0x1 << 1; -const U32 STATUS_SEARCH_PLACES_FOUNDNONE = 0x1 << 2; -const U32 STATUS_SEARCH_PLACES_SEARCHDISABLED = 0x1 << 3; -const U32 STATUS_SEARCH_PLACES_ESTATEEMPTY = 0x1 << 4; +const U32 STATUS_SEARCH_PLACES_NONE = 0x0; +const U32 STATUS_SEARCH_PLACES_BANNEDWORD = 0x1 << 0; +const U32 STATUS_SEARCH_PLACES_SHORTSTRING = 0x1 << 1; +const U32 STATUS_SEARCH_PLACES_FOUNDNONE = 0x1 << 2; +const U32 STATUS_SEARCH_PLACES_SEARCHDISABLED = 0x1 << 3; +const U32 STATUS_SEARCH_PLACES_ESTATEEMPTY = 0x1 << 4; // Events -const U32 STATUS_SEARCH_EVENTS_NONE = 0x0; -const U32 STATUS_SEARCH_EVENTS_BANNEDWORD = 0x1 << 0; -const U32 STATUS_SEARCH_EVENTS_SHORTSTRING = 0x1 << 1; -const U32 STATUS_SEARCH_EVENTS_FOUNDNONE = 0x1 << 2; -const U32 STATUS_SEARCH_EVENTS_SEARCHDISABLED = 0x1 << 3; -const U32 STATUS_SEARCH_EVENTS_NODATEOFFSET = 0x1 << 4; -const U32 STATUS_SEARCH_EVENTS_NOCATEGORY = 0x1 << 5; -const U32 STATUS_SEARCH_EVENTS_NOQUERY = 0x1 << 6; +const U32 STATUS_SEARCH_EVENTS_NONE = 0x0; +const U32 STATUS_SEARCH_EVENTS_BANNEDWORD = 0x1 << 0; +const U32 STATUS_SEARCH_EVENTS_SHORTSTRING = 0x1 << 1; +const U32 STATUS_SEARCH_EVENTS_FOUNDNONE = 0x1 << 2; +const U32 STATUS_SEARCH_EVENTS_SEARCHDISABLED = 0x1 << 3; +const U32 STATUS_SEARCH_EVENTS_NODATEOFFSET = 0x1 << 4; +const U32 STATUS_SEARCH_EVENTS_NOCATEGORY = 0x1 << 5; +const U32 STATUS_SEARCH_EVENTS_NOQUERY = 0x1 << 6; //Classifieds -const U32 STATUS_SEARCH_CLASSIFIEDS_NONE = 0x0; -const U32 STATUS_SEARCH_CLASSIFIEDS_BANNEDWORD = 0x1 << 0; -const U32 STATUS_SEARCH_CLASSIFIEDS_SHORTSTRING = 0x1 << 1; -const U32 STATUS_SEARCH_CLASSIFIEDS_FOUNDNONE = 0x1 << 2; -const U32 STATUS_SEARCH_CLASSIFIEDS_SEARCHDISABLED = 0x1 << 3; +const U32 STATUS_SEARCH_CLASSIFIEDS_NONE = 0x0; +const U32 STATUS_SEARCH_CLASSIFIEDS_BANNEDWORD = 0x1 << 0; +const U32 STATUS_SEARCH_CLASSIFIEDS_SHORTSTRING = 0x1 << 1; +const U32 STATUS_SEARCH_CLASSIFIEDS_FOUNDNONE = 0x1 << 2; +const U32 STATUS_SEARCH_CLASSIFIEDS_SEARCHDISABLED = 0x1 << 3; #endif diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index ab2d127f6e..835bccfb14 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -1,211 +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_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 - - +/**
+ * @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 284426c148..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/llsdappservices.cpp b/indra/llmessage/llsdappservices.cpp index 4ca45267bd..065bc5196e 100644 --- a/indra/llmessage/llsdappservices.cpp +++ b/indra/llmessage/llsdappservices.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdappservices.cpp * @author Phoenix * @date 2006-09-12 @@ -6,21 +6,21 @@ * $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$ */ @@ -34,244 +34,244 @@ void LLSDAppServices::useServices() { - /* - Having this function body here, causes the classes and globals in this - file to be linked into any program that uses the llmessage library. - */ + /* + Having this function body here, causes the classes and globals in this + file to be linked into any program that uses the llmessage library. + */ } class LLHTTPConfigService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("GET an array of all the options in priority order."); - desc.getAPI(); - desc.source(__FILE__, __LINE__); - } - - virtual LLSD simpleGet() const - { - LLSD result; - LLApp* app = LLApp::instance(); - for(int ii = 0; ii < LLApp::PRIORITY_COUNT; ++ii) - { - result.append(app->getOptionData((LLApp::OptionPriority)ii)); - } - return result; - } + virtual void describe(Description& desc) const + { + desc.shortInfo("GET an array of all the options in priority order."); + desc.getAPI(); + desc.source(__FILE__, __LINE__); + } + + virtual LLSD simpleGet() const + { + LLSD result; + LLApp* app = LLApp::instance(); + for(int ii = 0; ii < LLApp::PRIORITY_COUNT; ++ii) + { + result.append(app->getOptionData((LLApp::OptionPriority)ii)); + } + return result; + } }; LLHTTPRegistration<LLHTTPConfigService> - gHTTPRegistratiAppConfig("/app/config"); + gHTTPRegistratiAppConfig("/app/config"); class LLHTTPConfigRuntimeService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Manipulate a map of runtime-override options."); - desc.getAPI(); - desc.postAPI(); - desc.source(__FILE__, __LINE__); - } - - virtual LLSD simpleGet() const - { - return LLApp::instance()->getOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE); - } + virtual void describe(Description& desc) const + { + desc.shortInfo("Manipulate a map of runtime-override options."); + desc.getAPI(); + desc.postAPI(); + desc.source(__FILE__, __LINE__); + } + + virtual LLSD simpleGet() const + { + return LLApp::instance()->getOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE); + } - virtual void post( - LLHTTPNode::ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLSD result = LLApp::instance()->getOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE); - LLSD::map_const_iterator iter = input.beginMap(); - LLSD::map_const_iterator end = input.endMap(); - for(; iter != end; ++iter) - { - result[(*iter).first] = (*iter).second; - } - LLApp::instance()->setOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE, - result); - response->result(result); - } + virtual void post( + LLHTTPNode::ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLSD result = LLApp::instance()->getOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE); + LLSD::map_const_iterator iter = input.beginMap(); + LLSD::map_const_iterator end = input.endMap(); + for(; iter != end; ++iter) + { + result[(*iter).first] = (*iter).second; + } + LLApp::instance()->setOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE, + result); + response->result(result); + } }; LLHTTPRegistration<LLHTTPConfigRuntimeService> - gHTTPRegistrationRuntimeConfig("/app/config/runtime-override"); + gHTTPRegistrationRuntimeConfig("/app/config/runtime-override"); class LLHTTPConfigRuntimeSingleService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Manipulate a single runtime-override option."); - desc.getAPI(); - desc.putAPI(); - desc.delAPI(); - desc.source(__FILE__, __LINE__); - } - - virtual bool validate(const std::string& name, LLSD& context) const - { - //LL_INFOS() << "validate: " << name << ", " - // << LLSDOStreamer<LLSDNotationFormatter>(context) << LL_ENDL; - if((std::string("PUT") == context[CONTEXT_REQUEST][CONTEXT_VERB].asString()) && !name.empty()) - { - return true; - } - else - { - // This is for GET and DELETE - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE); - if(options.has(name)) return true; - else return false; - } - } + virtual void describe(Description& desc) const + { + desc.shortInfo("Manipulate a single runtime-override option."); + desc.getAPI(); + desc.putAPI(); + desc.delAPI(); + desc.source(__FILE__, __LINE__); + } + + virtual bool validate(const std::string& name, LLSD& context) const + { + //LL_INFOS() << "validate: " << name << ", " + // << LLSDOStreamer<LLSDNotationFormatter>(context) << LL_ENDL; + if((std::string("PUT") == context[CONTEXT_REQUEST][CONTEXT_VERB].asString()) && !name.empty()) + { + return true; + } + else + { + // This is for GET and DELETE + LLSD options = LLApp::instance()->getOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE); + if(options.has(name)) return true; + else return false; + } + } - virtual void get( - LLHTTPNode::ResponsePtr response, - const LLSD& context) const - { - std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE); - response->result(options[name]); - } + virtual void get( + LLHTTPNode::ResponsePtr response, + const LLSD& context) const + { + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; + LLSD options = LLApp::instance()->getOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE); + response->result(options[name]); + } - virtual void put( - LLHTTPNode::ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE); - options[name] = input; - LLApp::instance()->setOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE, - options); - response->result(input); - } + virtual void put( + LLHTTPNode::ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; + LLSD options = LLApp::instance()->getOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE); + options[name] = input; + LLApp::instance()->setOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE, + options); + response->result(input); + } - virtual void del( - LLHTTPNode::ResponsePtr response, - const LLSD& context) const - { - std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE); - options.erase(name); - LLApp::instance()->setOptionData( - LLApp::PRIORITY_RUNTIME_OVERRIDE, - options); - response->result(LLSD()); - } + virtual void del( + LLHTTPNode::ResponsePtr response, + const LLSD& context) const + { + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; + LLSD options = LLApp::instance()->getOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE); + options.erase(name); + LLApp::instance()->setOptionData( + LLApp::PRIORITY_RUNTIME_OVERRIDE, + options); + response->result(LLSD()); + } }; LLHTTPRegistration<LLHTTPConfigRuntimeSingleService> - gHTTPRegistrationRuntimeSingleConfig( - "/app/config/runtime-override/<option-name>"); + gHTTPRegistrationRuntimeSingleConfig( + "/app/config/runtime-override/<option-name>"); template<int PRIORITY> class LLHTTPConfigPriorityService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Get a map of the options at this priority."); - desc.getAPI(); - desc.source(__FILE__, __LINE__); - } + virtual void describe(Description& desc) const + { + desc.shortInfo("Get a map of the options at this priority."); + desc.getAPI(); + desc.source(__FILE__, __LINE__); + } - virtual void get( - LLHTTPNode::ResponsePtr response, - const LLSD& context) const - { - response->result(LLApp::instance()->getOptionData( - (LLApp::OptionPriority)PRIORITY)); - } + virtual void get( + LLHTTPNode::ResponsePtr response, + const LLSD& context) const + { + response->result(LLApp::instance()->getOptionData( + (LLApp::OptionPriority)PRIORITY)); + } }; LLHTTPRegistration< LLHTTPConfigPriorityService<LLApp::PRIORITY_COMMAND_LINE> > - gHTTPRegistrationCommandLineConfig("/app/config/command-line"); + gHTTPRegistrationCommandLineConfig("/app/config/command-line"); LLHTTPRegistration< - LLHTTPConfigPriorityService<LLApp::PRIORITY_SPECIFIC_CONFIGURATION> > - gHTTPRegistrationSpecificConfig("/app/config/specific"); + LLHTTPConfigPriorityService<LLApp::PRIORITY_SPECIFIC_CONFIGURATION> > + gHTTPRegistrationSpecificConfig("/app/config/specific"); LLHTTPRegistration< - LLHTTPConfigPriorityService<LLApp::PRIORITY_GENERAL_CONFIGURATION> > - gHTTPRegistrationGeneralConfig("/app/config/general"); + LLHTTPConfigPriorityService<LLApp::PRIORITY_GENERAL_CONFIGURATION> > + gHTTPRegistrationGeneralConfig("/app/config/general"); LLHTTPRegistration< LLHTTPConfigPriorityService<LLApp::PRIORITY_DEFAULT> > - gHTTPRegistrationDefaultConfig("/app/config/default"); + gHTTPRegistrationDefaultConfig("/app/config/default"); class LLHTTPLiveConfigService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Get a map of the currently live options."); - desc.getAPI(); - desc.source(__FILE__, __LINE__); - } + virtual void describe(Description& desc) const + { + desc.shortInfo("Get a map of the currently live options."); + desc.getAPI(); + desc.source(__FILE__, __LINE__); + } - virtual void get( - LLHTTPNode::ResponsePtr response, - const LLSD& context) const - { - LLSD result; - LLApp* app = LLApp::instance(); - LLSD::map_const_iterator iter; - LLSD::map_const_iterator end; - for(int ii = LLApp::PRIORITY_COUNT - 1; ii >= 0; --ii) - { - LLSD options = app->getOptionData((LLApp::OptionPriority)ii); - iter = options.beginMap(); - end = options.endMap(); - for(; iter != end; ++iter) - { - result[(*iter).first] = (*iter).second; - } - } - response->result(result); - } + virtual void get( + LLHTTPNode::ResponsePtr response, + const LLSD& context) const + { + LLSD result; + LLApp* app = LLApp::instance(); + LLSD::map_const_iterator iter; + LLSD::map_const_iterator end; + for(int ii = LLApp::PRIORITY_COUNT - 1; ii >= 0; --ii) + { + LLSD options = app->getOptionData((LLApp::OptionPriority)ii); + iter = options.beginMap(); + end = options.endMap(); + for(; iter != end; ++iter) + { + result[(*iter).first] = (*iter).second; + } + } + response->result(result); + } }; LLHTTPRegistration<LLHTTPLiveConfigService> - gHTTPRegistrationLiveConfig("/app/config/live"); + gHTTPRegistrationLiveConfig("/app/config/live"); class LLHTTPLiveConfigSingleService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Get the named live option."); - desc.getAPI(); - desc.source(__FILE__, __LINE__); - } + virtual void describe(Description& desc) const + { + desc.shortInfo("Get the named live option."); + desc.getAPI(); + desc.source(__FILE__, __LINE__); + } - virtual bool validate(const std::string& name, LLSD& context) const - { - LL_INFOS() << "LLHTTPLiveConfigSingleService::validate(" << name - << ")" << LL_ENDL; - LLSD option = LLApp::instance()->getOption(name); - if(option.isDefined()) return true; - else return false; - } + virtual bool validate(const std::string& name, LLSD& context) const + { + LL_INFOS() << "LLHTTPLiveConfigSingleService::validate(" << name + << ")" << LL_ENDL; + LLSD option = LLApp::instance()->getOption(name); + if(option.isDefined()) return true; + else return false; + } - virtual void get( - LLHTTPNode::ResponsePtr response, - const LLSD& context) const - { - std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; - response->result(LLApp::instance()->getOption(name)); - } + virtual void get( + LLHTTPNode::ResponsePtr response, + const LLSD& context) const + { + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; + response->result(LLApp::instance()->getOption(name)); + } }; LLHTTPRegistration<LLHTTPLiveConfigSingleService> - gHTTPRegistrationLiveSingleConfig("/app/config/live/<option-name>"); + gHTTPRegistrationLiveSingleConfig("/app/config/live/<option-name>"); diff --git a/indra/llmessage/llsdappservices.h b/indra/llmessage/llsdappservices.h index e76e20cea9..6b3b7c0da3 100644 --- a/indra/llmessage/llsdappservices.h +++ b/indra/llmessage/llsdappservices.h @@ -1,4 +1,4 @@ -/** +/** * @file llsdappservices.h * @author Phoenix * @date 2006-09-12 @@ -7,21 +7,21 @@ * $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$ */ @@ -29,7 +29,7 @@ #ifndef LL_LLSDAPPSERVICES_H #define LL_LLSDAPPSERVICES_H -/** +/** * @class LLSDAppServices * @brief This class forces a link to llsdappservices if the static * method is called which declares the /app web services. @@ -37,21 +37,21 @@ class LLSDAppServices { public: - /** - * @brief Call this method to declare the /app common web services. - * - * This will register: - * /app/config - * /app/config/runtime-override - * /app/config/runtime-override/<option-name> - * /app/config/command-line - * /app/config/specific - * /app/config/general - * /app/config/default - * /app/config/live - * /app/config/live/<option-name> - */ - static void useServices(); + /** + * @brief Call this method to declare the /app common web services. + * + * This will register: + * /app/config + * /app/config/runtime-override + * /app/config/runtime-override/<option-name> + * /app/config/command-line + * /app/config/specific + * /app/config/general + * /app/config/default + * /app/config/live + * /app/config/live/<option-name> + */ + static void useServices(); }; diff --git a/indra/llmessage/llsdhttpserver.cpp b/indra/llmessage/llsdhttpserver.cpp index 8ac6b3cb12..35f3a45ed6 100644 --- a/indra/llmessage/llsdhttpserver.cpp +++ b/indra/llmessage/llsdhttpserver.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsdhttpserver.cpp * @brief Standard LLSD services * * $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$ */ @@ -29,7 +29,7 @@ #include "llhttpnode.h" -/** +/** * This module implements common services that should be included * in all server URL trees. These services facilitate debugging and * introsepction. @@ -37,10 +37,10 @@ void LLHTTPStandardServices::useServices() { - /* - Having this function body here, causes the classes and globals in this - file to be linked into any program that uses the llmessage library. - */ + /* + Having this function body here, causes the classes and globals in this + file to be linked into any program that uses the llmessage library. + */ } @@ -48,103 +48,103 @@ void LLHTTPStandardServices::useServices() class LLHTTPHelloService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("says hello"); - desc.getAPI(); - desc.output("\"hello\""); - desc.source(__FILE__, __LINE__); - } - - virtual LLSD simpleGet() const - { - LLSD result = "hello"; - return result; - } + virtual void describe(Description& desc) const + { + desc.shortInfo("says hello"); + desc.getAPI(); + desc.output("\"hello\""); + desc.source(__FILE__, __LINE__); + } + + virtual LLSD simpleGet() const + { + LLSD result = "hello"; + return result; + } }; LLHTTPRegistration<LLHTTPHelloService> - gHTTPRegistrationWebHello("/web/hello"); + gHTTPRegistrationWebHello("/web/hello"); class LLHTTPEchoService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("echo input"); - desc.postAPI(); - desc.input("<any>"); - desc.output("<the input>"); - desc.source(__FILE__, __LINE__); - } - - virtual LLSD simplePost(const LLSD& params) const - { - return params; - } + virtual void describe(Description& desc) const + { + desc.shortInfo("echo input"); + desc.postAPI(); + desc.input("<any>"); + desc.output("<the input>"); + desc.source(__FILE__, __LINE__); + } + + virtual LLSD simplePost(const LLSD& params) const + { + return params; + } }; LLHTTPRegistration<LLHTTPEchoService> - gHTTPRegistrationWebEcho("/web/echo"); + gHTTPRegistrationWebEcho("/web/echo"); class LLAPIService : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("information about the URLs this server supports"); - desc.getAPI(); - desc.output("a list of URLs supported"); - desc.source(__FILE__, __LINE__); - } - - virtual bool handles(const LLSD& remainder, LLSD& context) const - { - return followRemainder(remainder) != NULL; - } + virtual void describe(Description& desc) const + { + desc.shortInfo("information about the URLs this server supports"); + desc.getAPI(); + desc.output("a list of URLs supported"); + desc.source(__FILE__, __LINE__); + } + + virtual bool handles(const LLSD& remainder, LLSD& context) const + { + return followRemainder(remainder) != NULL; + } virtual void get(ResponsePtr response, const LLSD& context) const - { - const LLSD& remainder = context[CONTEXT_REQUEST]["remainder"]; - - if (remainder.size() > 0) - { - const LLHTTPNode* node = followRemainder(remainder); - if (!node) - { - response->notFound(); - return; - } - - Description desc; - node->describe(desc); - response->result(desc.getInfo()); - return; - } - - response->result(rootNode()->allNodePaths()); - } + { + const LLSD& remainder = context[CONTEXT_REQUEST]["remainder"]; + + if (remainder.size() > 0) + { + const LLHTTPNode* node = followRemainder(remainder); + if (!node) + { + response->notFound(); + return; + } + + Description desc; + node->describe(desc); + response->result(desc.getInfo()); + return; + } + + response->result(rootNode()->allNodePaths()); + } private: - const LLHTTPNode* followRemainder(const LLSD& remainder) const - { - const LLHTTPNode* node = rootNode(); - - LLSD::array_const_iterator i = remainder.beginArray(); - LLSD::array_const_iterator end = remainder.endArray(); - for (; node && i != end; ++i) - { - node = node->findNode(*i); - } - - return node; - } + const LLHTTPNode* followRemainder(const LLSD& remainder) const + { + const LLHTTPNode* node = rootNode(); + + LLSD::array_const_iterator i = remainder.beginArray(); + LLSD::array_const_iterator end = remainder.endArray(); + for (; node && i != end; ++i) + { + node = node->findNode(*i); + } + + return node; + } }; LLHTTPRegistration<LLAPIService> - gHTTPRegistrationWebServerApi("/web/server/api"); + gHTTPRegistrationWebServerApi("/web/server/api"); diff --git a/indra/llmessage/llsdhttpserver.h b/indra/llmessage/llsdhttpserver.h index 39f9204604..5d748ec73c 100644 --- a/indra/llmessage/llsdhttpserver.h +++ b/indra/llmessage/llsdhttpserver.h @@ -1,25 +1,25 @@ -/** +/** * @file llsdhttpserver.h * @brief Standard LLSD services * * $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$ */ @@ -27,7 +27,7 @@ #ifndef LL_LLSDHTTPSERVER_H #define LL_LLSDHTTPSERVER_H -/** +/** * This module implements and defines common services that should be included * in all server URL trees. These services facilitate debugging and * introsepction. @@ -36,16 +36,16 @@ class LLHTTPStandardServices { public: - static void useServices(); - /**< - Having a call to this function causes the following services to be - registered: - /web/echo -- echo input - /web/hello -- return "hello" - /web/server/api -- return a list of url paths on the server - /web/server/api/<..path..> - -- return description of the path - */ + static void useServices(); + /**< + Having a call to this function causes the following services to be + registered: + /web/echo -- echo input + /web/hello -- return "hello" + /web/server/api -- return a list of url paths on the server + /web/server/api/<..path..> + -- return description of the path + */ }; #endif // LL_LLSDHTTPSERVER_H diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp index 309cf53bef..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; -} - -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 2c728977ca..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 d533d6535b..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 4119de6009..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/llservice.cpp b/indra/llmessage/llservice.cpp index ddcc13d969..47027dcfce 100644 --- a/indra/llmessage/llservice.cpp +++ b/indra/llmessage/llservice.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llservice.cpp * @author Phoenix * @date 2005-04-20 @@ -6,21 +6,21 @@ * $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$ */ @@ -41,71 +41,71 @@ LLService::~LLService() // static bool LLService::registerCreator(const std::string& name, creator_t fn) { - LL_INFOS() << "LLService::registerCreator(" << name << ")" << LL_ENDL; - if(name.empty()) - { - return false; - } + LL_INFOS() << "LLService::registerCreator(" << name << ")" << LL_ENDL; + if(name.empty()) + { + return false; + } - creators_t::value_type vt(name, fn); - std::pair<creators_t::iterator, bool> rv = sCreatorFunctors.insert(vt); - return rv.second; + creators_t::value_type vt(name, fn); + std::pair<creators_t::iterator, bool> rv = sCreatorFunctors.insert(vt); + return rv.second; - // alternately... - //std::string name_str(name); - //sCreatorFunctors[name_str] = fn; + // alternately... + //std::string name_str(name); + //sCreatorFunctors[name_str] = fn; } // static LLIOPipe* LLService::activate( - const std::string& name, - LLPumpIO::chain_t& chain, - LLSD context) + const std::string& name, + LLPumpIO::chain_t& chain, + LLSD context) { - if(name.empty()) - { - LL_INFOS() << "LLService::activate - no service specified." << LL_ENDL; - return NULL; - } - creators_t::iterator it = sCreatorFunctors.find(name); - LLIOPipe* rv = NULL; - if(it != sCreatorFunctors.end()) - { - if((*it).second->build(chain, context)) - { - rv = chain[0].get(); - } - else - { - // empty out the chain, because failed service creation - // should just discard this stuff. - LL_WARNS() << "LLService::activate - unable to build chain: " << name - << LL_ENDL; - chain.clear(); - } - } - else - { - LL_WARNS() << "LLService::activate - unable find factory: " << name - << LL_ENDL; - } - return rv; + if(name.empty()) + { + LL_INFOS() << "LLService::activate - no service specified." << LL_ENDL; + return NULL; + } + creators_t::iterator it = sCreatorFunctors.find(name); + LLIOPipe* rv = NULL; + if(it != sCreatorFunctors.end()) + { + if((*it).second->build(chain, context)) + { + rv = chain[0].get(); + } + else + { + // empty out the chain, because failed service creation + // should just discard this stuff. + LL_WARNS() << "LLService::activate - unable to build chain: " << name + << LL_ENDL; + chain.clear(); + } + } + else + { + LL_WARNS() << "LLService::activate - unable find factory: " << name + << LL_ENDL; + } + return rv; } // static bool LLService::discard(const std::string& name) { - if(name.empty()) - { - return false; - } - creators_t::iterator it = sCreatorFunctors.find(name); - if(it != sCreatorFunctors.end()) - { - //(*it).second->discard(); - sCreatorFunctors.erase(it); - return true; - } - return false; + if(name.empty()) + { + return false; + } + creators_t::iterator it = sCreatorFunctors.find(name); + if(it != sCreatorFunctors.end()) + { + //(*it).second->discard(); + sCreatorFunctors.erase(it); + return true; + } + return false; } diff --git a/indra/llmessage/llservice.h b/indra/llmessage/llservice.h index f215acab56..6c32fa8102 100644 --- a/indra/llmessage/llservice.h +++ b/indra/llmessage/llservice.h @@ -1,4 +1,4 @@ -/** +/** * @file llservice.h * @author Phoenix * @date 2004-11-21 @@ -7,21 +7,21 @@ * $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$ */ @@ -45,12 +45,12 @@ class LLServiceCreator; */ namespace boost { - void intrusive_ptr_add_ref(LLServiceCreator* p); - void intrusive_ptr_release(LLServiceCreator* p); + void intrusive_ptr_add_ref(LLServiceCreator* p); + void intrusive_ptr_release(LLServiceCreator* p); }; #endif -/** +/** * @class LLServiceCreator * @brief This class is an abstract base class for classes which create * new <code>LLService</code> instances. @@ -63,41 +63,41 @@ namespace boost class LLServiceCreator { public: - typedef boost::intrusive_ptr<LLService> service_t; - virtual ~LLServiceCreator() {} - virtual service_t activate() = 0; - virtual void discard() = 0; + typedef boost::intrusive_ptr<LLService> service_t; + virtual ~LLServiceCreator() {} + virtual service_t activate() = 0; + virtual void discard() = 0; protected: - LLServiceCreator() : mReferenceCount(0) - { - } + LLServiceCreator() : mReferenceCount(0) + { + } private: - friend void boost::intrusive_ptr_add_ref(LLServiceCreator* p); - friend void boost::intrusive_ptr_release(LLServiceCreator* p); - U32 mReferenceCount; + friend void boost::intrusive_ptr_add_ref(LLServiceCreator* p); + friend void boost::intrusive_ptr_release(LLServiceCreator* p); + U32 mReferenceCount; }; #endif #if 0 namespace boost { - inline void intrusive_ptr_add_ref(LLServiceCreator* p) - { - ++p->mReferenceCount; - } - inline void intrusive_ptr_release(LLServiceCreator* p) - { - if(p && 0 == --p->mReferenceCount) - { - delete p; - } - } + inline void intrusive_ptr_add_ref(LLServiceCreator* p) + { + ++p->mReferenceCount; + } + inline void intrusive_ptr_release(LLServiceCreator* p) + { + if(p && 0 == --p->mReferenceCount) + { + delete p; + } + } }; #endif -/** +/** * @class LLService * @brief This class is the base class for the service classes. * @see LLIOPipe @@ -114,71 +114,71 @@ namespace boost class LLService : public LLIOPipe { public: - //typedef boost::intrusive_ptr<LLServiceCreator> creator_t; - //typedef boost::intrusive_ptr<LLService> service_t; - typedef std::shared_ptr<LLChainIOFactory> creator_t; - - /** - * @brief This method is used to register a protocol name with a - * a functor that creates the service. - * - * THOROUGH_DESCRIPTION - * @param aParameter A brief description of aParameter. - * @return Returns true if a service was successfully registered. - */ - static bool registerCreator(const std::string& name, creator_t fn); - - /** - * @brief This method connects to a service by name. - * - * @param name The name of the service to connect to. - * @param chain The constructed chain including the service instance. - * @param context Context for the activation. - * @return An instance of the service for use or NULL on failure. - */ - static LLIOPipe* activate( - const std::string& name, - LLPumpIO::chain_t& chain, - LLSD context); - - /** - * @brief - * - * @param name The name of the service to discard. - * @return true if service creator was found and discarded. - */ - static bool discard(const std::string& name); + //typedef boost::intrusive_ptr<LLServiceCreator> creator_t; + //typedef boost::intrusive_ptr<LLService> service_t; + typedef std::shared_ptr<LLChainIOFactory> creator_t; + + /** + * @brief This method is used to register a protocol name with a + * a functor that creates the service. + * + * THOROUGH_DESCRIPTION + * @param aParameter A brief description of aParameter. + * @return Returns true if a service was successfully registered. + */ + static bool registerCreator(const std::string& name, creator_t fn); + + /** + * @brief This method connects to a service by name. + * + * @param name The name of the service to connect to. + * @param chain The constructed chain including the service instance. + * @param context Context for the activation. + * @return An instance of the service for use or NULL on failure. + */ + static LLIOPipe* activate( + const std::string& name, + LLPumpIO::chain_t& chain, + LLSD context); + + /** + * @brief + * + * @param name The name of the service to discard. + * @return true if service creator was found and discarded. + */ + static bool discard(const std::string& name); protected: - // The creation factory static data. - typedef std::map<std::string, creator_t> creators_t; - static creators_t sCreatorFunctors; + // The creation factory static data. + typedef std::map<std::string, creator_t> creators_t; + static creators_t sCreatorFunctors; protected: - // construction & destruction. since this class is an abstract - // base class, it is up to Service implementations to actually - // deal with construction and not a public method. How that - // construction takes place will be handled by the service - // creators. - LLService(); - virtual ~LLService(); + // construction & destruction. since this class is an abstract + // base class, it is up to Service implementations to actually + // deal with construction and not a public method. How that + // construction takes place will be handled by the service + // creators. + LLService(); + virtual ~LLService(); protected: - // This frame timer records how long this service has - // existed. Useful for derived services to give themselves a - // lifetime and expiration. - // *NOTE: Phoenix - This functionaity has been moved to the - // pump. 2005-12-13 - //LLFrameTimer mTimer; - - // Since services are designed in an 'ask now, respond later' - // idiom which probably crosses thread boundaries, almost all - // services will need a handle to a response pipe. It will usually - // be the job of the service author to derive a useful - // implementation of response, and up to the service subscriber to - // further derive that class to do something useful when the - // response comes in. - LLIOPipe::ptr_t mResponse; + // This frame timer records how long this service has + // existed. Useful for derived services to give themselves a + // lifetime and expiration. + // *NOTE: Phoenix - This functionaity has been moved to the + // pump. 2005-12-13 + //LLFrameTimer mTimer; + + // Since services are designed in an 'ask now, respond later' + // idiom which probably crosses thread boundaries, almost all + // services will need a handle to a response pipe. It will usually + // be the job of the service author to derive a useful + // implementation of response, and up to the service subscriber to + // further derive that class to do something useful when the + // response comes in. + LLIOPipe::ptr_t mResponse; }; diff --git a/indra/llmessage/llservicebuilder.cpp b/indra/llmessage/llservicebuilder.cpp index cf2e42f95c..7dc49d5455 100644 --- a/indra/llmessage/llservicebuilder.cpp +++ b/indra/llmessage/llservicebuilder.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llservicebuilder.cpp * @brief Implementation of the LLServiceBuilder 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$ */ @@ -32,205 +32,205 @@ #include "llsdserialize.h" void LLServiceBuilder::loadServiceDefinitionsFromFile( - const std::string& service_filename) + const std::string& service_filename) { - llifstream service_file(service_filename.c_str(), std::ios::binary); - if(service_file.is_open()) - { - LLSD service_data; - LLSDSerialize::fromXMLDocument(service_data, service_file); - service_file.close(); - // Load service - LLSD service_map = service_data["services"]; - for(LLSD::array_iterator array_itr = service_map.beginArray(); - array_itr != service_map.endArray(); - ++array_itr) - { - LLSD service_llsd = (*array_itr)["service-builder"]; - std::string service_name = (*array_itr)["name"].asString(); - createServiceDefinition(service_name, service_llsd); - } - LL_INFOS() << "loaded config file: " << service_filename << LL_ENDL; - } - else - { - LL_WARNS() << "unable to find config file: " << service_filename << LL_ENDL; - } + llifstream service_file(service_filename.c_str(), std::ios::binary); + if(service_file.is_open()) + { + LLSD service_data; + LLSDSerialize::fromXMLDocument(service_data, service_file); + service_file.close(); + // Load service + LLSD service_map = service_data["services"]; + for(LLSD::array_iterator array_itr = service_map.beginArray(); + array_itr != service_map.endArray(); + ++array_itr) + { + LLSD service_llsd = (*array_itr)["service-builder"]; + std::string service_name = (*array_itr)["name"].asString(); + createServiceDefinition(service_name, service_llsd); + } + LL_INFOS() << "loaded config file: " << service_filename << LL_ENDL; + } + else + { + LL_WARNS() << "unable to find config file: " << service_filename << LL_ENDL; + } } void LLServiceBuilder::createServiceDefinition( - const std::string& service_name, - LLSD& service_llsd) + const std::string& service_name, + LLSD& service_llsd) { - if(service_llsd.isString()) - { - mServiceMap[ service_name ] = service_llsd.asString(); - } - else if(service_llsd.isMap()) - { - for(LLSD::map_iterator map_itr = service_llsd.beginMap(); - map_itr != service_llsd.endMap(); - ++map_itr) - { - std::string compound_builder_name = service_name; - compound_builder_name.append("-"); - compound_builder_name.append((*map_itr).first); - mServiceMap[ compound_builder_name ] = (*map_itr).second.asString(); - } - } + if(service_llsd.isString()) + { + mServiceMap[ service_name ] = service_llsd.asString(); + } + else if(service_llsd.isMap()) + { + for(LLSD::map_iterator map_itr = service_llsd.beginMap(); + map_itr != service_llsd.endMap(); + ++map_itr) + { + std::string compound_builder_name = service_name; + compound_builder_name.append("-"); + compound_builder_name.append((*map_itr).first); + mServiceMap[ compound_builder_name ] = (*map_itr).second.asString(); + } + } } static bool starts_with(const std::string& text, const char* prefix) { - return text.substr(0, strlen(prefix)) == prefix; + return text.substr(0, strlen(prefix)) == prefix; } // TODO: Build a real services.xml for windows development. // and remove the base_url logic below. std::string LLServiceBuilder::buildServiceURI(const std::string& service_name) const { - std::ostringstream service_url; - // Find the service builder - std::map<std::string, std::string>::const_iterator it = - mServiceMap.find(service_name); - if(it != mServiceMap.end()) - { - // construct the service builder url - LLApp* app = LLApp::instance(); - if(app) - { - // We define a base-url for some development configurations - // In production neither of these are defined and all services have full urls - LLSD base_url; + std::ostringstream service_url; + // Find the service builder + std::map<std::string, std::string>::const_iterator it = + mServiceMap.find(service_name); + if(it != mServiceMap.end()) + { + // construct the service builder url + LLApp* app = LLApp::instance(); + if(app) + { + // We define a base-url for some development configurations + // In production neither of these are defined and all services have full urls + LLSD base_url; - if (starts_with(service_name,"cap")) - { - base_url = app->getOption("cap-base-url"); - } + if (starts_with(service_name,"cap")) + { + base_url = app->getOption("cap-base-url"); + } - if (base_url.asString().empty()) - { - base_url = app->getOption("services-base-url"); - } - service_url << base_url.asString(); - } - service_url << it->second; - } - else - { - LL_WARNS() << "Cannot find service " << service_name << LL_ENDL; - } - return service_url.str(); + if (base_url.asString().empty()) + { + base_url = app->getOption("services-base-url"); + } + service_url << base_url.asString(); + } + service_url << it->second; + } + else + { + LL_WARNS() << "Cannot find service " << service_name << LL_ENDL; + } + return service_url.str(); } std::string LLServiceBuilder::buildServiceURI( - const std::string& service_name, - const LLSD& option_map) const + const std::string& service_name, + const LLSD& option_map) const { - return russ_format(buildServiceURI(service_name), option_map); + return russ_format(buildServiceURI(service_name), option_map); } std::string russ_format(const std::string& format_str, const LLSD& context) { - std::string service_url(format_str); - if(!service_url.empty() && context.isMap()) - { - // throw in a ridiculously large limiter to make sure we don't - // loop forever with bad input. - int iterations = 100; - bool keep_looping = true; - while(keep_looping) - { - if(0 == --iterations) - { - keep_looping = false; - } + std::string service_url(format_str); + if(!service_url.empty() && context.isMap()) + { + // throw in a ridiculously large limiter to make sure we don't + // loop forever with bad input. + int iterations = 100; + bool keep_looping = true; + while(keep_looping) + { + if(0 == --iterations) + { + keep_looping = false; + } - int depth = 0; - int deepest = 0; - bool find_match = false; - std::string::iterator iter(service_url.begin()); - std::string::iterator end(service_url.end()); - std::string::iterator deepest_node(service_url.end()); - std::string::iterator deepest_node_end(service_url.end()); - // parse out the variables to replace by going through {}s - // one at a time, starting with the "deepest" in series - // {{}}, and otherwise replacing right-to-left - for(; iter != end; ++iter) - { - switch(*iter) - { - case '{': - ++depth; - if(depth > deepest) - { - deepest = depth; - deepest_node = iter; - find_match = true; - } - break; - case '}': - --depth; - if(find_match) - { - deepest_node_end = iter; - find_match = false; - } - break; - default: - break; - } - } - if((deepest_node == end) || (deepest_node_end == end)) - { - break; - } - //replace the variable we found in the {} above. - // *NOTE: since the c++ implementation only understands - // params and straight string substitution, so it's a - // known distance of 2 to skip the directive. - std::string key(deepest_node + 2, deepest_node_end); - LLSD value = context[key]; - switch(*(deepest_node + 1)) - { - case '$': - if(value.isDefined()) - { - service_url.replace( - deepest_node, - deepest_node_end + 1, - value.asString()); - } - else - { - LL_WARNS() << "Unknown key: " << key << " in option map: " - << LLSDOStreamer<LLSDNotationFormatter>(context) - << LL_ENDL; - keep_looping = false; - } - break; - case '%': - { - std::string query_str = LLURI::mapToQueryString(value); - service_url.replace( - deepest_node, - deepest_node_end + 1, - query_str); - } - break; - default: - LL_INFOS() << "Unknown directive: " << *(deepest_node + 1) - << LL_ENDL; - keep_looping = false; - break; - } - } - } - if (service_url.find('{') != std::string::npos) - { - LL_WARNS() << "Constructed a likely bogus service URL: " << service_url - << LL_ENDL; - } - return service_url; + int depth = 0; + int deepest = 0; + bool find_match = false; + std::string::iterator iter(service_url.begin()); + std::string::iterator end(service_url.end()); + std::string::iterator deepest_node(service_url.end()); + std::string::iterator deepest_node_end(service_url.end()); + // parse out the variables to replace by going through {}s + // one at a time, starting with the "deepest" in series + // {{}}, and otherwise replacing right-to-left + for(; iter != end; ++iter) + { + switch(*iter) + { + case '{': + ++depth; + if(depth > deepest) + { + deepest = depth; + deepest_node = iter; + find_match = true; + } + break; + case '}': + --depth; + if(find_match) + { + deepest_node_end = iter; + find_match = false; + } + break; + default: + break; + } + } + if((deepest_node == end) || (deepest_node_end == end)) + { + break; + } + //replace the variable we found in the {} above. + // *NOTE: since the c++ implementation only understands + // params and straight string substitution, so it's a + // known distance of 2 to skip the directive. + std::string key(deepest_node + 2, deepest_node_end); + LLSD value = context[key]; + switch(*(deepest_node + 1)) + { + case '$': + if(value.isDefined()) + { + service_url.replace( + deepest_node, + deepest_node_end + 1, + value.asString()); + } + else + { + LL_WARNS() << "Unknown key: " << key << " in option map: " + << LLSDOStreamer<LLSDNotationFormatter>(context) + << LL_ENDL; + keep_looping = false; + } + break; + case '%': + { + std::string query_str = LLURI::mapToQueryString(value); + service_url.replace( + deepest_node, + deepest_node_end + 1, + query_str); + } + break; + default: + LL_INFOS() << "Unknown directive: " << *(deepest_node + 1) + << LL_ENDL; + keep_looping = false; + break; + } + } + } + if (service_url.find('{') != std::string::npos) + { + LL_WARNS() << "Constructed a likely bogus service URL: " << service_url + << LL_ENDL; + } + return service_url; } diff --git a/indra/llmessage/llservicebuilder.h b/indra/llmessage/llservicebuilder.h index 968995edf2..be03534514 100644 --- a/indra/llmessage/llservicebuilder.h +++ b/indra/llmessage/llservicebuilder.h @@ -1,25 +1,25 @@ -/** +/** * @file llservicebuilder.h * @brief Declaration of the LLServiceBuilder 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$ */ @@ -47,56 +47,56 @@ class LLSD; */ std::string russ_format(const std::string& format_str, const LLSD& context); -/** +/** * @class LLServiceBuilder * @brief This class builds urls for us to use when making web service calls. */ class LLServiceBuilder { - LOG_CLASS(LLServiceBuilder); + LOG_CLASS(LLServiceBuilder); public: - LLServiceBuilder(void) {} - ~LLServiceBuilder(void) {} + LLServiceBuilder(void) {} + ~LLServiceBuilder(void) {} - /** - * @brief Initialize this object with the service definitions. - * - * @param service_filename The services definition files -- services.xml. - */ - void loadServiceDefinitionsFromFile(const std::string& service_filename); + /** + * @brief Initialize this object with the service definitions. + * + * @param service_filename The services definition files -- services.xml. + */ + void loadServiceDefinitionsFromFile(const std::string& service_filename); - /** - * @brief Build a service url if the url needs no construction parameters. - * - * @param service_name The name of the service you want to call. - */ - std::string buildServiceURI(const std::string& service_name) const; + /** + * @brief Build a service url if the url needs no construction parameters. + * + * @param service_name The name of the service you want to call. + */ + std::string buildServiceURI(const std::string& service_name) const; - /** - * @brief Build a service url if the url with construction parameters. - * - * The parameter substitution supports string substituition from RUSS: - * [[Recursive_URL_Substitution_Syntax]] - * @param service_name The name of the service you want to call. - * @param option_map The parameters in a map of name:value for the service. - */ - std::string buildServiceURI( - const std::string& service_name, - const LLSD& option_map) const; + /** + * @brief Build a service url if the url with construction parameters. + * + * The parameter substitution supports string substituition from RUSS: + * [[Recursive_URL_Substitution_Syntax]] + * @param service_name The name of the service you want to call. + * @param option_map The parameters in a map of name:value for the service. + */ + std::string buildServiceURI( + const std::string& service_name, + const LLSD& option_map) const; public: - /** - * @brief Helper method which builds construction state for a service - * - * This method should probably be protected, but we need to test this - * method. - */ - void createServiceDefinition( - const std::string& service_name, - LLSD& service_url); + /** + * @brief Helper method which builds construction state for a service + * + * This method should probably be protected, but we need to test this + * method. + */ + void createServiceDefinition( + const std::string& service_name, + LLSD& service_url); protected: - std::map<std::string, std::string> mServiceMap; + std::map<std::string, std::string> mServiceMap; }; diff --git a/indra/llmessage/llstoredmessage.cpp b/indra/llmessage/llstoredmessage.cpp index 9f2f2bcda7..39696ea235 100644 --- a/indra/llmessage/llstoredmessage.cpp +++ b/indra/llmessage/llstoredmessage.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstoredmessage.cpp - * @brief + * @brief * * $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$ */ diff --git a/indra/llmessage/llstoredmessage.h b/indra/llmessage/llstoredmessage.h index 6ea150fda3..178b75ab04 100644 --- a/indra/llmessage/llstoredmessage.h +++ b/indra/llmessage/llstoredmessage.h @@ -1,25 +1,25 @@ -/** +/** * @file llstoredmessage.h - * @brief + * @brief * * $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$ */ @@ -38,12 +38,12 @@ class LLMessageSystem; class LLStoredMessage { public: - LLStoredMessage(const std::string& name, const LLSD& message); + LLStoredMessage(const std::string& name, const LLSD& message); private: - friend class LLMessageSystem; + friend class LLMessageSystem; - LLSD mMessage; - std::string mName; + LLSD mMessage; + std::string mName; }; typedef std::shared_ptr<LLStoredMessage> LLStoredMessagePtr; diff --git a/indra/llmessage/lltaskname.h b/indra/llmessage/lltaskname.h index 5dbd9c6223..413242dc05 100644 --- a/indra/llmessage/lltaskname.h +++ b/indra/llmessage/lltaskname.h @@ -1,4 +1,4 @@ -/** +/** * @file lltaskname.h * @brief This contains the current list of valid tasks and is inluded * into both simulator and viewer @@ -6,21 +6,21 @@ * $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$ */ @@ -29,7 +29,7 @@ #define LL_LLTASKNAME_H // Current valid tasks -// If you add a taskname here you will have to +// If you add a taskname here you will have to // 1) Add an initializer to init_object() in llscript.cpp // 1.1) Add to object_type_to_task_name() in llregion.cpp // 2) Add display code to LLStupidObject::render2(LLAgent* agentp) in llstupidobject.cpp @@ -37,24 +37,24 @@ typedef enum e_lltask_name { - LLTASK_NULL = 0, // Not a valid task - LLTASK_AGENT = 1, // The player's agent in Linden World - LLTASK_CHILD_AGENT = 2, // Child agents sent to adjacent regions -// LLTASK_BASIC_SHOT, // Simple shot that moves in a straight line -// LLTASK_BIG_SHOT, // Big shot that uses gravity - LLTASK_TREE = 5, // A tree -// LLTASK_BIRD, // a bird -// LLTASK_ATOR, // a predator -// LLTASK_SMOKE, // Smoke poof -// LLTASK_SPARK, // Little spark -// LLTASK_ROCK, // Rock - LLTASK_GRASS = 11, // Grass - LLTASK_PSYS = 12, // particle system test example -// LLTASK_ORACLE, -// LLTASK_DEMON, // Maxwell's demon -// LLTASK_LSL_TEST, // Linden Scripting Language Test Object - LLTASK_PRIMITIVE = 16, -// LLTASK_GHOST = 17, // a ghost (Boo!) - LLTASK_TREE_NEW = 18 + LLTASK_NULL = 0, // Not a valid task + LLTASK_AGENT = 1, // The player's agent in Linden World + LLTASK_CHILD_AGENT = 2, // Child agents sent to adjacent regions +// LLTASK_BASIC_SHOT, // Simple shot that moves in a straight line +// LLTASK_BIG_SHOT, // Big shot that uses gravity + LLTASK_TREE = 5, // A tree +// LLTASK_BIRD, // a bird +// LLTASK_ATOR, // a predator +// LLTASK_SMOKE, // Smoke poof +// LLTASK_SPARK, // Little spark +// LLTASK_ROCK, // Rock + LLTASK_GRASS = 11, // Grass + LLTASK_PSYS = 12, // particle system test example +// LLTASK_ORACLE, +// LLTASK_DEMON, // Maxwell's demon +// LLTASK_LSL_TEST, // Linden Scripting Language Test Object + LLTASK_PRIMITIVE = 16, +// LLTASK_GHOST = 17, // a ghost (Boo!) + LLTASK_TREE_NEW = 18 } ELLTaskName; #endif diff --git a/indra/llmessage/llteleportflags.h b/indra/llmessage/llteleportflags.h index fd1e702832..36f9e8e2c8 100644 --- a/indra/llmessage/llteleportflags.h +++ b/indra/llmessage/llteleportflags.h @@ -1,25 +1,25 @@ -/** +/** * @file llteleportflags.h * @brief Teleport flags * * $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$ */ @@ -27,39 +27,39 @@ #ifndef LL_LLTELEPORTFLAGS_H #define LL_LLTELEPORTFLAGS_H -const U32 TELEPORT_FLAGS_DEFAULT = 0; -const U32 TELEPORT_FLAGS_SET_HOME_TO_TARGET = 1 << 0; // newbie leaving prelude -const U32 TELEPORT_FLAGS_SET_LAST_TO_TARGET = 1 << 1; -const U32 TELEPORT_FLAGS_VIA_LURE = 1 << 2; -const U32 TELEPORT_FLAGS_VIA_LANDMARK = 1 << 3; -const U32 TELEPORT_FLAGS_VIA_LOCATION = 1 << 4; -const U32 TELEPORT_FLAGS_VIA_HOME = 1 << 5; -const U32 TELEPORT_FLAGS_VIA_TELEHUB = 1 << 6; -const U32 TELEPORT_FLAGS_VIA_LOGIN = 1 << 7; -const U32 TELEPORT_FLAGS_VIA_GODLIKE_LURE = 1 << 8; -const U32 TELEPORT_FLAGS_GODLIKE = 1 << 9; -const U32 TELEPORT_FLAGS_911 = 1 << 10; -const U32 TELEPORT_FLAGS_DISABLE_CANCEL = 1 << 11; // Used for llTeleportAgentHome() -const U32 TELEPORT_FLAGS_VIA_REGION_ID = 1 << 12; -const U32 TELEPORT_FLAGS_IS_FLYING = 1 << 13; -const U32 TELEPORT_FLAGS_SHOW_RESET_HOME = 1 << 14; -const U32 TELEPORT_FLAGS_FORCE_REDIRECT = 1 << 15; // used to force a redirect to some random location - used when kicking someone from land. -const U32 TELEPORT_FLAGS_VIA_GLOBAL_COORDS = 1 << 16; -const U32 TELEPORT_FLAGS_WITHIN_REGION = 1 << 17; +const U32 TELEPORT_FLAGS_DEFAULT = 0; +const U32 TELEPORT_FLAGS_SET_HOME_TO_TARGET = 1 << 0; // newbie leaving prelude +const U32 TELEPORT_FLAGS_SET_LAST_TO_TARGET = 1 << 1; +const U32 TELEPORT_FLAGS_VIA_LURE = 1 << 2; +const U32 TELEPORT_FLAGS_VIA_LANDMARK = 1 << 3; +const U32 TELEPORT_FLAGS_VIA_LOCATION = 1 << 4; +const U32 TELEPORT_FLAGS_VIA_HOME = 1 << 5; +const U32 TELEPORT_FLAGS_VIA_TELEHUB = 1 << 6; +const U32 TELEPORT_FLAGS_VIA_LOGIN = 1 << 7; +const U32 TELEPORT_FLAGS_VIA_GODLIKE_LURE = 1 << 8; +const U32 TELEPORT_FLAGS_GODLIKE = 1 << 9; +const U32 TELEPORT_FLAGS_911 = 1 << 10; +const U32 TELEPORT_FLAGS_DISABLE_CANCEL = 1 << 11; // Used for llTeleportAgentHome() +const U32 TELEPORT_FLAGS_VIA_REGION_ID = 1 << 12; +const U32 TELEPORT_FLAGS_IS_FLYING = 1 << 13; +const U32 TELEPORT_FLAGS_SHOW_RESET_HOME = 1 << 14; +const U32 TELEPORT_FLAGS_FORCE_REDIRECT = 1 << 15; // used to force a redirect to some random location - used when kicking someone from land. +const U32 TELEPORT_FLAGS_VIA_GLOBAL_COORDS = 1 << 16; +const U32 TELEPORT_FLAGS_WITHIN_REGION = 1 << 17; + +const U32 TELEPORT_FLAGS_MASK_VIA = TELEPORT_FLAGS_VIA_LURE + | TELEPORT_FLAGS_VIA_LANDMARK + | TELEPORT_FLAGS_VIA_LOCATION + | TELEPORT_FLAGS_VIA_HOME + | TELEPORT_FLAGS_VIA_TELEHUB + | TELEPORT_FLAGS_VIA_LOGIN + | TELEPORT_FLAGS_VIA_REGION_ID; -const U32 TELEPORT_FLAGS_MASK_VIA = TELEPORT_FLAGS_VIA_LURE - | TELEPORT_FLAGS_VIA_LANDMARK - | TELEPORT_FLAGS_VIA_LOCATION - | TELEPORT_FLAGS_VIA_HOME - | TELEPORT_FLAGS_VIA_TELEHUB - | TELEPORT_FLAGS_VIA_LOGIN - | TELEPORT_FLAGS_VIA_REGION_ID; - -const U32 LURE_FLAG_NORMAL_LURE = 1 << 0; -const U32 LURE_FLAG_GODLIKE_LURE = 1 << 1; +const U32 LURE_FLAG_NORMAL_LURE = 1 << 0; +const U32 LURE_FLAG_GODLIKE_LURE = 1 << 1; const U32 LURE_FLAG_GODLIKE_PURSUIT = 1 << 2; #endif diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index 62c53dbe55..57ffba9705 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -1,893 +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) -{ - 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 f02ed0c06d..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/lltemplatemessagedispatcher.cpp b/indra/llmessage/lltemplatemessagedispatcher.cpp index ee7a4e7e71..267c201705 100644 --- a/indra/llmessage/lltemplatemessagedispatcher.cpp +++ b/indra/llmessage/lltemplatemessagedispatcher.cpp @@ -5,21 +5,21 @@ * $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$ */ @@ -35,33 +35,33 @@ LLTemplateMessageDispatcher::LLTemplateMessageDispatcher(LLTemplateMessageReader &template_message_reader) : - mTemplateMessageReader(template_message_reader) + mTemplateMessageReader(template_message_reader) { } void LLTemplateMessageDispatcher::dispatch(const std::string& msg_name, - const LLSD& message, - LLHTTPNode::ResponsePtr responsep) + const LLSD& message, + LLHTTPNode::ResponsePtr responsep) { - std::vector<U8> data = message["body"]["binary-template-data"].asBinary(); - U32 size = data.size(); - if(size == 0) - { - return; - } + std::vector<U8> data = message["body"]["binary-template-data"].asBinary(); + U32 size = data.size(); + if(size == 0) + { + return; + } - LLHost host; - host = gMessageSystem->getSender(); + LLHost host; + host = gMessageSystem->getSender(); - bool validate_message = mTemplateMessageReader.validateMessage(&(data[0]), data.size(), host, true); + bool validate_message = mTemplateMessageReader.validateMessage(&(data[0]), data.size(), host, true); - if (validate_message) - { - mTemplateMessageReader.readMessage(&(data[0]),host); - } - else - { - gMessageSystem->clearReceiveState(); - } + if (validate_message) + { + mTemplateMessageReader.readMessage(&(data[0]),host); + } + else + { + gMessageSystem->clearReceiveState(); + } } diff --git a/indra/llmessage/lltemplatemessagedispatcher.h b/indra/llmessage/lltemplatemessagedispatcher.h index fe77f92074..f33e96bb9e 100644 --- a/indra/llmessage/lltemplatemessagedispatcher.h +++ b/indra/llmessage/lltemplatemessagedispatcher.h @@ -5,21 +5,21 @@ * $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$ */ @@ -36,13 +36,13 @@ class LLTemplateMessageDispatcher { public: - LLTemplateMessageDispatcher(LLTemplateMessageReader& template_message_reader); - void dispatch(const std::string& msg_name, - const LLSD& message, - LLHTTPNode::ResponsePtr responsep); + LLTemplateMessageDispatcher(LLTemplateMessageReader& template_message_reader); + void dispatch(const std::string& msg_name, + const LLSD& message, + LLHTTPNode::ResponsePtr responsep); private: - LLTemplateMessageReader &mTemplateMessageReader; + LLTemplateMessageReader &mTemplateMessageReader; }; #endif // LLTEMPLATEMESSAGEDISPATCHER_H diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 064c6e5bd4..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 14656230e3..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 0cfe5dbf38..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 4eb800de06..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 bad12101e5..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 15097642b4..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 50956aeb6d..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 f2a5dc214e..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 ccf0dd7fe0..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 60100e5a65..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/lltransfertargetfile.cpp b/indra/llmessage/lltransfertargetfile.cpp index ca0318a2d6..6d8b69fa6f 100644 --- a/indra/llmessage/lltransfertargetfile.cpp +++ b/indra/llmessage/lltransfertargetfile.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltransfertargetfile.cpp * @brief Transfer system for receiving 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$ */ @@ -33,99 +33,99 @@ LLTransferTargetFile::LLTransferTargetFile( - const LLUUID& uuid, - LLTransferSourceType src_type) : - LLTransferTarget(LLTTT_FILE, uuid, src_type), - mFP(NULL) + const LLUUID& uuid, + LLTransferSourceType src_type) : + LLTransferTarget(LLTTT_FILE, uuid, src_type), + mFP(NULL) { } LLTransferTargetFile::~LLTransferTargetFile() { - if (mFP) - { - LL_ERRS() << "LLTransferTargetFile::~LLTransferTargetFile - Should have been cleaned up in completion callback" << LL_ENDL; - fclose(mFP); - mFP = NULL; - } + if (mFP) + { + LL_ERRS() << "LLTransferTargetFile::~LLTransferTargetFile - Should have been cleaned up in completion callback" << LL_ENDL; + fclose(mFP); + mFP = NULL; + } } // virtual bool LLTransferTargetFile::unpackParams(LLDataPacker& dp) { - // we can safely ignore this call - return true; + // we can safely ignore this call + return true; } void LLTransferTargetFile::applyParams(const LLTransferTargetParams ¶ms) { - if (params.getType() != mType) - { - LL_WARNS() << "Target parameter type doesn't match!" << LL_ENDL; - return; - } - - mParams = (LLTransferTargetParamsFile &)params; + if (params.getType() != mType) + { + LL_WARNS() << "Target parameter type doesn't match!" << LL_ENDL; + return; + } + + mParams = (LLTransferTargetParamsFile &)params; } LLTSCode LLTransferTargetFile::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; - - if (!mFP) - { - mFP = LLFile::fopen(mParams.mFilename, "wb"); /* Flawfinder: ignore */ - - if (!mFP) - { - LL_WARNS() << "Failure opening " << mParams.mFilename << " for write by LLTransferTargetFile" << LL_ENDL; - return LLTS_ERROR; - } - } - if (!in_size) - { - return LLTS_OK; - } - - S32 count = (S32)fwrite(in_datap, 1, in_size, mFP); - if (count != in_size) - { - LL_WARNS() << "Failure in LLTransferTargetFile::dataCallback!" << LL_ENDL; - return LLTS_ERROR; - } - return LLTS_OK; + //LL_INFOS() << "LLTransferTargetFile::dataCallback" << LL_ENDL; + //LL_INFOS() << "Packet: " << packet_id << LL_ENDL; + + if (!mFP) + { + mFP = LLFile::fopen(mParams.mFilename, "wb"); /* Flawfinder: ignore */ + + if (!mFP) + { + LL_WARNS() << "Failure opening " << mParams.mFilename << " for write by LLTransferTargetFile" << LL_ENDL; + return LLTS_ERROR; + } + } + if (!in_size) + { + return LLTS_OK; + } + + S32 count = (S32)fwrite(in_datap, 1, in_size, mFP); + if (count != in_size) + { + LL_WARNS() << "Failure in LLTransferTargetFile::dataCallback!" << LL_ENDL; + return LLTS_ERROR; + } + return LLTS_OK; } void LLTransferTargetFile::completionCallback(const LLTSCode status) { - LL_INFOS() << "LLTransferTargetFile::completionCallback" << LL_ENDL; - if (mFP) - { - fclose(mFP); - } - - // Still need to gracefully handle error conditions. - switch (status) - { - case LLTS_DONE: - break; - case LLTS_ABORT: - case LLTS_ERROR: - // We're aborting this transfer, we don't want to keep this file. - LL_WARNS() << "Aborting file transfer for " << mParams.mFilename << LL_ENDL; - if (mFP) - { - // Only need to remove file if we successfully opened it. - LLFile::remove(mParams.mFilename); - } - default: - break; - } - - mFP = NULL; - if (mParams.mCompleteCallback) - { - mParams.mCompleteCallback(status, mParams.mUserData); - } + LL_INFOS() << "LLTransferTargetFile::completionCallback" << LL_ENDL; + if (mFP) + { + fclose(mFP); + } + + // Still need to gracefully handle error conditions. + switch (status) + { + case LLTS_DONE: + break; + case LLTS_ABORT: + case LLTS_ERROR: + // We're aborting this transfer, we don't want to keep this file. + LL_WARNS() << "Aborting file transfer for " << mParams.mFilename << LL_ENDL; + if (mFP) + { + // Only need to remove file if we successfully opened it. + LLFile::remove(mParams.mFilename); + } + default: + break; + } + + mFP = NULL; + if (mParams.mCompleteCallback) + { + mParams.mCompleteCallback(status, mParams.mUserData); + } } diff --git a/indra/llmessage/lltransfertargetfile.h b/indra/llmessage/lltransfertargetfile.h index 6d03ff2d2e..43189eb388 100644 --- a/indra/llmessage/lltransfertargetfile.h +++ b/indra/llmessage/lltransfertargetfile.h @@ -1,25 +1,25 @@ -/** +/** * @file lltransfertargetfile.h * @brief Transfer system for receiving 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$ */ @@ -34,42 +34,42 @@ typedef void (*LLTTFCompleteCallback)(const LLTSCode status, void *user_data); class LLTransferTargetParamsFile : public LLTransferTargetParams { public: - LLTransferTargetParamsFile() - : LLTransferTargetParams(LLTTT_FILE), + LLTransferTargetParamsFile() + : LLTransferTargetParams(LLTTT_FILE), - mCompleteCallback(NULL), - mUserData(NULL) - {} - void setFilename(const std::string& filename) { mFilename = filename; } - void setCallback(LLTTFCompleteCallback cb, void *user_data) { mCompleteCallback = cb; mUserData = user_data; } + mCompleteCallback(NULL), + mUserData(NULL) + {} + void setFilename(const std::string& filename) { mFilename = filename; } + void setCallback(LLTTFCompleteCallback cb, void *user_data) { mCompleteCallback = cb; mUserData = user_data; } - friend class LLTransferTargetFile; + friend class LLTransferTargetFile; protected: - std::string mFilename; - LLTTFCompleteCallback mCompleteCallback; - void * mUserData; + std::string mFilename; + LLTTFCompleteCallback mCompleteCallback; + void * mUserData; }; class LLTransferTargetFile : public LLTransferTarget { public: - LLTransferTargetFile(const LLUUID& uuid, LLTransferSourceType src_type); - virtual ~LLTransferTargetFile(); + LLTransferTargetFile(const LLUUID& uuid, LLTransferSourceType src_type); + virtual ~LLTransferTargetFile(); - static void requestTransfer(LLTransferTargetChannel *channelp, - const char *local_filename, - const LLTransferSourceParams &source_params, - LLTTFCompleteCallback callback); + static void requestTransfer(LLTransferTargetChannel *channelp, + const char *local_filename, + const LLTransferSourceParams &source_params, + LLTTFCompleteCallback callback); protected: - virtual bool unpackParams(LLDataPacker& dp); - /*virtual*/ void applyParams(const LLTransferTargetParams ¶ms); - /*virtual*/ LLTSCode dataCallback(const S32 packet_id, U8 *in_datap, const S32 in_size); - /*virtual*/ void completionCallback(const LLTSCode status); + virtual bool unpackParams(LLDataPacker& dp); + /*virtual*/ void applyParams(const LLTransferTargetParams ¶ms); + /*virtual*/ LLTSCode dataCallback(const S32 packet_id, U8 *in_datap, const S32 in_size); + /*virtual*/ void completionCallback(const LLTSCode status); - LLTransferTargetParamsFile mParams; + LLTransferTargetParamsFile mParams; - LLFILE *mFP; + LLFILE *mFP; }; #endif // LL_LLTRANSFERTARGETFILE_H diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp index 2806e08ebd..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 2e6e5a8d40..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/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp index 33944f7883..4591a49dce 100644 --- a/indra/llmessage/lltrustedmessageservice.cpp +++ b/indra/llmessage/lltrustedmessageservice.cpp @@ -5,21 +5,21 @@ * $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$ */ @@ -36,50 +36,50 @@ bool LLTrustedMessageService::validate(const std::string& name, LLSD& context) const { - return true; + return true; } void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response, - const LLSD& context, - const LLSD& input) const + const LLSD& context, + const LLSD& input) const { - std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"]; - std::string senderIP = context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST]; - std::string senderPort = context[CONTEXT_REQUEST][CONTEXT_HEADERS] - ["x-secondlife-udp-listen-port"]; + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"]; + std::string senderIP = context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST]; + std::string senderPort = context[CONTEXT_REQUEST][CONTEXT_HEADERS] + ["x-secondlife-udp-listen-port"]; + + LLSD message_data; + std::string sender = senderIP + ":" + senderPort; + message_data["sender"] = sender; + message_data["body"] = input; - LLSD message_data; - std::string sender = senderIP + ":" + senderPort; - message_data["sender"] = sender; - message_data["body"] = input; - - // untrusted senders should not have access to the trusted message - // service, but this can happen in development, so check and warn - LLMessageConfig::SenderTrust trust = - LLMessageConfig::getSenderTrustedness(name); - if ((trust == LLMessageConfig::TRUSTED || - (trust == LLMessageConfig::NOT_SET && - gMessageSystem->isTrustedMessage(name))) - && !gMessageSystem->isTrustedSender(LLHost(sender))) - { - LL_WARNS("Messaging") << "trusted message POST to /trusted-message/" - << name << " from unknown or untrusted sender " - << sender << LL_ENDL; - response->status(HTTP_FORBIDDEN, "Unknown or untrusted sender"); - } - else - { - gMessageSystem->receivedMessageFromTrustedSender(); - if (input.has("binary-template-data")) - { - LL_INFOS() << "Dispatching template: " << input << LL_ENDL; - // try and send this message using udp dispatch - LLMessageSystem::dispatchTemplate(name, message_data, response); - } - else - { - LL_INFOS() << "Dispatching without template: " << input << LL_ENDL; - LLMessageSystem::dispatch(name, message_data, response); - } - } + // untrusted senders should not have access to the trusted message + // service, but this can happen in development, so check and warn + LLMessageConfig::SenderTrust trust = + LLMessageConfig::getSenderTrustedness(name); + if ((trust == LLMessageConfig::TRUSTED || + (trust == LLMessageConfig::NOT_SET && + gMessageSystem->isTrustedMessage(name))) + && !gMessageSystem->isTrustedSender(LLHost(sender))) + { + LL_WARNS("Messaging") << "trusted message POST to /trusted-message/" + << name << " from unknown or untrusted sender " + << sender << LL_ENDL; + response->status(HTTP_FORBIDDEN, "Unknown or untrusted sender"); + } + else + { + gMessageSystem->receivedMessageFromTrustedSender(); + if (input.has("binary-template-data")) + { + LL_INFOS() << "Dispatching template: " << input << LL_ENDL; + // try and send this message using udp dispatch + LLMessageSystem::dispatchTemplate(name, message_data, response); + } + else + { + LL_INFOS() << "Dispatching without template: " << input << LL_ENDL; + LLMessageSystem::dispatch(name, message_data, response); + } + } } diff --git a/indra/llmessage/lltrustedmessageservice.h b/indra/llmessage/lltrustedmessageservice.h index 12a37bb535..c47987a217 100644 --- a/indra/llmessage/lltrustedmessageservice.h +++ b/indra/llmessage/lltrustedmessageservice.h @@ -5,21 +5,21 @@ * $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$ */ @@ -30,7 +30,7 @@ #include "linden_common.h" #include "llhttpnode.h" -// These are defined in lliosocket.h/lliosocket.cpp +// These are defined in lliosocket.h/lliosocket.cpp extern const std::string CONTEXT_REMOTE_HOST; extern const std::string CONTEXT_REMOTE_PORT; @@ -40,11 +40,11 @@ class LLTrustedMessageService { public: - bool validate(const std::string& name, LLSD& context) const; - - void post(LLHTTPNode::ResponsePtr response, - const LLSD& context, - const LLSD& input) const; + bool validate(const std::string& name, LLSD& context) const; + + void post(LLHTTPNode::ResponsePtr response, + const LLSD& context, + const LLSD& input) const; }; #endif // LLTRUSTEDMESSAGESERVICE_H diff --git a/indra/llmessage/lluseroperation.cpp b/indra/llmessage/lluseroperation.cpp index 6b0cc63686..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 != 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 -///---------------------------------------------------------------------------- +/**
+ * @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 9d0f4d04d1..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/llvehicleparams.h b/indra/llmessage/llvehicleparams.h index f34df7744e..fe4b68e3bf 100644 --- a/indra/llmessage/llvehicleparams.h +++ b/indra/llmessage/llvehicleparams.h @@ -1,4 +1,4 @@ -/** +/** * @file llvehicleparams.h * @brief For parameter names that must be shared between the * scripting language and the LLVehicleAction class on the simulator. @@ -6,21 +6,21 @@ * $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$ */ @@ -28,72 +28,72 @@ #ifndef LL_VEHICLE_PARAMS_H #define LL_VEHICLE_PARAMS_H -/** +/** * The idea is that the various parameters that control vehicle * behavior can be tweeked by name using general-purpose script calls. */ typedef enum e_vehicle_param { - VEHICLE_TYPE_NONE, // TYPE_0 - VEHICLE_TYPE_SLED, - VEHICLE_TYPE_CAR, - VEHICLE_TYPE_BOAT, - VEHICLE_TYPE_AIRPLANE, - VEHICLE_TYPE_BALLOON, // TYPE_5 - VEHICLE_TYPE_6, - VEHICLE_TYPE_7, - VEHICLE_TYPE_8, - VEHICLE_TYPE_9, - VEHICLE_TYPE_10, - VEHICLE_TYPE_11, - VEHICLE_TYPE_12, - VEHICLE_TYPE_13, - VEHICLE_TYPE_14, - VEHICLE_TYPE_15, - - // vector parameters - VEHICLE_LINEAR_FRICTION_TIMESCALE, - VEHICLE_ANGULAR_FRICTION_TIMESCALE, - VEHICLE_LINEAR_MOTOR_DIRECTION, - VEHICLE_ANGULAR_MOTOR_DIRECTION, - VEHICLE_LINEAR_MOTOR_OFFSET, - VEHICLE_VECTOR_PARAM_5, - VEHICLE_VECTOR_PARAM_6, - VEHICLE_VECTOR_PARAM_7, - - // floating point parameters - VEHICLE_HOVER_HEIGHT, - VEHICLE_HOVER_EFFICIENCY, - VEHICLE_HOVER_TIMESCALE, - VEHICLE_BUOYANCY, - - VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, - VEHICLE_LINEAR_DEFLECTION_TIMESCALE, - VEHICLE_LINEAR_MOTOR_TIMESCALE, - VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, - - VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, - VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, - VEHICLE_ANGULAR_MOTOR_TIMESCALE, - VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, - - VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, - VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, - - VEHICLE_BANKING_EFFICIENCY, - VEHICLE_BANKING_MIX, - VEHICLE_BANKING_TIMESCALE, - - VEHICLE_FLOAT_PARAM_17, - VEHICLE_FLOAT_PARAM_18, - VEHICLE_FLOAT_PARAM_19, - - // rotation parameters - VEHICLE_REFERENCE_FRAME, - VEHICLE_ROTATION_PARAM_1, - VEHICLE_ROTATION_PARAM_2, - VEHICLE_ROTATION_PARAM_3, + VEHICLE_TYPE_NONE, // TYPE_0 + VEHICLE_TYPE_SLED, + VEHICLE_TYPE_CAR, + VEHICLE_TYPE_BOAT, + VEHICLE_TYPE_AIRPLANE, + VEHICLE_TYPE_BALLOON, // TYPE_5 + VEHICLE_TYPE_6, + VEHICLE_TYPE_7, + VEHICLE_TYPE_8, + VEHICLE_TYPE_9, + VEHICLE_TYPE_10, + VEHICLE_TYPE_11, + VEHICLE_TYPE_12, + VEHICLE_TYPE_13, + VEHICLE_TYPE_14, + VEHICLE_TYPE_15, + + // vector parameters + VEHICLE_LINEAR_FRICTION_TIMESCALE, + VEHICLE_ANGULAR_FRICTION_TIMESCALE, + VEHICLE_LINEAR_MOTOR_DIRECTION, + VEHICLE_ANGULAR_MOTOR_DIRECTION, + VEHICLE_LINEAR_MOTOR_OFFSET, + VEHICLE_VECTOR_PARAM_5, + VEHICLE_VECTOR_PARAM_6, + VEHICLE_VECTOR_PARAM_7, + + // floating point parameters + VEHICLE_HOVER_HEIGHT, + VEHICLE_HOVER_EFFICIENCY, + VEHICLE_HOVER_TIMESCALE, + VEHICLE_BUOYANCY, + + VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, + VEHICLE_LINEAR_DEFLECTION_TIMESCALE, + VEHICLE_LINEAR_MOTOR_TIMESCALE, + VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, + + VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, + VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, + VEHICLE_ANGULAR_MOTOR_TIMESCALE, + VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, + + VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, + VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, + + VEHICLE_BANKING_EFFICIENCY, + VEHICLE_BANKING_MIX, + VEHICLE_BANKING_TIMESCALE, + + VEHICLE_FLOAT_PARAM_17, + VEHICLE_FLOAT_PARAM_18, + VEHICLE_FLOAT_PARAM_19, + + // rotation parameters + VEHICLE_REFERENCE_FRAME, + VEHICLE_ROTATION_PARAM_1, + VEHICLE_ROTATION_PARAM_2, + VEHICLE_ROTATION_PARAM_3, } EVehicleParam; @@ -104,20 +104,20 @@ typedef enum e_vehicle_param const U32 VEHICLE_FLAG_NO_DEFLECTION_UP = 1 << 0; // spring-loads roll only -const U32 VEHICLE_FLAG_LIMIT_ROLL_ONLY = 1 << 1; +const U32 VEHICLE_FLAG_LIMIT_ROLL_ONLY = 1 << 1; // hover flags -const U32 VEHICLE_FLAG_HOVER_WATER_ONLY = 1 << 2; -const U32 VEHICLE_FLAG_HOVER_TERRAIN_ONLY = 1 << 3; -const U32 VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT = 1 << 4; -const U32 VEHICLE_FLAG_HOVER_UP_ONLY = 1 << 5; +const U32 VEHICLE_FLAG_HOVER_WATER_ONLY = 1 << 2; +const U32 VEHICLE_FLAG_HOVER_TERRAIN_ONLY = 1 << 3; +const U32 VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT = 1 << 4; +const U32 VEHICLE_FLAG_HOVER_UP_ONLY = 1 << 5; -// caps world-z component of linear motor to prevent +// caps world-z component of linear motor to prevent // climbing up into the sky -const U32 VEHICLE_FLAG_LIMIT_MOTOR_UP = 1 << 6; +const U32 VEHICLE_FLAG_LIMIT_MOTOR_UP = 1 << 6; -const U32 VEHICLE_FLAG_MOUSELOOK_STEER = 1 << 7; -const U32 VEHICLE_FLAG_MOUSELOOK_BANK = 1 << 8; -const U32 VEHICLE_FLAG_CAMERA_DECOUPLED = 1 << 9; +const U32 VEHICLE_FLAG_MOUSELOOK_STEER = 1 << 7; +const U32 VEHICLE_FLAG_MOUSELOOK_BANK = 1 << 8; +const U32 VEHICLE_FLAG_CAMERA_DECOUPLED = 1 << 9; #endif diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index 58e85b49b4..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 6b236df1a5..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 ef2915ede3..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", 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 24bfd993bd..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 42afaad93b..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", 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 25bd363235..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 3322188694..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", 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 032c5e2533..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 6187d439d9..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 5b42e781eb..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 17651b1ecf..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 cd1fed3ba4..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 - 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 +/**
+ * @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.cpp b/indra/llmessage/machine.cpp index 1e9c9c3c9a..feb4ebfa8b 100644 --- a/indra/llmessage/machine.cpp +++ b/indra/llmessage/machine.cpp @@ -1,25 +1,25 @@ -/** +/** * @file machine.cpp * @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$ */ @@ -30,27 +30,27 @@ #include "llerror.h" void LLMachine::setMachinePort(S32 port) -{ - if (port < 0) - { - LL_INFOS() << "Can't assign a negative number to LLMachine::mPort" << LL_ENDL; - mHost.setPort(0); - } - else - { - mHost.setPort(port); - } +{ + if (port < 0) + { + LL_INFOS() << "Can't assign a negative number to LLMachine::mPort" << LL_ENDL; + mHost.setPort(0); + } + else + { + mHost.setPort(port); + } } -void LLMachine::setControlPort( S32 port ) +void LLMachine::setControlPort( S32 port ) { - if (port < 0) - { - LL_INFOS() << "Can't assign a negative number to LLMachine::mControlPort" << LL_ENDL; - mControlPort = 0; - } - else - { - mControlPort = port; - } + if (port < 0) + { + LL_INFOS() << "Can't assign a negative number to LLMachine::mControlPort" << LL_ENDL; + mControlPort = 0; + } + else + { + mControlPort = port; + } } diff --git a/indra/llmessage/machine.h b/indra/llmessage/machine.h index 831503741c..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/mean_collision_data.h b/indra/llmessage/mean_collision_data.h index 29de091603..5b5b3f2fd2 100644 --- a/indra/llmessage/mean_collision_data.h +++ b/indra/llmessage/mean_collision_data.h @@ -1,4 +1,4 @@ -/** +/** * @file mean_collision_data.h * @brief data type to log interactions between stuff and agents that * might be community standards violations @@ -6,21 +6,21 @@ * $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$ */ @@ -36,60 +36,60 @@ const S32 MAX_MEAN_COLLISIONS = 5; typedef enum e_mean_collision_types { - MEAN_INVALID, - MEAN_BUMP, - MEAN_LLPUSHOBJECT, - MEAN_SELECTED_OBJECT_COLLIDE, - MEAN_SCRIPTED_OBJECT_COLLIDE, - MEAN_PHYSICAL_OBJECT_COLLIDE, - MEAN_EOF + MEAN_INVALID, + MEAN_BUMP, + MEAN_LLPUSHOBJECT, + MEAN_SELECTED_OBJECT_COLLIDE, + MEAN_SCRIPTED_OBJECT_COLLIDE, + MEAN_PHYSICAL_OBJECT_COLLIDE, + MEAN_EOF } EMeanCollisionType; class LLMeanCollisionData { public: - LLMeanCollisionData(const LLUUID &victim, const LLUUID &perp, time_t time, EMeanCollisionType type, F32 mag) - : mVictim(victim), mPerp(perp), mTime(time), mType(type), mMag(mag) - { - } - - LLMeanCollisionData(LLMeanCollisionData *mcd) - : mVictim(mcd->mVictim), mPerp(mcd->mPerp), mTime(mcd->mTime), mType(mcd->mType), mMag(mcd->mMag), - mFullName(mcd->mFullName) - { - } - - friend std::ostream& operator<<(std::ostream& s, const LLMeanCollisionData &a) - { - switch(a.mType) - { - case MEAN_BUMP: - s << "Mean Collision: " << a.mPerp << " bumped " << a.mVictim << " with a velocity of " << a.mMag << " at " << ctime(&a.mTime); - break; - case MEAN_LLPUSHOBJECT: - s << "Mean Collision: " << a.mPerp << " llPushObject-ed " << a.mVictim << " with a total force of " << a.mMag << " at "<< ctime(&a.mTime); - break; - case MEAN_SELECTED_OBJECT_COLLIDE: - s << "Mean Collision: " << a.mPerp << " dragged an object into " << a.mVictim << " with a velocity of " << a.mMag << " at "<< ctime(&a.mTime); - break; - case MEAN_SCRIPTED_OBJECT_COLLIDE: - s << "Mean Collision: " << a.mPerp << " smacked " << a.mVictim << " with a scripted object with velocity of " << a.mMag << " at "<< ctime(&a.mTime); - break; - case MEAN_PHYSICAL_OBJECT_COLLIDE: - s << "Mean Collision: " << a.mPerp << " smacked " << a.mVictim << " with a physical object with velocity of " << a.mMag << " at "<< ctime(&a.mTime); - break; - default: - break; - } - return s; - } + LLMeanCollisionData(const LLUUID &victim, const LLUUID &perp, time_t time, EMeanCollisionType type, F32 mag) + : mVictim(victim), mPerp(perp), mTime(time), mType(type), mMag(mag) + { + } + + LLMeanCollisionData(LLMeanCollisionData *mcd) + : mVictim(mcd->mVictim), mPerp(mcd->mPerp), mTime(mcd->mTime), mType(mcd->mType), mMag(mcd->mMag), + mFullName(mcd->mFullName) + { + } + + friend std::ostream& operator<<(std::ostream& s, const LLMeanCollisionData &a) + { + switch(a.mType) + { + case MEAN_BUMP: + s << "Mean Collision: " << a.mPerp << " bumped " << a.mVictim << " with a velocity of " << a.mMag << " at " << ctime(&a.mTime); + break; + case MEAN_LLPUSHOBJECT: + s << "Mean Collision: " << a.mPerp << " llPushObject-ed " << a.mVictim << " with a total force of " << a.mMag << " at "<< ctime(&a.mTime); + break; + case MEAN_SELECTED_OBJECT_COLLIDE: + s << "Mean Collision: " << a.mPerp << " dragged an object into " << a.mVictim << " with a velocity of " << a.mMag << " at "<< ctime(&a.mTime); + break; + case MEAN_SCRIPTED_OBJECT_COLLIDE: + s << "Mean Collision: " << a.mPerp << " smacked " << a.mVictim << " with a scripted object with velocity of " << a.mMag << " at "<< ctime(&a.mTime); + break; + case MEAN_PHYSICAL_OBJECT_COLLIDE: + s << "Mean Collision: " << a.mPerp << " smacked " << a.mVictim << " with a physical object with velocity of " << a.mMag << " at "<< ctime(&a.mTime); + break; + default: + break; + } + return s; + } - LLUUID mVictim; - LLUUID mPerp; - time_t mTime; - EMeanCollisionType mType; - F32 mMag; - std::string mFullName; + LLUUID mVictim; + LLUUID mPerp; + time_t mTime; + EMeanCollisionType mType; + F32 mMag; + std::string mFullName; }; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 272bf9b672..b57f8f4513 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -1,4055 +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(); - 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>"); - +/**
+ * @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 65c1e07a68..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_prehash.cpp b/indra/llmessage/message_prehash.cpp index 4dccacb889..c264a9f086 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -5,21 +5,21 @@ * $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$ */ @@ -412,7 +412,7 @@ char const* const _PREHASH_GlobalX = LLMessageStringTable::getInstance()->getStr char const* const _PREHASH_GlobalY = LLMessageStringTable::getInstance()->getString("GlobalY"); char const* const _PREHASH_CopyRotates = LLMessageStringTable::getInstance()->getString("CopyRotates"); char const* const _PREHASH_KickUserAck = LLMessageStringTable::getInstance()->getString("KickUserAck"); -char const* const _PREHASH_TopPick = LLMessageStringTable::getInstance()->getString("TopPick"); //legacy var need to be deleted -angela +char const* const _PREHASH_TopPick = LLMessageStringTable::getInstance()->getString("TopPick"); //legacy var need to be deleted -angela char const* const _PREHASH_SessionID = LLMessageStringTable::getInstance()->getString("SessionID"); char const* const _PREHASH_GlobalZ = LLMessageStringTable::getInstance()->getString("GlobalZ"); char const* const _PREHASH_DeclineFriendship = LLMessageStringTable::getInstance()->getString("DeclineFriendship"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index a393bbabb2..1d30b69b67 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -5,21 +5,21 @@ * $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$ */ diff --git a/indra/llmessage/message_string_table.cpp b/indra/llmessage/message_string_table.cpp index 8bcc452e3f..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 443303e45a..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 - // 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 +/**
+ * @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 a873026fa4..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 846b11a5d0..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 76c6b3e202..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 c3c3e2b3b3..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_code.h b/indra/llmessage/patch_code.h index 4c87c9808a..ee8bd58844 100644 --- a/indra/llmessage/patch_code.h +++ b/indra/llmessage/patch_code.h @@ -1,25 +1,25 @@ -/** +/** * @file patch_code.h * @brief Function declarations for encoding and decoding patches. * * $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$ */ @@ -31,16 +31,16 @@ class LLBitPack; class LLGroupHeader; class LLPatchHeader; -void init_patch_coding(LLBitPack &bitpack); -void code_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp); -void code_patch_header(LLBitPack &bitpack, LLPatchHeader *ph, S32 *patch); -void code_end_of_data(LLBitPack &bitpack); -void code_patch(LLBitPack &bitpack, S32 *patch, S32 postquant); -void end_patch_coding(LLBitPack &bitpack); +void init_patch_coding(LLBitPack &bitpack); +void code_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp); +void code_patch_header(LLBitPack &bitpack, LLPatchHeader *ph, S32 *patch); +void code_end_of_data(LLBitPack &bitpack); +void code_patch(LLBitPack &bitpack, S32 *patch, S32 postquant); +void end_patch_coding(LLBitPack &bitpack); -void init_patch_decoding(LLBitPack &bitpack); -void decode_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp); -void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph); -void decode_patch(LLBitPack &bitpack, S32 *patches); +void init_patch_decoding(LLBitPack &bitpack); +void decode_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp); +void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph); +void decode_patch(LLBitPack &bitpack, S32 *patches); #endif diff --git a/indra/llmessage/patch_dct.cpp b/indra/llmessage/patch_dct.cpp index 2144b4e712..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_dct.h b/indra/llmessage/patch_dct.h index 101231ec84..8c270d99bf 100644 --- a/indra/llmessage/patch_dct.h +++ b/indra/llmessage/patch_dct.h @@ -1,25 +1,25 @@ -/** +/** * @file patch_dct.h * @brief Function declarations for DCT and IDCT routines * * $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$ */ @@ -30,12 +30,12 @@ class LLVector3; // Code Values -const U8 ZERO_CODE = 0x0; +const U8 ZERO_CODE = 0x0; const U8 ZERO_EOB = 0x2; const U8 POSITIVE_VALUE = 0x6; const U8 NEGATIVE_VALUE = 0x7; -const S8 NORMAL_PATCH_SIZE = 16; +const S8 NORMAL_PATCH_SIZE = 16; const S8 LARGE_PATCH_SIZE = 32; const U8 END_OF_PATCHES = 97; @@ -45,35 +45,35 @@ const U8 END_OF_PATCHES = 97; // Top level header for group of headers //typedef struct LL_Group_Header //{ -// U16 stride; // 2 = 2 -// U8 patch_size; // 1 = 3 -// U8 layer_type; // 1 = 4 +// U16 stride; // 2 = 2 +// U8 patch_size; // 1 = 3 +// U8 layer_type; // 1 = 4 //} LLGroupHeader; class LLGroupHeader { public: - U16 stride; // 2 = 2 - U8 patch_size; // 1 = 3 - U8 layer_type; // 1 = 4 + U16 stride; // 2 = 2 + U8 patch_size; // 1 = 3 + U8 layer_type; // 1 = 4 }; // Individual patch header //typedef struct LL_Patch_Header //{ -// F32 dc_offset; // 4 bytes -// U16 range; // 2 = 7 ((S16) FP range (breaks if we need > 32K meters in 1 patch) -// U8 quant_wbits; // 1 = 8 (upper 4 bits is quant - 2, lower 4 bits is word bits - 2) -// U16 patchids; // 2 = 10 (actually only uses 10 bits, 5 for each) +// F32 dc_offset; // 4 bytes +// U16 range; // 2 = 7 ((S16) FP range (breaks if we need > 32K meters in 1 patch) +// U8 quant_wbits; // 1 = 8 (upper 4 bits is quant - 2, lower 4 bits is word bits - 2) +// U16 patchids; // 2 = 10 (actually only uses 10 bits, 5 for each) //} LLPatchHeader; class LLPatchHeader { public: - F32 dc_offset; // 4 bytes - U16 range; // 2 = 7 ((S16) FP range (breaks if we need > 32K meters in 1 patch) - U8 quant_wbits; // 1 = 8 (upper 4 bits is quant - 2, lower 4 bits is word bits - 2) - U16 patchids; // 2 = 10 (actually only uses 10 bits, 5 for each) + F32 dc_offset; // 4 bytes + U16 range; // 2 = 7 ((S16) FP range (breaks if we need > 32K meters in 1 patch) + U8 quant_wbits; // 1 = 8 (upper 4 bits is quant - 2, lower 4 bits is word bits - 2) + U16 patchids; // 2 = 10 (actually only uses 10 bits, 5 for each) }; // Compression routines diff --git a/indra/llmessage/patch_idct.cpp b/indra/llmessage/patch_idct.cpp index 687c1734c5..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/sound_ids.cpp b/indra/llmessage/sound_ids.cpp index 2b8a0807c6..17575dc687 100644 --- a/indra/llmessage/sound_ids.cpp +++ b/indra/llmessage/sound_ids.cpp @@ -1,24 +1,24 @@ -/** +/** * @file sound_ids.cpp * * $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$ */ @@ -29,48 +29,48 @@ #include "lluuid.h" const LLUUID SND_NULL = LLUUID::null; -const LLUUID SND_RIDE ("00000000-0000-0000-0000-000000000100"); -const LLUUID SND_SHOT ("00000000-0000-0000-0000-000000000101"); -const LLUUID SND_MORTAR ("00000000-0000-0000-0000-000000000102"); -const LLUUID SND_HIT ("00000000-0000-0000-0000-000000000103"); -const LLUUID SND_EXPLOSION ("00000000-0000-0000-0000-000000000104"); -const LLUUID SND_BOING ("00000000-0000-0000-0000-000000000105"); +const LLUUID SND_RIDE ("00000000-0000-0000-0000-000000000100"); +const LLUUID SND_SHOT ("00000000-0000-0000-0000-000000000101"); +const LLUUID SND_MORTAR ("00000000-0000-0000-0000-000000000102"); +const LLUUID SND_HIT ("00000000-0000-0000-0000-000000000103"); +const LLUUID SND_EXPLOSION ("00000000-0000-0000-0000-000000000104"); +const LLUUID SND_BOING ("00000000-0000-0000-0000-000000000105"); const LLUUID SND_OBJECT_CREATE ("9f1bc096-3592-411e-9b0b-c447a9ff054c"); // -// Different bird sounds for different states +// Different bird sounds for different states // -const LLUUID SND_CHIRP ("00000000-0000-0000-0000-000000000106"); // Flying random chirp -const LLUUID SND_CHIRP2 ("828a9526-175b-455d-8af0-0e3c0fb602b2"); // Spooked by user -const LLUUID SND_CHIRP3 ("f99772d6-1ce6-4a39-a28b-06d26c94c9e3"); // Spooked by object -const LLUUID SND_CHIRP4 ("54472ca4-7fc9-42cb-b7d5-99ad5b12bd50"); // Chasing other bird -const LLUUID SND_CHIRP5 ("2929964f-fac5-40d7-9179-2864a8fa9ace"); // Hopping random chirp -const LLUUID SND_CHIRPDEAD ("9abff1d3-863a-4e04-bd83-3834fd7fcff4"); // Hit by grenade - dead! +const LLUUID SND_CHIRP ("00000000-0000-0000-0000-000000000106"); // Flying random chirp +const LLUUID SND_CHIRP2 ("828a9526-175b-455d-8af0-0e3c0fb602b2"); // Spooked by user +const LLUUID SND_CHIRP3 ("f99772d6-1ce6-4a39-a28b-06d26c94c9e3"); // Spooked by object +const LLUUID SND_CHIRP4 ("54472ca4-7fc9-42cb-b7d5-99ad5b12bd50"); // Chasing other bird +const LLUUID SND_CHIRP5 ("2929964f-fac5-40d7-9179-2864a8fa9ace"); // Hopping random chirp +const LLUUID SND_CHIRPDEAD ("9abff1d3-863a-4e04-bd83-3834fd7fcff4"); // Hit by grenade - dead! -const LLUUID SND_MUNCH ("00000000-0000-0000-0000-000000000107"); -const LLUUID SND_PUNCH ("00000000-0000-0000-0000-000000000108"); -const LLUUID SND_SPLASH ("00000000-0000-0000-0000-000000000109"); -const LLUUID SND_CLICK ("00000000-0000-0000-0000-000000000110"); -const LLUUID SND_WHISTLE ("ab858f9a-1f44-4d39-9b33-351543d03ccb"); +const LLUUID SND_MUNCH ("00000000-0000-0000-0000-000000000107"); +const LLUUID SND_PUNCH ("00000000-0000-0000-0000-000000000108"); +const LLUUID SND_SPLASH ("00000000-0000-0000-0000-000000000109"); +const LLUUID SND_CLICK ("00000000-0000-0000-0000-000000000110"); +const LLUUID SND_WHISTLE ("ab858f9a-1f44-4d39-9b33-351543d03ccb"); const LLUUID SND_TYPING ("5e191c7b-8996-9ced-a177-b2ac32bfea06"); -const LLUUID SND_ARROW_SHOT ("00000000-0000-0000-0000-000000000111"); -const LLUUID SND_ARROW_THUD ("00000000-0000-0000-0000-000000000112"); -const LLUUID SND_LASER_SHOT ("00000000-0000-0000-0000-000000000113"); -const LLUUID SND_JET_THRUST ("67f5e4f0-0534-4d97-bc01-f297648d20e0"); +const LLUUID SND_ARROW_SHOT ("00000000-0000-0000-0000-000000000111"); +const LLUUID SND_ARROW_THUD ("00000000-0000-0000-0000-000000000112"); +const LLUUID SND_LASER_SHOT ("00000000-0000-0000-0000-000000000113"); +const LLUUID SND_JET_THRUST ("67f5e4f0-0534-4d97-bc01-f297648d20e0"); -const LLUUID SND_SILENCE ("00000000-0000-0000-0000-000000000114"); -const LLUUID SND_BUBBLES ("00000000-0000-0000-0000-000000000115"); -const LLUUID SND_WELCOME ("00000000-0000-0000-0000-000000000116"); -const LLUUID SND_SQUISH ("00000000-0000-0000-0000-000000000117"); -const LLUUID SND_SUBPOD ("00000000-0000-0000-0000-000000000118"); +const LLUUID SND_SILENCE ("00000000-0000-0000-0000-000000000114"); +const LLUUID SND_BUBBLES ("00000000-0000-0000-0000-000000000115"); +const LLUUID SND_WELCOME ("00000000-0000-0000-0000-000000000116"); +const LLUUID SND_SQUISH ("00000000-0000-0000-0000-000000000117"); +const LLUUID SND_SUBPOD ("00000000-0000-0000-0000-000000000118"); const LLUUID SND_FOOTSTEPS ("00000000-0000-0000-0000-000000000119"); const LLUUID SND_STEP_LEFT ("00000000-0000-0000-0000-000000000124"); const LLUUID SND_STEP_RIGHT ("00000000-0000-0000-0000-000000000125"); -const LLUUID SND_BALL_COLLISION ("00000000-0000-0000-0000-000000000120"); +const LLUUID SND_BALL_COLLISION ("00000000-0000-0000-0000-000000000120"); const LLUUID SND_OOOH_SCARE_ME ("00000000-0000-0000-0000-000000000121"); const LLUUID SND_PAYBACK_TIME ("00000000-0000-0000-0000-000000000122"); @@ -275,15 +275,15 @@ const LLUUID SND_ROLL_WOOD_WOOD_07 ("0c6aa481-b5bc-4573-ae83-8e16ff27e750"); const LLUUID SND_ROLL_WOOD_WOOD_08 ("214ab2c7-871a-451b-b0db-4c5677199011"); const LLUUID SND_ROLL_WOOD_WOOD_09 ("0086e4db-3ac6-4545-b414-6f359bedd9a5"); -const LLUUID SND_SLIDE_STONE_STONE_01 ("2a7dcbd1-d3e6-4767-8432-8322648e7b9d"); +const LLUUID SND_SLIDE_STONE_STONE_01 ("2a7dcbd1-d3e6-4767-8432-8322648e7b9d"); -const LLUUID SND_STONE_DIRT_01 ("97727335-392c-4338-ac4b-23a7883279c2"); -const LLUUID SND_STONE_DIRT_02 ("cbe75eb2-3375-41d8-9e3f-2ae46b4164ed"); -const LLUUID SND_STONE_DIRT_03 ("31e236ee-001b-4c8e-ad6c-c2074cb64357"); -const LLUUID SND_STONE_DIRT_04 ("c8091652-e04b-4a11-84ba-15dba06e7a1b"); +const LLUUID SND_STONE_DIRT_01 ("97727335-392c-4338-ac4b-23a7883279c2"); +const LLUUID SND_STONE_DIRT_02 ("cbe75eb2-3375-41d8-9e3f-2ae46b4164ed"); +const LLUUID SND_STONE_DIRT_03 ("31e236ee-001b-4c8e-ad6c-c2074cb64357"); +const LLUUID SND_STONE_DIRT_04 ("c8091652-e04b-4a11-84ba-15dba06e7a1b"); -const LLUUID SND_STONE_STONE_02 ("ba4ef5ac-7435-4240-b826-c24ba8fa5a78"); -const LLUUID SND_STONE_STONE_04 ("ea296329-0f09-4993-af1b-e6784bab1dc9"); +const LLUUID SND_STONE_STONE_02 ("ba4ef5ac-7435-4240-b826-c24ba8fa5a78"); +const LLUUID SND_STONE_STONE_04 ("ea296329-0f09-4993-af1b-e6784bab1dc9"); diff --git a/indra/llmessage/sound_ids.h b/indra/llmessage/sound_ids.h index 6a2e343ad3..d212ca322f 100644 --- a/indra/llmessage/sound_ids.h +++ b/indra/llmessage/sound_ids.h @@ -1,25 +1,25 @@ -/** +/** * @file sound_ids.h * @brief Temporary holder for sound IDs. * * $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$ */ @@ -41,13 +41,13 @@ extern const LLUUID SND_EXPLOSION; extern const LLUUID SND_BOING; extern const LLUUID SND_OBJECT_CREATE; -// Different bird sounds for different states -extern const LLUUID SND_CHIRP; // Flying random chirp -extern const LLUUID SND_CHIRP2; // Spooked by user -extern const LLUUID SND_CHIRP3; // Spooked by object -extern const LLUUID SND_CHIRP4; // Chasing other bird -extern const LLUUID SND_CHIRP5; // Hopping random chirp -extern const LLUUID SND_CHIRPDEAD; // Hit by grenade - dead! +// Different bird sounds for different states +extern const LLUUID SND_CHIRP; // Flying random chirp +extern const LLUUID SND_CHIRP2; // Spooked by user +extern const LLUUID SND_CHIRP3; // Spooked by object +extern const LLUUID SND_CHIRP4; // Chasing other bird +extern const LLUUID SND_CHIRP5; // Hopping random chirp +extern const LLUUID SND_CHIRPDEAD; // Hit by grenade - dead! extern const LLUUID SND_MUNCH; diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h index 0359eba803..cc72242e66 100644 --- a/indra/llmessage/tests/commtest.h +++ b/indra/llmessage/tests/commtest.h @@ -2,26 +2,26 @@ * @file commtest.h * @author Nat Goodspeed * @date 2009-01-09 - * @brief - * + * @brief + * * $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$ */ diff --git a/indra/llmessage/tests/llareslistener_test.cpp b/indra/llmessage/tests/llareslistener_test.cpp index 254185cbd0..f4a9e501ec 100644 --- a/indra/llmessage/tests/llareslistener_test.cpp +++ b/indra/llmessage/tests/llareslistener_test.cpp @@ -3,25 +3,25 @@ * @author Mark Palange * @date 2009-02-26 * @brief Tests of llareslistener.h. - * + * * $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$ */ @@ -57,14 +57,14 @@ LLAres::LLAres(): {} LLAres::~LLAres() {} void LLAres::rewriteURI(const std::string &uri, - LLAres::UriRewriteResponder *resp) + LLAres::UriRewriteResponder *resp) { - // This is the only LLAres method I chose to implement. - // The effect is that LLAres returns immediately with - // a result that is equal to the input uri. - std::vector<std::string> result; - result.push_back(uri); - resp->rewriteResult(result); + // This is the only LLAres method I chose to implement. + // The effect is that LLAres returns immediately with + // a result that is equal to the input uri. + std::vector<std::string> result; + result.push_back(uri); + resp->rewriteResult(result); } LLAres::QueryResponder::~QueryResponder() {} @@ -90,11 +90,11 @@ namespace tut typedef llareslistener_group::object object; llareslistener_group llareslistenergrp("llareslistener"); - struct ResponseCallback - { - std::vector<std::string> mURIs; - bool operator()(const LLSD& response) - { + struct ResponseCallback + { + std::vector<std::string> mURIs; + bool operator()(const LLSD& response) + { mURIs.clear(); for (LLSD::array_const_iterator ri(response.beginArray()), rend(response.endArray()); ri != rend; ++ri) @@ -102,16 +102,16 @@ namespace tut mURIs.push_back(*ri); } return false; - } - }; + } + }; template<> template<> void object::test<1>() { set_test_name("test event"); - // Tests the success and failure cases, since they both use - // the same code paths in the LLAres responder. - ResponseCallback response; + // Tests the success and failure cases, since they both use + // the same code paths in the LLAres responder. + ResponseCallback response; std::string pumpname("trigger"); // Since we're asking LLEventPumps to obtain() the pump by the desired // name, it will persist beyond the current scope, so ensure we @@ -121,15 +121,15 @@ namespace tut boost::bind(&ResponseCallback::operator(), &response, _1))); // Now build an LLSD request that will direct its response events to // that pump. - const std::string testURI("login.bar.com"); + const std::string testURI("login.bar.com"); LLSD request; request["op"] = "rewriteURI"; request["uri"] = testURI; request["reply"] = pumpname; LLEventPumps::instance().obtain("LLAres").post(request); - ensure_equals(response.mURIs.size(), 1); - ensure_equals(response.mURIs.front(), testURI); - } + ensure_equals(response.mURIs.size(), 1); + ensure_equals(response.mURIs.front(), testURI); + } template<> template<> void object::test<2>() diff --git a/indra/llmessage/tests/llavatarnamecache_test.cpp b/indra/llmessage/tests/llavatarnamecache_test.cpp index ec6b65d483..3735f42c47 100644 --- a/indra/llmessage/tests/llavatarnamecache_test.cpp +++ b/indra/llmessage/tests/llavatarnamecache_test.cpp @@ -6,25 +6,25 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + #include "linden_common.h" #include "../llavatarnamecache.h" @@ -33,70 +33,70 @@ namespace tut { - struct avatarnamecache_data - { - }; - typedef test_group<avatarnamecache_data> avatarnamecache_test; - typedef avatarnamecache_test::object avatarnamecache_object; - tut::avatarnamecache_test avatarnamecache_testcase("LLAvatarNameCache"); - - template<> template<> - void avatarnamecache_object::test<1>() - { - bool valid = false; - S32 max_age = 0; - - valid = max_age_from_cache_control("max-age=3600", &max_age); - ensure("typical input valid", valid); - ensure_equals("typical input parsed", max_age, 3600); - - valid = max_age_from_cache_control( - " max-age=600 , no-cache,private=\"stuff\" ", &max_age); - ensure("complex input valid", valid); - ensure_equals("complex input parsed", max_age, 600); - - valid = max_age_from_cache_control( - "no-cache, max-age = 123 ", &max_age); - ensure("complex input 2 valid", valid); - ensure_equals("complex input 2 parsed", max_age, 123); - } - - template<> template<> - void avatarnamecache_object::test<2>() - { - bool valid = false; - S32 max_age = -1; - - valid = max_age_from_cache_control("", &max_age); - ensure("empty input returns invalid", !valid); - ensure_equals("empty input doesn't change val", max_age, -1); - - valid = max_age_from_cache_control("no-cache", &max_age); - ensure("no max-age field returns invalid", !valid); - - valid = max_age_from_cache_control("max", &max_age); - ensure("just 'max' returns invalid", !valid); - - valid = max_age_from_cache_control("max-age", &max_age); - ensure("partial max-age is invalid", !valid); - - valid = max_age_from_cache_control("max-age=", &max_age); - ensure("longer partial max-age is invalid", !valid); - - valid = max_age_from_cache_control("max-age=FOO", &max_age); - ensure("invalid integer max-age is invalid", !valid); - - valid = max_age_from_cache_control("max-age 234", &max_age); - ensure("space separated max-age is invalid", !valid); - - valid = max_age_from_cache_control("max-age=0", &max_age); - ensure("zero max-age is valid", valid); - - // *TODO: Handle "0000" as zero - //valid = max_age_from_cache_control("max-age=0000", &max_age); - //ensure("multi-zero max-age is valid", valid); - - valid = max_age_from_cache_control("max-age=-123", &max_age); - ensure("less than zero max-age is invalid", !valid); - } + struct avatarnamecache_data + { + }; + typedef test_group<avatarnamecache_data> avatarnamecache_test; + typedef avatarnamecache_test::object avatarnamecache_object; + tut::avatarnamecache_test avatarnamecache_testcase("LLAvatarNameCache"); + + template<> template<> + void avatarnamecache_object::test<1>() + { + bool valid = false; + S32 max_age = 0; + + valid = max_age_from_cache_control("max-age=3600", &max_age); + ensure("typical input valid", valid); + ensure_equals("typical input parsed", max_age, 3600); + + valid = max_age_from_cache_control( + " max-age=600 , no-cache,private=\"stuff\" ", &max_age); + ensure("complex input valid", valid); + ensure_equals("complex input parsed", max_age, 600); + + valid = max_age_from_cache_control( + "no-cache, max-age = 123 ", &max_age); + ensure("complex input 2 valid", valid); + ensure_equals("complex input 2 parsed", max_age, 123); + } + + template<> template<> + void avatarnamecache_object::test<2>() + { + bool valid = false; + S32 max_age = -1; + + valid = max_age_from_cache_control("", &max_age); + ensure("empty input returns invalid", !valid); + ensure_equals("empty input doesn't change val", max_age, -1); + + valid = max_age_from_cache_control("no-cache", &max_age); + ensure("no max-age field returns invalid", !valid); + + valid = max_age_from_cache_control("max", &max_age); + ensure("just 'max' returns invalid", !valid); + + valid = max_age_from_cache_control("max-age", &max_age); + ensure("partial max-age is invalid", !valid); + + valid = max_age_from_cache_control("max-age=", &max_age); + ensure("longer partial max-age is invalid", !valid); + + valid = max_age_from_cache_control("max-age=FOO", &max_age); + ensure("invalid integer max-age is invalid", !valid); + + valid = max_age_from_cache_control("max-age 234", &max_age); + ensure("space separated max-age is invalid", !valid); + + valid = max_age_from_cache_control("max-age=0", &max_age); + ensure("zero max-age is valid", valid); + + // *TODO: Handle "0000" as zero + //valid = max_age_from_cache_control("max-age=0000", &max_age); + //ensure("multi-zero max-age is valid", valid); + + valid = max_age_from_cache_control("max-age=-123", &max_age); + ensure("less than zero max-age is invalid", !valid); + } } diff --git a/indra/llmessage/tests/llcoproceduremanager_test.cpp b/indra/llmessage/tests/llcoproceduremanager_test.cpp index d6481d4eea..4caae5f082 100644 --- a/indra/llmessage/tests/llcoproceduremanager_test.cpp +++ b/indra/llmessage/tests/llcoproceduremanager_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llcoproceduremanager_test.cpp * @author Brad * @date 2019-02 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2019&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$ */ @@ -100,7 +100,7 @@ namespace tut sync.yield(); ensure_equals("coprocedure failed to update foo", foo, 1); - + LLCoprocedureManager::instance().close("PoolName"); } diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp index 1c571a74da..78c195580c 100644 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ b/indra/llmessage/tests/llcurl_stub.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,18 +38,18 @@ LLCurl::Responder::Responder() void LLCurl::Responder::httpCompleted() { - if (isGoodStatus()) - { - httpSuccess(); - } - else - { - httpFailure(); - } + if (isGoodStatus()) + { + httpSuccess(); + } + else + { + httpFailure(); + } } void LLCurl::Responder::completedRaw(LLChannelDescriptors const&, - std::shared_ptr<LLBufferArray> const&) + std::shared_ptr<LLBufferArray> const&) { } @@ -67,33 +67,33 @@ void LLCurl::Responder::httpSuccess() std::string LLCurl::Responder::dumpResponse() const { - return "dumpResponse()"; + return "dumpResponse()"; } void LLCurl::Responder::successResult(const LLSD& content) { - setResult(HTTP_OK, "", content); - httpSuccess(); + setResult(HTTP_OK, "", content); + httpSuccess(); } void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) { - setResult(status, reason, content); - httpFailure(); + setResult(status, reason, content); + httpFailure(); } void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content) { - setResult(status, reason, content); - httpCompleted(); + setResult(status, reason, content); + httpCompleted(); } void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) { - mStatus = status; - mReason = reason; - mContent = content; + mStatus = status; + mReason = reason; + mContent = content; } #endif diff --git a/indra/llmessage/tests/llhost_test.cpp b/indra/llmessage/tests/llhost_test.cpp index efca1bbfca..a66655ad6c 100644 --- a/indra/llmessage/tests/llhost_test.cpp +++ b/indra/llmessage/tests/llhost_test.cpp @@ -7,25 +7,25 @@ * $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 "../llhost.h" @@ -34,238 +34,238 @@ namespace tut { - struct host_data - { - }; - typedef test_group<host_data> host_test; - typedef host_test::object host_object; - tut::host_test host_testcase("LLHost"); - - - template<> template<> - void host_object::test<1>() - { - LLHost host; - ensure("IP address is not NULL", (0 == host.getAddress()) && (0 == host.getPort()) && !host.isOk()); - } - template<> template<> - void host_object::test<2>() - { - U32 ip_addr = 0xc098017d; - U32 port = 8080; - LLHost host(ip_addr, port); - ensure("IP address is invalid", ip_addr == host.getAddress()); - ensure("Port Number is invalid", port == host.getPort()); - ensure("IP address and port number both should be ok", host.isOk()); - } - - template<> template<> - void host_object::test<3>() - { - const char* str = "192.168.1.1"; - U32 port = 8080; - LLHost host(str, port); - ensure("IP address could not be processed", (host.getAddress() == ip_string_to_u32(str))); - ensure("Port Number is invalid", (port == host.getPort())); - } - - template<> template<> - void host_object::test<4>() - { - U32 ip = ip_string_to_u32("192.168.1.1"); - U32 port = 22; - U64 ip_port = (((U64) ip) << 32) | port; - LLHost host(ip_port); - ensure("IP address is invalid", ip == host.getAddress()); - ensure("Port Number is invalid", port == host.getPort()); - } - - template<> template<> - void host_object::test<5>() - { - std::string ip_port_string = "192.168.1.1:8080"; - U32 ip = ip_string_to_u32("192.168.1.1"); - U32 port = 8080; - - LLHost host(ip_port_string); - ensure("IP address from IP:port is invalid", ip == host.getAddress()); - ensure("Port Number from from IP:port is invalid", port == host.getPort()); - } - - template<> template<> - void host_object::test<6>() - { - U32 ip = 0xc098017d, port = 8080; - LLHost host; - host.set(ip,port); - ensure("IP address is invalid", (ip == host.getAddress())); - ensure("Port Number is invalid", (port == host.getPort())); - } - - template<> template<> - void host_object::test<7>() - { - const char* str = "192.168.1.1"; - U32 port = 8080, ip; - LLHost host; - host.set(str,port); - ip = ip_string_to_u32(str); - ensure("IP address is invalid", (ip == host.getAddress())); - ensure("Port Number is invalid", (port == host.getPort())); - - str = "64.233.187.99"; - ip = ip_string_to_u32(str); - host.setAddress(str); - ensure("IP address is invalid", (ip == host.getAddress())); - - ip = 0xc098017b; - host.setAddress(ip); - ensure("IP address is invalid", (ip == host.getAddress())); - // should still use the old port - ensure("Port Number is invalid", (port == host.getPort())); - - port = 8084; - host.setPort(port); - ensure("Port Number is invalid", (port == host.getPort())); - // should still use the old address - ensure("IP address is invalid", (ip == host.getAddress())); - } - - template<> template<> - void host_object::test<8>() - { - const std::string str("192.168.1.1"); - U32 port = 8080; - LLHost host; - host.set(str,port); - - std::string ip_string = host.getIPString(); - ensure("Function Failed", (ip_string == str)); - - std::string ip_string_port = host.getIPandPort(); - ensure("Function Failed", (ip_string_port == "192.168.1.1:8080")); - } - - -// getHostName() and setHostByName - template<> template<> - void host_object::test<9>() - { - skip("this test is irreparably flaky"); -// skip("setHostByName(\"google.com\"); getHostName() -> (e.g.) \"yx-in-f100.1e100.net\""); - // nat: is it reasonable to expect LLHost::getHostName() to echo - // back something resembling the string passed to setHostByName()? - // - // If that's not even reasonable, would a round trip in the /other/ - // direction make more sense? (Call getHostName() for something with - // known IP address; call setHostByName(); verify IP address) - // - // Failing that... is there a plausible way to test getHostName() and - // setHostByName()? Hopefully without putting up a dummy local DNS - // server? - - // monty: If you don't control the DNS server or the DNS configuration - // for the test point then, no, none of these will necessarily be - // reliable and may start to fail at any time. Forward translation - // is subject to CNAME records and round-robin address assignment. - // Reverse lookup is 1-to-many and is more and more likely to have - // nothing to do with the forward translation. - // - // So the test is increasingly meaningless on a real network. - - std::string hostStr = "lindenlab.com"; - LLHost host; - host.setHostByName(hostStr); - - // reverse DNS will likely result in appending of some - // sub-domain to the main hostname. so look for - // the main domain name and not do the exact compare - - std::string hostname = host.getHostName(); - try - { - ensure("getHostName failed", hostname.find(hostStr) != std::string::npos); - } - catch (const std::exception&) - { - std::cerr << "set '" << hostStr << "'; reported '" << hostname << "'" << std::endl; - throw; - } - } - -// setHostByName for dotted IP - template<> template<> - void host_object::test<10>() - { - std::string hostStr = "64.233.167.99"; - LLHost host; - host.setHostByName(hostStr); - ensure("SetHostByName for dotted IP Address failed", host.getAddress() == ip_string_to_u32(hostStr.c_str())); - } - - template<> template<> - void host_object::test<11>() - { - LLHost host1(0xc098017d, 8080); - LLHost host2 = host1; - ensure("Both IP addresses are not same", (host1.getAddress() == host2.getAddress())); - ensure("Both port numbers are not same", (host1.getPort() == host2.getPort())); - } - - template<> template<> - void host_object::test<12>() - { - LLHost host1("192.168.1.1", 8080); - std::string str1 = "192.168.1.1:8080"; - std::ostringstream stream; - stream << host1; - ensure("Operator << failed", ( stream.str()== str1)); - - // There is no istream >> llhost operator. - //std::istringstream is(stream.str()); - //LLHost host2; - //is >> host2; - //ensure("Operator >> failed. Not compatible with <<", host1 == host2); - } - - // operators ==, !=, < - template<> template<> - void host_object::test<13>() - { - U32 ip_addr = 0xc098017d; - U32 port = 8080; - LLHost host1(ip_addr, port); - LLHost host2(ip_addr, port); - ensure("operator== failed", host1 == host2); - - // change port - host2.setPort(7070); - ensure("operator!= failed", host1 != host2); - - // set port back to 8080 and change IP address now - host2.setPort(8080); - host2.setAddress(ip_addr+10); - ensure("operator!= failed", host1 != host2); - - ensure("operator< failed", host1 < host2); - - // set IP address back to same value and change port - host2.setAddress(ip_addr); - host2.setPort(host1.getPort() + 10); - ensure("operator< failed", host1 < host2); - } - - // invalid ip address string - template<> template<> - void host_object::test<14>() - { - LLHost host1("10.0.1.2", 6143); - ensure("10.0.1.2 should be a valid address", host1.isOk()); - - LLHost host2("booger-brains", 6143); - ensure("booger-brains should be an invalid ip addess", !host2.isOk()); - - LLHost host3("255.255.255.255", 6143); - ensure("255.255.255.255 should be valid broadcast address", host3.isOk()); - } + struct host_data + { + }; + typedef test_group<host_data> host_test; + typedef host_test::object host_object; + tut::host_test host_testcase("LLHost"); + + + template<> template<> + void host_object::test<1>() + { + LLHost host; + ensure("IP address is not NULL", (0 == host.getAddress()) && (0 == host.getPort()) && !host.isOk()); + } + template<> template<> + void host_object::test<2>() + { + U32 ip_addr = 0xc098017d; + U32 port = 8080; + LLHost host(ip_addr, port); + ensure("IP address is invalid", ip_addr == host.getAddress()); + ensure("Port Number is invalid", port == host.getPort()); + ensure("IP address and port number both should be ok", host.isOk()); + } + + template<> template<> + void host_object::test<3>() + { + const char* str = "192.168.1.1"; + U32 port = 8080; + LLHost host(str, port); + ensure("IP address could not be processed", (host.getAddress() == ip_string_to_u32(str))); + ensure("Port Number is invalid", (port == host.getPort())); + } + + template<> template<> + void host_object::test<4>() + { + U32 ip = ip_string_to_u32("192.168.1.1"); + U32 port = 22; + U64 ip_port = (((U64) ip) << 32) | port; + LLHost host(ip_port); + ensure("IP address is invalid", ip == host.getAddress()); + ensure("Port Number is invalid", port == host.getPort()); + } + + template<> template<> + void host_object::test<5>() + { + std::string ip_port_string = "192.168.1.1:8080"; + U32 ip = ip_string_to_u32("192.168.1.1"); + U32 port = 8080; + + LLHost host(ip_port_string); + ensure("IP address from IP:port is invalid", ip == host.getAddress()); + ensure("Port Number from from IP:port is invalid", port == host.getPort()); + } + + template<> template<> + void host_object::test<6>() + { + U32 ip = 0xc098017d, port = 8080; + LLHost host; + host.set(ip,port); + ensure("IP address is invalid", (ip == host.getAddress())); + ensure("Port Number is invalid", (port == host.getPort())); + } + + template<> template<> + void host_object::test<7>() + { + const char* str = "192.168.1.1"; + U32 port = 8080, ip; + LLHost host; + host.set(str,port); + ip = ip_string_to_u32(str); + ensure("IP address is invalid", (ip == host.getAddress())); + ensure("Port Number is invalid", (port == host.getPort())); + + str = "64.233.187.99"; + ip = ip_string_to_u32(str); + host.setAddress(str); + ensure("IP address is invalid", (ip == host.getAddress())); + + ip = 0xc098017b; + host.setAddress(ip); + ensure("IP address is invalid", (ip == host.getAddress())); + // should still use the old port + ensure("Port Number is invalid", (port == host.getPort())); + + port = 8084; + host.setPort(port); + ensure("Port Number is invalid", (port == host.getPort())); + // should still use the old address + ensure("IP address is invalid", (ip == host.getAddress())); + } + + template<> template<> + void host_object::test<8>() + { + const std::string str("192.168.1.1"); + U32 port = 8080; + LLHost host; + host.set(str,port); + + std::string ip_string = host.getIPString(); + ensure("Function Failed", (ip_string == str)); + + std::string ip_string_port = host.getIPandPort(); + ensure("Function Failed", (ip_string_port == "192.168.1.1:8080")); + } + + +// getHostName() and setHostByName + template<> template<> + void host_object::test<9>() + { + skip("this test is irreparably flaky"); +// skip("setHostByName(\"google.com\"); getHostName() -> (e.g.) \"yx-in-f100.1e100.net\""); + // nat: is it reasonable to expect LLHost::getHostName() to echo + // back something resembling the string passed to setHostByName()? + // + // If that's not even reasonable, would a round trip in the /other/ + // direction make more sense? (Call getHostName() for something with + // known IP address; call setHostByName(); verify IP address) + // + // Failing that... is there a plausible way to test getHostName() and + // setHostByName()? Hopefully without putting up a dummy local DNS + // server? + + // monty: If you don't control the DNS server or the DNS configuration + // for the test point then, no, none of these will necessarily be + // reliable and may start to fail at any time. Forward translation + // is subject to CNAME records and round-robin address assignment. + // Reverse lookup is 1-to-many and is more and more likely to have + // nothing to do with the forward translation. + // + // So the test is increasingly meaningless on a real network. + + std::string hostStr = "lindenlab.com"; + LLHost host; + host.setHostByName(hostStr); + + // reverse DNS will likely result in appending of some + // sub-domain to the main hostname. so look for + // the main domain name and not do the exact compare + + std::string hostname = host.getHostName(); + try + { + ensure("getHostName failed", hostname.find(hostStr) != std::string::npos); + } + catch (const std::exception&) + { + std::cerr << "set '" << hostStr << "'; reported '" << hostname << "'" << std::endl; + throw; + } + } + +// setHostByName for dotted IP + template<> template<> + void host_object::test<10>() + { + std::string hostStr = "64.233.167.99"; + LLHost host; + host.setHostByName(hostStr); + ensure("SetHostByName for dotted IP Address failed", host.getAddress() == ip_string_to_u32(hostStr.c_str())); + } + + template<> template<> + void host_object::test<11>() + { + LLHost host1(0xc098017d, 8080); + LLHost host2 = host1; + ensure("Both IP addresses are not same", (host1.getAddress() == host2.getAddress())); + ensure("Both port numbers are not same", (host1.getPort() == host2.getPort())); + } + + template<> template<> + void host_object::test<12>() + { + LLHost host1("192.168.1.1", 8080); + std::string str1 = "192.168.1.1:8080"; + std::ostringstream stream; + stream << host1; + ensure("Operator << failed", ( stream.str()== str1)); + + // There is no istream >> llhost operator. + //std::istringstream is(stream.str()); + //LLHost host2; + //is >> host2; + //ensure("Operator >> failed. Not compatible with <<", host1 == host2); + } + + // operators ==, !=, < + template<> template<> + void host_object::test<13>() + { + U32 ip_addr = 0xc098017d; + U32 port = 8080; + LLHost host1(ip_addr, port); + LLHost host2(ip_addr, port); + ensure("operator== failed", host1 == host2); + + // change port + host2.setPort(7070); + ensure("operator!= failed", host1 != host2); + + // set port back to 8080 and change IP address now + host2.setPort(8080); + host2.setAddress(ip_addr+10); + ensure("operator!= failed", host1 != host2); + + ensure("operator< failed", host1 < host2); + + // set IP address back to same value and change port + host2.setAddress(ip_addr); + host2.setPort(host1.getPort() + 10); + ensure("operator< failed", host1 < host2); + } + + // invalid ip address string + template<> template<> + void host_object::test<14>() + { + LLHost host1("10.0.1.2", 6143); + ensure("10.0.1.2 should be a valid address", host1.isOk()); + + LLHost host2("booger-brains", 6143); + ensure("booger-brains should be an invalid ip addess", !host2.isOk()); + + LLHost host3("255.255.255.255", 6143); + ensure("255.255.255.255 should be valid broadcast address", host3.isOk()); + } } diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp index 78faa66a0d..1881144d3e 100644 --- a/indra/llmessage/tests/llhttpclient_test.cpp +++ b/indra/llmessage/tests/llhttpclient_test.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llhttpclient_test.cpp * @brief Testing the HTTP client classes. * * $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$ */ @@ -47,265 +47,265 @@ namespace tut { - struct HTTPClientTestData - { - public: - HTTPClientTestData(): - PORT(LLStringUtil::getenv("PORT")), - // Turning NULL PORT into empty string doesn't make things work; - // that's just to keep this initializer from blowing up. We test - // PORT separately in the constructor body. - local_server(STRINGIZE("http://127.0.0.1:" << PORT << "/")) - { - ensure("Set environment variable PORT to local test server port", !PORT.empty()); - apr_pool_create(&mPool, NULL); - LLCurl::initClass(false); - mClientPump = new LLPumpIO(mPool); - - LLHTTPClient::setPump(*mClientPump); - } - - ~HTTPClientTestData() - { - delete mClientPump; - SUBSYSTEM_CLEANUP(LLProxy); - apr_pool_destroy(mPool); - } - - void runThePump(float timeout = 100.0f) - { - LLTimer timer; - timer.setTimerExpirySec(timeout); - - while(!mSawCompleted && !mSawCompletedHeader && !timer.hasExpired()) - { - LLFrameTimer::updateFrameTime(); - if (mClientPump) - { - mClientPump->pump(); - mClientPump->callback(); - } - } - } - - const std::string PORT; - const std::string local_server; - - private: - apr_pool_t* mPool; - LLPumpIO* mClientPump; - - protected: - void ensureStatusOK() - { - if (mSawError) - { - std::string msg = - llformat("httpFailure() called when not expected, status %d", - mStatus); - fail(msg); - } - } - - void ensureStatusError() - { - if (!mSawError) - { - fail("httpFailure() wasn't called"); - } - } - - LLSD getResult() - { - return mResult; - } - LLSD getHeader() - { - return mHeader; - } - - protected: - bool mSawError; - U32 mStatus; - std::string mReason; - bool mSawCompleted; - bool mSawCompletedHeader; - LLSD mResult; - LLSD mHeader; - bool mResultDeleted; - - class Result : public LLHTTPClient::Responder - { - protected: - Result(HTTPClientTestData& client) - : mClient(client) - { - } - - public: - static Result* build(HTTPClientTestData& client) - { - return new Result(client); - } - - ~Result() - { - mClient.mResultDeleted = true; - } - - protected: - virtual void httpFailure() - { - mClient.mSawError = true; - mClient.mStatus = getStatus(); - mClient.mReason = getReason(); - } - - virtual void httpSuccess() - { - mClient.mResult = getContent(); - } - - virtual void httpCompleted() - { - LLHTTPClient::Responder::httpCompleted(); - - mClient.mSawCompleted = true; - mClient.mSawCompletedHeader = true; - mClient.mHeader = getResponseHeaders(); - } - - private: - HTTPClientTestData& mClient; - }; - - friend class Result; - - protected: - LLHTTPClient::ResponderPtr newResult() - { - mSawError = false; - mStatus = 0; - mSawCompleted = false; - mSawCompletedHeader = false; - mResult.clear(); - mHeader.clear(); - mResultDeleted = false; - - return Result::build(*this); - } - }; - - - typedef test_group<HTTPClientTestData> HTTPClientTestGroup; - typedef HTTPClientTestGroup::object HTTPClientTestObject; - HTTPClientTestGroup httpClientTestGroup("http_client"); - - template<> template<> - void HTTPClientTestObject::test<1>() - { - LLHTTPClient::get(local_server, newResult()); - runThePump(); - ensureStatusOK(); - ensure("result object wasn't destroyed", mResultDeleted); - } - - template<> template<> - void HTTPClientTestObject::test<2>() - { - // Please nobody listen on this particular port... - LLHTTPClient::get("http://127.0.0.1:7950", newResult()); - runThePump(); - ensureStatusError(); - } - - template<> template<> - void HTTPClientTestObject::test<3>() - { - LLSD sd; - - sd["list"][0]["one"] = 1; - sd["list"][0]["two"] = 2; - sd["list"][1]["three"] = 3; - sd["list"][1]["four"] = 4; - - LLHTTPClient::post(local_server + "web/echo", sd, newResult()); - runThePump(); - ensureStatusOK(); - ensure_equals("echoed result matches", getResult(), sd); - } - - template<> template<> - void HTTPClientTestObject::test<4>() - { - LLSD sd; - - sd["message"] = "This is my test message."; - - LLHTTPClient::put(local_server + "test/storage", sd, newResult()); - runThePump(); - ensureStatusOK(); - - LLHTTPClient::get(local_server + "test/storage", newResult()); - runThePump(); - ensureStatusOK(); - ensure_equals("echoed result matches", getResult(), sd); - - } - - template<> template<> - void HTTPClientTestObject::test<5>() - { - LLSD sd; - sd["status"] = 543; - sd["reason"] = "error for testing"; - - LLHTTPClient::post(local_server + "test/error", sd, newResult()); - runThePump(); - ensureStatusError(); - ensure_contains("reason", mReason, sd["reason"]); - } - - template<> template<> - void HTTPClientTestObject::test<6>() - { - const F32 timeout = 1.0f; - LLHTTPClient::get(local_server + "test/timeout", newResult(), LLSD(), timeout); - runThePump(timeout * 5.0f); - ensureStatusError(); - ensure_equals("reason", mReason, "STATUS_EXPIRED"); - } - - template<> template<> - void HTTPClientTestObject::test<7>() - { - LLHTTPClient::get(local_server, newResult()); - runThePump(); - ensureStatusOK(); - LLSD expected = getResult(); - - LLSD result; - result = LLHTTPClient::blockingGet(local_server); - LLSD body = result["body"]; - ensure_equals("echoed result matches", body.size(), expected.size()); - } - template<> template<> - void HTTPClientTestObject::test<8>() - { - // This is testing for the presence of the Header in the returned results - // from an HTTP::get call. - LLHTTPClient::get(local_server, newResult()); - runThePump(); - ensureStatusOK(); - LLSD header = getHeader(); - ensure("got a header", ! header.emptyMap().asBoolean()); - } - template<> template<> - void HTTPClientTestObject::test<9>() - { - LLHTTPClient::head(local_server, newResult()); - runThePump(); - ensureStatusOK(); - ensure("result object wasn't destroyed", mResultDeleted); - } + struct HTTPClientTestData + { + public: + HTTPClientTestData(): + PORT(LLStringUtil::getenv("PORT")), + // Turning NULL PORT into empty string doesn't make things work; + // that's just to keep this initializer from blowing up. We test + // PORT separately in the constructor body. + local_server(STRINGIZE("http://127.0.0.1:" << PORT << "/")) + { + ensure("Set environment variable PORT to local test server port", !PORT.empty()); + apr_pool_create(&mPool, NULL); + LLCurl::initClass(false); + mClientPump = new LLPumpIO(mPool); + + LLHTTPClient::setPump(*mClientPump); + } + + ~HTTPClientTestData() + { + delete mClientPump; + SUBSYSTEM_CLEANUP(LLProxy); + apr_pool_destroy(mPool); + } + + void runThePump(float timeout = 100.0f) + { + LLTimer timer; + timer.setTimerExpirySec(timeout); + + while(!mSawCompleted && !mSawCompletedHeader && !timer.hasExpired()) + { + LLFrameTimer::updateFrameTime(); + if (mClientPump) + { + mClientPump->pump(); + mClientPump->callback(); + } + } + } + + const std::string PORT; + const std::string local_server; + + private: + apr_pool_t* mPool; + LLPumpIO* mClientPump; + + protected: + void ensureStatusOK() + { + if (mSawError) + { + std::string msg = + llformat("httpFailure() called when not expected, status %d", + mStatus); + fail(msg); + } + } + + void ensureStatusError() + { + if (!mSawError) + { + fail("httpFailure() wasn't called"); + } + } + + LLSD getResult() + { + return mResult; + } + LLSD getHeader() + { + return mHeader; + } + + protected: + bool mSawError; + U32 mStatus; + std::string mReason; + bool mSawCompleted; + bool mSawCompletedHeader; + LLSD mResult; + LLSD mHeader; + bool mResultDeleted; + + class Result : public LLHTTPClient::Responder + { + protected: + Result(HTTPClientTestData& client) + : mClient(client) + { + } + + public: + static Result* build(HTTPClientTestData& client) + { + return new Result(client); + } + + ~Result() + { + mClient.mResultDeleted = true; + } + + protected: + virtual void httpFailure() + { + mClient.mSawError = true; + mClient.mStatus = getStatus(); + mClient.mReason = getReason(); + } + + virtual void httpSuccess() + { + mClient.mResult = getContent(); + } + + virtual void httpCompleted() + { + LLHTTPClient::Responder::httpCompleted(); + + mClient.mSawCompleted = true; + mClient.mSawCompletedHeader = true; + mClient.mHeader = getResponseHeaders(); + } + + private: + HTTPClientTestData& mClient; + }; + + friend class Result; + + protected: + LLHTTPClient::ResponderPtr newResult() + { + mSawError = false; + mStatus = 0; + mSawCompleted = false; + mSawCompletedHeader = false; + mResult.clear(); + mHeader.clear(); + mResultDeleted = false; + + return Result::build(*this); + } + }; + + + typedef test_group<HTTPClientTestData> HTTPClientTestGroup; + typedef HTTPClientTestGroup::object HTTPClientTestObject; + HTTPClientTestGroup httpClientTestGroup("http_client"); + + template<> template<> + void HTTPClientTestObject::test<1>() + { + LLHTTPClient::get(local_server, newResult()); + runThePump(); + ensureStatusOK(); + ensure("result object wasn't destroyed", mResultDeleted); + } + + template<> template<> + void HTTPClientTestObject::test<2>() + { + // Please nobody listen on this particular port... + LLHTTPClient::get("http://127.0.0.1:7950", newResult()); + runThePump(); + ensureStatusError(); + } + + template<> template<> + void HTTPClientTestObject::test<3>() + { + LLSD sd; + + sd["list"][0]["one"] = 1; + sd["list"][0]["two"] = 2; + sd["list"][1]["three"] = 3; + sd["list"][1]["four"] = 4; + + LLHTTPClient::post(local_server + "web/echo", sd, newResult()); + runThePump(); + ensureStatusOK(); + ensure_equals("echoed result matches", getResult(), sd); + } + + template<> template<> + void HTTPClientTestObject::test<4>() + { + LLSD sd; + + sd["message"] = "This is my test message."; + + LLHTTPClient::put(local_server + "test/storage", sd, newResult()); + runThePump(); + ensureStatusOK(); + + LLHTTPClient::get(local_server + "test/storage", newResult()); + runThePump(); + ensureStatusOK(); + ensure_equals("echoed result matches", getResult(), sd); + + } + + template<> template<> + void HTTPClientTestObject::test<5>() + { + LLSD sd; + sd["status"] = 543; + sd["reason"] = "error for testing"; + + LLHTTPClient::post(local_server + "test/error", sd, newResult()); + runThePump(); + ensureStatusError(); + ensure_contains("reason", mReason, sd["reason"]); + } + + template<> template<> + void HTTPClientTestObject::test<6>() + { + const F32 timeout = 1.0f; + LLHTTPClient::get(local_server + "test/timeout", newResult(), LLSD(), timeout); + runThePump(timeout * 5.0f); + ensureStatusError(); + ensure_equals("reason", mReason, "STATUS_EXPIRED"); + } + + template<> template<> + void HTTPClientTestObject::test<7>() + { + LLHTTPClient::get(local_server, newResult()); + runThePump(); + ensureStatusOK(); + LLSD expected = getResult(); + + LLSD result; + result = LLHTTPClient::blockingGet(local_server); + LLSD body = result["body"]; + ensure_equals("echoed result matches", body.size(), expected.size()); + } + template<> template<> + void HTTPClientTestObject::test<8>() + { + // This is testing for the presence of the Header in the returned results + // from an HTTP::get call. + LLHTTPClient::get(local_server, newResult()); + runThePump(); + ensureStatusOK(); + LLSD header = getHeader(); + ensure("got a header", ! header.emptyMap().asBoolean()); + } + template<> template<> + void HTTPClientTestObject::test<9>() + { + LLHTTPClient::head(local_server, newResult()); + runThePump(); + ensureStatusOK(); + ensure("result object wasn't destroyed", mResultDeleted); + } } diff --git a/indra/llmessage/tests/llhttpnode_stub.cpp b/indra/llmessage/tests/llhttpnode_stub.cpp index 479a256bdd..d896084021 100644 --- a/indra/llmessage/tests/llhttpnode_stub.cpp +++ b/indra/llmessage/tests/llhttpnode_stub.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llhttpnode_stub.cpp * @brief STUB Implementation of classes for generic HTTP/LSL/REST handling. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * + * * Second Life Viewer Source Code * Copyright (c) 2006-2009, 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$ */ @@ -69,28 +69,28 @@ const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const { return N LLHTTPNode::Response::~Response(){} void LLHTTPNode::Response::notFound(const std::string& message) { - status(404, message); + status(404, message); } void LLHTTPNode::Response::notFound() { - status(404, "Not Found"); + status(404, "Not Found"); } void LLHTTPNode::Response::methodNotAllowed() { - status(405, "Method Not Allowed"); + status(405, "Method Not Allowed"); } void LLHTTPNode::Response::statusUnknownError(S32 code) { - status(code, "Unknown Error"); + status(code, "Unknown Error"); } void LLHTTPNode::Response::status(S32 code, const std::string& message) { } -void LLHTTPNode::Response::addHeader(const std::string& name,const std::string& value) +void LLHTTPNode::Response::addHeader(const std::string& name,const std::string& value) { - mHeaders[name] = value; + mHeaders[name] = value; } void LLHTTPNode::describe(Description& desc) const { } diff --git a/indra/llmessage/tests/llnamevalue_test.cpp b/indra/llmessage/tests/llnamevalue_test.cpp index 8902fdd2e8..f77cd102f4 100644 --- a/indra/llmessage/tests/llnamevalue_test.cpp +++ b/indra/llmessage/tests/llnamevalue_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llnamevalue_test.cpp * @author Adroit * @date 2007-02 @@ -7,21 +7,21 @@ * $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$ */ @@ -41,366 +41,366 @@ namespace tut { - struct namevalue_test - { - namevalue_test() - { - } - }; - typedef test_group<namevalue_test> namevalue_t; - typedef namevalue_t::object namevalue_object_t; - tut::namevalue_t tut_namevalue("LLNameValue"); - - - template<> template<> - void namevalue_object_t::test<1>() - { - // LLNameValue() - LLNameValue nValue; - ensure("mName should have been NULL", nValue.mName == NULL); - ensure("getTypeEnum failed",nValue.getTypeEnum() == NVT_NULL); - ensure("getClassEnum failed",nValue.getClassEnum() == NVC_NULL); - ensure("getSendtoEnum failed",nValue.getSendtoEnum() == NVS_NULL); - - LLNameValue nValue1(" SecondLife ASSET RW SIM 232324343"); - - } - - // LLNameValue(const char* data); - // LLNameValue(const char* name, const char* data, const char* type, const char* nvclass, const char* nvsendto, - // TNameValueCallback nvcb = NULL, void** user_data = NULL); - template<> template<> - void namevalue_object_t::test<2>() - { - LLNameValue nValue(" SecondLife ASSET RW S 232324343"); - ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife"))); - ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_ASSET); - ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE); - ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM); - ensure("getString failed", (0==strcmp(nValue.getAsset(),"232324343"))); - ensure("sendToData or sendToViewer failed", !nValue.sendToData() && !nValue.sendToViewer()); - - LLNameValue nValue1("\n\r SecondLife_1 STRING READ_WRITE SIM 232324343"); - ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife_1"))); - ensure("1. getTypeEnum failed", nValue1.getTypeEnum() == NVT_STRING); - ensure("1. getClassEnum failed", nValue1.getClassEnum() == NVC_READ_WRITE); - ensure("1. getSendtoEnum failed", nValue1.getSendtoEnum() == NVS_SIM); - ensure("1. getString failed", (0==strcmp(nValue1.getString(),"232324343"))); - ensure("1. sendToData or sendToViewer failed", !nValue1.sendToData() && !nValue1.sendToViewer()); - - LLNameValue nValue2("SecondLife", "23.5", "F32", "R", "DS"); - ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32); - ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY); - ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_DATA_SIM); - ensure("2. getF32 failed", *nValue2.getF32() == 23.5f); - ensure("2. sendToData or sendToViewer failed", nValue2.sendToData() && !nValue2.sendToViewer()); - - LLNameValue nValue3("SecondLife", "-43456787", "S32", "READ_ONLY", "SIM_SPACE"); - ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32); - ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY); - ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_DATA_SIM); - ensure("3. getS32 failed", *nValue3.getS32() == -43456787); - ensure("sendToData or sendToViewer failed", nValue3.sendToData() && !nValue3.sendToViewer()); - - LLNameValue nValue4("SecondLife", "<1.0, 2.0, 3.0>", "VEC3", "RW", "SV"); - LLVector3 llvec4(1.0, 2.0, 3.0); - ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3); - ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE); - ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM_VIEWER); - ensure("4. getVec3 failed", *nValue4.getVec3() == llvec4); - ensure("4. sendToData or sendToViewer failed", !nValue4.sendToData() && nValue4.sendToViewer()); - - LLNameValue nValue5("SecondLife", "-1.0, 2.4, 3", "VEC3", "RW", "SIM_VIEWER"); - LLVector3 llvec5(-1.0f, 2.4f, 3); - ensure("5. getTypeEnum failed", nValue5.getTypeEnum() == NVT_VEC3); - ensure("5. getClassEnum failed", nValue5.getClassEnum() == NVC_READ_WRITE); - ensure("5. getSendtoEnum failed", nValue5.getSendtoEnum() == NVS_SIM_VIEWER); - ensure("5. getVec3 failed", *nValue5.getVec3() == llvec5); - ensure("5. sendToData or sendToViewer failed", !nValue5.sendToData() && nValue5.sendToViewer()); - - LLNameValue nValue6("SecondLife", "89764323", "U32", "RW", "DSV"); - ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32); - ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE); - ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_DATA_SIM_VIEWER); - ensure("6. getU32 failed", *nValue6.getU32() == 89764323); - ensure("6. sendToData or sendToViewer failed", nValue6.sendToData() && nValue6.sendToViewer()); - - LLNameValue nValue7("SecondLife", "89764323323232", "U64", "RW", "SIM_SPACE_VIEWER"); - U64 u64_7 = U64L(89764323323232); - ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64); - ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE); - ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_DATA_SIM_VIEWER); - ensure("7. getU32 failed", *nValue7.getU64() == u64_7); - ensure("7. sendToData or sendToViewer failed", nValue7.sendToData() && nValue7.sendToViewer()); - } - - // LLNameValue(const char* name, const char* data, const char* type, const char* nvclass, - // TNameValueCallback nvcb = NULL, void** user_data = NULL); - template<> template<> - void namevalue_object_t::test<3>() - { - LLNameValue nValue("SecondLife", "232324343", "ASSET", "READ_WRITE"); - ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife"))); - ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_ASSET); - ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE); - ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM); - ensure("getString failed", (0==strcmp(nValue.getAsset(),"232324343"))); - - LLNameValue nValue1("SecondLife", "232324343", "STRING", "READ_WRITE"); - ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife"))); - ensure("1. getTypeEnum failed", nValue1.getTypeEnum() == NVT_STRING); - ensure("1. getClassEnum failed", nValue1.getClassEnum() == NVC_READ_WRITE); - ensure("1. getSendtoEnum failed", nValue1.getSendtoEnum() == NVS_SIM); - ensure("1. getString failed", (0==strcmp(nValue1.getString(),"232324343"))); - - LLNameValue nValue2("SecondLife", "23.5", "F32", "R"); - ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32); - ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY); - ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_SIM); - ensure("2. getF32 failed", *nValue2.getF32() == 23.5f); - - LLNameValue nValue3("SecondLife", "-43456787", "S32", "READ_ONLY"); - ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32); - ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY); - ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_SIM); - ensure("3. getS32 failed", *nValue3.getS32() == -43456787); - - LLNameValue nValue4("SecondLife", "<1.0, 2.0, 3.0>", "VEC3", "RW"); - LLVector3 llvec4(1.0, 2.0, 3.0); - ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3); - ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE); - ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM); - ensure("4. getVec3 failed", *nValue4.getVec3() == llvec4); - - LLNameValue nValue5("SecondLife", "-1.0, 2.4, 3", "VEC3", "RW"); - LLVector3 llvec5(-1.0f, 2.4f, 3); - ensure("5. getTypeEnum failed", nValue5.getTypeEnum() == NVT_VEC3); - ensure("5. getClassEnum failed", nValue5.getClassEnum() == NVC_READ_WRITE); - ensure("5. getSendtoEnum failed", nValue5.getSendtoEnum() == NVS_SIM); - ensure("5. getVec3 failed", *nValue5.getVec3() == llvec5); - - LLNameValue nValue6("SecondLife", "89764323", "U32", "RW"); - ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32); - ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE); - ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_SIM); - ensure("6. getU32 failed", *nValue6.getU32() == 89764323); - - LLNameValue nValue7("SecondLife", "89764323323232", "U64", "RW"); - U64 u64_7 = U64L(89764323323232); - ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64); - ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE); - ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_SIM); - ensure("7. getU32 failed", *nValue7.getU64() == u64_7); - } - - // LLNameValue(const char* name, const char* type, const char* nvclass, - // TNameValueCallback nvcb = NULL, void** user_data = NULL); - template<> template<> - void namevalue_object_t::test<4>() - { - LLNameValue nValue("SecondLife", "STRING", "READ_WRITE"); - ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife"))); - ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_STRING); - ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE); - ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM); - - LLNameValue nValue1("SecondLife", "ASSET", "READ_WRITE"); - ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife"))); - ensure("1. getTypeEnum for RW failed", nValue1.getTypeEnum() == NVT_ASSET); - ensure("1. getClassEnum for RW failed", nValue1.getClassEnum() == NVC_READ_WRITE); - ensure("1. getSendtoEnum for RW failed", nValue1.getSendtoEnum() == NVS_SIM); - - LLNameValue nValue2("SecondLife", "F32", "READ_ONLY"); - ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32); - ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY); - ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_SIM); - - LLNameValue nValue3("SecondLife", "S32", "READ_ONLY"); - ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32); - ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY); - ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_SIM); - - LLNameValue nValue4("SecondLife", "VEC3", "READ_WRITE"); - ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3); - ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE); - ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM); - - LLNameValue nValue6("SecondLife", "U32", "READ_WRITE"); - ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32); - ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE); - ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_SIM); - - LLNameValue nValue7("SecondLife", "U64", "READ_WRITE"); - ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64); - ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE); - ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_SIM); - } - - template<> template<> - void namevalue_object_t::test<5>() - { - LLNameValue nValue("SecondLife", "This is a test", "STRING", "RW", "SIM"); - - ensure("getString failed", (0 == strcmp(nValue.getString(),"This is a test"))); - } - - template<> template<> - void namevalue_object_t::test<6>() - { - LLNameValue nValue("SecondLife", "This is a test", "ASSET", "RW", "S"); - ensure("getAsset failed", (0 == strcmp(nValue.getAsset(),"This is a test"))); - } - - template<> template<> - void namevalue_object_t::test<7>() - { - LLNameValue nValue("SecondLife", "555555", "F32", "RW", "SIM"); - - ensure("getF32 failed",*nValue.getF32() == 555555.f); - } - - template<> template<> - void namevalue_object_t::test<8>() - { - LLNameValue nValue("SecondLife", "-5555", "S32", "RW", "SIM"); - - ensure("getS32 failed", *nValue.getS32() == -5555); - - S32 sVal = 0x7FFFFFFF; - nValue.setS32(sVal); - ensure("getS32 failed", *nValue.getS32() == sVal); - - sVal = -0x7FFFFFFF; - nValue.setS32(sVal); - ensure("getS32 failed", *nValue.getS32() == sVal); - - sVal = 0; - nValue.setS32(sVal); - ensure("getS32 failed", *nValue.getS32() == sVal); - } - - template<> template<> - void namevalue_object_t::test<9>() - { - LLNameValue nValue("SecondLife", "<-3, 2, 1>", "VEC3", "RW", "SIM"); - LLVector3 vecExpected(-3, 2, 1); - LLVector3 vec; - nValue.getVec3(vec); - ensure("getVec3 failed", vec == vecExpected); - } - - template<> template<> - void namevalue_object_t::test<10>() - { - LLNameValue nValue("SecondLife", "12345678", "U32", "RW", "SIM"); - - ensure("getU32 failed",*nValue.getU32() == 12345678); - - U32 val = 0xFFFFFFFF; - nValue.setU32(val); - ensure("U32 max", *nValue.getU32() == val); - - val = 0; - nValue.setU32(val); - ensure("U32 min", *nValue.getU32() == val); - } - - template<> template<> - void namevalue_object_t::test<11>() - { - //skip_fail("incomplete support for U64."); - LLNameValue nValue("SecondLife", "44444444444", "U64", "RW", "SIM"); - - ensure("getU64 failed",*nValue.getU64() == U64L(44444444444)); - - // there is no LLNameValue::setU64() - } - - - template<> template<> - void namevalue_object_t::test<12>() - { - //skip_fail("incomplete support for U64."); - LLNameValue nValue("SecondLife U64 RW DSV 44444444444"); - std::string ret_str = nValue.printNameValue(); - - ensure_equals("1:printNameValue failed",ret_str,"SecondLife U64 RW DSV 44444444444"); - - LLNameValue nValue1(ret_str.c_str()); - ensure_equals("Serialization of printNameValue failed", *nValue.getU64(), *nValue1.getU64()); - } - - template<> template<> - void namevalue_object_t::test<13>() - { - LLNameValue nValue("SecondLife STRING RW DSV 44444444444"); - std::string ret_str = nValue.printData(); - ensure_equals("1:printData failed",ret_str,"44444444444"); - - LLNameValue nValue1("SecondLife S32 RW DSV 44444"); - ret_str = nValue1.printData(); - ensure_equals("2:printData failed",ret_str,"44444"); - } - - template<> template<> - void namevalue_object_t::test<14>() - { - LLNameValue nValue("SecodLife STRING RW SIM 22222"); - std::ostringstream stream1,stream2,stream3, stream4, stream5; - stream1 << nValue; - ensure_equals("STRING << failed",stream1.str(),"22222"); - - LLNameValue nValue1("SecodLife F32 RW SIM 22222"); - stream2 << nValue1; - ensure_equals("F32 << failed",stream2.str(),"22222"); - - LLNameValue nValue2("SecodLife S32 RW SIM 22222"); - stream3<< nValue2; - ensure_equals("S32 << failed",stream3.str(),"22222"); - - LLNameValue nValue3("SecodLife U32 RW SIM 122222"); - stream4<< nValue3; - ensure_equals("U32 << failed",stream4.str(),"122222"); - - // I don't think we use U64 name value pairs. JC - //skip_fail("incomplete support for U64."); - //LLNameValue nValue4("SecodLife U64 RW SIM 22222"); - //stream5<< nValue4; - //ensure("U64 << failed",0 == strcmp((stream5.str()).c_str(),"22222")); - } - - template<> template<> - void namevalue_object_t::test<15>() - { - LLNameValue nValue("SecondLife", "This is a test", "ASSET", "R", "S"); - - ensure("getAsset failed", (0 == strcmp(nValue.getAsset(),"This is a test"))); - // this should not have updated as it is read only. - nValue.setAsset("New Value should not be updated"); - ensure("setAsset on ReadOnly failed", (0 == strcmp(nValue.getAsset(),"This is a test"))); - - LLNameValue nValue1("SecondLife", "1234", "U32", "R", "S"); - // this should not have updated as it is read only. - nValue1.setU32(4567); - ensure("setU32 on ReadOnly failed", *nValue1.getU32() == 1234); - - LLNameValue nValue2("SecondLife", "1234", "S32", "R", "S"); - // this should not have updated as it is read only. - nValue2.setS32(4567); - ensure("setS32 on ReadOnly failed", *nValue2.getS32() == 1234); - - LLNameValue nValue3("SecondLife", "1234", "F32", "R", "S"); - // this should not have updated as it is read only. - nValue3.setF32(4567); - ensure("setF32 on ReadOnly failed", *nValue3.getF32() == 1234); - - LLNameValue nValue4("SecondLife", "<1,2,3>", "VEC3", "R", "S"); - // this should not have updated as it is read only. - LLVector3 vec(4,5,6); - nValue3.setVec3(vec); - LLVector3 vec1(1,2,3); - ensure("setVec3 on ReadOnly failed", *nValue4.getVec3() == vec1); - - // cant test for U64 as no set64 exists nor any operators support U64 type - } + struct namevalue_test + { + namevalue_test() + { + } + }; + typedef test_group<namevalue_test> namevalue_t; + typedef namevalue_t::object namevalue_object_t; + tut::namevalue_t tut_namevalue("LLNameValue"); + + + template<> template<> + void namevalue_object_t::test<1>() + { + // LLNameValue() + LLNameValue nValue; + ensure("mName should have been NULL", nValue.mName == NULL); + ensure("getTypeEnum failed",nValue.getTypeEnum() == NVT_NULL); + ensure("getClassEnum failed",nValue.getClassEnum() == NVC_NULL); + ensure("getSendtoEnum failed",nValue.getSendtoEnum() == NVS_NULL); + + LLNameValue nValue1(" SecondLife ASSET RW SIM 232324343"); + + } + + // LLNameValue(const char* data); + // LLNameValue(const char* name, const char* data, const char* type, const char* nvclass, const char* nvsendto, + // TNameValueCallback nvcb = NULL, void** user_data = NULL); + template<> template<> + void namevalue_object_t::test<2>() + { + LLNameValue nValue(" SecondLife ASSET RW S 232324343"); + ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife"))); + ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_ASSET); + ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE); + ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM); + ensure("getString failed", (0==strcmp(nValue.getAsset(),"232324343"))); + ensure("sendToData or sendToViewer failed", !nValue.sendToData() && !nValue.sendToViewer()); + + LLNameValue nValue1("\n\r SecondLife_1 STRING READ_WRITE SIM 232324343"); + ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife_1"))); + ensure("1. getTypeEnum failed", nValue1.getTypeEnum() == NVT_STRING); + ensure("1. getClassEnum failed", nValue1.getClassEnum() == NVC_READ_WRITE); + ensure("1. getSendtoEnum failed", nValue1.getSendtoEnum() == NVS_SIM); + ensure("1. getString failed", (0==strcmp(nValue1.getString(),"232324343"))); + ensure("1. sendToData or sendToViewer failed", !nValue1.sendToData() && !nValue1.sendToViewer()); + + LLNameValue nValue2("SecondLife", "23.5", "F32", "R", "DS"); + ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32); + ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY); + ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_DATA_SIM); + ensure("2. getF32 failed", *nValue2.getF32() == 23.5f); + ensure("2. sendToData or sendToViewer failed", nValue2.sendToData() && !nValue2.sendToViewer()); + + LLNameValue nValue3("SecondLife", "-43456787", "S32", "READ_ONLY", "SIM_SPACE"); + ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32); + ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY); + ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_DATA_SIM); + ensure("3. getS32 failed", *nValue3.getS32() == -43456787); + ensure("sendToData or sendToViewer failed", nValue3.sendToData() && !nValue3.sendToViewer()); + + LLNameValue nValue4("SecondLife", "<1.0, 2.0, 3.0>", "VEC3", "RW", "SV"); + LLVector3 llvec4(1.0, 2.0, 3.0); + ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3); + ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE); + ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM_VIEWER); + ensure("4. getVec3 failed", *nValue4.getVec3() == llvec4); + ensure("4. sendToData or sendToViewer failed", !nValue4.sendToData() && nValue4.sendToViewer()); + + LLNameValue nValue5("SecondLife", "-1.0, 2.4, 3", "VEC3", "RW", "SIM_VIEWER"); + LLVector3 llvec5(-1.0f, 2.4f, 3); + ensure("5. getTypeEnum failed", nValue5.getTypeEnum() == NVT_VEC3); + ensure("5. getClassEnum failed", nValue5.getClassEnum() == NVC_READ_WRITE); + ensure("5. getSendtoEnum failed", nValue5.getSendtoEnum() == NVS_SIM_VIEWER); + ensure("5. getVec3 failed", *nValue5.getVec3() == llvec5); + ensure("5. sendToData or sendToViewer failed", !nValue5.sendToData() && nValue5.sendToViewer()); + + LLNameValue nValue6("SecondLife", "89764323", "U32", "RW", "DSV"); + ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32); + ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE); + ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_DATA_SIM_VIEWER); + ensure("6. getU32 failed", *nValue6.getU32() == 89764323); + ensure("6. sendToData or sendToViewer failed", nValue6.sendToData() && nValue6.sendToViewer()); + + LLNameValue nValue7("SecondLife", "89764323323232", "U64", "RW", "SIM_SPACE_VIEWER"); + U64 u64_7 = U64L(89764323323232); + ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64); + ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE); + ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_DATA_SIM_VIEWER); + ensure("7. getU32 failed", *nValue7.getU64() == u64_7); + ensure("7. sendToData or sendToViewer failed", nValue7.sendToData() && nValue7.sendToViewer()); + } + + // LLNameValue(const char* name, const char* data, const char* type, const char* nvclass, + // TNameValueCallback nvcb = NULL, void** user_data = NULL); + template<> template<> + void namevalue_object_t::test<3>() + { + LLNameValue nValue("SecondLife", "232324343", "ASSET", "READ_WRITE"); + ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife"))); + ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_ASSET); + ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE); + ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM); + ensure("getString failed", (0==strcmp(nValue.getAsset(),"232324343"))); + + LLNameValue nValue1("SecondLife", "232324343", "STRING", "READ_WRITE"); + ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife"))); + ensure("1. getTypeEnum failed", nValue1.getTypeEnum() == NVT_STRING); + ensure("1. getClassEnum failed", nValue1.getClassEnum() == NVC_READ_WRITE); + ensure("1. getSendtoEnum failed", nValue1.getSendtoEnum() == NVS_SIM); + ensure("1. getString failed", (0==strcmp(nValue1.getString(),"232324343"))); + + LLNameValue nValue2("SecondLife", "23.5", "F32", "R"); + ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32); + ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY); + ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_SIM); + ensure("2. getF32 failed", *nValue2.getF32() == 23.5f); + + LLNameValue nValue3("SecondLife", "-43456787", "S32", "READ_ONLY"); + ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32); + ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY); + ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_SIM); + ensure("3. getS32 failed", *nValue3.getS32() == -43456787); + + LLNameValue nValue4("SecondLife", "<1.0, 2.0, 3.0>", "VEC3", "RW"); + LLVector3 llvec4(1.0, 2.0, 3.0); + ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3); + ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE); + ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM); + ensure("4. getVec3 failed", *nValue4.getVec3() == llvec4); + + LLNameValue nValue5("SecondLife", "-1.0, 2.4, 3", "VEC3", "RW"); + LLVector3 llvec5(-1.0f, 2.4f, 3); + ensure("5. getTypeEnum failed", nValue5.getTypeEnum() == NVT_VEC3); + ensure("5. getClassEnum failed", nValue5.getClassEnum() == NVC_READ_WRITE); + ensure("5. getSendtoEnum failed", nValue5.getSendtoEnum() == NVS_SIM); + ensure("5. getVec3 failed", *nValue5.getVec3() == llvec5); + + LLNameValue nValue6("SecondLife", "89764323", "U32", "RW"); + ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32); + ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE); + ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_SIM); + ensure("6. getU32 failed", *nValue6.getU32() == 89764323); + + LLNameValue nValue7("SecondLife", "89764323323232", "U64", "RW"); + U64 u64_7 = U64L(89764323323232); + ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64); + ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE); + ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_SIM); + ensure("7. getU32 failed", *nValue7.getU64() == u64_7); + } + + // LLNameValue(const char* name, const char* type, const char* nvclass, + // TNameValueCallback nvcb = NULL, void** user_data = NULL); + template<> template<> + void namevalue_object_t::test<4>() + { + LLNameValue nValue("SecondLife", "STRING", "READ_WRITE"); + ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife"))); + ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_STRING); + ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE); + ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM); + + LLNameValue nValue1("SecondLife", "ASSET", "READ_WRITE"); + ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife"))); + ensure("1. getTypeEnum for RW failed", nValue1.getTypeEnum() == NVT_ASSET); + ensure("1. getClassEnum for RW failed", nValue1.getClassEnum() == NVC_READ_WRITE); + ensure("1. getSendtoEnum for RW failed", nValue1.getSendtoEnum() == NVS_SIM); + + LLNameValue nValue2("SecondLife", "F32", "READ_ONLY"); + ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32); + ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY); + ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_SIM); + + LLNameValue nValue3("SecondLife", "S32", "READ_ONLY"); + ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32); + ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY); + ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_SIM); + + LLNameValue nValue4("SecondLife", "VEC3", "READ_WRITE"); + ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3); + ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE); + ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM); + + LLNameValue nValue6("SecondLife", "U32", "READ_WRITE"); + ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32); + ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE); + ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_SIM); + + LLNameValue nValue7("SecondLife", "U64", "READ_WRITE"); + ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64); + ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE); + ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_SIM); + } + + template<> template<> + void namevalue_object_t::test<5>() + { + LLNameValue nValue("SecondLife", "This is a test", "STRING", "RW", "SIM"); + + ensure("getString failed", (0 == strcmp(nValue.getString(),"This is a test"))); + } + + template<> template<> + void namevalue_object_t::test<6>() + { + LLNameValue nValue("SecondLife", "This is a test", "ASSET", "RW", "S"); + ensure("getAsset failed", (0 == strcmp(nValue.getAsset(),"This is a test"))); + } + + template<> template<> + void namevalue_object_t::test<7>() + { + LLNameValue nValue("SecondLife", "555555", "F32", "RW", "SIM"); + + ensure("getF32 failed",*nValue.getF32() == 555555.f); + } + + template<> template<> + void namevalue_object_t::test<8>() + { + LLNameValue nValue("SecondLife", "-5555", "S32", "RW", "SIM"); + + ensure("getS32 failed", *nValue.getS32() == -5555); + + S32 sVal = 0x7FFFFFFF; + nValue.setS32(sVal); + ensure("getS32 failed", *nValue.getS32() == sVal); + + sVal = -0x7FFFFFFF; + nValue.setS32(sVal); + ensure("getS32 failed", *nValue.getS32() == sVal); + + sVal = 0; + nValue.setS32(sVal); + ensure("getS32 failed", *nValue.getS32() == sVal); + } + + template<> template<> + void namevalue_object_t::test<9>() + { + LLNameValue nValue("SecondLife", "<-3, 2, 1>", "VEC3", "RW", "SIM"); + LLVector3 vecExpected(-3, 2, 1); + LLVector3 vec; + nValue.getVec3(vec); + ensure("getVec3 failed", vec == vecExpected); + } + + template<> template<> + void namevalue_object_t::test<10>() + { + LLNameValue nValue("SecondLife", "12345678", "U32", "RW", "SIM"); + + ensure("getU32 failed",*nValue.getU32() == 12345678); + + U32 val = 0xFFFFFFFF; + nValue.setU32(val); + ensure("U32 max", *nValue.getU32() == val); + + val = 0; + nValue.setU32(val); + ensure("U32 min", *nValue.getU32() == val); + } + + template<> template<> + void namevalue_object_t::test<11>() + { + //skip_fail("incomplete support for U64."); + LLNameValue nValue("SecondLife", "44444444444", "U64", "RW", "SIM"); + + ensure("getU64 failed",*nValue.getU64() == U64L(44444444444)); + + // there is no LLNameValue::setU64() + } + + + template<> template<> + void namevalue_object_t::test<12>() + { + //skip_fail("incomplete support for U64."); + LLNameValue nValue("SecondLife U64 RW DSV 44444444444"); + std::string ret_str = nValue.printNameValue(); + + ensure_equals("1:printNameValue failed",ret_str,"SecondLife U64 RW DSV 44444444444"); + + LLNameValue nValue1(ret_str.c_str()); + ensure_equals("Serialization of printNameValue failed", *nValue.getU64(), *nValue1.getU64()); + } + + template<> template<> + void namevalue_object_t::test<13>() + { + LLNameValue nValue("SecondLife STRING RW DSV 44444444444"); + std::string ret_str = nValue.printData(); + ensure_equals("1:printData failed",ret_str,"44444444444"); + + LLNameValue nValue1("SecondLife S32 RW DSV 44444"); + ret_str = nValue1.printData(); + ensure_equals("2:printData failed",ret_str,"44444"); + } + + template<> template<> + void namevalue_object_t::test<14>() + { + LLNameValue nValue("SecodLife STRING RW SIM 22222"); + std::ostringstream stream1,stream2,stream3, stream4, stream5; + stream1 << nValue; + ensure_equals("STRING << failed",stream1.str(),"22222"); + + LLNameValue nValue1("SecodLife F32 RW SIM 22222"); + stream2 << nValue1; + ensure_equals("F32 << failed",stream2.str(),"22222"); + + LLNameValue nValue2("SecodLife S32 RW SIM 22222"); + stream3<< nValue2; + ensure_equals("S32 << failed",stream3.str(),"22222"); + + LLNameValue nValue3("SecodLife U32 RW SIM 122222"); + stream4<< nValue3; + ensure_equals("U32 << failed",stream4.str(),"122222"); + + // I don't think we use U64 name value pairs. JC + //skip_fail("incomplete support for U64."); + //LLNameValue nValue4("SecodLife U64 RW SIM 22222"); + //stream5<< nValue4; + //ensure("U64 << failed",0 == strcmp((stream5.str()).c_str(),"22222")); + } + + template<> template<> + void namevalue_object_t::test<15>() + { + LLNameValue nValue("SecondLife", "This is a test", "ASSET", "R", "S"); + + ensure("getAsset failed", (0 == strcmp(nValue.getAsset(),"This is a test"))); + // this should not have updated as it is read only. + nValue.setAsset("New Value should not be updated"); + ensure("setAsset on ReadOnly failed", (0 == strcmp(nValue.getAsset(),"This is a test"))); + + LLNameValue nValue1("SecondLife", "1234", "U32", "R", "S"); + // this should not have updated as it is read only. + nValue1.setU32(4567); + ensure("setU32 on ReadOnly failed", *nValue1.getU32() == 1234); + + LLNameValue nValue2("SecondLife", "1234", "S32", "R", "S"); + // this should not have updated as it is read only. + nValue2.setS32(4567); + ensure("setS32 on ReadOnly failed", *nValue2.getS32() == 1234); + + LLNameValue nValue3("SecondLife", "1234", "F32", "R", "S"); + // this should not have updated as it is read only. + nValue3.setF32(4567); + ensure("setF32 on ReadOnly failed", *nValue3.getF32() == 1234); + + LLNameValue nValue4("SecondLife", "<1,2,3>", "VEC3", "R", "S"); + // this should not have updated as it is read only. + LLVector3 vec(4,5,6); + nValue3.setVec3(vec); + LLVector3 vec1(1,2,3); + ensure("setVec3 on ReadOnly failed", *nValue4.getVec3() == vec1); + + // cant test for U64 as no set64 exists nor any operators support U64 type + } } diff --git a/indra/llmessage/tests/llpartdata_test.cpp b/indra/llmessage/tests/llpartdata_test.cpp index de81e0bbb2..c517232bcc 100644 --- a/indra/llmessage/tests/llpartdata_test.cpp +++ b/indra/llmessage/tests/llpartdata_test.cpp @@ -7,21 +7,21 @@ * $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$ */ @@ -39,116 +39,116 @@ namespace tut { - //bunch of sniffed data that *should* be a valid particle system - static U8 msg[] = { - 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x80, 0x00, 0x80, - 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x5e, 0x12, 0x0b, 0xa1, 0x58, 0x05, 0xdc, 0x57, 0x66, - 0xb7, 0xf5, 0xac, 0x4b, 0xd1, 0x8f, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, 0x00, 0x0a, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7e, 0xc6, 0x81, 0xdc, 0x7e, 0xc6, 0x81, 0xdc, 0x77, 0xcf, 0xef, 0xd4, 0xce, 0x64, 0x1a, 0x7e, - 0x26, 0x87, 0x55, 0x7f, 0xdd, 0x65, 0x22, 0x7f, 0xdd, 0x65, 0x22, 0x7f, 0x77, 0xcf, 0x98, 0xa3, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf2, - 0xf1, 0x65, 0x32, 0x1b, 0xef, 0x18, 0x70, 0x66, 0xba, 0x30, 0xa0, 0x11, 0xaa, 0x2f, 0xb0, 0xab, 0xd0, - 0x30, 0x7d, 0xbd, 0x01, 0x00, 0xf8, 0x0d, 0xb8, 0x30, 0x01, 0x00, 0x00, 0x00, 0xce, 0xc6, 0x81, 0xdc, - 0xce, 0xc6, 0x81, 0xdc, 0xc7, 0xcf, 0xef, 0xd4, 0x75, 0x65, 0x1a, 0x7f, 0x62, 0x6f, 0x55, 0x7f, 0x6d, - 0x65, 0x22, 0x7f, 0x6d, 0x65, 0x22, 0x7f, 0xc7, 0xcf, 0x98, 0xa3, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf2, 0xf1, 0x62, 0x12, 0x1b, 0xef, - 0x18, 0x7e, 0xbd, 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xac, 0x28, 0x03, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, - 0xe0, 0xb9, 0x30, 0x03, 0xe1, 0xb9, 0x30, 0xbb, 0x00, 0x00, 0x00, 0x48, 0xe0, 0xb9, 0x30, 0x36, 0xd9, - 0x81, 0xdc, 0x36, 0xd9, 0x81, 0xdc, 0x3f, 0xd0, 0xef, 0xd4, 0xa5, 0x7a, 0x72, 0x7f, 0x26, 0x30, 0x55, - 0x7f, 0x95, 0x7a, 0x22, 0x7f, 0x95, 0x7a, 0x22, 0x7f, 0x3f, 0xd0, 0x98, 0xa3, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - struct partdata_test - { - }; + //bunch of sniffed data that *should* be a valid particle system + static U8 msg[] = { + 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x80, 0x00, 0x80, + 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x5e, 0x12, 0x0b, 0xa1, 0x58, 0x05, 0xdc, 0x57, 0x66, + 0xb7, 0xf5, 0xac, 0x4b, 0xd1, 0x8f, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, 0x00, 0x0a, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0xc6, 0x81, 0xdc, 0x7e, 0xc6, 0x81, 0xdc, 0x77, 0xcf, 0xef, 0xd4, 0xce, 0x64, 0x1a, 0x7e, + 0x26, 0x87, 0x55, 0x7f, 0xdd, 0x65, 0x22, 0x7f, 0xdd, 0x65, 0x22, 0x7f, 0x77, 0xcf, 0x98, 0xa3, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf2, + 0xf1, 0x65, 0x32, 0x1b, 0xef, 0x18, 0x70, 0x66, 0xba, 0x30, 0xa0, 0x11, 0xaa, 0x2f, 0xb0, 0xab, 0xd0, + 0x30, 0x7d, 0xbd, 0x01, 0x00, 0xf8, 0x0d, 0xb8, 0x30, 0x01, 0x00, 0x00, 0x00, 0xce, 0xc6, 0x81, 0xdc, + 0xce, 0xc6, 0x81, 0xdc, 0xc7, 0xcf, 0xef, 0xd4, 0x75, 0x65, 0x1a, 0x7f, 0x62, 0x6f, 0x55, 0x7f, 0x6d, + 0x65, 0x22, 0x7f, 0x6d, 0x65, 0x22, 0x7f, 0xc7, 0xcf, 0x98, 0xa3, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf2, 0xf1, 0x62, 0x12, 0x1b, 0xef, + 0x18, 0x7e, 0xbd, 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xac, 0x28, 0x03, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, + 0xe0, 0xb9, 0x30, 0x03, 0xe1, 0xb9, 0x30, 0xbb, 0x00, 0x00, 0x00, 0x48, 0xe0, 0xb9, 0x30, 0x36, 0xd9, + 0x81, 0xdc, 0x36, 0xd9, 0x81, 0xdc, 0x3f, 0xd0, 0xef, 0xd4, 0xa5, 0x7a, 0x72, 0x7f, 0x26, 0x30, 0x55, + 0x7f, 0x95, 0x7a, 0x22, 0x7f, 0x95, 0x7a, 0x22, 0x7f, 0x3f, 0xd0, 0x98, 0xa3, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + struct partdata_test + { + }; + + typedef test_group<partdata_test> partdata_test_t; + typedef partdata_test_t::object partdata_test_object_t; + tut::partdata_test_t tut_partdata_test("LLPartData"); + + template<> template<> + void partdata_test_object_t::test<1>() + { + LLPartSysData llpsysdata; + LLDataPackerBinaryBuffer dp1(msg, sizeof(msg)); - typedef test_group<partdata_test> partdata_test_t; - typedef partdata_test_t::object partdata_test_object_t; - tut::partdata_test_t tut_partdata_test("LLPartData"); + ensure("LLPartSysData::unpack failed.", llpsysdata.unpack(dp1)); - template<> template<> - void partdata_test_object_t::test<1>() - { - LLPartSysData llpsysdata; - LLDataPackerBinaryBuffer dp1(msg, sizeof(msg)); - ensure("LLPartSysData::unpack failed.", llpsysdata.unpack(dp1)); + //mCRC 1 unsigned int + ensure("mCRC different after unpacking", llpsysdata.mCRC == (U32) 1); + //mFlags 0 unsigned int + ensure ("mFlags different after unpacking", llpsysdata.mFlags == (U32) 0); + //mPattern 1 '' unsigned char + ensure ("mPattern different after unpacking", llpsysdata.mPattern == (U8) 1); + //mInnerAngle 0.00000000 float + ensure_approximately_equals("mInnerAngle different after unpacking", llpsysdata.mInnerAngle, 0.f, 8); + //mOuterAngle 0.00000000 float + ensure_approximately_equals("mOuterAngle different after unpacking", llpsysdata.mOuterAngle, 0.f, 8); + //mAngularVelocity 0,0,0 + ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[0], 0.f, 8); + ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[1], 0.f, 8); + ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[2], 0.f, 8); + //mBurstRate 0.097656250 float + ensure_approximately_equals("mBurstRate different after unpacking", llpsysdata.mBurstRate, 0.097656250f, 8); + //mBurstPartCount 1 '' unsigned char + ensure("mBurstPartCount different after unpacking", llpsysdata.mBurstPartCount == (U8) 1); + //mBurstRadius 0.00000000 float + ensure_approximately_equals("mBurstRadius different after unpacking", llpsysdata.mBurstRadius, 0.f, 8); + //mBurstSpeedMin 1.0000000 float + ensure_approximately_equals("mBurstSpeedMin different after unpacking", llpsysdata.mBurstSpeedMin, 1.f, 8); + //mBurstSpeedMax 1.0000000 float + ensure_approximately_equals("mBurstSpeedMax different after unpacking", llpsysdata.mBurstSpeedMax, 1.f, 8); + //mMaxAge 0.00000000 float + ensure_approximately_equals("mMaxAge different after unpacking", llpsysdata.mMaxAge, 0.f, 8); + //mStartAge 0.00000000 float + ensure_approximately_equals("mStartAge different after unpacking", llpsysdata.mStartAge, 0.f, 8); + //mPartAccel <0,0,0> + ensure_approximately_equals("mPartAccel.mV[0] different after unpacking", llpsysdata.mPartAccel.mV[0], 0.f, 7); + ensure_approximately_equals("mPartAccel.mV[1] different after unpacking", llpsysdata.mPartAccel.mV[1], 0.f, 7); + ensure_approximately_equals("mPartAccel.mV[2] different after unpacking", llpsysdata.mPartAccel.mV[2], 0.f, 7); - - //mCRC 1 unsigned int - ensure("mCRC different after unpacking", llpsysdata.mCRC == (U32) 1); - //mFlags 0 unsigned int - ensure ("mFlags different after unpacking", llpsysdata.mFlags == (U32) 0); - //mPattern 1 '' unsigned char - ensure ("mPattern different after unpacking", llpsysdata.mPattern == (U8) 1); - //mInnerAngle 0.00000000 float - ensure_approximately_equals("mInnerAngle different after unpacking", llpsysdata.mInnerAngle, 0.f, 8); - //mOuterAngle 0.00000000 float - ensure_approximately_equals("mOuterAngle different after unpacking", llpsysdata.mOuterAngle, 0.f, 8); - //mAngularVelocity 0,0,0 - ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[0], 0.f, 8); - ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[1], 0.f, 8); - ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[2], 0.f, 8); - //mBurstRate 0.097656250 float - ensure_approximately_equals("mBurstRate different after unpacking", llpsysdata.mBurstRate, 0.097656250f, 8); - //mBurstPartCount 1 '' unsigned char - ensure("mBurstPartCount different after unpacking", llpsysdata.mBurstPartCount == (U8) 1); - //mBurstRadius 0.00000000 float - ensure_approximately_equals("mBurstRadius different after unpacking", llpsysdata.mBurstRadius, 0.f, 8); - //mBurstSpeedMin 1.0000000 float - ensure_approximately_equals("mBurstSpeedMin different after unpacking", llpsysdata.mBurstSpeedMin, 1.f, 8); - //mBurstSpeedMax 1.0000000 float - ensure_approximately_equals("mBurstSpeedMax different after unpacking", llpsysdata.mBurstSpeedMax, 1.f, 8); - //mMaxAge 0.00000000 float - ensure_approximately_equals("mMaxAge different after unpacking", llpsysdata.mMaxAge, 0.f, 8); - //mStartAge 0.00000000 float - ensure_approximately_equals("mStartAge different after unpacking", llpsysdata.mStartAge, 0.f, 8); - //mPartAccel <0,0,0> - ensure_approximately_equals("mPartAccel.mV[0] different after unpacking", llpsysdata.mPartAccel.mV[0], 0.f, 7); - ensure_approximately_equals("mPartAccel.mV[1] different after unpacking", llpsysdata.mPartAccel.mV[1], 0.f, 7); - ensure_approximately_equals("mPartAccel.mV[2] different after unpacking", llpsysdata.mPartAccel.mV[2], 0.f, 7); + //mPartData + LLPartData& data = llpsysdata.mPartData; - //mPartData - LLPartData& data = llpsysdata.mPartData; + //mFlags 132354 unsigned int + ensure ("mPartData.mFlags different after unpacking", data.mFlags == (U32) 132354); + //mMaxAge 10.000000 float + ensure_approximately_equals("mPartData.mMaxAge different after unpacking", data.mMaxAge, 10.f, 8); + //mStartColor <1,1,1,1> + ensure_approximately_equals("mPartData.mStartColor.mV[0] different after unpacking", data.mStartColor.mV[0], 1.f, 8); + ensure_approximately_equals("mPartData.mStartColor.mV[1] different after unpacking", data.mStartColor.mV[1], 1.f, 8); + ensure_approximately_equals("mPartData.mStartColor.mV[2] different after unpacking", data.mStartColor.mV[2], 1.f, 8); + ensure_approximately_equals("mPartData.mStartColor.mV[3] different after unpacking", data.mStartColor.mV[3], 1.f, 8); + //mEndColor <1,1,0,0> + ensure_approximately_equals("mPartData.mEndColor.mV[0] different after unpacking", data.mEndColor.mV[0], 1.f, 8); + ensure_approximately_equals("mPartData.mEndColor.mV[1] different after unpacking", data.mEndColor.mV[1], 1.f, 8); + ensure_approximately_equals("mPartData.mEndColor.mV[2] different after unpacking", data.mEndColor.mV[2], 0.f, 8); + ensure_approximately_equals("mPartData.mEndColor.mV[3] different after unpacking", data.mEndColor.mV[3], 0.f, 8); + //mStartScale <1,1> + ensure_approximately_equals("mPartData.mStartScale.mV[0] different after unpacking", data.mStartScale.mV[0], 1.f, 8); + ensure_approximately_equals("mPartData.mStartScale.mV[1] different after unpacking", data.mStartScale.mV[1], 1.f, 8); + //mEndScale <0,0> + ensure_approximately_equals("mPartData.mEndScale.mV[0] different after unpacking", data.mEndScale.mV[0], 0.f, 8); + ensure_approximately_equals("mPartData.mEndScale.mV[1] different after unpacking", data.mEndScale.mV[1], 0.f, 8); + //mPosOffset <0,0,0> + ensure_approximately_equals("mPartData.mPosOffset.mV[0] different after unpacking", data.mPosOffset.mV[0], 0.f, 8); + ensure_approximately_equals("mPartData.mPosOffset.mV[1] different after unpacking", data.mPosOffset.mV[1], 0.f, 8); + ensure_approximately_equals("mPartData.mPosOffset.mV[2] different after unpacking", data.mPosOffset.mV[2], 0.f, 8); + //mParameter 0.00000000 float + ensure_approximately_equals("mPartData.mParameter different after unpacking", data.mParameter, 0.f, 8); - //mFlags 132354 unsigned int - ensure ("mPartData.mFlags different after unpacking", data.mFlags == (U32) 132354); - //mMaxAge 10.000000 float - ensure_approximately_equals("mPartData.mMaxAge different after unpacking", data.mMaxAge, 10.f, 8); - //mStartColor <1,1,1,1> - ensure_approximately_equals("mPartData.mStartColor.mV[0] different after unpacking", data.mStartColor.mV[0], 1.f, 8); - ensure_approximately_equals("mPartData.mStartColor.mV[1] different after unpacking", data.mStartColor.mV[1], 1.f, 8); - ensure_approximately_equals("mPartData.mStartColor.mV[2] different after unpacking", data.mStartColor.mV[2], 1.f, 8); - ensure_approximately_equals("mPartData.mStartColor.mV[3] different after unpacking", data.mStartColor.mV[3], 1.f, 8); - //mEndColor <1,1,0,0> - ensure_approximately_equals("mPartData.mEndColor.mV[0] different after unpacking", data.mEndColor.mV[0], 1.f, 8); - ensure_approximately_equals("mPartData.mEndColor.mV[1] different after unpacking", data.mEndColor.mV[1], 1.f, 8); - ensure_approximately_equals("mPartData.mEndColor.mV[2] different after unpacking", data.mEndColor.mV[2], 0.f, 8); - ensure_approximately_equals("mPartData.mEndColor.mV[3] different after unpacking", data.mEndColor.mV[3], 0.f, 8); - //mStartScale <1,1> - ensure_approximately_equals("mPartData.mStartScale.mV[0] different after unpacking", data.mStartScale.mV[0], 1.f, 8); - ensure_approximately_equals("mPartData.mStartScale.mV[1] different after unpacking", data.mStartScale.mV[1], 1.f, 8); - //mEndScale <0,0> - ensure_approximately_equals("mPartData.mEndScale.mV[0] different after unpacking", data.mEndScale.mV[0], 0.f, 8); - ensure_approximately_equals("mPartData.mEndScale.mV[1] different after unpacking", data.mEndScale.mV[1], 0.f, 8); - //mPosOffset <0,0,0> - ensure_approximately_equals("mPartData.mPosOffset.mV[0] different after unpacking", data.mPosOffset.mV[0], 0.f, 8); - ensure_approximately_equals("mPartData.mPosOffset.mV[1] different after unpacking", data.mPosOffset.mV[1], 0.f, 8); - ensure_approximately_equals("mPartData.mPosOffset.mV[2] different after unpacking", data.mPosOffset.mV[2], 0.f, 8); - //mParameter 0.00000000 float - ensure_approximately_equals("mPartData.mParameter different after unpacking", data.mParameter, 0.f, 8); - - //mStartGlow 0.00000000 float - ensure_approximately_equals("mPartData.mStartGlow different after unpacking", data.mStartGlow, 0.f, 8); - //mEndGlow 0.00000000 float - ensure_approximately_equals("mPartData.mEndGlow different after unpacking", data.mEndGlow, 0.f, 8); - //mBlendFuncSource 2 '' unsigned char - ensure("mPartData.mBlendFuncSource different after unpacking", data.mBlendFuncSource == (U8) 2); - //mBlendFuncDest 1 '' unsigned char - ensure("mPartData.mBlendFuncDest different after unpacking", data.mBlendFuncDest == (U8) 1); - } + //mStartGlow 0.00000000 float + ensure_approximately_equals("mPartData.mStartGlow different after unpacking", data.mStartGlow, 0.f, 8); + //mEndGlow 0.00000000 float + ensure_approximately_equals("mPartData.mEndGlow different after unpacking", data.mEndGlow, 0.f, 8); + //mBlendFuncSource 2 '' unsigned char + ensure("mPartData.mBlendFuncSource different after unpacking", data.mBlendFuncSource == (U8) 2); + //mBlendFuncDest 1 '' unsigned char + ensure("mPartData.mBlendFuncDest different after unpacking", data.mBlendFuncDest == (U8) 1); + } } diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp index 3f87a4aff6..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/lltestmessagesender.cpp b/indra/llmessage/tests/lltestmessagesender.cpp index ee40e0249e..1765a9eccd 100644 --- a/indra/llmessage/tests/lltestmessagesender.cpp +++ b/indra/llmessage/tests/lltestmessagesender.cpp @@ -1,25 +1,25 @@ -/** - * @file - * @brief +/** + * @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$ */ @@ -32,7 +32,7 @@ LLTestMessageSender::~LLTestMessageSender() S32 LLTestMessageSender::sendMessage(const LLHost& host, LLStoredMessagePtr message) { - mSendHosts.push_back(host); - mSendMessages.push_back(message); - return 0; + mSendHosts.push_back(host); + mSendMessages.push_back(message); + return 0; } diff --git a/indra/llmessage/tests/lltestmessagesender.h b/indra/llmessage/tests/lltestmessagesender.h index bb89289585..e78cfad96e 100644 --- a/indra/llmessage/tests/lltestmessagesender.h +++ b/indra/llmessage/tests/lltestmessagesender.h @@ -1,25 +1,25 @@ -/** - * @file - * @brief +/** + * @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$ */ @@ -38,11 +38,11 @@ class LLTestMessageSender : public LLMessageSenderInterface { public: - virtual ~LLTestMessageSender(); - virtual S32 sendMessage(const LLHost& host, LLStoredMessagePtr message); + virtual ~LLTestMessageSender(); + virtual S32 sendMessage(const LLHost& host, LLStoredMessagePtr message); - std::vector<LLHost> mSendHosts; - std::vector<LLStoredMessagePtr> mSendMessages; + std::vector<LLHost> mSendHosts; + std::vector<LLStoredMessagePtr> mSendMessages; }; diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp index 41f982a7e2..cc199141b8 100644 --- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp +++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp @@ -5,21 +5,21 @@ * $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$ */ @@ -40,7 +40,7 @@ LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; LLMessageConfig::SenderTrust LLMessageConfig::getSenderTrustedness(const std::string& msg_name) { - return LLMessageConfig::NOT_SET; + return LLMessageConfig::NOT_SET; } void LLMessageSystem::receivedMessageFromTrustedSender() @@ -49,12 +49,12 @@ void LLMessageSystem::receivedMessageFromTrustedSender() bool LLMessageSystem::isTrustedSender(const LLHost& host) const { - return false; + return false; } bool LLMessageSystem::isTrustedMessage(const std::string& name) const { - return false; + return false; } bool messageDispatched = false; @@ -63,80 +63,80 @@ LLSD lastLLSD; std::string lastMessageName; void LLMessageSystem::dispatch(const std::string& msg_name, - const LLSD& message, - LLHTTPNode::ResponsePtr responsep) + const LLSD& message, + LLHTTPNode::ResponsePtr responsep) { - messageDispatched = true; - lastLLSD = message; - lastMessageName = msg_name; + messageDispatched = true; + lastLLSD = message; + lastMessageName = msg_name; } void LLMessageSystem::dispatchTemplate(const std::string& msg_name, - const LLSD& message, - LLHTTPNode::ResponsePtr responsep) + const LLSD& message, + LLHTTPNode::ResponsePtr responsep) { - lastLLSD = message; - lastMessageName = msg_name; - messageDispatchedAsBinary = true; + lastLLSD = message; + lastMessageName = msg_name; + messageDispatchedAsBinary = true; } namespace tut { - struct LLTrustedMessageServiceData - { - LLTrustedMessageServiceData() - { - LLSD emptyLLSD; - lastLLSD = emptyLLSD; - lastMessageName = "uninitialised message name"; - messageDispatched = false; - messageDispatchedAsBinary = false; - } - }; - - typedef test_group<LLTrustedMessageServiceData> factory; - typedef factory::object object; + struct LLTrustedMessageServiceData + { + LLTrustedMessageServiceData() + { + LLSD emptyLLSD; + lastLLSD = emptyLLSD; + lastMessageName = "uninitialised message name"; + messageDispatched = false; + messageDispatchedAsBinary = false; + } + }; + + typedef test_group<LLTrustedMessageServiceData> factory; + typedef factory::object object; } namespace { - tut::factory tf("LLTrustedMessageServiceData"); + tut::factory tf("LLTrustedMessageServiceData"); } namespace tut { - // characterisation tests - - // 1) test that messages get forwarded with names etc. as current behaviour (something like LLMessageSystem::dispatch(name, data...) - - // test llsd messages are sent as normal using LLMessageSystem::dispatch() (eventually) - template<> template<> - void object::test<1>() - { - LLHTTPNode::ResponsePtr response; - LLSD input; - LLSD context; - LLTrustedMessageService adapter; - adapter.post(response, context, input); - // test original ting got called wit nowt, ya get me blood? - ensure_equals(messageDispatched, true); - ensure(lastLLSD.has("body")); - } - - // test that llsd wrapped binary-template-data messages are - // sent via LLMessageSystem::binaryDispatch() or similar - template<> template<> - void object::test<2>() - { - LLHTTPNode::ResponsePtr response; - LLSD input; - input["binary-template-data"] = "10001010110"; //make me a message here. - LLSD context; - LLTrustedMessageService adapter; - - adapter.post(response, context, input); - ensure("check template-binary-data message was dispatched as binary", messageDispatchedAsBinary); - ensure_equals(lastLLSD["body"]["binary-template-data"].asString(), "10001010110"); - // test somit got called with "10001010110" (something like LLMessageSystem::dispatchTemplate(blah)) - } + // characterisation tests + + // 1) test that messages get forwarded with names etc. as current behaviour (something like LLMessageSystem::dispatch(name, data...) + + // test llsd messages are sent as normal using LLMessageSystem::dispatch() (eventually) + template<> template<> + void object::test<1>() + { + LLHTTPNode::ResponsePtr response; + LLSD input; + LLSD context; + LLTrustedMessageService adapter; + adapter.post(response, context, input); + // test original ting got called wit nowt, ya get me blood? + ensure_equals(messageDispatched, true); + ensure(lastLLSD.has("body")); + } + + // test that llsd wrapped binary-template-data messages are + // sent via LLMessageSystem::binaryDispatch() or similar + template<> template<> + void object::test<2>() + { + LLHTTPNode::ResponsePtr response; + LLSD input; + input["binary-template-data"] = "10001010110"; //make me a message here. + LLSD context; + LLTrustedMessageService adapter; + + adapter.post(response, context, input); + ensure("check template-binary-data message was dispatched as binary", messageDispatchedAsBinary); + ensure_equals(lastLLSD["body"]["binary-template-data"].asString(), "10001010110"); + // test somit got called with "10001010110" (something like LLMessageSystem::dispatchTemplate(blah)) + } } diff --git a/indra/llmessage/tests/llxfer_file_test.cpp b/indra/llmessage/tests/llxfer_file_test.cpp index cf95d2627c..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);
+ }
+}
diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h index 5986524342..a88c4ec596 100644 --- a/indra/llmessage/tests/networkio.h +++ b/indra/llmessage/tests/networkio.h @@ -2,26 +2,26 @@ * @file networkio.h * @author Nat Goodspeed * @date 2009-01-09 - * @brief - * + * @brief + * * $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$ */ |