From 3777dbb3d6ed9b3411eef71c10182afed19c974b Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 8 Dec 2023 23:57:40 +0000 Subject: More sl-20635 - moved new attachment data to AvatarAppearance message --- indra/llmessage/message.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/llmessage') diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 31acc65642..5de29ba66f 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -307,12 +307,15 @@ void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure 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; } -- cgit v1.2.3 From da967da9c7aa0d88f478d476e8bb059ba79ca818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Thu, 11 Jan 2024 11:32:15 +0100 Subject: Rename OS X to macOS, mostly in comments We only support 10.13+ now, and it's been called macOS since 10.12. References in code to older versions are unchanged. --- indra/llmessage/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 523bcbb60d..60030bb920 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -77,7 +77,7 @@ const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1"; const char* BROADCAST_ADDRESS_STRING = "255.255.255.255"; #if LL_DARWIN - // Mac OS X returns an error when trying to set these to 400000. Smaller values succeed. + // 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 -- cgit v1.2.3 From 9e854b697a06abed2a0917fb6120445f176764f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Fri, 16 Feb 2024 19:29:51 +0100 Subject: misc: BOOL to bool --- indra/llmessage/llassetstorage.cpp | 2 +- indra/llmessage/llmessagereader.h | 2 +- indra/llmessage/llsdmessagereader.cpp | 2 +- indra/llmessage/llsdmessagereader.h | 2 +- indra/llmessage/lltemplatemessagereader.cpp | 2 +- indra/llmessage/lltemplatemessagereader.h | 2 +- indra/llmessage/llxfermanager.cpp | 4 ++-- indra/llmessage/message.cpp | 4 ++-- indra/llmessage/message.h | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index f38a5e663e..60d95c3367 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -1020,7 +1020,7 @@ void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_dat LLUUID uuid; S8 asset_type_s8; LLAssetType::EType asset_type; - BOOL success = FALSE; + bool success = false; msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid); msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8); diff --git a/indra/llmessage/llmessagereader.h b/indra/llmessage/llmessagereader.h index 3b77a6bfe4..647f267785 100644 --- a/indra/llmessage/llmessagereader.h +++ b/indra/llmessage/llmessagereader.h @@ -52,7 +52,7 @@ class 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 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; diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp index b729ebafa9..d533d6535b 100644 --- a/indra/llmessage/llsdmessagereader.cpp +++ b/indra/llmessage/llsdmessagereader.cpp @@ -114,7 +114,7 @@ void LLSDMessageReader::getBinaryData(const char *block, const char *var, //virtual void LLSDMessageReader::getBOOL(const char *block, const char *var, - BOOL &data, + bool &data, S32 blocknum) { data = getLLSD(mMessage, block, var, blocknum); diff --git a/indra/llmessage/llsdmessagereader.h b/indra/llmessage/llsdmessagereader.h index 3b3d7fbfbe..4119de6009 100644 --- a/indra/llmessage/llsdmessagereader.h +++ b/indra/llmessage/llsdmessagereader.h @@ -46,7 +46,7 @@ public: 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, + 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); diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 32f79f0546..8a41d5565d 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -284,7 +284,7 @@ void LLTemplateMessageReader::getU8(const char *block, const char *var, } void LLTemplateMessageReader::getBOOL(const char *block, const char *var, - BOOL &b, S32 blocknum ) + bool &b, S32 blocknum ) { U8 value; getData(block, var, &value, sizeof(U8), blocknum); diff --git a/indra/llmessage/lltemplatemessagereader.h b/indra/llmessage/lltemplatemessagereader.h index fcf8f92fa6..88889cd7d2 100644 --- a/indra/llmessage/lltemplatemessagereader.h +++ b/indra/llmessage/lltemplatemessagereader.h @@ -47,7 +47,7 @@ public: 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, + 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); diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index f9b59d7e42..956ecc11a3 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -757,7 +757,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user LLUUID uuid; LLAssetType::EType type; S16 type_s16; - BOOL b_use_big_packets; + bool b_use_big_packets; mesgsys->getBOOL("XferID", "UseBigPackets", b_use_big_packets); @@ -853,7 +853,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user } LL_INFOS("Xfer") << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << LL_ENDL; - BOOL delete_local_on_completion = FALSE; + bool delete_local_on_completion = false; mesgsys->getBOOL("XferID", "DeleteOnCompletion", delete_local_on_completion); // -1 chunk_size causes it to use the default diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 5de29ba66f..5e24061959 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -3673,13 +3673,13 @@ void LLMessageSystem::getU8(const char *block, const char *var, U8 &u, LLMessageStringTable::getInstance()->getString(var), u, blocknum); } -void LLMessageSystem::getBOOLFast(const char *block, const char *var, BOOL &b, +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, +void LLMessageSystem::getBOOL(const char *block, const char *var, bool &b, S32 blocknum) { getBOOLFast(LLMessageStringTable::getInstance()->getString(block), diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index e25a9ea7ef..c041a69d79 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -599,8 +599,8 @@ public: */ 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 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); -- cgit v1.2.3 From 48b121ab03435507e2ed9a865de9f8aff992877a Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Sat, 17 Feb 2024 14:02:06 +0200 Subject: viewer#826 Follow-up buildfix: update lldatapacker --- indra/llmessage/lldatapacker.cpp | 556 +++++++++++++++++++-------------------- indra/llmessage/lldatapacker.h | 312 +++++++++++----------- 2 files changed, 434 insertions(+), 434 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 9f7768f78e..b3113cd5d8 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -45,7 +45,7 @@ const S32 DP_BUFSIZE = 512; static char DUMMY_BUFFER[128]; /*Flawfinder: ignore*/ -LLDataPacker::LLDataPacker() : mPassFlags(0), mWriteEnabled(FALSE) +LLDataPacker::LLDataPacker() : mPassFlags(0), mWriteEnabled(false) { } @@ -61,10 +61,10 @@ 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 LLDataPacker::packFixed(const F32 value, const char *name, + const bool is_signed, const U32 int_bits, const U32 frac_bits) { - BOOL success = TRUE; + bool success = true; S32 unsigned_bits = int_bits + frac_bits; S32 total_bits = unsigned_bits; @@ -113,10 +113,10 @@ BOOL LLDataPacker::packFixed(const F32 value, const char *name, return success; } -BOOL LLDataPacker::unpackFixed(F32 &value, const char *name, - const BOOL is_signed, const U32 int_bits, const U32 frac_bits) +bool LLDataPacker::unpackFixed(F32 &value, const char *name, + const bool is_signed, const U32 int_bits, const U32 frac_bits) { - BOOL success = TRUE; + 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; @@ -166,82 +166,82 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name, return success; } -BOOL LLDataPacker::unpackU16s(U16 *values, S32 count, const char *name) +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 false; } } - return TRUE; + return true; } -BOOL LLDataPacker::unpackS16s(S16 *values, S32 count, const char *name) +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 false; } } - return TRUE; + return true; } -BOOL LLDataPacker::unpackF32s(F32 *values, S32 count, const char *name) +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 false; } } - return TRUE; + return true; } -BOOL LLDataPacker::unpackColor4Us(LLColor4U *values, S32 count, const char *name) +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 false; } } - return TRUE; + return true; } -BOOL LLDataPacker::unpackUUIDs(LLUUID *values, S32 count, const char *name) +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 false; } } - return TRUE; + return true; } //--------------------------------------------------------------------------- // LLDataPackerBinaryBuffer implementation //--------------------------------------------------------------------------- -BOOL LLDataPackerBinaryBuffer::packString(const std::string& value, const char *name) +bool LLDataPackerBinaryBuffer::packString(const std::string& value, const char *name) { S32 length = value.length()+1; if (!verifyLength(length, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -249,30 +249,30 @@ BOOL LLDataPackerBinaryBuffer::packString(const std::string& value, const char * htolememcpy(mCurBufferp, value.c_str(), MVT_VARIABLE, length); } mCurBufferp += length; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackString(std::string& value, const char *name) +bool LLDataPackerBinaryBuffer::unpackString(std::string& value, const char *name) { S32 length = (S32)strlen((char *)mCurBufferp) + 1; /*Flawfinder: ignore*/ if (!verifyLength(length, name)) { - return FALSE; + return false; } value = std::string((char*)mCurBufferp); // We already assume NULL termination calling strlen() mCurBufferp += length; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packBinaryData(const U8 *value, S32 size, const char *name) +bool LLDataPackerBinaryBuffer::packBinaryData(const U8 *value, S32 size, const char *name) { if (!verifyLength(size + 4, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -285,16 +285,16 @@ BOOL LLDataPackerBinaryBuffer::packBinaryData(const U8 *value, S32 size, const c htolememcpy(mCurBufferp, value, MVT_VARIABLE, size); } mCurBufferp += size; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char *name) +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; + return false; } htolememcpy(&size, mCurBufferp, MVT_S32, 4); @@ -303,21 +303,21 @@ BOOL LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char if (!verifyLength(size, name)) { LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData would unpack invalid data, aborting!" << LL_ENDL; - return FALSE; + return false; } htolememcpy(value, mCurBufferp, MVT_VARIABLE, size); mCurBufferp += size; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packBinaryDataFixed(const U8 *value, S32 size, const char *name) +bool LLDataPackerBinaryBuffer::packBinaryDataFixed(const U8 *value, S32 size, const char *name) { if (!verifyLength(size, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -325,27 +325,27 @@ BOOL LLDataPackerBinaryBuffer::packBinaryDataFixed(const U8 *value, S32 size, co htolememcpy(mCurBufferp, value, MVT_VARIABLE, size); } mCurBufferp += size; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) +bool LLDataPackerBinaryBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) { if (!verifyLength(size, name)) { - return FALSE; + return false; } htolememcpy(value, mCurBufferp, MVT_VARIABLE, size); mCurBufferp += size; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packU8(const U8 value, const char *name) +bool LLDataPackerBinaryBuffer::packU8(const U8 value, const char *name) { if (!verifyLength(sizeof(U8), name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -353,28 +353,28 @@ BOOL LLDataPackerBinaryBuffer::packU8(const U8 value, const char *name) *mCurBufferp = value; } mCurBufferp++; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackU8(U8 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackU8(U8 &value, const char *name) { if (!verifyLength(sizeof(U8), name)) { - return FALSE; + return false; } value = *mCurBufferp; mCurBufferp++; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packU16(const U16 value, const char *name) +bool LLDataPackerBinaryBuffer::packU16(const U16 value, const char *name) { if (!verifyLength(sizeof(U16), name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -382,25 +382,25 @@ BOOL LLDataPackerBinaryBuffer::packU16(const U16 value, const char *name) htolememcpy(mCurBufferp, &value, MVT_U16, 2); } mCurBufferp += 2; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name) { if (!verifyLength(sizeof(U16), name)) { - return FALSE; + return false; } htolememcpy(&value, mCurBufferp, MVT_U16, 2); mCurBufferp += 2; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name) +bool LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name) { - BOOL success = verifyLength(sizeof(S16), name); + bool success = verifyLength(sizeof(S16), name); if (mWriteEnabled && success) { @@ -410,9 +410,9 @@ BOOL LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name) return success; } -BOOL LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name) { - BOOL success = verifyLength(sizeof(S16), name); + bool success = verifyLength(sizeof(S16), name); if (success) { @@ -422,11 +422,11 @@ BOOL LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name) return success; } -BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name) +bool LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name) { if (!verifyLength(sizeof(U32), name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -434,28 +434,28 @@ BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name) htolememcpy(mCurBufferp, &value, MVT_U32, 4); } mCurBufferp += 4; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackU32(U32 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackU32(U32 &value, const char *name) { if (!verifyLength(sizeof(U32), name)) { - return FALSE; + return false; } htolememcpy(&value, mCurBufferp, MVT_U32, 4); mCurBufferp += 4; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packS32(const S32 value, const char *name) +bool LLDataPackerBinaryBuffer::packS32(const S32 value, const char *name) { if (!verifyLength(sizeof(S32), name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -463,28 +463,28 @@ BOOL LLDataPackerBinaryBuffer::packS32(const S32 value, const char *name) htolememcpy(mCurBufferp, &value, MVT_S32, 4); } mCurBufferp += 4; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackS32(S32 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackS32(S32 &value, const char *name) { if(!verifyLength(sizeof(S32), name)) { - return FALSE; + return false; } htolememcpy(&value, mCurBufferp, MVT_S32, 4); mCurBufferp += 4; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packF32(const F32 value, const char *name) +bool LLDataPackerBinaryBuffer::packF32(const F32 value, const char *name) { if (!verifyLength(sizeof(F32), name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -492,28 +492,28 @@ BOOL LLDataPackerBinaryBuffer::packF32(const F32 value, const char *name) htolememcpy(mCurBufferp, &value, MVT_F32, 4); } mCurBufferp += 4; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackF32(F32 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackF32(F32 &value, const char *name) { if (!verifyLength(sizeof(F32), name)) { - return FALSE; + return false; } htolememcpy(&value, mCurBufferp, MVT_F32, 4); mCurBufferp += 4; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packColor4(const LLColor4 &value, const char *name) +bool LLDataPackerBinaryBuffer::packColor4(const LLColor4 &value, const char *name) { if (!verifyLength(16, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -521,28 +521,28 @@ BOOL LLDataPackerBinaryBuffer::packColor4(const LLColor4 &value, const char *nam htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); } mCurBufferp += 16; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackColor4(LLColor4 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackColor4(LLColor4 &value, const char *name) { if (!verifyLength(16, name)) { - return FALSE; + return false; } htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); mCurBufferp += 16; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packColor4U(const LLColor4U &value, const char *name) +bool LLDataPackerBinaryBuffer::packColor4U(const LLColor4U &value, const char *name) { if (!verifyLength(4, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -550,29 +550,29 @@ BOOL LLDataPackerBinaryBuffer::packColor4U(const LLColor4U &value, const char *n htolememcpy(mCurBufferp, value.mV, MVT_VARIABLE, 4); } mCurBufferp += 4; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackColor4U(LLColor4U &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackColor4U(LLColor4U &value, const char *name) { if (!verifyLength(4, name)) { - return FALSE; + return false; } htolememcpy(value.mV, mCurBufferp, MVT_VARIABLE, 4); mCurBufferp += 4; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packVector2(const LLVector2 &value, const char *name) +bool LLDataPackerBinaryBuffer::packVector2(const LLVector2 &value, const char *name) { if (!verifyLength(8, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -581,29 +581,29 @@ BOOL LLDataPackerBinaryBuffer::packVector2(const LLVector2 &value, const char *n htolememcpy(mCurBufferp+4, &value.mV[1], MVT_F32, 4); } mCurBufferp += 8; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackVector2(LLVector2 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackVector2(LLVector2 &value, const char *name) { if (!verifyLength(8, name)) { - return FALSE; + return false; } htolememcpy(&value.mV[0], mCurBufferp, MVT_F32, 4); htolememcpy(&value.mV[1], mCurBufferp+4, MVT_F32, 4); mCurBufferp += 8; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packVector3(const LLVector3 &value, const char *name) +bool LLDataPackerBinaryBuffer::packVector3(const LLVector3 &value, const char *name) { if (!verifyLength(12, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -611,27 +611,27 @@ BOOL LLDataPackerBinaryBuffer::packVector3(const LLVector3 &value, const char *n htolememcpy(mCurBufferp, value.mV, MVT_LLVector3, 12); } mCurBufferp += 12; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackVector3(LLVector3 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackVector3(LLVector3 &value, const char *name) { if (!verifyLength(12, name)) { - return FALSE; + return false; } htolememcpy(value.mV, mCurBufferp, MVT_LLVector3, 12); mCurBufferp += 12; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packVector4(const LLVector4 &value, const char *name) +bool LLDataPackerBinaryBuffer::packVector4(const LLVector4 &value, const char *name) { if (!verifyLength(16, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -639,27 +639,27 @@ BOOL LLDataPackerBinaryBuffer::packVector4(const LLVector4 &value, const char *n htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); } mCurBufferp += 16; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackVector4(LLVector4 &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackVector4(LLVector4 &value, const char *name) { if (!verifyLength(16, name)) { - return FALSE; + return false; } htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); mCurBufferp += 16; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::packUUID(const LLUUID &value, const char *name) +bool LLDataPackerBinaryBuffer::packUUID(const LLUUID &value, const char *name) { if (!verifyLength(16, name)) { - return FALSE; + return false; } if (mWriteEnabled) @@ -667,20 +667,20 @@ BOOL LLDataPackerBinaryBuffer::packUUID(const LLUUID &value, const char *name) htolememcpy(mCurBufferp, value.mData, MVT_LLUUID, 16); } mCurBufferp += 16; - return TRUE; + return true; } -BOOL LLDataPackerBinaryBuffer::unpackUUID(LLUUID &value, const char *name) +bool LLDataPackerBinaryBuffer::unpackUUID(LLUUID &value, const char *name) { if (!verifyLength(16, name)) { - return FALSE; + return false; } htolememcpy(value.mData, mCurBufferp, MVT_LLUUID, 16); mCurBufferp += 16; - return TRUE; + return true; } const LLDataPackerBinaryBuffer& LLDataPackerBinaryBuffer::operator=(const LLDataPackerBinaryBuffer &a) @@ -722,9 +722,9 @@ void LLDataPackerBinaryBuffer::dumpBufferToLog() //--------------------------------------------------------------------------- // LLDataPackerAsciiBuffer implementation //--------------------------------------------------------------------------- -BOOL LLDataPackerAsciiBuffer::packString(const std::string& value, const char *name) +bool LLDataPackerAsciiBuffer::packString(const std::string& value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -752,21 +752,21 @@ BOOL LLDataPackerAsciiBuffer::packString(const std::string& value, const char *n return success; } -BOOL LLDataPackerAsciiBuffer::unpackString(std::string& value, const char *name) +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; + return false; } value = valuestr; - return TRUE; + return true; } -BOOL LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const char *name) +bool LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; @@ -789,7 +789,7 @@ BOOL LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const ch S32 i; - BOOL bBufferFull = FALSE; + bool bBufferFull = false; for (i = 0; i < size && !bBufferFull; i++) { numCopied = snprintf(mCurBufferp, getBufferSize()-getCurrentSize(), "%02x ", value[i]); /* Flawfinder: ignore */ @@ -797,7 +797,7 @@ BOOL LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const ch { numCopied = getBufferSize()-getCurrentSize(); LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: data truncated: " << LL_ENDL; - bBufferFull = TRUE; + bBufferFull = true; } mCurBufferp += numCopied; } @@ -829,13 +829,13 @@ BOOL LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const ch } -BOOL LLDataPackerAsciiBuffer::unpackBinaryData(U8 *value, S32 &size, const char *name) +bool LLDataPackerAsciiBuffer::unpackBinaryData(U8 *value, S32 &size, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } char *cur_pos = &valuestr[0]; @@ -854,16 +854,16 @@ BOOL LLDataPackerAsciiBuffer::unpackBinaryData(U8 *value, S32 &size, const char } -BOOL LLDataPackerAsciiBuffer::packBinaryDataFixed(const U8 *value, S32 size, const char *name) +bool LLDataPackerAsciiBuffer::packBinaryDataFixed(const U8 *value, S32 size, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mWriteEnabled) { S32 i; int numCopied = 0; - BOOL bBufferFull = FALSE; + bool bBufferFull = false; for (i = 0; i < size && !bBufferFull; i++) { numCopied = snprintf(mCurBufferp, getBufferSize()-getCurrentSize(), "%02x ", value[i]); /* Flawfinder: ignore */ @@ -871,7 +871,7 @@ BOOL LLDataPackerAsciiBuffer::packBinaryDataFixed(const U8 *value, S32 size, con { numCopied = getBufferSize()-getCurrentSize(); LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryDataFixed: data truncated: " << LL_ENDL; - bBufferFull = TRUE; + bBufferFull = true; } mCurBufferp += numCopied; @@ -901,13 +901,13 @@ BOOL LLDataPackerAsciiBuffer::packBinaryDataFixed(const U8 *value, S32 size, con } -BOOL LLDataPackerAsciiBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) +bool LLDataPackerAsciiBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } char *cur_pos = &valuestr[0]; @@ -925,9 +925,9 @@ BOOL LLDataPackerAsciiBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const c -BOOL LLDataPackerAsciiBuffer::packU8(const U8 value, const char *name) +bool LLDataPackerAsciiBuffer::packU8(const U8 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -958,13 +958,13 @@ BOOL LLDataPackerAsciiBuffer::packU8(const U8 value, const char *name) } -BOOL LLDataPackerAsciiBuffer::unpackU8(U8 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackU8(U8 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } S32 in_val; @@ -973,9 +973,9 @@ BOOL LLDataPackerAsciiBuffer::unpackU8(U8 &value, const char *name) return success; } -BOOL LLDataPackerAsciiBuffer::packU16(const U16 value, const char *name) +bool LLDataPackerAsciiBuffer::packU16(const U16 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1005,13 +1005,13 @@ BOOL LLDataPackerAsciiBuffer::packU16(const U16 value, const char *name) } -BOOL LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } S32 in_val; @@ -1020,9 +1020,9 @@ BOOL LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name) return success; } -BOOL LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name) +bool LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1052,13 +1052,13 @@ BOOL LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name) } -BOOL LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } S32 in_val; @@ -1067,9 +1067,9 @@ BOOL LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name) return success; } -BOOL LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name) +bool LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1097,13 +1097,13 @@ BOOL LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name) } -BOOL LLDataPackerAsciiBuffer::unpackU32(U32 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackU32(U32 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%u", &value); @@ -1111,9 +1111,9 @@ BOOL LLDataPackerAsciiBuffer::unpackU32(U32 &value, const char *name) } -BOOL LLDataPackerAsciiBuffer::packS32(const S32 value, const char *name) +bool LLDataPackerAsciiBuffer::packS32(const S32 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1141,13 +1141,13 @@ BOOL LLDataPackerAsciiBuffer::packS32(const S32 value, const char *name) } -BOOL LLDataPackerAsciiBuffer::unpackS32(S32 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackS32(S32 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%d", &value); @@ -1155,9 +1155,9 @@ BOOL LLDataPackerAsciiBuffer::unpackS32(S32 &value, const char *name) } -BOOL LLDataPackerAsciiBuffer::packF32(const F32 value, const char *name) +bool LLDataPackerAsciiBuffer::packF32(const F32 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1185,13 +1185,13 @@ BOOL LLDataPackerAsciiBuffer::packF32(const F32 value, const char *name) } -BOOL LLDataPackerAsciiBuffer::unpackF32(F32 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackF32(F32 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%f", &value); @@ -1199,9 +1199,9 @@ BOOL LLDataPackerAsciiBuffer::unpackF32(F32 &value, const char *name) } -BOOL LLDataPackerAsciiBuffer::packColor4(const LLColor4 &value, const char *name) +bool LLDataPackerAsciiBuffer::packColor4(const LLColor4 &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1229,22 +1229,22 @@ BOOL LLDataPackerAsciiBuffer::packColor4(const LLColor4 &value, const char *name } -BOOL LLDataPackerAsciiBuffer::unpackColor4(LLColor4 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackColor4(LLColor4 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + 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 LLDataPackerAsciiBuffer::packColor4U(const LLColor4U &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1272,13 +1272,13 @@ BOOL LLDataPackerAsciiBuffer::packColor4U(const LLColor4U &value, const char *na } -BOOL LLDataPackerAsciiBuffer::unpackColor4U(LLColor4U &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackColor4U(LLColor4U &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } S32 r, g, b, a; @@ -1292,9 +1292,9 @@ BOOL LLDataPackerAsciiBuffer::unpackColor4U(LLColor4U &value, const char *name) } -BOOL LLDataPackerAsciiBuffer::packVector2(const LLVector2 &value, const char *name) +bool LLDataPackerAsciiBuffer::packVector2(const LLVector2 &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1322,13 +1322,13 @@ BOOL LLDataPackerAsciiBuffer::packVector2(const LLVector2 &value, const char *na } -BOOL LLDataPackerAsciiBuffer::unpackVector2(LLVector2 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackVector2(LLVector2 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%f %f", &value.mV[0], &value.mV[1]); @@ -1336,9 +1336,9 @@ BOOL LLDataPackerAsciiBuffer::unpackVector2(LLVector2 &value, const char *name) } -BOOL LLDataPackerAsciiBuffer::packVector3(const LLVector3 &value, const char *name) +bool LLDataPackerAsciiBuffer::packVector3(const LLVector3 &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1366,22 +1366,22 @@ BOOL LLDataPackerAsciiBuffer::packVector3(const LLVector3 &value, const char *na } -BOOL LLDataPackerAsciiBuffer::unpackVector3(LLVector3 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackVector3(LLVector3 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + 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 LLDataPackerAsciiBuffer::packVector4(const LLVector4 &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; if (mWriteEnabled) @@ -1409,13 +1409,13 @@ BOOL LLDataPackerAsciiBuffer::packVector4(const LLVector4 &value, const char *na } -BOOL LLDataPackerAsciiBuffer::unpackVector4(LLVector4 &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackVector4(LLVector4 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]); @@ -1423,9 +1423,9 @@ BOOL LLDataPackerAsciiBuffer::unpackVector4(LLVector4 &value, const char *name) } -BOOL LLDataPackerAsciiBuffer::packUUID(const LLUUID &value, const char *name) +bool LLDataPackerAsciiBuffer::packUUID(const LLUUID &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); int numCopied = 0; @@ -1449,20 +1449,20 @@ BOOL LLDataPackerAsciiBuffer::packUUID(const LLUUID &value, const char *name) { numCopied = getBufferSize()-getCurrentSize(); LL_WARNS() << "LLDataPackerAsciiBuffer::packUUID: truncated: " << LL_ENDL; - success = FALSE; + success = false; } mCurBufferp += numCopied; return success; } -BOOL LLDataPackerAsciiBuffer::unpackUUID(LLUUID &value, const char *name) +bool LLDataPackerAsciiBuffer::unpackUUID(LLUUID &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } char tmp_str[64]; /* Flawfinder: ignore */ @@ -1507,9 +1507,9 @@ void LLDataPackerAsciiBuffer::writeIndentedName(const char *name) } } -BOOL LLDataPackerAsciiBuffer::getValueStr(const char *name, char *out_value, S32 value_len) +bool LLDataPackerAsciiBuffer::getValueStr(const char *name, char *out_value, S32 value_len) { - BOOL success = TRUE; + bool success = true; char buffer[DP_BUFSIZE]; /* Flawfinder: ignore */ char keyword[DP_BUFSIZE]; /* Flawfinder: ignore */ char value[DP_BUFSIZE]; /* Flawfinder: ignore */ @@ -1530,7 +1530,7 @@ BOOL LLDataPackerAsciiBuffer::getValueStr(const char *name, char *out_value, S32 if (strcmp(keyword, name)) { LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL; - return FALSE; + return false; } } else @@ -1565,9 +1565,9 @@ std::string convertF32ToString(F32 val) //--------------------------------------------------------------------------- // LLDataPackerAsciiFile implementation //--------------------------------------------------------------------------- -BOOL LLDataPackerAsciiFile::packString(const std::string& value, const char *name) +bool LLDataPackerAsciiFile::packString(const std::string& value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1580,22 +1580,22 @@ BOOL LLDataPackerAsciiFile::packString(const std::string& value, const char *nam return success; } -BOOL LLDataPackerAsciiFile::unpackString(std::string& value, const char *name) +bool LLDataPackerAsciiFile::unpackString(std::string& value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } value = valuestr; return success; } -BOOL LLDataPackerAsciiFile::packBinaryData(const U8 *value, S32 size, const char *name) +bool LLDataPackerAsciiFile::packBinaryData(const U8 *value, S32 size, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) @@ -1627,13 +1627,13 @@ BOOL LLDataPackerAsciiFile::packBinaryData(const U8 *value, S32 size, const char } -BOOL LLDataPackerAsciiFile::unpackBinaryData(U8 *value, S32 &size, const char *name) +bool LLDataPackerAsciiFile::unpackBinaryData(U8 *value, S32 &size, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore*/ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } char *cur_pos = &valuestr[0]; @@ -1652,9 +1652,9 @@ BOOL LLDataPackerAsciiFile::unpackBinaryData(U8 *value, S32 &size, const char *n } -BOOL LLDataPackerAsciiFile::packBinaryDataFixed(const U8 *value, S32 size, const char *name) +bool LLDataPackerAsciiFile::packBinaryDataFixed(const U8 *value, S32 size, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) @@ -1681,13 +1681,13 @@ BOOL LLDataPackerAsciiFile::packBinaryDataFixed(const U8 *value, S32 size, const } -BOOL LLDataPackerAsciiFile::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) +bool LLDataPackerAsciiFile::unpackBinaryDataFixed(U8 *value, S32 size, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore*/ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } char *cur_pos = &valuestr[0]; @@ -1705,9 +1705,9 @@ BOOL LLDataPackerAsciiFile::unpackBinaryDataFixed(U8 *value, S32 size, const cha -BOOL LLDataPackerAsciiFile::packU8(const U8 value, const char *name) +bool LLDataPackerAsciiFile::packU8(const U8 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1723,13 +1723,13 @@ BOOL LLDataPackerAsciiFile::packU8(const U8 value, const char *name) } -BOOL LLDataPackerAsciiFile::unpackU8(U8 &value, const char *name) +bool LLDataPackerAsciiFile::unpackU8(U8 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } S32 in_val; @@ -1738,9 +1738,9 @@ BOOL LLDataPackerAsciiFile::unpackU8(U8 &value, const char *name) return success; } -BOOL LLDataPackerAsciiFile::packU16(const U16 value, const char *name) +bool LLDataPackerAsciiFile::packU16(const U16 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1754,13 +1754,13 @@ BOOL LLDataPackerAsciiFile::packU16(const U16 value, const char *name) } -BOOL LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name) +bool LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } S32 in_val; @@ -1769,9 +1769,9 @@ BOOL LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name) return success; } -BOOL LLDataPackerAsciiFile::packS16(const S16 value, const char *name) +bool LLDataPackerAsciiFile::packS16(const S16 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1785,13 +1785,13 @@ BOOL LLDataPackerAsciiFile::packS16(const S16 value, const char *name) } -BOOL LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name) +bool LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } S32 in_val; @@ -1800,9 +1800,9 @@ BOOL LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name) return success; } -BOOL LLDataPackerAsciiFile::packU32(const U32 value, const char *name) +bool LLDataPackerAsciiFile::packU32(const U32 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1816,13 +1816,13 @@ BOOL LLDataPackerAsciiFile::packU32(const U32 value, const char *name) } -BOOL LLDataPackerAsciiFile::unpackU32(U32 &value, const char *name) +bool LLDataPackerAsciiFile::unpackU32(U32 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%u", &value); @@ -1830,9 +1830,9 @@ BOOL LLDataPackerAsciiFile::unpackU32(U32 &value, const char *name) } -BOOL LLDataPackerAsciiFile::packS32(const S32 value, const char *name) +bool LLDataPackerAsciiFile::packS32(const S32 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1846,13 +1846,13 @@ BOOL LLDataPackerAsciiFile::packS32(const S32 value, const char *name) } -BOOL LLDataPackerAsciiFile::unpackS32(S32 &value, const char *name) +bool LLDataPackerAsciiFile::unpackS32(S32 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%d", &value); @@ -1860,9 +1860,9 @@ BOOL LLDataPackerAsciiFile::unpackS32(S32 &value, const char *name) } -BOOL LLDataPackerAsciiFile::packF32(const F32 value, const char *name) +bool LLDataPackerAsciiFile::packF32(const F32 value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1876,13 +1876,13 @@ BOOL LLDataPackerAsciiFile::packF32(const F32 value, const char *name) } -BOOL LLDataPackerAsciiFile::unpackF32(F32 &value, const char *name) +bool LLDataPackerAsciiFile::unpackF32(F32 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%f", &value); @@ -1890,9 +1890,9 @@ BOOL LLDataPackerAsciiFile::unpackF32(F32 &value, const char *name) } -BOOL LLDataPackerAsciiFile::packColor4(const LLColor4 &value, const char *name) +bool LLDataPackerAsciiFile::packColor4(const LLColor4 &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1906,22 +1906,22 @@ BOOL LLDataPackerAsciiFile::packColor4(const LLColor4 &value, const char *name) } -BOOL LLDataPackerAsciiFile::unpackColor4(LLColor4 &value, const char *name) +bool LLDataPackerAsciiFile::unpackColor4(LLColor4 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + 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 LLDataPackerAsciiFile::packColor4U(const LLColor4U &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1935,13 +1935,13 @@ BOOL LLDataPackerAsciiFile::packColor4U(const LLColor4U &value, const char *name } -BOOL LLDataPackerAsciiFile::unpackColor4U(LLColor4U &value, const char *name) +bool LLDataPackerAsciiFile::unpackColor4U(LLColor4U &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } S32 r, g, b, a; @@ -1955,9 +1955,9 @@ BOOL LLDataPackerAsciiFile::unpackColor4U(LLColor4U &value, const char *name) } -BOOL LLDataPackerAsciiFile::packVector2(const LLVector2 &value, const char *name) +bool LLDataPackerAsciiFile::packVector2(const LLVector2 &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -1971,13 +1971,13 @@ BOOL LLDataPackerAsciiFile::packVector2(const LLVector2 &value, const char *name } -BOOL LLDataPackerAsciiFile::unpackVector2(LLVector2 &value, const char *name) +bool LLDataPackerAsciiFile::unpackVector2(LLVector2 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%f %f", &value.mV[0], &value.mV[1]); @@ -1985,9 +1985,9 @@ BOOL LLDataPackerAsciiFile::unpackVector2(LLVector2 &value, const char *name) } -BOOL LLDataPackerAsciiFile::packVector3(const LLVector3 &value, const char *name) +bool LLDataPackerAsciiFile::packVector3(const LLVector3 &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -2001,22 +2001,22 @@ BOOL LLDataPackerAsciiFile::packVector3(const LLVector3 &value, const char *name } -BOOL LLDataPackerAsciiFile::unpackVector3(LLVector3 &value, const char *name) +bool LLDataPackerAsciiFile::unpackVector3(LLVector3 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + 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 LLDataPackerAsciiFile::packVector4(const LLVector4 &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); if (mFP) { @@ -2030,13 +2030,13 @@ BOOL LLDataPackerAsciiFile::packVector4(const LLVector4 &value, const char *name } -BOOL LLDataPackerAsciiFile::unpackVector4(LLVector4 &value, const char *name) +bool LLDataPackerAsciiFile::unpackVector4(LLVector4 &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } sscanf(valuestr,"%f %f %f %f", &value.mV[0], &value.mV[1], &value.mV[2], &value.mV[3]); @@ -2044,9 +2044,9 @@ BOOL LLDataPackerAsciiFile::unpackVector4(LLVector4 &value, const char *name) } -BOOL LLDataPackerAsciiFile::packUUID(const LLUUID &value, const char *name) +bool LLDataPackerAsciiFile::packUUID(const LLUUID &value, const char *name) { - BOOL success = TRUE; + bool success = true; writeIndentedName(name); std::string tmp_str; value.toString(tmp_str); @@ -2062,13 +2062,13 @@ BOOL LLDataPackerAsciiFile::packUUID(const LLUUID &value, const char *name) } -BOOL LLDataPackerAsciiFile::unpackUUID(LLUUID &value, const char *name) +bool LLDataPackerAsciiFile::unpackUUID(LLUUID &value, const char *name) { - BOOL success = TRUE; + bool success = true; char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ if (!getValueStr(name, valuestr, DP_BUFSIZE)) { - return FALSE; + return false; } char tmp_str[64]; /*Flawfinder: ignore */ @@ -2100,9 +2100,9 @@ void LLDataPackerAsciiFile::writeIndentedName(const char *name) } } -BOOL LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 value_len) +bool LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 value_len) { - BOOL success = FALSE; + bool success = false; char buffer[DP_BUFSIZE]; /*Flawfinder: ignore*/ char keyword[DP_BUFSIZE]; /*Flawfinder: ignore*/ char value[DP_BUFSIZE]; /*Flawfinder: ignore*/ @@ -2117,7 +2117,7 @@ BOOL LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 v if (0 != fgetpos(mFP, &last_pos)) // 0==success for fgetpos { LL_WARNS() << "Data packer failed to fgetpos" << LL_ENDL; - return FALSE; + return false; } if (fgets(buffer, DP_BUFSIZE, mFP) == NULL) @@ -2131,20 +2131,20 @@ BOOL LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 v { LL_WARNS() << "Data packer could not get the keyword!" << LL_ENDL; fsetpos(mFP, &last_pos); - return FALSE; + 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; + 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; + success = true; } else if (mInputStream) { @@ -2154,19 +2154,19 @@ BOOL LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 v if (!keyword[0]) { LL_WARNS() << "Data packer could not get the keyword!" << LL_ENDL; - return FALSE; + return false; } if (strcmp(keyword, name)) { LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL; - return FALSE; + 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; + success = true; } return success; diff --git a/indra/llmessage/lldatapacker.h b/indra/llmessage/lldatapacker.h index ac28cadbce..8e980d8611 100644 --- a/indra/llmessage/lldatapacker.h +++ b/indra/llmessage/lldatapacker.h @@ -43,72 +43,72 @@ public: virtual void reset(); virtual void dumpBufferToLog(); - virtual BOOL hasNext() const = 0; + 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 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; + 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 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 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 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 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 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 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); + 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); + 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 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 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 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 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 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); + 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 + bool mWriteEnabled; // disable this to do things like determine filesize without actually copying data }; class LLDataPackerBinaryBuffer : public LLDataPacker @@ -120,7 +120,7 @@ public: mCurBufferp(bufferp), mBufferSize(size) { - mWriteEnabled = TRUE; + mWriteEnabled = true; } LLDataPackerBinaryBuffer() @@ -131,58 +131,58 @@ public: { } - /*virtual*/ BOOL packString(const std::string& value, const char *name); - /*virtual*/ BOOL unpackString(std::string& value, const char *name); + /*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 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 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 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 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 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 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 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 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 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 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 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 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 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); + /*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 freeBuffer() { delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = false; } void assignBuffer(U8 *bufferp, S32 size) { if(mBufferp && mBufferp != bufferp) @@ -192,31 +192,31 @@ public: mBufferp = bufferp; mCurBufferp = bufferp; mBufferSize = size; - mWriteEnabled = TRUE; + mWriteEnabled = true; } const LLDataPackerBinaryBuffer& operator=(const LLDataPackerBinaryBuffer &a); - /*virtual*/ BOOL hasNext() const { return getCurrentSize() < getBufferSize(); } + /*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); } /*virtual*/ void dumpBufferToLog(); protected: - inline BOOL verifyLength(const S32 data_size, const char *name); + 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) +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 false; } - return TRUE; + return true; } class LLDataPackerAsciiBuffer : public LLDataPacker @@ -228,8 +228,8 @@ public: mCurBufferp = bufferp; mBufferSize = size; mPassFlags = 0; - mIncludeNames = FALSE; - mWriteEnabled = TRUE; + mIncludeNames = false; + mWriteEnabled = true; } LLDataPackerAsciiBuffer() @@ -238,57 +238,57 @@ public: mCurBufferp = NULL; mBufferSize = 0; mPassFlags = 0; - mIncludeNames = FALSE; - mWriteEnabled = FALSE; + 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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); + /*virtual*/ bool packUUID(const LLUUID &value, const char *name); + /*virtual*/ bool unpackUUID(LLUUID &value, const char *name); - void setIncludeNames(BOOL b) { mIncludeNames = b; } + 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; } @@ -296,7 +296,7 @@ public: S32 getBufferSize() const { return mBufferSize; } /*virtual*/ void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); } - /*virtual*/ BOOL hasNext() const { return getCurrentSize() < getBufferSize(); } + /*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); } inline void freeBuffer(); inline void assignBuffer(char* bufferp, S32 size); @@ -304,15 +304,15 @@ public: protected: void writeIndentedName(const char *name); - BOOL getValueStr(const char *name, char *out_value, const S32 value_len); + bool getValueStr(const char *name, char *out_value, const S32 value_len); protected: - inline BOOL verifyLength(const S32 data_size, const char *name); + 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 + bool mIncludeNames; // useful for debugging, print the name of each field }; inline void LLDataPackerAsciiBuffer::freeBuffer() @@ -320,7 +320,7 @@ inline void LLDataPackerAsciiBuffer::freeBuffer() delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; - mWriteEnabled = FALSE; + mWriteEnabled = false; } inline void LLDataPackerAsciiBuffer::assignBuffer(char* bufferp, S32 size) @@ -328,19 +328,19 @@ inline void LLDataPackerAsciiBuffer::assignBuffer(char* bufferp, S32 size) mBufferp = bufferp; mCurBufferp = bufferp; mBufferSize = size; - mWriteEnabled = TRUE; + mWriteEnabled = true; } -inline BOOL LLDataPackerAsciiBuffer::verifyLength(const S32 data_size, const char *name) +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 false; } - return TRUE; + return true; } class LLDataPackerAsciiFile : public LLDataPacker @@ -362,7 +362,7 @@ public: mOutputStream(&output_stream), mInputStream(NULL) { - mWriteEnabled = TRUE; + mWriteEnabled = true; } LLDataPackerAsciiFile(std::istream& input_stream, const S32 indent = 2) @@ -374,55 +374,55 @@ public: { } - /*virtual*/ BOOL packString(const std::string& value, const char *name); - /*virtual*/ BOOL unpackString(std::string& value, const char *name); + /*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 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 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 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 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 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 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 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 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 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 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 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 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 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); + /*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); + bool getValueStr(const char *name, char *out_value, const S32 value_len); - /*virtual*/ BOOL hasNext() const { return true; } + /*virtual*/ bool hasNext() const { return true; } protected: S32 mIndent; -- cgit v1.2.3 From f1c97f4057833220a2e9ac045d701208e30457d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Sun, 18 Feb 2024 16:41:22 +0100 Subject: misc: BOOL to bool --- indra/llmessage/llassetstorage.cpp | 46 ++++++++-------- indra/llmessage/llassetstorage.h | 22 ++++---- indra/llmessage/llcachename.cpp | 30 +++++----- indra/llmessage/llcachename.h | 8 +-- indra/llmessage/llcircuit.cpp | 60 ++++++++++---------- indra/llmessage/llcircuit.h | 34 ++++++------ indra/llmessage/llclassifiedflags.cpp | 4 +- indra/llmessage/llclassifiedflags.h | 2 +- indra/llmessage/llhost.cpp | 6 +- indra/llmessage/llhost.h | 2 +- indra/llmessage/llinstantmessage.cpp | 4 +- indra/llmessage/llinstantmessage.h | 4 +- indra/llmessage/llmail.cpp | 8 +-- indra/llmessage/llmail.h | 4 +- indra/llmessage/llmessagebuilder.h | 12 ++-- indra/llmessage/llmessagereader.cpp | 8 +-- indra/llmessage/llmessagereader.h | 5 +- indra/llmessage/llmessagetemplateparser.cpp | 64 +++++++++++----------- indra/llmessage/llmessagethrottle.cpp | 16 +++--- indra/llmessage/llmessagethrottle.h | 4 +- indra/llmessage/llnamevalue.cpp | 4 +- indra/llmessage/llnamevalue.h | 4 +- indra/llmessage/llpacketack.cpp | 2 +- indra/llmessage/llpacketring.cpp | 12 ++-- indra/llmessage/llpacketring.h | 12 ++-- indra/llmessage/llpartdata.cpp | 80 +++++++++++++-------------- indra/llmessage/llpartdata.h | 16 +++--- indra/llmessage/llsdmessagebuilder.cpp | 22 ++++---- indra/llmessage/llsdmessagebuilder.h | 12 ++-- indra/llmessage/lltemplatemessagebuilder.cpp | 26 ++++----- indra/llmessage/lltemplatemessagebuilder.h | 12 ++-- indra/llmessage/lltemplatemessagereader.cpp | 36 ++++++------ indra/llmessage/lltemplatemessagereader.h | 8 +-- indra/llmessage/llthrottle.cpp | 64 +++++++++++----------- indra/llmessage/llthrottle.h | 12 ++-- indra/llmessage/lltransfermanager.cpp | 16 +++--- indra/llmessage/lltransfermanager.h | 10 ++-- indra/llmessage/lltransfersourceasset.cpp | 10 ++-- indra/llmessage/lltransfersourceasset.h | 8 +-- indra/llmessage/lltransfersourcefile.cpp | 10 ++-- indra/llmessage/lltransfersourcefile.h | 6 +- indra/llmessage/lluseroperation.cpp | 8 +-- indra/llmessage/lluseroperation.h | 8 +-- indra/llmessage/llxfer.cpp | 2 +- indra/llmessage/llxfer.h | 2 +- indra/llmessage/llxfer_file.cpp | 4 +- indra/llmessage/llxfer_file.h | 4 +- indra/llmessage/llxfer_vfile.cpp | 4 +- indra/llmessage/llxfer_vfile.h | 4 +- indra/llmessage/llxfermanager.cpp | 14 ++--- indra/llmessage/llxfermanager.h | 20 +++---- indra/llmessage/llxorcipher.cpp | 6 +- indra/llmessage/message.cpp | 82 ++++++++++++++-------------- indra/llmessage/message.h | 34 ++++++------ indra/llmessage/partsyspacket.cpp | 16 +++--- indra/llmessage/partsyspacket.h | 8 +-- 56 files changed, 471 insertions(+), 470 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 60d95c3367..2f76e686ec 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -354,9 +354,9 @@ void LLAssetStorage::_init(LLMessageSystem *msg, LLAssetStorage::~LLAssetStorage() { - mShutDown = TRUE; + mShutDown = true; - _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE); + _cleanupRequests(true, LL_ERR_CIRCUIT_GONE); if (gMessageSystem) { @@ -378,10 +378,10 @@ void LLAssetStorage::setUpstream(const LLHost &upstream_host) void LLAssetStorage::checkForTimeouts() { - _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT); + _cleanupRequests(false, LL_ERR_TCP_TIMEOUT); } -void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) +void LLAssetStorage::_cleanupRequests(bool all, S32 error) { F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); @@ -436,7 +436,7 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) } -BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type) +bool LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type) { return LLFileSystem::getExists(uuid, type); } @@ -450,7 +450,7 @@ bool LLAssetStorage::findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetTyp llassert(callback != NULL); } - BOOL exists = LLFileSystem::getExists(uuid, type); + bool exists = LLFileSystem::getExists(uuid, type); if (exists) { LLFileSystem file(uuid, type); @@ -482,7 +482,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLAssetStorage::LLGetAssetCallback callback, void *user_data, - BOOL is_priority) + bool is_priority) { LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; @@ -523,7 +523,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, return; } - BOOL exists = LLFileSystem::getExists(uuid, type); + bool exists = LLFileSystem::getExists(uuid, type); LLFileSystem file(uuid, type); U32 size = exists ? file.getSize() : 0; @@ -547,7 +547,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, file.remove(); } - BOOL duplicate = FALSE; + bool duplicate = false; // check to see if there's a pending download of this uuid already for (request_list_t::iterator iter = mPendingDownloads.begin(); @@ -566,7 +566,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, // this is a duplicate request // queue the request, but don't actually ask for it again - duplicate = TRUE; + duplicate = true; } } if (duplicate) @@ -700,7 +700,7 @@ void LLAssetStorage::getEstateAsset( EstateAssetType etype, LLGetAssetCallback callback, void *user_data, - BOOL is_priority) + bool is_priority) { LL_DEBUGS() << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << LL_ENDL; @@ -724,7 +724,7 @@ void LLAssetStorage::getEstateAsset( return; } - BOOL exists = LLFileSystem::getExists(asset_id, atype); + bool exists = LLFileSystem::getExists(asset_id, atype); LLFileSystem file(asset_id, atype); U32 size = exists ? file.getSize() : 0; @@ -846,7 +846,7 @@ void LLAssetStorage::getInvItemAsset( LLAssetType::EType atype, LLGetAssetCallback callback, void *user_data, - BOOL is_priority) + bool is_priority) { LL_DEBUGS() << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << LL_ENDL; @@ -995,12 +995,12 @@ void LLAssetStorage::uploadCompleteCallback( return; } LLAssetRequest *req = (LLAssetRequest *)user_data; - BOOL success = TRUE; + bool success = true; if (result) { LL_WARNS("AssetStorage") << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << LL_ENDL; - success = FALSE; + success = false; } // we're done grabbing the file, tell the client @@ -1030,7 +1030,7 @@ void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_dat this_ptr->_callUploadCallbacks(uuid, asset_type, success, LLExtStat::NONE); } -void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status ) +void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, bool success, LLExtStat ext_status ) { // SJB: We process the callbacks in reverse order, I do not know if this is important, // but I didn't want to mess with it. @@ -1348,7 +1348,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, S32, LLExtStat), void *user_data, - BOOL is_priority) + bool is_priority) { // check for duplicates here, since we're about to fool the normal duplicate checker for (request_list_t::iterator iter = mPendingDownloads.begin(); @@ -1391,7 +1391,7 @@ void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, std::string filename; // Check if the asset is marked toxic, and don't load bad stuff - BOOL toxic = gAssetStorage->isAssetToxic( uuid ); + bool toxic = gAssetStorage->isAssetToxic( uuid ); if ( !status && !toxic ) @@ -1489,9 +1489,9 @@ void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::ET // Check if an asset is in the toxic map. If it is, the entry is updated -BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) +bool LLAssetStorage::isAssetToxic( const LLUUID& uuid ) { - BOOL is_toxic = FALSE; + bool is_toxic = false; if ( !uuid.isNull() ) { @@ -1499,8 +1499,8 @@ BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) if ( iter != mToxicAssetMap.end() ) { // Found toxic asset (*iter).second = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; - is_toxic = TRUE; - } + is_toxic = true; + } } return is_toxic; } @@ -1509,7 +1509,7 @@ BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) // Clean the toxic asset list, remove old entries -void LLAssetStorage::flushOldToxicAssets( BOOL force_it ) +void LLAssetStorage::flushOldToxicAssets( bool force_it ) { // Scan and look for old entries U64 now = LLFrameTimer::getTotalTime(); diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index 274e6a50ad..d9c95485f6 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -232,11 +232,11 @@ public: void setUpstream(const LLHost &upstream_host); - BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); + 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); + void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, bool is_priority = false); /* * TransactionID version @@ -259,19 +259,19 @@ public: 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); + 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. + 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 ); + bool isAssetToxic( const LLUUID& uuid ); // Clean the toxic asset list, remove old entries - void flushOldToxicAssets( BOOL force_it ); + void flushOldToxicAssets( bool force_it ); // Add an item to the toxic asset map void markAssetToxic( const LLUUID& uuid ); @@ -352,7 +352,7 @@ public: // 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); + 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 @@ -374,12 +374,12 @@ public: // 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); + 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; + void *user_data, bool duplicate, + bool is_priority) = 0; private: void _init(LLMessageSystem *msg, diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index a2e85cf6c2..59dd64336e 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -215,7 +215,7 @@ public: Impl(LLMessageSystem* msg); ~Impl(); - BOOL getName(const LLUUID& id, std::string& first, std::string& last); + 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); @@ -402,13 +402,13 @@ void LLCacheName::exportFile(std::ostream& ostr) } -BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last) +bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last) { if(id.isNull()) { first = sCacheName["nobody"]; last.clear(); - return TRUE; + return true; } LLCacheNameEntry* entry = get_ptr_in_map(mCache, id ); @@ -416,7 +416,7 @@ BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::strin { first = entry->mFirstName; last = entry->mLastName; - return TRUE; + return true; } else { @@ -426,7 +426,7 @@ BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::strin { mAskNameQueue.insert(id); } - return FALSE; + return false; } } @@ -440,22 +440,22 @@ void LLCacheName::localizeCacheName(std::string key, std::string value) LL_WARNS()<< " Error localizing cache key " << key << " To "<< value<mGroupName; - return TRUE; + return true; } else { @@ -480,27 +480,27 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) { impl.mAskGroupQueue.insert(id); } - return FALSE; + return false; } } -BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id) +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) +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; + return true; } else { - return FALSE; + return false; } } diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index d238c3a247..d4c18d4d4c 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -71,11 +71,11 @@ public: // If available, copies name ("bobsmith123" or "James Linden") into string // If not available, copies the string "waiting". // Returns TRUE iff available. - BOOL getFullName(const LLUUID& id, std::string& full_name); + 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); + 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 @@ -100,7 +100,7 @@ public: // provided. The caller must allocate at least // DB_GROUP_NAME_BUF_SIZE characters. If not available, this // method copies the string "waiting". Returns TRUE iff available. - BOOL getGroupName(const LLUUID& id, std::string& group); + 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 diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index a9a292958f..bb667201a0 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -282,7 +282,7 @@ S32 LLCircuitData::resendUnackedPackets(const F64Seconds now) // reliable_iter iter; - BOOL have_resend_overflow = FALSE; + bool have_resend_overflow = false; for (iter = mUnackedPackets.begin(); iter != mUnackedPackets.end();) { packetp = iter->second; @@ -488,7 +488,7 @@ void LLCircuit::removeCircuitData(const LLHost &host) mLastCircuit = NULL; } -void LLCircuitData::setAlive(BOOL b_alive) +void LLCircuitData::setAlive(bool b_alive) { if (mbAlive != b_alive) { @@ -500,12 +500,12 @@ void LLCircuitData::setAlive(BOOL b_alive) { mLastPingReceivedTime = LLMessageSystem::getMessageTimeSeconds(); mPingsInTransit = 0; - mBlocked = FALSE; + mBlocked = false; } } -void LLCircuitData::setAllowTimeout(BOOL allow) +void LLCircuitData::setAllowTimeout(bool allow) { mbAllowTimeout = allow; @@ -513,7 +513,7 @@ void LLCircuitData::setAllowTimeout(BOOL allow) { // resuming circuit // make sure it's alive - setAlive(TRUE); + setAlive(true); } } @@ -599,7 +599,7 @@ void LLCircuit::resendUnackedPackets(S32& unacked_list_length, S32& unacked_list } -BOOL LLCircuitData::isDuplicateResend(TPACKETID packetnum) +bool LLCircuitData::isDuplicateResend(TPACKETID packetnum) { return (mRecentlyReceivedReliablePackets.find(packetnum) != mRecentlyReceivedReliablePackets.end()); } @@ -632,7 +632,7 @@ LLCircuitData* LLCircuit::findCircuit(const LLHost& host) const } -BOOL LLCircuit::isCircuitAlive(const LLHost& host) const +bool LLCircuit::isCircuitAlive(const LLHost& host) const { LLCircuitData *cdp = findCircuit(host); if(cdp) @@ -640,7 +640,7 @@ BOOL LLCircuit::isCircuitAlive(const LLHost& host) const return cdp->mbAlive; } - return FALSE; + return false; } void LLCircuitData::setTimeoutCallback(void (*callback_func)(const LLHost &host, void *user_data), void *user_data) @@ -649,7 +649,7 @@ void LLCircuitData::setTimeoutCallback(void (*callback_func)(const LLHost &host, mTimeoutUserData = user_data; } -void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) +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. @@ -844,7 +844,7 @@ void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys) } -BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) +bool LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) { F64Seconds cur_time = LLMessageSystem::getMessageTimeSeconds(); mLastPingSendTime = cur_time; @@ -852,7 +852,7 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) if (!checkCircuitTimeout()) { // Pass this back to the calling LLCircuit, this circuit needs to be cleaned up. - return FALSE; + return false; } // WARNING! @@ -866,7 +866,7 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) // 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; + bool wrapped = false; reliable_iter iter; iter = mUnackedPackets.upper_bound(getPacketOutID()); if (iter == mUnackedPackets.end()) @@ -874,19 +874,19 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) // Nothing AFTER this one, so we want the lowest packet ID // then. iter = mUnackedPackets.begin(); - wrapped = TRUE; + wrapped = true; } TPACKETID packet_id = 0; // Check against the "final" packets - BOOL wrapped_final = FALSE; + 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; + wrapped_final = true; } //LL_INFOS() << mHost << " - unacked count " << mUnackedPackets.size() << LL_ENDL; @@ -922,12 +922,12 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) } else { - BOOL had_unacked = FALSE; + bool had_unacked = false; if (iter != mUnackedPackets.end()) { // Unacked list has the lowest so far packet_id = iter->first; - had_unacked = TRUE; + had_unacked = true; //LL_INFOS() << mHost << ": Unacked" << LL_ENDL; } @@ -989,7 +989,7 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) } } - return TRUE; + return true; } @@ -1041,7 +1041,7 @@ void LLCircuitData::clearDuplicateList(TPACKETID oldest_id) //LL_INFOS() << "Recent list after: " << mRecentlyReceivedReliablePackets.size() << LL_ENDL; } -BOOL LLCircuitData::checkCircuitTimeout() +bool LLCircuitData::checkCircuitTimeout() { F64Seconds time_since_last_ping = LLMessageSystem::getMessageTimeSeconds() - mLastPingReceivedTime; @@ -1049,7 +1049,7 @@ BOOL LLCircuitData::checkCircuitTimeout() if (time_since_last_ping > mHeartbeatTimeout) { LL_WARNS() << "LLCircuitData::checkCircuitTimeout for " << mHost << " last ping " << time_since_last_ping << " seconds ago." < PING_START_BLOCK)) { - mBlocked = TRUE; + mBlocked = true; } } @@ -1344,19 +1344,19 @@ U32 LLCircuitData::getPacketsLost() const } -BOOL LLCircuitData::isAlive() const +bool LLCircuitData::isAlive() const { return mbAlive; } -BOOL LLCircuitData::isBlocked() const +bool LLCircuitData::isBlocked() const { return mBlocked; } -BOOL LLCircuitData::getAllowTimeout() const +bool LLCircuitData::getAllowTimeout() const { return mbAllowTimeout; } @@ -1402,13 +1402,13 @@ F32Milliseconds LLCircuitData::getPingDelayAveraged() } -BOOL LLCircuitData::getTrusted() const +bool LLCircuitData::getTrusted() const { return mTrusted; } -void LLCircuitData::setTrusted(BOOL t) +void LLCircuitData::setTrusted(bool t) { mTrusted = t; } diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h index b8021bc9f0..95e470b543 100644 --- a/indra/llmessage/llcircuit.h +++ b/indra/llmessage/llcircuit.h @@ -100,7 +100,7 @@ public: void setRemoteID(const LLUUID& id) { mRemoteID = id; } void setRemoteSessionID(const LLUUID& id) { mRemoteSessionID = id; } - void setTrusted(BOOL t); + void setTrusted(bool t); // The local end point ID is used when establishing a trusted circuit. // no matching set function for getLocalEndPointID() @@ -111,9 +111,9 @@ public: S32 getPingsInTransit() const { return mPingsInTransit; } // ACCESSORS - BOOL isAlive() const; - BOOL isBlocked() const; - BOOL getAllowTimeout() const; + bool isAlive() const; + bool isBlocked() const; + bool getAllowTimeout() const; F32Milliseconds getPingDelayAveraged(); F32Milliseconds getPingInTransitTime(); U32 getPacketsIn() const; @@ -122,7 +122,7 @@ public: U32 getPacketsOut() const; U32 getPacketsLost() const; TPACKETID getPacketOutID() const; - BOOL getTrusted() const; + bool getTrusted() const; F32 getAgeInSeconds() const; S32 getUnackedPacketCount() const { return mUnackedPacketCount; } S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; } @@ -164,31 +164,31 @@ public: protected: TPACKETID nextPacketOutID(); void setPacketInID(TPACKETID id); - void checkPacketInID(TPACKETID id, BOOL receive_resent); + 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 + 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 + 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); + 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); + 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); + void setAlive(bool b_alive); + void setAllowTimeout(bool allow); protected: // Identification for this circuit. @@ -212,12 +212,12 @@ protected: 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 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 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 + 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. @@ -293,7 +293,7 @@ public: // ACCESSORS LLCircuitData* findCircuit(const LLHost& host) const; - BOOL isCircuitAlive(const LLHost& host) const; + bool isCircuitAlive(const LLHost& host) const; // MANIPULATORS LLCircuitData *addCircuitData(const LLHost &host, TPACKETID in_id); diff --git a/indra/llmessage/llclassifiedflags.cpp b/indra/llmessage/llclassifiedflags.cpp index f6084d4a60..bf8c9171a7 100644 --- a/indra/llmessage/llclassifiedflags.cpp +++ b/indra/llmessage/llclassifiedflags.cpp @@ -36,7 +36,7 @@ #include "llclassifiedflags.h" -ClassifiedFlags pack_classified_flags_request(BOOL auto_renew, BOOL inc_pg, BOOL inc_mature, BOOL inc_adult) +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; @@ -47,7 +47,7 @@ ClassifiedFlags pack_classified_flags_request(BOOL auto_renew, BOOL inc_pg, BOOL return rv; } -ClassifiedFlags pack_classified_flags(BOOL auto_renew, BOOL inc_pg, BOOL inc_mature, BOOL inc_adult) +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; diff --git a/indra/llmessage/llclassifiedflags.h b/indra/llmessage/llclassifiedflags.h index 17fc867453..0365ea8f09 100644 --- a/indra/llmessage/llclassifiedflags.h +++ b/indra/llmessage/llclassifiedflags.h @@ -51,7 +51,7 @@ 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_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); diff --git a/indra/llmessage/llhost.cpp b/indra/llmessage/llhost.cpp index ae5c2ecf69..30e4109729 100644 --- a/indra/llmessage/llhost.cpp +++ b/indra/llmessage/llhost.cpp @@ -103,7 +103,7 @@ std::string LLHost::getHostName() const } } -BOOL LLHost::setHostByName(const std::string& hostname) +bool LLHost::setHostByName(const std::string& hostname) { hostent *he; std::string local_name(hostname); @@ -123,7 +123,7 @@ BOOL LLHost::setHostByName(const std::string& hostname) if (he) { mIP = *(U32 *)he->h_addr_list[0]; - return TRUE; + return true; } else { @@ -147,7 +147,7 @@ BOOL LLHost::setHostByName(const std::string& hostname) LL_WARNS() << "LLHost::setAddress(): unknown error - " << error_number << LL_ENDL; break; } - return FALSE; + return false; } } diff --git a/indra/llmessage/llhost.h b/indra/llmessage/llhost.h index 79cad4b123..dd12e381d4 100644 --- a/indra/llmessage/llhost.h +++ b/indra/llmessage/llhost.h @@ -80,7 +80,7 @@ public: 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); + bool setHostByName(const std::string& hname); LLHost& operator=(const LLHost &rhs); void invalidate() { mIP = INVALID_HOST_IP_ADDRESS; mPort = INVALID_PORT;}; diff --git a/indra/llmessage/llinstantmessage.cpp b/indra/llmessage/llinstantmessage.cpp index dd5a655d7e..52102e55c8 100644 --- a/indra/llmessage/llinstantmessage.cpp +++ b/indra/llmessage/llinstantmessage.cpp @@ -54,7 +54,7 @@ const S32 IM_TTL = 1; void pack_instant_message( LLMessageSystem* msg, const LLUUID& from_id, - BOOL from_group, + bool from_group, const LLUUID& session_id, const LLUUID& to_id, const std::string& name, @@ -93,7 +93,7 @@ void pack_instant_message( void pack_instant_message_block( LLMessageSystem* msg, const LLUUID& from_id, - BOOL from_group, + bool from_group, const LLUUID& session_id, const LLUUID& to_id, const std::string& name, diff --git a/indra/llmessage/llinstantmessage.h b/indra/llmessage/llinstantmessage.h index 55cda15405..383fe2591a 100644 --- a/indra/llmessage/llinstantmessage.h +++ b/indra/llmessage/llinstantmessage.h @@ -180,7 +180,7 @@ extern const S32 IM_TTL; void pack_instant_message( LLMessageSystem* msgsystem, const LLUUID& from_id, - BOOL from_group, + bool from_group, const LLUUID& session_id, const LLUUID& to_id, const std::string& name, @@ -198,7 +198,7 @@ void pack_instant_message( void pack_instant_message_block( LLMessageSystem* msgsystem, const LLUUID& from_id, - BOOL from_group, + bool from_group, const LLUUID& session_id, const LLUUID& to_id, const std::string& name, diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index fcda2a85f6..b22cd8cccd 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -102,7 +102,7 @@ void disconnect_smtp() // Returns TRUE on success. // message should NOT be SMTP escaped. // static -BOOL LLMail::send( +bool LLMail::send( const char* from_name, const char* from_address, const char* to_name, @@ -120,7 +120,7 @@ BOOL LLMail::send( headers); if(header.empty()) { - return FALSE; + return false; } std::string message_str; @@ -129,8 +129,8 @@ BOOL LLMail::send( message_str = message; } bool rv = send(header, message_str, to_address, from_address); - if(rv) return TRUE; - return FALSE; + if(rv) return true; + return false; } // static diff --git a/indra/llmessage/llmail.h b/indra/llmessage/llmail.h index 3791714363..f97a443c47 100644 --- a/indra/llmessage/llmail.h +++ b/indra/llmessage/llmail.h @@ -48,7 +48,7 @@ public: * @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. + * @return Returns true if the call succeeds, false otherwise. * * Results in: * From: "from_name" @@ -57,7 +57,7 @@ public: * * message */ - static BOOL send( + static bool send( const char* from_name, const char* from_address, const char* to_name, diff --git a/indra/llmessage/llmessagebuilder.h b/indra/llmessage/llmessagebuilder.h index bf5be929f2..75bd5f5cc7 100644 --- a/indra/llmessage/llmessagebuilder.h +++ b/indra/llmessage/llmessagebuilder.h @@ -49,14 +49,14 @@ public: virtual void newMessage(const char* name) = 0; virtual void nextBlock(const char* blockname) = 0; - virtual BOOL removeLastBlock() = 0; // TODO: babbage: remove this horror + 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 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; @@ -76,12 +76,12 @@ public: 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 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 bool isBuilt() const = 0; + virtual bool isClear() const = 0; virtual U32 buildMessage( U8* buffer, U32 buffer_size, @@ -90,7 +90,7 @@ public: virtual void clearMessage() = 0; // TODO: babbage: remove this horror - virtual void setBuilt(BOOL b) = 0; + virtual void setBuilt(bool b) = 0; virtual const char* getMessageName() const = 0; diff --git a/indra/llmessage/llmessagereader.cpp b/indra/llmessage/llmessagereader.cpp index 1d1bee7f59..4a6f5145b3 100644 --- a/indra/llmessage/llmessagereader.cpp +++ b/indra/llmessage/llmessagereader.cpp @@ -27,7 +27,7 @@ #include "linden_common.h" #include "llmessagereader.h" -static BOOL sTimeDecodes = FALSE; +static bool sTimeDecodes = false; static F32 sTimeDecodesSpamThreshold = 0.05f; @@ -38,7 +38,7 @@ LLMessageReader::~LLMessageReader() } //static -void LLMessageReader::setTimeDecodes(BOOL b) +void LLMessageReader::setTimeDecodes(bool b) { sTimeDecodes = b; } @@ -49,8 +49,8 @@ void LLMessageReader::setTimeDecodesSpamThreshold(F32 seconds) sTimeDecodesSpamThreshold = seconds; } -//static -BOOL LLMessageReader::getTimeDecodes() +//static +bool LLMessageReader::getTimeDecodes() { return sTimeDecodes; } diff --git a/indra/llmessage/llmessagereader.h b/indra/llmessage/llmessagereader.h index 647f267785..2f64371f63 100644 --- a/indra/llmessage/llmessagereader.h +++ b/indra/llmessage/llmessagereader.h @@ -84,8 +84,9 @@ class LLMessageReader virtual void copyToBuilder(LLMessageBuilder&) const = 0; - static void setTimeDecodes(BOOL b); - static BOOL getTimeDecodes(); + + static void setTimeDecodes(bool b); + static bool getTimeDecodes(); static void setTimeDecodesSpamThreshold(F32 seconds); static F32 getTimeDecodesSpamThreshold(); }; diff --git a/indra/llmessage/llmessagetemplateparser.cpp b/indra/llmessage/llmessagetemplateparser.cpp index 1f7c09dbe5..3e81fed49e 100644 --- a/indra/llmessage/llmessagetemplateparser.cpp +++ b/indra/llmessage/llmessagetemplateparser.cpp @@ -42,7 +42,7 @@ // * - repeat last check // checks 'a' -BOOL b_return_alphanumeric_ok(char c) +bool b_return_alphanumeric_ok(char c) { if ( ( (c < 'A') ||(c > 'Z')) @@ -51,26 +51,26 @@ BOOL b_return_alphanumeric_ok(char c) &&( (c < '0') ||(c > '9'))) { - return FALSE; + return false; } - return TRUE; + return true; } // checks 'c' -BOOL b_return_character_ok(char c) +bool b_return_character_ok(char c) { if ( ( (c < 'A') ||(c > 'Z')) &&( (c < 'a') ||(c > 'z'))) { - return FALSE; + return false; } - return TRUE; + return true; } // checks 'f' -BOOL b_return_first_variable_ok(char c) +bool b_return_first_variable_ok(char c) { if ( ( (c < 'A') ||(c > 'Z')) @@ -78,13 +78,13 @@ BOOL b_return_first_variable_ok(char c) ||(c > 'z')) &&(c != '_')) { - return FALSE; + return false; } - return TRUE; + return true; } // checks 'v' -BOOL b_return_variable_ok(char c) +bool b_return_variable_ok(char c) { if ( ( (c < 'A') ||(c > 'Z')) @@ -94,35 +94,35 @@ BOOL b_return_variable_ok(char c) ||(c > '9')) &&(c != '_')) { - return FALSE; + return false; } - return TRUE; + return true; } // checks 's' -BOOL b_return_signed_integer_ok(char c) +bool b_return_signed_integer_ok(char c) { if ( ( (c < '0') ||(c > '9')) &&(c != '-')) { - return FALSE; + return false; } - return TRUE; + return true; } // checks 'd' -BOOL b_return_integer_ok(char c) +bool b_return_integer_ok(char c) { if ( (c < '0') ||(c > '9')) { - return FALSE; + return false; } - return TRUE; + return true; } -BOOL (*gParseCheckCharacters[])(char c) = +bool (*gParseCheckCharacters[])(char c) = { b_return_alphanumeric_ok, b_return_character_ok, @@ -156,7 +156,7 @@ S32 get_checker_number(char checker) } // check token based on passed simplified regular expression -BOOL b_check_token(const char *token, const char *regexp) +bool b_check_token(const char *token, const char *regexp) { S32 tptr, rptr = 0; S32 current_checker, next_checker = 0; @@ -166,13 +166,13 @@ BOOL b_check_token(const char *token, const char *regexp) if (current_checker == -1) { LL_ERRS() << "Invalid regular expression value!" << LL_ENDL; - return FALSE; + return false; } if (current_checker == 9999) { LL_ERRS() << "Regular expression can't start with *!" << LL_ENDL; - return FALSE; + return false; } for (tptr = 0; token[tptr]; tptr++) @@ -196,40 +196,40 @@ BOOL b_check_token(const char *token, const char *regexp) } } } - return TRUE; + 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) +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 false; } - return TRUE; + 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) +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 false; } - return TRUE; + return true; } // An integer is made up of the digits 0-9 -BOOL b_positive_integer_ok(const char *token) +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 false; } - return TRUE; + return true; } diff --git a/indra/llmessage/llmessagethrottle.cpp b/indra/llmessage/llmessagethrottle.cpp index 14582aaf32..bddb9e14d6 100644 --- a/indra/llmessage/llmessagethrottle.cpp +++ b/indra/llmessage/llmessagethrottle.cpp @@ -66,13 +66,13 @@ void LLMessageThrottle::pruneEntries() // Look for the first entry younger than the maximum age. F32 max_age = (F32)MAX_MESSAGE_AGE[cat]; - BOOL found = FALSE; + 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; + found = true; // Did we find at least one entry to remove? if (r_iterator != message_list->rbegin()) @@ -95,7 +95,7 @@ void LLMessageThrottle::pruneEntries() } } -BOOL LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg) +bool LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg) { message_list_t* message_list = &(mMessageList[MTC_VIEWER_ALERT]); @@ -114,16 +114,16 @@ BOOL LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg { // This message was not found. Add it to the list. message_list->push_front(entry); - return TRUE; + return true; } else { // This message was already in the list. - return FALSE; + return false; } } -BOOL LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, const std::string& mesg) +bool LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, const std::string& mesg) { message_list_t* message_list = &(mMessageList[MTC_AGENT_ALERT]); @@ -142,12 +142,12 @@ BOOL LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, c { // This message was not found. Add it to the list. message_list->push_front(entry); - return TRUE; + return true; } else { // This message was already in the list. - return FALSE; + return false; } } diff --git a/indra/llmessage/llmessagethrottle.h b/indra/llmessage/llmessagethrottle.h index 4ea84f712a..ae62b43920 100644 --- a/indra/llmessage/llmessagethrottle.h +++ b/indra/llmessage/llmessagethrottle.h @@ -59,8 +59,8 @@ public: LLMessageThrottle(); ~LLMessageThrottle(); - BOOL addViewerAlert (const LLUUID& to, const std::string& mesg); - BOOL addAgentAlert (const LLUUID& agent, const LLUUID& task, const std::string& mesg); + bool addViewerAlert (const LLUUID& to, const std::string& mesg); + bool addAgentAlert (const LLUUID& agent, const LLUUID& task, const std::string& mesg); void pruneEntries(); diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp index c51883ee3d..761e990c76 100644 --- a/indra/llmessage/llnamevalue.cpp +++ b/indra/llmessage/llnamevalue.cpp @@ -676,13 +676,13 @@ LLVector3 *LLNameValue::getVec3() } -BOOL LLNameValue::sendToData() const +bool LLNameValue::sendToData() const { return (mSendto == NVS_DATA_SIM || mSendto == NVS_DATA_SIM_VIEWER); } -BOOL LLNameValue::sendToViewer() const +bool LLNameValue::sendToViewer() const { return (mSendto == NVS_SIM_VIEWER || mSendto == NVS_DATA_SIM_VIEWER); } diff --git a/indra/llmessage/llnamevalue.h b/indra/llmessage/llnamevalue.h index f8b556b5fe..92b20284ef 100644 --- a/indra/llmessage/llnamevalue.h +++ b/indra/llmessage/llnamevalue.h @@ -139,8 +139,8 @@ public: const char *getClass() const { return mStringClass; } const char *getSendto() const { return mStringSendto; } - BOOL sendToData() const; - BOOL sendToViewer() const; + bool sendToData() const; + bool sendToViewer() const; void callCallback(); std::string printNameValue() const; diff --git a/indra/llmessage/llpacketack.cpp b/indra/llmessage/llpacketack.cpp index c3c022c297..8e04934286 100644 --- a/indra/llmessage/llpacketack.cpp +++ b/indra/llmessage/llpacketack.cpp @@ -58,7 +58,7 @@ LLReliablePacket::LLReliablePacket( else { mRetries = 0; - mPingBasedRetry = TRUE; + mPingBasedRetry = true; mTimeout = F32Seconds(0.f); mCallback = NULL; mCallbackData = NULL; diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 687212ea10..7ba76bea25 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -97,12 +97,12 @@ void LLPacketRing::setDropPercentage (F32 percent_to_drop) mDropPercentage = percent_to_drop; } -void LLPacketRing::setUseInThrottle(const BOOL use_throttle) +void LLPacketRing::setUseInThrottle(const bool use_throttle) { mUseInThrottle = use_throttle; } -void LLPacketRing::setUseOutThrottle(const BOOL use_throttle) +void LLPacketRing::setUseOutThrottle(const bool use_throttle) { mUseOutThrottle = use_throttle; } @@ -161,7 +161,7 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap) // If using the throttle, simulate a limited size input buffer. if (mUseInThrottle) { - BOOL done = FALSE; + bool done = false; // push any current net packet (if any) onto delay ring while (!done) @@ -270,9 +270,9 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap) return packet_size; } -BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host) +bool LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host) { - BOOL status = TRUE; + bool status = true; if (!mUseOutThrottle) { return sendPacketImpl(h_socket, send_buffer, buf_size, host ); @@ -344,7 +344,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL return status; } -BOOL LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host) +bool LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host) { if (!LLProxy::isSOCKSProxyEnabled()) diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index b214271e78..888ee927b5 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -46,14 +46,14 @@ public: void dropPackets(U32); void setDropPercentage (F32 percent_to_drop); - void setUseInThrottle(const BOOL use_throttle); - void setUseOutThrottle(const BOOL use_throttle); + 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); + bool sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host); inline LLHost getLastSender(); inline LLHost getLastReceivingInterface(); @@ -61,8 +61,8 @@ public: S32 getAndResetActualInBits() { S32 bits = mActualBitsIn; mActualBitsIn = 0; return bits;} S32 getAndResetActualOutBits() { S32 bits = mActualBitsOut; mActualBitsOut = 0; return bits;} protected: - BOOL mUseInThrottle; - BOOL mUseOutThrottle; + bool mUseInThrottle; + bool mUseOutThrottle; // For simulating a lower-bandwidth connection - BPS LLThrottle mInThrottle; @@ -84,7 +84,7 @@ protected: LLHost mLastReceivingIF; private: - BOOL sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host); + bool sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host); }; diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp index 6664eb02dc..a4852cefba 100644 --- a/indra/llmessage/llpartdata.cpp +++ b/indra/llmessage/llpartdata.cpp @@ -71,31 +71,31 @@ S32 LLPartData::getSize() const } -BOOL LLPartData::unpackLegacy(LLDataPacker &dp) +bool LLPartData::unpackLegacy(LLDataPacker &dp) { LLColor4U coloru; dp.unpackU32(mFlags, "pdflags"); - dp.unpackFixed(mMaxAge, "pdmaxage", FALSE, 8, 8); + 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); + 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; + return true; } -BOOL LLPartData::unpack(LLDataPacker &dp) +bool LLPartData::unpack(LLDataPacker &dp) { S32 size = 0; dp.unpackS32(size, "partsize"); @@ -105,7 +105,7 @@ BOOL LLPartData::unpack(LLDataPacker &dp) if (mFlags & LL_PART_DATA_GLOW) { - if (size < PS_PART_DATA_GLOW_SIZE) return FALSE; + if (size < PS_PART_DATA_GLOW_SIZE) return false; U8 tmp_glow = 0; dp.unpackU8(tmp_glow,"pdstartglow"); @@ -123,7 +123,7 @@ BOOL LLPartData::unpack(LLDataPacker &dp) if (mFlags & LL_PART_DATA_BLEND) { - if (size < PS_PART_DATA_BLEND_SIZE) return FALSE; + if (size < PS_PART_DATA_BLEND_SIZE) return false; dp.unpackU8(mBlendFuncSource,"pdblendsource"); dp.unpackU8(mBlendFuncDest,"pdblenddest"); size -= PS_PART_DATA_BLEND_SIZE; @@ -144,11 +144,11 @@ BOOL LLPartData::unpack(LLDataPacker &dp) } //this particle system won't display properly, better to not show anything - return FALSE; + return false; } - return TRUE; + return true; } void LLPartData::setFlags(const U32 flags) @@ -240,44 +240,44 @@ LLPartSysData::LLPartSysData() mNumParticles = 0; } -BOOL LLPartSysData::unpackSystem(LLDataPacker &dp) +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); + 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.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(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.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; + return true; } -BOOL LLPartSysData::unpackLegacy(LLDataPacker &dp) +bool LLPartSysData::unpackLegacy(LLDataPacker &dp) { unpackSystem(dp); mPartData.unpackLegacy(dp); - return TRUE; + return true; } -BOOL LLPartSysData::unpack(LLDataPacker &dp) +bool LLPartSysData::unpack(LLDataPacker &dp) { // syssize is currently unused. Adding now when modifying the 'version to make extensible in the future S32 size = 0; @@ -300,7 +300,7 @@ BOOL LLPartSysData::unpack(LLDataPacker &dp) { dp.unpackU8(feh, "whippang"); } - return FALSE; + return false; } unpackSystem(dp); @@ -324,7 +324,7 @@ std::ostream& operator<<(std::ostream& s, const LLPartSysData &data) return s; } -BOOL LLPartSysData::isNullPS(const S32 block_num) +bool LLPartSysData::isNullPS(const S32 block_num) { U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE]; U32 crc; @@ -335,13 +335,13 @@ BOOL LLPartSysData::isNullPS(const S32 block_num) if (!size) { - return TRUE; + return true; } if (size > PS_MAX_DATA_BLOCK_SIZE) { //size is too big, newer particle version unsupported - return TRUE; + return true; } gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); @@ -355,7 +355,7 @@ BOOL LLPartSysData::isNullPS(const S32 block_num) if (tmp > PS_SYS_DATA_BLOCK_SIZE) { //unknown system data block size, don't know how to parse it, treat as NULL - return TRUE; + return true; } } @@ -363,12 +363,12 @@ BOOL LLPartSysData::isNullPS(const S32 block_num) if (crc == 0) { - return TRUE; + return true; } - return FALSE; + return false; } -BOOL LLPartSysData::unpackBlock(const S32 block_num) +bool LLPartSysData::unpackBlock(const S32 block_num) { U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE]; @@ -378,7 +378,7 @@ BOOL LLPartSysData::unpackBlock(const S32 block_num) if (size > PS_MAX_DATA_BLOCK_SIZE) { // Larger packets are newer and unsupported - return FALSE; + return false; } // Get from message diff --git a/indra/llmessage/llpartdata.h b/indra/llmessage/llpartdata.h index ed5c1a6ac7..c61e411a23 100644 --- a/indra/llmessage/llpartdata.h +++ b/indra/llmessage/llpartdata.h @@ -88,10 +88,10 @@ public: mParameter(0.f) { } - BOOL unpackLegacy(LLDataPacker &dp); - BOOL unpack(LLDataPacker &dp); + bool unpackLegacy(LLDataPacker &dp); + bool unpack(LLDataPacker &dp); - BOOL pack(LLDataPacker &dp); + bool pack(LLDataPacker &dp); bool hasGlow() const; bool hasBlendFunc() const; @@ -183,11 +183,11 @@ class LLPartSysData public: LLPartSysData(); - BOOL unpack(LLDataPacker &dp); - BOOL unpackLegacy(LLDataPacker &dp); - BOOL unpackBlock(const S32 block_num); + 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) + static bool isNullPS(const S32 block_num); // Returns false if this is a "NULL" particle system (i.e. no system) bool isLegacyCompatible() const; @@ -227,7 +227,7 @@ public: S32 getdataBlockSize() const; private: - BOOL unpackSystem(LLDataPacker &dp); + bool unpackSystem(LLDataPacker &dp); public: // Public because I'm lazy.... diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp index 49456c71ed..7ea0c55afd 100644 --- a/indra/llmessage/llsdmessagebuilder.cpp +++ b/indra/llmessage/llsdmessagebuilder.cpp @@ -68,8 +68,8 @@ void LLSDMessageBuilder::newMessage(const char* name) // virtual void LLSDMessageBuilder::clearMessage() { - mbSBuilt = FALSE; - mbSClear = TRUE; + mbSBuilt = false; + mbSClear = true; mCurrentMessage = LLSD::emptyMap(); mCurrentMessageName = ""; @@ -96,10 +96,10 @@ void LLSDMessageBuilder::nextBlock(const char* blockname) } // TODO: Remove this horror... -BOOL LLSDMessageBuilder::removeLastBlock() +bool LLSDMessageBuilder::removeLastBlock() { /* TODO: finish implementing this */ - return FALSE; + return false; } void LLSDMessageBuilder::addBinaryData( @@ -168,9 +168,9 @@ void LLSDMessageBuilder::addIPPort(const char* varname, U16 v) (*mCurrentBlock)[varname] = v; } -void LLSDMessageBuilder::addBOOL(const char* varname, BOOL v) +void LLSDMessageBuilder::addBOOL(const char* varname, bool v) { - (*mCurrentBlock)[varname] = (v == TRUE); + (*mCurrentBlock)[varname] = (v == true); } void LLSDMessageBuilder::addString(const char* varname, const char* v) @@ -218,9 +218,9 @@ void LLSDMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length) { } -BOOL LLSDMessageBuilder::isMessageFull(const char* blockname) const +bool LLSDMessageBuilder::isMessageFull(const char* blockname) const { - return FALSE; + return false; } U32 LLSDMessageBuilder::buildMessage(U8*, U32, U8) @@ -400,13 +400,13 @@ const LLSD& LLSDMessageBuilder::getMessage() const } //virtual -void LLSDMessageBuilder::setBuilt(BOOL b) { mbSBuilt = b; } +void LLSDMessageBuilder::setBuilt(bool b) { mbSBuilt = b; } //virtual -BOOL LLSDMessageBuilder::isBuilt() const {return mbSBuilt;} +bool LLSDMessageBuilder::isBuilt() const {return mbSBuilt;} //virtual -BOOL LLSDMessageBuilder::isClear() const {return mbSClear;} +bool LLSDMessageBuilder::isClear() const {return mbSClear;} //virtual S32 LLSDMessageBuilder::getMessageSize() diff --git a/indra/llmessage/llsdmessagebuilder.h b/indra/llmessage/llsdmessagebuilder.h index 9c7c1bfde3..f1e824f5d4 100644 --- a/indra/llmessage/llsdmessagebuilder.h +++ b/indra/llmessage/llsdmessagebuilder.h @@ -48,14 +48,14 @@ public: virtual void newMessage(const char* name); virtual void nextBlock(const char* blockname); - virtual BOOL removeLastBlock(); // TODO: babbage: remove this horror... + 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 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); @@ -75,18 +75,18 @@ public: 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 bool isMessageFull(const char* blockname) const; virtual void compressMessage(U8*& buf_ptr, U32& buffer_length); - virtual BOOL isBuilt() const; - virtual BOOL isClear() const; + 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 void setBuilt(bool b); virtual S32 getMessageSize(); virtual const char* getMessageName() const; diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index 5ac5f6c580..fad94ecab6 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -220,7 +220,7 @@ void LLTemplateMessageBuilder::nextBlock(const char* blockname) } // TODO: Remove this horror... -BOOL LLTemplateMessageBuilder::removeLastBlock() +bool LLTemplateMessageBuilder::removeLastBlock() { if (mCurrentSBlockName) { @@ -268,18 +268,18 @@ BOOL LLTemplateMessageBuilder::removeLastBlock() << ". Block: " << block_name << ". Number: " << num_blocks << LL_ENDL; - return FALSE; + return false; } else { // Decrement the counter. block_data->mBlockNumber--; - return TRUE; + return true; } } } } - return FALSE; + return false; } // add data to variable in current block @@ -445,7 +445,7 @@ void LLTemplateMessageBuilder::addIPPort(const char *varname, U16 u) addData(varname, &u, MVT_IP_PORT, sizeof(u)); } -void LLTemplateMessageBuilder::addBOOL(const char* varname, BOOL b) +void LLTemplateMessageBuilder::addBOOL(const char* varname, bool b) { // Can't just cast a BOOL (actually a U32) to a U8. // In some cases the low order bits will be zero. @@ -584,15 +584,15 @@ void LLTemplateMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length) } } -BOOL LLTemplateMessageBuilder::isMessageFull(const char* blockname) const +bool LLTemplateMessageBuilder::isMessageFull(const char* blockname) const { if(mCurrentSendTotal > MTUBYTES) { - return TRUE; + return true; } if(!blockname) { - return FALSE; + return false; } char* bnamep = (char*)blockname; S32 max; @@ -614,9 +614,9 @@ BOOL LLTemplateMessageBuilder::isMessageFull(const char* blockname) const } if(mCurrentSMessageData->mMemberBlocks[bnamep]->mBlockNumber >= max) { - return TRUE; + return true; } - return FALSE; + return false; } static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* template_data, LLMsgData* message_data) @@ -877,13 +877,13 @@ void LLTemplateMessageBuilder::copyFromLLSD(const LLSD&) } //virtual -void LLTemplateMessageBuilder::setBuilt(BOOL b) { mbSBuilt = b; } +void LLTemplateMessageBuilder::setBuilt(bool b) { mbSBuilt = b; } //virtual -BOOL LLTemplateMessageBuilder::isBuilt() const {return mbSBuilt;} +bool LLTemplateMessageBuilder::isBuilt() const {return mbSBuilt;} //virtual -BOOL LLTemplateMessageBuilder::isClear() const {return mbSClear;} +bool LLTemplateMessageBuilder::isClear() const {return mbSClear;} //virtual S32 LLTemplateMessageBuilder::getMessageSize() {return mCurrentSendTotal;} diff --git a/indra/llmessage/lltemplatemessagebuilder.h b/indra/llmessage/lltemplatemessagebuilder.h index 4f614a4657..b8b4b36c3d 100644 --- a/indra/llmessage/lltemplatemessagebuilder.h +++ b/indra/llmessage/lltemplatemessagebuilder.h @@ -49,12 +49,12 @@ public: virtual void newMessage(const char* name); virtual void nextBlock(const char* blockname); - virtual BOOL removeLastBlock(); // TODO: babbage: remove this horror... + 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 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); @@ -74,18 +74,18 @@ public: 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 bool isMessageFull(const char* blockname) const; virtual void compressMessage(U8*& buf_ptr, U32& buffer_length); - virtual BOOL isBuilt() const; - virtual BOOL isClear() const; + 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 void setBuilt(bool b); virtual S32 getMessageSize(); virtual const char* getMessageName() const; diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 8a41d5565d..0ff49a2308 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -286,9 +286,9 @@ void LLTemplateMessageReader::getU8(const char *block, const char *var, 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; + bool value; + getData(block, var, &value, sizeof(bool), blocknum); + b = value; } void LLTemplateMessageReader::getS16(const char *block, const char *var, @@ -443,7 +443,7 @@ S32 LLTemplateMessageReader::getMessageSize() const } // Returns template for the message contained in buffer -BOOL LLTemplateMessageReader::decodeTemplate( +bool LLTemplateMessageReader::decodeTemplate( const U8* buffer, S32 buffer_size, // inputs LLMessageTemplate** msg_template ) // outputs { @@ -453,7 +453,7 @@ BOOL LLTemplateMessageReader::decodeTemplate( if (buffer_size <= 0) { LL_WARNS() << "No message waiting for decode!" << LL_ENDL; - return(FALSE); + return(false); } U32 num = 0; @@ -489,7 +489,7 @@ BOOL LLTemplateMessageReader::decodeTemplate( { LL_WARNS() << "Packet with unusable length received (too short): " << buffer_size << LL_ENDL; - return(FALSE); + return(false); } LLMessageTemplate* temp = get_ptr_in_map(mMessageNumbers,num); @@ -503,10 +503,10 @@ BOOL LLTemplateMessageReader::decodeTemplate( LL_WARNS_ONCE() << "Message #" << std::hex << num << std::dec << " received but not registered!" << LL_ENDL; //gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); - return(FALSE); + return(false); } - return(TRUE); + return(true); } void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S32 where, const S32 wanted ) @@ -531,7 +531,7 @@ void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S3 static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages"); // decode a given message -BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender ) +bool LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender ) { LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES); @@ -592,7 +592,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender else { LL_ERRS() << "Unknown block type" << LL_ENDL; - return FALSE; + return false; } LLMsgBlkData* cur_data_block = NULL; @@ -698,7 +698,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender && !mCurrentRMessageTemplate->mMemberBlocks.empty()) { LL_DEBUGS() << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << LL_ENDL; - return FALSE; + return false; } { @@ -747,16 +747,16 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender } } } - return TRUE; + return true; } -BOOL LLTemplateMessageReader::validateMessage(const U8* buffer, - S32 buffer_size, +bool LLTemplateMessageReader::validateMessage(const U8* buffer, + S32 buffer_size, const LLHost& sender, bool trusted) { mReceiveSize = buffer_size; - BOOL valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate ); + bool valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate ); if(valid) { mCurrentRMessageTemplate->mReceiveCount++; @@ -773,7 +773,7 @@ BOOL LLTemplateMessageReader::validateMessage(const U8* buffer, << " from " << ((trusted) ? "trusted " : "untrusted ") << sender << LL_ENDL; - valid = FALSE; + valid = false; } if(valid && isUdpBanned()) @@ -781,12 +781,12 @@ BOOL LLTemplateMessageReader::validateMessage(const U8* buffer, LL_WARNS() << "Received UDP black listed message " << getMessageName() << " from " << sender << LL_ENDL; - valid = FALSE; + valid = false; } return valid; } -BOOL LLTemplateMessageReader::readMessage(const U8* buffer, +bool LLTemplateMessageReader::readMessage(const U8* buffer, const LLHost& sender) { return decodeData(buffer, sender); diff --git a/indra/llmessage/lltemplatemessagereader.h b/indra/llmessage/lltemplatemessagereader.h index 88889cd7d2..14656230e3 100644 --- a/indra/llmessage/lltemplatemessagereader.h +++ b/indra/llmessage/lltemplatemessagereader.h @@ -98,9 +98,9 @@ public: virtual void copyToBuilder(LLMessageBuilder&) const; - BOOL validateMessage(const U8* buffer, S32 buffer_size, + bool validateMessage(const U8* buffer, S32 buffer_size, const LLHost& sender, bool trusted = false); - BOOL readMessage(const U8* buffer, const LLHost& sender); + bool readMessage(const U8* buffer, const LLHost& sender); bool isTrusted() const; bool isBanned(bool trusted_source) const; @@ -111,12 +111,12 @@ 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 + 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 ); + bool decodeData(const U8* buffer, const LLHost& sender ); S32 mReceiveSize; LLMessageTemplate* mCurrentRMessageTemplate; diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp index e659414e8c..dc02b5ea90 100644 --- a/indra/llmessage/llthrottle.cpp +++ b/indra/llmessage/llthrottle.cpp @@ -57,9 +57,9 @@ F32 LLThrottle::getAvailable() return mAvailable + (mRate * elapsed_time.value()); } -BOOL LLThrottle::checkOverflow(const F32 amount) +bool LLThrottle::checkOverflow(const F32 amount) { - BOOL retval = TRUE; + bool retval = true; F32 lookahead_amount = mRate * mLookaheadSecs; @@ -72,17 +72,17 @@ BOOL LLThrottle::checkOverflow(const F32 amount) { // ...enough space to send this message // Also do if > lookahead so we can use if amount > capped amount. - retval = FALSE; + retval = false; } return retval; } -BOOL LLThrottle::throttleOverflow(const F32 amount) +bool LLThrottle::throttleOverflow(const F32 amount) { F32Seconds elapsed_time; F32 lookahead_amount; - BOOL retval = TRUE; + bool retval = true; lookahead_amount = mRate * mLookaheadSecs; @@ -97,12 +97,12 @@ BOOL LLThrottle::throttleOverflow(const F32 amount) // ...channel completely open, so allow send regardless // of size. This allows sends on very low BPS channels. mAvailable = lookahead_amount; - retval = FALSE; + retval = false; } else if (mAvailable > amount) { // ...enough space to send this message - retval = FALSE; + retval = false; } // We actually already sent the bits. @@ -236,15 +236,15 @@ void LLThrottleGroup::resetDynamicAdjust() } -BOOL LLThrottleGroup::setNominalBPS(F32* throttle_vec) +bool LLThrottleGroup::setNominalBPS(F32* throttle_vec) { - BOOL changed = FALSE; + bool changed = false; S32 i; for (i = 0; i < TC_EOF; i++) { if (mNominalBPS[i] != throttle_vec[i]) { - changed = TRUE; + changed = true; mNominalBPS[i] = throttle_vec[i]; } } @@ -285,9 +285,9 @@ S32 LLThrottleGroup::getAvailable(S32 throttle_cat) } -BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits) +bool LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits) { - BOOL retval = TRUE; + bool retval = true; F32 category_bps = mCurrentBPS[throttle_cat]; F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME; @@ -302,23 +302,23 @@ BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 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; + retval = false; } else if ( bits_available > bits ) { // ...enough space to send this message - retval = FALSE; + retval = false; } return retval; } -BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits) +bool LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits) { F32Seconds elapsed_time; F32 category_bps; F32 lookahead_bits; - BOOL retval = TRUE; + bool retval = true; category_bps = mCurrentBPS[throttle_cat]; lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME; @@ -333,12 +333,12 @@ BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 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; + retval = false; } else if ( mBitsAvailable[throttle_cat] > bits ) { // ...enough space to send this message - retval = FALSE; + retval = false; } // We actually already sent the bits. @@ -354,7 +354,7 @@ BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits) } -BOOL LLThrottleGroup::dynamicAdjust() +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 @@ -370,7 +370,7 @@ BOOL LLThrottleGroup::dynamicAdjust() // Only dynamically adjust every few seconds if ((mt_sec - mDynamicAdjustTime) < DYNAMIC_ADJUST_TIME) { - return FALSE; + return false; } mDynamicAdjustTime = mt_sec; @@ -394,11 +394,11 @@ BOOL LLThrottleGroup::dynamicAdjust() // Look for busy channels // TODO: Fold into loop above. - BOOL channels_busy = FALSE; + 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]; + bool channel_busy[TC_EOF]; + bool channel_idle[TC_EOF]; + bool channel_over_nominal[TC_EOF]; for (i = 0; i < TC_EOF; i++) { @@ -406,34 +406,34 @@ BOOL LLThrottleGroup::dynamicAdjust() if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) { // this channel is busy - channels_busy = TRUE; + channels_busy = true; busy_nominal_sum += mNominalBPS[i]; // use for allocation of pooled idle bandwidth - channel_busy[i] = TRUE; + channel_busy[i] = true; } else { - channel_busy[i] = FALSE; + 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; + channel_idle[i] = true; } else { - channel_idle[i] = FALSE; + channel_idle[i] = false; } // Is this an overpumped channel? if (mCurrentBPS[i] > mNominalBPS[i]) { - channel_over_nominal[i] = TRUE; + channel_over_nominal[i] = true; } else { - channel_over_nominal[i] = FALSE; + channel_over_nominal[i] = false; } } @@ -573,5 +573,5 @@ BOOL LLThrottleGroup::dynamicAdjust() } } } - return TRUE; + return true; } diff --git a/indra/llmessage/llthrottle.h b/indra/llmessage/llthrottle.h index e43e54f61b..9b829e788a 100644 --- a/indra/llmessage/llthrottle.h +++ b/indra/llmessage/llthrottle.h @@ -41,8 +41,8 @@ public: ~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 + 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; } @@ -73,10 +73,10 @@ public: ~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 + 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 diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp index 452b77fb6d..fb901644c7 100644 --- a/indra/llmessage/lltransfermanager.cpp +++ b/indra/llmessage/lltransfermanager.cpp @@ -254,7 +254,7 @@ void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **) msgp->getBinaryData("TransferInfo", "Params", tmp, size); LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE); - BOOL unpack_ok = tsp->unpackParams(dpb); + bool unpack_ok = tsp->unpackParams(dpb); if (!unpack_ok) { // This should only happen if the data is corrupt or @@ -505,7 +505,7 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) // 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; + bool done = false; while (!done) { LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size); @@ -780,7 +780,7 @@ void LLTransferSourceChannel::updateTransfers() LLPriQueueMap::pqm_iter iter, next; - BOOL done = FALSE; + bool done = false; for (iter = mTransferSources.mMap.begin(); (iter != mTransferSources.mMap.end()) && !done;) { //LL_INFOS() << "LLTransferSourceChannel::updateTransfers()" << LL_ENDL; @@ -791,7 +791,7 @@ void LLTransferSourceChannel::updateTransfers() LLTransferSource *tsp = iter->second; U8 *datap = NULL; S32 data_size = 0; - BOOL delete_data = FALSE; + bool delete_data = false; S32 packet_id = 0; S32 sent_bytes = 0; LLTSCode status = LLTS_OK; @@ -1335,7 +1335,7 @@ void LLTransferSourceParamsInvItem::packParams(LLDataPacker &dp) const } -BOOL LLTransferSourceParamsInvItem::unpackParams(LLDataPacker &dp) +bool LLTransferSourceParamsInvItem::unpackParams(LLDataPacker &dp) { S32 tmp_at; @@ -1349,7 +1349,7 @@ BOOL LLTransferSourceParamsInvItem::unpackParams(LLDataPacker &dp) mAssetType = (LLAssetType::EType)tmp_at; - return TRUE; + return true; } LLTransferSourceParamsEstate::LLTransferSourceParamsEstate() : @@ -1387,7 +1387,7 @@ void LLTransferSourceParamsEstate::packParams(LLDataPacker &dp) const } -BOOL LLTransferSourceParamsEstate::unpackParams(LLDataPacker &dp) +bool LLTransferSourceParamsEstate::unpackParams(LLDataPacker &dp) { S32 tmp_et; @@ -1397,5 +1397,5 @@ BOOL LLTransferSourceParamsEstate::unpackParams(LLDataPacker &dp) mEstateAssetType = (EstateAssetType)tmp_et; - return TRUE; + return true; } diff --git a/indra/llmessage/lltransfermanager.h b/indra/llmessage/lltransfermanager.h index 6aad153c24..a756771445 100644 --- a/indra/llmessage/lltransfermanager.h +++ b/indra/llmessage/lltransfermanager.h @@ -263,7 +263,7 @@ public: virtual ~LLTransferSourceParams(); virtual void packParams(LLDataPacker &dp) const = 0; - virtual BOOL unpackParams(LLDataPacker &dp) = 0; + virtual bool unpackParams(LLDataPacker &dp) = 0; LLTransferSourceType getType() const { return mType; } @@ -300,13 +300,13 @@ protected: const S32 max_bytes, U8 **datap, S32 &returned_bytes, - BOOL &delete_returned) = 0; + 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 bool unpackParams(LLDataPacker& dp) = 0; virtual S32 getNextPacketID() { return mLastPacketID + 1; } virtual void setLastPacketID(const S32 packet_id) { mLastPacketID = packet_id; } @@ -440,7 +440,7 @@ public: LLTransferSourceParamsInvItem(); virtual ~LLTransferSourceParamsInvItem() {} /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); + /*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); @@ -472,7 +472,7 @@ public: LLTransferSourceParamsEstate(); virtual ~LLTransferSourceParamsEstate() {} /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); + /*virtual*/ bool unpackParams(LLDataPacker &dp); void setAgentSession(const LLUUID &agent_id, const LLUUID &session_id); void setEstateAssetType(const EstateAssetType etype); diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 027283232d..32fdc83f0e 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -62,7 +62,7 @@ void LLTransferSourceAsset::initTransfer() mParams.getAssetType(), LLTransferSourceAsset::responderCallback, tidp, - FALSE); + false); } else { @@ -91,7 +91,7 @@ LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id, const S32 max_bytes, U8 **data_handle, S32 &returned_bytes, - BOOL &delete_returned) + bool &delete_returned) { //LL_INFOS() << "LLTransferSourceAsset::dataCallback" << LL_ENDL; if (!mGotResponse) @@ -164,7 +164,7 @@ void LLTransferSourceAsset::packParams(LLDataPacker& dp) const mParams.packParams(dp); } -BOOL LLTransferSourceAsset::unpackParams(LLDataPacker &dp) +bool LLTransferSourceAsset::unpackParams(LLDataPacker &dp) { //LL_INFOS() << "LLTransferSourceAsset::unpackParams" << LL_ENDL; return mParams.unpackParams(dp); @@ -240,7 +240,7 @@ void LLTransferSourceParamsAsset::packParams(LLDataPacker &dp) const } -BOOL LLTransferSourceParamsAsset::unpackParams(LLDataPacker &dp) +bool LLTransferSourceParamsAsset::unpackParams(LLDataPacker &dp) { S32 tmp_at; @@ -249,6 +249,6 @@ BOOL LLTransferSourceParamsAsset::unpackParams(LLDataPacker &dp) mAssetType = (LLAssetType::EType)tmp_at; - return TRUE; + return true; } diff --git a/indra/llmessage/lltransfersourceasset.h b/indra/llmessage/lltransfersourceasset.h index 585e683cb3..f2a5dc214e 100644 --- a/indra/llmessage/lltransfersourceasset.h +++ b/indra/llmessage/lltransfersourceasset.h @@ -38,7 +38,7 @@ public: LLTransferSourceParamsAsset(); virtual ~LLTransferSourceParamsAsset() {} /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); + /*virtual*/ bool unpackParams(LLDataPacker &dp); void setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type); @@ -65,15 +65,15 @@ protected: const S32 max_bytes, U8 **datap, S32 &returned_bytes, - BOOL &delete_returned); + bool &delete_returned); /*virtual*/ void completionCallback(const LLTSCode status); virtual void packParams(LLDataPacker& dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); + /*virtual*/ bool unpackParams(LLDataPacker &dp); protected: LLTransferSourceParamsAsset mParams; - BOOL mGotResponse; + bool mGotResponse; S32 mCurPos; }; diff --git a/indra/llmessage/lltransfersourcefile.cpp b/indra/llmessage/lltransfersourcefile.cpp index 1f284a158d..1192a6e461 100644 --- a/indra/llmessage/lltransfersourcefile.cpp +++ b/indra/llmessage/lltransfersourcefile.cpp @@ -86,7 +86,7 @@ LLTSCode LLTransferSourceFile::dataCallback(const S32 packet_id, const S32 max_bytes, U8 **data_handle, S32 &returned_bytes, - BOOL &delete_returned) + bool &delete_returned) { //LL_INFOS() << "LLTransferSourceFile::dataCallback" << LL_ENDL; @@ -141,7 +141,7 @@ void LLTransferSourceFile::packParams(LLDataPacker& dp) const mParams.packParams(dp); } -BOOL LLTransferSourceFile::unpackParams(LLDataPacker &dp) +bool LLTransferSourceFile::unpackParams(LLDataPacker &dp) { //LL_INFOS() << "LLTransferSourceFile::unpackParams" << LL_ENDL; return mParams.unpackParams(dp); @@ -150,7 +150,7 @@ BOOL LLTransferSourceFile::unpackParams(LLDataPacker &dp) LLTransferSourceParamsFile::LLTransferSourceParamsFile() : LLTransferSourceParams(LLTST_FILE), - mDeleteOnCompletion(FALSE) + mDeleteOnCompletion(false) { } @@ -162,7 +162,7 @@ void LLTransferSourceParamsFile::packParams(LLDataPacker &dp) const } -BOOL LLTransferSourceParamsFile::unpackParams(LLDataPacker &dp) +bool LLTransferSourceParamsFile::unpackParams(LLDataPacker &dp) { dp.unpackString(mFilename, "Filename"); U8 delete_flag; @@ -170,5 +170,5 @@ BOOL LLTransferSourceParamsFile::unpackParams(LLDataPacker &dp) mDeleteOnCompletion = delete_flag; LL_INFOS() << "Unpacked filename: " << mFilename << LL_ENDL; - return TRUE; + return true; } diff --git a/indra/llmessage/lltransfersourcefile.h b/indra/llmessage/lltransfersourcefile.h index 985042417e..bda6bad14f 100644 --- a/indra/llmessage/lltransfersourcefile.h +++ b/indra/llmessage/lltransfersourcefile.h @@ -35,7 +35,7 @@ public: LLTransferSourceParamsFile(); virtual ~LLTransferSourceParamsFile() {} /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); + /*virtual*/ bool unpackParams(LLDataPacker &dp); void setFilename(const std::string &filename) { mFilename = filename; } std::string getFilename() const { return mFilename; } @@ -61,11 +61,11 @@ protected: const S32 max_bytes, U8 **datap, S32 &returned_bytes, - BOOL &delete_returned); + bool &delete_returned); /*virtual*/ void completionCallback(const LLTSCode status); virtual void packParams(LLDataPacker& dp) const; - /*virtual*/ BOOL unpackParams(LLDataPacker &dp); + /*virtual*/ bool unpackParams(LLDataPacker &dp); protected: LLTransferSourceParamsFile mParams; diff --git a/indra/llmessage/lluseroperation.cpp b/indra/llmessage/lluseroperation.cpp index c506af19ce..d56997c7de 100644 --- a/indra/llmessage/lluseroperation.cpp +++ b/indra/llmessage/lluseroperation.cpp @@ -72,14 +72,14 @@ void LLUserOperation::SetNoExpireFlag(const BOOL flag) mNoExpire = flag; } -BOOL LLUserOperation::isExpired() +bool LLUserOperation::isExpired() { if (!mNoExpire) { const F32 EXPIRE_TIME_SECS = 10.f; return mTimer.getElapsedTimeF32() > EXPIRE_TIME_SECS; } - return FALSE; + return false; } void LLUserOperation::expire() @@ -128,7 +128,7 @@ LLUserOperation* LLUserOperationMgr::findOperation(const LLUUID& tid) } -BOOL LLUserOperationMgr::deleteOperation(LLUserOperation* op) +bool LLUserOperationMgr::deleteOperation(LLUserOperation* op) { size_t rv = 0; if(op) @@ -138,7 +138,7 @@ BOOL LLUserOperationMgr::deleteOperation(LLUserOperation* op) delete op; op = NULL; } - return rv ? TRUE : FALSE; + return rv ? true : false; } void LLUserOperationMgr::deleteExpiredOperations() diff --git a/indra/llmessage/lluseroperation.h b/indra/llmessage/lluseroperation.h index 7db5f0b27f..88e5f82622 100644 --- a/indra/llmessage/lluseroperation.h +++ b/indra/llmessage/lluseroperation.h @@ -44,7 +44,7 @@ public: const LLUUID& getAgentID() const { return mAgentID; } // Operation never got necessary data, so expired - virtual BOOL isExpired(); + virtual bool isExpired(); // ability to mark this operation as never expiring. void SetNoExpireFlag(const BOOL flag); @@ -54,7 +54,7 @@ public: // 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; + 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 @@ -68,7 +68,7 @@ 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. + bool mNoExpire; // this is used for operations that expect an answer and will wait till it gets one. }; @@ -80,7 +80,7 @@ public: void addOperation(LLUserOperation* op); LLUserOperation* findOperation(const LLUUID& transaction_id); - BOOL deleteOperation(LLUserOperation* op); + bool deleteOperation(LLUserOperation* op); // Call this method every once in a while to clean up old // transactions. diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index 93d5cfc131..ad291df717 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -327,7 +327,7 @@ S32 LLXfer::processEOF() /////////////////////////////////////////////////////////// -S32 LLXfer::encodePacketNum(S32 packet_num, BOOL is_EOF) +S32 LLXfer::encodePacketNum(S32 packet_num, bool is_EOF) { if (is_EOF) { diff --git a/indra/llmessage/llxfer.h b/indra/llmessage/llxfer.h index a906674dec..cfd9f83d54 100644 --- a/indra/llmessage/llxfer.h +++ b/indra/llmessage/llxfer.h @@ -103,7 +103,7 @@ class LLXfer virtual S32 suck(S32 start_position); virtual S32 flush(); - virtual S32 encodePacketNum(S32 packet_num, BOOL is_eof); + virtual S32 encodePacketNum(S32 packet_num, bool is_eof); virtual void setXferSize (S32 data_size); virtual S32 getMaxBufferSize(); diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index 7fd4222fb7..f5e9071aa4 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -412,14 +412,14 @@ S32 LLXfer_File::processEOF() /////////////////////////////////////////////////////////// -BOOL LLXfer_File::matchesLocalFilename(const std::string& filename) +bool LLXfer_File::matchesLocalFilename(const std::string& filename) { return (filename == mLocalFilename); } /////////////////////////////////////////////////////////// -BOOL LLXfer_File::matchesRemoteFilename(const std::string& filename, ELLPath remote_path) +bool LLXfer_File::matchesRemoteFilename(const std::string& filename, ELLPath remote_path) { return ((filename == mRemoteFilename) && (remote_path == mRemotePath)); } diff --git a/indra/llmessage/llxfer_file.h b/indra/llmessage/llxfer_file.h index ab9374549e..15a0120932 100644 --- a/indra/llmessage/llxfer_file.h +++ b/indra/llmessage/llxfer_file.h @@ -69,8 +69,8 @@ class LLXfer_File : public LLXfer 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 bool matchesLocalFilename(const std::string& filename); + virtual bool matchesRemoteFilename(const std::string& filename, ELLPath remote_path); virtual S32 getMaxBufferSize(); diff --git a/indra/llmessage/llxfer_vfile.cpp b/indra/llmessage/llxfer_vfile.cpp index 12419b342d..f478825d97 100644 --- a/indra/llmessage/llxfer_vfile.cpp +++ b/indra/llmessage/llxfer_vfile.cpp @@ -367,14 +367,14 @@ S32 LLXfer_VFile::processEOF() //////////////////////////////////////////////////////////// -BOOL LLXfer_VFile::matchesLocalFile(const LLUUID &id, LLAssetType::EType type) +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) +bool LLXfer_VFile::matchesRemoteFile(const LLUUID &id, LLAssetType::EType type) { return (id == mRemoteID && type == mType); } diff --git a/indra/llmessage/llxfer_vfile.h b/indra/llmessage/llxfer_vfile.h index d82bab5f6c..71eaeb7393 100644 --- a/indra/llmessage/llxfer_vfile.h +++ b/indra/llmessage/llxfer_vfile.h @@ -72,8 +72,8 @@ class LLXfer_VFile : public LLXfer 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 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(); diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 956ecc11a3..591dbc18c2 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -367,7 +367,7 @@ U64 LLXferManager::getNextID () /////////////////////////////////////////////////////////// -S32 LLXferManager::encodePacketNum(S32 packet_num, BOOL is_EOF) +S32 LLXferManager::encodePacketNum(S32 packet_num, bool is_EOF) { if (is_EOF) { @@ -385,7 +385,7 @@ S32 LLXferManager::decodePacketNum(S32 packet_num) /////////////////////////////////////////////////////////// -BOOL LLXferManager::isLastPacket(S32 packet_num) +bool LLXferManager::isLastPacket(S32 packet_num) { return(packet_num & 0x80000000); } @@ -396,11 +396,11 @@ 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, + bool delete_remote_on_completion, void (*callback)(void**,S32,LLExtStat), void** user_data, - BOOL is_priority, - BOOL use_big_packets) + bool is_priority, + bool use_big_packets) { LLXfer_File* file_xfer_p = NULL; @@ -464,7 +464,7 @@ void LLXferManager::requestVFile(const LLUUID& local_id, const LLHost& remote_host, void (*callback)(void**,S32,LLExtStat), void** user_data, - BOOL is_priority) + bool is_priority) { LLXfer_VFile * xfer_p = NULL; @@ -1235,7 +1235,7 @@ void LLXferManager::startPendingDownloads() /////////////////////////////////////////////////////////// -void LLXferManager::addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority) +void LLXferManager::addToList(LLXfer* xferp, xfer_list_t & xfer_list, bool is_priority) { if(is_priority) { diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index f49209bed0..17625aedfa 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -100,7 +100,7 @@ class LLXferManager protected: // implementation methods virtual void startPendingDownloads(); - virtual void addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority); + virtual void addToList(LLXfer* xferp, xfer_list_t & xfer_list, bool is_priority); std::multiset mExpectedTransfers; // files that are authorized to transfer out std::multiset mExpectedRequests; // files that are authorized to be downloaded on top of std::multiset mExpectedVFileTransfers; // files that are authorized to transfer out @@ -135,9 +135,9 @@ class LLXferManager // 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); + 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 @@ -145,19 +145,19 @@ class LLXferManager const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, - BOOL delete_remote_on_completion, + bool delete_remote_on_completion, void (*callback)(void**,S32,LLExtStat), void** user_data, - BOOL is_priority = FALSE, - BOOL use_big_packets = FALSE); + 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, + bool delete_remote_on_completion, void (*callback)(void*, S32, void**, S32, LLExtStat), void** user_data, - BOOL is_priority = FALSE); + bool is_priority = false); */ // vfile requesting // .. to vfile @@ -165,7 +165,7 @@ class LLXferManager LLAssetType::EType type, const LLHost& remote_host, void (*callback)(void**,S32,LLExtStat), void** user_data, - BOOL is_priority = FALSE); + 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 diff --git a/indra/llmessage/llxorcipher.cpp b/indra/llmessage/llxorcipher.cpp index 9053e1b2f1..17651b1ecf 100644 --- a/indra/llmessage/llxorcipher.cpp +++ b/indra/llmessage/llxorcipher.cpp @@ -109,7 +109,7 @@ void LLXORCipher::init(const U8* pad, U32 pad_len) #ifdef _DEBUG // static -BOOL LLXORCipher::testHarness() +bool LLXORCipher::testHarness() { const U32 PAD_LEN = 3; const U8 PAD[] = "abc"; @@ -122,7 +122,7 @@ BOOL LLXORCipher::testHarness() 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; + if(0 != memcmp((void*)MESSAGE, decrypted, MSG_LENGTH)) return false; + return true; } #endif diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 5e24061959..d11efab7ab 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -362,7 +362,7 @@ void LLMessageSystem::clearReceiveState() } -BOOL LLMessageSystem::poll(F32 seconds) +bool LLMessageSystem::poll(F32 seconds) { S32 num_socks; apr_status_t status; @@ -373,11 +373,11 @@ BOOL LLMessageSystem::poll(F32 seconds) } if (num_socks) { - return TRUE; + return true; } else { - return FALSE; + return false; } } @@ -468,7 +468,7 @@ LLCircuitData* LLMessageSystem::findCircuit(const LLHost& host, else { // wake up the circuit - cdp->setAlive(TRUE); + cdp->setAlive(true); if(resetPacketId) { @@ -484,10 +484,10 @@ LLCircuitData* LLMessageSystem::findCircuit(const LLHost& host, // 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 ) +bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) { // Pump - BOOL valid_packet = FALSE; + bool valid_packet = false; LLTransferTargetVFile::updateQueue(); @@ -506,8 +506,8 @@ BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) { clearReceiveState(); - BOOL recv_reliable = FALSE; - BOOL recv_resent = FALSE; + BOOL recv_reliable = false; + BOOL recv_resent = false; S32 acks = 0; S32 true_rcv_size = 0; @@ -531,7 +531,7 @@ BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) callExceptionFunc(MX_PACKET_TOO_SHORT); } // no data in packet receive buffer - valid_packet = FALSE; + valid_packet = false; } else { @@ -554,7 +554,7 @@ BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) LL_WARNS("Messaging") << "Malformed packet received. Packet size " << receive_size << " with invalid no. of acks " << acks << LL_ENDL; - valid_packet = FALSE; + valid_packet = false; continue; } } @@ -593,11 +593,11 @@ BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) if (buffer[0] & LL_RELIABLE_FLAG) { - recv_reliable = TRUE; + recv_reliable = true; } if (buffer[0] & LL_RESENT_FLAG) { - recv_resent = TRUE; + recv_resent = true; if (cdp && cdp->isDuplicateResend(mCurrentRecvPacketID)) { // We need to ACK here to suppress @@ -635,7 +635,7 @@ BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) LL_INFOS("Messaging") << str.str() << LL_ENDL; } mPacketsIn++; - valid_packet = FALSE; + valid_packet = false; continue; } } @@ -664,7 +664,7 @@ BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) { logMsgFromInvalidCircuit( host, recv_reliable ); clearReceiveState(); - valid_packet = FALSE; + valid_packet = false; } if( @@ -677,12 +677,12 @@ BOOL LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) clearReceiveState(); sendDenyTrustedCircuit(host); - valid_packet = FALSE; + valid_packet = false; } if( valid_packet ) { - logValidMsg(cdp, host, recv_reliable, recv_resent, (BOOL)(acks>0) ); + logValidMsg(cdp, host, recv_reliable, recv_resent, acks>0 ); valid_packet = mTemplateMessageReader->readMessage(buffer, host); } @@ -943,7 +943,7 @@ void LLMessageSystem::nextBlock(const char *blockname) nextBlockFast(LLMessageStringTable::getInstance()->getString(blockname)); } -BOOL LLMessageSystem::isSendFull(const char* blockname) +bool LLMessageSystem::isSendFull(const char* blockname) { char* stringTableName = NULL; if(NULL != blockname) @@ -953,7 +953,7 @@ BOOL LLMessageSystem::isSendFull(const char* blockname) return isSendFullFast(stringTableName); } -BOOL LLMessageSystem::isSendFullFast(const char* blockname) +bool LLMessageSystem::isSendFullFast(const char* blockname) { return mMessageBuilder->isMessageFull(blockname); } @@ -961,7 +961,7 @@ BOOL LLMessageSystem::isSendFullFast(const char* 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() +bool LLMessageSystem::removeLastBlock() { return mMessageBuilder->removeLastBlock(); } @@ -1524,7 +1524,7 @@ void LLMessageSystem::enableCircuit(const LLHost &host, BOOL trusted) } else { - cdp->setAlive(TRUE); + cdp->setAlive(true); } cdp->setTrusted(trusted); } @@ -1595,14 +1595,14 @@ void LLMessageSystem::setCircuitTimeoutCallback(const LLHost &host, void (*callb } -BOOL LLMessageSystem::checkCircuitBlocked(const U32 circuit) +bool LLMessageSystem::checkCircuitBlocked(const U32 circuit) { LLHost host = findHost(circuit); if (!host.isOk()) { LL_DEBUGS("Messaging") << "checkCircuitBlocked: Unknown circuit " << circuit << LL_ENDL; - return TRUE; + return true; } LLCircuitData *cdp = mCircuitInfo.findCircuit(host); @@ -1613,18 +1613,18 @@ BOOL LLMessageSystem::checkCircuitBlocked(const U32 circuit) else { LL_INFOS("Messaging") << "checkCircuitBlocked(circuit): Unknown host - " << host << LL_ENDL; - return FALSE; + return false; } } -BOOL LLMessageSystem::checkCircuitAlive(const U32 circuit) +bool LLMessageSystem::checkCircuitAlive(const U32 circuit) { LLHost host = findHost(circuit); if (!host.isOk()) { LL_DEBUGS("Messaging") << "checkCircuitAlive: Unknown circuit " << circuit << LL_ENDL; - return FALSE; + return false; } LLCircuitData *cdp = mCircuitInfo.findCircuit(host); @@ -1635,11 +1635,11 @@ BOOL LLMessageSystem::checkCircuitAlive(const U32 circuit) else { LL_INFOS("Messaging") << "checkCircuitAlive(circuit): Unknown host - " << host << LL_ENDL; - return FALSE; + return false; } } -BOOL LLMessageSystem::checkCircuitAlive(const LLHost &host) +bool LLMessageSystem::checkCircuitAlive(const LLHost &host) { LLCircuitData *cdp = mCircuitInfo.findCircuit(host); if (cdp) @@ -1649,7 +1649,7 @@ BOOL LLMessageSystem::checkCircuitAlive(const LLHost &host) else { LL_DEBUGS("Messaging") << "checkCircuitAlive(host): Unknown host - " << host << LL_ENDL; - return FALSE; + return false; } } @@ -2291,7 +2291,7 @@ void process_create_trusted_circuit(LLMessageSystem *msg, void **) their_digest[MD5HEX_STR_SIZE - 1] = '\0'; if(msg->isMatchingDigestForWindowAndUUIDs(their_digest, TRUST_TIME_WINDOW, local_id, remote_id)) { - cdp->setTrusted(TRUE); + cdp->setTrusted(true); LL_INFOS("Messaging") << "Trusted digest from " << msg->getSender() << LL_ENDL; return; } @@ -2715,7 +2715,7 @@ void LLMessageSystem::dumpReceiveCounts() -BOOL LLMessageSystem::isClear() const +bool LLMessageSystem::isClear() const { return mMessageBuilder->isClear(); } @@ -2981,12 +2981,12 @@ void LLMessageSystem::setExceptionFunc(EMessageException e, } } -BOOL LLMessageSystem::callExceptionFunc(EMessageException exception) +bool LLMessageSystem::callExceptionFunc(EMessageException exception) { callbacks_t::iterator it = mExceptionCallbacks.find(exception); if(it == mExceptionCallbacks.end()) { - return FALSE; + return false; } exception_t& ex = it->second; @@ -2995,12 +2995,12 @@ BOOL LLMessageSystem::callExceptionFunc(EMessageException exception) if (!ex_cb) { LL_WARNS("Messaging") << "LLMessageSystem::callExceptionFunc: bad message exception callback." << LL_ENDL; - return FALSE; + return false; } (ex_cb)(this, ex.second, exception); - return TRUE; + return true; } void LLMessageSystem::setTimingFunc(msg_timing_callback func, void* data) @@ -3009,14 +3009,14 @@ void LLMessageSystem::setTimingFunc(msg_timing_callback func, void* data) mTimingCallbackData = data; } -BOOL LLMessageSystem::isCircuitCodeKnown(U32 code) const +bool LLMessageSystem::isCircuitCodeKnown(U32 code) const { if(mCircuitCodes.find(code) == mCircuitCodes.end()) - return FALSE; - return TRUE; + return false; + return true; } -BOOL LLMessageSystem::isMessageFast(const char *msg) +bool LLMessageSystem::isMessageFast(const char *msg) { return msg == mMessageReader->getMessageName(); } @@ -3561,12 +3561,12 @@ void LLMessageSystem::addIPPort(const char *varname, U16 v) mMessageBuilder->addIPPort(LLMessageStringTable::getInstance()->getString(varname), v); } -void LLMessageSystem::addBOOLFast(const char* varname, BOOL v) +void LLMessageSystem::addBOOLFast(const char* varname, bool v) { mMessageBuilder->addBOOL(varname, v); } -void LLMessageSystem::addBOOL(const char* varname, BOOL v) +void LLMessageSystem::addBOOL(const char* varname, bool v) { mMessageBuilder->addBOOL(LLMessageStringTable::getInstance()->getString(varname), v); } @@ -3969,7 +3969,7 @@ S32 LLMessageSystem::getReceiveSize() const } //static -void LLMessageSystem::setTimeDecodes( BOOL b ) +void LLMessageSystem::setTimeDecodes( bool b ) { LLMessageReader::setTimeDecodes(b); } diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index c041a69d79..c40da26067 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -390,7 +390,7 @@ public: 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); + 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 @@ -407,18 +407,18 @@ public: } // This method returns true if the code is in the circuit codes map. - BOOL isCircuitCodeKnown(U32 code) const; + 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 ); + 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) + bool isMessageFast(const char *msg); + bool isMessage(const char *msg) { return isMessageFast(LLMessageStringTable::getInstance()->getString(msg)); } @@ -482,8 +482,8 @@ 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 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 @@ -528,10 +528,10 @@ public: // 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 isSendFull(const char* blockname = NULL); + bool isSendFullFast(const char* blockname = NULL); - BOOL removeLastBlock(); + bool removeLastBlock(); //void buildMessage(); @@ -717,9 +717,9 @@ public: 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); + 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); @@ -738,7 +738,7 @@ public: void dumpReceiveCounts(); // dumps receive count for each message type to LL_INFOS() void dumpCircuitInfo(); // Circuit information to LL_INFOS() - BOOL isClear() const; // returns mbSClear; + bool isClear() const; // returns mbSClear; S32 flush(const LLHost &host); U32 getListenPort( void ) const; @@ -765,8 +765,8 @@ public: 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); + static void setTimeDecodes(bool b); + static void setTimeDecodesSpamThreshold(F32 seconds); // message handlers internal to the message systesm //static void processAssignCircuitCode(LLMessageSystem* msg, void**); diff --git a/indra/llmessage/partsyspacket.cpp b/indra/llmessage/partsyspacket.cpp index d87de38aa5..d42a7ef989 100644 --- a/indra/llmessage/partsyspacket.cpp +++ b/indra/llmessage/partsyspacket.cpp @@ -1052,7 +1052,7 @@ U32 LLPartSysCompressedPacket::readWindDiffusionFactor(LLPartInitData *in, U32 s return startByte; } -BOOL LLPartSysCompressedPacket::fromLLPartInitData(LLPartInitData *in, U32 &bytesUsed) +bool LLPartSysCompressedPacket::fromLLPartInitData(LLPartInitData *in, U32 &bytesUsed) { writeFlagByte(in); @@ -1171,7 +1171,7 @@ BOOL LLPartSysCompressedPacket::fromLLPartInitData(LLPartInitData *in, U32 &byte return TRUE; } -BOOL LLPartSysCompressedPacket::toLLPartInitData(LLPartInitData *out, U32 *bytesUsed) +bool LLPartSysCompressedPacket::toLLPartInitData(LLPartInitData *out, U32 *bytesUsed) { U32 currByte = 4; @@ -1259,21 +1259,21 @@ BOOL LLPartSysCompressedPacket::toLLPartInitData(LLPartInitData *out, U32 *bytes } *bytesUsed = currByte; - return TRUE; + return true; } -BOOL LLPartSysCompressedPacket::fromUnsignedBytes(U8 *in, U32 bytesUsed) +bool LLPartSysCompressedPacket::fromUnsignedBytes(U8 *in, U32 bytesUsed) { if ((in != NULL) && (bytesUsed <= sizeof(mData))) { memcpy(mData, in, bytesUsed); /* Flawfinder: ignore */ mNumBytes = bytesUsed; - return TRUE; + return true; } else { LL_ERRS() << "NULL input data or number of bytes exceed mData size" << LL_ENDL; - return FALSE; + return false; } } @@ -1283,10 +1283,10 @@ U32 LLPartSysCompressedPacket::bufferSize() return mNumBytes; } -BOOL LLPartSysCompressedPacket::toUnsignedBytes(U8 *out) +bool LLPartSysCompressedPacket::toUnsignedBytes(U8 *out) { memcpy(out, mData, mNumBytes); /* Flawfinder: ignore */ - return TRUE; + return true; } U8 * LLPartSysCompressedPacket::getBytePtr() diff --git a/indra/llmessage/partsyspacket.h b/indra/llmessage/partsyspacket.h index d9abecea3f..0a8e433cbd 100644 --- a/indra/llmessage/partsyspacket.h +++ b/indra/llmessage/partsyspacket.h @@ -202,10 +202,10 @@ 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); + 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(); -- cgit v1.2.3 From d9bd57762edee6a5a2031ab896b6994746fdf4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Sun, 18 Feb 2024 18:12:56 +0100 Subject: revert to U8 --- indra/llmessage/lltemplatemessagereader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 0ff49a2308..064c6e5bd4 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -286,9 +286,9 @@ void LLTemplateMessageReader::getU8(const char *block, const char *var, void LLTemplateMessageReader::getBOOL(const char *block, const char *var, bool &b, S32 blocknum ) { - bool value; - getData(block, var, &value, sizeof(bool), blocknum); - b = value; + U8 value; + getData(block, var, &value, sizeof(U8), blocknum); + b = (bool)value; } void LLTemplateMessageReader::getS16(const char *block, const char *var, -- cgit v1.2.3 From c2e00c0403b95ef10264807bdbfc3b1e4fdf0921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Sun, 18 Feb 2024 19:15:07 +0100 Subject: fix some tests --- indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp index e20f61b73f..fd4f10f39a 100644 --- a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp +++ b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp @@ -47,16 +47,16 @@ void LLMessageSystem::clearReceiveState(void) char gUdpDispatchedData[MAX_BUFFER_SIZE]; bool gUdpDispatchWasCalled = false; -BOOL LLTemplateMessageReader::readMessage(const U8* data,class LLHost const &) -{ +bool LLTemplateMessageReader::readMessage(const U8* data,class LLHost const &) +{ gUdpDispatchWasCalled = true; strcpy(gUdpDispatchedData, reinterpret_cast(data)); return true; } -BOOL gValidateMessage = FALSE; -BOOL LLTemplateMessageReader::validateMessage(const U8*, S32 buffer_size, LLHost const &sender, bool trusted) -{ +bool gValidateMessage = false; +bool LLTemplateMessageReader::validateMessage(const U8*, S32 buffer_size, LLHost const &sender, bool trusted) +{ return gValidateMessage; } -- cgit v1.2.3 From 321f283032688f0feddc696654e86f62af07121a Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 19 Feb 2024 15:01:44 +0100 Subject: Replace remaining BOOL with bool llinventory and llmessage --- indra/llmessage/llassetstorage.cpp | 16 ++--- indra/llmessage/llassetstorage.h | 14 ++-- indra/llmessage/llblowfishcipher.h | 2 +- indra/llmessage/llcachename.cpp | 2 +- indra/llmessage/llcircuit.cpp | 14 ++-- indra/llmessage/llclassifiedflags.h | 2 +- indra/llmessage/llmessagetemplate.h | 6 +- indra/llmessage/llmessagetemplateparser.cpp | 4 +- indra/llmessage/llpacketack.h | 8 +-- indra/llmessage/llpacketring.cpp | 4 +- indra/llmessage/llregionflags.h | 2 +- indra/llmessage/llregionhandle.h | 8 +-- indra/llmessage/llsdmessagebuilder.cpp | 12 ++-- indra/llmessage/llsdmessagebuilder.h | 4 +- indra/llmessage/lltemplatemessagebuilder.cpp | 16 ++--- indra/llmessage/lltemplatemessagebuilder.h | 4 +- indra/llmessage/llthrottle.cpp | 2 +- indra/llmessage/lltransfermanager.cpp | 14 ++-- indra/llmessage/lltransfermanager.h | 12 ++-- indra/llmessage/lltransfersourceasset.cpp | 10 +-- indra/llmessage/lltransfersourcefile.cpp | 4 +- indra/llmessage/lltransfersourcefile.h | 6 +- indra/llmessage/lltransfertargetvfile.cpp | 4 +- indra/llmessage/lltransfertargetvfile.h | 2 +- indra/llmessage/lluseroperation.cpp | 8 +-- indra/llmessage/lluseroperation.h | 4 +- indra/llmessage/llxfer.cpp | 10 +-- indra/llmessage/llxfer.h | 4 +- indra/llmessage/llxfer_file.cpp | 18 ++--- indra/llmessage/llxfer_file.h | 10 +-- indra/llmessage/llxfer_mem.cpp | 8 +-- indra/llmessage/llxfer_mem.h | 4 +- indra/llmessage/llxfer_vfile.cpp | 8 +-- indra/llmessage/llxfer_vfile.h | 2 +- indra/llmessage/llxfermanager.cpp | 6 +- indra/llmessage/llxfermanager.h | 8 +-- indra/llmessage/llxorcipher.h | 14 ++-- indra/llmessage/machine.h | 2 +- indra/llmessage/message.cpp | 104 +++++++++++++-------------- indra/llmessage/message.h | 42 +++++------ indra/llmessage/message_string_table.cpp | 4 +- indra/llmessage/net.cpp | 24 +++---- indra/llmessage/net.h | 2 +- indra/llmessage/partsyspacket.cpp | 4 +- indra/llmessage/patch_code.cpp | 8 +-- indra/llmessage/patch_dct.cpp | 16 ++--- indra/llmessage/patch_idct.cpp | 20 +++--- 47 files changed, 250 insertions(+), 252 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 2f76e686ec..13fda24e62 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -198,14 +198,14 @@ LLBaseDownloadRequest::LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetTy mDownCallback(), mUserData(NULL), mHost(), - mIsTemp(FALSE), - mIsPriority(FALSE), - mDataSentInFirstPacket(FALSE), - mDataIsInCache(FALSE) + mIsTemp(false), + mIsPriority(false), + mDataSentInFirstPacket(false), + mDataIsInCache(false) { // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been // running a message system loop. - mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); + mTime = LLMessageSystem::getMessageTimeSeconds(true); } // virtual @@ -228,8 +228,8 @@ LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type : LLBaseDownloadRequest(uuid, type), mUpCallback(), mInfoCallback( NULL ), - mIsLocal(FALSE), - mIsUserWaiting(FALSE), + mIsLocal(false), + mIsUserWaiting(false), mTimeout(LL_ASSET_STORAGE_TIMEOUT), mBytesFetched(0) { @@ -344,7 +344,7 @@ void LLAssetStorage::_init(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host) { - mShutDown = FALSE; + mShutDown = false; mMessageSys = msg; mXferManager = xfer; diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index d9c95485f6..dd63724039 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -122,11 +122,11 @@ public: void *mUserData; LLHost mHost; - BOOL mIsTemp; + bool mIsTemp; F64Seconds mTime; // Message system time - BOOL mIsPriority; - BOOL mDataSentInFirstPacket; - BOOL mDataIsInCache; + bool mIsPriority; + bool mDataSentInFirstPacket; + bool mDataIsInCache; }; class LLAssetRequest : public LLBaseDownloadRequest @@ -143,8 +143,8 @@ public: // 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. + 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; @@ -209,7 +209,7 @@ public: }; protected: - BOOL mShutDown; + bool mShutDown; LLHost mUpstreamHost; LLMessageSystem *mMessageSys; diff --git a/indra/llmessage/llblowfishcipher.h b/indra/llmessage/llblowfishcipher.h index e2e54526e8..65228df11f 100644 --- a/indra/llmessage/llblowfishcipher.h +++ b/indra/llmessage/llblowfishcipher.h @@ -46,7 +46,7 @@ public: /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const; #ifdef _DEBUG - static BOOL testHarness(); + static bool testHarness(); #endif private: diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 59dd64336e..c90b6d86ad 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -99,7 +99,7 @@ public: } void done() { mID.setNull(); } - bool isDone() const { return mID.isNull() != FALSE; } + bool isDone() const { return mID.isNull() != false; } }; class ReplySender diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index bb667201a0..a0bf999dee 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -73,10 +73,10 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, mHighestPacketID(in_id), mTimeoutCallback(NULL), mTimeoutUserData(NULL), - mTrusted(FALSE), - mbAllowTimeout(TRUE), - mbAlive(TRUE), - mBlocked(FALSE), + mTrusted(false), + mbAllowTimeout(true), + mbAlive(true), + mBlocked(false), mPingTime(0.0), mLastPingSendTime(0.0), mLastPingReceivedTime(0.0), @@ -111,7 +111,7 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, { // 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); + F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(true); F32 distribution_offset = ll_frand(); mPingTime = mt_sec; @@ -1273,7 +1273,7 @@ void LLCircuitData::pingTimerStop(const U8 ping_id) { // 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); + mt_secs = LLMessageSystem::getMessageTimeSeconds(true); } mLastPingReceivedTime = mt_secs; @@ -1291,7 +1291,7 @@ void LLCircuitData::pingTimerStop(const U8 ping_id) mPingsInTransit = delta_ping; if (mBlocked && (mPingsInTransit <= PING_RELEASE_BLOCK)) { - mBlocked = FALSE; + mBlocked = false; } } diff --git a/indra/llmessage/llclassifiedflags.h b/indra/llmessage/llclassifiedflags.h index 0365ea8f09..9298b90357 100644 --- a/indra/llmessage/llclassifiedflags.h +++ b/indra/llmessage/llclassifiedflags.h @@ -53,7 +53,7 @@ const S32 MAX_CLASSIFIEDS = 100; // 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); +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); diff --git a/indra/llmessage/llmessagetemplate.h b/indra/llmessage/llmessagetemplate.h index a44e16fc3a..41aca4ab91 100644 --- a/indra/llmessage/llmessagetemplate.h +++ b/indra/llmessage/llmessagetemplate.h @@ -361,14 +361,14 @@ public: mUserData = user_data; } - BOOL callHandlerFunc(LLMessageSystem *msgsystem) const + bool callHandlerFunc(LLMessageSystem *msgsystem) const { if (mHandlerFunc) { mHandlerFunc(msgsystem, mUserData); - return TRUE; + return true; } - return FALSE; + return false; } bool isUdpBanned() const diff --git a/indra/llmessage/llmessagetemplateparser.cpp b/indra/llmessage/llmessagetemplateparser.cpp index 3e81fed49e..4b61272454 100644 --- a/indra/llmessage/llmessagetemplateparser.cpp +++ b/indra/llmessage/llmessagetemplateparser.cpp @@ -180,12 +180,12 @@ bool b_check_token(const char *token, const char *regexp) if (current_checker == -1) { LL_ERRS() << "Input exceeds regular expression!\nDid you forget a *?" << LL_ENDL; - return FALSE; + return false; } if (!gParseCheckCharacters[current_checker](token[tptr])) { - return FALSE; + return false; } if (next_checker != 9999) { diff --git a/indra/llmessage/llpacketack.h b/indra/llmessage/llpacketack.h index f0ed923f19..76e2e43acb 100644 --- a/indra/llmessage/llpacketack.h +++ b/indra/llmessage/llpacketack.h @@ -35,7 +35,7 @@ class LLReliablePacketParams public: LLHost mHost; S32 mRetries; - BOOL mPingBasedRetry; + bool mPingBasedRetry; F32Seconds mTimeout; void (*mCallback)(void **,S32); void** mCallbackData; @@ -53,7 +53,7 @@ public: { mHost.invalidate(); mRetries = 0; - mPingBasedRetry = TRUE; + mPingBasedRetry = true; mTimeout = F32Seconds(0.f); mCallback = NULL; mCallbackData = NULL; @@ -63,7 +63,7 @@ public: void set( const LLHost& host, S32 retries, - BOOL ping_based_retry, + bool ping_based_retry, F32Seconds timeout, void (*callback)(void**,S32), void** callback_data, char* name) @@ -98,7 +98,7 @@ protected: S32 mSocket; LLHost mHost; S32 mRetries; - BOOL mPingBasedRetry; + bool mPingBasedRetry; F32Seconds mTimeout; void (*mCallback)(void**,S32); void** mCallbackData; diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 7ba76bea25..8e098bfc8c 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -45,8 +45,8 @@ /////////////////////////////////////////////////////////// LLPacketRing::LLPacketRing () : - mUseInThrottle(FALSE), - mUseOutThrottle(FALSE), + mUseInThrottle(false), + mUseOutThrottle(false), mInThrottle(256000.f), mOutThrottle(64000.f), mActualBitsIn(0), diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 464bf05250..489765e0ac 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -106,7 +106,7 @@ const U64 REGION_FLAGS_ESTATE_MASK = REGION_FLAGS_EXTERNALLY_VISIBLE | REGION_FLAGS_DENY_ANONYMOUS | REGION_FLAGS_DENY_AGEUNVERIFIED; -inline BOOL is_prelude( U64 flags ) +inline bool is_prelude( U64 flags ) { // definition of prelude does not depend on fixed-sun return 0 == (flags & REGION_FLAGS_PRELUDE_UNSET) diff --git a/indra/llmessage/llregionhandle.h b/indra/llmessage/llregionhandle.h index 085757dcbc..284426c148 100644 --- a/indra/llmessage/llregionhandle.h +++ b/indra/llmessage/llregionhandle.h @@ -63,13 +63,13 @@ inline U64 to_region_handle_global(const F32 x_global, const F32 y_global) return region_handle; } -inline BOOL to_region_handle(const F32 x_pos, const F32 y_pos, U64 *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; + return false; } else { @@ -78,14 +78,14 @@ inline BOOL to_region_handle(const F32 x_pos, const F32 y_pos, U64 *region_handl if (y_pos < 0.f) { // LL_WARNS() << "to_region_handle:Clamping negative y position " << y_pos << " to zero!" << LL_ENDL; - return FALSE; + return false; } else { y_int = (U32)ll_round(y_pos); } *region_handle = to_region_handle(x_int, y_int); - return TRUE; + return true; } // stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp index 7ea0c55afd..309cf53bef 100644 --- a/indra/llmessage/llsdmessagebuilder.cpp +++ b/indra/llmessage/llsdmessagebuilder.cpp @@ -44,8 +44,8 @@ LLSDMessageBuilder::LLSDMessageBuilder() : mCurrentBlock(NULL), mCurrentMessageName(""), mCurrentBlockName(""), - mbSBuilt(FALSE), - mbSClear(TRUE) + mbSBuilt(false), + mbSClear(true) { } @@ -58,8 +58,8 @@ LLSDMessageBuilder::~LLSDMessageBuilder() // virtual void LLSDMessageBuilder::newMessage(const char* name) { - mbSBuilt = FALSE; - mbSClear = FALSE; + mbSBuilt = false; + mbSClear = false; mCurrentMessage = LLSD::emptyMap(); mCurrentMessageName = (char*)name; @@ -170,7 +170,7 @@ void LLSDMessageBuilder::addIPPort(const char* varname, U16 v) void LLSDMessageBuilder::addBOOL(const char* varname, bool v) { - (*mCurrentBlock)[varname] = (v == true); + (*mCurrentBlock)[varname] = v; } void LLSDMessageBuilder::addString(const char* varname, const char* v) @@ -354,7 +354,7 @@ void LLSDMessageBuilder::copyFromMessageData(const LLMsgData& data) break; case MVT_BOOL: - addBOOL(varname, *(BOOL*)mvci.getData()); + addBOOL(varname, *(bool*)mvci.getData()); break; case MVT_IP_ADDR: diff --git a/indra/llmessage/llsdmessagebuilder.h b/indra/llmessage/llsdmessagebuilder.h index f1e824f5d4..2c728977ca 100644 --- a/indra/llmessage/llsdmessagebuilder.h +++ b/indra/llmessage/llsdmessagebuilder.h @@ -119,8 +119,8 @@ private: LLSD* mCurrentBlock; std::string mCurrentMessageName; std::string mCurrentBlockName; - BOOL mbSBuilt; - BOOL mbSClear; + bool mbSBuilt; + bool mbSClear; }; #endif // LL_LLSDMESSAGEBUILDER_H diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index fad94ecab6..4188feb318 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -42,8 +42,8 @@ LLTemplateMessageBuilder::LLTemplateMessageBuilder(const message_template_name_m mCurrentSDataBlock(NULL), mCurrentSMessageName(NULL), mCurrentSBlockName(NULL), - mbSBuilt(FALSE), - mbSClear(TRUE), + mbSBuilt(false), + mbSClear(true), mCurrentSendTotal(0), mMessageTemplates(name_template_map) { @@ -59,8 +59,8 @@ LLTemplateMessageBuilder::~LLTemplateMessageBuilder() // virtual void LLTemplateMessageBuilder::newMessage(const char *name) { - mbSBuilt = FALSE; - mbSClear = FALSE; + mbSBuilt = false; + mbSClear = false; mCurrentSendTotal = 0; @@ -103,8 +103,8 @@ void LLTemplateMessageBuilder::newMessage(const char *name) // virtual void LLTemplateMessageBuilder::clearMessage() { - mbSBuilt = FALSE; - mbSClear = TRUE; + mbSBuilt = false; + mbSClear = true; mCurrentSendTotal = 0; @@ -447,8 +447,6 @@ void LLTemplateMessageBuilder::addIPPort(const char *varname, U16 u) void LLTemplateMessageBuilder::addBOOL(const char* varname, bool b) { - // Can't just cast a BOOL (actually a U32) to a U8. - // In some cases the low order bits will be zero. U8 temp = (b != 0); addData(varname, &temp, MVT_BOOL, sizeof(temp)); } @@ -823,7 +821,7 @@ U32 LLTemplateMessageBuilder::buildMessage( { result += buildBlock(buffer + result, buffer_size - result, *iter, mCurrentSMessageData); } - mbSBuilt = TRUE; + mbSBuilt = true; return result; } diff --git a/indra/llmessage/lltemplatemessagebuilder.h b/indra/llmessage/lltemplatemessagebuilder.h index b8b4b36c3d..f02ed0c06d 100644 --- a/indra/llmessage/lltemplatemessagebuilder.h +++ b/indra/llmessage/lltemplatemessagebuilder.h @@ -106,8 +106,8 @@ private: LLMsgBlkData* mCurrentSDataBlock; char* mCurrentSMessageName; char* mCurrentSBlockName; - BOOL mbSBuilt; - BOOL mbSClear; + bool mbSBuilt; + bool mbSClear; S32 mCurrentSendTotal; const message_template_name_map_t& mMessageTemplates; }; diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp index dc02b5ea90..0cfe5dbf38 100644 --- a/indra/llmessage/llthrottle.cpp +++ b/indra/llmessage/llthrottle.cpp @@ -37,7 +37,7 @@ LLThrottle::LLThrottle(const F32 rate) mRate = rate; mAvailable = 0.f; mLookaheadSecs = 0.25f; - mLastSendTime = LLMessageSystem::getMessageTimeSeconds(TRUE); + mLastSendTime = LLMessageSystem::getMessageTimeSeconds(true); } diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp index fb901644c7..bad12101e5 100644 --- a/indra/llmessage/lltransfermanager.cpp +++ b/indra/llmessage/lltransfermanager.cpp @@ -49,7 +49,7 @@ LLTransferSource::stype_scfunc_map LLTransferSource::sSourceCreateMap; // LLTransferManager::LLTransferManager() : - mValid(FALSE) + mValid(false) { S32 i; for (i = 0; i < LLTTT_NUM_TYPES; i++) @@ -78,7 +78,7 @@ void LLTransferManager::init() { LL_ERRS() << "Double initializing LLTransferManager!" << LL_ENDL; } - mValid = TRUE; + mValid = true; // Register message system handlers gMessageSystem->setHandlerFunc("TransferRequest", processTransferRequest, NULL); @@ -90,7 +90,7 @@ void LLTransferManager::init() void LLTransferManager::cleanup() { - mValid = FALSE; + mValid = false; host_tc_map::iterator iter; for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++) @@ -342,7 +342,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) //LL_INFOS() << "Receiving " << transfer_id << ", size " << size << " bytes" << LL_ENDL; ttp->setSize(size); - ttp->setGotInfo(TRUE); + ttp->setGotInfo(true); // OK, at this point we to handle any delayed transfer packets (which could happen // if this packet was lost) @@ -557,7 +557,7 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) else { // No matching delayed packet, abort it. - done = TRUE; + done = true; } } } @@ -822,7 +822,7 @@ void LLTransferSourceChannel::updateTransfers() 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), + gMessageSystem->sendReliable(getHost(), LL_DEFAULT_RELIABLE_RETRIES, true, F32Seconds(0.f), LLTransferManager::reliablePacketCallback, (void**)cb_uuid); // Do bookkeeping for the throttle @@ -1207,7 +1207,7 @@ LLTransferTarget::LLTransferTarget( mSourceType(source_type), mID(transfer_id), mChannelp(NULL), - mGotInfo(FALSE), + mGotInfo(false), mSize(0), mLastPacketID(-1) { diff --git a/indra/llmessage/lltransfermanager.h b/indra/llmessage/lltransfermanager.h index a756771445..15097642b4 100644 --- a/indra/llmessage/lltransfermanager.h +++ b/indra/llmessage/lltransfermanager.h @@ -121,7 +121,7 @@ public: LLTransferSource *findTransferSource(const LLUUID &transfer_id); - BOOL isValid() const { return mValid; } + bool isValid() const { return mValid; } static void processTransferRequest(LLMessageSystem *mesgsys, void **); static void processTransferInfo(LLMessageSystem *mesgsys, void **); @@ -138,13 +138,13 @@ public: void addTransferBitsOut(const LLTransferChannelType tctype, const S32 bits) { mTransferBitsOut[tctype] += bits; } protected: LLTransferConnection *getTransferConnection(const LLHost &host); - BOOL removeTransferConnection(const LLHost &host); + bool removeTransferConnection(const LLHost &host); protected: // Convenient typedefs typedef std::map host_tc_map; - BOOL mValid; + bool mValid; LLHost mHost; S32 mTransferBitsIn[LLTTT_NUM_TYPES]; @@ -408,8 +408,8 @@ protected: 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; } + void setGotInfo(const bool got_info) { mGotInfo = got_info; } + bool gotInfo() const { return mGotInfo; } bool addDelayedPacket( const S32 packet_id, @@ -425,7 +425,7 @@ protected: LLTransferSourceType mSourceType; LLUUID mID; LLTransferTargetChannel *mChannelp; - BOOL mGotInfo; + bool mGotInfo; S32 mSize; S32 mLastPacketID; diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 32fdc83f0e..50956aeb6d 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -36,7 +36,7 @@ LLTransferSourceAsset::LLTransferSourceAsset(const LLUUID &request_id, const F32 priority) : LLTransferSource(LLTST_ASSET, request_id, priority), - mGotResponse(FALSE), + mGotResponse(false), mCurPos(0) { } @@ -120,7 +120,7 @@ LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id, return LLTS_ERROR; } - delete_returned = TRUE; + delete_returned = true; U8 *tmpp = new U8[max_bytes]; *data_handle = tmpp; if (!vf.read(tmpp, max_bytes)) /* Flawfinder: Ignore */ @@ -129,7 +129,7 @@ LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id, delete[] tmpp; *data_handle = NULL; returned_bytes = 0; - delete_returned = FALSE; + delete_returned = false; return LLTS_ERROR; } @@ -144,7 +144,7 @@ LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id, delete[] tmpp; *data_handle = NULL; returned_bytes = 0; - delete_returned = FALSE; + delete_returned = false; } return LLTS_DONE; } @@ -194,7 +194,7 @@ void LLTransferSourceAsset::responderCallback(const LLUUID& uuid, LLAssetType::E LLTSCode status; - tsap->mGotResponse = TRUE; + tsap->mGotResponse = true; if (LL_ERR_NOERR == result) { // Everything's OK. diff --git a/indra/llmessage/lltransfersourcefile.cpp b/indra/llmessage/lltransfersourcefile.cpp index 1192a6e461..ccf0dd7fe0 100644 --- a/indra/llmessage/lltransfersourcefile.cpp +++ b/indra/llmessage/lltransfersourcefile.cpp @@ -102,7 +102,7 @@ LLTSCode LLTransferSourceFile::dataCallback(const S32 packet_id, } // Grab up until the max number of bytes from the file. - delete_returned = TRUE; + delete_returned = true; U8 *tmpp = new U8[max_bytes]; *data_handle = tmpp; returned_bytes = (S32)fread(tmpp, 1, max_bytes, mFP); @@ -111,7 +111,7 @@ LLTSCode LLTransferSourceFile::dataCallback(const S32 packet_id, delete[] tmpp; *data_handle = NULL; returned_bytes = 0; - delete_returned = FALSE; + delete_returned = false; return LLTS_DONE; } diff --git a/indra/llmessage/lltransfersourcefile.h b/indra/llmessage/lltransfersourcefile.h index bda6bad14f..60100e5a65 100644 --- a/indra/llmessage/lltransfersourcefile.h +++ b/indra/llmessage/lltransfersourcefile.h @@ -40,12 +40,12 @@ public: void setFilename(const std::string &filename) { mFilename = filename; } std::string getFilename() const { return mFilename; } - void setDeleteOnCompletion(BOOL enabled) { mDeleteOnCompletion = enabled; } - BOOL getDeleteOnCompletion() { return mDeleteOnCompletion; } + 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; + bool mDeleteOnCompletion; }; class LLTransferSourceFile : public LLTransferSource diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp index f6faadf87f..2806e08ebd 100644 --- a/indra/llmessage/lltransfertargetvfile.cpp +++ b/indra/llmessage/lltransfertargetvfile.cpp @@ -94,7 +94,7 @@ LLTransferTargetVFile::LLTransferTargetVFile( const LLUUID& uuid, LLTransferSourceType src_type) : LLTransferTarget(LLTTT_VFILE, uuid, src_type), - mNeedsCreate(TRUE) + mNeedsCreate(true) { mTempID.generate(); } @@ -141,7 +141,7 @@ LLTSCode LLTransferTargetVFile::dataCallback(const S32 packet_id, U8 *in_datap, LLFileSystem vf(mTempID, mParams.getAssetType(), LLFileSystem::APPEND); if (mNeedsCreate) { - mNeedsCreate = FALSE; + mNeedsCreate = false; } if (!in_size) diff --git a/indra/llmessage/lltransfertargetvfile.h b/indra/llmessage/lltransfertargetvfile.h index 39a9125f1b..2e6e5a8d40 100644 --- a/indra/llmessage/lltransfertargetvfile.h +++ b/indra/llmessage/lltransfertargetvfile.h @@ -86,7 +86,7 @@ protected: LLTransferTargetParamsVFile mParams; - BOOL mNeedsCreate; + bool mNeedsCreate; LLUUID mTempID; }; diff --git a/indra/llmessage/lluseroperation.cpp b/indra/llmessage/lluseroperation.cpp index d56997c7de..3e387d3d5e 100644 --- a/indra/llmessage/lluseroperation.cpp +++ b/indra/llmessage/lluseroperation.cpp @@ -41,7 +41,7 @@ LLUserOperationMgr* gUserOperationMgr = NULL; LLUserOperation::LLUserOperation(const LLUUID& agent_id) : mAgentID(agent_id), mTimer(), - mNoExpire(FALSE) + mNoExpire(false) { mTransactionID.generate(); } @@ -51,7 +51,7 @@ LLUserOperation::LLUserOperation(const LLUUID& agent_id, mAgentID(agent_id), mTransactionID(transaction_id), mTimer(), - mNoExpire(FALSE) + mNoExpire(false) { } @@ -59,7 +59,7 @@ LLUserOperation::LLUserOperation(const LLUUID& agent_id, // transaction, agent, et. after construction. LLUserOperation::LLUserOperation() : mTimer(), - mNoExpire(FALSE) + mNoExpire(false) { } @@ -67,7 +67,7 @@ LLUserOperation::~LLUserOperation() { } -void LLUserOperation::SetNoExpireFlag(const BOOL flag) +void LLUserOperation::SetNoExpireFlag(const bool flag) { mNoExpire = flag; } diff --git a/indra/llmessage/lluseroperation.h b/indra/llmessage/lluseroperation.h index 88e5f82622..9d0f4d04d1 100644 --- a/indra/llmessage/lluseroperation.h +++ b/indra/llmessage/lluseroperation.h @@ -47,14 +47,14 @@ public: virtual bool isExpired(); // ability to mark this operation as never expiring. - void SetNoExpireFlag(const BOOL flag); + 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; + 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 diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index ad291df717..854f5664f0 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -63,13 +63,13 @@ void LLXfer::init (S32 chunk_size) mXferSize = 0; mStatus = e_LL_XFER_UNINITIALIZED; - mWaitingForACK = FALSE; + mWaitingForACK = false; mCallback = NULL; mCallbackDataHandle = NULL; mCallbackResult = 0; - mBufferContainsEOF = FALSE; + mBufferContainsEOF = false; mBuffer = NULL; mBufferLength = 0; mBufferStartOffset = 0; @@ -187,7 +187,7 @@ void LLXfer::sendPacket(S32 packet_num) { char fdata_buf[LL_XFER_LARGE_PAYLOAD+4]; /* Flawfinder: ignore */ S32 fdata_size = mChunkSize; - BOOL last_packet = FALSE; + bool last_packet = false; S32 num_copy = 0; // if the desired packet is not in our current buffered excerpt from the file. . . @@ -217,7 +217,7 @@ void LLXfer::sendPacket(S32 packet_num) if (((U32)(desired_read_position + fdata_size) >= (U32)mBufferLength) && (mBufferContainsEOF)) { - last_packet = TRUE; + last_packet = true; } if (packet_num) @@ -270,7 +270,7 @@ void LLXfer::sendPacket(S32 packet_num) } ACKTimer.reset(); - mWaitingForACK = TRUE; + mWaitingForACK = true; } if (last_packet) { diff --git a/indra/llmessage/llxfer.h b/indra/llmessage/llxfer.h index cfd9f83d54..6b236df1a5 100644 --- a/indra/llmessage/llxfer.h +++ b/indra/llmessage/llxfer.h @@ -63,11 +63,11 @@ class LLXfer char *mBuffer; U32 mBufferLength; // Size of valid data, not actual allocated buffer size U32 mBufferStartOffset; - BOOL mBufferContainsEOF; + bool mBufferContainsEOF; ELLXferStatus mStatus; - BOOL mWaitingForACK; + bool mWaitingForACK; void (*mCallback)(void **,S32,LLExtStat); void **mCallbackDataHandle; diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index f5e9071aa4..ef2915ede3 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -49,10 +49,10 @@ 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); + init(LLStringUtil::null, false, chunk_size); } -LLXfer_File::LLXfer_File (const std::string& local_filename, BOOL delete_local_on_completion, S32 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); @@ -67,7 +67,7 @@ LLXfer_File::~LLXfer_File () /////////////////////////////////////////////////////////// -void LLXfer_File::init (const std::string& local_filename, BOOL delete_local_on_completion, S32 chunk_size) +void LLXfer_File::init (const std::string& local_filename, bool delete_local_on_completion, S32 chunk_size) { mFp = NULL; @@ -75,8 +75,8 @@ void LLXfer_File::init (const std::string& local_filename, BOOL delete_local_on_ mRemoteFilename.clear(); mRemotePath = LL_PATH_NONE; mTempFilename.clear(); - mDeleteLocalOnCompletion = FALSE; - mDeleteRemoteOnCompletion = FALSE; + mDeleteLocalOnCompletion = false; + mDeleteRemoteOnCompletion = false; if (!local_filename.empty()) { @@ -120,7 +120,7 @@ S32 LLXfer_File::initializeRequest(U64 xfer_id, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, - BOOL delete_remote_on_completion, + bool delete_remote_on_completion, void (*callback)(void**,S32,LLExtStat), void** user_data) { @@ -174,7 +174,7 @@ S32 LLXfer_File::startDownload() gMessageSystem->addStringFast(_PREHASH_Filename, mRemoteFilename); gMessageSystem->addU8("FilePath", (U8) mRemotePath); gMessageSystem->addBOOL("DeleteOnCompletion", mDeleteRemoteOnCompletion); - gMessageSystem->addBOOL("UseBigPackets", BOOL(mChunkSize == LL_XFER_LARGE_PAYLOAD)); + gMessageSystem->addBOOL("UseBigPackets", mChunkSize == LL_XFER_LARGE_PAYLOAD); gMessageSystem->addUUIDFast(_PREHASH_VFileID, LLUUID::null); gMessageSystem->addS16Fast(_PREHASH_VFileType, -1); @@ -287,11 +287,11 @@ S32 LLXfer_File::suck(S32 start_position) if (feof(mFp)) { - mBufferContainsEOF = TRUE; + mBufferContainsEOF = true; } else { - mBufferContainsEOF = FALSE; + mBufferContainsEOF = false; } } else diff --git a/indra/llmessage/llxfer_file.h b/indra/llmessage/llxfer_file.h index 15a0120932..24bfd993bd 100644 --- a/indra/llmessage/llxfer_file.h +++ b/indra/llmessage/llxfer_file.h @@ -39,15 +39,15 @@ class LLXfer_File : public LLXfer ELLPath mRemotePath; std::string mTempFilename; - BOOL mDeleteLocalOnCompletion; - BOOL mDeleteRemoteOnCompletion; + 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); + 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 init(const std::string& local_filename, bool delete_local_on_completion, S32 chunk_size); virtual void cleanup(); virtual S32 initializeRequest(U64 xfer_id, @@ -55,7 +55,7 @@ class LLXfer_File : public LLXfer const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, - BOOL delete_remote_on_completion, + bool delete_remote_on_completion, void (*callback)(void**,S32,LLExtStat), void** user_data); virtual S32 startDownload(); diff --git a/indra/llmessage/llxfer_mem.cpp b/indra/llmessage/llxfer_mem.cpp index da8534ecdc..42afaad93b 100644 --- a/indra/llmessage/llxfer_mem.cpp +++ b/indra/llmessage/llxfer_mem.cpp @@ -52,7 +52,7 @@ void LLXfer_Mem::init () { mRemoteFilename.clear(); mRemotePath = LL_PATH_NONE; - mDeleteRemoteOnCompletion = FALSE; + mDeleteRemoteOnCompletion = false; } /////////////////////////////////////////////////////////// @@ -73,7 +73,7 @@ void LLXfer_Mem::setXferSize (S32 xfer_size) mBufferLength = 0; mBufferStartOffset = 0; - mBufferContainsEOF = TRUE; + mBufferContainsEOF = true; // cout << "starting transfer of size: " << xfer_size << endl; } @@ -124,7 +124,7 @@ S32 LLXfer_Mem::initializeRequest(U64 xfer_id, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, - BOOL delete_remote_on_completion, + bool delete_remote_on_completion, void (*callback)(void*,S32,void**,S32,LLExtStat), void** user_data) { @@ -164,7 +164,7 @@ S32 LLXfer_Mem::startDownload() gMessageSystem->addStringFast(_PREHASH_Filename, mRemoteFilename); gMessageSystem->addU8("FilePath", (U8) mRemotePath); gMessageSystem->addBOOL("DeleteOnCompletion", mDeleteRemoteOnCompletion); - gMessageSystem->addBOOL("UseBigPackets", BOOL(mChunkSize == LL_XFER_LARGE_PAYLOAD)); + gMessageSystem->addBOOL("UseBigPackets", mChunkSize == LL_XFER_LARGE_PAYLOAD); gMessageSystem->addUUIDFast(_PREHASH_VFileID, LLUUID::null); gMessageSystem->addS16Fast(_PREHASH_VFileType, -1); diff --git a/indra/llmessage/llxfer_mem.h b/indra/llmessage/llxfer_mem.h index d07779de87..25bd363235 100644 --- a/indra/llmessage/llxfer_mem.h +++ b/indra/llmessage/llxfer_mem.h @@ -39,7 +39,7 @@ class LLXfer_Mem : public LLXfer void (*mCallback)(void *, S32, void **, S32, LLExtStat); std::string mRemoteFilename; ELLPath mRemotePath; - BOOL mDeleteRemoteOnCompletion; + bool mDeleteRemoteOnCompletion; public: @@ -59,7 +59,7 @@ class LLXfer_Mem : public LLXfer const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, - BOOL delete_remote_on_completion, + bool delete_remote_on_completion, void (*callback)(void*,S32,void**,S32,LLExtStat), void** user_data); virtual S32 startDownload(); diff --git a/indra/llmessage/llxfer_vfile.cpp b/indra/llmessage/llxfer_vfile.cpp index f478825d97..3322188694 100644 --- a/indra/llmessage/llxfer_vfile.cpp +++ b/indra/llmessage/llxfer_vfile.cpp @@ -138,7 +138,7 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, mBufferLength = 0; mPacketNum = 0; mTempID.generate(); - mDeleteTempFile = TRUE; + mDeleteTempFile = true; mStatus = e_LL_XFER_PENDING; return retval; } @@ -156,8 +156,8 @@ S32 LLXfer_VFile::startDownload() gMessageSystem->addU64Fast(_PREHASH_ID, mID); gMessageSystem->addStringFast(_PREHASH_Filename, ""); gMessageSystem->addU8("FilePath", (U8) LL_PATH_NONE); - gMessageSystem->addBOOL("DeleteOnCompletion", FALSE); - gMessageSystem->addBOOL("UseBigPackets", BOOL(mChunkSize == LL_XFER_LARGE_PAYLOAD)); + gMessageSystem->addBOOL("DeleteOnCompletion", false); + gMessageSystem->addBOOL("UseBigPackets", mChunkSize == LL_XFER_LARGE_PAYLOAD); gMessageSystem->addUUIDFast(_PREHASH_VFileID, mRemoteID); gMessageSystem->addS16Fast(_PREHASH_VFileType, (S16)mType); @@ -345,7 +345,7 @@ S32 LLXfer_VFile::processEOF() { // Rename worked: the original file is gone. Clear mDeleteTempFile // so we don't attempt to delete the file in cleanup() - mDeleteTempFile = FALSE; + mDeleteTempFile = false; } } else diff --git a/indra/llmessage/llxfer_vfile.h b/indra/llmessage/llxfer_vfile.h index 71eaeb7393..032c5e2533 100644 --- a/indra/llmessage/llxfer_vfile.h +++ b/indra/llmessage/llxfer_vfile.h @@ -44,7 +44,7 @@ class LLXfer_VFile : public LLXfer std::string mName; - BOOL mDeleteTempFile; + bool mDeleteTempFile; public: LLXfer_VFile (); diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 591dbc18c2..6187d439d9 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -79,7 +79,7 @@ void LLXferManager::init() setMaxIncomingXfers(LL_DEFAULT_MAX_REQUEST_FIFO_XFERS); // Turn on or off ack throttling - mUseAckThrottling = FALSE; + mUseAckThrottling = false; setAckThrottleBPS(100000); } @@ -116,7 +116,7 @@ void LLXferManager::setHardLimitOutgoingXfersPerCircuit(S32 max_num) mHardLimitOutgoingXfersPerCircuit = max_num; } -void LLXferManager::setUseAckThrottling(const BOOL use) +void LLXferManager::setUseAckThrottling(const bool use) { mUseAckThrottling = use; } @@ -1005,7 +1005,7 @@ void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*use if (xferp) { // cout << "confirmed packet #" << packetNum << " ping: "<< xferp->ACKTimer.getElapsedTimeF32() << endl; - xferp->mWaitingForACK = FALSE; + xferp->mWaitingForACK = false; if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) { xferp->sendNextPacket(); diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index 17625aedfa..5b42e781eb 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -76,7 +76,7 @@ class LLXferManager S32 mHardLimitOutgoingXfersPerCircuit; // At this limit, kill off the connection S32 mMaxIncomingXfers; - BOOL mUseAckThrottling; // Use ack throttling to cap file xfer bandwidth + bool mUseAckThrottling; // Use ack throttling to cap file xfer bandwidth std::deque mXferAckQueue; LLThrottle mAckThrottle; public: @@ -85,8 +85,8 @@ class LLXferManager // an xfer must happen asap. enum { - LOW_PRIORITY = FALSE, - HIGH_PRIORITY = TRUE, + LOW_PRIORITY = false, + HIGH_PRIORITY = true, }; // Linked FIFO list, add to the front and pull from back @@ -113,7 +113,7 @@ class LLXferManager virtual void init(); virtual void cleanup(); - void setUseAckThrottling(const BOOL use); + void setUseAckThrottling(const bool use); void setAckThrottleBPS(const F32 bps); // list management routines diff --git a/indra/llmessage/llxorcipher.h b/indra/llmessage/llxorcipher.h index c5b0700f0d..cd1fed3ba4 100644 --- a/indra/llmessage/llxorcipher.h +++ b/indra/llmessage/llxorcipher.h @@ -43,18 +43,18 @@ public: LLXORCipher& operator=(const LLXORCipher& cipher); // Cipher functions - /*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); - /*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); - /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const; + 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); } - BOOL decrypt(U8* buf, U32 len) { return decrypt((const U8*)buf, len, buf, len); } + 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(); + // working. Returns true if it is. + static bool testHarness(); #endif protected: diff --git a/indra/llmessage/machine.h b/indra/llmessage/machine.h index 07aadd47d2..6505a88639 100644 --- a/indra/llmessage/machine.h +++ b/indra/llmessage/machine.h @@ -65,7 +65,7 @@ public: // 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 + bool isValid() const { return (mHost.getPort() != 0); } // TRUE if corresponds to functioning machine // set functions void setMachineType(EMachineType machine_type) { mMachineType = machine_type; } diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index d11efab7ab..91a1250857 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -148,11 +148,11 @@ static const char* nullToEmpty(const char* s) void LLMessageSystem::init() { // initialize member variables - mVerboseLog = FALSE; + mVerboseLog = false; - mbError = FALSE; + mbError = false; mErrorCode = 0; - mSendReliable = FALSE; + mSendReliable = false; mUnackedListDepth = 0; mUnackedListSize = 0; @@ -214,7 +214,7 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, mVersionFlags = 0x0; // default to not accepting packets from not alive circuits - mbProtected = TRUE; + mbProtected = true; // default to blocking trusted connections on a public interface if one is specified mBlockUntrustedInterface = true; @@ -239,7 +239,7 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, S32 error = start_net(mSocket, mPort); if (error != 0) { - mbError = TRUE; + mbError = true; mErrorCode = error; } // LL_DEBUGS("Messaging") << << "*** port: " << mPort << LL_ENDL; @@ -288,7 +288,7 @@ void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure if(filename.empty()) { LL_ERRS("Messaging") << "No template filename specified" << LL_ENDL; - mbError = TRUE; + mbError = true; return; } @@ -300,7 +300,7 @@ void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure } else { LL_WARNS("Messaging") << "Failed to open template: " << filename << LL_ENDL; } - mbError = TRUE; + mbError = true; return; } @@ -506,8 +506,8 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) { clearReceiveState(); - BOOL recv_reliable = false; - BOOL recv_resent = false; + bool recv_reliable = false; + bool recv_resent = false; S32 acks = 0; S32 true_rcv_size = 0; @@ -768,7 +768,7 @@ void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time) } } - BOOL dump = FALSE; + bool dump = false; { // Check the status of circuits mCircuitInfo.updateWatchDogTimers(this); @@ -793,17 +793,17 @@ void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time) { if (mNumMessageCounts >= mMaxMessageCounts) { - dump = TRUE; + 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; + mReceiveTime = getMessageTimeSeconds(true) - mMessageCountTime; if (mReceiveTime > mMaxMessageTime) { - dump = TRUE; + dump = true; } } } @@ -833,7 +833,7 @@ void LLMessageSystem::copyMessageReceivedToSend() { mMessageBuilder = mLLSDMessageBuilder; } - mSendReliable = FALSE; + mSendReliable = false; mMessageBuilder->newMessage(mMessageReader->getMessageName()); mMessageReader->copyToBuilder(*mMessageBuilder); } @@ -928,7 +928,7 @@ S32 LLMessageSystem::sendMessage(const LLHost &host, LLStoredMessagePtr message) void LLMessageSystem::clearMessage() { - mSendReliable = FALSE; + mSendReliable = false; mMessageBuilder->clearMessage(); } @@ -968,7 +968,7 @@ bool LLMessageSystem::removeLastBlock() S32 LLMessageSystem::sendReliable(const LLHost &host) { - return sendReliable(host, LL_DEFAULT_RELIABLE_RETRIES, TRUE, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL); + return sendReliable(host, LL_DEFAULT_RELIABLE_RETRIES, true, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL); } @@ -987,15 +987,15 @@ S32 LLMessageSystem::sendSemiReliable(const LLHost &host, void (*callback)(void timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX; } - const S32 retries = 0; - const BOOL ping_based_timeout = FALSE; + 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, + bool ping_based_timeout, F32Seconds timeout, void (*callback)(void **,S32), void ** callback_data) @@ -1013,7 +1013,7 @@ S32 LLMessageSystem::sendReliable( const LLHost &host, } } - mSendReliable = TRUE; + mSendReliable = true; mReliablePacketParams.set(host, retries, ping_based_timeout, timeout, callback, callback_data, const_cast(mMessageBuilder->getMessageName())); @@ -1040,7 +1040,7 @@ void LLMessageSystem::forwardReliable(const U32 circuit_code) S32 LLMessageSystem::forwardReliable( const LLHost &host, S32 retries, - BOOL ping_based_timeout, + bool ping_based_timeout, F32Seconds timeout, void (*callback)(void **,S32), void ** callback_data) @@ -1067,9 +1067,9 @@ S32 LLMessageSystem::flushSemiReliable(const LLHost &host, void (*callback)(void S32 send_bytes = 0; if (mMessageBuilder->getMessageSize()) { - mSendReliable = TRUE; + mSendReliable = true; // No need for ping-based retry as not going to retry - mReliablePacketParams.set(host, 0, FALSE, timeout, callback, + mReliablePacketParams.set(host, 0, false, timeout, callback, callback_data, const_cast(mMessageBuilder->getMessageName())); send_bytes = sendMessage(host); @@ -1169,7 +1169,7 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) host.getUntrustedSimulatorCap(), mLLSDMessageBuilder->getMessageName(), message, cb)); - mSendReliable = FALSE; + mSendReliable = false; mReliablePacketParams.clear(); return 1; } @@ -1218,7 +1218,7 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) // 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; + bool is_ack_appended = false; std::vector acks; if((space_left > 0) && (ack_count > 0) && (mMessageBuilder->getMessageName() != _PREHASH_PacketAck)) @@ -1269,10 +1269,10 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) // tack the count in the final byte U8 count = (U8)append_ack_count; buf_ptr[buffer_length++] = count; - is_ack_appended = TRUE; + is_ack_appended = true; } - BOOL success; + bool success; success = mPacketRing.sendPacket(mSocket, (char *)buf_ptr, buffer_length, host); if (!success) @@ -1307,12 +1307,12 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) mPacketsOut++; mTotalBytesOut += buffer_length; - mSendReliable = FALSE; + mSendReliable = false; mReliablePacketParams.clear(); return buffer_length; } -void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, BOOL recv_reliable ) +void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, bool recv_reliable ) { if(mVerboseLog) { @@ -1339,7 +1339,7 @@ void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, BOOL recv_re // TODO: babbage: work out if we need these // mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber; mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize(); - mMessageCountList[mNumMessageCounts].mInvalid = TRUE; + mMessageCountList[mNumMessageCounts].mInvalid = true; mNumMessageCounts++; } } @@ -1392,12 +1392,12 @@ void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host ) // = mCurrentRMessageTemplate->mMessageNumber; mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize(); - mMessageCountList[mNumMessageCounts].mInvalid = TRUE; + mMessageCountList[mNumMessageCounts].mInvalid = true; mNumMessageCounts++; } } -void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, BOOL recv_reliable, BOOL recv_resent, BOOL recv_acks ) +void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, bool recv_reliable, bool recv_resent, bool recv_acks ) { if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM) { @@ -1408,7 +1408,7 @@ void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, BOOL r // TODO: babbage: work out if we need these //mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber; mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize(); - mMessageCountList[mNumMessageCounts].mInvalid = FALSE; + mMessageCountList[mNumMessageCounts].mInvalid = false; mNumMessageCounts++; } @@ -1502,7 +1502,7 @@ void LLMessageSystem::getCircuitInfo(LLSD& info) const } // returns whether the given host is on a trusted circuit -BOOL LLMessageSystem::getCircuitTrust(const LLHost &host) +bool LLMessageSystem::getCircuitTrust(const LLHost &host) { LLCircuitData *cdp = mCircuitInfo.findCircuit(host); if (cdp) @@ -1510,12 +1510,12 @@ BOOL LLMessageSystem::getCircuitTrust(const LLHost &host) return cdp->getTrusted(); } - return FALSE; + return false; } // Activate a circuit, and set its trust level (TRUE if trusted, // FALSE if not). -void LLMessageSystem::enableCircuit(const LLHost &host, BOOL trusted) +void LLMessageSystem::enableCircuit(const LLHost &host, bool trusted) { LLCircuitData *cdp = mCircuitInfo.findCircuit(host); if (!cdp) @@ -1576,7 +1576,7 @@ void LLMessageSystem::disableCircuit(const LLHost &host) } -void LLMessageSystem::setCircuitAllowTimeout(const LLHost &host, BOOL allow) +void LLMessageSystem::setCircuitAllowTimeout(const LLHost &host, bool allow) { LLCircuitData *cdp = mCircuitInfo.findCircuit(host); if (cdp) @@ -1654,7 +1654,7 @@ bool LLMessageSystem::checkCircuitAlive(const LLHost &host) } -void LLMessageSystem::setCircuitProtection(BOOL b_protect) +void LLMessageSystem::setCircuitProtection(bool b_protect) { mbProtected = b_protect; } @@ -1782,7 +1782,7 @@ void open_circuit(LLMessageSystem *msgsystem, void** /*user_data*/) msgsystem->getIPPortFast(_PREHASH_CircuitInfo, _PREHASH_Port, port); // By default, OpenCircuit's are untrusted - msgsystem->enableCircuit(LLHost(ip, port), FALSE); + msgsystem->enableCircuit(LLHost(ip, port), false); } void close_circuit(LLMessageSystem *msgsystem, void** /*user_data*/) @@ -1947,9 +1947,9 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, // passed the circuit code and session id check, so we will go // ahead and persist the ID associated. LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender()); - BOOL had_circuit_already = cdp ? TRUE : FALSE; + bool had_circuit_already = cdp ? true : false; - msg->enableCircuit(msg->getSender(), FALSE); + msg->enableCircuit(msg->getSender(), false); cdp = msg->mCircuitInfo.findCircuit(msg->getSender()); if(cdp) { @@ -1973,7 +1973,7 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, // 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. + 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; @@ -2460,13 +2460,13 @@ bool start_messaging_system( if (!gMessageSystem) { LL_ERRS("AppInit") << "Messaging system initialization failed." << LL_ENDL; - return FALSE; + return false; } // bail if system encountered an error. if(!gMessageSystem->isOK()) { - return FALSE; + return false; } if (b_dump_prehash_file) @@ -2517,12 +2517,12 @@ bool start_messaging_system( // Initialize the transfer manager gTransferManager.init(); - return TRUE; + return true; } void LLMessageSystem::startLogging() { - mVerboseLog = TRUE; + mVerboseLog = true; std::ostringstream str; str << "START MESSAGE LOG" << std::endl; str << "Legend:" << std::endl; @@ -2536,7 +2536,7 @@ void LLMessageSystem::stopLogging() { if(mVerboseLog) { - mVerboseLog = FALSE; + mVerboseLog = false; LL_INFOS("Messaging") << "END MESSAGE LOG" << LL_ENDL; } } @@ -2757,7 +2757,7 @@ S32 LLMessageSystem::zeroCodeAdjustCurrentSendTotal() 0); } // TODO: babbage: remove this horror - mMessageBuilder->setBuilt(FALSE); + mMessageBuilder->setBuilt(false); S32 count = mSendSize; @@ -3357,7 +3357,7 @@ void LLMessageSystem::dumpPacketToLog() //static -U64Microseconds LLMessageSystem::getMessageTimeUsecs(const BOOL update) +U64Microseconds LLMessageSystem::getMessageTimeUsecs(const bool update) { if (gMessageSystem) { @@ -3374,7 +3374,7 @@ U64Microseconds LLMessageSystem::getMessageTimeUsecs(const BOOL update) } //static -F64Seconds LLMessageSystem::getMessageTimeSeconds(const BOOL update) +F64Seconds LLMessageSystem::getMessageTimeSeconds(const bool update) { if (gMessageSystem) { @@ -3432,7 +3432,7 @@ void LLMessageSystem::newMessageFast(const char *name) mMessageBuilder = mTemplateMessageBuilder; } } - mSendReliable = FALSE; + mSendReliable = false; mMessageBuilder->newMessage(name); } @@ -3923,7 +3923,7 @@ void LLMessageSystem::getString(const char *block, const char *var, blocknum); } -BOOL LLMessageSystem::has(const char *blockname) const +bool LLMessageSystem::has(const char *blockname) const { return getNumberOfBlocks(blockname) > 0; } diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index c40da26067..c167d7ff57 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -74,7 +74,7 @@ public: char *getString(const char *str); U32 mUsed; - BOOL mEmpty[MESSAGE_NUMBER_OF_HASH_BUCKETS]; + bool mEmpty[MESSAGE_NUMBER_OF_HASH_BUCKETS]; char mString[MESSAGE_NUMBER_OF_HASH_BUCKETS][MESSAGE_MAX_STRINGS_LENGTH]; /* Flawfinder: ignore */ }; @@ -296,7 +296,7 @@ class LLMessageSystem : public LLMessageSenderInterface LLReliablePacketParams mReliablePacketParams; // Set this flag to TRUE when you want *very* verbose logs. - BOOL mVerboseLog; + bool mVerboseLog; F32 mMessageFileVersionNumber; @@ -314,7 +314,7 @@ public: S32 mSystemVersionServer; U32 mVersionFlags; - BOOL mbProtected; + bool mbProtected; U32 mNumberHighFreqMessages; U32 mNumberMediumFreqMessages; @@ -347,7 +347,7 @@ public: 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? + bool mSendReliable; // does the outgoing message require a pos ack? LLCircuit mCircuitInfo; F64Seconds mCircuitPrintTime; // used to print circuit debug info every couple minutes @@ -370,7 +370,7 @@ public: ~LLMessageSystem(); - BOOL isOK() const { return !mbError; } + bool isOK() const { return !mbError; } S32 getErrorCode() const { return mErrorCode; } // Read file and build message templates filename must point to a @@ -548,7 +548,7 @@ public: // Use this one if you DON'T want automatic ping-based retry. S32 sendReliable( const LLHost &host, S32 retries, - BOOL ping_based_retries, + bool ping_based_retries, F32Seconds timeout, void (*callback)(void **,S32), void ** callback_data); @@ -568,7 +568,7 @@ public: S32 forwardReliable( const LLHost &host, S32 retries, - BOOL ping_based_timeout, + bool ping_based_timeout, F32Seconds timeout, void (*callback)(void **,S32), void ** callback_data); @@ -579,7 +579,7 @@ private: S32 sendMessage(const LLHost &host, const char* name, const LLSD& message); public: - // BOOL decodeData(const U8 *buffer, const LLHost &host); + // bool decodeData(const U8 *buffer, const LLHost &host); /** gets binary data from the current message. @@ -659,7 +659,7 @@ public: U32 getOurCircuitCode(); - void enableCircuit(const LLHost &host, BOOL trusted); + void enableCircuit(const LLHost &host, bool trusted); void disableCircuit(const LLHost &host); // Use this to establish trust on startup and in response to @@ -712,20 +712,20 @@ public: // 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); + bool getCircuitTrust(const LLHost &host); - void setCircuitAllowTimeout(const LLHost &host, BOOL allow); + 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); + void setCircuitProtection(bool b_protect); U32 findCircuitCode(const LLHost &host); LLHost findHost(const U32 circuit_code); void sanityCheck(); - BOOL has(const char *blockname) const; + 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; @@ -762,8 +762,8 @@ public: 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 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); @@ -839,11 +839,11 @@ private: LLUUID mSessionID; void addTemplate(LLMessageTemplate *templatep); - BOOL decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template ); + bool decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template ); - void logMsgFromInvalidCircuit( const LLHost& sender, BOOL recv_reliable ); + 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 logValidMsg(LLCircuitData *cdp, const LLHost& sender, bool recv_reliable, bool recv_resent, bool recv_acks ); void logRanOffEndOfPacket( const LLHost& sender ); class LLMessageCountInfo @@ -851,7 +851,7 @@ private: public: U32 mMessageNum; U32 mMessageBytes; - BOOL mInvalid; + bool mInvalid; }; LLMessagePollInfo *mPollInfop; @@ -862,7 +862,7 @@ private: // Must be valid during decode - BOOL mbError; + bool mbError; S32 mErrorCode; F64Seconds mResendDumpTime; // The last time we dumped resends @@ -885,7 +885,7 @@ private: 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; + static bool mTimeDecodes; // Measure time for all message decodes if TRUE; msg_timing_callback mTimingCallback; void* mTimingCallbackData; diff --git a/indra/llmessage/message_string_table.cpp b/indra/llmessage/message_string_table.cpp index e4f5fb3a38..8bcc452e3f 100644 --- a/indra/llmessage/message_string_table.cpp +++ b/indra/llmessage/message_string_table.cpp @@ -47,7 +47,7 @@ LLMessageStringTable::LLMessageStringTable() { for (U32 i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++) { - mEmpty[i] = TRUE; + mEmpty[i] = true; mString[i][0] = 0; } } @@ -75,7 +75,7 @@ char* LLMessageStringTable::getString(const char *str) // 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; + mEmpty[hash_value] = false; mUsed++; if (mUsed >= MESSAGE_NUMBER_OF_HASH_BUCKETS - 1) { diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 60030bb920..e43751f23e 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -339,7 +339,7 @@ S32 receive_packet(int hSocket, char * receiveBuffer) } // Returns TRUE on success. -BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort) +bool send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort) { // Sends a packet to the address set in initNet // @@ -364,7 +364,7 @@ BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, i // assume it is. JNC 2002.01.18 if (WSAECONNRESET == WSAGetLastError()) { - return TRUE; + return true; } LL_INFOS() << "sendto() failed to " << u32_to_ip_string(recipient) << ":" << nPort << ", Error " << last_error << LL_ENDL; @@ -598,11 +598,11 @@ int receive_packet(int hSocket, char * receiveBuffer) return nRet; } -BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, int nPort) +bool send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, int nPort) { int ret; - BOOL success; - BOOL resend; + bool success; + bool resend; S32 send_attempts = 0; stDstAddr.sin_addr.s_addr = recipient; @@ -616,34 +616,34 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, if (ret >= 0) { // successful send - success = TRUE; - resend = FALSE; + success = true; + resend = false; } else { // send failed, check to see if we should resend - success = FALSE; + 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; + 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; + 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; + resend = false; } } } @@ -652,7 +652,7 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, if (send_attempts >= 3) { LL_INFOS() << "sendPacket() bailed out of send!" << LL_ENDL; - return FALSE; + return false; } return success; diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h index beb67bae4e..3d45899a56 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -43,7 +43,7 @@ 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. +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(); diff --git a/indra/llmessage/partsyspacket.cpp b/indra/llmessage/partsyspacket.cpp index d42a7ef989..846b11a5d0 100644 --- a/indra/llmessage/partsyspacket.cpp +++ b/indra/llmessage/partsyspacket.cpp @@ -89,7 +89,7 @@ void gSetInitDataDefaults(LLPartInitData *setMe) setMe->mFlags[i] = 0x00; } - setMe->createMe = TRUE; + setMe->createMe = true; setMe->maxParticles = 25; setMe->initialParticles = 25; @@ -1168,7 +1168,7 @@ bool LLPartSysCompressedPacket::fromLLPartInitData(LLPartInitData *in, U32 &byte // llprintline("returning from \"fromLLPartInitData\" with %d bytes\n", bytesUsed); - return TRUE; + return true; } bool LLPartSysCompressedPacket::toLLPartInitData(LLPartInitData *out, U32 *bytesUsed) diff --git a/indra/llmessage/patch_code.cpp b/indra/llmessage/patch_code.cpp index 32f8d80782..c3c3e2b3b3 100644 --- a/indra/llmessage/patch_code.cpp +++ b/indra/llmessage/patch_code.cpp @@ -130,7 +130,7 @@ void code_patch(LLBitPack &bitpack, S32 *patch, S32 postquant) { S32 i, j, patch_size = gPatchSize, wbits = gWordBits; S32 temp; - BOOL b_eob; + bool b_eob; if ( (postquant > patch_size*patch_size) ||(postquant < 0)) @@ -143,16 +143,16 @@ void code_patch(LLBitPack &bitpack, S32 *patch, S32 postquant) for (i = 0; i < patch_size*patch_size; i++) { - b_eob = FALSE; + b_eob = false; temp = patch[i]; if (!temp) { - b_eob = TRUE; + b_eob = true; for (j = i; j < patch_size*patch_size - postquant; j++) { if (patch[j]) { - b_eob = FALSE; + b_eob = false; break; } } diff --git a/indra/llmessage/patch_dct.cpp b/indra/llmessage/patch_dct.cpp index b5518b61ea..2144b4e712 100644 --- a/indra/llmessage/patch_dct.cpp +++ b/indra/llmessage/patch_dct.cpp @@ -85,8 +85,8 @@ 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; + bool b_diag = false; + bool b_right = true; i = 0; j = 0; @@ -107,8 +107,8 @@ void build_copy_matrix(S32 size) i++; else j++; - b_right = FALSE; - b_diag = TRUE; + b_right = false; + b_diag = true; } else { @@ -116,8 +116,8 @@ void build_copy_matrix(S32 size) j++; else i++; - b_right = TRUE; - b_diag = TRUE; + b_right = true; + b_diag = true; } } else @@ -129,7 +129,7 @@ void build_copy_matrix(S32 size) if ( (i == size - 1) ||(j == 0)) { - b_diag = FALSE; + b_diag = false; } } else @@ -139,7 +139,7 @@ void build_copy_matrix(S32 size) if ( (i == 0) ||(j == size - 1)) { - b_diag = FALSE; + b_diag = false; } } } diff --git a/indra/llmessage/patch_idct.cpp b/indra/llmessage/patch_idct.cpp index 9ce35df284..687c1734c5 100644 --- a/indra/llmessage/patch_idct.cpp +++ b/indra/llmessage/patch_idct.cpp @@ -74,8 +74,8 @@ 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; + bool b_diag = false; + bool b_right = true; i = 0; j = 0; @@ -96,8 +96,8 @@ void build_decopy_matrix(S32 size) i++; else j++; - b_right = FALSE; - b_diag = TRUE; + b_right = false; + b_diag = true; } else { @@ -105,8 +105,8 @@ void build_decopy_matrix(S32 size) j++; else i++; - b_right = TRUE; - b_diag = TRUE; + b_right = true; + b_diag = true; } } else @@ -118,7 +118,7 @@ void build_decopy_matrix(S32 size) if ( (i == size - 1) ||(j == 0)) { - b_diag = FALSE; + b_diag = false; } } else @@ -128,7 +128,7 @@ void build_decopy_matrix(S32 size) if ( (i == 0) ||(j == size - 1)) { - b_diag = FALSE; + b_diag = false; } } } @@ -658,8 +658,8 @@ void decompress_patchv(LLVector3 *v, S32 *cpatch, LLPatchHeader *ph) F32 mult = ooq*range; F32 addval = mult*(F32)(1<<(prequant - 1))+hmin; -// BOOL b_diag = FALSE; -// BOOL b_right = TRUE; +// bool b_diag = false; +// bool b_right = true; for (i = 0; i < size*size; i++) { -- cgit v1.2.3 From e160758b5c32f7b4b9622a5c25c7c53070395c7d Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 1 Mar 2024 13:48:46 +0100 Subject: Convert remaining TRUE/FALSE to true/false --- indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp | 8 ++++---- indra/llmessage/tests/llxfer_file_test.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp index fd4f10f39a..3f87a4aff6 100644 --- a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp +++ b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp @@ -84,7 +84,7 @@ namespace tut mMessageName = "MessageName"; gUdpDispatchWasCalled = false; gClearRecvWasCalled = false; - gValidateMessage = FALSE; + gValidateMessage = false; mMessage["body"]["binary-template-data"] = std::vector(); } @@ -121,7 +121,7 @@ namespace tut { LLTemplateMessageReader* pReader = NULL; LLTemplateMessageDispatcher t(*pReader); - gValidateMessage = TRUE; + gValidateMessage = true; std::vector vector_data; fillVector(vector_data, gBinaryTemplateData); mMessage["body"]["binary-template-data"] = vector_data; @@ -138,7 +138,7 @@ namespace tut std::vector vector_data; fillVector(vector_data, gBinaryTemplateData); mMessage["body"]["binary-template-data"] = vector_data; - gValidateMessage = FALSE; + gValidateMessage = false; t.dispatch(mMessageName, mMessage, mResponsePtr); ensure("clear received message was called", gClearRecvWasCalled); } @@ -149,7 +149,7 @@ namespace tut { LLTemplateMessageReader* pReader = NULL; LLTemplateMessageDispatcher t(*pReader); - gValidateMessage = TRUE; + gValidateMessage = true; std::vector vector_data; fillVector(vector_data, gBinaryTemplateData); mMessage["body"]["binary-template-data"] = vector_data; diff --git a/indra/llmessage/tests/llxfer_file_test.cpp b/indra/llmessage/tests/llxfer_file_test.cpp index a8c1adf9b4..cf95d2627c 100644 --- a/indra/llmessage/tests/llxfer_file_test.cpp +++ b/indra/llmessage/tests/llxfer_file_test.cpp @@ -51,7 +51,7 @@ namespace tut oversized_filename += 'X'; } - LLXfer_File xff(oversized_filename, FALSE, 1); + LLXfer_File xff(oversized_filename, false, 1); ensure("oversized local_filename nul-terminated", xff.getFileName().length() < LL_MAX_PATH); } -- cgit v1.2.3 From 53d4fcd3597d2042b2c82bd3aaa41f61fdb7b3d5 Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Wed, 27 Mar 2024 19:51:59 -0400 Subject: Remove dead googlemock dependency and related setup code --- indra/llmessage/CMakeLists.txt | 1 - indra/llmessage/tests/llmockhttpclient.h | 66 -------------------------------- 2 files changed, 67 deletions(-) delete mode 100644 indra/llmessage/tests/llmockhttpclient.h (limited to 'indra/llmessage') diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index e44309476b..40d08f4f17 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -3,7 +3,6 @@ project(llmessage) include(00-Common) -include(GoogleMock) include(LLAddBuildTest) include(LLCommon) include(LLCoreHttp) diff --git a/indra/llmessage/tests/llmockhttpclient.h b/indra/llmessage/tests/llmockhttpclient.h deleted file mode 100644 index af26bf8803..0000000000 --- a/indra/llmessage/tests/llmockhttpclient.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * @brief - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -/* Macro Definitions */ -#ifndef LL_LLMOCKHTTPCLIENT_H -#define LL_LLMOCKHTTPCLIENT_H - -#include "linden_common.h" -#include "llhttpclientinterface.h" - -#include - -class LLMockHTTPClient : public LLHTTPClientInterface -{ -public: - MOCK_METHOD2(get, void(const std::string& url, LLCurl::ResponderPtr responder)); - MOCK_METHOD3(get, void(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)); - MOCK_METHOD3(put, void(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)); -}; - -// A helper to match responder types -template -struct ResponderType -{ - bool operator()(LLCurl::ResponderPtr ptr) const - { - T* p = dynamic_cast(ptr.get()); - return p != NULL; - } -}; - -inline bool operator==(const LLSD& l, const LLSD& r) -{ - std::ostringstream ls, rs; - ls << l; - rs << r; - return ls.str() == rs.str(); - -} - - -#endif //LL_LLMOCKHTTPCLIENT_H - -- cgit v1.2.3 From 17e1f3692c5c1e9cbc6ba6895b312a8baae9aec2 Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Fri, 5 Apr 2024 19:03:58 -0400 Subject: Port from JsonCPP to Boost.Json for json parsing and serializing (#1054) --- indra/llmessage/CMakeLists.txt | 1 - indra/llmessage/llcorehttputil.cpp | 39 ++++++++++++++++---------------------- 2 files changed, 16 insertions(+), 24 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 40d08f4f17..5322139304 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -10,7 +10,6 @@ include(LLAddBuildTest) include(Python) include(Tut) include(Python) -include(JsonCpp) set(llmessage_SOURCE_FILES llassetstorage.cpp diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 460740cebc..7619b46fed 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -35,8 +35,7 @@ #include "llsd.h" #include "llsdjson.h" #include "llsdserialize.h" -#include "json/reader.h" // JSON -#include "json/writer.h" // JSON +#include "boost/json.hpp" // Boost.Json #include "llfilesystem.h" #include "message.h" // for getting the port @@ -585,15 +584,12 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: } LLCore::BufferArrayStream bas(body); - Json::Value jsonRoot; - try - { - bas >> jsonRoot; - } - catch (std::runtime_error& e) + boost::json::error_code ec; + boost::json::value jsonRoot = boost::json::parse(bas, ec); + if(ec.failed()) { // deserialization failed. Record the reason and pass back an empty map for markup. - status = LLCore::HttpStatus(499, std::string(e.what())); + status = LLCore::HttpStatus(499, std::string(ec.what())); return result; } @@ -613,14 +609,11 @@ LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &succes } LLCore::BufferArrayStream bas(body); - Json::Value jsonRoot; - try + boost::json::error_code ec; + boost::json::value jsonRoot = boost::json::parse(bas, ec); + if (ec.failed()) { - bas >> jsonRoot; - } - catch (std::runtime_error&) - { success = false; return LLSD(); } @@ -802,12 +795,12 @@ LLSD HttpCoroutineAdapter::postJsonAndSuspend(LLCore::HttpRequest::ptr_t request { LLCore::BufferArrayStream outs(rawbody.get()); - Json::Value root = LlsdToJson(body); - Json::FastWriter writer; + auto root = LlsdToJson(body); + std::string value = boost::json::serialize(root); - LL_WARNS("Http::post") << "JSON Generates: \"" << writer.write(root) << "\"" << LL_ENDL; + LL_WARNS("Http::post") << "JSON Generates: \"" << value << "\"" << LL_ENDL; - outs << writer.write(root); + outs << value; } return postAndSuspend_(request, url, rawbody, options, headers, httpHandler); @@ -861,11 +854,11 @@ LLSD HttpCoroutineAdapter::putJsonAndSuspend(LLCore::HttpRequest::ptr_t request, { LLCore::BufferArrayStream outs(rawbody.get()); - Json::Value root = LlsdToJson(body); - Json::FastWriter writer; + auto root = LlsdToJson(body); + std::string value = boost::json::serialize(root); - LL_WARNS("Http::put") << "JSON Generates: \"" << writer.write(root) << "\"" << LL_ENDL; - outs << writer.write(root); + LL_WARNS("Http::put") << "JSON Generates: \"" << value << "\"" << LL_ENDL; + outs << value; } return putAndSuspend_(request, url, rawbody, options, headers, httpHandler); -- cgit v1.2.3 From 5f4d312c8d2b6ba0fd13279ccfc569acd4f37c82 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 24 Apr 2024 19:49:27 +0200 Subject: Fix BOOL vs bool issues after merge --- indra/llmessage/lldatapacker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 745eb70f14..1545443798 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -302,7 +302,7 @@ bool LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char if (size < 0) { LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData unpacked invalid size, aborting!" << LL_ENDL; - return FALSE; + return false; } mCurBufferp += 4; -- cgit v1.2.3 From f9473e8afcb624cc1b101195bf15943ec372b56f Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 6 May 2024 16:52:34 +0200 Subject: secondlife/viewer#1333 BOOL to bool conversion leftovers: ternaries --- indra/llmessage/llcachename.cpp | 8 ++++---- indra/llmessage/llpumpio.cpp | 34 +++++++++++++++++++--------------- indra/llmessage/llregionflags.h | 9 +++++++-- indra/llmessage/lluseroperation.cpp | 2 +- indra/llmessage/message.cpp | 2 +- 5 files changed, 32 insertions(+), 23 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index c90b6d86ad..5b4f9aded7 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -87,19 +87,19 @@ public: LLUUID mID; LLCacheNameSignal mSignal; LLHost mHost; - + PendingReply(const LLUUID& id, const LLHost& host) : mID(id), mHost(host) { } - + boost::signals2::connection setCallback(const LLCacheNameCallback& cb) { return mSignal.connect(cb); } - + void done() { mID.setNull(); } - bool isDone() const { return mID.isNull() != false; } + bool isDone() const { return mID.isNull(); } }; class ReplySender diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index 44720f0015..52e6be6f98 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -113,7 +113,7 @@ void ll_debug_poll_fd(const char* msg, const apr_pollfd_t* poll) { LL_DEBUGS() << "Poll -- " << (msg?msg:"") << ": no descriptor." << LL_ENDL; } -#endif +#endif } /** @@ -181,12 +181,13 @@ bool LLPumpIO::prime(apr_pool_t* pool) { cleanup(); initialize(pool); - return ((pool == NULL) ? false : true); + return pool != nullptr; } bool LLPumpIO::addChain(const chain_t& chain, F32 timeout, bool has_curl_request) { - if(chain.empty()) return false; + if (chain.empty()) + return false; LLChainInfo info; info.mHasCurlRequest = has_curl_request; @@ -218,12 +219,13 @@ bool LLPumpIO::addChain( 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 (!data) + return false; + if (links.empty()) + return false; #if LL_DEBUG_PIPE_TYPE_IN_PUMP LL_DEBUGS() << "LLPumpIO::addChain() " << links[0].mPipe << " '" @@ -243,10 +245,11 @@ bool LLPumpIO::addChain( bool LLPumpIO::setTimeoutSeconds(F32 timeout) { // If no chain is running, return failure. - if(mRunningChains.end() == mCurrentChain) + if (mRunningChains.end() == mCurrentChain) { return false; } + (*mCurrentChain).setTimeoutSeconds(timeout); return true; } @@ -254,7 +257,7 @@ bool LLPumpIO::setTimeoutSeconds(F32 timeout) void LLPumpIO::adjustTimeoutSeconds(F32 delta) { // Ensure a chain is running - if(mRunningChains.end() != mCurrentChain) + if (mRunningChains.end() != mCurrentChain) { (*mCurrentChain).adjustTimeoutSeconds(delta); } @@ -263,27 +266,27 @@ void LLPumpIO::adjustTimeoutSeconds(F32 delta) static std::string events_2_string(apr_int16_t events) { std::ostringstream ostr; - if(events & APR_POLLIN) + if (events & APR_POLLIN) { ostr << "read,"; } - if(events & APR_POLLPRI) + if (events & APR_POLLPRI) { ostr << "priority,"; } - if(events & APR_POLLOUT) + if (events & APR_POLLOUT) { ostr << "write,"; } - if(events & APR_POLLERR) + if (events & APR_POLLERR) { ostr << "error,"; } - if(events & APR_POLLHUP) + if (events & APR_POLLHUP) { ostr << "hangup,"; } - if(events & APR_POLLNVAL) + if (events & APR_POLLNVAL) { ostr << "invalid,"; } @@ -292,7 +295,8 @@ static std::string events_2_string(apr_int16_t events) bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll) { - if(!pipe) return false; + if (!pipe) + return false; ll_debug_poll_fd("Set conditional", poll); LL_DEBUGS() << "Setting conditionals (" << (poll ? events_2_string(poll->reqevents) :"null") diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 489765e0ac..ab2d127f6e 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -106,11 +106,16 @@ const U64 REGION_FLAGS_ESTATE_MASK = REGION_FLAGS_EXTERNALLY_VISIBLE | 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 0 == (flags & REGION_FLAGS_PRELUDE_UNSET) - && 0 != (flags & REGION_FLAGS_PRELUDE_SET); + return !is_flag_set(flags, REGION_FLAGS_PRELUDE_UNSET) && + is_flag_set(flags, REGION_FLAGS_PRELUDE_SET); } inline U64 set_prelude_flags(U64 flags) diff --git a/indra/llmessage/lluseroperation.cpp b/indra/llmessage/lluseroperation.cpp index 3e387d3d5e..6b0cc63686 100644 --- a/indra/llmessage/lluseroperation.cpp +++ b/indra/llmessage/lluseroperation.cpp @@ -138,7 +138,7 @@ bool LLUserOperationMgr::deleteOperation(LLUserOperation* op) delete op; op = NULL; } - return rv ? true : false; + return rv != 0; } void LLUserOperationMgr::deleteExpiredOperations() diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 0d7810a659..272bf9b672 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -1947,7 +1947,7 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, // passed the circuit code and session id check, so we will go // ahead and persist the ID associated. LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender()); - bool had_circuit_already = cdp ? true : false; + bool had_circuit_already = cdp != nullptr; msg->enableCircuit(msg->getSender(), false); cdp = msg->mCircuitInfo.findCircuit(msg->getSender()); -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/llmessage/llassetstorage.h | 862 +-- indra/llmessage/llblowfishcipher.h | 114 +- indra/llmessage/llcachename.cpp | 2042 ++--- indra/llmessage/llcachename.h | 296 +- indra/llmessage/llcipher.h | 112 +- indra/llmessage/llcircuit.cpp | 2838 +++---- indra/llmessage/llcircuit.h | 700 +- indra/llmessage/llclassifiedflags.cpp | 168 +- indra/llmessage/llclassifiedflags.h | 124 +- indra/llmessage/lldatapacker.cpp | 4360 +++++------ indra/llmessage/lldatapacker.h | 870 +-- indra/llmessage/llhost.cpp | 352 +- indra/llmessage/llhost.h | 308 +- indra/llmessage/llinstantmessage.cpp | 328 +- indra/llmessage/llinstantmessage.h | 436 +- indra/llmessage/llmail.cpp | 792 +- indra/llmessage/llmail.h | 260 +- indra/llmessage/llmessagebuilder.h | 202 +- indra/llmessage/llmessagereader.cpp | 124 +- indra/llmessage/llmessagereader.h | 188 +- indra/llmessage/llmessagetemplate.h | 842 +- indra/llmessage/llmessagetemplateparser.cpp | 1522 ++-- indra/llmessage/llmessagethrottle.cpp | 306 +- indra/llmessage/llmessagethrottle.h | 160 +- indra/llmessage/llnamevalue.cpp | 1940 ++--- indra/llmessage/llnamevalue.h | 366 +- indra/llmessage/llpacketack.cpp | 164 +- indra/llmessage/llpacketack.h | 232 +- indra/llmessage/llpacketring.cpp | 742 +- indra/llmessage/llpacketring.h | 202 +- indra/llmessage/llpartdata.cpp | 838 +- indra/llmessage/llpartdata.h | 558 +- indra/llmessage/llpumpio.cpp | 2300 +++--- indra/llmessage/llregionflags.h | 422 +- indra/llmessage/llregionhandle.h | 252 +- indra/llmessage/llsdmessagebuilder.cpp | 848 +- indra/llmessage/llsdmessagebuilder.h | 252 +- indra/llmessage/llsdmessagereader.cpp | 688 +- indra/llmessage/llsdmessagereader.h | 216 +- indra/llmessage/lltemplatemessagebuilder.cpp | 1786 ++--- indra/llmessage/lltemplatemessagebuilder.h | 230 +- indra/llmessage/lltemplatemessagereader.cpp | 1660 ++-- indra/llmessage/lltemplatemessagereader.h | 254 +- indra/llmessage/llthrottle.cpp | 1154 +-- indra/llmessage/llthrottle.h | 202 +- indra/llmessage/lltransfermanager.cpp | 2802 +++---- indra/llmessage/lltransfermanager.h | 998 +-- indra/llmessage/lltransfersourceasset.cpp | 508 +- indra/llmessage/lltransfersourceasset.h | 162 +- indra/llmessage/lltransfersourcefile.cpp | 348 +- indra/llmessage/lltransfersourcefile.h | 150 +- indra/llmessage/lltransfertargetvfile.cpp | 468 +- indra/llmessage/lltransfertargetvfile.h | 186 +- indra/llmessage/lluseroperation.cpp | 380 +- indra/llmessage/lluseroperation.h | 194 +- indra/llmessage/llxfer.cpp | 776 +- indra/llmessage/llxfer.h | 246 +- indra/llmessage/llxfer_file.cpp | 950 +-- indra/llmessage/llxfer_file.h | 174 +- indra/llmessage/llxfer_mem.cpp | 392 +- indra/llmessage/llxfer_mem.h | 154 +- indra/llmessage/llxfer_vfile.cpp | 794 +- indra/llmessage/llxfer_vfile.h | 182 +- indra/llmessage/llxfermanager.cpp | 2652 +++---- indra/llmessage/llxfermanager.h | 446 +- indra/llmessage/llxorcipher.cpp | 256 +- indra/llmessage/llxorcipher.h | 134 +- indra/llmessage/machine.h | 190 +- indra/llmessage/message.cpp | 8110 ++++++++++---------- indra/llmessage/message.h | 2342 +++--- indra/llmessage/message_string_table.cpp | 182 +- indra/llmessage/net.cpp | 1326 ++-- indra/llmessage/net.h | 148 +- indra/llmessage/partsyspacket.cpp | 2594 +++---- indra/llmessage/partsyspacket.h | 522 +- indra/llmessage/patch_code.cpp | 816 +- indra/llmessage/patch_dct.cpp | 1538 ++-- indra/llmessage/patch_idct.cpp | 1368 ++-- .../tests/lltemplatemessagedispatcher_test.cpp | 320 +- indra/llmessage/tests/llxfer_file_test.cpp | 116 +- 80 files changed, 33268 insertions(+), 33268 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index 6b6d4a3ae7..88fa572092 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 -#include - -#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 LLGetAssetCallback; -typedef std::function 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 -struct ll_asset_request_equal : public std::equal_to -{ - 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 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 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 +#include + +#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 LLGetAssetCallback; +typedef std::function 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 +struct ll_asset_request_equal : public std::equal_to +{ + 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 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 request_list_t; + request_list_t mPendingDownloads; + request_list_t mPendingUploads; + request_list_t mPendingLocalUploads; + + // Map of toxic assets - these caused problems when recently rezzed, so avoid them + toxic_asset_map_t mToxicAssetMap; // Objects in this list are known to cause problems and are not loaded + +public: + LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host); + + LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer); + virtual ~LLAssetStorage(); + + void setUpstream(const LLHost &upstream_host); + + bool hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); + + // public interface methods + // note that your callback may get called BEFORE the function returns + void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, bool is_priority = false); + + /* + * TransactionID version + * Viewer needs the store_local + */ + virtual void storeAssetData( + const LLTransactionID& tid, + LLAssetType::EType atype, + LLStoreAssetCallback callback, + void* user_data, + bool temp_file = false, + bool is_priority = false, + bool store_local = false, + bool user_waiting= false, + F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) = 0; + + virtual void logAssetStorageInfo() = 0; + + virtual void checkForTimeouts(); + + void getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, + const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype, + LLGetAssetCallback callback, void *user_data, bool is_priority); + + void getInvItemAsset(const LLHost &object_sim, + const LLUUID &agent_id, const LLUUID &session_id, + const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id, + const LLUUID &asset_id, LLAssetType::EType atype, + LLGetAssetCallback cb, void *user_data, bool is_priority = false); // Get a particular inventory item. + + // Check if an asset is in the toxic map. If it is, the entry is updated + bool isAssetToxic( const LLUUID& uuid ); + + // Clean the toxic asset list, remove old entries + void flushOldToxicAssets( bool force_it ); + + // Add an item to the toxic asset map + void markAssetToxic( const LLUUID& uuid ); + +protected: + bool findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, + LLGetAssetCallback callback, void *user_data); + + LLSD getPendingDetailsImpl(const request_list_t* requests, + LLAssetType::EType asset_type, + const std::string& detail_prefix) const; + + LLSD getPendingRequestImpl(const request_list_t* requests, + LLAssetType::EType asset_type, + const LLUUID& asset_id) const; + + bool deletePendingRequestImpl(request_list_t* requests, + LLAssetType::EType asset_type, + const LLUUID& asset_id); + +public: + static const LLAssetRequest* findRequest(const request_list_t* requests, + LLAssetType::EType asset_type, + const LLUUID& asset_id); + static LLAssetRequest* findRequest(request_list_t* requests, + LLAssetType::EType asset_type, + const LLUUID& asset_id); + + request_list_t* getRequestList(ERequestType rt); + const request_list_t* getRequestList(ERequestType rt) const; + static std::string getRequestName(ERequestType rt); + + S32 getNumPendingDownloads() const; + S32 getNumPendingUploads() const; + S32 getNumPendingLocalUploads(); + S32 getNumPending(ERequestType rt) const; + + LLSD getPendingDetails(ERequestType rt, + LLAssetType::EType asset_type, + const std::string& detail_prefix) const; + + LLSD getPendingRequest(ERequestType rt, + LLAssetType::EType asset_type, + const LLUUID& asset_id) const; + + bool deletePendingRequest(ERequestType rt, + LLAssetType::EType asset_type, + const LLUUID& asset_id); + + + static void removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type, + const LLUUID& callback_id, LLAssetType::EType callback_type, + S32 result_code, LLExtStat ext_status); + + // download process callbacks + static void downloadCompleteCallback( + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, LLExtStat ext_status); + static void downloadEstateAssetCompleteCallback( + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, LLExtStat ext_status); + static void downloadInvItemCompleteCallback( + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, LLExtStat ext_status); + + // upload process callbacks + static void uploadCompleteCallback(const LLUUID&, void *user_data, S32 result, LLExtStat ext_status); + static void processUploadComplete(LLMessageSystem *msg, void **this_handle); + + // debugging + static const char* getErrorString( S32 status ); + + // deprecated file-based methods + // Not overriden + void getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, bool is_priority = false); + + /* + * TransactionID version + */ + virtual void storeAssetData( + const std::string& filename, + const LLTransactionID &transaction_id, + LLAssetType::EType type, + LLStoreAssetCallback callback, + void *user_data, + bool temp_file = false, + bool is_priority = false, + bool user_waiting = false, + F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0; + + static void legacyGetDataCallback(const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status); + static void legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status); + + // add extra methods to handle metadata + +protected: + void _cleanupRequests(bool all, S32 error); + void _callUploadCallbacks(const LLUUID &uuid, const LLAssetType::EType asset_type, bool success, LLExtStat ext_status); + + virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, + void *user_data, bool duplicate, + bool is_priority) = 0; + +private: + void _init(LLMessageSystem *msg, + LLXferManager *xfer, + const LLHost &upstream_host); + +protected: + enum EMetricResult + { + // Static valued enums for #dw readability - please copy this + // declaration to them on updates -- source in llassetstorage.h + MR_INVALID = -1, // Makes no sense + MR_OKAY = 0, // Success - no metric normally + MR_ZERO_SIZE = 1, // Zero size asset + MR_BAD_FUNCTION = 2, // Tried to use a virtual base (PROGRAMMER ERROR) + MR_FILE_NONEXIST = 3, // Old format store call - source file does not exist + MR_NO_FILENAME = 4, // Old format store call - source filename is NULL/0-length + MR_NO_UPSTREAM = 5, // Upstream provider is missing + MR_CACHE_CORRUPTION = 6 // cache is corrupt - too-large or mismatched stated/returned sizes + }; + + static class LLMetrics *metric_recipient; + + static void reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const std::string& filename, + const LLUUID& agent_id, S32 asset_size, EMetricResult result, + const char* file, const S32 line, const std::string& message ); +public: + static void setMetricRecipient( LLMetrics *recip ) + { + metric_recipient = recip; + } +}; + +//////////////////////////////////////////////////////////////////////// +// Wrappers to replicate deprecated API +//////////////////////////////////////////////////////////////////////// + +class LLLegacyAssetRequest +{ +public: + void (*mDownCallback)(const char *, const LLUUID&, void *, S32, LLExtStat); + LLStoreAssetCallback mUpCallback; + + void *mUserData; +}; + +extern LLAssetStorage *gAssetStorage; +extern const LLUUID CATEGORIZE_LOST_AND_FOUND_ID; +#endif diff --git a/indra/llmessage/llblowfishcipher.h b/indra/llmessage/llblowfishcipher.h index 59d6f159c5..53dc94cce9 100644 --- a/indra/llmessage/llblowfishcipher.h +++ b/indra/llmessage/llblowfishcipher.h @@ -1,57 +1,57 @@ -/** - * @file llblowfishcipher.h - * @brief A symmetric block cipher, designed in 1993 by Bruce Schneier. - * We use it because it has an 8 byte block size, allowing encryption of - * two UUIDs and a timestamp (16x2 + 4 = 36 bytes) with only 40 bytes of - * output. AES has a block size of 32 bytes, so this would require 64 bytes. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LLBLOWFISHCIPHER_H -#define LLBLOWFISHCIPHER_H - -#include "llcipher.h" - - -class LLBlowfishCipher : public LLCipher -{ -public: - // Secret may be up to 56 bytes in length per Blowfish spec. - LLBlowfishCipher(const U8* secret, size_t secret_size); - virtual ~LLBlowfishCipher(); - - // See llcipher.h for documentation. - /*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); - /*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); - /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const; - -#ifdef _DEBUG - static bool testHarness(); -#endif - -private: - U8* mSecret; - size_t mSecretSize; -}; - -#endif // LL_LLCRYPTO_H +/** + * @file llblowfishcipher.h + * @brief A symmetric block cipher, designed in 1993 by Bruce Schneier. + * We use it because it has an 8 byte block size, allowing encryption of + * two UUIDs and a timestamp (16x2 + 4 = 36 bytes) with only 40 bytes of + * output. AES has a block size of 32 bytes, so this would require 64 bytes. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLBLOWFISHCIPHER_H +#define LLBLOWFISHCIPHER_H + +#include "llcipher.h" + + +class LLBlowfishCipher : public LLCipher +{ +public: + // Secret may be up to 56 bytes in length per Blowfish spec. + LLBlowfishCipher(const U8* secret, size_t secret_size); + virtual ~LLBlowfishCipher(); + + // See llcipher.h for documentation. + /*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); + /*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len); + /*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const; + +#ifdef _DEBUG + static bool testHarness(); +#endif + +private: + U8* mSecret; + size_t mSecretSize; +}; + +#endif // LL_LLCRYPTO_H diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index cb654f5a30..6fb21957e0 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 - -// 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 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 AskQueue; -typedef std::list ReplyQueue; -typedef std::map PendingQueue; -typedef std::map Cache; -typedef std::map 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<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 + +// 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 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 AskQueue; +typedef std::list ReplyQueue; +typedef std::map PendingQueue; +typedef std::map Cache; +typedef std::map 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<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 958f91d3c0..1df713c7c7 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 -#include - -class LLMessageSystem; -class LLHost; -class LLUUID; - - -typedef boost::signals2::signal 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 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 +#include + +class LLMessageSystem; +class LLHost; +class LLUUID; + + +typedef boost::signals2::signal 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 sCacheName; +private: + + class Impl; + Impl& impl; +}; + + + +extern LLCacheName* gCacheName; + +#endif diff --git a/indra/llmessage/llcipher.h b/indra/llmessage/llcipher.h index cbd5d5bde1..bbd7eae1d5 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 bd9b3553fe..fa206d9282 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 - -#else - -#if LL_LINUX -#include // RTLD_LAZY -#endif -#include -#include -#include - -#endif - - -#if !defined(USE_CIRCUIT_LIST) -#include -#endif -#include -#include -#include - -#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 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 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(), - llselect2nd())); -} - -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(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." <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 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() << "/" << circuit.mBytesOut.valueInUnits() - << " Kbps: " - << S32(circuit.mBytesIn.valueInUnits() / circuit.mExistenceTimer.getElapsedTimeF32().value()) - << "/" - << S32(circuit.mBytesOut.valueInUnits() / circuit.mExistenceTimer.getElapsedTimeF32().value()) - << " Packets: " << circuit.mPacketsIn << "/" << circuit.mPacketsOut - << endl; - - s << "Recent In/Out " << circuit.mLastPeriodLength - << " KBytes: " - << circuit.mBytesInLastPeriod.valueInUnits() - << "/" - << circuit.mBytesOutLastPeriod.valueInUnits() - << " Kbps: " - << (S32)(circuit.mBytesInLastPeriod.valueInUnits() / circuit.mLastPeriodLength.value()) - << "/" - << (S32)(circuit.mBytesOutLastPeriod.valueInUnits() / 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 + +#else + +#if LL_LINUX +#include // RTLD_LAZY +#endif +#include +#include +#include + +#endif + + +#if !defined(USE_CIRCUIT_LIST) +#include +#endif +#include +#include +#include + +#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 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 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(), + llselect2nd())); +} + +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(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." <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 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() << "/" << circuit.mBytesOut.valueInUnits() + << " Kbps: " + << S32(circuit.mBytesIn.valueInUnits() / circuit.mExistenceTimer.getElapsedTimeF32().value()) + << "/" + << S32(circuit.mBytesOut.valueInUnits() / circuit.mExistenceTimer.getElapsedTimeF32().value()) + << " Packets: " << circuit.mPacketsIn << "/" << circuit.mPacketsOut + << endl; + + s << "Recent In/Out " << circuit.mLastPeriodLength + << " KBytes: " + << circuit.mBytesInLastPeriod.valueInUnits() + << "/" + << circuit.mBytesOutLastPeriod.valueInUnits() + << " Kbps: " + << (S32)(circuit.mBytesInLastPeriod.valueInUnits() / circuit.mLastPeriodLength.value()) + << "/" + << (S32)(circuit.mBytesOutLastPeriod.valueInUnits() / 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 ba38849f70..521982d7b1 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 -#include - -#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 packet_time_map; - - packet_time_map mPotentialLostPackets; - packet_time_map mRecentlyReceivedReliablePackets; - std::vector mAcks; - F32 mAckCreationTime; // first ack creation time - - typedef std::map 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 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 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 +#include + +#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 packet_time_map; + + packet_time_map mPotentialLostPackets; + packet_time_map mRecentlyReceivedReliablePackets; + std::vector mAcks; + F32 mAckCreationTime; // first ack creation time + + typedef std::map 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 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 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 345942955c..0df249d035 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 126b23340f..ee29e4ed13 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/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index e8cd11c0a0..134f34aafa 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 5c896d28fc..167c102b43 100644 --- a/indra/llmessage/lldatapacker.h +++ b/indra/llmessage/lldatapacker.h @@ -1,435 +1,435 @@ -/** - * @file lldatapacker.h - * @brief Data packer declaration for tightly storing binary data. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLDATAPACKER_H -#define LL_LLDATAPACKER_H - -class LLColor4; -class LLColor4U; -class LLVector2; -class LLVector3; -class LLVector4; -class LLUUID; - -class LLDataPacker -{ -public: - virtual ~LLDataPacker() {} - - // Not required to override, but error to call? - virtual void reset(); - virtual void dumpBufferToLog(); - - virtual bool hasNext() const = 0; - - virtual bool packString(const std::string& value, const char *name) = 0; - virtual bool unpackString(std::string& value, const char *name) = 0; - - virtual bool packBinaryData(const U8 *value, S32 size, const char *name) = 0; - virtual bool unpackBinaryData(U8 *value, S32 &size, const char *name) = 0; - - // Constant size binary data packing - virtual bool packBinaryDataFixed(const U8 *value, S32 size, const char *name) = 0; - virtual bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name) = 0; - - virtual bool packU8(const U8 value, const char *name) = 0; - virtual bool unpackU8(U8 &value, const char *name) = 0; - - virtual bool packU16(const U16 value, const char *name) = 0; - virtual bool unpackU16(U16 &value, const char *name) = 0; - bool unpackU16s(U16 *value, S32 count, const char *name); - - virtual bool packS16(const S16 value, const char *name) = 0; - virtual bool unpackS16(S16 &value, const char *name) = 0; - bool unpackS16s(S16 *value, S32 count, const char *name); - - virtual bool packU32(const U32 value, const char *name) = 0; - virtual bool unpackU32(U32 &value, const char *name) = 0; - - virtual bool packS32(const S32 value, const char *name) = 0; - virtual bool unpackS32(S32 &value, const char *name) = 0; - - virtual bool packF32(const F32 value, const char *name) = 0; - virtual bool unpackF32(F32 &value, const char *name) = 0; - bool unpackF32s(F32 *values, S32 count, const char *name); - - // Packs a float into an integer, using the given size - // and picks the right U* data type to pack into. - bool packFixed(const F32 value, const char *name, - const bool is_signed, const U32 int_bits, const U32 frac_bits); - bool unpackFixed(F32 &value, const char *name, - const bool is_signed, const U32 int_bits, const U32 frac_bits); - - virtual bool packColor4(const LLColor4 &value, const char *name) = 0; - virtual bool unpackColor4(LLColor4 &value, const char *name) = 0; - - virtual bool packColor4U(const LLColor4U &value, const char *name) = 0; - virtual bool unpackColor4U(LLColor4U &value, const char *name) = 0; - bool unpackColor4Us(LLColor4U *values, S32 count, const char *name); - - virtual bool packVector2(const LLVector2 &value, const char *name) = 0; - virtual bool unpackVector2(LLVector2 &value, const char *name) = 0; - - virtual bool packVector3(const LLVector3 &value, const char *name) = 0; - virtual bool unpackVector3(LLVector3 &value, const char *name) = 0; - - virtual bool packVector4(const LLVector4 &value, const char *name) = 0; - virtual bool unpackVector4(LLVector4 &value, const char *name) = 0; - - virtual bool packUUID(const LLUUID &value, const char *name) = 0; - virtual bool unpackUUID(LLUUID &value, const char *name) = 0; - bool unpackUUIDs(LLUUID *values, S32 count, const char *name); - U32 getPassFlags() const { return mPassFlags; } - void setPassFlags(U32 flags) { mPassFlags = flags; } -protected: - LLDataPacker(); -protected: - U32 mPassFlags; - bool mWriteEnabled; // disable this to do things like determine filesize without actually copying data -}; - -class LLDataPackerBinaryBuffer : public LLDataPacker -{ -public: - LLDataPackerBinaryBuffer(U8 *bufferp, S32 size) - : LLDataPacker(), - mBufferp(bufferp), - mCurBufferp(bufferp), - mBufferSize(size) - { - mWriteEnabled = true; - } - - LLDataPackerBinaryBuffer() - : LLDataPacker(), - mBufferp(NULL), - mCurBufferp(NULL), - mBufferSize(0) - { - } - - /*virtual*/ bool packString(const std::string& value, const char *name); - /*virtual*/ bool unpackString(std::string& value, const char *name); - - /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name); - /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name); - - // Constant size binary data packing - /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name); - /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name); - - /*virtual*/ bool packU8(const U8 value, const char *name); - /*virtual*/ bool unpackU8(U8 &value, const char *name); - - /*virtual*/ bool packU16(const U16 value, const char *name); - /*virtual*/ bool unpackU16(U16 &value, const char *name); - - /*virtual*/ bool packS16(const S16 value, const char *name); - /*virtual*/ bool unpackS16(S16 &value, const char *name); - - /*virtual*/ bool packU32(const U32 value, const char *name); - /*virtual*/ bool unpackU32(U32 &value, const char *name); - - /*virtual*/ bool packS32(const S32 value, const char *name); - /*virtual*/ bool unpackS32(S32 &value, const char *name); - - /*virtual*/ bool packF32(const F32 value, const char *name); - /*virtual*/ bool unpackF32(F32 &value, const char *name); - - /*virtual*/ bool packColor4(const LLColor4 &value, const char *name); - /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name); - - /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name); - /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name); - - /*virtual*/ bool packVector2(const LLVector2 &value, const char *name); - /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name); - - /*virtual*/ bool packVector3(const LLVector3 &value, const char *name); - /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name); - - /*virtual*/ bool packVector4(const LLVector4 &value, const char *name); - /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name); - - /*virtual*/ bool packUUID(const LLUUID &value, const char *name); - /*virtual*/ bool unpackUUID(LLUUID &value, const char *name); - - S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp); } - S32 getBufferSize() const { return mBufferSize; } - const U8* getBuffer() const { return mBufferp; } - void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); } - void shift(S32 offset) { reset(); mCurBufferp += offset;} - void freeBuffer() { delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = false; } - void assignBuffer(U8 *bufferp, S32 size) - { - if(mBufferp && mBufferp != bufferp) - { - freeBuffer() ; - } - mBufferp = bufferp; - mCurBufferp = bufferp; - mBufferSize = size; - mWriteEnabled = true; - } - const LLDataPackerBinaryBuffer& operator=(const LLDataPackerBinaryBuffer &a); - - /*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); } - - /*virtual*/ void dumpBufferToLog(); -protected: - inline bool verifyLength(const S32 data_size, const char *name); - - U8 *mBufferp; - U8 *mCurBufferp; - S32 mBufferSize; -}; - -inline bool LLDataPackerBinaryBuffer::verifyLength(const S32 data_size, const char *name) -{ - if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size) - { - LL_WARNS() << "Buffer overflow in BinaryBuffer length verify, field name " << name << "!" << LL_ENDL; - LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL; - return false; - } - - return true; -} - -class LLDataPackerAsciiBuffer : public LLDataPacker -{ -public: - LLDataPackerAsciiBuffer(char* bufferp, S32 size) - { - mBufferp = bufferp; - mCurBufferp = bufferp; - mBufferSize = size; - mPassFlags = 0; - mIncludeNames = false; - mWriteEnabled = true; - } - - LLDataPackerAsciiBuffer() - { - mBufferp = NULL; - mCurBufferp = NULL; - mBufferSize = 0; - mPassFlags = 0; - mIncludeNames = false; - mWriteEnabled = false; - } - - /*virtual*/ bool packString(const std::string& value, const char *name); - /*virtual*/ bool unpackString(std::string& value, const char *name); - - /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name); - /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name); - - // Constant size binary data packing - /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name); - /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name); - - /*virtual*/ bool packU8(const U8 value, const char *name); - /*virtual*/ bool unpackU8(U8 &value, const char *name); - - /*virtual*/ bool packU16(const U16 value, const char *name); - /*virtual*/ bool unpackU16(U16 &value, const char *name); - - /*virtual*/ bool packS16(const S16 value, const char *name); - /*virtual*/ bool unpackS16(S16 &value, const char *name); - - /*virtual*/ bool packU32(const U32 value, const char *name); - /*virtual*/ bool unpackU32(U32 &value, const char *name); - - /*virtual*/ bool packS32(const S32 value, const char *name); - /*virtual*/ bool unpackS32(S32 &value, const char *name); - - /*virtual*/ bool packF32(const F32 value, const char *name); - /*virtual*/ bool unpackF32(F32 &value, const char *name); - - /*virtual*/ bool packColor4(const LLColor4 &value, const char *name); - /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name); - - /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name); - /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name); - - /*virtual*/ bool packVector2(const LLVector2 &value, const char *name); - /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name); - - /*virtual*/ bool packVector3(const LLVector3 &value, const char *name); - /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name); - - /*virtual*/ bool packVector4(const LLVector4 &value, const char *name); - /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name); - - /*virtual*/ bool packUUID(const LLUUID &value, const char *name); - /*virtual*/ bool unpackUUID(LLUUID &value, const char *name); - - void setIncludeNames(bool b) { mIncludeNames = b; } - - // Include the trailing NULL so it's always a valid string - S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp) + 1; } - - S32 getBufferSize() const { return mBufferSize; } - /*virtual*/ void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); } - - /*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); } - - inline void freeBuffer(); - inline void assignBuffer(char* bufferp, S32 size); - void dump(); - -protected: - void writeIndentedName(const char *name); - bool getValueStr(const char *name, char *out_value, const S32 value_len); - -protected: - inline bool verifyLength(const S32 data_size, const char *name); - - char *mBufferp; - char *mCurBufferp; - S32 mBufferSize; - bool mIncludeNames; // useful for debugging, print the name of each field -}; - -inline void LLDataPackerAsciiBuffer::freeBuffer() -{ - delete [] mBufferp; - mBufferp = mCurBufferp = NULL; - mBufferSize = 0; - mWriteEnabled = false; -} - -inline void LLDataPackerAsciiBuffer::assignBuffer(char* bufferp, S32 size) -{ - mBufferp = bufferp; - mCurBufferp = bufferp; - mBufferSize = size; - mWriteEnabled = true; -} - -inline bool LLDataPackerAsciiBuffer::verifyLength(const S32 data_size, const char *name) -{ - if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size) - { - LL_WARNS() << "Buffer overflow in AsciiBuffer length verify, field name " << name << "!" << LL_ENDL; - LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL; - return false; - } - - return true; -} - -class LLDataPackerAsciiFile : public LLDataPacker -{ -public: - LLDataPackerAsciiFile(LLFILE *fp, const S32 indent = 2) - : LLDataPacker(), - mIndent(indent), - mFP(fp), - mOutputStream(NULL), - mInputStream(NULL) - { - } - - LLDataPackerAsciiFile(std::ostream& output_stream, const S32 indent = 2) - : LLDataPacker(), - mIndent(indent), - mFP(NULL), - mOutputStream(&output_stream), - mInputStream(NULL) - { - mWriteEnabled = true; - } - - LLDataPackerAsciiFile(std::istream& input_stream, const S32 indent = 2) - : LLDataPacker(), - mIndent(indent), - mFP(NULL), - mOutputStream(NULL), - mInputStream(&input_stream) - { - } - - /*virtual*/ bool packString(const std::string& value, const char *name); - /*virtual*/ bool unpackString(std::string& value, const char *name); - - /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name); - /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name); - - /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name); - /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name); - - /*virtual*/ bool packU8(const U8 value, const char *name); - /*virtual*/ bool unpackU8(U8 &value, const char *name); - - /*virtual*/ bool packU16(const U16 value, const char *name); - /*virtual*/ bool unpackU16(U16 &value, const char *name); - - /*virtual*/ bool packS16(const S16 value, const char *name); - /*virtual*/ bool unpackS16(S16 &value, const char *name); - - /*virtual*/ bool packU32(const U32 value, const char *name); - /*virtual*/ bool unpackU32(U32 &value, const char *name); - - /*virtual*/ bool packS32(const S32 value, const char *name); - /*virtual*/ bool unpackS32(S32 &value, const char *name); - - /*virtual*/ bool packF32(const F32 value, const char *name); - /*virtual*/ bool unpackF32(F32 &value, const char *name); - - /*virtual*/ bool packColor4(const LLColor4 &value, const char *name); - /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name); - - /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name); - /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name); - - /*virtual*/ bool packVector2(const LLVector2 &value, const char *name); - /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name); - - /*virtual*/ bool packVector3(const LLVector3 &value, const char *name); - /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name); - - /*virtual*/ bool packVector4(const LLVector4 &value, const char *name); - /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name); - - /*virtual*/ bool packUUID(const LLUUID &value, const char *name); - /*virtual*/ bool unpackUUID(LLUUID &value, const char *name); -protected: - void writeIndentedName(const char *name); - bool getValueStr(const char *name, char *out_value, const S32 value_len); - - /*virtual*/ bool hasNext() const { return true; } - -protected: - S32 mIndent; - LLFILE *mFP; - std::ostream* mOutputStream; - std::istream* mInputStream; -}; - -#endif // LL_LLDATAPACKER - +/** + * @file lldatapacker.h + * @brief Data packer declaration for tightly storing binary data. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDATAPACKER_H +#define LL_LLDATAPACKER_H + +class LLColor4; +class LLColor4U; +class LLVector2; +class LLVector3; +class LLVector4; +class LLUUID; + +class LLDataPacker +{ +public: + virtual ~LLDataPacker() {} + + // Not required to override, but error to call? + virtual void reset(); + virtual void dumpBufferToLog(); + + virtual bool hasNext() const = 0; + + virtual bool packString(const std::string& value, const char *name) = 0; + virtual bool unpackString(std::string& value, const char *name) = 0; + + virtual bool packBinaryData(const U8 *value, S32 size, const char *name) = 0; + virtual bool unpackBinaryData(U8 *value, S32 &size, const char *name) = 0; + + // Constant size binary data packing + virtual bool packBinaryDataFixed(const U8 *value, S32 size, const char *name) = 0; + virtual bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name) = 0; + + virtual bool packU8(const U8 value, const char *name) = 0; + virtual bool unpackU8(U8 &value, const char *name) = 0; + + virtual bool packU16(const U16 value, const char *name) = 0; + virtual bool unpackU16(U16 &value, const char *name) = 0; + bool unpackU16s(U16 *value, S32 count, const char *name); + + virtual bool packS16(const S16 value, const char *name) = 0; + virtual bool unpackS16(S16 &value, const char *name) = 0; + bool unpackS16s(S16 *value, S32 count, const char *name); + + virtual bool packU32(const U32 value, const char *name) = 0; + virtual bool unpackU32(U32 &value, const char *name) = 0; + + virtual bool packS32(const S32 value, const char *name) = 0; + virtual bool unpackS32(S32 &value, const char *name) = 0; + + virtual bool packF32(const F32 value, const char *name) = 0; + virtual bool unpackF32(F32 &value, const char *name) = 0; + bool unpackF32s(F32 *values, S32 count, const char *name); + + // Packs a float into an integer, using the given size + // and picks the right U* data type to pack into. + bool packFixed(const F32 value, const char *name, + const bool is_signed, const U32 int_bits, const U32 frac_bits); + bool unpackFixed(F32 &value, const char *name, + const bool is_signed, const U32 int_bits, const U32 frac_bits); + + virtual bool packColor4(const LLColor4 &value, const char *name) = 0; + virtual bool unpackColor4(LLColor4 &value, const char *name) = 0; + + virtual bool packColor4U(const LLColor4U &value, const char *name) = 0; + virtual bool unpackColor4U(LLColor4U &value, const char *name) = 0; + bool unpackColor4Us(LLColor4U *values, S32 count, const char *name); + + virtual bool packVector2(const LLVector2 &value, const char *name) = 0; + virtual bool unpackVector2(LLVector2 &value, const char *name) = 0; + + virtual bool packVector3(const LLVector3 &value, const char *name) = 0; + virtual bool unpackVector3(LLVector3 &value, const char *name) = 0; + + virtual bool packVector4(const LLVector4 &value, const char *name) = 0; + virtual bool unpackVector4(LLVector4 &value, const char *name) = 0; + + virtual bool packUUID(const LLUUID &value, const char *name) = 0; + virtual bool unpackUUID(LLUUID &value, const char *name) = 0; + bool unpackUUIDs(LLUUID *values, S32 count, const char *name); + U32 getPassFlags() const { return mPassFlags; } + void setPassFlags(U32 flags) { mPassFlags = flags; } +protected: + LLDataPacker(); +protected: + U32 mPassFlags; + bool mWriteEnabled; // disable this to do things like determine filesize without actually copying data +}; + +class LLDataPackerBinaryBuffer : public LLDataPacker +{ +public: + LLDataPackerBinaryBuffer(U8 *bufferp, S32 size) + : LLDataPacker(), + mBufferp(bufferp), + mCurBufferp(bufferp), + mBufferSize(size) + { + mWriteEnabled = true; + } + + LLDataPackerBinaryBuffer() + : LLDataPacker(), + mBufferp(NULL), + mCurBufferp(NULL), + mBufferSize(0) + { + } + + /*virtual*/ bool packString(const std::string& value, const char *name); + /*virtual*/ bool unpackString(std::string& value, const char *name); + + /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name); + /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name); + + // Constant size binary data packing + /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name); + /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name); + + /*virtual*/ bool packU8(const U8 value, const char *name); + /*virtual*/ bool unpackU8(U8 &value, const char *name); + + /*virtual*/ bool packU16(const U16 value, const char *name); + /*virtual*/ bool unpackU16(U16 &value, const char *name); + + /*virtual*/ bool packS16(const S16 value, const char *name); + /*virtual*/ bool unpackS16(S16 &value, const char *name); + + /*virtual*/ bool packU32(const U32 value, const char *name); + /*virtual*/ bool unpackU32(U32 &value, const char *name); + + /*virtual*/ bool packS32(const S32 value, const char *name); + /*virtual*/ bool unpackS32(S32 &value, const char *name); + + /*virtual*/ bool packF32(const F32 value, const char *name); + /*virtual*/ bool unpackF32(F32 &value, const char *name); + + /*virtual*/ bool packColor4(const LLColor4 &value, const char *name); + /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name); + + /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name); + /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name); + + /*virtual*/ bool packVector2(const LLVector2 &value, const char *name); + /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name); + + /*virtual*/ bool packVector3(const LLVector3 &value, const char *name); + /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name); + + /*virtual*/ bool packVector4(const LLVector4 &value, const char *name); + /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name); + + /*virtual*/ bool packUUID(const LLUUID &value, const char *name); + /*virtual*/ bool unpackUUID(LLUUID &value, const char *name); + + S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp); } + S32 getBufferSize() const { return mBufferSize; } + const U8* getBuffer() const { return mBufferp; } + void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); } + void shift(S32 offset) { reset(); mCurBufferp += offset;} + void freeBuffer() { delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = false; } + void assignBuffer(U8 *bufferp, S32 size) + { + if(mBufferp && mBufferp != bufferp) + { + freeBuffer() ; + } + mBufferp = bufferp; + mCurBufferp = bufferp; + mBufferSize = size; + mWriteEnabled = true; + } + const LLDataPackerBinaryBuffer& operator=(const LLDataPackerBinaryBuffer &a); + + /*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); } + + /*virtual*/ void dumpBufferToLog(); +protected: + inline bool verifyLength(const S32 data_size, const char *name); + + U8 *mBufferp; + U8 *mCurBufferp; + S32 mBufferSize; +}; + +inline bool LLDataPackerBinaryBuffer::verifyLength(const S32 data_size, const char *name) +{ + if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size) + { + LL_WARNS() << "Buffer overflow in BinaryBuffer length verify, field name " << name << "!" << LL_ENDL; + LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL; + return false; + } + + return true; +} + +class LLDataPackerAsciiBuffer : public LLDataPacker +{ +public: + LLDataPackerAsciiBuffer(char* bufferp, S32 size) + { + mBufferp = bufferp; + mCurBufferp = bufferp; + mBufferSize = size; + mPassFlags = 0; + mIncludeNames = false; + mWriteEnabled = true; + } + + LLDataPackerAsciiBuffer() + { + mBufferp = NULL; + mCurBufferp = NULL; + mBufferSize = 0; + mPassFlags = 0; + mIncludeNames = false; + mWriteEnabled = false; + } + + /*virtual*/ bool packString(const std::string& value, const char *name); + /*virtual*/ bool unpackString(std::string& value, const char *name); + + /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name); + /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name); + + // Constant size binary data packing + /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name); + /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name); + + /*virtual*/ bool packU8(const U8 value, const char *name); + /*virtual*/ bool unpackU8(U8 &value, const char *name); + + /*virtual*/ bool packU16(const U16 value, const char *name); + /*virtual*/ bool unpackU16(U16 &value, const char *name); + + /*virtual*/ bool packS16(const S16 value, const char *name); + /*virtual*/ bool unpackS16(S16 &value, const char *name); + + /*virtual*/ bool packU32(const U32 value, const char *name); + /*virtual*/ bool unpackU32(U32 &value, const char *name); + + /*virtual*/ bool packS32(const S32 value, const char *name); + /*virtual*/ bool unpackS32(S32 &value, const char *name); + + /*virtual*/ bool packF32(const F32 value, const char *name); + /*virtual*/ bool unpackF32(F32 &value, const char *name); + + /*virtual*/ bool packColor4(const LLColor4 &value, const char *name); + /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name); + + /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name); + /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name); + + /*virtual*/ bool packVector2(const LLVector2 &value, const char *name); + /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name); + + /*virtual*/ bool packVector3(const LLVector3 &value, const char *name); + /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name); + + /*virtual*/ bool packVector4(const LLVector4 &value, const char *name); + /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name); + + /*virtual*/ bool packUUID(const LLUUID &value, const char *name); + /*virtual*/ bool unpackUUID(LLUUID &value, const char *name); + + void setIncludeNames(bool b) { mIncludeNames = b; } + + // Include the trailing NULL so it's always a valid string + S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp) + 1; } + + S32 getBufferSize() const { return mBufferSize; } + /*virtual*/ void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); } + + /*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); } + + inline void freeBuffer(); + inline void assignBuffer(char* bufferp, S32 size); + void dump(); + +protected: + void writeIndentedName(const char *name); + bool getValueStr(const char *name, char *out_value, const S32 value_len); + +protected: + inline bool verifyLength(const S32 data_size, const char *name); + + char *mBufferp; + char *mCurBufferp; + S32 mBufferSize; + bool mIncludeNames; // useful for debugging, print the name of each field +}; + +inline void LLDataPackerAsciiBuffer::freeBuffer() +{ + delete [] mBufferp; + mBufferp = mCurBufferp = NULL; + mBufferSize = 0; + mWriteEnabled = false; +} + +inline void LLDataPackerAsciiBuffer::assignBuffer(char* bufferp, S32 size) +{ + mBufferp = bufferp; + mCurBufferp = bufferp; + mBufferSize = size; + mWriteEnabled = true; +} + +inline bool LLDataPackerAsciiBuffer::verifyLength(const S32 data_size, const char *name) +{ + if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size) + { + LL_WARNS() << "Buffer overflow in AsciiBuffer length verify, field name " << name << "!" << LL_ENDL; + LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL; + return false; + } + + return true; +} + +class LLDataPackerAsciiFile : public LLDataPacker +{ +public: + LLDataPackerAsciiFile(LLFILE *fp, const S32 indent = 2) + : LLDataPacker(), + mIndent(indent), + mFP(fp), + mOutputStream(NULL), + mInputStream(NULL) + { + } + + LLDataPackerAsciiFile(std::ostream& output_stream, const S32 indent = 2) + : LLDataPacker(), + mIndent(indent), + mFP(NULL), + mOutputStream(&output_stream), + mInputStream(NULL) + { + mWriteEnabled = true; + } + + LLDataPackerAsciiFile(std::istream& input_stream, const S32 indent = 2) + : LLDataPacker(), + mIndent(indent), + mFP(NULL), + mOutputStream(NULL), + mInputStream(&input_stream) + { + } + + /*virtual*/ bool packString(const std::string& value, const char *name); + /*virtual*/ bool unpackString(std::string& value, const char *name); + + /*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name); + /*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name); + + /*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name); + /*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name); + + /*virtual*/ bool packU8(const U8 value, const char *name); + /*virtual*/ bool unpackU8(U8 &value, const char *name); + + /*virtual*/ bool packU16(const U16 value, const char *name); + /*virtual*/ bool unpackU16(U16 &value, const char *name); + + /*virtual*/ bool packS16(const S16 value, const char *name); + /*virtual*/ bool unpackS16(S16 &value, const char *name); + + /*virtual*/ bool packU32(const U32 value, const char *name); + /*virtual*/ bool unpackU32(U32 &value, const char *name); + + /*virtual*/ bool packS32(const S32 value, const char *name); + /*virtual*/ bool unpackS32(S32 &value, const char *name); + + /*virtual*/ bool packF32(const F32 value, const char *name); + /*virtual*/ bool unpackF32(F32 &value, const char *name); + + /*virtual*/ bool packColor4(const LLColor4 &value, const char *name); + /*virtual*/ bool unpackColor4(LLColor4 &value, const char *name); + + /*virtual*/ bool packColor4U(const LLColor4U &value, const char *name); + /*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name); + + /*virtual*/ bool packVector2(const LLVector2 &value, const char *name); + /*virtual*/ bool unpackVector2(LLVector2 &value, const char *name); + + /*virtual*/ bool packVector3(const LLVector3 &value, const char *name); + /*virtual*/ bool unpackVector3(LLVector3 &value, const char *name); + + /*virtual*/ bool packVector4(const LLVector4 &value, const char *name); + /*virtual*/ bool unpackVector4(LLVector4 &value, const char *name); + + /*virtual*/ bool packUUID(const LLUUID &value, const char *name); + /*virtual*/ bool unpackUUID(LLUUID &value, const char *name); +protected: + void writeIndentedName(const char *name); + bool getValueStr(const char *name, char *out_value, const S32 value_len); + + /*virtual*/ bool hasNext() const { return true; } + +protected: + S32 mIndent; + LLFILE *mFP; + std::ostream* mOutputStream; + std::istream* mInputStream; +}; + +#endif // LL_LLDATAPACKER + diff --git a/indra/llmessage/llhost.cpp b/indra/llmessage/llhost.cpp index 264d64bb50..ace316512f 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 -#else - #include - #include // ntonl() - #include - #include - #include -#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 +#else + #include + #include // ntonl() + #include + #include + #include +#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 1a3a48eede..6824fa3d78 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 -#include - -#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 +#include + +#include "net.h" + +const U32 INVALID_PORT = 0; +const U32 INVALID_HOST_IP_ADDRESS = 0x0; + +class LLHost { +protected: + U32 mPort; + U32 mIP; + std::string mUntrustedSimCap; +public: + + // CREATORS + LLHost() + : mPort(INVALID_PORT), + mIP(INVALID_HOST_IP_ADDRESS) + { } // STL's hash_map expect this T() + + LLHost( U32 ipv4_addr, U32 port ) + : mPort( port ) + { + mIP = ipv4_addr; + } + + LLHost( const std::string& ipv4_addr, U32 port ) + : mPort( port ) + { + mIP = ip_string_to_u32(ipv4_addr.c_str()); + } + + explicit LLHost(const U64 ip_port) + { + U32 ip = (U32)(ip_port >> 32); + U32 port = (U32)(ip_port & (U64)0xFFFFFFFF); + mIP = ip; + mPort = port; + } + + explicit LLHost(const std::string& ip_and_port); + + ~LLHost() + { } + + // MANIPULATORS + void set( U32 ip, U32 port ) { mIP = ip; mPort = port; } + void set( const std::string& ipstr, U32 port ) { mIP = ip_string_to_u32(ipstr.c_str()); mPort = port; } + void setAddress( const std::string& ipstr ) { mIP = ip_string_to_u32(ipstr.c_str()); } + void setAddress( U32 ip ) { mIP = ip; } + void setPort( U32 port ) { mPort = port; } + bool setHostByName(const std::string& hname); + + LLHost& operator=(const LLHost &rhs); + void invalidate() { mIP = INVALID_HOST_IP_ADDRESS; mPort = INVALID_PORT;}; + + // READERS + U32 getAddress() const { return mIP; } + U32 getPort() const { return mPort; } + bool isOk() const { return (mIP != INVALID_HOST_IP_ADDRESS) && (mPort != INVALID_PORT); } + bool isInvalid() { return (mIP == INVALID_HOST_IP_ADDRESS) || (mPort == INVALID_PORT); } + size_t hash() const { return (mIP << 16) | (mPort & 0xffff); } + std::string getString() const; + std::string getIPString() const; + std::string getHostName() const; + std::string getIPandPort() const; + + std::string getUntrustedSimulatorCap() const { return mUntrustedSimCap; } + void setUntrustedSimulatorCap(const std::string &capurl) { mUntrustedSimCap = capurl; } + + friend std::ostream& operator<< (std::ostream& os, const LLHost &hh); + + // This operator is not well defined. does it expect a + // "192.168.1.1:80" notation or "int int" format? Phoenix 2007-05-18 + //friend std::istream& operator>> (std::istream& is, LLHost &hh); + + friend bool operator==( const LLHost &lhs, const LLHost &rhs ); + friend bool operator!=( const LLHost &lhs, const LLHost &rhs ); + friend bool operator<(const LLHost &lhs, const LLHost &rhs); +}; + + +// Function Object required for STL templates using LLHost as key +class LLHostHash +{ +public: + size_t operator() (const LLHost &hh) const { return hh.hash(); } +}; + + +inline bool operator==( const LLHost &lhs, const LLHost &rhs ) +{ + return (lhs.mIP == rhs.mIP) && (lhs.mPort == rhs.mPort); +} + +inline bool operator!=( const LLHost &lhs, const LLHost &rhs ) +{ + return (lhs.mIP != rhs.mIP) || (lhs.mPort != rhs.mPort); +} + +inline bool operator<(const LLHost &lhs, const LLHost &rhs) +{ + if (lhs.mIP < rhs.mIP) + { + return true; + } + if (lhs.mIP > rhs.mIP) + { + return false; + } + + if (lhs.mPort < rhs.mPort) + { + return true; + } + else + { + return false; + } +} + + +#endif // LL_LLHOST_H diff --git a/indra/llmessage/llinstantmessage.cpp b/indra/llmessage/llinstantmessage.cpp index 0563613cfa..4c62c07fcb 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 d1f5eef548..d413e81c90 100644 --- a/indra/llmessage/llinstantmessage.h +++ b/indra/llmessage/llinstantmessage.h @@ -1,218 +1,218 @@ -/** - * @file llinstantmessage.h - * @brief Constants and declarations used by instant messages. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLINSTANTMESSAGE_H -#define LL_LLINSTANTMESSAGE_H - -#include "llhost.h" -#include "lluuid.h" -#include "llsd.h" -#include "llrefcount.h" -#include "llpointer.h" -#include "v3math.h" - -class LLMessageSystem; - -// The ImprovedInstantMessage only supports 8 bits in the "Dialog" -// field, so don't go past the byte boundary -enum EInstantMessage -{ - // default. ID is meaningless, nothing in the binary bucket. - IM_NOTHING_SPECIAL = 0, - - // pops a messagebox with a single OK button - IM_MESSAGEBOX = 1, - - // pops a countdown messagebox with a single OK button - // IM_MESSAGEBOX_COUNTDOWN = 2, - - // You've been invited to join a group. - // ID is the group id. - - // The binary bucket contains a null terminated string - // representation of the officer/member status and join cost for - // the invitee. (bug # 7672) The format is 1 byte for - // officer/member (O for officer, M for member), and as many bytes - // as necessary for cost. - IM_GROUP_INVITATION = 3, - - // Inventory offer. - // ID is the transaction id - // Binary bucket is a list of inventory uuid and type. - IM_INVENTORY_OFFERED = 4, - IM_INVENTORY_ACCEPTED = 5, - IM_INVENTORY_DECLINED = 6, - - // Group vote - // Name is name of person who called vote. - // ID is vote ID used for internal tracking - // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 - IM_GROUP_VOTE = 7, - - // Group message - // This means that the message is meant for everyone in the - // agent's group. This will result in a database query to find all - // participants and start an im session. - IM_GROUP_MESSAGE_DEPRECATED = 8, - - // Task inventory offer. - // ID is the transaction id - // Binary bucket is a (mostly) complete packed inventory item - IM_TASK_INVENTORY_OFFERED = 9, - IM_TASK_INVENTORY_ACCEPTED = 10, - IM_TASK_INVENTORY_DECLINED = 11, - - // Copied as pending, type LL_NOTHING_SPECIAL, for new users - // used by offline tools - IM_NEW_USER_DEFAULT = 12, - - // - // session based messaging - the way that people usually actually - // communicate with each other. - // - - // Invite users to a session. - IM_SESSION_INVITE = 13, - - IM_SESSION_P2P_INVITE = 14, - - // start a session with your gruop - IM_SESSION_GROUP_START = 15, - - // start a session without a calling card (finder or objects) - IM_SESSION_CONFERENCE_START = 16, - - // send a message to a session. - IM_SESSION_SEND = 17, - - // leave a session - IM_SESSION_LEAVE = 18, - - // an instant message from an object - for differentiation on the - // viewer, since you can't IM an object yet. - IM_FROM_TASK = 19, - - // sent an IM to a do not disturb user, this is the auto response - IM_DO_NOT_DISTURB_AUTO_RESPONSE = 20, - - // Shows the message in the console and chat history - IM_CONSOLE_AND_CHAT_HISTORY = 21, - - // IM Types used for luring your friends - IM_LURE_USER = 22, - IM_LURE_ACCEPTED = 23, - IM_LURE_DECLINED = 24, - IM_GODLIKE_LURE_USER = 25, - IM_TELEPORT_REQUEST = 26, - - // IM that notifie of a new group election. - // Name is name of person who called vote. - // ID is election ID used for internal tracking - IM_GROUP_ELECTION_DEPRECATED = 27, - - // IM to tell the user to go to an URL. Put a text message in the - // message field, and put the url with a trailing \0 in the binary - // bucket. - IM_GOTO_URL = 28, - - // a message generated by a script which we don't want to - // be sent through e-mail. Similar to IM_FROM_TASK, but - // it is shown as an alert on the viewer. - IM_FROM_TASK_AS_ALERT = 31, - - // IM from group officer to all group members. - IM_GROUP_NOTICE = 32, - IM_GROUP_NOTICE_INVENTORY_ACCEPTED = 33, - IM_GROUP_NOTICE_INVENTORY_DECLINED = 34, - - IM_GROUP_INVITATION_ACCEPT = 35, - IM_GROUP_INVITATION_DECLINE = 36, - - IM_GROUP_NOTICE_REQUESTED = 37, - - IM_FRIENDSHIP_OFFERED = 38, - IM_FRIENDSHIP_ACCEPTED = 39, - IM_FRIENDSHIP_DECLINED_DEPRECATED = 40, - - IM_TYPING_START = 41, - IM_TYPING_STOP = 42, - - IM_COUNT -}; - - -extern const U8 IM_ONLINE; -extern const U8 IM_OFFLINE; - -extern const char EMPTY_BINARY_BUCKET[]; -extern const S32 EMPTY_BINARY_BUCKET_SIZE; - -extern const U32 NO_TIMESTAMP; -extern const std::string SYSTEM_FROM; -extern const std::string INTERACTIVE_SYSTEM_FROM; - -// Number of retry attempts on sending the im. -extern const S32 IM_TTL; - -void pack_instant_message( - LLMessageSystem* msgsystem, - const LLUUID& from_id, - bool from_group, - const LLUUID& session_id, - const LLUUID& to_id, - const std::string& name, - const std::string& message, - U8 offline = IM_ONLINE, - EInstantMessage dialog = IM_NOTHING_SPECIAL, - const LLUUID& id = LLUUID::null, - U32 parent_estate_id = 0, - const LLUUID& region_id = LLUUID::null, - const LLVector3& position = LLVector3::zero, - U32 timestamp = NO_TIMESTAMP, - const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET, - S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE); - -void pack_instant_message_block( - LLMessageSystem* msgsystem, - const LLUUID& from_id, - bool from_group, - const LLUUID& session_id, - const LLUUID& to_id, - const std::string& name, - const std::string& message, - U8 offline = IM_ONLINE, - EInstantMessage dialog = IM_NOTHING_SPECIAL, - const LLUUID& id = LLUUID::null, - U32 parent_estate_id = 0, - const LLUUID& region_id = LLUUID::null, - const LLVector3& position = LLVector3::zero, - U32 timestamp = NO_TIMESTAMP, - const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET, - S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE); - - -#endif // LL_LLINSTANTMESSAGE_H - +/** + * @file llinstantmessage.h + * @brief Constants and declarations used by instant messages. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLINSTANTMESSAGE_H +#define LL_LLINSTANTMESSAGE_H + +#include "llhost.h" +#include "lluuid.h" +#include "llsd.h" +#include "llrefcount.h" +#include "llpointer.h" +#include "v3math.h" + +class LLMessageSystem; + +// The ImprovedInstantMessage only supports 8 bits in the "Dialog" +// field, so don't go past the byte boundary +enum EInstantMessage +{ + // default. ID is meaningless, nothing in the binary bucket. + IM_NOTHING_SPECIAL = 0, + + // pops a messagebox with a single OK button + IM_MESSAGEBOX = 1, + + // pops a countdown messagebox with a single OK button + // IM_MESSAGEBOX_COUNTDOWN = 2, + + // You've been invited to join a group. + // ID is the group id. + + // The binary bucket contains a null terminated string + // representation of the officer/member status and join cost for + // the invitee. (bug # 7672) The format is 1 byte for + // officer/member (O for officer, M for member), and as many bytes + // as necessary for cost. + IM_GROUP_INVITATION = 3, + + // Inventory offer. + // ID is the transaction id + // Binary bucket is a list of inventory uuid and type. + IM_INVENTORY_OFFERED = 4, + IM_INVENTORY_ACCEPTED = 5, + IM_INVENTORY_DECLINED = 6, + + // Group vote + // Name is name of person who called vote. + // ID is vote ID used for internal tracking + // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 + IM_GROUP_VOTE = 7, + + // Group message + // This means that the message is meant for everyone in the + // agent's group. This will result in a database query to find all + // participants and start an im session. + IM_GROUP_MESSAGE_DEPRECATED = 8, + + // Task inventory offer. + // ID is the transaction id + // Binary bucket is a (mostly) complete packed inventory item + IM_TASK_INVENTORY_OFFERED = 9, + IM_TASK_INVENTORY_ACCEPTED = 10, + IM_TASK_INVENTORY_DECLINED = 11, + + // Copied as pending, type LL_NOTHING_SPECIAL, for new users + // used by offline tools + IM_NEW_USER_DEFAULT = 12, + + // + // session based messaging - the way that people usually actually + // communicate with each other. + // + + // Invite users to a session. + IM_SESSION_INVITE = 13, + + IM_SESSION_P2P_INVITE = 14, + + // start a session with your gruop + IM_SESSION_GROUP_START = 15, + + // start a session without a calling card (finder or objects) + IM_SESSION_CONFERENCE_START = 16, + + // send a message to a session. + IM_SESSION_SEND = 17, + + // leave a session + IM_SESSION_LEAVE = 18, + + // an instant message from an object - for differentiation on the + // viewer, since you can't IM an object yet. + IM_FROM_TASK = 19, + + // sent an IM to a do not disturb user, this is the auto response + IM_DO_NOT_DISTURB_AUTO_RESPONSE = 20, + + // Shows the message in the console and chat history + IM_CONSOLE_AND_CHAT_HISTORY = 21, + + // IM Types used for luring your friends + IM_LURE_USER = 22, + IM_LURE_ACCEPTED = 23, + IM_LURE_DECLINED = 24, + IM_GODLIKE_LURE_USER = 25, + IM_TELEPORT_REQUEST = 26, + + // IM that notifie of a new group election. + // Name is name of person who called vote. + // ID is election ID used for internal tracking + IM_GROUP_ELECTION_DEPRECATED = 27, + + // IM to tell the user to go to an URL. Put a text message in the + // message field, and put the url with a trailing \0 in the binary + // bucket. + IM_GOTO_URL = 28, + + // a message generated by a script which we don't want to + // be sent through e-mail. Similar to IM_FROM_TASK, but + // it is shown as an alert on the viewer. + IM_FROM_TASK_AS_ALERT = 31, + + // IM from group officer to all group members. + IM_GROUP_NOTICE = 32, + IM_GROUP_NOTICE_INVENTORY_ACCEPTED = 33, + IM_GROUP_NOTICE_INVENTORY_DECLINED = 34, + + IM_GROUP_INVITATION_ACCEPT = 35, + IM_GROUP_INVITATION_DECLINE = 36, + + IM_GROUP_NOTICE_REQUESTED = 37, + + IM_FRIENDSHIP_OFFERED = 38, + IM_FRIENDSHIP_ACCEPTED = 39, + IM_FRIENDSHIP_DECLINED_DEPRECATED = 40, + + IM_TYPING_START = 41, + IM_TYPING_STOP = 42, + + IM_COUNT +}; + + +extern const U8 IM_ONLINE; +extern const U8 IM_OFFLINE; + +extern const char EMPTY_BINARY_BUCKET[]; +extern const S32 EMPTY_BINARY_BUCKET_SIZE; + +extern const U32 NO_TIMESTAMP; +extern const std::string SYSTEM_FROM; +extern const std::string INTERACTIVE_SYSTEM_FROM; + +// Number of retry attempts on sending the im. +extern const S32 IM_TTL; + +void pack_instant_message( + LLMessageSystem* msgsystem, + const LLUUID& from_id, + bool from_group, + const LLUUID& session_id, + const LLUUID& to_id, + const std::string& name, + const std::string& message, + U8 offline = IM_ONLINE, + EInstantMessage dialog = IM_NOTHING_SPECIAL, + const LLUUID& id = LLUUID::null, + U32 parent_estate_id = 0, + const LLUUID& region_id = LLUUID::null, + const LLVector3& position = LLVector3::zero, + U32 timestamp = NO_TIMESTAMP, + const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET, + S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE); + +void pack_instant_message_block( + LLMessageSystem* msgsystem, + const LLUUID& from_id, + bool from_group, + const LLUUID& session_id, + const LLUUID& to_id, + const std::string& name, + const std::string& message, + U8 offline = IM_ONLINE, + EInstantMessage dialog = IM_NOTHING_SPECIAL, + const LLUUID& id = LLUUID::null, + U32 parent_estate_id = 0, + const LLUUID& region_id = LLUUID::null, + const LLVector3& position = LLVector3::zero, + U32 timestamp = NO_TIMESTAMP, + const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET, + S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE); + + +#endif // LL_LLINSTANTMESSAGE_H + diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index fe01f2d4a4..ca027d7675 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 -#include - -#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" - from_fmt << "\"" << from_name << "\" <" << from_address << ">"; - } - else - { - // - 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 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 +#include + +#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" + from_fmt << "\"" << from_name << "\" <" << from_address << ">"; + } + else + { + // + 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 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 1523e7b5c6..d67b89d1ea 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" - * To: "to_name" - * 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" + * To: "to_name" + * Subject: subject + * + * message + */ + static bool send( + const char* from_name, + const char* from_address, + const char* to_name, + const char* to_address, + const char* subject, + const char* message, + const LLSD& headers = LLSD()); + + /** + * @brief build the complete smtp transaction & header for use in an + * mail. + * + * @param from_name The name of the email sender + * @param from_address The email address for the sender + * @param to_name The name of the email recipient + * @param to_address The email recipient address + * @param subject The subject of the email + * @param headers optional X-Foo headers in an llsd map. + * @return Returns the complete SMTP transaction mail header. + */ + static std::string buildSMTPTransaction( + const char* from_name, + const char* from_address, + const char* to_name, + const char* to_address, + const char* subject, + const LLSD& headers = LLSD()); + + /** + * @brief send an email with header and body. + * + * @param header The email header. Use build_mail_header(). + * @param message The unescaped email message. + * @param from_address Used for debugging + * @param to_address Used for debugging + * @return Returns true if the message could be sent. + */ + static bool send( + const std::string& header, + const std::string& message, + const char* from_address, + const char* to_address); + + // IM-to-email sessions use a "session id" based on an encrypted + // combination of from agent_id, to agent_id, and timestamp. When + // a user replies to an email we use the from_id to determine the + // sender's name and the to_id to route the message. The address + // is encrypted to prevent users from building addresses to spoof + // IMs from other users. The timestamps allow the "sessions" to + // expire, in case one of the sessions is stolen/hijacked. + // + // indra/tools/mailglue is responsible for parsing the inbound mail. + // + // secret: binary blob passed to blowfish, max length 56 bytes + // secret_size: length of blob, in bytes + // + // Returns: "base64" encoded email local-part, with _ and - as the + // non-alphanumeric characters. This allows better compatibility + // with email systems than the default / and + extra chars. JC + static std::string encryptIMEmailAddress( + const LLUUID& from_agent_id, + const LLUUID& to_agent_id, + U32 time, + const U8* secret, + size_t secret_size); +}; + +extern const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE; + +#endif diff --git a/indra/llmessage/llmessagebuilder.h b/indra/llmessage/llmessagebuilder.h index 2acb47c238..3f04857945 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 - -#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 + +#include "stdtypes.h" + +class LLMsgData; +class LLQuaternion; +class LLSD; +class LLUUID; +class LLVector3; +class LLVector3d; +class LLVector4; + +class LLMessageBuilder +{ +public: + + //CLASS_LOG_TYPE(LLMessageBuilder); + + virtual ~LLMessageBuilder(); + virtual void newMessage(const char* name) = 0; + + virtual void nextBlock(const char* blockname) = 0; + virtual bool removeLastBlock() = 0; // TODO: babbage: remove this horror + + /** All add* methods expect pointers to canonical strings. */ + virtual void addBinaryData( + const char* varname, + const void* data, + S32 size) = 0; + virtual void addBOOL(const char* varname, bool b) = 0; + virtual void addS8(const char* varname, S8 s) = 0; + virtual void addU8(const char* varname, U8 u) = 0; + virtual void addS16(const char* varname, S16 i) = 0; + virtual void addU16(const char* varname, U16 i) = 0; + virtual void addF32(const char* varname, F32 f) = 0; + virtual void addS32(const char* varname, S32 s) = 0; + virtual void addU32(const char* varname, U32 u) = 0; + virtual void addU64(const char* varname, U64 lu) = 0; + virtual void addF64(const char* varname, F64 d) = 0; + virtual void addVector3(const char* varname, const LLVector3& vec) = 0; + virtual void addVector4(const char* varname, const LLVector4& vec) = 0; + virtual void addVector3d(const char* varname, const LLVector3d& vec) = 0; + virtual void addQuat(const char* varname, const LLQuaternion& quat) = 0; + virtual void addUUID(const char* varname, const LLUUID& uuid) = 0; + virtual void addIPAddr(const char* varname, const U32 ip) = 0; + virtual void addIPPort(const char* varname, const U16 port) = 0; + virtual void addString(const char* varname, const char* s) = 0; + virtual void addString(const char* varname, const std::string& s) = 0; + + virtual bool isMessageFull(const char* blockname) const = 0; + virtual void compressMessage(U8*& buf_ptr, U32& buffer_length) = 0; + virtual S32 getMessageSize() = 0; + + virtual bool isBuilt() const = 0; + virtual bool isClear() const = 0; + virtual U32 buildMessage( + U8* buffer, + U32 buffer_size, + U8 offset_to_data) = 0; + /**< Return built message size */ + virtual void clearMessage() = 0; + + // TODO: babbage: remove this horror + virtual void setBuilt(bool b) = 0; + + virtual const char* getMessageName() const = 0; + + virtual void copyFromMessageData(const LLMsgData& data) = 0; + virtual void copyFromLLSD(const LLSD& data) = 0; +}; + +#endif // LL_LLMESSAGEBUILDER_H diff --git a/indra/llmessage/llmessagereader.cpp b/indra/llmessage/llmessagereader.cpp index 80c4379549..4d4bf679ed 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 42d8906e16..5bc9aea5e4 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/llmessagetemplate.h b/indra/llmessage/llmessagetemplate.h index 454bae7238..e91d4346b6 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 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 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 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 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 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 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 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 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 274ec3e273..cf1f49116e 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 - - -// 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 > tokenizer; - -LLTemplateTokenizer::LLTemplateTokenizer(const std::string & contents) : mStarted(false), mTokens() -{ - boost::char_separator newline("\r\n", "", boost::keep_empty_tokens); - boost::char_separator 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 + + +// 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 > tokenizer; + +LLTemplateTokenizer::LLTemplateTokenizer(const std::string & contents) : mStarted(false), mTokens() +{ + boost::char_separator newline("\r\n", "", boost::keep_empty_tokens); + boost::char_separator spaces(" \t"); + U32 line_counter = 1; + + tokenizer line_tokens(contents, newline); + for(tokenizer::iterator line_iter = line_tokens.begin(); + line_iter != line_tokens.end(); + ++line_iter, ++line_counter) + { + tokenizer word_tokens(*line_iter, spaces); + for(tokenizer::iterator word_iter = word_tokens.begin(); + word_iter != word_tokens.end(); + ++word_iter) + { + if((*word_iter)[0] == '/') + { + break; // skip to end of line on comments + } + positioned_token pt;// = new positioned_token(); + pt.str = std::string(*word_iter); + pt.line = line_counter; + mTokens.push_back(pt); + } + } + mCurrent = mTokens.begin(); +} +void LLTemplateTokenizer::inc() +{ + if(atEOF()) + { + error("trying to increment token of EOF"); + } + else if(mStarted) + { + ++mCurrent; + } + else + { + mStarted = true; + mCurrent = mTokens.begin(); + } +} +void LLTemplateTokenizer::dec() +{ + if(mCurrent == mTokens.begin()) + { + if(mStarted) + { + mStarted = false; + } + else + { + error("trying to decrement past beginning of file"); + } + } + else + { + mCurrent--; + } +} + +std::string LLTemplateTokenizer::get() const +{ + if(atEOF()) + { + error("trying to get EOF"); + } + return mCurrent->str; +} + +U32 LLTemplateTokenizer::line() const +{ + if(atEOF()) + { + return 0; + } + return mCurrent->line; +} + +bool LLTemplateTokenizer::atEOF() const +{ + return mCurrent == mTokens.end(); +} + +std::string LLTemplateTokenizer::next() +{ + inc(); + return get(); +} + +bool LLTemplateTokenizer::want(const std::string & token) +{ + if(atEOF()) return false; + inc(); + if(atEOF()) return false; + if(get() != token) + { + dec(); // back up a step + return false; + } + return true; +} + +bool LLTemplateTokenizer::wantEOF() +{ + // see if the next token is EOF + if(atEOF()) return true; + inc(); + if(!atEOF()) + { + dec(); // back up a step + return false; + } + return true; +} + +void LLTemplateTokenizer::error(std::string message) const +{ + if(atEOF()) + { + LL_ERRS() << "Unexpected end of file: " << message << LL_ENDL; + } + else + { + LL_ERRS() << "Problem parsing message template at line " + << line() << ", with token '" << get() << "' : " + << message << LL_ENDL; + } +} + + +// Done with tokenizer, next is the parser. + +LLTemplateParser::LLTemplateParser(LLTemplateTokenizer & tokens): + mVersion(0.f), + mMessages() +{ + // the version number should be the first thing in the file + if (tokens.want("version")) + { + // version number + std::string vers_string = tokens.next(); + mVersion = (F32)atof(vers_string.c_str()); + + LL_INFOS() << "### Message template version " << mVersion << " ###" << LL_ENDL; + } + else + { + LL_ERRS() << "Version must be first in the message template, found " + << tokens.next() << LL_ENDL; + } + + while(LLMessageTemplate * templatep = parseMessage(tokens)) + { + if (templatep->getDeprecation() != MD_DEPRECATED) + { + mMessages.push_back(templatep); + } + else + { + delete templatep; + } + } + + if(!tokens.wantEOF()) + { + LL_ERRS() << "Expected end of template or a message, instead found: " + << tokens.next() << " at " << tokens.line() << LL_ENDL; + } +} + +F32 LLTemplateParser::getVersion() const +{ + return mVersion; +} + +LLTemplateParser::message_iterator LLTemplateParser::getMessagesBegin() const +{ + return mMessages.begin(); +} + +LLTemplateParser::message_iterator LLTemplateParser::getMessagesEnd() const +{ + return mMessages.end(); +} + + +// static +LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens) +{ + LLMessageTemplate *templatep = NULL; + if(!tokens.want("{")) + { + return NULL; + } + + // name first + std::string template_name = tokens.next(); + + // is name a legit C variable name + if (!b_variable_ok(template_name.c_str())) + { + LL_ERRS() << "Not legit variable name: " << template_name << " at " << tokens.line() << LL_ENDL; + } + + // ok, now get Frequency ("High", "Medium", or "Low") + EMsgFrequency frequency = MFT_LOW; + std::string freq_string = tokens.next(); + if (freq_string == "High") + { + frequency = MFT_HIGH; + } + else if (freq_string == "Medium") + { + frequency = MFT_MEDIUM; + } + else if (freq_string == "Low" || freq_string == "Fixed") + { + frequency = MFT_LOW; + } + else + { + LL_ERRS() << "Expected frequency, got " << freq_string << " at " << tokens.line() << LL_ENDL; + } + + // TODO more explicit checking here pls + U32 message_number = strtoul(tokens.next().c_str(),NULL,0); + + switch (frequency) { + case MFT_HIGH: + break; + case MFT_MEDIUM: + message_number = (255 << 8) | message_number; + break; + case MFT_LOW: + message_number = (255 << 24) | (255 << 16) | message_number; + break; + default: + LL_ERRS() << "Unknown frequency enum: " << frequency << LL_ENDL; + } + + templatep = new LLMessageTemplate( + template_name.c_str(), + message_number, + frequency); + + // Now get trust ("Trusted", "NotTrusted") + std::string trust = tokens.next(); + if (trust == "Trusted") + { + templatep->setTrust(MT_TRUST); + } + else if (trust == "NotTrusted") + { + templatep->setTrust(MT_NOTRUST); + } + else + { + LL_ERRS() << "Bad trust " << trust << " at " << tokens.line() << LL_ENDL; + } + + // get encoding + std::string encoding = tokens.next(); + if(encoding == "Unencoded") + { + templatep->setEncoding(ME_UNENCODED); + } + else if(encoding == "Zerocoded") + { + templatep->setEncoding(ME_ZEROCODED); + } + else + { + LL_ERRS() << "Bad encoding " << encoding << " at " << tokens.line() << LL_ENDL; + } + + // get deprecation + if(tokens.want("Deprecated")) + { + templatep->setDeprecation(MD_DEPRECATED); + } + else if (tokens.want("UDPDeprecated")) + { + templatep->setDeprecation(MD_UDPDEPRECATED); + } + else if (tokens.want("UDPBlackListed")) + { + templatep->setDeprecation(MD_UDPBLACKLISTED); + } + else if (tokens.want("NotDeprecated")) + { + // this is the default value, but it can't hurt to set it twice + templatep->setDeprecation(MD_NOTDEPRECATED); + } + else { + // It's probably a brace, let's just start block processing + } + + while(LLMessageBlock * blockp = parseBlock(tokens)) + { + templatep->addBlock(blockp); + } + + if(!tokens.want("}")) + { + LL_ERRS() << "Expecting closing } for message " << template_name + << " at " << tokens.line() << LL_ENDL; + } + return templatep; +} + +// static +LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens) +{ + LLMessageBlock * blockp = NULL; + + if(!tokens.want("{")) + { + return NULL; + } + + // name first + std::string block_name = tokens.next(); + + // is name a legit C variable name + if (!b_variable_ok(block_name.c_str())) + { + LL_ERRS() << "not a legal block name: " << block_name + << " at " << tokens.line() << LL_ENDL; + } + + // now, block type ("Single", "Multiple", or "Variable") + std::string block_type = tokens.next(); + // which one is it? + if (block_type == "Single") + { + // ok, we can create a block + blockp = new LLMessageBlock(block_name.c_str(), MBT_SINGLE); + } + else if (block_type == "Multiple") + { + // need to get the number of repeats + std::string repeats = tokens.next(); + + // is it a legal integer + if (!b_positive_integer_ok(repeats.c_str())) + { + LL_ERRS() << "not a legal integer for block multiple count: " + << repeats << " at " << tokens.line() << LL_ENDL; + } + + // ok, we can create a block + blockp = new LLMessageBlock(block_name.c_str(), + MBT_MULTIPLE, + atoi(repeats.c_str())); + } + else if (block_type == "Variable") + { + // ok, we can create a block + blockp = new LLMessageBlock(block_name.c_str(), MBT_VARIABLE); + } + else + { + LL_ERRS() << "bad block type: " << block_type + << " at " << tokens.line() << LL_ENDL; + } + + + while(LLMessageVariable * varp = parseVariable(tokens)) + { + blockp->addVariable(varp->getName(), + varp->getType(), + varp->getSize()); + delete varp; + } + + if(!tokens.want("}")) + { + LL_ERRS() << "Expecting closing } for block " << block_name + << " at " << tokens.line() << LL_ENDL; + } + return blockp; + +} + +// static +LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens) +{ + LLMessageVariable * varp = NULL; + if(!tokens.want("{")) + { + return NULL; + } + + std::string var_name = tokens.next(); + + if (!b_variable_ok(var_name.c_str())) + { + LL_ERRS() << "Not a legit variable name: " << var_name + << " at " << tokens.line() << LL_ENDL; + } + + std::string var_type = tokens.next(); + + if (var_type == "U8") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_U8, 1); + } + else if (var_type == "U16") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_U16, 2); + } + else if (var_type == "U32") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_U32, 4); + } + else if (var_type == "U64") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_U64, 8); + } + else if (var_type == "S8") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_S8, 1); + } + else if (var_type == "S16") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_S16, 2); + } + else if (var_type == "S32") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_S32, 4); + } + else if (var_type == "S64") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_S64, 8); + } + else if (var_type == "F32") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_F32, 4); + } + else if (var_type == "F64") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_F64, 8); + } + else if (var_type == "LLVector3") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3, 12); + } + else if (var_type == "LLVector3d") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3d, 24); + } + else if (var_type == "LLVector4") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector4, 16); + } + else if (var_type == "LLQuaternion") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_LLQuaternion, 12); + } + else if (var_type == "LLUUID") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_LLUUID, 16); + } + else if (var_type == "BOOL") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_BOOL, 1); + } + else if (var_type == "IPADDR") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_IP_ADDR, 4); + } + else if (var_type == "IPPORT") + { + varp = new LLMessageVariable(var_name.c_str(), MVT_IP_PORT, 2); + } + else if (var_type == "Fixed" || var_type == "Variable") + { + std::string variable_size = tokens.next(); + + if (!b_positive_integer_ok(variable_size.c_str())) + { + LL_ERRS() << "not a legal integer variable size: " << variable_size + << " at " << tokens.line() << LL_ENDL; + } + + EMsgVariableType type_enum; + if(var_type == "Variable") + { + type_enum = MVT_VARIABLE; + } + else if(var_type == "Fixed") + { + type_enum = MVT_FIXED; + } + else + { + type_enum = MVT_FIXED; // removes a warning + LL_ERRS() << "bad variable type: " << var_type + << " at " << tokens.line() << LL_ENDL; + } + + varp = new LLMessageVariable( + var_name.c_str(), + type_enum, + atoi(variable_size.c_str())); + } + else + { + LL_ERRS() << "bad variable type:" << var_type + << " at " << tokens.line() << LL_ENDL; + } + + if(!tokens.want("}")) + { + LL_ERRS() << "Expecting closing } for variable " << var_name + << " at " << tokens.line() << LL_ENDL; + } + return varp; +} diff --git a/indra/llmessage/llmessagethrottle.cpp b/indra/llmessage/llmessagethrottle.cpp index 77af27e404..abcb1085ba 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 9597fbccdf..295bddbd8c 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 - -#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 message_list_t; - typedef std::deque::iterator message_list_iterator_t; - typedef std::deque::reverse_iterator message_list_reverse_iterator_t; - typedef std::deque::const_iterator message_list_const_iterator_t; - typedef std::deque::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 + +#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 message_list_t; + typedef std::deque::iterator message_list_iterator_t; + typedef std::deque::reverse_iterator message_list_reverse_iterator_t; + typedef std::deque::const_iterator message_list_const_iterator_t; + typedef std::deque::const_reverse_iterator message_list_const_reverse_iterator_t; + message_list_t mMessageList[MTC_EOF]; +}; + +extern LLMessageThrottle gMessageThrottle; + +#endif + + diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp index 5254091481..853ae7df82 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 6876c6020d..3c442df009 100644 --- a/indra/llmessage/llnamevalue.h +++ b/indra/llmessage/llnamevalue.h @@ -1,183 +1,183 @@ -/** - * @file llnamevalue.h - * @brief class for defining name value pairs. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLNAMEVALUE_H -#define LL_LLNAMEVALUE_H - -// As of January 2008, I believe we only use the following name-value -// pairs. This is hard to prove because they are initialized from -// strings. JC -// -// FirstName STRING -// LastName STRING -// AttachPt U32 -// AttachmentItemId STRING -// Title STRING -// AttachmentOffset VEC3 -// AttachmentOrientation VEC3 -// SitObject STRING -// SitPosition VEC3 - -#include "llstringtable.h" -#include "llmath.h" -#include "v3math.h" -#include "lldbstrings.h" - -class LLNameValue; -class LLStringTable; - -typedef enum e_name_value_types -{ - NVT_NULL, - NVT_STRING, - NVT_F32, - NVT_S32, - NVT_VEC3, - NVT_U32, - NVT_CAMERA, // Deprecated, but leaving in case removing this will cause problems - NVT_ASSET, - NVT_U64, - NVT_EOF -} ENameValueType; - -typedef enum e_name_value_class -{ - NVC_NULL, - NVC_READ_ONLY, - NVC_READ_WRITE, - NVC_EOF -} ENameValueClass; - -typedef enum e_name_value_sento -{ - NVS_NULL, - NVS_SIM, - NVS_DATA_SIM, - NVS_SIM_VIEWER, - NVS_DATA_SIM_VIEWER, - NVS_EOF -} ENameValueSendto; - - -// NameValues can always be "printed" into a buffer of this length. -const U32 NAME_VALUE_BUF_SIZE = 1024; - - -const U32 NAME_VALUE_TYPE_STRING_LENGTH = 8; -const U32 NAME_VALUE_CLASS_STRING_LENGTH = 16; -const U32 NAME_VALUE_SENDTO_STRING_LENGTH = 18; -const U32 NAME_VALUE_DATA_SIZE = - NAME_VALUE_BUF_SIZE - - ( DB_NV_NAME_BUF_SIZE + - NAME_VALUE_TYPE_STRING_LENGTH + - NAME_VALUE_CLASS_STRING_LENGTH + - NAME_VALUE_SENDTO_STRING_LENGTH ); - - -extern char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH]; /* Flawfinder: Ignore */ -extern char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH]; /* Flawfinder: Ignore */ -extern char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH]; /* Flawfinder: Ignore */ - -typedef union u_name_value_reference -{ - char *string; - F32 *f32; - S32 *s32; - LLVector3 *vec3; - U32 *u32; - U64 *u64; -} UNameValueReference; - - -class LLNameValue -{ -public: - void baseInit(); - void init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto ); - - LLNameValue(); - LLNameValue(const char *data); - LLNameValue(const char *name, const char *type, const char *nvclass ); - LLNameValue(const char *name, const char *data, const char *type, const char *nvclass ); - LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto ); - - ~LLNameValue(); - - char *getString(); - const char *getAsset() const; - F32 *getF32(); - S32 *getS32(); - void getVec3(LLVector3 &vec); - LLVector3 *getVec3(); - U32 *getU32(); - U64 *getU64(); - - const char *getType() const { return mStringType; } - const char *getClass() const { return mStringClass; } - const char *getSendto() const { return mStringSendto; } - - bool sendToData() const; - bool sendToViewer() const; - - void callCallback(); - std::string printNameValue() const; - std::string printData() const; - - ENameValueType getTypeEnum() const { return mType; } - ENameValueClass getClassEnum() const { return mClass; } - ENameValueSendto getSendtoEnum() const { return mSendto; } - - LLNameValue &operator=(const LLNameValue &a); - void setString(const char *a); - void setAsset(const char *a); - void setF32(const F32 a); - void setS32(const S32 a); - void setVec3(const LLVector3 &a); - void setU32(const U32 a); - - friend std::ostream& operator<<(std::ostream& s, const LLNameValue &a); - -private: - void printNameValue(std::ostream& s); - -public: - char *mName; - - char *mStringType; - ENameValueType mType; - char *mStringClass; - ENameValueClass mClass; - char *mStringSendto; - ENameValueSendto mSendto; - - UNameValueReference mNameValueReference; - LLStringTable *mNVNameTable; -}; - -extern LLStringTable gNVNameTable; - - -#endif +/** + * @file llnamevalue.h + * @brief class for defining name value pairs. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLNAMEVALUE_H +#define LL_LLNAMEVALUE_H + +// As of January 2008, I believe we only use the following name-value +// pairs. This is hard to prove because they are initialized from +// strings. JC +// +// FirstName STRING +// LastName STRING +// AttachPt U32 +// AttachmentItemId STRING +// Title STRING +// AttachmentOffset VEC3 +// AttachmentOrientation VEC3 +// SitObject STRING +// SitPosition VEC3 + +#include "llstringtable.h" +#include "llmath.h" +#include "v3math.h" +#include "lldbstrings.h" + +class LLNameValue; +class LLStringTable; + +typedef enum e_name_value_types +{ + NVT_NULL, + NVT_STRING, + NVT_F32, + NVT_S32, + NVT_VEC3, + NVT_U32, + NVT_CAMERA, // Deprecated, but leaving in case removing this will cause problems + NVT_ASSET, + NVT_U64, + NVT_EOF +} ENameValueType; + +typedef enum e_name_value_class +{ + NVC_NULL, + NVC_READ_ONLY, + NVC_READ_WRITE, + NVC_EOF +} ENameValueClass; + +typedef enum e_name_value_sento +{ + NVS_NULL, + NVS_SIM, + NVS_DATA_SIM, + NVS_SIM_VIEWER, + NVS_DATA_SIM_VIEWER, + NVS_EOF +} ENameValueSendto; + + +// NameValues can always be "printed" into a buffer of this length. +const U32 NAME_VALUE_BUF_SIZE = 1024; + + +const U32 NAME_VALUE_TYPE_STRING_LENGTH = 8; +const U32 NAME_VALUE_CLASS_STRING_LENGTH = 16; +const U32 NAME_VALUE_SENDTO_STRING_LENGTH = 18; +const U32 NAME_VALUE_DATA_SIZE = + NAME_VALUE_BUF_SIZE - + ( DB_NV_NAME_BUF_SIZE + + NAME_VALUE_TYPE_STRING_LENGTH + + NAME_VALUE_CLASS_STRING_LENGTH + + NAME_VALUE_SENDTO_STRING_LENGTH ); + + +extern char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH]; /* Flawfinder: Ignore */ +extern char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH]; /* Flawfinder: Ignore */ +extern char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH]; /* Flawfinder: Ignore */ + +typedef union u_name_value_reference +{ + char *string; + F32 *f32; + S32 *s32; + LLVector3 *vec3; + U32 *u32; + U64 *u64; +} UNameValueReference; + + +class LLNameValue +{ +public: + void baseInit(); + void init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto ); + + LLNameValue(); + LLNameValue(const char *data); + LLNameValue(const char *name, const char *type, const char *nvclass ); + LLNameValue(const char *name, const char *data, const char *type, const char *nvclass ); + LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto ); + + ~LLNameValue(); + + char *getString(); + const char *getAsset() const; + F32 *getF32(); + S32 *getS32(); + void getVec3(LLVector3 &vec); + LLVector3 *getVec3(); + U32 *getU32(); + U64 *getU64(); + + const char *getType() const { return mStringType; } + const char *getClass() const { return mStringClass; } + const char *getSendto() const { return mStringSendto; } + + bool sendToData() const; + bool sendToViewer() const; + + void callCallback(); + std::string printNameValue() const; + std::string printData() const; + + ENameValueType getTypeEnum() const { return mType; } + ENameValueClass getClassEnum() const { return mClass; } + ENameValueSendto getSendtoEnum() const { return mSendto; } + + LLNameValue &operator=(const LLNameValue &a); + void setString(const char *a); + void setAsset(const char *a); + void setF32(const F32 a); + void setS32(const S32 a); + void setVec3(const LLVector3 &a); + void setU32(const U32 a); + + friend std::ostream& operator<<(std::ostream& s, const LLNameValue &a); + +private: + void printNameValue(std::ostream& s); + +public: + char *mName; + + char *mStringType; + ENameValueType mType; + char *mStringClass; + ENameValueClass mClass; + char *mStringSendto; + ENameValueSendto mSendto; + + UNameValueReference mNameValueReference; + LLStringTable *mNVNameTable; +}; + +extern LLStringTable gNVNameTable; + + +#endif diff --git a/indra/llmessage/llpacketack.cpp b/indra/llmessage/llpacketack.cpp index 19d21bf5d0..e66e8b0285 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 -#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 +#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 c359ec2c0e..0903c01e14 100644 --- a/indra/llmessage/llpacketack.h +++ b/indra/llmessage/llpacketack.h @@ -1,116 +1,116 @@ -/** - * @file llpacketack.h - * @brief Reliable UDP helpers for the message system. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLPACKETACK_H -#define LL_LLPACKETACK_H - -#include "llhost.h" -#include "llunits.h" - -class LLReliablePacketParams -{ -public: - LLHost mHost; - S32 mRetries; - bool mPingBasedRetry; - F32Seconds mTimeout; - void (*mCallback)(void **,S32); - void** mCallbackData; - char* mMessageName; - -public: - LLReliablePacketParams() - { - clear(); - }; - - ~LLReliablePacketParams() { }; - - void clear() - { - mHost.invalidate(); - mRetries = 0; - mPingBasedRetry = true; - mTimeout = F32Seconds(0.f); - mCallback = NULL; - mCallbackData = NULL; - mMessageName = NULL; - }; - - void set( - const LLHost& host, - S32 retries, - bool ping_based_retry, - F32Seconds timeout, - void (*callback)(void**,S32), - void** callback_data, char* name) - { - mHost = host; - mRetries = retries; - mPingBasedRetry = ping_based_retry; - mTimeout = timeout; - mCallback = callback; - mCallbackData = callback_data; - mMessageName = name; - }; -}; - -class LLReliablePacket -{ -public: - LLReliablePacket( - S32 socket, - U8* buf_ptr, - S32 buf_len, - LLReliablePacketParams* params); - ~LLReliablePacket() - { - mCallback = NULL; - delete [] mBuffer; - mBuffer = NULL; - }; - - friend class LLCircuitData; -protected: - S32 mSocket; - LLHost mHost; - S32 mRetries; - bool mPingBasedRetry; - F32Seconds mTimeout; - void (*mCallback)(void**,S32); - void** mCallbackData; - char* mMessageName; - - U8* mBuffer; - S32 mBufferLength; - - TPACKETID mPacketID; - - F64Seconds mExpirationTime; -}; - -#endif - +/** + * @file llpacketack.h + * @brief Reliable UDP helpers for the message system. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPACKETACK_H +#define LL_LLPACKETACK_H + +#include "llhost.h" +#include "llunits.h" + +class LLReliablePacketParams +{ +public: + LLHost mHost; + S32 mRetries; + bool mPingBasedRetry; + F32Seconds mTimeout; + void (*mCallback)(void **,S32); + void** mCallbackData; + char* mMessageName; + +public: + LLReliablePacketParams() + { + clear(); + }; + + ~LLReliablePacketParams() { }; + + void clear() + { + mHost.invalidate(); + mRetries = 0; + mPingBasedRetry = true; + mTimeout = F32Seconds(0.f); + mCallback = NULL; + mCallbackData = NULL; + mMessageName = NULL; + }; + + void set( + const LLHost& host, + S32 retries, + bool ping_based_retry, + F32Seconds timeout, + void (*callback)(void**,S32), + void** callback_data, char* name) + { + mHost = host; + mRetries = retries; + mPingBasedRetry = ping_based_retry; + mTimeout = timeout; + mCallback = callback; + mCallbackData = callback_data; + mMessageName = name; + }; +}; + +class LLReliablePacket +{ +public: + LLReliablePacket( + S32 socket, + U8* buf_ptr, + S32 buf_len, + LLReliablePacketParams* params); + ~LLReliablePacket() + { + mCallback = NULL; + delete [] mBuffer; + mBuffer = NULL; + }; + + friend class LLCircuitData; +protected: + S32 mSocket; + LLHost mHost; + S32 mRetries; + bool mPingBasedRetry; + F32Seconds mTimeout; + void (*mCallback)(void**,S32); + void** mCallbackData; + char* mMessageName; + + U8* mBuffer; + S32 mBufferLength; + + TPACKETID mPacketID; + + F64Seconds mExpirationTime; +}; + +#endif + diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 8f96554939..be838770a8 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 -#else - #include - #include -#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(static_cast(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(static_cast(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(static_cast(&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 +#else + #include + #include +#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(static_cast(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(static_cast(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(static_cast(&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 64f9f937af..f0e95f8524 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 - -#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 mReceiveQueue; - std::queue 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 + +#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 mReceiveQueue; + std::queue 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 afbc74b847..296f4b5464 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 70c425b0a5..49b9e51a3d 100644 --- a/indra/llmessage/llpartdata.h +++ b/indra/llmessage/llpartdata.h @@ -1,279 +1,279 @@ -/** - * @file llpartdata.h - * @brief Particle system data packing - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLPARTDATA_H -#define LL_LLPARTDATA_H - -#include "lluuid.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v2math.h" -#include "v4color.h" - -class LLMessageSystem; -class LLDataPacker; - -const S32 PS_CUR_VERSION = 18; - -// -// These constants are used by the script code, not by the particle system itself -// - -enum LLPSScriptFlags -{ - // Flags for the different parameters of individual particles - LLPS_PART_FLAGS, - LLPS_PART_START_COLOR, - LLPS_PART_START_ALPHA, - LLPS_PART_END_COLOR, - LLPS_PART_END_ALPHA, - LLPS_PART_START_SCALE, - LLPS_PART_END_SCALE, - LLPS_PART_MAX_AGE, - - // Flags for the different parameters of the particle source - LLPS_SRC_ACCEL, - LLPS_SRC_PATTERN, - LLPS_SRC_INNERANGLE, - LLPS_SRC_OUTERANGLE, - LLPS_SRC_TEXTURE, - LLPS_SRC_BURST_RATE, - LLPS_SRC_BURST_DURATION, - LLPS_SRC_BURST_PART_COUNT, - LLPS_SRC_BURST_RADIUS, - LLPS_SRC_BURST_SPEED_MIN, - LLPS_SRC_BURST_SPEED_MAX, - LLPS_SRC_MAX_AGE, - LLPS_SRC_TARGET_UUID, - LLPS_SRC_OMEGA, - LLPS_SRC_ANGLE_BEGIN, - LLPS_SRC_ANGLE_END, - - LLPS_PART_BLEND_FUNC_SOURCE, - LLPS_PART_BLEND_FUNC_DEST, - LLPS_PART_START_GLOW, - LLPS_PART_END_GLOW -}; - - -class LLPartData -{ -public: - LLPartData() : - mFlags(0), - mMaxAge(0.f), - mParameter(0.f) - { - } - bool unpackLegacy(LLDataPacker &dp); - bool unpack(LLDataPacker &dp); - - bool pack(LLDataPacker &dp); - - bool hasGlow() const; - bool hasBlendFunc() const; - - // Masks for the different particle flags - enum - { - LL_PART_INTERP_COLOR_MASK = 0x01, - LL_PART_INTERP_SCALE_MASK = 0x02, - LL_PART_BOUNCE_MASK = 0x04, - LL_PART_WIND_MASK = 0x08, - LL_PART_FOLLOW_SRC_MASK = 0x10, // Follows source, no rotation following (expensive!) - LL_PART_FOLLOW_VELOCITY_MASK = 0x20, // Particles orient themselves with velocity - LL_PART_TARGET_POS_MASK = 0x40, - LL_PART_TARGET_LINEAR_MASK = 0x80, // Particle uses a direct linear interpolation - LL_PART_EMISSIVE_MASK = 0x100, // Particle is "emissive", instead of being lit - LL_PART_BEAM_MASK = 0x200, // Particle is a "beam" connecting source and target - LL_PART_RIBBON_MASK = 0x400, // Particles are joined together into one continuous triangle strip - - // Not implemented yet! - //LL_PART_RANDOM_ACCEL_MASK = 0x100, // Particles have random acceleration - //LL_PART_RANDOM_VEL_MASK = 0x200, // Particles have random velocity shifts" - //LL_PART_TRAIL_MASK = 0x400, // Particles have historical "trails" - - //sYSTEM SET FLAGS - LL_PART_DATA_GLOW = 0x10000, - LL_PART_DATA_BLEND = 0x20000, - - // Viewer side use only! - LL_PART_HUD = 0x40000000, - LL_PART_DEAD_MASK = 0x80000000, - }; - - enum - { - LL_PART_BF_ONE = 0, - LL_PART_BF_ZERO = 1, - LL_PART_BF_DEST_COLOR = 2, - LL_PART_BF_SOURCE_COLOR = 3, - LL_PART_BF_ONE_MINUS_DEST_COLOR = 4, - LL_PART_BF_ONE_MINUS_SOURCE_COLOR = 5, - UNSUPPORTED_DEST_ALPHA = 6, - LL_PART_BF_SOURCE_ALPHA = 7, - UNSUPPORTED_ONE_MINUS_DEST_ALPHA = 8, - LL_PART_BF_ONE_MINUS_SOURCE_ALPHA = 9, - LL_PART_BF_COUNT = 10 - }; - - static bool validBlendFunc(S32 func); - - void setFlags(const U32 flags); - void setMaxAge(const F32 max_age); - void setStartScale(const F32 xs, F32 ys); - void setEndScale(const F32 xs, F32 ys); - void setStartColor(const LLVector3 &rgb); - void setEndColor(const LLVector3 &rgb); - void setStartAlpha(const F32 alpha); - void setEndAlpha(const F32 alpha); - - - friend class LLPartSysData; - friend class LLViewerPartSourceScript; - -private: - S32 getSize() const; - - // These are public because I'm really lazy... -public: - U32 mFlags; // Particle state/interpolators in effect - F32 mMaxAge; // Maximum age of the particle - LLColor4 mStartColor; // Start color - LLColor4 mEndColor; // End color - LLVector2 mStartScale; // Start scale - LLVector2 mEndScale; // End scale - - LLVector3 mPosOffset; // Offset from source if using FOLLOW_SOURCE - F32 mParameter; // A single floating point parameter - - F32 mStartGlow; - F32 mEndGlow; - - U8 mBlendFuncSource; - U8 mBlendFuncDest; -}; - - -class LLPartSysData -{ -public: - LLPartSysData(); - - bool unpack(LLDataPacker &dp); - bool unpackLegacy(LLDataPacker &dp); - bool unpackBlock(const S32 block_num); - - static bool isNullPS(const S32 block_num); // Returns false if this is a "NULL" particle system (i.e. no system) - - bool isLegacyCompatible() const; - - // Different masks for effects on the source - enum - { - LL_PART_SRC_OBJ_REL_MASK = 0x01, // Accel and velocity for particles relative object rotation - LL_PART_USE_NEW_ANGLE = 0x02, // Particles uses new 'correct' angle parameters. - }; - - // The different patterns for how particles are created - enum - { - LL_PART_SRC_PATTERN_DROP = 0x01, - LL_PART_SRC_PATTERN_EXPLODE = 0x02, - // Not implemented fully yet - LL_PART_SRC_PATTERN_ANGLE = 0x04, - LL_PART_SRC_PATTERN_ANGLE_CONE = 0x08, - LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY = 0x10, - }; - - - void setBurstSpeedMin(const F32 spd) { mBurstSpeedMin = llclamp(spd, -100.f, 100.f); } - void setBurstSpeedMax(const F32 spd) { mBurstSpeedMax = llclamp(spd, -100.f, 100.f); } - void setBurstRadius(const F32 rad) { mBurstRadius = llclamp(rad, 0.f, 50.f); } - void setPartAccel(const LLVector3 &accel); - void setUseNewAngle() { mFlags |= LL_PART_USE_NEW_ANGLE; } - void unsetUseNewAngle() { mFlags &= ~LL_PART_USE_NEW_ANGLE; } - - // Since the actual particle creation rate is - // a combination of multiple parameters, we - // need to clamp it using a separate method instead of an accessor. - void clampSourceParticleRate(); - - friend std::ostream& operator<<(std::ostream& s, const LLPartSysData &data); // Stream a - - S32 getdataBlockSize() const; - -private: - bool unpackSystem(LLDataPacker &dp); - -public: - // Public because I'm lazy.... - - // - // There are two kinds of data for the particle system - // 1. Parameters which specify parameters of the source (mSource*) - // 2. Parameters which specify parameters of the particles generated by the source (mPart*) - // - - U32 mCRC; - U32 mFlags; - - U8 mPattern; // Pattern for particle velocity/output - F32 mInnerAngle; // Inner angle for PATTERN_ANGLE - F32 mOuterAngle; // Outer angle for PATTERN_ANGLE - LLVector3 mAngularVelocity; // Angular velocity for emission axis (for PATTERN_ANGLE) - - F32 mBurstRate; // How often to do a burst of particles - U8 mBurstPartCount; // How many particles in a burst - F32 mBurstRadius; - F32 mBurstSpeedMin; // Minimum particle velocity - F32 mBurstSpeedMax; // Maximum particle velocity - - F32 mMaxAge; // Maximum lifetime of this particle source - - LLUUID mTargetUUID; // Target UUID for the particle system - - F32 mStartAge; // Age at which to start the particle system (for an update after the - // particle system has started) - - - // - // These are actually particle properties, but can be mutated by the source, - // so are stored here instead - // - LLVector3 mPartAccel; - LLUUID mPartImageID; - - // - // The "template" partdata where we actually store the non-mutable particle parameters - // - LLPartData mPartData; - -protected: - S32 mNumParticles; // Number of particles generated -}; - -#endif // LL_LLPARTDATA_H +/** + * @file llpartdata.h + * @brief Particle system data packing + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPARTDATA_H +#define LL_LLPARTDATA_H + +#include "lluuid.h" +#include "v3math.h" +#include "v3dmath.h" +#include "v2math.h" +#include "v4color.h" + +class LLMessageSystem; +class LLDataPacker; + +const S32 PS_CUR_VERSION = 18; + +// +// These constants are used by the script code, not by the particle system itself +// + +enum LLPSScriptFlags +{ + // Flags for the different parameters of individual particles + LLPS_PART_FLAGS, + LLPS_PART_START_COLOR, + LLPS_PART_START_ALPHA, + LLPS_PART_END_COLOR, + LLPS_PART_END_ALPHA, + LLPS_PART_START_SCALE, + LLPS_PART_END_SCALE, + LLPS_PART_MAX_AGE, + + // Flags for the different parameters of the particle source + LLPS_SRC_ACCEL, + LLPS_SRC_PATTERN, + LLPS_SRC_INNERANGLE, + LLPS_SRC_OUTERANGLE, + LLPS_SRC_TEXTURE, + LLPS_SRC_BURST_RATE, + LLPS_SRC_BURST_DURATION, + LLPS_SRC_BURST_PART_COUNT, + LLPS_SRC_BURST_RADIUS, + LLPS_SRC_BURST_SPEED_MIN, + LLPS_SRC_BURST_SPEED_MAX, + LLPS_SRC_MAX_AGE, + LLPS_SRC_TARGET_UUID, + LLPS_SRC_OMEGA, + LLPS_SRC_ANGLE_BEGIN, + LLPS_SRC_ANGLE_END, + + LLPS_PART_BLEND_FUNC_SOURCE, + LLPS_PART_BLEND_FUNC_DEST, + LLPS_PART_START_GLOW, + LLPS_PART_END_GLOW +}; + + +class LLPartData +{ +public: + LLPartData() : + mFlags(0), + mMaxAge(0.f), + mParameter(0.f) + { + } + bool unpackLegacy(LLDataPacker &dp); + bool unpack(LLDataPacker &dp); + + bool pack(LLDataPacker &dp); + + bool hasGlow() const; + bool hasBlendFunc() const; + + // Masks for the different particle flags + enum + { + LL_PART_INTERP_COLOR_MASK = 0x01, + LL_PART_INTERP_SCALE_MASK = 0x02, + LL_PART_BOUNCE_MASK = 0x04, + LL_PART_WIND_MASK = 0x08, + LL_PART_FOLLOW_SRC_MASK = 0x10, // Follows source, no rotation following (expensive!) + LL_PART_FOLLOW_VELOCITY_MASK = 0x20, // Particles orient themselves with velocity + LL_PART_TARGET_POS_MASK = 0x40, + LL_PART_TARGET_LINEAR_MASK = 0x80, // Particle uses a direct linear interpolation + LL_PART_EMISSIVE_MASK = 0x100, // Particle is "emissive", instead of being lit + LL_PART_BEAM_MASK = 0x200, // Particle is a "beam" connecting source and target + LL_PART_RIBBON_MASK = 0x400, // Particles are joined together into one continuous triangle strip + + // Not implemented yet! + //LL_PART_RANDOM_ACCEL_MASK = 0x100, // Particles have random acceleration + //LL_PART_RANDOM_VEL_MASK = 0x200, // Particles have random velocity shifts" + //LL_PART_TRAIL_MASK = 0x400, // Particles have historical "trails" + + //sYSTEM SET FLAGS + LL_PART_DATA_GLOW = 0x10000, + LL_PART_DATA_BLEND = 0x20000, + + // Viewer side use only! + LL_PART_HUD = 0x40000000, + LL_PART_DEAD_MASK = 0x80000000, + }; + + enum + { + LL_PART_BF_ONE = 0, + LL_PART_BF_ZERO = 1, + LL_PART_BF_DEST_COLOR = 2, + LL_PART_BF_SOURCE_COLOR = 3, + LL_PART_BF_ONE_MINUS_DEST_COLOR = 4, + LL_PART_BF_ONE_MINUS_SOURCE_COLOR = 5, + UNSUPPORTED_DEST_ALPHA = 6, + LL_PART_BF_SOURCE_ALPHA = 7, + UNSUPPORTED_ONE_MINUS_DEST_ALPHA = 8, + LL_PART_BF_ONE_MINUS_SOURCE_ALPHA = 9, + LL_PART_BF_COUNT = 10 + }; + + static bool validBlendFunc(S32 func); + + void setFlags(const U32 flags); + void setMaxAge(const F32 max_age); + void setStartScale(const F32 xs, F32 ys); + void setEndScale(const F32 xs, F32 ys); + void setStartColor(const LLVector3 &rgb); + void setEndColor(const LLVector3 &rgb); + void setStartAlpha(const F32 alpha); + void setEndAlpha(const F32 alpha); + + + friend class LLPartSysData; + friend class LLViewerPartSourceScript; + +private: + S32 getSize() const; + + // These are public because I'm really lazy... +public: + U32 mFlags; // Particle state/interpolators in effect + F32 mMaxAge; // Maximum age of the particle + LLColor4 mStartColor; // Start color + LLColor4 mEndColor; // End color + LLVector2 mStartScale; // Start scale + LLVector2 mEndScale; // End scale + + LLVector3 mPosOffset; // Offset from source if using FOLLOW_SOURCE + F32 mParameter; // A single floating point parameter + + F32 mStartGlow; + F32 mEndGlow; + + U8 mBlendFuncSource; + U8 mBlendFuncDest; +}; + + +class LLPartSysData +{ +public: + LLPartSysData(); + + bool unpack(LLDataPacker &dp); + bool unpackLegacy(LLDataPacker &dp); + bool unpackBlock(const S32 block_num); + + static bool isNullPS(const S32 block_num); // Returns false if this is a "NULL" particle system (i.e. no system) + + bool isLegacyCompatible() const; + + // Different masks for effects on the source + enum + { + LL_PART_SRC_OBJ_REL_MASK = 0x01, // Accel and velocity for particles relative object rotation + LL_PART_USE_NEW_ANGLE = 0x02, // Particles uses new 'correct' angle parameters. + }; + + // The different patterns for how particles are created + enum + { + LL_PART_SRC_PATTERN_DROP = 0x01, + LL_PART_SRC_PATTERN_EXPLODE = 0x02, + // Not implemented fully yet + LL_PART_SRC_PATTERN_ANGLE = 0x04, + LL_PART_SRC_PATTERN_ANGLE_CONE = 0x08, + LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY = 0x10, + }; + + + void setBurstSpeedMin(const F32 spd) { mBurstSpeedMin = llclamp(spd, -100.f, 100.f); } + void setBurstSpeedMax(const F32 spd) { mBurstSpeedMax = llclamp(spd, -100.f, 100.f); } + void setBurstRadius(const F32 rad) { mBurstRadius = llclamp(rad, 0.f, 50.f); } + void setPartAccel(const LLVector3 &accel); + void setUseNewAngle() { mFlags |= LL_PART_USE_NEW_ANGLE; } + void unsetUseNewAngle() { mFlags &= ~LL_PART_USE_NEW_ANGLE; } + + // Since the actual particle creation rate is + // a combination of multiple parameters, we + // need to clamp it using a separate method instead of an accessor. + void clampSourceParticleRate(); + + friend std::ostream& operator<<(std::ostream& s, const LLPartSysData &data); // Stream a + + S32 getdataBlockSize() const; + +private: + bool unpackSystem(LLDataPacker &dp); + +public: + // Public because I'm lazy.... + + // + // There are two kinds of data for the particle system + // 1. Parameters which specify parameters of the source (mSource*) + // 2. Parameters which specify parameters of the particles generated by the source (mPart*) + // + + U32 mCRC; + U32 mFlags; + + U8 mPattern; // Pattern for particle velocity/output + F32 mInnerAngle; // Inner angle for PATTERN_ANGLE + F32 mOuterAngle; // Outer angle for PATTERN_ANGLE + LLVector3 mAngularVelocity; // Angular velocity for emission axis (for PATTERN_ANGLE) + + F32 mBurstRate; // How often to do a burst of particles + U8 mBurstPartCount; // How many particles in a burst + F32 mBurstRadius; + F32 mBurstSpeedMin; // Minimum particle velocity + F32 mBurstSpeedMax; // Maximum particle velocity + + F32 mMaxAge; // Maximum lifetime of this particle source + + LLUUID mTargetUUID; // Target UUID for the particle system + + F32 mStartAge; // Age at which to start the particle system (for an update after the + // particle system has started) + + + // + // These are actually particle properties, but can be mutated by the source, + // so are stored here instead + // + LLVector3 mPartAccel; + LLUUID mPartImageID; + + // + // The "template" partdata where we actually store the non-mutable particle parameters + // + LLPartData mPartData; + +protected: + S32 mNumParticles; // Number of particles generated +}; + +#endif // LL_LLPARTDATA_H diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index 646f8aa2ca..d3b75cf86b 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 -#include -#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 -#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 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] <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)); - 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(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::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 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(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 +#include +#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 +#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 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] <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)); + 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(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::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 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(mCallbacks)); + mPendingCallbacks.clear(); + } + if(!mCallbacks.empty()) + { + callbacks_t::iterator it = mCallbacks.begin(); + callbacks_t::iterator end = mCallbacks.end(); + for(; it != end; ++it) + { + // it's always the first and last time for respone chains + (*it).mHead = (*it).mChainLinks.begin(); + (*it).mInit = true; + (*it).mEOS = true; + processChain(*it); + } + mCallbacks.clear(); + } +} + +void LLPumpIO::control(LLPumpIO::EControl op) +{ + switch(op) + { + case PAUSE: + mState = PAUSING; + break; + case RESUME: + mState = NORMAL; + break; + default: + // no-op + break; + } +} + +void LLPumpIO::initialize(apr_pool_t* pool) +{ + if(!pool) return; + mPool = pool; +} + +void LLPumpIO::cleanup() +{ + if(mPollset) + { +// LL_DEBUGS() << "cleaning up pollset" << LL_ENDL; + apr_pollset_destroy(mPollset); + mPollset = NULL; + } + if(mCurrentPool) + { + apr_pool_destroy(mCurrentPool); + mCurrentPool = NULL; + } + mPool = NULL; +} + +void LLPumpIO::rebuildPollset() +{ +// LL_DEBUGS() << "LLPumpIO::rebuildPollset()" << LL_ENDL; + if(mPollset) + { + //LL_DEBUGS() << "destroying pollset" << LL_ENDL; + apr_pollset_destroy(mPollset); + mPollset = NULL; + } + U32 size = 0; + running_chains_t::iterator run_it = mRunningChains.begin(); + running_chains_t::iterator run_end = mRunningChains.end(); + for(; run_it != run_end; ++run_it) + { + size += (*run_it).mDescriptors.size(); + } + //LL_DEBUGS() << "found " << size << " descriptors." << LL_ENDL; + if(size) + { + // Recycle the memory pool + const S32 POLLSET_POOL_RECYCLE_COUNT = 100; + if(mCurrentPool + && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT))) + { + apr_pool_destroy(mCurrentPool); + mCurrentPool = NULL; + mCurrentPoolReallocCount = 0; + } + if(!mCurrentPool) + { + apr_status_t status = apr_pool_create(&mCurrentPool, mPool); + (void)ll_apr_warn_status(status); + } + + // add all of the file descriptors + run_it = mRunningChains.begin(); + LLChainInfo::conditionals_t::iterator fd_it; + LLChainInfo::conditionals_t::iterator fd_end; + apr_pollset_create(&mPollset, size, mCurrentPool, 0); + for(; run_it != run_end; ++run_it) + { + fd_it = (*run_it).mDescriptors.begin(); + fd_end = (*run_it).mDescriptors.end(); + for(; fd_it != fd_end; ++fd_it) + { + apr_pollset_add(mPollset, &((*fd_it).second)); + } + } + } +} + +void LLPumpIO::processChain(LLChainInfo& chain) +{ + PUMP_DEBUG; + LLIOPipe::EStatus status = LLIOPipe::STATUS_OK; + links_t::iterator it = chain.mHead; + links_t::iterator end = chain.mChainLinks.end(); + bool need_process_signaled = false; + bool keep_going = true; + do + { +#if LL_DEBUG_PROCESS_LINK +#if LL_DEBUG_PIPE_TYPE_IN_PUMP + LL_INFOS() << "Processing " << typeid(*((*it).mPipe)).name() << "." + << LL_ENDL; +#else + LL_INFOS() << "Processing link " << (*it).mPipe << "." << LL_ENDL; +#endif +#endif +#if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN + if(chain.mData) + { + char* buf = NULL; + S32 bytes = chain.mData->countAfter((*it).mChannels.in(), NULL); + if(bytes) + { + buf = new char[bytes + 1]; + chain.mData->readAfter( + (*it).mChannels.in(), + NULL, + (U8*)buf, + bytes); + buf[bytes] = '\0'; + LL_INFOS() << "CHANNEL IN(" << (*it).mChannels.in() << "): " + << buf << LL_ENDL; + delete[] buf; + buf = NULL; + } + else + { + LL_INFOS() << "CHANNEL IN(" << (*it).mChannels.in()<< "): (null)" + << LL_ENDL; + } + } +#endif + PUMP_DEBUG; + status = (*it).mPipe->process( + (*it).mChannels, + chain.mData, + chain.mEOS, + chain.mContext, + this); +#if LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT + if(chain.mData) + { + char* buf = NULL; + S32 bytes = chain.mData->countAfter((*it).mChannels.out(), NULL); + if(bytes) + { + buf = new char[bytes + 1]; + chain.mData->readAfter( + (*it).mChannels.out(), + NULL, + (U8*)buf, + bytes); + buf[bytes] = '\0'; + LL_INFOS() << "CHANNEL OUT(" << (*it).mChannels.out()<< "): " + << buf << LL_ENDL; + delete[] buf; + buf = NULL; + } + else + { + LL_INFOS() << "CHANNEL OUT(" << (*it).mChannels.out()<< "): (null)" + << LL_ENDL; + } + } +#endif + +#if LL_DEBUG_PROCESS_RETURN_VALUE + // Only bother with the success codes - error codes are logged + // below. + if(LLIOPipe::isSuccess(status)) + { + LL_INFOS() << "Pipe returned: '" +#if LL_DEBUG_PIPE_TYPE_IN_PUMP + << typeid(*((*it).mPipe)).name() << "':'" +#endif + << LLIOPipe::lookupStatusString(status) << "'" << LL_ENDL; + } +#endif + + PUMP_DEBUG; + switch(status) + { + case LLIOPipe::STATUS_OK: + // no-op + break; + case LLIOPipe::STATUS_STOP: + PUMP_DEBUG; + status = LLIOPipe::STATUS_OK; + chain.mHead = end; + keep_going = false; + break; + case LLIOPipe::STATUS_DONE: + PUMP_DEBUG; + status = LLIOPipe::STATUS_OK; + chain.mHead = (it + 1); + chain.mEOS = true; + break; + case LLIOPipe::STATUS_BREAK: + PUMP_DEBUG; + status = LLIOPipe::STATUS_OK; + keep_going = false; + break; + case LLIOPipe::STATUS_NEED_PROCESS: + PUMP_DEBUG; + status = LLIOPipe::STATUS_OK; + if(!need_process_signaled) + { + need_process_signaled = true; + chain.mHead = it; + } + break; + default: + PUMP_DEBUG; + if(LLIOPipe::isError(status)) + { + LL_INFOS() << "Pump generated pipe err: '" +#if LL_DEBUG_PIPE_TYPE_IN_PUMP + << typeid(*((*it).mPipe)).name() << "':'" +#endif + << LLIOPipe::lookupStatusString(status) + << "'" << LL_ENDL; +#if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN_ON_ERROR + if(chain.mData) + { + char* buf = NULL; + S32 bytes = chain.mData->countAfter( + (*it).mChannels.in(), + NULL); + if(bytes) + { + buf = new char[bytes + 1]; + chain.mData->readAfter( + (*it).mChannels.in(), + NULL, + (U8*)buf, + bytes); + buf[bytes] = '\0'; + LL_INFOS() << "Input After Error: " << buf << LL_ENDL; + delete[] buf; + buf = NULL; + } + else + { + LL_INFOS() << "Input After Error: (null)" << LL_ENDL; + } + } + else + { + LL_INFOS() << "Input After Error: (null)" << LL_ENDL; + } +#endif + keep_going = false; + chain.mHead = it; + if(!handleChainError(chain, status)) + { + chain.mHead = end; + } + } + else + { + LL_INFOS() << "Unhandled status code: " << status << ":" + << LLIOPipe::lookupStatusString(status) << LL_ENDL; + } + break; + } + PUMP_DEBUG; + } while(keep_going && (++it != end)); + PUMP_DEBUG; +} + +bool LLPumpIO::isChainExpired(LLChainInfo& chain) +{ + if(!chain.mHasCurlRequest) + { + return false ; + } + + for(links_t::iterator iter = chain.mChainLinks.begin(); iter != chain.mChainLinks.end(); ++iter) + { + if(!(*iter).mPipe->isValid()) + { + return true ; + } + } + + return false ; +} + +bool LLPumpIO::handleChainError( + LLChainInfo& chain, + LLIOPipe::EStatus error) +{ + links_t::reverse_iterator rit; + if(chain.mHead == chain.mChainLinks.end()) + { + rit = links_t::reverse_iterator(chain.mHead); + } + else + { + rit = links_t::reverse_iterator(chain.mHead + 1); + } + + links_t::reverse_iterator rend = chain.mChainLinks.rend(); + bool handled = false; + bool keep_going = true; + do + { +#if LL_DEBUG_PIPE_TYPE_IN_PUMP + LL_DEBUGS() << "Passing error to " << typeid(*((*rit).mPipe)).name() + << "." << LL_ENDL; +#endif + error = (*rit).mPipe->handleError(error, this); + switch(error) + { + case LLIOPipe::STATUS_OK: + handled = true; + chain.mHead = rit.base(); + break; + case LLIOPipe::STATUS_STOP: + case LLIOPipe::STATUS_DONE: + case LLIOPipe::STATUS_BREAK: + case LLIOPipe::STATUS_NEED_PROCESS: +#if LL_DEBUG_PIPE_TYPE_IN_PUMP + LL_DEBUGS() << "Pipe " << typeid(*((*rit).mPipe)).name() + << " returned code to stop error handler." << LL_ENDL; +#endif + keep_going = false; + break; + case LLIOPipe::STATUS_EXPIRED: + keep_going = false; + break ; + default: + if(LLIOPipe::isSuccess(error)) + { + LL_INFOS() << "Unhandled status code: " << error << ":" + << LLIOPipe::lookupStatusString(error) << LL_ENDL; + error = LLIOPipe::STATUS_ERROR; + keep_going = false; + } + break; + } + } while(keep_going && !handled && (++rit != rend)); + return handled; +} + +/** + * LLPumpIO::LLChainInfo + */ + +LLPumpIO::LLChainInfo::LLChainInfo() : + mInit(false), + mLock(0), + mEOS(false), + mHasCurlRequest(false) +{ + mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS); +} + +void LLPumpIO::LLChainInfo::setTimeoutSeconds(F32 timeout) +{ + if(timeout > 0.0f) + { + mTimer.start(); + mTimer.reset(); + mTimer.setTimerExpirySec(timeout); + } + else + { + mTimer.stop(); + } +} + +void LLPumpIO::LLChainInfo::adjustTimeoutSeconds(F32 delta) +{ + if(mTimer.getStarted()) + { + F64 expiry = mTimer.expiresAt(); + expiry += delta; + mTimer.setExpiryAt(expiry); + } +} diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 835bccfb14..4f23c4d160 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 f732cdcce5..d68cd4d202 100644 --- a/indra/llmessage/llregionhandle.h +++ b/indra/llmessage/llregionhandle.h @@ -1,126 +1,126 @@ -/** - * @file llregionhandle.h - * @brief Routines for converting positions to/from region handles. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLREGIONHANDLE_H -#define LL_LLREGIONHANDLE_H - -#include "indra_constants.h" -#include "v3math.h" -#include "v3dmath.h" - -inline U64 to_region_handle(const U32 x_origin, const U32 y_origin) -{ - U64 region_handle; - region_handle = ((U64)x_origin) << 32; - region_handle |= (U64) y_origin; - return region_handle; -} - -inline U64 to_region_handle(const LLVector3d& pos_global) -{ - U32 global_x = (U32)pos_global.mdV[VX]; - global_x -= global_x % 256; - - U32 global_y = (U32)pos_global.mdV[VY]; - global_y -= global_y % 256; - - return to_region_handle(global_x, global_y); -} - -inline U64 to_region_handle_global(const F32 x_global, const F32 y_global) -{ - // Round down to the nearest origin - U32 x_origin = (U32)x_global; - x_origin -= x_origin % REGION_WIDTH_U32; - U32 y_origin = (U32)y_global; - y_origin -= y_origin % REGION_WIDTH_U32; - U64 region_handle; - region_handle = ((U64)x_origin) << 32; - region_handle |= (U64) y_origin; - return region_handle; -} - -inline bool to_region_handle(const F32 x_pos, const F32 y_pos, U64 *region_handle) -{ - U32 x_int, y_int; - if (x_pos < 0.f) - { -// LL_WARNS() << "to_region_handle:Clamping negative x position " << x_pos << " to zero!" << LL_ENDL; - return false; - } - else - { - x_int = (U32)ll_round(x_pos); - } - if (y_pos < 0.f) - { -// LL_WARNS() << "to_region_handle:Clamping negative y position " << y_pos << " to zero!" << LL_ENDL; - return false; - } - else - { - y_int = (U32)ll_round(y_pos); - } - *region_handle = to_region_handle(x_int, y_int); - return true; -} - -// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos -inline void from_region_handle(const U64 ®ion_handle, F32 *x_pos, F32 *y_pos) -{ - *x_pos = (F32)((U32)(region_handle >> 32)); - *y_pos = (F32)((U32)(region_handle & 0xFFFFFFFF)); -} - -// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos -inline void from_region_handle(const U64 ®ion_handle, U32 *x_pos, U32 *y_pos) -{ - *x_pos = ((U32)(region_handle >> 32)); - *y_pos = ((U32)(region_handle & 0xFFFFFFFF)); -} - -// return the word-frame XY location of sim's SouthWest corner in LLVector3d -inline LLVector3d from_region_handle(const U64 ®ion_handle) -{ - return LLVector3d(((U32)(region_handle >> 32)), (U32)(region_handle & 0xFFFFFFFF), 0.f); -} - -// grid-based region handle encoding. pass in a grid position -// (eg: 1000,1000) and this will return the region handle. -inline U64 grid_to_region_handle(const U32 grid_x, const U32 grid_y) -{ - return to_region_handle(grid_x * REGION_WIDTH_UNITS, - grid_y * REGION_WIDTH_UNITS); -} - -inline void grid_from_region_handle(const U64& region_handle, U32* grid_x, U32* grid_y) -{ - from_region_handle(region_handle, grid_x, grid_y); - *grid_x /= REGION_WIDTH_UNITS; - *grid_y /= REGION_WIDTH_UNITS; -} - -#endif +/** + * @file llregionhandle.h + * @brief Routines for converting positions to/from region handles. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLREGIONHANDLE_H +#define LL_LLREGIONHANDLE_H + +#include "indra_constants.h" +#include "v3math.h" +#include "v3dmath.h" + +inline U64 to_region_handle(const U32 x_origin, const U32 y_origin) +{ + U64 region_handle; + region_handle = ((U64)x_origin) << 32; + region_handle |= (U64) y_origin; + return region_handle; +} + +inline U64 to_region_handle(const LLVector3d& pos_global) +{ + U32 global_x = (U32)pos_global.mdV[VX]; + global_x -= global_x % 256; + + U32 global_y = (U32)pos_global.mdV[VY]; + global_y -= global_y % 256; + + return to_region_handle(global_x, global_y); +} + +inline U64 to_region_handle_global(const F32 x_global, const F32 y_global) +{ + // Round down to the nearest origin + U32 x_origin = (U32)x_global; + x_origin -= x_origin % REGION_WIDTH_U32; + U32 y_origin = (U32)y_global; + y_origin -= y_origin % REGION_WIDTH_U32; + U64 region_handle; + region_handle = ((U64)x_origin) << 32; + region_handle |= (U64) y_origin; + return region_handle; +} + +inline bool to_region_handle(const F32 x_pos, const F32 y_pos, U64 *region_handle) +{ + U32 x_int, y_int; + if (x_pos < 0.f) + { +// LL_WARNS() << "to_region_handle:Clamping negative x position " << x_pos << " to zero!" << LL_ENDL; + return false; + } + else + { + x_int = (U32)ll_round(x_pos); + } + if (y_pos < 0.f) + { +// LL_WARNS() << "to_region_handle:Clamping negative y position " << y_pos << " to zero!" << LL_ENDL; + return false; + } + else + { + y_int = (U32)ll_round(y_pos); + } + *region_handle = to_region_handle(x_int, y_int); + return true; +} + +// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos +inline void from_region_handle(const U64 ®ion_handle, F32 *x_pos, F32 *y_pos) +{ + *x_pos = (F32)((U32)(region_handle >> 32)); + *y_pos = (F32)((U32)(region_handle & 0xFFFFFFFF)); +} + +// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos +inline void from_region_handle(const U64 ®ion_handle, U32 *x_pos, U32 *y_pos) +{ + *x_pos = ((U32)(region_handle >> 32)); + *y_pos = ((U32)(region_handle & 0xFFFFFFFF)); +} + +// return the word-frame XY location of sim's SouthWest corner in LLVector3d +inline LLVector3d from_region_handle(const U64 ®ion_handle) +{ + return LLVector3d(((U32)(region_handle >> 32)), (U32)(region_handle & 0xFFFFFFFF), 0.f); +} + +// grid-based region handle encoding. pass in a grid position +// (eg: 1000,1000) and this will return the region handle. +inline U64 grid_to_region_handle(const U32 grid_x, const U32 grid_y) +{ + return to_region_handle(grid_x * REGION_WIDTH_UNITS, + grid_y * REGION_WIDTH_UNITS); +} + +inline void grid_from_region_handle(const U64& region_handle, U32* grid_x, U32* grid_y) +{ + from_region_handle(region_handle, grid_x, grid_y); + *grid_x /= REGION_WIDTH_UNITS; + *grid_y /= REGION_WIDTH_UNITS; +} + +#endif diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp index 3f4553fcee..8d7d51e13f 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 v; - v.resize(size); - memcpy(&(v[0]), reinterpret_cast(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 v; + v.resize(size); + memcpy(&(v[0]), reinterpret_cast(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 8eac962ba0..72ea6d0dd6 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 - -#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 + +#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 c0e8f634b2..8be6158d82 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 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 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 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 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 510730c115..6f4256380b 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 - -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 + +class LLMessageTemplate; +class LLMsgData; + +class LLSDMessageReader : public LLMessageReader +{ +public: + + LLSDMessageReader(); + virtual ~LLSDMessageReader(); + + /** All get* methods expect pointers to canonical strings. */ + virtual void getBinaryData(const char *block, const char *var, + void *datap, S32 size, S32 blocknum = 0, + S32 max_size = S32_MAX); + virtual void getBOOL(const char *block, const char *var, bool &data, + S32 blocknum = 0); + virtual void getS8(const char *block, const char *var, S8 &data, + S32 blocknum = 0); + virtual void getU8(const char *block, const char *var, U8 &data, + S32 blocknum = 0); + virtual void getS16(const char *block, const char *var, S16 &data, + S32 blocknum = 0); + virtual void getU16(const char *block, const char *var, U16 &data, + S32 blocknum = 0); + virtual void getS32(const char *block, const char *var, S32 &data, + S32 blocknum = 0); + virtual void getF32(const char *block, const char *var, F32 &data, + S32 blocknum = 0); + virtual void getU32(const char *block, const char *var, U32 &data, + S32 blocknum = 0); + virtual void getU64(const char *block, const char *var, U64 &data, + S32 blocknum = 0); + virtual void getF64(const char *block, const char *var, F64 &data, + S32 blocknum = 0); + virtual void getVector3(const char *block, const char *var, + LLVector3 &vec, S32 blocknum = 0); + virtual void getVector4(const char *block, const char *var, + LLVector4 &vec, S32 blocknum = 0); + virtual void getVector3d(const char *block, const char *var, + LLVector3d &vec, S32 blocknum = 0); + virtual void getQuat(const char *block, const char *var, LLQuaternion &q, + S32 blocknum = 0); + virtual void getUUID(const char *block, const char *var, LLUUID &uuid, + S32 blocknum = 0); + virtual void getIPAddr(const char *block, const char *var, U32 &ip, + S32 blocknum = 0); + virtual void getIPPort(const char *block, const char *var, U16 &port, + S32 blocknum = 0); + virtual void getString(const char *block, const char *var, + S32 buffer_size, char *buffer, S32 blocknum = 0); + virtual void getString(const char *block, const char *var, std::string& outstr, + S32 blocknum = 0); + + virtual S32 getNumberOfBlocks(const char *blockname); + virtual S32 getSize(const char *blockname, const char *varname); + virtual S32 getSize(const char *blockname, S32 blocknum, + const char *varname); + + virtual void clearMessage(); + + virtual const char* getMessageName() const; + virtual S32 getMessageSize() const; + + virtual void copyToBuilder(LLMessageBuilder&) const; + + /** Expects a pointer to a canonical name string */ + void setMessage(const char* name, const LLSD& msg); + +private: + const char* mMessageName; // Canonical (prehashed) string. + LLSD mMessage; +}; + +#endif // LL_LLSDMESSAGEREADER_H diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index 57ffba9705..758d6d343f 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 bb50b0ab8a..b86ec4d87d 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 - -#include "llmessagebuilder.h" -#include "llmsgvariabletype.h" - -class LLMsgData; -class LLMessageTemplate; -class LLMsgBlkData; -class LLMessageTemplate; - -class LLTemplateMessageBuilder : public LLMessageBuilder -{ -public: - - typedef std::map 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 + +#include "llmessagebuilder.h" +#include "llmsgvariabletype.h" + +class LLMsgData; +class LLMessageTemplate; +class LLMsgBlkData; +class LLMessageTemplate; + +class LLTemplateMessageBuilder : public LLMessageBuilder +{ +public: + + typedef std::map message_template_name_map_t; + + LLTemplateMessageBuilder(const message_template_name_map_t&); + virtual ~LLTemplateMessageBuilder(); + + virtual void newMessage(const char* name); + + virtual void nextBlock(const char* blockname); + virtual bool removeLastBlock(); // TODO: babbage: remove this horror... + + /** All add* methods expect pointers to canonical varname strings. */ + virtual void addBinaryData(const char *varname, const void *data, + S32 size); + virtual void addBOOL(const char* varname, bool b); + virtual void addS8(const char* varname, S8 s); + virtual void addU8(const char* varname, U8 u); + virtual void addS16(const char* varname, S16 i); + virtual void addU16(const char* varname, U16 i); + virtual void addF32(const char* varname, F32 f); + virtual void addS32(const char* varname, S32 s); + virtual void addU32(const char* varname, U32 u); + virtual void addU64(const char* varname, U64 lu); + virtual void addF64(const char* varname, F64 d); + virtual void addVector3(const char* varname, const LLVector3& vec); + virtual void addVector4(const char* varname, const LLVector4& vec); + virtual void addVector3d(const char* varname, const LLVector3d& vec); + virtual void addQuat(const char* varname, const LLQuaternion& quat); + virtual void addUUID(const char* varname, const LLUUID& uuid); + virtual void addIPAddr(const char* varname, const U32 ip); + virtual void addIPPort(const char* varname, const U16 port); + virtual void addString(const char* varname, const char* s); + virtual void addString(const char* varname, const std::string& s); + + virtual bool isMessageFull(const char* blockname) const; + virtual void compressMessage(U8*& buf_ptr, U32& buffer_length); + + virtual bool isBuilt() const; + virtual bool isClear() const; + virtual U32 buildMessage(U8* buffer, U32 buffer_size, U8 offset_to_data); + /**< Return built message size */ + + virtual void clearMessage(); + + // TODO: babbage: remove this horror. + virtual void setBuilt(bool b); + + virtual S32 getMessageSize(); + virtual const char* getMessageName() const; + + virtual void copyFromMessageData(const LLMsgData& data); + virtual void copyFromLLSD(const LLSD&); + + LLMsgData* getCurrentMessage() const { return mCurrentSMessageData; } +private: + void addData(const char* varname, const void* data, + EMsgVariableType type, S32 size); + + void addData(const char* varname, const void* data, + EMsgVariableType type); + + LLMsgData* mCurrentSMessageData; + const LLMessageTemplate* mCurrentSMessageTemplate; + LLMsgBlkData* mCurrentSDataBlock; + char* mCurrentSMessageName; + char* mCurrentSBlockName; + bool mbSBuilt; + bool mbSClear; + S32 mCurrentSendTotal; + const message_template_name_map_t& mMessageTemplates; +}; + +#endif // LL_LLTEMPLATEMESSAGEBUILDER_H diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 46123f0f55..b62288590e 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 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 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 0b06f6d23a..6f1977cf83 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 - -class LLMessageTemplate; -class LLMsgData; - -class LLTemplateMessageReader : public LLMessageReader -{ -public: - - typedef std::map 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 + +class LLMessageTemplate; +class LLMsgData; + +class LLTemplateMessageReader : public LLMessageReader +{ +public: + + typedef std::map 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 a3f02204d0..5ce96fc551 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 be497d9371..b8a8c9f1f7 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 f5351c6b58..72d623ea42 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::pqm_iter iter = - mTransferSources.mMap.begin(); - LLPriQueueMap::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::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::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::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::pqm_iter iter = + mTransferSources.mMap.begin(); + LLPriQueueMap::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::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::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::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 184ff2563a..ada5528b49 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 -#include - -#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 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::iterator tsc_iter; - typedef std::list::iterator ttc_iter; - friend class LLTransferManager; -protected: - - LLHost mHost; - std::list mTransferSourceChannels; - std::list 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::iterator ts_iter; - - LLTransferChannelType mChannelType; - LLHost mHost; - LLPriQueueMap 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::iterator tt_iter; - - LLTransferChannelType mChannelType; - LLHost mHost; - std::list 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 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 transfer_packet_map; - typedef std::map::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 +#include + +#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 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::iterator tsc_iter; + typedef std::list::iterator ttc_iter; + friend class LLTransferManager; +protected: + + LLHost mHost; + std::list mTransferSourceChannels; + std::list 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::iterator ts_iter; + + LLTransferChannelType mChannelType; + LLHost mHost; + LLPriQueueMap 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::iterator tt_iter; + + LLTransferChannelType mChannelType; + LLHost mHost; + std::list 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 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 transfer_packet_map; + typedef std::map::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 f09855aacd..082f12b8bf 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 50755d65ad..6c4c39011a 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 97d5716ca4..77a6c466c7 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 3b9cd7231c..a447ab091b 100644 --- a/indra/llmessage/lltransfersourcefile.h +++ b/indra/llmessage/lltransfersourcefile.h @@ -1,75 +1,75 @@ -/** - * @file lltransfersourcefile.h - * @brief Transfer system for sending a file. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLTRANSFERSOURCEFILE_H -#define LL_LLTRANSFERSOURCEFILE_H - -#include "lltransfermanager.h" - -class LLTransferSourceParamsFile : public LLTransferSourceParams -{ -public: - LLTransferSourceParamsFile(); - virtual ~LLTransferSourceParamsFile() {} - /*virtual*/ void packParams(LLDataPacker &dp) const; - /*virtual*/ bool unpackParams(LLDataPacker &dp); - - void setFilename(const std::string &filename) { mFilename = filename; } - std::string getFilename() const { return mFilename; } - - void setDeleteOnCompletion(bool enabled) { mDeleteOnCompletion = enabled; } - bool getDeleteOnCompletion() { return mDeleteOnCompletion; } -protected: - std::string mFilename; - // ONLY DELETE THINGS OFF THE SIM IF THE FILENAME BEGINS IN 'TEMP' - bool mDeleteOnCompletion; -}; - -class LLTransferSourceFile : public LLTransferSource -{ -public: - LLTransferSourceFile(const LLUUID &transfer_id, const F32 priority); - virtual ~LLTransferSourceFile(); - -protected: - /*virtual*/ void initTransfer(); - /*virtual*/ F32 updatePriority(); - /*virtual*/ LLTSCode dataCallback(const S32 packet_id, - const S32 max_bytes, - U8 **datap, - S32 &returned_bytes, - bool &delete_returned); - /*virtual*/ void completionCallback(const LLTSCode status); - - virtual void packParams(LLDataPacker& dp) const; - /*virtual*/ bool unpackParams(LLDataPacker &dp); - -protected: - LLTransferSourceParamsFile mParams; - LLFILE *mFP; -}; - -#endif // LL_LLTRANSFERSOURCEFILE_H +/** + * @file lltransfersourcefile.h + * @brief Transfer system for sending a file. + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRANSFERSOURCEFILE_H +#define LL_LLTRANSFERSOURCEFILE_H + +#include "lltransfermanager.h" + +class LLTransferSourceParamsFile : public LLTransferSourceParams +{ +public: + LLTransferSourceParamsFile(); + virtual ~LLTransferSourceParamsFile() {} + /*virtual*/ void packParams(LLDataPacker &dp) const; + /*virtual*/ bool unpackParams(LLDataPacker &dp); + + void setFilename(const std::string &filename) { mFilename = filename; } + std::string getFilename() const { return mFilename; } + + void setDeleteOnCompletion(bool enabled) { mDeleteOnCompletion = enabled; } + bool getDeleteOnCompletion() { return mDeleteOnCompletion; } +protected: + std::string mFilename; + // ONLY DELETE THINGS OFF THE SIM IF THE FILENAME BEGINS IN 'TEMP' + bool mDeleteOnCompletion; +}; + +class LLTransferSourceFile : public LLTransferSource +{ +public: + LLTransferSourceFile(const LLUUID &transfer_id, const F32 priority); + virtual ~LLTransferSourceFile(); + +protected: + /*virtual*/ void initTransfer(); + /*virtual*/ F32 updatePriority(); + /*virtual*/ LLTSCode dataCallback(const S32 packet_id, + const S32 max_bytes, + U8 **datap, + S32 &returned_bytes, + bool &delete_returned); + /*virtual*/ void completionCallback(const LLTSCode status); + + virtual void packParams(LLDataPacker& dp) const; + /*virtual*/ bool unpackParams(LLDataPacker &dp); + +protected: + LLTransferSourceParamsFile mParams; + LLFILE *mFP; +}; + +#endif // LL_LLTRANSFERSOURCEFILE_H diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp index dbf377bfa2..fcf853845b 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 e1d48ce73d..4a78c3c522 100644 --- a/indra/llmessage/lltransfertargetvfile.h +++ b/indra/llmessage/lltransfertargetvfile.h @@ -1,93 +1,93 @@ -/** - * @file lltransfertargetvfile.h - * @brief Transfer system for receiving a vfile. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLTRANSFERTARGETVFILE_H -#define LL_LLTRANSFERTARGETVFILE_H - -#include "lltransfermanager.h" -#include "llassetstorage.h" -#include "llfilesystem.h" - -class LLFileSystem; - -// Lame, an S32 for now until I figure out the deal with how we want to do -// error codes. -typedef void (*LLTTVFCompleteCallback)( - S32 status, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, LLExtStat ext_status ); - -class LLTransferTargetParamsVFile : public LLTransferTargetParams -{ -public: - LLTransferTargetParamsVFile(); - - void setAsset(const LLUUID& asset_id, LLAssetType::EType asset_type); - void setCallback(LLTTVFCompleteCallback cb, LLBaseDownloadRequest& request); - - LLUUID getAssetID() const { return mAssetID; } - LLAssetType::EType getAssetType() const { return mAssetType; } - - friend class LLTransferTargetVFile; -protected: - bool unpackParams(LLDataPacker& dp); - - LLUUID mAssetID; - LLAssetType::EType mAssetType; - - LLTTVFCompleteCallback mCompleteCallback; - LLBaseDownloadRequest* mRequestDatap; - S32 mErrCode; -}; - - -class LLTransferTargetVFile : public LLTransferTarget -{ -public: - LLTransferTargetVFile(const LLUUID& uuid, LLTransferSourceType src_type); - virtual ~LLTransferTargetVFile(); - - //static void requestTransfer(LLTransferTargetChannel* channelp, - // const char* local_filename, - // const LLTransferSourceParams& source_params, - // LLTTVFCompleteCallback callback); - - static void updateQueue(bool shutdown = false); - -protected: - virtual bool unpackParams(LLDataPacker& dp); - /*virtual*/ void applyParams(const LLTransferTargetParams& params); - /*virtual*/ LLTSCode dataCallback(const S32 packet_id, U8* in_datap, const S32 in_size); - /*virtual*/ void completionCallback(const LLTSCode status); - - LLTransferTargetParamsVFile mParams; - - bool mNeedsCreate; - LLUUID mTempID; -}; - -#endif // LL_LLTRANSFERTARGETFILE_H +/** + * @file lltransfertargetvfile.h + * @brief Transfer system for receiving a vfile. + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRANSFERTARGETVFILE_H +#define LL_LLTRANSFERTARGETVFILE_H + +#include "lltransfermanager.h" +#include "llassetstorage.h" +#include "llfilesystem.h" + +class LLFileSystem; + +// Lame, an S32 for now until I figure out the deal with how we want to do +// error codes. +typedef void (*LLTTVFCompleteCallback)( + S32 status, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, LLExtStat ext_status ); + +class LLTransferTargetParamsVFile : public LLTransferTargetParams +{ +public: + LLTransferTargetParamsVFile(); + + void setAsset(const LLUUID& asset_id, LLAssetType::EType asset_type); + void setCallback(LLTTVFCompleteCallback cb, LLBaseDownloadRequest& request); + + LLUUID getAssetID() const { return mAssetID; } + LLAssetType::EType getAssetType() const { return mAssetType; } + + friend class LLTransferTargetVFile; +protected: + bool unpackParams(LLDataPacker& dp); + + LLUUID mAssetID; + LLAssetType::EType mAssetType; + + LLTTVFCompleteCallback mCompleteCallback; + LLBaseDownloadRequest* mRequestDatap; + S32 mErrCode; +}; + + +class LLTransferTargetVFile : public LLTransferTarget +{ +public: + LLTransferTargetVFile(const LLUUID& uuid, LLTransferSourceType src_type); + virtual ~LLTransferTargetVFile(); + + //static void requestTransfer(LLTransferTargetChannel* channelp, + // const char* local_filename, + // const LLTransferSourceParams& source_params, + // LLTTVFCompleteCallback callback); + + static void updateQueue(bool shutdown = false); + +protected: + virtual bool unpackParams(LLDataPacker& dp); + /*virtual*/ void applyParams(const LLTransferTargetParams& params); + /*virtual*/ LLTSCode dataCallback(const S32 packet_id, U8* in_datap, const S32 in_size); + /*virtual*/ void completionCallback(const LLTSCode status); + + LLTransferTargetParamsVFile mParams; + + bool mNeedsCreate; + LLUUID mTempID; +}; + +#endif // LL_LLTRANSFERTARGETFILE_H diff --git a/indra/llmessage/lluseroperation.cpp b/indra/llmessage/lluseroperation.cpp index f7897f9754..36ab87086d 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 384978571c..c3ac2e350c 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 - -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 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 + +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 user_operation_list_t; + user_operation_list_t mUserOperationList; + LLUUID mLastOperationConsidered; +}; + +extern LLUserOperationMgr* gUserOperationMgr; + +#endif // LL_LLUSEROPERATION_H diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index 057f4de0ab..358c8be671 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 22cf05ba5a..9a0901a84a 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 a9450f725b..ad15d5969b 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 -#include -#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 +#include +#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 baf57753ae..f30ef3eed6 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 825bff3820..b619974270 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 49c3e8d20d..4e87b0ca5a 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 c37ee1ca2d..4f31973f3d 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 33fb63f68c..f62da815f8 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 d4d12b8ff2..f6ed43a4e4 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& files, - const std::string& filename) -{ - std::multiset::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 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::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& files, + const std::string& filename) +{ + std::multiset::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 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::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 ce412ddd26..3be5f5a228 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 -#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 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 xfer_list_t; - xfer_list_t mSendList; - xfer_list_t mReceiveList; - - typedef std::list 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 mExpectedTransfers; // files that are authorized to transfer out - std::multiset mExpectedRequests; // files that are authorized to be downloaded on top of - std::multiset mExpectedVFileTransfers; // files that are authorized to transfer out - std::multiset 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 +#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 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 xfer_list_t; + xfer_list_t mSendList; + xfer_list_t mReceiveList; + + typedef std::list 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 mExpectedTransfers; // files that are authorized to transfer out + std::multiset mExpectedRequests; // files that are authorized to be downloaded on top of + std::multiset mExpectedVFileTransfers; // files that are authorized to transfer out + std::multiset 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 2770200fe5..8db4fca629 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 14cea5dc02..50ea997b4d 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.h b/indra/llmessage/machine.h index 67e890d19a..05d366cbc3 100644 --- a/indra/llmessage/machine.h +++ b/indra/llmessage/machine.h @@ -1,95 +1,95 @@ -/** - * @file machine.h - * @brief LLMachine class header file - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_MACHINE_H -#define LL_MACHINE_H - -#include "net.h" -#include "llhost.h" - -typedef enum e_machine_type -{ - MT_NULL, - MT_SIMULATOR, - MT_VIEWER, - MT_SPACE_SERVER, - MT_OBJECT_REPOSITORY, - MT_PROXY, - MT_EOF -} EMachineType; - -const U32 ADDRESS_STRING_SIZE = 12; - -class LLMachine -{ -public: - LLMachine() - : mMachineType(MT_NULL), mControlPort(0) {} - - LLMachine(EMachineType machine_type, U32 ip, S32 port) - : mMachineType(machine_type), mControlPort(0), mHost(ip,port) {} - - LLMachine(EMachineType machine_type, const LLHost &host) - : mMachineType(machine_type) {mHost = host; mControlPort = 0;} - - ~LLMachine() {} - - // get functions - EMachineType getMachineType() const { return mMachineType; } - U32 getMachineIP() const { return mHost.getAddress(); } - S32 getMachinePort() const { return mHost.getPort(); } - const LLHost &getMachineHost() const { return mHost; } - // The control port is the listen port of the parent process that - // launched this machine. 0 means none or not known. - const S32 &getControlPort() const { return mControlPort; } - bool isValid() const { return (mHost.getPort() != 0); } // true if corresponds to functioning machine - - // set functions - void setMachineType(EMachineType machine_type) { mMachineType = machine_type; } - void setMachineIP(U32 ip) { mHost.setAddress(ip); } - void setMachineHost(const LLHost &host) { mHost = host; } - - void setMachinePort(S32 port); - void setControlPort( S32 port ); - - - // member variables - -// Someday these should be made private. -// When they are, some of the code that breaks should -// become member functions of LLMachine -- Leviathan -//private: - - // I fixed the others, somebody should fix these! - djs - EMachineType mMachineType; - -protected: - - S32 mControlPort; - LLHost mHost; -}; - -#endif +/** + * @file machine.h + * @brief LLMachine class header file + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_MACHINE_H +#define LL_MACHINE_H + +#include "net.h" +#include "llhost.h" + +typedef enum e_machine_type +{ + MT_NULL, + MT_SIMULATOR, + MT_VIEWER, + MT_SPACE_SERVER, + MT_OBJECT_REPOSITORY, + MT_PROXY, + MT_EOF +} EMachineType; + +const U32 ADDRESS_STRING_SIZE = 12; + +class LLMachine +{ +public: + LLMachine() + : mMachineType(MT_NULL), mControlPort(0) {} + + LLMachine(EMachineType machine_type, U32 ip, S32 port) + : mMachineType(machine_type), mControlPort(0), mHost(ip,port) {} + + LLMachine(EMachineType machine_type, const LLHost &host) + : mMachineType(machine_type) {mHost = host; mControlPort = 0;} + + ~LLMachine() {} + + // get functions + EMachineType getMachineType() const { return mMachineType; } + U32 getMachineIP() const { return mHost.getAddress(); } + S32 getMachinePort() const { return mHost.getPort(); } + const LLHost &getMachineHost() const { return mHost; } + // The control port is the listen port of the parent process that + // launched this machine. 0 means none or not known. + const S32 &getControlPort() const { return mControlPort; } + bool isValid() const { return (mHost.getPort() != 0); } // true if corresponds to functioning machine + + // set functions + void setMachineType(EMachineType machine_type) { mMachineType = machine_type; } + void setMachineIP(U32 ip) { mHost.setAddress(ip); } + void setMachineHost(const LLHost &host) { mHost = host; } + + void setMachinePort(S32 port); + void setControlPort( S32 port ); + + + // member variables + +// Someday these should be made private. +// When they are, some of the code that breaks should +// become member functions of LLMachine -- Leviathan +//private: + + // I fixed the others, somebody should fix these! - djs + EMachineType mMachineType; + +protected: + + S32 mControlPort; + LLHost mHost; +}; + +#endif diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index b57f8f4513..e705c36ff8 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 -#include -#include -#include -#endif -#include -#include -#include - -#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 - gHTTPRegistrationMessageWildcard("/message/"); - -//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 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 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(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(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 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::iterator iter = cdp->mAcks.begin(); - std::vector::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 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::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 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 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 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" <\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(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(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 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 > - gHTTPRegistrationTrustedMessageWildcard("/trusted-message/"); - +/** + * @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 +#include +#include +#include +#endif +#include +#include +#include + +#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 + gHTTPRegistrationMessageWildcard("/message/"); + +//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 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 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(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(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 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::iterator iter = cdp->mAcks.begin(); + std::vector::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 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::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 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 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 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" <\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(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(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 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 > + gHTTPRegistrationTrustedMessageWildcard("/trusted-message/"); + diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 8f15bc266d..b4b0d94021 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 -#include - -#if LL_LINUX -#include -#include -#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 -{ - 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 message_template_name_map_t; - typedef std::map 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 mIPPortToCircuitCode; - std::map 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 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 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 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 exception_t; - typedef std::map 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 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 - bool checkAllMessages(ARGS&&... args) - { - return mMessageSystem->checkAllMessages(*this, std::forward(args)...); - } - - template - bool checkMessages(ARGS&&... args) - { - return mMessageSystem->checkMessages(*this, std::forward(args)...); - } - - template - void processAcks(ARGS&&... args) - { - return mMessageSystem->processAcks(*this, std::forward(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 +#include + +#if LL_LINUX +#include +#include +#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 +{ + 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 message_template_name_map_t; + typedef std::map 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 mIPPortToCircuitCode; + std::map 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 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 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 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 exception_t; + typedef std::map 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 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 + bool checkAllMessages(ARGS&&... args) + { + return mMessageSystem->checkAllMessages(*this, std::forward(args)...); + } + + template + bool checkMessages(ARGS&&... args) + { + return mMessageSystem->checkMessages(*this, std::forward(args)...); + } + + template + void processAcks(ARGS&&... args) + { + return mMessageSystem->processAcks(*this, std::forward(args)...); + } + +private: + LLMessageSystem* mMessageSystem; +}; + +// Must specific overall system version, which is used to determine +// if a patch is available in the message template checksum verification. +// Return true if able to initialize system. +bool start_messaging_system( + const std::string& template_name, + U32 port, + S32 version_major, + S32 version_minor, + S32 version_patch, + bool b_dump_prehash_file, + const std::string& secret, + const LLUseCircuitCodeResponder* responder, + bool failure_is_fatal, + const F32 circuit_heartbeat_interval, + const F32 circuit_timeout); + +void end_messaging_system(bool print_summary = true); + +void null_message_callback(LLMessageSystem *msg, void **data); + +// +// Inlines +// + +#if !defined( LL_BIG_ENDIAN ) && !defined( LL_LITTLE_ENDIAN ) +#error Unknown endianness for htolememcpy. Did you miss a common include? +#endif + +static inline void *htolememcpy(void *vs, const void *vct, EMsgVariableType type, size_t n) +{ + char *s = (char *)vs; + const char *ct = (const char *)vct; +#ifdef LL_BIG_ENDIAN + S32 i, length; +#endif + switch(type) + { + case MVT_FIXED: + case MVT_VARIABLE: + case MVT_U8: + case MVT_S8: + case MVT_BOOL: + case MVT_LLUUID: + case MVT_IP_ADDR: // these two are swizzled in the getters and setters + case MVT_IP_PORT: // these two are swizzled in the getters and setters + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ + + case MVT_U16: + case MVT_S16: + if (n != 2) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + *(s + 1) = *(ct); + *(s) = *(ct + 1); + return(vs); +#else + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ +#endif + + case MVT_U32: + case MVT_S32: + case MVT_F32: + if (n != 4) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + *(s + 3) = *(ct); + *(s + 2) = *(ct + 1); + *(s + 1) = *(ct + 2); + *(s) = *(ct + 3); + return(vs); +#else + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ +#endif + + case MVT_U64: + case MVT_S64: + case MVT_F64: + if (n != 8) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + *(s + 7) = *(ct); + *(s + 6) = *(ct + 1); + *(s + 5) = *(ct + 2); + *(s + 4) = *(ct + 3); + *(s + 3) = *(ct + 4); + *(s + 2) = *(ct + 5); + *(s + 1) = *(ct + 6); + *(s) = *(ct + 7); + return(vs); +#else + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ +#endif + + case MVT_LLVector3: + case MVT_LLQuaternion: // We only send x, y, z and infer w (we set x, y, z to ensure that w >= 0) + if (n != 12) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + htolememcpy(s + 8, ct + 8, MVT_F32, 4); + htolememcpy(s + 4, ct + 4, MVT_F32, 4); + return(htolememcpy(s, ct, MVT_F32, 4)); +#else + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ +#endif + + case MVT_LLVector3d: + if (n != 24) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + htolememcpy(s + 16, ct + 16, MVT_F64, 8); + htolememcpy(s + 8, ct + 8, MVT_F64, 8); + return(htolememcpy(s, ct, MVT_F64, 8)); +#else + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ +#endif + + case MVT_LLVector4: + if (n != 16) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + htolememcpy(s + 12, ct + 12, MVT_F32, 4); + htolememcpy(s + 8, ct + 8, MVT_F32, 4); + htolememcpy(s + 4, ct + 4, MVT_F32, 4); + return(htolememcpy(s, ct, MVT_F32, 4)); +#else + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ +#endif + + case MVT_U16Vec3: + if (n != 6) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + htolememcpy(s + 4, ct + 4, MVT_U16, 2); + htolememcpy(s + 2, ct + 2, MVT_U16, 2); + return(htolememcpy(s, ct, MVT_U16, 2)); +#else + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ +#endif + + case MVT_U16Quat: + if (n != 8) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + htolememcpy(s + 6, ct + 6, MVT_U16, 2); + htolememcpy(s + 4, ct + 4, MVT_U16, 2); + htolememcpy(s + 2, ct + 2, MVT_U16, 2); + return(htolememcpy(s, ct, MVT_U16, 2)); +#else + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ +#endif + + case MVT_S16Array: + if (n % 2) + { + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; + } +#ifdef LL_BIG_ENDIAN + length = n % 2; + for (i = 1; i < length; i++) + { + htolememcpy(s + i*2, ct + i*2, MVT_S16, 2); + } + return(htolememcpy(s, ct, MVT_S16, 2)); +#else + return(memcpy(s,ct,n)); +#endif + + default: + return(memcpy(s,ct,n)); /* Flawfinder: ignore */ + } +} + +inline void *ntohmemcpy(void *s, const void *ct, EMsgVariableType type, size_t n) +{ + return(htolememcpy(s,ct,type, n)); +} + +inline const LLHost& LLMessageSystem::getReceivingInterface() const {return mLastReceivingIF;} + +inline U32 LLMessageSystem::getSenderIP() const +{ + return mLastSender.getAddress(); +} + +inline U32 LLMessageSystem::getSenderPort() const +{ + return mLastSender.getPort(); +} + + +//----------------------------------------------------------------------------- +// Transmission aliases +//----------------------------------------------------------------------------- + +inline S32 LLMessageSystem::sendMessage(const U32 circuit) +{ + return sendMessage(findHost(circuit)); +} + +#endif diff --git a/indra/llmessage/message_string_table.cpp b/indra/llmessage/message_string_table.cpp index facc8f6cae..6d2157eec9 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 833380632c..1c49f9be36 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 - -#if LL_WINDOWS -#include "llwin32headerslean.h" -#else - #include - #include - #include - #include - #include - #include -#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 + +#if LL_WINDOWS +#include "llwin32headerslean.h" +#else + #include + #include + #include + #include + #include + #include +#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 b6040b0a35..c41f3bb89f 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 f0af91e7a3..6113adbfcf 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<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<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<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<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<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<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<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<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 09d0ef76d5..23307f3409 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 5c9dc5ad87..489b6ce6a6 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< 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< (1<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< 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< (1<stride = retvalu16; + + U8 retvalu8 = 0; + bitpack.bitUnpack(&retvalu8, 8); + gopp->patch_size = retvalu8; + + retvalu8 = 0; + bitpack.bitUnpack(&retvalu8, 8); + gopp->layer_type = retvalu8; + + gPatchSize = gopp->patch_size; +} + +void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph) +{ + U8 retvalu8; + + retvalu8 = 0; + bitpack.bitUnpack(&retvalu8, 8); + ph->quant_wbits = retvalu8; + + if (END_OF_PATCHES == ph->quant_wbits) + { + // End of data, blitz the rest. + ph->dc_offset = 0; + ph->range = 0; + ph->patchids = 0; + return; + } + + U32 retvalu32 = 0; +#ifdef LL_BIG_ENDIAN + U8 *ret = (U8 *)&retvalu32; + bitpack.bitUnpack(&(ret[3]), 8); + bitpack.bitUnpack(&(ret[2]), 8); + bitpack.bitUnpack(&(ret[1]), 8); + bitpack.bitUnpack(&(ret[0]), 8); +#else + bitpack.bitUnpack((U8 *)&retvalu32, 32); +#endif + ph->dc_offset = *(F32 *)&retvalu32; + + U16 retvalu16 = 0; +#ifdef LL_BIG_ENDIAN + ret = (U8 *)&retvalu16; + bitpack.bitUnpack(&(ret[1]), 8); + bitpack.bitUnpack(&(ret[0]), 8); +#else + bitpack.bitUnpack((U8 *)&retvalu16, 16); +#endif + ph->range = retvalu16; + + retvalu16 = 0; +#ifdef LL_BIG_ENDIAN + ret = (U8 *)&retvalu16; + bitpack.bitUnpack(&(ret[1]), 8); + bitpack.bitUnpack(&(ret[0]), 2); +#else + bitpack.bitUnpack((U8 *)&retvalu16, 10); +#endif + ph->patchids = retvalu16; + + gWordBits = (ph->quant_wbits & 0xf) + 2; +} + +void decode_patch(LLBitPack &bitpack, S32 *patches) +{ +#ifdef LL_BIG_ENDIAN + S32 i, j, patch_size = gPatchSize, wbits = gWordBits; + U8 tempu8; + U16 tempu16; + U32 tempu32; + for (i = 0; i < patch_size*patch_size; i++) + { + bitpack.bitUnpack((U8 *)&tempu8, 1); + if (tempu8) + { + // either 0 EOB or Value + bitpack.bitUnpack((U8 *)&tempu8, 1); + if (tempu8) + { + // value + bitpack.bitUnpack((U8 *)&tempu8, 1); + if (tempu8) + { + // negative + patches[i] = -1; + } + else + { + // positive + patches[i] = 1; + } + if (wbits <= 8) + { + bitpack.bitUnpack((U8 *)&tempu8, wbits); + patches[i] *= tempu8; + } + else if (wbits <= 16) + { + tempu16 = 0; + U8 *ret = (U8 *)&tempu16; + bitpack.bitUnpack(&(ret[1]), 8); + bitpack.bitUnpack(&(ret[0]), wbits - 8); + patches[i] *= tempu16; + } + else if (wbits <= 24) + { + tempu32 = 0; + U8 *ret = (U8 *)&tempu32; + bitpack.bitUnpack(&(ret[2]), 8); + bitpack.bitUnpack(&(ret[1]), 8); + bitpack.bitUnpack(&(ret[0]), wbits - 16); + patches[i] *= tempu32; + } + else if (wbits <= 32) + { + tempu32 = 0; + U8 *ret = (U8 *)&tempu32; + bitpack.bitUnpack(&(ret[3]), 8); + bitpack.bitUnpack(&(ret[2]), 8); + bitpack.bitUnpack(&(ret[1]), 8); + bitpack.bitUnpack(&(ret[0]), wbits - 24); + patches[i] *= tempu32; + } + } + else + { + for (j = i; j < patch_size*patch_size; j++) + { + patches[j] = 0; + } + return; + } + } + else + { + patches[i] = 0; + } + } +#else + S32 i, j, patch_size = gPatchSize, wbits = gWordBits; + U32 temp; + for (i = 0; i < patch_size*patch_size; i++) + { + temp = 0; + bitpack.bitUnpack((U8 *)&temp, 1); + if (temp) + { + // either 0 EOB or Value + temp = 0; + bitpack.bitUnpack((U8 *)&temp, 1); + if (temp) + { + // value + temp = 0; + bitpack.bitUnpack((U8 *)&temp, 1); + if (temp) + { + // negative + temp = 0; + bitpack.bitUnpack((U8 *)&temp, wbits); + patches[i] = temp; + patches[i] *= -1; + } + else + { + // positive + temp = 0; + bitpack.bitUnpack((U8 *)&temp, wbits); + patches[i] = temp; + } + } + else + { + for (j = i; j < patch_size*patch_size; j++) + { + patches[j] = 0; + } + return; + } + } + else + { + patches[i] = 0; + } + } +#endif +} + diff --git a/indra/llmessage/patch_dct.cpp b/indra/llmessage/patch_dct.cpp index 10b3e5dd77..728fe84537 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<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<quant_wbits = wordsize - 2; + php->quant_wbits |= (prequant - 2)<<4; + + for (j = 0; j < size; j++) + { + tblock = block + j*size; + tpatch = patch + j*stride; + for (i = 0; i < size; i++) + { +// block[j*size + i] = (patch[j*stride + i] - dc)*premult - sub; + *(tblock++) = *(tpatch++)*premult - sub; + } + } + + if (size == 16) + dct_patch(block, cpatch); + else + dct_patch_large(block, cpatch); +} + +void get_patch_group_header(LLGroupHeader *gopp) +{ + PCGD *pcp = &gPatchCompressGlobalData; + gopp->stride = pcp->patch_stride; + gopp->patch_size = pcp->patch_size; + gopp->layer_type = pcp->layer_type; +} diff --git a/indra/llmessage/patch_idct.cpp b/indra/llmessage/patch_idct.cpp index c5320e22e3..5483cf98c0 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<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<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<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<dc_offset; + S32 stride = gopp->stride; + + F32 ooq = 1.f/(F32)quantize; + F32 *dq = gPatchDequantizeTable; + S32 *decopy_matrix = gDeCopyMatrix; + + F32 mult = ooq*range; + F32 addval = mult*(F32)(1<<(prequant - 1))+hmin; + +// bool b_diag = false; +// bool b_right = true; + + for (i = 0; i < size*size; i++) + { + *(tblock++) = *(cpatch + *(decopy_matrix++))*(*dq++); + } + + if (size == 16) + idct_patch(block); + else + idct_patch_large(block); + + for (j = 0; j < size; j++) + { + tvec = v + j*stride; + tblock = block + j*size; + for (i = 0; i < size; i++) + { + (*tvec++).mV[VZ] = *(tblock++)*mult+addval; + } + } +} + diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp index d0a34d720a..c5b852453f 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 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(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& vector_data, const char* data) -{ - vector_data.resize(strlen(data) + 1); - strcpy(reinterpret_cast(&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(); - } - - LLSD mMessage; - LLHTTPNode::ResponsePtr mResponsePtr; - std::string mMessageName; - }; - - typedef test_group 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 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 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 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 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(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& vector_data, const char* data) +{ + vector_data.resize(strlen(data) + 1); + strcpy(reinterpret_cast(&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(); + } + + LLSD mMessage; + LLHTTPNode::ResponsePtr mResponsePtr; + std::string mMessageName; + }; + + typedef test_group 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 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 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 vector_data; + fillVector(vector_data, gBinaryTemplateData); + mMessage["body"]["binary-template-data"] = vector_data; + t.dispatch(mMessageName, mMessage, mResponsePtr); + ensure("data couriered correctly", strcmp(gBinaryTemplateData, gUdpDispatchedData) == 0); + } +} + diff --git a/indra/llmessage/tests/llxfer_file_test.cpp b/indra/llmessage/tests/llxfer_file_test.cpp index 6a2e0566df..358659a5b9 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_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 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 Date: Thu, 30 May 2024 15:41:36 +0200 Subject: Fix a bunch of uninitialized variable warnings that showed up in Visual Studio --- indra/llmessage/llregionflags.h | 188 ++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 96 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 4f23c4d160..2b7ba80a78 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -28,83 +28,83 @@ #define LL_LLREGIONFLAGS_H // Can you be hurt here? Should health be on? -const U64 REGION_FLAGS_ALLOW_DAMAGE = (1 << 0); +constexpr U64 REGION_FLAGS_ALLOW_DAMAGE = (1ULL << 0); // Can you make landmarks here? -const U64 REGION_FLAGS_ALLOW_LANDMARK = (1 << 1); +constexpr U64 REGION_FLAGS_ALLOW_LANDMARK = (1ULL << 1); // Do we reset the home position when someone teleports away from here? -const U64 REGION_FLAGS_ALLOW_SET_HOME = (1 << 2); +constexpr U64 REGION_FLAGS_ALLOW_SET_HOME = (1ULL << 2); // Do we reset the home position when someone teleports away from here? -const U64 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3); +constexpr U64 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1ULL << 3); // Does the sun move? -const U64 REGION_FLAGS_SUN_FIXED = (1 << 4); +constexpr U64 REGION_FLAGS_SUN_FIXED = (1ULL << 4); // Does the estate owner allow private parcels? -const U64 REGION_FLAGS_ALLOW_ACCESS_OVERRIDE = (1 << 5); +constexpr U64 REGION_FLAGS_ALLOW_ACCESS_OVERRIDE = (1ULL << 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); +constexpr U64 REGION_FLAGS_BLOCK_TERRAFORM = (1ULL << 6); // Can't release, sell, or buy land. -const U64 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7); +constexpr U64 REGION_FLAGS_BLOCK_LAND_RESELL = (1ULL << 7); // All content wiped once per night -const U64 REGION_FLAGS_SANDBOX = (1 << 8); +constexpr U64 REGION_FLAGS_SANDBOX = (1ULL << 8); -const U64 REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE = (1 << 9); +constexpr U64 REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE = (1ULL << 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); +constexpr U64 REGION_FLAGS_SKIP_COLLISIONS = (1ULL << 12); // Pin all non agent rigid bodies +constexpr U64 REGION_FLAGS_SKIP_SCRIPTS = (1ULL << 13); +constexpr U64 REGION_FLAGS_SKIP_PHYSICS = (1ULL << 14); // Skip all physics +constexpr U64 REGION_FLAGS_EXTERNALLY_VISIBLE = (1ULL << 15); +constexpr U64 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT = (1ULL << 16); +constexpr U64 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT = (1ULL << 17); +constexpr U64 REGION_FLAGS_BLOCK_DWELL = (1ULL << 18); // Is flight allowed? -const U64 REGION_FLAGS_BLOCK_FLY = (1 << 19); +constexpr U64 REGION_FLAGS_BLOCK_FLY = (1ULL << 19); // Is direct teleport (p2p) allowed? -const U64 REGION_FLAGS_ALLOW_DIRECT_TELEPORT = (1 << 20); +constexpr U64 REGION_FLAGS_ALLOW_DIRECT_TELEPORT = (1ULL << 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); +constexpr U64 REGION_FLAGS_ESTATE_SKIP_SCRIPTS = (1ULL << 21); -const U64 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1 << 22); +constexpr U64 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1ULL << 22); -const U64 REGION_FLAGS_DENY_ANONYMOUS = (1 << 23); +constexpr U64 REGION_FLAGS_DENY_ANONYMOUS = (1ULL << 23); -const U64 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1 << 26); +constexpr U64 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1ULL << 26); -const U64 REGION_FLAGS_BLOCK_FLYOVER = (1 << 27); +constexpr U64 REGION_FLAGS_BLOCK_FLYOVER = (1ULL << 27); -const U64 REGION_FLAGS_ALLOW_VOICE = (1 << 28); +constexpr U64 REGION_FLAGS_ALLOW_VOICE = (1ULL << 28); -const U64 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29); -const U64 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30); +constexpr U64 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1ULL << 29); +constexpr U64 REGION_FLAGS_DENY_AGEUNVERIFIED = (1ULL << 30); -const U64 REGION_FLAGS_DENY_BOTS = (1 << 31); +constexpr U64 REGION_FLAGS_DENY_BOTS = (1ULL << 31); -const U64 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK | - REGION_FLAGS_ALLOW_SET_HOME | - REGION_FLAGS_ALLOW_PARCEL_CHANGES | - REGION_FLAGS_ALLOW_VOICE; +constexpr 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; +constexpr U64 REGION_FLAGS_PRELUDE_SET = REGION_FLAGS_RESET_HOME_ON_TELEPORT; +constexpr 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; +constexpr 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) { @@ -133,79 +133,75 @@ inline U64 unset_prelude_flags(U64 flags) } // Region protocols -const U64 REGION_PROTOCOLS_AGENT_APPEARANCE_SERVICE = (1 << 0); +constexpr U64 REGION_PROTOCOLS_AGENT_APPEARANCE_SERVICE = (1ULL << 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 +constexpr U32 ESTATE_ALL = 0; // will not match in db, reserved key for logic +constexpr U32 ESTATE_MAINLAND = 1; +constexpr U32 ESTATE_ORIENTATION = 2; +constexpr U32 ESTATE_INTERNAL = 3; +constexpr U32 ESTATE_SHOWCASE = 4; +constexpr U32 ESTATE_TEEN = 5; +constexpr 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; +constexpr U32 ESTATE_ACCESS_ALLOWED_AGENTS = 1 << 0; +constexpr U32 ESTATE_ACCESS_ALLOWED_GROUPS = 1 << 1; +constexpr U32 ESTATE_ACCESS_BANNED_AGENTS = 1 << 2; +constexpr 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; +constexpr 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; +constexpr 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; +constexpr 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; +constexpr U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1U << 0; +constexpr U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1U << 1; + +constexpr U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1U << 2; +constexpr U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1U << 3; +constexpr U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1U << 4; +constexpr U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1U << 5; +constexpr U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1U << 6; +constexpr U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1U << 7; +constexpr U32 ESTATE_ACCESS_MANAGER_ADD = 1U << 8; +constexpr U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9; +constexpr U32 ESTATE_ACCESS_NO_REPLY = 1U << 10; +constexpr U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11; + +constexpr S32 ESTATE_MAX_MANAGERS = 20; +constexpr S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access +constexpr S32 ESTATE_MAX_BANNED_IDS = 750; // max for banned +constexpr 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); +constexpr U32 SWD_OTHERS_LAND_ONLY = (1 << 0); +constexpr U32 SWD_ALWAYS_RETURN_OBJECTS = (1 << 1); +constexpr 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; +constexpr U32 EXPERIENCE_KEY_TYPE_NONE = 0; +constexpr U32 EXPERIENCE_KEY_TYPE_BLOCKED = 1; +constexpr U32 EXPERIENCE_KEY_TYPE_ALLOWED = 2; +constexpr 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; +constexpr U32 EXPERIENCE_KEY_TYPE_FIRST = EXPERIENCE_KEY_TYPE_BLOCKED; +constexpr 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; - - +constexpr U32 ESTATE_EXPERIENCE_TRUSTED_ADD = 1U << 2; +constexpr U32 ESTATE_EXPERIENCE_TRUSTED_REMOVE = 1U << 3; +constexpr U32 ESTATE_EXPERIENCE_ALLOWED_ADD = 1U << 4; +constexpr U32 ESTATE_EXPERIENCE_ALLOWED_REMOVE = 1U << 5; +constexpr U32 ESTATE_EXPERIENCE_BLOCKED_ADD = 1U << 6; +constexpr U32 ESTATE_EXPERIENCE_BLOCKED_REMOVE = 1U << 7; + +constexpr S32 ESTATE_MAX_EXPERIENCE_IDS = 8; #endif - - -- cgit v1.2.3 From b42f9d836b4c0f7fbd4bdae1734021e2a09fdbe8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 1 Jun 2024 15:49:26 +0200 Subject: Re-enable a lot of compiler warnings for MSVC and address the C4267 "possible loss of precision" warnings --- indra/llmessage/llassetstorage.cpp | 2 +- indra/llmessage/llavatarnamecache.cpp | 2 +- indra/llmessage/llcachename.cpp | 8 ++++---- indra/llmessage/llcircuit.cpp | 4 ++-- indra/llmessage/llcoproceduremanager.cpp | 2 +- indra/llmessage/lldatapacker.cpp | 4 ++-- indra/llmessage/llfiltersd2xmlrpc.cpp | 4 ++-- indra/llmessage/lliohttpserver.cpp | 2 +- indra/llmessage/lliosocket.cpp | 2 +- indra/llmessage/llmail.cpp | 2 +- indra/llmessage/llproxy.cpp | 2 +- indra/llmessage/llpumpio.cpp | 2 +- indra/llmessage/llsdmessagereader.cpp | 8 ++++---- indra/llmessage/lltemplatemessagedispatcher.cpp | 4 ++-- indra/llmessage/llxfer_file.cpp | 2 +- indra/llmessage/message.cpp | 4 ++-- 16 files changed, 27 insertions(+), 27 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 13fda24e62..b3390451a2 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -1125,7 +1125,7 @@ S32 LLAssetStorage::getNumPending(LLAssetStorage::ERequestType rt) const S32 num_pending = -1; if (requests) { - num_pending = requests->size(); + num_pending = static_cast(requests->size()); } return num_pending; } diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index a0cd6f93c1..ff7c2f8387 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -240,7 +240,7 @@ void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &h // Same logic as error response case const LLSD& unresolved_agents = data["bad_ids"]; - S32 num_unresolved = unresolved_agents.size(); + auto num_unresolved = unresolved_agents.size(); if (num_unresolved > 0) { LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; " diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 6fb21957e0..63ac46722a 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -562,13 +562,13 @@ 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(')'); + auto open_paren = complete_name.rfind(" ("); + auto close_paren = complete_name.rfind(')'); if (open_paren != std::string::npos && close_paren == complete_name.length()-1) { - S32 length = close_paren - open_paren - 2; + auto length = close_paren - open_paren - 2; std::string legacy_name = complete_name.substr(open_paren+2, length); if (legacy_name.length() > 0) @@ -577,7 +577,7 @@ std::string LLCacheName::buildLegacyName(const std::string& complete_name) LLStringUtil::toUpper(cap_letter); legacy_name = cap_letter + legacy_name.substr(1); - S32 separator = legacy_name.find('.'); + auto separator = legacy_name.find('.'); if (separator != std::string::npos) { diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index fa206d9282..bf22f3d3f0 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -781,8 +781,8 @@ void LLCircuitData::checkPacketInID(TPACKETID id, bool receive_resent) void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys) { F64Seconds cur_time = LLMessageSystem::getMessageTimeSeconds(); - S32 count = mPingSet.size(); - S32 cur = 0; + size_t count = mPingSet.size(); + size_t cur = 0; // Only process each circuit once at most, stop processing if no circuits while((cur < count) && !mPingSet.empty()) diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 959cfb2762..263670bdac 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -87,7 +87,7 @@ public: /// inline S32 count() const { - return countPending() + countActive(); + return static_cast(countPending() + countActive()); } void close(); diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 134f34aafa..e911150787 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -237,7 +237,7 @@ bool LLDataPacker::unpackUUIDs(LLUUID *values, S32 count, const char *name) bool LLDataPackerBinaryBuffer::packString(const std::string& value, const char *name) { - S32 length = value.length()+1; + S32 length = static_cast(value.length()) + 1; if (!verifyLength(length, name)) { @@ -740,7 +740,7 @@ bool LLDataPackerAsciiBuffer::packString(const std::string& value, const char *n } else { - numCopied = value.length() + 1; /*Flawfinder: ignore*/ + numCopied = static_cast(value.length()) + 1; /*Flawfinder: ignore*/ } // snprintf returns number of bytes that would have been written diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp index df78652361..84b56d54bf 100644 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ b/indra/llmessage/llfiltersd2xmlrpc.cpp @@ -274,12 +274,12 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) if(!buffer.empty()) { // *TODO: convert to LLBase64 - int b64_buffer_length = apr_base64_encode_len(buffer.size()); + int b64_buffer_length = apr_base64_encode_len(static_cast(buffer.size())); char* b64_buffer = new char[b64_buffer_length]; b64_buffer_length = apr_base64_encode_binary( b64_buffer, &buffer[0], - buffer.size()); + static_cast(buffer.size())); ostr.write(b64_buffer, b64_buffer_length - 1); delete[] b64_buffer; } diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 9791a20743..e562f09844 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -494,7 +494,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( 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()); + buffer->prepend(channels.out(), (U8*)header.c_str(), static_cast(header.size())); PUMP_DEBUG; return STATUS_DONE; } diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index a14d10fe5f..f2192acee0 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -346,7 +346,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl( PUMP_DEBUG; len = READ_BUFFER_SIZE; status = apr_socket_recv(mSource->getSocket(), read_buf, &len); - buffer->append(channels.out(), (U8*)read_buf, len); + buffer->append(channels.out(), (U8*)read_buf, static_cast(len)); } while((APR_SUCCESS == status) && (READ_BUFFER_SIZE == len)); LL_DEBUGS() << "socket read status: " << status << LL_ENDL; LLIOPipe::EStatus rv = STATUS_OK; diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index ca027d7675..9e10a356db 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -273,7 +273,7 @@ bool LLMail::send( std::string good_string = "\n..\n"; while (1) { - int index = message.find(bad_string); + auto index = message.find(bad_string); if (index == std::string::npos) break; message.replace(index, bad_string.size(), good_string); } diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 3e1e5daa02..864e68998c 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -123,7 +123,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy) // 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; + U32 request_size = static_cast(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()); diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index d3b75cf86b..e1cd70b216 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -818,7 +818,7 @@ void LLPumpIO::rebuildPollset() running_chains_t::iterator run_end = mRunningChains.end(); for(; run_it != run_end; ++run_it) { - size += (*run_it).mDescriptors.size(); + size += static_cast((*run_it).mDescriptors.size()); } //LL_DEBUGS() << "found " << size << " descriptors." << LL_ENDL; if(size) diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp index 8be6158d82..6ade7c0dad 100644 --- a/indra/llmessage/llsdmessagereader.cpp +++ b/indra/llmessage/llsdmessagereader.cpp @@ -242,7 +242,7 @@ void LLSDMessageReader::getString(const char *block, const char *var, return; } std::string data = getLLSD(mMessage, block, var, blocknum); - S32 data_size = data.size(); + auto data_size = data.size(); if (data_size >= buffer_size) { data_size = buffer_size - 1; @@ -261,7 +261,7 @@ void LLSDMessageReader::getString(const char *block, const char *var, //virtual S32 LLSDMessageReader::getNumberOfBlocks(const char *blockname) { - return mMessage[blockname].size(); + return static_cast(mMessage[blockname].size()); } S32 getElementSize(const LLSD& llsd) @@ -276,7 +276,7 @@ S32 getElementSize(const LLSD& llsd) case LLSD::TypeReal: return sizeof(F64); case LLSD::TypeString: - return llsd.size(); + return static_cast(llsd.size()); case LLSD::TypeUUID: return sizeof(LLUUID); case LLSD::TypeDate: @@ -286,7 +286,7 @@ S32 getElementSize(const LLSD& llsd) case LLSD::TypeBinary: { std::vector data = llsd; - return data.size() * sizeof(U8); + return static_cast(data.size() * sizeof(U8)); } case LLSD::TypeMap: case LLSD::TypeArray: diff --git a/indra/llmessage/lltemplatemessagedispatcher.cpp b/indra/llmessage/lltemplatemessagedispatcher.cpp index 267c201705..0e709d6c75 100644 --- a/indra/llmessage/lltemplatemessagedispatcher.cpp +++ b/indra/llmessage/lltemplatemessagedispatcher.cpp @@ -44,7 +44,7 @@ void LLTemplateMessageDispatcher::dispatch(const std::string& msg_name, LLHTTPNode::ResponsePtr responsep) { std::vector data = message["body"]["binary-template-data"].asBinary(); - U32 size = data.size(); + auto size = data.size(); if(size == 0) { return; @@ -53,7 +53,7 @@ void LLTemplateMessageDispatcher::dispatch(const std::string& msg_name, LLHost host; host = gMessageSystem->getSender(); - bool validate_message = mTemplateMessageReader.validateMessage(&(data[0]), data.size(), host, true); + bool validate_message = mTemplateMessageReader.validateMessage(&(data[0]), static_cast(size), host, true); if (validate_message) { diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index ad15d5969b..71b910297b 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -317,7 +317,7 @@ S32 LLXfer_File::flush() if (mFp) { - S32 write_size = fwrite(mBuffer,1,mBufferLength,mFp); + S32 write_size = static_cast(fwrite(mBuffer,1,mBufferLength,mFp)); if (write_size != mBufferLength) { LL_WARNS("Xfer") << "Non-matching write size, requested " << mBufferLength diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index e705c36ff8..cfa5178fc6 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -2172,7 +2172,7 @@ S32 LLMessageSystem::sendError( if (LLMessageConfig::getMessageFlavor(ERROR_MESSAGE_NAME) == LLMessageConfig::TEMPLATE_FLAVOR) { - S32 msg_size = temp.size() + mMessageBuilder->getMessageSize(); + S32 msg_size = static_cast(temp.size()) + mMessageBuilder->getMessageSize(); if(msg_size >= ETHERNET_MTU_BYTES) { pack_data = false; @@ -2180,7 +2180,7 @@ S32 LLMessageSystem::sendError( } if(pack_data) { - addBinaryData("Data", (void*)temp.c_str(), temp.size()); + addBinaryData("Data", (void*)temp.c_str(), static_cast(temp.size())); } else { -- cgit v1.2.3 From c0fad3028fd55c2067ce6a0ae4382cffe1014284 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 10 Jun 2024 16:42:43 +0200 Subject: Re-enable compiler warnings C4018, C4100, C4231 and C4506 --- indra/llmessage/llpartdata.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp index 296f4b5464..d4cf95c1e3 100644 --- a/indra/llmessage/llpartdata.cpp +++ b/indra/llmessage/llpartdata.cpp @@ -289,14 +289,14 @@ bool LLPartSysData::unpack(LLDataPacker &dp) //skip to LLPartData block U8 feh = 0; - for (U32 i = 0; i < size; ++i) + for (S32 i = 0; i < size; ++i) { dp.unpackU8(feh, "whippang"); } dp.unpackS32(size, "partsize"); //skip LLPartData block - for (U32 i = 0; i < size; ++i) + for (S32 i = 0; i < size; ++i) { dp.unpackU8(feh, "whippang"); } -- cgit v1.2.3