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 c2e0ee9231a547b4f6fd65487a7102036a852ed6 Mon Sep 17 00:00:00 2001 From: Bennett Goble Date: Fri, 29 Mar 2024 14:58:33 -0700 Subject: BUG-134040: Fix broken SOCKS5 proxy Second Life's SOCKS5 proxy has been broken on windows for at least six years due to a conflation of milliseconds and microseconds in the APR timeout value used when attempting to ping the proxy. --- indra/llmessage/llproxy.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 749e599c66..17f0d9f345 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -465,7 +465,7 @@ void LLProxy::applyProxySettings(CURL* handle) /** * @brief Send one TCP packet and receive one in return. * - * This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking + * This operation is done synchronously with a 100ms timeout. Therefore, it should not be used when a blocking * operation would impact the operation of the viewer. * * @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP. @@ -482,7 +482,7 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou apr_size_t expected_len = outlen; - handle->setBlocking(1000); + handle->setBlocking(100000); // 100ms, 100000us. Should be sufficient for localhost, nearby network rv = apr_socket_send(apr_socket, dataout, &outlen); if (APR_SUCCESS != rv) @@ -498,8 +498,6 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou rv = -1; } - ms_sleep(1); - if (APR_SUCCESS == rv) { expected_len = maxinlen; -- cgit v1.2.3 From 57d423745fd1d3d0ea6a0c69b869a20c27e27fc5 Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn Date: Fri, 5 Apr 2024 19:25:02 +0200 Subject: Linux viewer (ReleaseOS) resurrection (#1099) Co-authored-by: AiraYumi --- indra/llmessage/CMakeLists.txt | 3 --- indra/llmessage/llnamevalue.cpp | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index e44309476b..88ab29ec67 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -3,14 +3,11 @@ project(llmessage) include(00-Common) -include(GoogleMock) include(LLAddBuildTest) include(LLCommon) include(LLCoreHttp) include(LLAddBuildTest) include(Python) -include(Tut) -include(Python) include(JsonCpp) set(llmessage_SOURCE_FILES diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp index c51883ee3d..15de4046ac 100644 --- a/indra/llmessage/llnamevalue.cpp +++ b/indra/llmessage/llnamevalue.cpp @@ -35,6 +35,10 @@ #include "llstring.h" #include "llstringtable.h" +#if LL_LINUX +#pragma GCC diagnostic ignored "-Wstringop-truncation" // It's actually okay what happens here +#endif + // 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 -- 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 8f0c41c2e5d5c66df5e975b743140112494c4a7a Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn Date: Mon, 15 Apr 2024 22:59:16 +0200 Subject: Chore/pragma gcc cleansweep (#1226) * Remove all GCC warning suppression pragmas. * For Linux just just raise(SIGSEGV) as the crash driver. This has a much higher chance of the compiler understanding out intent and figuring out we end the program here. * Remove -Wno-stringop-overflow and -Wno-stringop-truncation from GCC_WARNINGS. After calling raise(SIGSEGV) as the crash driver I saw no issue with those warnings anymore After removing thoses GCC pragmas there is also no need for clang -Wno-unknown-warning-option anymore. * Remove CMakePresets from this PR. * Remove Lindens from comments :) --- indra/llmessage/llnamevalue.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp index 15de4046ac..97b2d3aa5f 100644 --- a/indra/llmessage/llnamevalue.cpp +++ b/indra/llmessage/llnamevalue.cpp @@ -35,10 +35,6 @@ #include "llstring.h" #include "llstringtable.h" -#if LL_LINUX -#pragma GCC diagnostic ignored "-Wstringop-truncation" // It's actually okay what happens here -#endif - // 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 @@ -971,4 +967,3 @@ std::ostream& operator<<(std::ostream& s, const LLNameValue &a) } return s; } - -- cgit v1.2.3 From c78be38a6a4211f06876bc80b3f19f89a5f936e0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 17 Apr 2024 16:39:37 -0400 Subject: Reintroduce LLCoros::killreq() to request killing a named coroutine. Make LLCoros constructor echo "LLApp" status-change events on new "LLCoros" event pump. Rename LLCoros::kill() to killreq() because this operation only registers a request for the named coroutine to terminate next time it calls checkStop(). Add a new CoroData member to record the name of the coroutine requesting termination. killreq() sets that and also posts "killreq" to "LLCoros". Add an optional final-cleanup callback to LLCoros::checkStop(). Make checkStop() check for a pending killreq() request as well as viewer termination. Introduce new LLCoros::Killed exception for that case. Introduce LLCoros::getStopListener(), with two overloads, to encapsulate some of the messy logic to listen (perhaps temporarily) for viewer shutdown. Both overloads are for use by code at the source end of a queue or promise or other resource for which coroutines might still be waiting at viewer shutdown time. One overload is specifically for when the caller knows the name of the one and only coroutine that will wait on the resource (e.g. because the caller IS that coroutine). That overload honors killreq(). Use getStopListener() to simplify the four existing places where we set up such a listener. Add a fifth: also make WorkQueue listen for viewer shutdown (resolving a TODO comment). Remove LLLUAmanager::terminateScript(), getTerminationList() and the static sTerminationList. In the Lua interrupt callback, instead of checking sTerminationList, call LLCoros::checkStop(). Change LLFloaterLUAScripts terminate-script logic to call LLCoros::killreq() instead of posting on "LLLua" and calling LLLUAmanager::terminateScript(). Drop LLApp::setStatus() posting to "LLLua" LLEventPump: the above makes that moot. --- indra/llmessage/llcoproceduremanager.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index ebbaea9b12..ad0e0178b6 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -307,25 +307,20 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): { try { - // store in our LLTempBoundListener so that when the LLCoprocedurePool is - // destroyed, we implicitly disconnect from this LLEventPump - // Monitores application status - mStatusListener = LLEventPumps::instance().obtain("LLApp").listen( + // Store in our LLTempBoundListener so that when the LLCoprocedurePool is + // destroyed, we implicitly disconnect from this LLEventPump. + // Monitors application status. + mStatusListener = LLCoros::getStopListener( poolName + "_pool", // Make sure it won't repeat names from lleventcoro - [pendingCoprocs = mPendingCoprocs, poolName](const LLSD& status) - { - auto& statsd = status["status"]; - if (statsd.asString() != "running") + [pendingCoprocs = mPendingCoprocs, poolName](const LLSD& event) { LL_INFOS("CoProcMgr") << "Pool " << poolName - << " closing queue because status " << statsd + << " closing queue because status " << event << LL_ENDL; // This should ensure that all waiting coprocedures in this // pool will wake up and terminate. pendingCoprocs->close(); - } - return false; - }); + }); } catch (const LLEventPump::DupListenerName &) { @@ -334,7 +329,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): // // If this somehow happens again it is better to crash later on shutdown due to pump // not stopping coroutine and see warning in logs than on startup or during login. - LL_WARNS("CoProcMgr") << "Attempted to register dupplicate listener name: " << poolName + LL_WARNS("CoProcMgr") << "Attempted to register duplicate listener name: " << poolName << "_pool. Failed to start listener." << LL_ENDL; llassert(0); // Fix Me! Ignoring missing listener! -- 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 7fc5f7e649c564fa8479a72a45459d0cc427d0f8 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Thu, 2 May 2024 10:57:39 -0500 Subject: #1354 Make coroutines use LLCoros::Mutex instead of LLMutex (#1356) * #1354 Make coroutines use LLCoros::Mutex instead of LLMutex * #1354 Fix some more unsafe coroutine executions. * #1354 Implement changes requested by Nat --- indra/llmessage/llavatarnamecache.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index f7a9f55685..314e7f0217 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -45,6 +45,7 @@ #include "llcorehttputil.h" #include "llexception.h" #include "stringize.h" +#include "workqueue.h" #include #include @@ -179,19 +180,26 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector::const_iterator it = agentIds.begin(); - for (; it != agentIds.end(); ++it) - { - const LLUUID& agent_id = *it; - LLAvatarNameCache::getInstance()->handleAgentError(agent_id); - } - return; - } + // dispatch handler execution back to mainloop + auto workqueue = LL::WorkQueue::getInstance("mainloop"); - LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults); + if (workqueue) + { + workqueue->post([=]() + { + if (!success) + { // on any sort of failure add dummy records for any agent IDs + // in this request that we do not have cached already + for (const auto& agent_id : agentIds) + { + LLAvatarNameCache::getInstance()->handleAgentError(agent_id); + } + return; + } + + LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults); + }); + } } } catch (const LLCoros::Stop&) -- 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 1ebf006b73c06d037e3d3ae4393136082195096d 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/tests/llmockhttpclient.h | 66 -------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 indra/llmessage/tests/llmockhttpclient.h (limited to 'indra/llmessage') diff --git a/indra/llmessage/tests/llmockhttpclient.h b/indra/llmessage/tests/llmockhttpclient.h deleted file mode 100644 index 1611ab7bd8..0000000000 --- a/indra/llmessage/tests/llmockhttpclient.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * @brief - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -/* Macro Definitions */ -#ifndef LL_LLMOCKHTTPCLIENT_H -#define LL_LLMOCKHTTPCLIENT_H - -#include "linden_common.h" -#include "llhttpclientinterface.h" - -#include - -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 c3da5bb12d1c7c173929433589a4068555791bea Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 15 May 2024 09:11:29 -0400 Subject: Manual whitespace fixes (fix_whitespace.py). --- indra/llmessage/llcoproceduremanager.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index c1c1db7437..1a32b8e62a 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -41,7 +41,7 @@ //========================================================================= // Map of pool sizes for known pools static const std::map DefaultPoolSizes{ - {std::string("Upload"), 1}, + {std::string("Upload"), 1}, {std::string("AIS"), 1}, // *TODO: Rider for the moment keep AIS calls serialized otherwise the COF will tend to get out of sync. }; @@ -61,11 +61,11 @@ public: LLCoprocedurePool(const std::string &name, size_t size); ~LLCoprocedurePool(); - /// Places the coprocedure on the queue for processing. - /// + /// Places the coprocedure on the queue for processing. + /// /// @param name Is used for debugging and should identify this coroutine. - /// @param proc Is a bound function to be executed - /// + /// @param proc Is a bound function to be executed + /// /// @return This method returns a UUID that can be used later to cancel execution. LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc); @@ -91,7 +91,7 @@ public: } void close(); - + private: struct QueuedCoproc { @@ -108,7 +108,7 @@ private: CoProcedure_t mProc; }; - // we use a buffered_channel here rather than unbuffered_channel since we want to be able to + // we use a buffered_channel here rather than unbuffered_channel since we want to be able to // push values without blocking,even if there's currently no one calling a pop operation (due to // fiber running right now) typedef boost::fibers::buffered_channel CoprocQueue_t; @@ -167,7 +167,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) if (size == 0) { - // if not found grab the know default... if there is no known + // if not found grab the know default... if there is no known // default use a reasonable number like 5. auto it = DefaultPoolSizes.find(poolName); size = (it != DefaultPoolSizes.end()) ? it->second : DEFAULT_POOL_SIZE; @@ -190,7 +190,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) //------------------------------------------------------------------------- LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc) { - // Attempt to find the pool and enqueue the procedure. If the pool does + // Attempt to find the pool and enqueue the procedure. If the pool does // not exist, create it. poolMap_t::iterator it = mPoolMap.find(pool); @@ -350,7 +350,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL; } -LLCoprocedurePool::~LLCoprocedurePool() +LLCoprocedurePool::~LLCoprocedurePool() { } -- 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 From c95b4bf3ea2b681d6d05468b07e60fedb71fa2cf Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 10 Jun 2024 20:42:42 +0300 Subject: Post-merge - trim trailing whitespace --- indra/llmessage/llassetstorage.cpp | 132 ++++++++++++++++++------------------- indra/llmessage/llcorehttputil.cpp | 122 +++++++++++++++++----------------- 2 files changed, 127 insertions(+), 127 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index b3390451a2..70a7a34a70 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llassetstorage.cpp * @brief Implementation of the base asset storage system. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -74,18 +74,18 @@ namespace return false; } -// Rider: This is the general case of the operator declared above. The code compares the callback -// passed into the LLAssetStorage functions to determine if there are duplicated requests for an -// asset. Unfortunately std::function does not provide a direct way to compare two variables so -// we define the operator here. -// XCode is not very happy with the variadic temples in use below so we will just define the specific +// Rider: This is the general case of the operator declared above. The code compares the callback +// passed into the LLAssetStorage functions to determine if there are duplicated requests for an +// asset. Unfortunately std::function does not provide a direct way to compare two variables so +// we define the operator here. +// XCode is not very happy with the variadic temples in use below so we will just define the specific // case of comparing two LLGetAssetCallback objects since that is all we really use. -// +// // template // bool operator == (const std::function &a, const std::function &b) // { // typedef T(fnType)(U...); -// +// // auto fnPtrA = a.target(); // auto fnPtrB = b.target(); // if (fnPtrA && fnPtrB) @@ -112,8 +112,8 @@ LLAssetInfo::LLAssetInfo( void ) LLAssetInfo::LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id, LLAssetType::EType type, const char* name, const char* desc ) - : mUuid( object_id ), - mCreatorID( creator_id ), + : mUuid( object_id ), + mCreatorID( creator_id ), mType( type ) { setName( name ); @@ -355,7 +355,7 @@ void LLAssetStorage::_init(LLMessageSystem *msg, LLAssetStorage::~LLAssetStorage() { mShutDown = true; - + _cleanupRequests(true, LL_ERR_CIRCUIT_GONE); if (gMessageSystem) @@ -372,7 +372,7 @@ LLAssetStorage::~LLAssetStorage() void LLAssetStorage::setUpstream(const LLHost &upstream_host) { LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL; - + mUpstreamHost = upstream_host; } @@ -398,7 +398,7 @@ void LLAssetStorage::_cleanupRequests(bool all, S32 error) // if all is true, we want to clean up everything // otherwise just check for timed out requests // EXCEPT for upload timeouts - if (all + if (all || ((RT_DOWNLOAD == rt) && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime))) { @@ -406,7 +406,7 @@ void LLAssetStorage::_cleanupRequests(bool all, S32 error) << (all ? "aborted" : "timed out") << " for " << tmp->getUUID() << "." << LLAssetType::lookup(tmp->getType()) << LL_ENDL; - + timed_out.push_front(tmp); iter = requests->erase(curiter); } @@ -477,11 +477,11 @@ bool LLAssetStorage::findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetTyp // GET routines /////////////////////////////////////////////////////////////////////////// -// IW - uuid is passed by value to avoid side effects, please don't re-add & +// IW - uuid is passed by value to avoid side effects, please don't re-add & void LLAssetStorage::getAssetData(const LLUUID uuid, - LLAssetType::EType type, + LLAssetType::EType type, LLAssetStorage::LLGetAssetCallback callback, - void *user_data, + void *user_data, bool is_priority) { LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; @@ -546,9 +546,9 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; file.remove(); } - + bool duplicate = false; - + // check to see if there's a pending download of this uuid already for (request_list_t::iterator iter = mPendingDownloads.begin(); iter != mPendingDownloads.end(); ++iter ) @@ -563,7 +563,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, << "." << LLAssetType::lookup(type) << LL_ENDL; return; } - + // this is a duplicate request // queue the request, but don't actually ask for it again duplicate = true; @@ -571,11 +571,11 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, } if (duplicate) { - LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid + LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid << "." << LLAssetType::lookup(type) << LL_ENDL; } - - _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); + + _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); } } @@ -645,7 +645,7 @@ void LLAssetStorage::downloadCompleteCallback( // Inefficient since we're doing a find through a list that may have thousands of elements. // This is due for refactoring; we will probably change mPendingDownloads into a set. - request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), + request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), gAssetStorage->mPendingDownloads.end(), req); @@ -668,7 +668,7 @@ void LLAssetStorage::downloadCompleteCallback( if (vfile.getSize() <= 0) { LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset " << callback_id << LL_ENDL; - + result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; vfile.remove(); } @@ -693,13 +693,13 @@ void LLAssetStorage::downloadCompleteCallback( void LLAssetStorage::getEstateAsset( const LLHost &object_sim, - const LLUUID &agent_id, + const LLUUID &agent_id, const LLUUID &session_id, - const LLUUID &asset_id, - LLAssetType::EType atype, + const LLUUID &asset_id, + LLAssetType::EType atype, EstateAssetType etype, - LLGetAssetCallback callback, - void *user_data, + LLGetAssetCallback callback, + void *user_data, bool is_priority) { LL_DEBUGS() << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << LL_ENDL; @@ -723,7 +723,7 @@ void LLAssetStorage::getEstateAsset( { return; } - + bool exists = LLFileSystem::getExists(asset_id, atype); LLFileSystem file(asset_id, atype); U32 size = exists ? file.getSize() : 0; @@ -836,21 +836,21 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( } void LLAssetStorage::getInvItemAsset( - const LLHost &object_sim, - const LLUUID &agent_id, + const LLHost &object_sim, + const LLUUID &agent_id, const LLUUID &session_id, const LLUUID &owner_id, - const LLUUID &task_id, + const LLUUID &task_id, const LLUUID &item_id, - const LLUUID &asset_id, + const LLUUID &asset_id, LLAssetType::EType atype, - LLGetAssetCallback callback, - void *user_data, + LLGetAssetCallback callback, + void *user_data, bool is_priority) { LL_DEBUGS() << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << LL_ENDL; - bool exists = false; + bool exists = false; U32 size = 0; if(asset_id.notNull()) @@ -910,7 +910,7 @@ void LLAssetStorage::getInvItemAsset( spi.setAsset(asset_id, atype); LL_DEBUGS("ViewerAsset") << "requesting inv item id " << item_id << " asset_id " << asset_id << " type " << LLAssetType::lookup(atype) << LL_ENDL; - + // Set our destination file, and the completion callback. LLTransferTargetParamsVFile tpvf; tpvf.setAsset(asset_id, atype); @@ -984,9 +984,9 @@ void LLAssetStorage::downloadInvItemCompleteCallback( // static void LLAssetStorage::uploadCompleteCallback( - const LLUUID& uuid, - void *user_data, - S32 result, + const LLUUID& uuid, + void *user_data, + S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed) { if (!gAssetStorage) @@ -1190,7 +1190,7 @@ const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_ LLAssetType::EType asset_type, const LLUUID& asset_id) { - if (requests) + if (requests) { // Search the requests list for the asset. request_list_t::const_iterator iter = requests->begin(); @@ -1213,7 +1213,7 @@ LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requ LLAssetType::EType asset_type, const LLUUID& asset_id) { - if (requests) + if (requests) { // Search the requests list for the asset. request_list_t::iterator iter = requests->begin(); @@ -1296,7 +1296,7 @@ bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* re delete req; return true; } - + return false; } @@ -1340,14 +1340,14 @@ const char* LLAssetStorage::getErrorString(S32 status) } } -void LLAssetStorage::getAssetData(const LLUUID uuid, - LLAssetType::EType type, - void (*callback)(const char*, - const LLUUID&, - void *, - S32, - LLExtStat), - void *user_data, +void LLAssetStorage::getAssetData(const LLUUID uuid, + LLAssetType::EType type, + void (*callback)(const char*, + const LLUUID&, + void *, + S32, + LLExtStat), + void *user_data, bool is_priority) { // check for duplicates here, since we're about to fool the normal duplicate checker @@ -1358,7 +1358,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, auto cbptr = tmp->mDownCallback.target(); - if (type == tmp->getType() && + if (type == tmp->getType() && uuid == tmp->getUUID() && (cbptr && (*cbptr == legacyGetDataCallback)) && callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && @@ -1369,8 +1369,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, return; } } - - + + LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; legacy->mDownCallback = callback; @@ -1381,10 +1381,10 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, } // static -void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, +void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, LLAssetType::EType type, - void *user_data, - S32 status, + void *user_data, + S32 status, LLExtStat ext_status) { LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; @@ -1403,7 +1403,7 @@ void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, uuid.toString(uuid_str); filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); - LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ if (fp) { const S32 buf_size = 65536; @@ -1458,7 +1458,7 @@ void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::ET std::string filename(in_filename); if (filename.empty()) filename = ll_safe_string(file); - + // Create revised message - new_message = "in_message :: file:line" std::stringstream new_message; new_message << in_message << " :: " << filename << ":" << line; @@ -1531,7 +1531,7 @@ void LLAssetStorage::flushOldToxicAssets( bool force_it ) // Add an item to the toxic asset map void LLAssetStorage::markAssetToxic( const LLUUID& uuid ) -{ +{ if ( !uuid.isNull() ) { // Set the value to the current time. Creates a new entry if needed diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 7619b46fed..684e96883f 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llcorehttputil.cpp * @date 2014-08-25 * @brief Implementation of adapter and utility classes expanding the llcorehttp interfaces. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2014&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,7 +48,7 @@ namespace LLCoreHttpUtil const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; -namespace +namespace { const std::string HTTP_LOGBODY_KEY("HTTPLogBodyOnError"); @@ -87,9 +87,9 @@ void logMessageFail(std::string logAuth, std::string url, std::string message) } //========================================================================= -/// The HttpRequestPumper is a utility class. When constructed it will poll the +/// The HttpRequestPumper is a utility class. When constructed it will poll the /// supplied HttpRequest once per frame until it is destroyed. -/// +/// class HttpRequestPumper { public: @@ -261,7 +261,7 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons LLCore::HttpStatus status = response->getStatus(); if (status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_HANDLE_NOT_FOUND)) - { // A response came in for a canceled request and we have not processed the + { // A response came in for a canceled request and we have not processed the // cancel yet. Patience! return; } @@ -273,9 +273,9 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons LLCore::HttpStatus::type_enum_t errType = status.getType(); LL_INFOS() - << "Possible failure [" << status.toTerseString() << "] cannot "<< response->getRequestMethod() + << "Possible failure [" << status.toTerseString() << "] cannot "<< response->getRequestMethod() << " url '" << response->getRequestURL() - << "' because " << status.toString() + << "' because " << status.toString() << LL_ENDL; if ((errType >= 400) && (errType < 500)) { @@ -360,13 +360,13 @@ void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::str } //========================================================================= -/// The HttpCoroLLSDHandler is a specialization of the LLCore::HttpHandler for -/// interacting with coroutines. When the request is completed the response +/// The HttpCoroLLSDHandler is a specialization of the LLCore::HttpHandler for +/// interacting with coroutines. When the request is completed the response /// will be posted onto the supplied Event Pump. -/// +/// /// If the LLSD retrieved from through the HTTP connection is not in the form /// of a LLSD::map it will be returned as in an llsd["content"] element. -/// +/// /// The LLSD posted back to the coroutine will have the following additions: /// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status /// +- ["status"] - The status code associated with the HTTP call @@ -374,7 +374,7 @@ void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::str /// +- ["type"] - The LLCore::HttpStatus type associted with the HTTP call /// +- ["url"] - The URL used to make the call. /// +- ["headers"] - A map of name name value pairs with the HTTP headers. -/// +/// class HttpCoroLLSDHandler : public HttpCoroHandler { public: @@ -390,7 +390,7 @@ HttpCoroLLSDHandler::HttpCoroLLSDHandler(LLEventStream &reply): HttpCoroHandler(reply) { } - + LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) { @@ -424,7 +424,7 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: #endif if (!success) - { + { #if 1 // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); @@ -440,13 +440,13 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: status = LLCore::HttpStatus(499, "Failed to deserialize LLSD."); } #endif - // If we've gotten to this point and the result LLSD is still undefined + // If we've gotten to this point and the result LLSD is still undefined // either there was an issue deserializing the body or the response was // blank. Create an empty map to hold the result either way. result = LLSD::emptyMap(); } else if (!result.isMap()) - { // The results are not themselves a map. Move them down so that + { // The results are not themselves a map. Move them down so that // this method can return a map to the caller. // *TODO: Should it always do this? LLSD newResult = LLSD::emptyMap(); @@ -476,13 +476,13 @@ LLSD HttpCoroLLSDHandler::parseBody(LLCore::HttpResponse *response, bool &succes //======================================================================== -/// The HttpCoroRawHandler is a specialization of the LLCore::HttpHandler for -/// interacting with coroutines. -/// -/// In addition to the normal "http_results" the returned LLSD will contain +/// The HttpCoroRawHandler is a specialization of the LLCore::HttpHandler for +/// interacting with coroutines. +/// +/// In addition to the normal "http_results" the returned LLSD will contain /// an entry keyed with "raw" containing the unprocessed results of the HTTP /// call. -/// +/// class HttpCoroRawHandler : public HttpCoroHandler { public: @@ -515,9 +515,9 @@ LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:: #if 1 // This is the slower implementation. It is safe vis-a-vi the const_cast<> and modification // of a LLSD managed array but contains an extra (potentially large) copy. - // + // // *TODO: https://jira.secondlife.com/browse/MAINT-5221 - + LLSD::Binary data; data.reserve(size); bas >> std::noskipws; @@ -526,12 +526,12 @@ LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:: result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = data; #else - // This is disabled because it's dangerous. See the other case for an + // This is disabled because it's dangerous. See the other case for an // alternate implementation. // We create a new LLSD::Binary object and assign it to the result map. - // The LLSD has created it's own copy so we retrieve it asBinary and const cast + // The LLSD has created it's own copy so we retrieve it asBinary and const cast // the reference so that we can modify it. - // *TODO: This is potentially dangerous... but I am trying to avoid a potentially + // *TODO: This is potentially dangerous... but I am trying to avoid a potentially // large copy. result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = LLSD::Binary(); LLSD::Binary &data = const_cast( result[HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary() ); @@ -551,13 +551,13 @@ LLSD HttpCoroRawHandler::parseBody(LLCore::HttpResponse *response, bool &success } //======================================================================== -/// The HttpCoroJSONHandler is a specialization of the LLCore::HttpHandler for -/// interacting with coroutines. -/// -/// In addition to the normal "http_results" the returned LLSD will contain -/// JSON entries will be converted into an LLSD map. All results are considered +/// The HttpCoroJSONHandler is a specialization of the LLCore::HttpHandler for +/// interacting with coroutines. +/// +/// In addition to the normal "http_results" the returned LLSD will contain +/// JSON entries will be converted into an LLSD map. All results are considered /// strings -/// +/// class HttpCoroJSONHandler : public HttpCoroHandler { public: @@ -692,7 +692,7 @@ LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = requestPostWithLLSD(request, mPolicyId, url, body, options, headers, @@ -730,7 +730,7 @@ LLSD HttpCoroutineAdapter::postRawAndSuspend(LLCore::HttpRequest::ptr_t request, return postAndSuspend_(request, url, rawbody, options, headers, httpHandler); } -// *TODO: This functionality could be moved into the LLCore::Http library itself +// *TODO: This functionality could be moved into the LLCore::Http library itself // by having the CURL layer read the file directly. LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request, const std::string & url, std::string fileName, @@ -759,7 +759,7 @@ LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request return postAndSuspend(request, url, fileData, options, headers); } -// *TODO: This functionality could be moved into the LLCore::Http library itself +// *TODO: This functionality could be moved into the LLCore::Http library itself // by having the CURL layer read the file directly. LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request, const std::string & url, LLUUID assetId, LLAssetType::EType assetType, @@ -776,7 +776,7 @@ LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request U8* fileBuffer; fileBuffer = new U8[fileSize]; vfile.read(fileBuffer, fileSize); - + outs.write((char*)fileBuffer, fileSize); delete[] fileBuffer; } @@ -816,7 +816,7 @@ LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = request->requestPost(mPolicyId, url, rawbody.get(), options, headers, handler); @@ -873,7 +873,7 @@ LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = requestPutWithLLSD(request, mPolicyId, url, body, options, headers, @@ -900,7 +900,7 @@ LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = request->requestPut(mPolicyId, url, rawbody.get(), options, headers, handler); @@ -950,13 +950,13 @@ LLSD HttpCoroutineAdapter::getJsonAndSuspend(LLCore::HttpRequest::ptr_t request, LLSD HttpCoroutineAdapter::getAndSuspend_(LLCore::HttpRequest::ptr_t &request, const std::string & url, - LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, + LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler) { HttpRequestPumper pumper(request); checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = request->requestGet(mPolicyId, url, options, headers, handler); @@ -985,7 +985,7 @@ LLSD HttpCoroutineAdapter::deleteAndSuspend(LLCore::HttpRequest::ptr_t request, } LLSD HttpCoroutineAdapter::deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request, - const std::string & url, + const std::string & url, LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) { LLEventStream replyPump(mAdapterName + "Reply", true); @@ -996,13 +996,13 @@ LLSD HttpCoroutineAdapter::deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t reque LLSD HttpCoroutineAdapter::deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request, - const std::string & url, LLCore::HttpOptions::ptr_t &options, + const std::string & url, LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler) { HttpRequestPumper pumper(request); checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = request->requestDelete(mPolicyId, url, options, headers, handler); @@ -1039,7 +1039,7 @@ LLSD HttpCoroutineAdapter::patchAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. LLCore::HttpHandle hhandle = requestPatchWithLLSD(request, mPolicyId, url, body, options, headers, @@ -1073,7 +1073,7 @@ LLSD HttpCoroutineAdapter::copyAndSuspend(LLCore::HttpRequest::ptr_t request, LLSD HttpCoroutineAdapter::copyAndSuspend_(LLCore::HttpRequest::ptr_t &request, - const std::string & url, + const std::string & url, LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler) { @@ -1081,9 +1081,9 @@ LLSD HttpCoroutineAdapter::copyAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. - // + // LLCore::HttpHandle hhandle = request->requestCopy(mPolicyId, url, options, headers, handler); @@ -1123,9 +1123,9 @@ LLSD HttpCoroutineAdapter::moveAndSuspend_(LLCore::HttpRequest::ptr_t &request, checkDefaultHeaders(headers); - // The HTTPCoroHandler does not self delete, so retrieval of a the contained + // The HTTPCoroHandler does not self delete, so retrieval of a the contained // pointer from the smart pointer is safe in this case. - // + // LLCore::HttpHandle hhandle = request->requestMove(mPolicyId, url, options, headers, handler); @@ -1174,7 +1174,7 @@ void HttpCoroutineAdapter::cancelSuspendedOperation() } } -void HttpCoroutineAdapter::saveState(LLCore::HttpHandle yieldingHandle, +void HttpCoroutineAdapter::saveState(LLCore::HttpHandle yieldingHandle, LLCore::HttpRequest::ptr_t &request, HttpCoroHandler::ptr_t &handler) { mWeakRequest = request; @@ -1190,15 +1190,15 @@ void HttpCoroutineAdapter::cleanState() } /*static*/ -LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, - const std::string &url) +LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, + const std::string &url) { LLCore::HttpStatus status = request->getStatus(); LL_WARNS("CoreHTTP") << "Error posting to " << url << " Status=" << status.getStatus() << " message = " << status.getMessage() << LL_ENDL; - // Mimic the status results returned from an http error that we had - // to wait on + // Mimic the status results returned from an http error that we had + // to wait on LLSD httpresults = LLSD::emptyMap(); HttpCoroHandler::writeStatusCodes(status, url, httpresults); @@ -1228,7 +1228,7 @@ void HttpCoroutineAdapter::callbackHttpGet(const std::string &url, LLCore::HttpR /*static*/ void HttpCoroutineAdapter::messageHttpGet(const std::string &url, const std::string &success, const std::string &failure) { - completionCallback_t cbSuccess = (success.empty()) ? NULL : + completionCallback_t cbSuccess = (success.empty()) ? NULL : static_cast(boost::bind(&logMessageSuccess, "HttpCoroutineAdapter", url, success)); completionCallback_t cbFailure = (failure.empty()) ? NULL : static_cast(boost::bind(&logMessageFail, "HttpCoroutineAdapter", url, failure)); @@ -1253,7 +1253,7 @@ void HttpCoroutineAdapter::trivialGetCoro(std::string url, LLCore::HttpRequest:: LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (!status) - { + { if (failure) { failure(httpResults); -- cgit v1.2.3 From 2ea5ac0c43e3e28d2b1774f5367d099271a1da32 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 1 Jul 2024 13:34:50 +0200 Subject: #1111 Remove xmlrpc-epi --- indra/llmessage/CMakeLists.txt | 3 - indra/llmessage/llfiltersd2xmlrpc.cpp | 778 ---------------------------------- indra/llmessage/llfiltersd2xmlrpc.h | 271 ------------ 3 files changed, 1052 deletions(-) delete mode 100644 indra/llmessage/llfiltersd2xmlrpc.cpp delete mode 100644 indra/llmessage/llfiltersd2xmlrpc.h (limited to 'indra/llmessage') diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 5322139304..b2757a7306 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -27,7 +27,6 @@ set(llmessage_SOURCE_FILES lldatapacker.cpp lldispatcher.cpp llexperiencecache.cpp - llfiltersd2xmlrpc.cpp llgenericstreamingmessage.cpp llhost.cpp llhttpnode.cpp @@ -111,7 +110,6 @@ set(llmessage_HEADER_FILES lleventflags.h llexperiencecache.h llextendedstatus.h - llfiltersd2xmlrpc.h llfollowcamparams.h llgenericstreamingmessage.h llhost.h @@ -193,7 +191,6 @@ target_link_libraries( llfilesystem llmath llcorehttp - ll::xmlrpc-epi ) target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp deleted file mode 100644 index 84b56d54bf..0000000000 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ /dev/null @@ -1,778 +0,0 @@ -/** - * @file llfiltersd2xmlrpc.cpp - * @author Phoenix - * @date 2005-04-26 - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -/** - * xml rpc request: - * - * - * examples.getStateName - * 41 - * - * - * - * xml rpc response: - * - * - * - * South Dakota - * - * - * - * xml rpc fault: - * - * - * - * - * faultCode4 - * faultString... - * - * - * - * - * llsd rpc request: - * - * { 'method':'...', 'parameter':...]} - * - * - * llsd rpc response: - * - * { 'response':... } - * - * - * llsd rpc fault: - * - * { 'fault': {'code':i..., 'description':'...'} } - * - * - */ - -#include "linden_common.h" -#include "llfiltersd2xmlrpc.h" - -#include -#include - -#ifdef LL_USESYSTEMLIBS -#include -#else -#include -#endif - -#include "apr_base64.h" - -#include "llbuffer.h" -#include "llbufferstream.h" -#include "llfasttimer.h" -#include "llmemorystream.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "lluuid.h" - -// spammy mode -//#define LL_SPEW_STREAM_OUT_DEBUGGING 1 - -/** - * String constants - */ -static const char XML_HEADER[] = ""; -static const char XMLRPC_REQUEST_HEADER_1[] = ""; -static const char XMLRPC_REQUEST_HEADER_2[] = ""; -static const char XMLRPC_REQUEST_FOOTER[] = ""; -static const char XMLRPC_METHOD_RESPONSE_HEADER[] = ""; -static const char XMLRPC_METHOD_RESPONSE_FOOTER[] = ""; -static const char XMLRPC_RESPONSE_HEADER[] = ""; -static const char XMLRPC_RESPONSE_FOOTER[] = ""; -static const char XMLRPC_FAULT_1[] = "faultCode"; -static const char XMLRPC_FAULT_2[] = "faultString"; -static const char XMLRPC_FAULT_3[] = ""; -static const char LLSDRPC_RESPONSE_HEADER[] = "{'response':"; -static const char LLSDRPC_RESPONSE_FOOTER[] = "}"; -const char LLSDRPC_REQUEST_HEADER_1[] = "{'method':'"; -const char LLSDRPC_REQUEST_HEADER_2[] = "', 'parameter': "; -const char LLSDRPC_REQUEST_FOOTER[] = "}"; -static const char LLSDRPC_FAULT_HADER_1[] = "{ 'fault': {'code':i"; -static const char LLSDRPC_FAULT_HADER_2[] = ", 'description':"; -static const char LLSDRPC_FAULT_FOOTER[] = "} }"; -static const S32 DEFAULT_PRECISION = 20; - -/** - * LLFilterSD2XMLRPC - */ -LLFilterSD2XMLRPC::LLFilterSD2XMLRPC() -{ -} - -LLFilterSD2XMLRPC::~LLFilterSD2XMLRPC() -{ -} - -std::string xml_escape_string(const std::string& in) -{ - std::ostringstream out; - std::string::const_iterator it = in.begin(); - std::string::const_iterator end = in.end(); - for(; it != end; ++it) - { - switch((*it)) - { - case '<': - out << "<"; - break; - case '>': - out << ">"; - break; - case '&': - out << "&"; - break; - case '\'': - out << "'"; - break; - case '"': - out << """; - break; - default: - out << (*it); - break; - } - } - return out.str(); -} - -void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) -{ - ostr << ""; - switch(sd.type()) - { - case LLSD::TypeMap: - { -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(map) BEGIN" << LL_ENDL; -#endif - ostr << ""; - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing struct" << LL_ENDL; - } - LLSD::map_const_iterator it = sd.beginMap(); - LLSD::map_const_iterator end = sd.endMap(); - for(; it != end; ++it) - { - ostr << "" << xml_escape_string((*it).first) - << ""; - streamOut(ostr, (*it).second); - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing '" << (*it).first - << "' with sd type " << (*it).second.type() << LL_ENDL; - } - ostr << ""; - } - ostr << ""; -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(map) END" << LL_ENDL; -#endif - break; - } - case LLSD::TypeArray: - { -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(array) BEGIN" << LL_ENDL; -#endif - ostr << ""; - LLSD::array_const_iterator it = sd.beginArray(); - LLSD::array_const_iterator end = sd.endArray(); - for(; it != end; ++it) - { - streamOut(ostr, *it); - if(ostr.fail()) - { - LL_INFOS() << "STREAM FAILURE writing array element sd type " - << (*it).type() << LL_ENDL; - } - } -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(array) END" << LL_ENDL; -#endif - ostr << ""; - break; - } - case LLSD::TypeUndefined: - // treat undefined as a bool with a false value. - case LLSD::TypeBoolean: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(bool)" << LL_ENDL; -#endif - ostr << "" << (sd.asBoolean() ? "1" : "0") << ""; - break; - case LLSD::TypeInteger: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(int)" << LL_ENDL; -#endif - ostr << "" << sd.asInteger() << ""; - break; - case LLSD::TypeReal: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(real)" << LL_ENDL; -#endif - ostr << "" << sd.asReal() << ""; - break; - case LLSD::TypeString: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(string)" << LL_ENDL; -#endif - ostr << "" << xml_escape_string(sd.asString()) << ""; - break; - case LLSD::TypeUUID: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(uuid)" << LL_ENDL; -#endif - // serialize it as a string - ostr << "" << sd.asString() << ""; - break; - case LLSD::TypeURI: - { -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(uri)" << LL_ENDL; -#endif - // serialize it as a string - ostr << "" << xml_escape_string(sd.asString()) << ""; - break; - } - case LLSD::TypeBinary: - { -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(binary)" << LL_ENDL; -#endif - // this is pretty inefficient, but we'll deal with that - // problem when it becomes one. - ostr << ""; - LLSD::Binary buffer = sd.asBinary(); - if(!buffer.empty()) - { - // *TODO: convert to LLBase64 - 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], - static_cast(buffer.size())); - ostr.write(b64_buffer, b64_buffer_length - 1); - delete[] b64_buffer; - } - ostr << ""; - break; - } - case LLSD::TypeDate: -#if LL_SPEW_STREAM_OUT_DEBUGGING - LL_INFOS() << "streamOut(date)" << LL_ENDL; -#endif - // no need to escape this since it will be alpha-numeric. - ostr << "" << sd.asString() << ""; - break; - default: - // unhandled type - LL_WARNS() << "Unhandled structured data type: " << sd.type() - << LL_ENDL; - break; - } - ostr << ""; -} - -/** - * LLFilterSD2XMLRPCResponse - */ - -LLFilterSD2XMLRPCResponse::LLFilterSD2XMLRPCResponse() -{ -} - -LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse() -{ -} - - -// virtual -LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) -{ - LL_PROFILE_ZONE_SCOPED; - - PUMP_DEBUG; - // This pipe does not work if it does not have everyting. This - // could be addressed by making a stream parser for llsd which - // handled partial information. - if(!eos) - { - return STATUS_BREAK; - } - - PUMP_DEBUG; - // we have everyting in the buffer, so turn the structure data rpc - // response into an xml rpc response. - LLBufferStream stream(channels, buffer.get()); - stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER; - LLSD sd; - LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); - - PUMP_DEBUG; - LLIOPipe::EStatus rv = STATUS_ERROR; - if(sd.has("response")) - { - PUMP_DEBUG; - // it is a normal response. pack it up and ship it out. - stream.precision(DEFAULT_PRECISION); - stream << XMLRPC_RESPONSE_HEADER; - streamOut(stream, sd["response"]); - stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER; - rv = STATUS_DONE; - } - else if(sd.has("fault")) - { - PUMP_DEBUG; - // it is a fault. - stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger() - << XMLRPC_FAULT_2 - << xml_escape_string(sd["fault"]["description"].asString()) - << XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER; - rv = STATUS_DONE; - } - else - { - LL_WARNS() << "Unable to determine the type of LLSD response." << LL_ENDL; - } - PUMP_DEBUG; - return rv; -} - -/** - * LLFilterSD2XMLRPCRequest - */ -LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest() -{ -} - -LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest(const char* method) -{ - if(method) - { - mMethod.assign(method); - } -} - -LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest() -{ -} - -// virtual -LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) -{ - LL_PROFILE_ZONE_SCOPED; - // This pipe does not work if it does not have everyting. This - // could be addressed by making a stream parser for llsd which - // handled partial information. - PUMP_DEBUG; - if(!eos) - { - LL_INFOS() << "!eos" << LL_ENDL; - return STATUS_BREAK; - } - - // See if we can parse it - LLBufferStream stream(channels, buffer.get()); - LLSD sd; - LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); - if(stream.fail()) - { - LL_INFOS() << "STREAM FAILURE reading structure data." << LL_ENDL; - } - - PUMP_DEBUG; - // We can get the method and parameters from either the member - // function or passed in via the buffer. We prefer the buffer if - // we found a parameter and a method, or fall back to using - // mMethod and putting everyting in the buffer into the parameter. - std::string method; - LLSD param_sd; - if(sd.has("method") && sd.has("parameter")) - { - method = sd["method"].asString(); - param_sd = sd["parameter"]; - } - else - { - method = mMethod; - param_sd = sd; - } - if(method.empty()) - { - LL_WARNS() << "SD -> XML Request no method found." << LL_ENDL; - return STATUS_ERROR; - } - - PUMP_DEBUG; - // We have a method, and some kind of parameter, so package it up - // and send it out. - LLBufferStream ostream(channels, buffer.get()); - ostream.precision(DEFAULT_PRECISION); - if(ostream.fail()) - { - LL_INFOS() << "STREAM FAILURE setting precision" << LL_ENDL; - } - ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1 - << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2; - if(ostream.fail()) - { - LL_INFOS() << "STREAM FAILURE writing method headers" << LL_ENDL; - } - switch(param_sd.type()) - { - case LLSD::TypeMap: - // If the params are a map, then we do not want to iterate - // through them since the iterators returned will be map - // ordered un-named values, which will lose the names, and - // only stream the values, turning it into an array. - ostream << ""; - streamOut(ostream, param_sd); - ostream << ""; - break; - case LLSD::TypeArray: - { - - LLSD::array_iterator it = param_sd.beginArray(); - LLSD::array_iterator end = param_sd.endArray(); - for(; it != end; ++it) - { - ostream << ""; - streamOut(ostream, *it); - ostream << ""; - } - break; - } - default: - ostream << ""; - streamOut(ostream, param_sd); - ostream << ""; - break; - } - - stream << XMLRPC_REQUEST_FOOTER; - return STATUS_DONE; -} - -/** - * LLFilterXMLRPCResponse2LLSD - */ -// this is a c function here since it's really an implementation -// detail that requires a header file just get the definition of the -// parameters. -LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value) -{ - XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value); - LLIOPipe::EStatus status = LLIOPipe::STATUS_OK; - switch(type) - { - case xmlrpc_type_base64: - { - S32 len = XMLRPC_GetValueStringLen(value); - const char* buf = XMLRPC_GetValueBase64(value); - ostr << " b("; - if((len > 0) && buf) - { - ostr << len << ")\""; - ostr.write(buf, len); - ostr << "\""; - } - else - { - ostr << "0)\"\""; - } - break; - } - case xmlrpc_type_boolean: - //LL_DEBUGS() << "stream_out() bool" << LL_ENDL; - ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false"); - break; - case xmlrpc_type_datetime: - ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\""; - break; - case xmlrpc_type_double: - ostr << " r" << XMLRPC_GetValueDouble(value); - //LL_DEBUGS() << "stream_out() double" << XMLRPC_GetValueDouble(value) - // << LL_ENDL; - break; - case xmlrpc_type_int: - ostr << " i" << XMLRPC_GetValueInt(value); - //LL_DEBUGS() << "stream_out() integer:" << XMLRPC_GetValueInt(value) - // << LL_ENDL; - break; - case xmlrpc_type_string: - //LL_DEBUGS() << "stream_out() string: " << str << LL_ENDL; - ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'" - << XMLRPC_GetValueString(value) << "'"; - break; - case xmlrpc_type_array: // vector - case xmlrpc_type_mixed: // vector - { - //LL_DEBUGS() << "stream_out() array" << LL_ENDL; - ostr << " ["; - U32 needs_comma = 0; - XMLRPC_VALUE current = XMLRPC_VectorRewind(value); - while(current && (LLIOPipe::STATUS_OK == status)) - { - if(needs_comma++) ostr << ","; - status = stream_out(ostr, current); - current = XMLRPC_VectorNext(value); - } - ostr << "]"; - break; - } - case xmlrpc_type_struct: // still vector - { - //LL_DEBUGS() << "stream_out() struct" << LL_ENDL; - ostr << " {"; - std::string name; - U32 needs_comma = 0; - XMLRPC_VALUE current = XMLRPC_VectorRewind(value); - while(current && (LLIOPipe::STATUS_OK == status)) - { - if(needs_comma++) ostr << ","; - name.assign(XMLRPC_GetValueID(current)); - ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':"; - status = stream_out(ostr, current); - current = XMLRPC_VectorNext(value); - } - ostr << "}"; - break; - } - case xmlrpc_type_empty: - case xmlrpc_type_none: - default: - status = LLIOPipe::STATUS_ERROR; - LL_WARNS() << "Found an empty xmlrpc type.." << LL_ENDL; - // not much we can do here... - break; - }; - return status; -} - -LLFilterXMLRPCResponse2LLSD::LLFilterXMLRPCResponse2LLSD() -{ -} - -LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD() -{ -} - -LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) -{ - LL_PROFILE_ZONE_SCOPED; - - PUMP_DEBUG; - if(!eos) return STATUS_BREAK; - if(!buffer) return STATUS_ERROR; - - PUMP_DEBUG; - // *FIX: This technique for reading data is far from optimal. We - // need to have some kind of istream interface into the xml - // parser... - S32 bytes = buffer->countAfter(channels.in(), NULL); - if(!bytes) return STATUS_ERROR; - char* buf = new char[bytes + 1]; - buf[bytes] = '\0'; - buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); - - //LL_DEBUGS() << "xmlrpc response: " << buf << LL_ENDL; - - PUMP_DEBUG; - XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML( - buf, - bytes, - NULL); - if(!response) - { - LL_WARNS() << "XML -> SD Response unable to parse xml." << LL_ENDL; - delete[] buf; - return STATUS_ERROR; - } - - PUMP_DEBUG; - LLBufferStream stream(channels, buffer.get()); - stream.precision(DEFAULT_PRECISION); - if(XMLRPC_ResponseIsFault(response)) - { - PUMP_DEBUG; - stream << LLSDRPC_FAULT_HADER_1 - << XMLRPC_GetResponseFaultCode(response) - << LLSDRPC_FAULT_HADER_2; - const char* fault_str = XMLRPC_GetResponseFaultString(response); - std::string fault_string; - if(fault_str) - { - fault_string.assign(fault_str); - } - stream << "'" << LLSDNotationFormatter::escapeString(fault_string) - << "'" <countAfter(channels.in(), NULL); - if(!bytes) return STATUS_ERROR; - char* buf = new char[bytes + 1]; - buf[bytes] = '\0'; - buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); - - //LL_DEBUGS() << "xmlrpc request: " << buf << LL_ENDL; - - // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if - // values that are less than 0x20 are passed to it, except - // 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage - U8* cur_pBuf = (U8*)buf; - U8 cur_char; - for (S32 i=0; i SD Request process parse error." << LL_ENDL; - delete[] buf; - return STATUS_ERROR; - } - - PUMP_DEBUG; - LLBufferStream stream(channels, buffer.get()); - stream.precision(DEFAULT_PRECISION); - const char* name = XMLRPC_RequestGetMethodName(request); - stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "") - << LLSDRPC_REQUEST_HEADER_2; - XMLRPC_VALUE param = XMLRPC_RequestGetData(request); - if(param) - { - PUMP_DEBUG; - S32 size = XMLRPC_VectorSize(param); - if(size > 1) - { - // if there are multiple parameters, stuff the values into - // an array so that the next step in the chain can read them. - stream << "["; - } - XMLRPC_VALUE current = XMLRPC_VectorRewind(param); - bool needs_comma = false; - while(current) - { - if(needs_comma) - { - stream << ","; - } - needs_comma = true; - stream_out(stream, current); - current = XMLRPC_VectorNext(param); - } - if(size > 1) - { - // close the array - stream << "]"; - } - } - stream << LLSDRPC_REQUEST_FOOTER; - XMLRPC_RequestFree(request, 1); - delete[] buf; - PUMP_DEBUG; - return STATUS_DONE; -} - diff --git a/indra/llmessage/llfiltersd2xmlrpc.h b/indra/llmessage/llfiltersd2xmlrpc.h deleted file mode 100644 index 55938d3e2b..0000000000 --- a/indra/llmessage/llfiltersd2xmlrpc.h +++ /dev/null @@ -1,271 +0,0 @@ -/** - * @file llfiltersd2xmlrpc.h - * @author Phoenix - * @date 2005-04-26 - * - * $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_LLFILTERSD2XMLRPC_H -#define LL_LLFILTERSD2XMLRPC_H - -/** - * These classes implement the necessary pipes for translating between - * xmlrpc and llsd rpc. The llsd rpcs mechanism was developed as an - * extensible and easy to parse serialization grammer which maintains - * a time efficient in-memory representation. - */ - -#include -#include "lliopipe.h" - -/** - * @class LLFilterSD2XMLRPC - * @brief Filter from serialized LLSD to an XMLRPC method call - * - * This clas provides common functionality for the LLFilterSD2XMLRPRC - * request and response classes. - */ -class LLFilterSD2XMLRPC : public LLIOPipe -{ -public: - LLFilterSD2XMLRPC(); - virtual ~LLFilterSD2XMLRPC(); - -protected: - /** - * @brief helper method - */ - void streamOut(std::ostream& ostr, const LLSD& sd); -}; - -/** - * @class LLFilterSD2XMLRPCResponse - * @brief Filter from serialized LLSD to an XMLRPC response - * - * This class filters a serialized LLSD object to an xmlrpc - * repsonse. Since resonses are limited to a single param, the xmlrprc - * response only serializes it as one object. - * This class correctly handles normal llsd responses as well as llsd - * rpc faults. - * - * For example, if given: - * {'response':[ i200, r3.4, {"foo":"bar"} ]} - * Would generate: - * - * - * - * 200 - * 3.4 - * - * foobar - * - * - * - */ -class LLFilterSD2XMLRPCResponse : public LLFilterSD2XMLRPC -{ -public: - // constructor - LLFilterSD2XMLRPCResponse(); - - // destructor - virtual ~LLFilterSD2XMLRPCResponse(); - - /* @name LLIOPipe virtual implementations - */ - //@{ -protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} -}; - -/** - * @class LLFilterSD2XMLRPCRequest - * @brief Filter from serialized LLSD to an XMLRPC method call - * - * This class will accept any kind of serialized LLSD object, but you - * probably want to have an array on the outer boundary since this - * object will interpret each element in the top level LLSD as a - * parameter into the xmlrpc spec. - * - * For example, you would represent 3 params as: - * - * {'method'='foo', 'parameter':[i200, r3.4, {"foo":"bar"}]} - * - * To generate: - * - * - * - * 200 - * 3.4 - * - * foobar - * - * - * - * This class will accept 2 different kinds of encodings. The first - * just an array of params as long as you specify the method in the - * constructor. It will also accept a structured data in the form: - * {'method':'$method_name', 'parameter':[...] } In the latter form, the - * encoded 'method' will be used regardless of the construction of the - * object, and the 'parameter' will be used as parameter to the call. - */ -class LLFilterSD2XMLRPCRequest : public LLFilterSD2XMLRPC -{ -public: - // constructor - LLFilterSD2XMLRPCRequest(); - - // constructor - LLFilterSD2XMLRPCRequest(const char* method); - - // destructor - virtual ~LLFilterSD2XMLRPCRequest(); - - /* @name LLIOPipe virtual implementations - */ - //@{ -protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} - -protected: - // The method name of this request. - std::string mMethod; -}; - -/** - * @class LLFilterXMLRPCResponse2LLSD - * @brief Filter from serialized XMLRPC method response to LLSD - * - * The xmlrpc spec states that responses can only have one element - * which can be of any supported type. - * This takes in xml of the form: - * - * - * ok - * - * And processes it into: - * 'ok' - * - */ -class LLFilterXMLRPCResponse2LLSD : public LLIOPipe -{ -public: - // constructor - LLFilterXMLRPCResponse2LLSD(); - - // destructor - virtual ~LLFilterXMLRPCResponse2LLSD(); - - /* @name LLIOPipe virtual implementations - */ - //@{ -protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} - -protected: -}; - -/** - * @class LLFilterXMLRPCRequest2LLSD - * @brief Filter from serialized XMLRPC method call to LLSD - * - * This takes in xml of the form: - * - * - * repeat - * - * 4 - * ok - * - * - * And processes it into: - * { 'method':'repeat', 'params':[i4, 'ok'] } - */ -class LLFilterXMLRPCRequest2LLSD : public LLIOPipe -{ -public: - // constructor - LLFilterXMLRPCRequest2LLSD(); - - // destructor - virtual ~LLFilterXMLRPCRequest2LLSD(); - - /* @name LLIOPipe virtual implementations - */ - //@{ -protected: - /** - * @brief Process the data in buffer. - */ - virtual EStatus process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump); - //@} - -protected: -}; - -/** - * @brief This function takes string, and escapes it appropritately - * for inclusion as xml data. - */ -std::string xml_escape_string(const std::string& in); - -/** - * @brief Externally available constants - */ -extern const char LLSDRPC_REQUEST_HEADER_1[]; -extern const char LLSDRPC_REQUEST_HEADER_2[]; -extern const char LLSDRPC_REQUEST_FOOTER[]; - -#endif // LL_LLFILTERSD2XMLRPC_H -- cgit v1.2.3 From 08b933a0c67463f06f124420f16c8a3f7dc83f1f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 3 Jul 2024 17:42:24 -0500 Subject: #1870 Tune up for better experience on integrated intel with low memory (#1872) * More deterministic vsize calculation. Add control for choosing downscale method. * Quick hack to make GLTF preview work again --- indra/llmessage/llassetstorage.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 70a7a34a70..2de59c1b6a 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -484,6 +484,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, void *user_data, bool is_priority) { + LL_PROFILE_ZONE_SCOPED; + LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << LL_ENDL; @@ -529,6 +531,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, if (size > 0) { + LL_PROFILE_ZONE_NAMED("gad - file in cache"); // we've already got the file // theoretically, partial files w/o a pending request shouldn't happen // unless there's a weird error @@ -548,7 +551,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, } bool duplicate = false; - + LL_PROFILE_ZONE_NAMED("gad - check pending downloads"); // check to see if there's a pending download of this uuid already for (request_list_t::iterator iter = mPendingDownloads.begin(); iter != mPendingDownloads.end(); ++iter ) -- cgit v1.2.3 From 1296afd96a74877feb91690ec8dcd99b225554b8 Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Thu, 4 Jul 2024 13:02:34 -0400 Subject: Reduce LLSD::Binary temporaries --- indra/llmessage/llcorehttputil.cpp | 2 +- indra/llmessage/lltemplatemessagedispatcher.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 684e96883f..3fdc691141 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -523,7 +523,7 @@ LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:: bas >> std::noskipws; data.assign(std::istream_iterator(bas), std::istream_iterator()); - result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = data; + result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = std::move(data); #else // This is disabled because it's dangerous. See the other case for an diff --git a/indra/llmessage/lltemplatemessagedispatcher.cpp b/indra/llmessage/lltemplatemessagedispatcher.cpp index 0e709d6c75..edbeb4acc1 100644 --- a/indra/llmessage/lltemplatemessagedispatcher.cpp +++ b/indra/llmessage/lltemplatemessagedispatcher.cpp @@ -43,7 +43,7 @@ void LLTemplateMessageDispatcher::dispatch(const std::string& msg_name, const LLSD& message, LLHTTPNode::ResponsePtr responsep) { - std::vector data = message["body"]["binary-template-data"].asBinary(); + const LLSD::Binary& data = message["body"]["binary-template-data"].asBinary(); auto size = data.size(); if(size == 0) { @@ -53,11 +53,11 @@ void LLTemplateMessageDispatcher::dispatch(const std::string& msg_name, LLHost host; host = gMessageSystem->getSender(); - bool validate_message = mTemplateMessageReader.validateMessage(&(data[0]), static_cast(size), host, true); + bool validate_message = mTemplateMessageReader.validateMessage(data.data(), static_cast(size), host, true); if (validate_message) { - mTemplateMessageReader.readMessage(&(data[0]),host); + mTemplateMessageReader.readMessage(data.data(),host); } else { -- cgit v1.2.3 From 9fdca96f8bd2211a99fe88e57b70cbecefa20b6d Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 8 Jul 2024 20:27:14 +0200 Subject: Re-enable compiler warnings C4244 and C4396 except for lltracerecording.h and llunittype.h for now --- indra/llmessage/llbuffer.cpp | 16 ++++++++-------- indra/llmessage/llbufferstream.cpp | 4 ++-- indra/llmessage/llcircuit.cpp | 4 ++-- indra/llmessage/lliohttpserver.cpp | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index dc7115b167..3a4b493b26 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -142,7 +142,7 @@ LLHeapBuffer::~LLHeapBuffer() S32 LLHeapBuffer::bytesLeft() const { - return (mSize - (mNextFree - mBuffer)); + return (mSize - (S32)(mNextFree - mBuffer)); } // virtual @@ -371,11 +371,11 @@ LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address) return it; } S32 channel = (*it).getChannel(); - LLSegment segment1(channel, base, (address - base) + 1); + LLSegment segment1(channel, base, (S32)((address - base) + 1)); *it = segment1; segment_iterator_t rv = it; ++it; - LLSegment segment2(channel, address + 1, size - (address - base) - 1); + LLSegment segment2(channel, address + 1, (S32)(size - (address - base) - 1)); mSegments.insert(it, segment2); return rv; } @@ -424,7 +424,7 @@ LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter( segment = LLSegment( (*rv).getChannel(), address, - (*rv).size() - (address - (*rv).data())); + (*rv).size() - (S32)(address - (*rv).data())); } else { @@ -533,7 +533,7 @@ S32 LLBufferArray::countAfter(S32 channel, U8* start) const if(++start < ((*it).data() + (*it).size())) { // it's in the same segment - offset = start - (*it).data(); + offset = (S32)(start - (*it).data()); } else if(++it == end) { @@ -586,7 +586,7 @@ U8* LLBufferArray::readAfter( && (*it).isOnChannel(channel)) { // copy the data out of this segment - S32 bytes_in_segment = (*it).size() - (start - (*it).data()); + S32 bytes_in_segment = (*it).size() - (S32)(start - (*it).data()); bytes_to_copy = llmin(bytes_left, bytes_in_segment); memcpy(dest, start, bytes_to_copy); /*Flawfinder: ignore*/ len += bytes_to_copy; @@ -681,7 +681,7 @@ U8* LLBufferArray::seek( { if(delta > 0) { - S32 bytes_in_segment = (*it).size() - (start - (*it).data()); + S32 bytes_in_segment = (*it).size() - (S32)(start - (*it).data()); S32 local_delta = llmin(delta, bytes_in_segment); rv += local_delta; delta -= local_delta; @@ -689,7 +689,7 @@ U8* LLBufferArray::seek( } else { - S32 bytes_in_segment = start - (*it).data(); + S32 bytes_in_segment = (S32)(start - (*it).data()); S32 local_delta = llmin(llabs(delta), bytes_in_segment); rv -= local_delta; delta += local_delta; diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp index e51b489813..2c745f6fe4 100644 --- a/indra/llmessage/llbufferstream.cpp +++ b/indra/llmessage/llbufferstream.cpp @@ -273,7 +273,7 @@ streampos LLBufferStreamBuf::seekoff( } LLMutexLock lock(mBuffer->getMutex()); - address = mBuffer->seek(mChannels.in(), base_addr, off); + address = mBuffer->seek(mChannels.in(), base_addr, (S32)off); if(address) { LLBufferArray::segment_iterator_t iter; @@ -306,7 +306,7 @@ streampos LLBufferStreamBuf::seekoff( } LLMutexLock lock(mBuffer->getMutex()); - address = mBuffer->seek(mChannels.out(), base_addr, off); + address = mBuffer->seek(mChannels.out(), base_addr, (S32)off); if(address) { LLBufferArray::segment_iterator_t iter; diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index bf22f3d3f0..8f9c02bdca 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -525,13 +525,13 @@ void LLCircuitData::checkPeriodTime() F64Seconds period_length = mt_sec - mPeriodTime; if ( period_length > TARGET_PERIOD_LENGTH) { - F32 bps_in = F32Bits(mBytesInThisPeriod).value() / period_length.value(); + F32 bps_in = F32Bits(mBytesInThisPeriod).value() / (F32)period_length.value(); if (bps_in > mPeakBPSIn) { mPeakBPSIn = bps_in; } - F32 bps_out = F32Bits(mBytesOutThisPeriod).value() / period_length.value(); + F32 bps_out = F32Bits(mBytesOutThisPeriod).value() / (F32)period_length.value(); if (bps_out > mPeakBPSOut) { mPeakBPSOut = bps_out; diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index e562f09844..edc431e538 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -625,7 +625,7 @@ bool LLHTTPResponder::readHeaderLine( } return false; } - S32 offset = -((len - 1) - (newline - dest)); + S32 offset = -((len - 1) - (S32)(newline - dest)); ++newline; *newline = '\0'; mLastRead = buffer->seek(channels.in(), last, offset); -- cgit v1.2.3 From 3013424057d8963bb55eca4bd58a91c21e4395fc Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Sun, 21 Jul 2024 20:10:21 -0400 Subject: Fix rare shutdown crash in gCacheName --- indra/llmessage/llcachename.cpp | 33 ++++++++++++++++----------------- indra/llmessage/llcachename.h | 7 ++++--- 2 files changed, 20 insertions(+), 20 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 63ac46722a..64f660d0ce 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -53,7 +53,6 @@ const U32 PENDING_TIMEOUT_SECS = 5 * 60; // Globals LLCacheName* gCacheName = NULL; -std::map LLCacheName::sCacheName; /// --------------------------------------------------------------------------- /// class LLCacheNameEntry @@ -215,7 +214,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, std::map& default_names); boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback); void addPending(const LLUUID& id, const LLHost& host); @@ -247,9 +246,9 @@ LLCacheName::LLCacheName(LLMessageSystem* msg) LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host) : impl(* new Impl(msg)) { - sCacheName["waiting"] = "(Loading...)"; - sCacheName["nobody"] = "(nobody)"; - sCacheName["none"] = "(none)"; + mCacheName["waiting"] = "(Loading...)"; + mCacheName["nobody"] = "(nobody)"; + mCacheName["none"] = "(none)"; setUpstream(upstream_host); } @@ -274,7 +273,7 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg) LLCacheName::Impl::~Impl() { - for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); + std::for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); mCache.clear(); for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer()); mReplyQueue.clear(); @@ -402,11 +401,11 @@ 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, std::map& default_names) { if(id.isNull()) { - first = sCacheName["nobody"]; + first = default_names["nobody"]; last.clear(); return true; } @@ -420,7 +419,7 @@ bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::strin } else { - first = sCacheName["waiting"]; + first = default_names["waiting"]; last.clear(); if (!isRequestPending(id)) { @@ -434,8 +433,8 @@ bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::strin // static void LLCacheName::localizeCacheName(std::string key, std::string value) { - if (key!="" && value!= "" ) - sCacheName[key]=value; + if (!key.empty() && !value.empty()) + mCacheName[key]=value; else LL_WARNS()<< " Error localizing cache key " << key << " To "<< value< sCacheName; + void localizeCacheName(std::string key, std::string value); + private: + std::map mCacheName; class Impl; Impl& impl; -- cgit v1.2.3 From c7c7342ed3bc17fcef5b5fe0970859ac753a6639 Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Sun, 28 Jul 2024 13:03:25 -0400 Subject: Update boost to 1.85 and fix deprecation warnings --- indra/llmessage/llcorehttputil.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 3fdc691141..918a69be6f 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -585,7 +585,7 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: LLCore::BufferArrayStream bas(body); - boost::json::error_code ec; + boost::system::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. @@ -610,7 +610,7 @@ LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &succes LLCore::BufferArrayStream bas(body); - boost::json::error_code ec; + boost::system::error_code ec; boost::json::value jsonRoot = boost::json::parse(bas, ec); if (ec.failed()) { -- cgit v1.2.3 From 9e4185bf75edbbf313735be56b1aaefcf0d31299 Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Sun, 21 Jul 2024 20:10:21 -0400 Subject: Fix rare shutdown crash in gCacheName --- indra/llmessage/llcachename.cpp | 33 ++++++++++++++++----------------- indra/llmessage/llcachename.h | 7 ++++--- 2 files changed, 20 insertions(+), 20 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 63ac46722a..64f660d0ce 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -53,7 +53,6 @@ const U32 PENDING_TIMEOUT_SECS = 5 * 60; // Globals LLCacheName* gCacheName = NULL; -std::map LLCacheName::sCacheName; /// --------------------------------------------------------------------------- /// class LLCacheNameEntry @@ -215,7 +214,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, std::map& default_names); boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback); void addPending(const LLUUID& id, const LLHost& host); @@ -247,9 +246,9 @@ LLCacheName::LLCacheName(LLMessageSystem* msg) LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host) : impl(* new Impl(msg)) { - sCacheName["waiting"] = "(Loading...)"; - sCacheName["nobody"] = "(nobody)"; - sCacheName["none"] = "(none)"; + mCacheName["waiting"] = "(Loading...)"; + mCacheName["nobody"] = "(nobody)"; + mCacheName["none"] = "(none)"; setUpstream(upstream_host); } @@ -274,7 +273,7 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg) LLCacheName::Impl::~Impl() { - for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); + std::for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); mCache.clear(); for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer()); mReplyQueue.clear(); @@ -402,11 +401,11 @@ 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, std::map& default_names) { if(id.isNull()) { - first = sCacheName["nobody"]; + first = default_names["nobody"]; last.clear(); return true; } @@ -420,7 +419,7 @@ bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::strin } else { - first = sCacheName["waiting"]; + first = default_names["waiting"]; last.clear(); if (!isRequestPending(id)) { @@ -434,8 +433,8 @@ bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::strin // static void LLCacheName::localizeCacheName(std::string key, std::string value) { - if (key!="" && value!= "" ) - sCacheName[key]=value; + if (!key.empty() && !value.empty()) + mCacheName[key]=value; else LL_WARNS()<< " Error localizing cache key " << key << " To "<< value< sCacheName; + void localizeCacheName(std::string key, std::string value); + private: + std::map mCacheName; class Impl; Impl& impl; -- cgit v1.2.3 From b5e306f7d89e82984a37824a3640bd67a5c45d61 Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Wed, 14 Aug 2024 11:01:02 -0400 Subject: Enable /permissive- on MSVC for better standards conformance (#2251) * Enable /permissive- on MSVC for better C++ conformance and fix related errors * Clean up left over warning suppressions from old library or msvc versions --- indra/llmessage/llblowfishcipher.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llblowfishcipher.cpp b/indra/llmessage/llblowfishcipher.cpp index ed036e396d..3973565e22 100644 --- a/indra/llmessage/llblowfishcipher.cpp +++ b/indra/llmessage/llblowfishcipher.cpp @@ -88,7 +88,7 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) src_len)) { LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptUpdate failure" << LL_ENDL; - goto ERROR; + goto BF_ENCRYPT_ERROR; } // There may be some final data left to encrypt if the input is @@ -96,14 +96,14 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len)) { LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL; - goto ERROR; + goto BF_ENCRYPT_ERROR; } output_len += temp_len; EVP_CIPHER_CTX_free(context); return output_len; -ERROR: +BF_ENCRYPT_ERROR: EVP_CIPHER_CTX_free(context); return 0; } -- cgit v1.2.3 From 1d017b76292cf8c7afad34ec54d7401e2f1795e5 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 20 Aug 2024 08:28:35 -0400 Subject: Trim trailing blank line. --- indra/llmessage/message_string_table.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/message_string_table.cpp b/indra/llmessage/message_string_table.cpp index 6d2157eec9..084c373265 100644 --- a/indra/llmessage/message_string_table.cpp +++ b/indra/llmessage/message_string_table.cpp @@ -88,4 +88,3 @@ char* LLMessageStringTable::getString(const char *str) } return mString[hash_value]; } - -- cgit v1.2.3 From 9f7dd0177201fe080c287144b99a70125be1fb2b Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Tue, 20 Aug 2024 17:41:48 +0200 Subject: Clean up boost includes and remove compiler warning pragma for unreachable code in PCH (#2361) --- indra/llmessage/lliopipe.h | 1 - indra/llmessage/llservice.h | 64 --------------------------------------- indra/llmessage/llstoredmessage.h | 1 - 3 files changed, 66 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/lliopipe.h b/indra/llmessage/lliopipe.h index a58ee045c2..1887b5cd9a 100644 --- a/indra/llmessage/lliopipe.h +++ b/indra/llmessage/lliopipe.h @@ -30,7 +30,6 @@ #define LL_LLIOPIPE_H #include -#include #include "llwin32headerslean.h" #include "apr_poll.h" diff --git a/indra/llmessage/llservice.h b/indra/llmessage/llservice.h index 6c32fa8102..7853e357f9 100644 --- a/indra/llmessage/llservice.h +++ b/indra/llmessage/llservice.h @@ -31,72 +31,10 @@ #include #include -//#include -//#include -//#include "llframetimer.h" #include "lliopipe.h" #include "llchainio.h" -#if 0 -class LLServiceCreator; -/** - * intrusive pointer support - */ -namespace boost -{ - void intrusive_ptr_add_ref(LLServiceCreator* p); - void intrusive_ptr_release(LLServiceCreator* p); -}; -#endif - -/** - * @class LLServiceCreator - * @brief This class is an abstract base class for classes which create - * new LLService instances. - * - * Derive classes from this class which appropriately implement the - * operator() and destructor. - * @see LLService - */ -#if 0 -class LLServiceCreator -{ -public: - typedef boost::intrusive_ptr service_t; - virtual ~LLServiceCreator() {} - virtual service_t activate() = 0; - virtual void discard() = 0; - -protected: - LLServiceCreator() : mReferenceCount(0) - { - } - -private: - friend void boost::intrusive_ptr_add_ref(LLServiceCreator* p); - friend void boost::intrusive_ptr_release(LLServiceCreator* p); - U32 mReferenceCount; -}; -#endif - -#if 0 -namespace boost -{ - inline void intrusive_ptr_add_ref(LLServiceCreator* p) - { - ++p->mReferenceCount; - } - inline void intrusive_ptr_release(LLServiceCreator* p) - { - if(p && 0 == --p->mReferenceCount) - { - delete p; - } - } -}; -#endif - /** * @class LLService * @brief This class is the base class for the service classes. @@ -114,8 +52,6 @@ namespace boost class LLService : public LLIOPipe { public: - //typedef boost::intrusive_ptr creator_t; - //typedef boost::intrusive_ptr service_t; typedef std::shared_ptr creator_t; /** diff --git a/indra/llmessage/llstoredmessage.h b/indra/llmessage/llstoredmessage.h index 178b75ab04..2bd64fafd7 100644 --- a/indra/llmessage/llstoredmessage.h +++ b/indra/llmessage/llstoredmessage.h @@ -29,7 +29,6 @@ #include "linden_common.h" #include "llsd.h" -#include #include -- cgit v1.2.3 From 74205607b7e106f3b7566ef4a4b9c2fcdfa2f83e Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Fri, 13 Sep 2024 16:28:48 +0200 Subject: Clean up Windows build (#2562) * APR_DECLARE_STATIC and APU_DECLARE_STATIC gets already defined in APR.cmake * Move both _CRT_SECURE_NO_WARNINGS and _WINSOCK_DEPRECATED_NO_WARNINGS definitions to 00-Common.cmake * Always define WIN32_LEAN_AND_MEAN and include subset of Windows API by default * Remove llwin32headerslean.h and remove unnecessary WIN32_LEAN_AND_MEAN definition handling in llwin32headers.h * Clean up includes of Windows API headers * Get rid of workaround to link against IPHLPAPI.lib in lluuid.cpp - this seems to have been an issue in the past that has been fixed --- indra/llmessage/llhost.cpp | 3 +-- indra/llmessage/lliopipe.h | 2 +- indra/llmessage/lliosocket.h | 2 +- indra/llmessage/llmail.cpp | 1 - indra/llmessage/net.cpp | 2 +- 5 files changed, 4 insertions(+), 6 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llhost.cpp b/indra/llmessage/llhost.cpp index ace316512f..e7e3e27f58 100644 --- a/indra/llmessage/llhost.cpp +++ b/indra/llmessage/llhost.cpp @@ -31,8 +31,7 @@ #include "llerror.h" #if LL_WINDOWS - #define WIN32_LEAN_AND_MEAN - #include + #include #else #include #include // ntonl() diff --git a/indra/llmessage/lliopipe.h b/indra/llmessage/lliopipe.h index 1887b5cd9a..b40539f38c 100644 --- a/indra/llmessage/lliopipe.h +++ b/indra/llmessage/lliopipe.h @@ -30,7 +30,7 @@ #define LL_LLIOPIPE_H #include -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include "apr_poll.h" #include "llsd.h" diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index 0a3f2617e6..4b79c77b56 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -38,7 +38,7 @@ */ #include "lliopipe.h" -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include "apr_pools.h" #include "apr_network_io.h" #include "llchainio.h" diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 9e10a356db..b842aeda62 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -28,7 +28,6 @@ #include "llmail.h" -// APR on Windows needs full windows headers #include "llwin32headers.h" #include #include diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 1c49f9be36..f153c938cf 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -32,7 +32,7 @@ #include #if LL_WINDOWS -#include "llwin32headerslean.h" +#include "llwin32headers.h" #else #include #include -- cgit v1.2.3 From 13221f67c465017f44ca46aeca23b0d820935825 Mon Sep 17 00:00:00 2001 From: Leviathan Linden Date: Tue, 19 Sep 2023 09:40:08 -0700 Subject: add GameControl feature and SDL2 dependency --- indra/llmessage/message_prehash.cpp | 2 ++ indra/llmessage/message_prehash.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'indra/llmessage') diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index c264a9f086..d3b80d684f 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -1402,3 +1402,5 @@ char const* const _PREHASH_HoverHeight = LLMessageStringTable::getInstance()->ge char const* const _PREHASH_Experience = LLMessageStringTable::getInstance()->getString("Experience"); char const* const _PREHASH_ExperienceID = LLMessageStringTable::getInstance()->getString("ExperienceID"); char const* const _PREHASH_LargeGenericMessage = LLMessageStringTable::getInstance()->getString("LargeGenericMessage"); +char const* const _PREHASH_GameControlInput = LLMessageStringTable::getInstance()->getString("GameControlInput"); +char const* const _PREHASH_AxisData = LLMessageStringTable::getInstance()->getString("AxisData"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 1d30b69b67..5449eaf2a5 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -1403,5 +1403,7 @@ extern char const* const _PREHASH_HoverHeight; extern char const* const _PREHASH_Experience; extern char const* const _PREHASH_ExperienceID; extern char const* const _PREHASH_LargeGenericMessage; +extern char const* const _PREHASH_GameControlInput; +extern char const* const _PREHASH_AxisData; #endif -- cgit v1.2.3 From bd252f8151f777508efb15cfe2c69c9a103d98be Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Sat, 5 Oct 2024 07:07:01 +0200 Subject: Follow up for 39eb250 (#2815) --- indra/llmessage/patch_code.cpp | 1 - indra/llmessage/patch_dct.cpp | 1 - indra/llmessage/patch_idct.cpp | 1 - 3 files changed, 3 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/patch_code.cpp b/indra/llmessage/patch_code.cpp index 489b6ce6a6..9f9f4c852a 100644 --- a/indra/llmessage/patch_code.cpp +++ b/indra/llmessage/patch_code.cpp @@ -27,7 +27,6 @@ #include "linden_common.h" #include "llmath.h" -//#include "vmath.h" #include "v3math.h" #include "patch_dct.h" #include "patch_code.h" diff --git a/indra/llmessage/patch_dct.cpp b/indra/llmessage/patch_dct.cpp index 728fe84537..e74e5fd459 100644 --- a/indra/llmessage/patch_dct.cpp +++ b/indra/llmessage/patch_dct.cpp @@ -27,7 +27,6 @@ #include "linden_common.h" #include "llmath.h" -//#include "vmath.h" #include "v3math.h" #include "patch_dct.h" diff --git a/indra/llmessage/patch_idct.cpp b/indra/llmessage/patch_idct.cpp index 5483cf98c0..4bcc439917 100644 --- a/indra/llmessage/patch_idct.cpp +++ b/indra/llmessage/patch_idct.cpp @@ -27,7 +27,6 @@ #include "linden_common.h" #include "llmath.h" -//#include "vmath.h" #include "v3math.h" #include "patch_dct.h" -- cgit v1.2.3