summaryrefslogtreecommitdiff
path: root/indra/llmessage/message.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llmessage/message.cpp
Print done when done.
Diffstat (limited to 'indra/llmessage/message.cpp')
-rw-r--r--indra/llmessage/message.cpp5876
1 files changed, 5876 insertions, 0 deletions
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
new file mode 100644
index 0000000000..cdafafc8db
--- /dev/null
+++ b/indra/llmessage/message.cpp
@@ -0,0 +1,5876 @@
+/**
+ * @file message.cpp
+ * @brief LLMessageSystem class implementation
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "message.h"
+
+// system library includes
+#if !LL_WINDOWS
+// following header files required for inet_addr()
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <cstring>
+#include <time.h>
+#include <iomanip>
+#include <iterator>
+#include <sstream>
+
+#include "llapr.h"
+#include "apr-1/apr_portable.h"
+#include "apr-1/apr_network_io.h"
+#include "apr-1/apr_poll.h"
+
+// linden library headers
+#include "indra_constants.h"
+#include "lldir.h"
+#include "llerror.h"
+#include "llfasttimer.h"
+#include "llmd5.h"
+#include "llsd.h"
+#include "lltransfermanager.h"
+#include "lluuid.h"
+#include "llxfermanager.h"
+#include "timing.h"
+#include "llquaternion.h"
+#include "u64.h"
+#include "v3dmath.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "lltransfertargetvfile.h"
+
+// Constants
+//const char* MESSAGE_LOG_FILENAME = "message.log";
+static const F32 CIRCUIT_DUMP_TIMEOUT = 30.f;
+static const S32 TRUST_TIME_WINDOW = 3;
+
+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; }
+ 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) : mOffset(-1), 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 mOffset;
+ S32 mBlockNumber;
+ typedef LLDynamicArrayIndexed<LLMsgVarData, const char *, 8> msg_var_data_map_t;
+ msg_var_data_map_t mMemberVarData;
+ char *mName;
+ S32 mTotalSize;
+};
+
+
+class LLMsgData
+{
+public:
+ LLMsgData(const char *name) : mTotalSize(-1)
+ {
+ mName = (char *)name;
+ }
+ ~LLMsgData()
+ {
+ for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePairedPointer());
+ }
+
+ 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:
+ S32 mOffset;
+ typedef std::map<char*, LLMsgBlkData*> msg_blk_data_map_t;
+ msg_blk_data_map_t mMemberBlocks;
+ char *mName;
+ S32 mTotalSize;
+};
+
+inline void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S32 data_size)
+{
+ mSize = size;
+ mDataSize = data_size;
+ if ( (type != MVT_VARIABLE) && (type != MVT_FIXED)
+ && (mType != MVT_VARIABLE) && (mType != MVT_FIXED))
+ {
+ if (mType != type)
+ {
+ llwarns << "Type mismatch in addData for " << mName
+ << " message: " << gMessageSystem->getCurrentSMessageName()
+ << " block: " << gMessageSystem->getCurrentSBlockName()
+ << llendl;
+ }
+ }
+ if(size)
+ {
+ delete mData; // Delete it if it already exists
+ mData = new U8[size];
+ htonmemcpy(mData, data, mType, size);
+ }
+}
+
+
+
+inline void LLMsgData::addDataFast(char *blockname, char *varname, const void *data, S32 size, EMsgVariableType type, S32 data_size)
+{
+ // remember that if the blocknumber is > 0 then the number is appended to the name
+ char *namep = (char *)blockname;
+ LLMsgBlkData* block_data = mMemberBlocks[namep];
+ if (block_data->mBlockNumber)
+ {
+ namep += block_data->mBlockNumber;
+ block_data->addData(varname, data, size, type, data_size);
+ }
+ else
+ {
+ block_data->addData(varname, data, size, type, data_size);
+ }
+}
+
+// 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(char *name, const EMsgVariableType type, const S32 size) : mType(type), mSize(size)
+ {
+ mName = gMessageStringTable.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(char *name, EMsgBlockType type, S32 number = 1) : mType(type), mNumber(number), mTotalSize(0)
+ {
+ mName = gMessageStringTable.getString(name);
+ }
+
+ ~LLMessageBlock()
+ {
+ for_each(mMemberVariables.begin(), mMemberVariables.end(), DeletePairedPointer());
+ }
+
+ void addVariable(char *name, const EMsgVariableType type, const S32 size)
+ {
+ LLMessageVariable** varp = &mMemberVariables[name];
+ if (*varp != NULL)
+ {
+ llerrs << name << " has already been used as a variable name!" << llendl;
+ }
+ *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();
+ }
+
+ friend std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg);
+
+ typedef std::map<const char *, LLMessageVariable*> 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
+};
+
+class LLMessageTemplate
+{
+public:
+ LLMessageTemplate(const char *name, U32 message_number, EMsgFrequency freq)
+ :
+ //mMemberBlocks(),
+ mName(NULL),
+ mFrequency(freq),
+ mTrust(MT_NOTRUST),
+ mEncoding(ME_ZEROCODED),
+ 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 = gMessageStringTable.getString(name);
+ }
+
+ ~LLMessageTemplate()
+ {
+ for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePairedPointer());
+ }
+
+ void addBlock(LLMessageBlock *blockp)
+ {
+ LLMessageBlock** member_blockp = &mMemberBlocks[blockp->mName];
+ if (*member_blockp != NULL)
+ {
+ llerrs << "Block " << blockp->mName
+ << "has already been used as a block name!" << llendl;
+ }
+ *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)
+ {
+ return mTrust;
+ }
+
+ // controls for how the message should be encoded
+ void setEncoding(EMsgEncoding e)
+ {
+ mEncoding = e;
+ }
+ EMsgEncoding getEncoding()
+ {
+ return mEncoding;
+ }
+
+ void setHandlerFunc(void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data)
+ {
+ mHandlerFunc = handler_func;
+ mUserData = user_data;
+ }
+
+ BOOL callHandlerFunc(LLMessageSystem *msgsystem)
+ {
+ if (mHandlerFunc)
+ {
+ mHandlerFunc(msgsystem, mUserData);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ bool isBanned(bool trustedSource)
+ {
+ return trustedSource ? mBanFromTrusted : mBanFromUntrusted;
+ }
+
+ friend std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg);
+
+public:
+ typedef std::map<char*, LLMessageBlock*> message_block_map_t;
+ message_block_map_t mMemberBlocks;
+ char *mName;
+ EMsgFrequency mFrequency;
+ EMsgTrust mTrust;
+ EMsgEncoding mEncoding;
+ 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;
+};
+
+
+
+// static
+BOOL LLMessageSystem::mTimeDecodes = FALSE;
+
+// static, 50ms per message decode
+F32 LLMessageSystem::mTimeDecodesSpamThreshold = 0.05f;
+
+// FIXME: 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;
+};
+
+
+// LLMessageVariable functions and friends
+
+std::ostream& operator<<(std::ostream& s, LLMessageVariable &msg)
+{
+ s << "\t\t" << msg.mName << " (";
+ switch (msg.mType)
+ {
+ case MVT_FIXED:
+ s << "Fixed, " << msg.mSize << " bytes total)\n";
+ break;
+ case MVT_VARIABLE:
+ s << "Variable, " << msg.mSize << " bytes of size info)\n";
+ break;
+ default:
+ s << "Unknown\n";
+ break;
+ }
+ return s;
+}
+
+// LLMessageBlock functions and friends
+
+std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg)
+{
+ s << "\t" << msg.mName << " (";
+ switch (msg.mType)
+ {
+ case MBT_SINGLE:
+ s << "Fixed";
+ break;
+ case MBT_MULTIPLE:
+ s << "Multiple - " << msg.mNumber << " copies";
+ break;
+ case MBT_VARIABLE:
+ s << "Variable";
+ break;
+ default:
+ s << "Unknown";
+ break;
+ }
+ if (msg.mTotalSize != -1)
+ {
+ s << ", " << msg.mTotalSize << " bytes each, " << msg.mNumber*msg.mTotalSize << " bytes total)\n";
+ }
+ else
+ {
+ s << ")\n";
+ }
+
+
+ for (LLMessageBlock::message_variable_map_t::iterator iter = msg.mMemberVariables.begin();
+ iter != msg.mMemberVariables.end(); iter++)
+ {
+ LLMessageVariable& ci = *(iter->second);
+ s << ci;
+ }
+
+ return s;
+}
+
+// LLMessageTemplate functions and friends
+
+std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg)
+{
+ switch (msg.mFrequency)
+ {
+ case MFT_HIGH:
+ s << "========================================\n" << "Message #" << msg.mMessageNumber << "\n" << msg.mName << " (";
+ s << "High";
+ break;
+ case MFT_MEDIUM:
+ s << "========================================\n" << "Message #";
+ s << (msg.mMessageNumber & 0xFF) << "\n" << msg.mName << " (";
+ s << "Medium";
+ break;
+ case MFT_LOW:
+ s << "========================================\n" << "Message #";
+ s << (msg.mMessageNumber & 0xFFFF) << "\n" << msg.mName << " (";
+ s << "Low";
+ break;
+ default:
+ s << "Unknown";
+ break;
+ }
+
+ if (msg.mTotalSize != -1)
+ {
+ s << ", " << msg.mTotalSize << " bytes total)\n";
+ }
+ else
+ {
+ s << ")\n";
+ }
+
+ for (LLMessageTemplate::message_block_map_t::iterator iter = msg.mMemberBlocks.begin();
+ iter != msg.mMemberBlocks.end(); iter++)
+ {
+ LLMessageBlock* ci = iter->second;
+ s << *ci;
+ }
+
+ return s;
+}
+
+// LLMessageList functions and friends
+
+// 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(char *token, char *regexp)
+{
+ S32 tptr, rptr = 0;
+ S32 current_checker, next_checker = 0;
+
+ current_checker = get_checker_number(regexp[rptr++]);
+
+ if (current_checker == -1)
+ {
+ llerrs << "Invalid regular expression value!" << llendl;
+ return FALSE;
+ }
+
+ if (current_checker == 9999)
+ {
+ llerrs << "Regular expression can't start with *!" << llendl;
+ return FALSE;
+ }
+
+ for (tptr = 0; token[tptr]; tptr++)
+ {
+ if (current_checker == -1)
+ {
+ llerrs << "Input exceeds regular expression!\nDid you forget a *?" << llendl;
+ 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(char *token)
+{
+ if (!b_check_token(token, "fv*"))
+ {
+ llerrs << "Token '" << token << "' isn't a variable!" << llendl;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// An integer is made up of the digits 0-9 and may be preceded by a '-'
+BOOL b_integer_ok(char *token)
+{
+ if (!b_check_token(token, "sd*"))
+ {
+ llerrs << "Token isn't an integer!" << llendl;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// An integer is made up of the digits 0-9
+BOOL b_positive_integer_ok(char *token)
+{
+ if (!b_check_token(token, "d*"))
+ {
+ llerrs << "Token isn't an integer!" << llendl;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void LLMessageSystem::init()
+{
+ // initialize member variables
+ mVerboseLog = FALSE;
+
+ mbError = FALSE;
+ mErrorCode = 0;
+ mIncomingCompressedSize = 0;
+ mSendReliable = FALSE;
+
+ mbSBuilt = FALSE;
+ mbSClear = TRUE;
+
+ mUnackedListDepth = 0;
+ mUnackedListSize = 0;
+ mDSMaxListDepth = 0;
+
+ mCurrentRMessageData = NULL;
+ mCurrentRMessageTemplate = NULL;
+
+ mCurrentSMessageData = NULL;
+ mCurrentSMessageTemplate = NULL;
+ mCurrentSMessageName = NULL;
+
+ mCurrentRecvPacketID = 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;
+
+ mMessageFileChecksum = 0;
+ mMessageFileVersionNumber = 0.f;
+}
+
+LLMessageSystem::LLMessageSystem()
+{
+ init();
+
+ mSystemVersionMajor = 0;
+ mSystemVersionMinor = 0;
+ mSystemVersionPatch = 0;
+ mSystemVersionServer = 0;
+ mVersionFlags = 0x0;
+
+ // default to not accepting packets from not alive circuits
+ mbProtected = TRUE;
+
+ mSendPacketFailureCount = 0;
+ mCircuitPrintFreq = 0.f; // seconds
+
+ // initialize various bits of net info
+ mSocket = 0;
+ mPort = 0;
+
+ mPollInfop = NULL;
+
+ mResendDumpTime = 0;
+ mMessageCountTime = 0;
+ mCircuitPrintTime = 0;
+ mCurrentMessageTimeSeconds = 0;
+
+ // Constants for dumping output based on message processing time/count
+ mNumMessageCounts = 0;
+ mMaxMessageCounts = 0; // >= 0 means dump warnings
+ mMaxMessageTime = 0.f;
+
+ mTrueReceiveSize = 0;
+
+ // Error if checking this state, subclass methods which aren't implemented are delegated
+ // to properly constructed message system.
+ mbError = TRUE;
+}
+
+// Read file and build message templates
+LLMessageSystem::LLMessageSystem(const char *filename, U32 port,
+ S32 version_major,
+ S32 version_minor,
+ S32 version_patch)
+{
+ init();
+
+ mSystemVersionMajor = version_major;
+ mSystemVersionMinor = version_minor;
+ mSystemVersionPatch = version_patch;
+ mSystemVersionServer = 0;
+ mVersionFlags = 0x0;
+
+ // default to not accepting packets from not alive circuits
+ mbProtected = TRUE;
+
+ mSendPacketFailureCount = 0;
+
+ mCircuitPrintFreq = 60.f; // seconds
+
+ loadTemplateFile(filename);
+
+ // initialize various bits of net info
+ mSocket = 0;
+ mPort = port;
+
+ S32 error = start_net(mSocket, mPort);
+ if (error != 0)
+ {
+ mbError = TRUE;
+ mErrorCode = error;
+ }
+ //llinfos << << "*** port: " << mPort << llendl;
+
+ //
+ // Create the data structure that we can poll on
+ //
+ if (!gAPRPoolp)
+ {
+ llerrs << "No APR pool before message system initialization!" << llendl;
+ 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;
+
+ F64 mt_sec = getMessageTimeSeconds();
+ mResendDumpTime = mt_sec;
+ mMessageCountTime = mt_sec;
+ mCircuitPrintTime = mt_sec;
+ mCurrentMessageTimeSeconds = mt_sec;
+
+ // Constants for dumping output based on message processing time/count
+ mNumMessageCounts = 0;
+ mMaxMessageCounts = 200; // >= 0 means dump warnings
+ mMaxMessageTime = 1.f;
+
+ mTrueReceiveSize = 0;
+}
+
+// Read file and build message templates
+void LLMessageSystem::loadTemplateFile(const char* filename)
+{
+ if(!filename)
+ {
+ llerrs << "No template filename specified" << llendl;
+ }
+
+ char token[MAX_MESSAGE_INTERNAL_NAME_SIZE]; /* Flawfinder: ignore */
+
+ // state variables
+ BOOL b_template_start = TRUE;
+ BOOL b_template_end = FALSE;
+ BOOL b_template = FALSE;
+ BOOL b_block_start = FALSE;
+ BOOL b_block_end = FALSE;
+ BOOL b_block = FALSE;
+ BOOL b_variable_start = FALSE;
+ BOOL b_variable_end = FALSE;
+ BOOL b_variable = FALSE;
+ //BOOL b_in_comment_block = FALSE; // not yet used
+
+ // working temp variables
+ LLMessageTemplate *templatep = NULL;
+ char template_name[MAX_MESSAGE_INTERNAL_NAME_SIZE]; /* Flawfinder: ignore */
+
+ LLMessageBlock *blockp = NULL;
+ char block_name[MAX_MESSAGE_INTERNAL_NAME_SIZE]; /* Flawfinder: ignore */
+
+ LLMessageVariable var;
+ char var_name[MAX_MESSAGE_INTERNAL_NAME_SIZE]; /* Flawfinder: ignore */
+ char formatString[MAX_MESSAGE_INTERNAL_NAME_SIZE];
+
+ FILE* messagefilep = NULL;
+ mMessageFileChecksum = 0;
+ mMessageFileVersionNumber = 0.f;
+ S32 checksum_offset = 0;
+ char* checkp = NULL;
+
+ snprintf(formatString, sizeof(formatString), "%%%ds", MAX_MESSAGE_INTERNAL_NAME_SIZE);
+ messagefilep = LLFile::fopen(filename, "r");
+ if (messagefilep)
+ {
+// mName = gMessageStringTable.getString(filename);
+
+ fseek(messagefilep, 0L, SEEK_SET );
+ while(fscanf(messagefilep, formatString, token) != EOF)
+ {
+ // skip comments
+ if (token[0] == '/')
+ {
+ // skip to end of line
+ while (token[0] != 10)
+ fscanf(messagefilep, "%c", token);
+ continue;
+ }
+
+ checkp = token;
+
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // what are we looking for
+ if (!strcmp(token, "{"))
+ {
+ // is that a legit option?
+ if (b_template_start)
+ {
+ // yup!
+ b_template_start = FALSE;
+
+ // remember that it could be only a signal message, so name is all that it contains
+ b_template_end = TRUE;
+
+ // start working on it!
+ b_template = TRUE;
+ }
+ else if (b_block_start)
+ {
+ // yup!
+ b_block_start = FALSE;
+ b_template_end = FALSE;
+
+ // start working on it!
+ b_block = TRUE;
+ }
+ else if (b_variable_start)
+ {
+ // yup!
+ b_variable_start = FALSE;
+ b_block_end = FALSE;
+
+ // start working on it!
+ b_variable = TRUE;
+ }
+ else
+ {
+ llerrs << "Detcted unexpected token '" << token
+ << "' while parsing template." << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ }
+
+ if (!strcmp(token, "}"))
+ {
+ // is that a legit option?
+ if (b_template_end)
+ {
+ // yup!
+ b_template_end = FALSE;
+ b_template = FALSE;
+ b_block_start = FALSE;
+
+ // add data!
+ // we've gotten a complete variable! hooray!
+ // add it!
+ addTemplate(templatep);
+
+ //llinfos << "Read template: "templatep->mNametemp_str
+ // << llendl;
+
+ // look for next one!
+ b_template_start = TRUE;
+ }
+ else if (b_block_end)
+ {
+ // yup!
+ b_block_end = FALSE;
+ b_variable_start = FALSE;
+
+ // add data!
+ // we've gotten a complete variable! hooray!
+ // add it to template
+
+ templatep->addBlock(blockp);
+
+ // start working on it!
+ b_template_end = TRUE;
+ b_block_start = TRUE;
+ }
+ else if (b_variable_end)
+ {
+ // yup!
+ b_variable_end = FALSE;
+
+ // add data!
+ // we've gotten a complete variable! hooray!
+ // add it to block
+ blockp->addVariable(var.getName(), var.getType(), var.getSize());
+
+ // start working on it!
+ b_variable_start = TRUE;
+ b_block_end = TRUE;
+ }
+ else
+ {
+ llerrs << "Detcted unexpected token '" << token
+ << "' while parsing template." << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ }
+
+ // now, are we looking to start a template?
+ if (b_template)
+ {
+
+ b_template = FALSE;
+
+ // name first
+ if (fscanf(messagefilep, formatString, template_name) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected message template name, but file ended"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ // debugging to help figure out busted templates
+ //llinfos << template_name << llendl;
+
+ // is name a legit C variable name
+ if (!b_variable_ok(template_name))
+ {
+ // nope!
+ llerrs << "Not legal message template name: "
+ << template_name << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = template_name;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // ok, now get Frequency ("High", "Medium", or "Low")
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected message template frequency, found EOF."
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // which one is it?
+ if (!strcmp(token, "High"))
+ {
+ if (++mNumberHighFreqMessages == 255)
+ {
+ // oops, too many High Frequency messages!!
+ llerrs << "Message " << template_name
+ << " exceeded 254 High frequency messages!"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ // ok, we can create a template!
+ // message number is just mNumberHighFreqMessages
+ templatep = new LLMessageTemplate(template_name, mNumberHighFreqMessages, MFT_HIGH);
+ //lldebugs << "Template " << template_name << " # "
+ // << std::hex << mNumberHighFreqMessages
+ // << std::dec << " high"
+ // << llendl;
+ }
+ else if (!strcmp(token, "Medium"))
+ {
+ if (++mNumberMediumFreqMessages == 255)
+ {
+ // oops, too many Medium Frequency messages!!
+ llerrs << "Message " << template_name
+ << " exceeded 254 Medium frequency messages!"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ // ok, we can create a template!
+ // message number is ((255 << 8) | mNumberMediumFreqMessages)
+ templatep = new LLMessageTemplate(template_name, (255 << 8) | mNumberMediumFreqMessages, MFT_MEDIUM);
+ //lldebugs << "Template " << template_name << " # "
+ // << std::hex << mNumberMediumFreqMessages
+ // << std::dec << " medium"
+ // << llendl;
+ }
+ else if (!strcmp(token, "Low"))
+ {
+ if (++mNumberLowFreqMessages == 65535)
+ {
+ // oops, too many High Frequency messages!!
+ llerrs << "Message " << template_name
+ << " exceeded 65534 Low frequency messages!"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ // ok, we can create a template!
+ // message number is ((255 << 24) | (255 << 16) | mNumberLowFreqMessages)
+ templatep = new LLMessageTemplate(template_name, (255 << 24) | (255 << 16) | mNumberLowFreqMessages, MFT_LOW);
+ //lldebugs << "Template " << template_name << " # "
+ // << std::hex << mNumberLowFreqMessages
+ // << std::dec << " low"
+ // << llendl;
+ }
+ else if (!strcmp(token, "Fixed"))
+ {
+ U32 message_num = 0;
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected message template number (fixed),"
+ << " found EOF." << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ message_num = strtoul(token,NULL,0);
+
+ // ok, we can create a template!
+ // message number is ((255 << 24) | (255 << 16) | mNumberLowFreqMessages)
+ templatep = new LLMessageTemplate(template_name, message_num, MFT_LOW);
+ }
+ else
+ {
+ // oops, bad frequency line
+ llerrs << "Bad frequency! " << token
+ << " isn't High, Medium, or Low" << llendl
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ // Now get trust ("Trusted", "NotTrusted")
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // File ended
+ llerrs << "Expected message template "
+ "trust, but file ended."
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32) *checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ if (strcmp(token, "Trusted") == 0)
+ {
+ templatep->setTrust(MT_TRUST);
+ }
+ else if (strcmp(token, "NotTrusted") == 0)
+ {
+ templatep->setTrust(MT_NOTRUST);
+ }
+ else
+ {
+ // bad trust token
+ llerrs << "bad trust: " << token
+ << " isn't Trusted or NotTrusted"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ // get encoding
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // File ended
+ llerrs << "Expected message encoding, but file ended."
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ checkp = token;
+ while(*checkp)
+ {
+ mMessageFileChecksum += ((U32) *checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ if(0 == strcmp(token, "Unencoded"))
+ {
+ templatep->setEncoding(ME_UNENCODED);
+ }
+ else if(0 == strcmp(token, "Zerocoded"))
+ {
+ templatep->setEncoding(ME_ZEROCODED);
+ }
+ else
+ {
+ // bad trust token
+ llerrs << "bad encoding: " << token
+ << " isn't Unencoded or Zerocoded" << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ // ok, now we need to look for a block
+ b_block_start = TRUE;
+ continue;
+ }
+
+ // now, are we looking to start a template?
+ if (b_block)
+ {
+ b_block = FALSE;
+ // ok, need to pull header info
+
+ // name first
+ if (fscanf(messagefilep, formatString, block_name) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected block name, but file ended" << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = block_name;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // is name a legit C variable name
+ if (!b_variable_ok(block_name))
+ {
+ // nope!
+ llerrs << block_name << "is not a legal block name"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ // now, block type ("Single", "Multiple", or "Variable")
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected block type, but file ended." << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // which one is it?
+ if (!strcmp(token, "Single"))
+ {
+ // ok, we can create a block
+ blockp = new LLMessageBlock(block_name, MBT_SINGLE);
+ }
+ else if (!strcmp(token, "Multiple"))
+ {
+ // need to get the number of repeats
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected block multiple count,"
+ " but file ended." << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // is it a legal integer
+ if (!b_positive_integer_ok(token))
+ {
+ // nope!
+ llerrs << token << "is not a legal integer for"
+ " block multiple count" << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ // ok, we can create a block
+ blockp = new LLMessageBlock(block_name, MBT_MULTIPLE, atoi(token));
+ }
+ else if (!strcmp(token, "Variable"))
+ {
+ // ok, we can create a block
+ blockp = new LLMessageBlock(block_name, MBT_VARIABLE);
+ }
+ else
+ {
+ // oops, bad block type
+ llerrs << "Bad block type! " << token
+ << " isn't Single, Multiple, or Variable" << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ // ok, now we need to look for a variable
+ b_variable_start = TRUE;
+ continue;
+ }
+
+ // now, are we looking to start a template?
+ if (b_variable)
+ {
+ b_variable = FALSE;
+ // ok, need to pull header info
+
+ // name first
+ if (fscanf(messagefilep, formatString, var_name) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected variable name, but file ended."
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = var_name;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // is name a legit C variable name
+ if (!b_variable_ok(var_name))
+ {
+ // nope!
+ llerrs << var_name << " is not a legal variable name"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ // now, variable type ("Fixed" or "Variable")
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected variable type, but file ended"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+
+ // which one is it?
+ if (!strcmp(token, "U8"))
+ {
+ var = LLMessageVariable(var_name, MVT_U8, 1);
+ }
+ else if (!strcmp(token, "U16"))
+ {
+ var = LLMessageVariable(var_name, MVT_U16, 2);
+ }
+ else if (!strcmp(token, "U32"))
+ {
+ var = LLMessageVariable(var_name, MVT_U32, 4);
+ }
+ else if (!strcmp(token, "U64"))
+ {
+ var = LLMessageVariable(var_name, MVT_U64, 8);
+ }
+ else if (!strcmp(token, "S8"))
+ {
+ var = LLMessageVariable(var_name, MVT_S8, 1);
+ }
+ else if (!strcmp(token, "S16"))
+ {
+ var = LLMessageVariable(var_name, MVT_S16, 2);
+ }
+ else if (!strcmp(token, "S32"))
+ {
+ var = LLMessageVariable(var_name, MVT_S32, 4);
+ }
+ else if (!strcmp(token, "S64"))
+ {
+ var = LLMessageVariable(var_name, MVT_S64, 8);
+ }
+ else if (!strcmp(token, "F32"))
+ {
+ var = LLMessageVariable(var_name, MVT_F32, 4);
+ }
+ else if (!strcmp(token, "F64"))
+ {
+ var = LLMessageVariable(var_name, MVT_F64, 8);
+ }
+ else if (!strcmp(token, "LLVector3"))
+ {
+ var = LLMessageVariable(var_name, MVT_LLVector3, 12);
+ }
+ else if (!strcmp(token, "LLVector3d"))
+ {
+ var = LLMessageVariable(var_name, MVT_LLVector3d, 24);
+ }
+ else if (!strcmp(token, "LLVector4"))
+ {
+ var = LLMessageVariable(var_name, MVT_LLVector4, 16);
+ }
+ else if (!strcmp(token, "LLQuaternion"))
+ {
+ var = LLMessageVariable(var_name, MVT_LLQuaternion, 12);
+ }
+ else if (!strcmp(token, "LLUUID"))
+ {
+ var = LLMessageVariable(var_name, MVT_LLUUID, 16);
+ }
+ else if (!strcmp(token, "BOOL"))
+ {
+ var = LLMessageVariable(var_name, MVT_BOOL, 1);
+ }
+ else if (!strcmp(token, "IPADDR"))
+ {
+ var = LLMessageVariable(var_name, MVT_IP_ADDR, 4);
+ }
+ else if (!strcmp(token, "IPPORT"))
+ {
+ var = LLMessageVariable(var_name, MVT_IP_PORT, 2);
+ }
+ else if (!strcmp(token, "Fixed"))
+ {
+ // need to get the variable size
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected variable size, but file ended"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // is it a legal integer
+ if (!b_positive_integer_ok(token))
+ {
+ // nope!
+ llerrs << token << " is not a legal integer for"
+ " variable size" << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ // ok, we can create a block
+ var = LLMessageVariable(var_name, MVT_FIXED, atoi(token));
+ }
+ else if (!strcmp(token, "Variable"))
+ {
+ // need to get the variable size
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected variable size, but file ended"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ // is it a legal integer
+ if (!b_positive_integer_ok(token))
+ {
+ // nope!
+ llerrs << token << "is not a legal integer"
+ " for variable size" << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+ // ok, we can create a block
+ var = LLMessageVariable(var_name, MVT_VARIABLE, atoi(token));
+ }
+ else
+ {
+ // oops, bad variable type
+ llerrs << "Bad variable type! " << token
+ << " isn't Fixed or Variable" << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ // we got us a variable!
+ b_variable_end = TRUE;
+ continue;
+ }
+
+ // do we have a version number stuck in the file?
+ if (!strcmp(token, "version"))
+ {
+ // version number
+ if (fscanf(messagefilep, formatString, token) == EOF)
+ {
+ // oops, file ended
+ llerrs << "Expected version number, but file ended"
+ << llendl;
+ mbError = TRUE;
+ fclose(messagefilep);
+ return;
+ }
+
+ checkp = token;
+ while (*checkp)
+ {
+ mMessageFileChecksum += ((U32)*checkp++) << checksum_offset;
+ checksum_offset = (checksum_offset + 8) % 32;
+ }
+
+ mMessageFileVersionNumber = (F32)atof(token);
+
+// llinfos << "### Message template version " << mMessageFileVersionNumber << " ###" << llendl;
+ continue;
+ }
+ }
+
+ llinfos << "Message template checksum = " << std::hex << mMessageFileChecksum << std::dec << llendl;
+ }
+ else
+ {
+ llwarns << "Failed to open template: " << filename << llendl;
+ mbError = TRUE;
+ return;
+ }
+ fclose(messagefilep);
+}
+
+
+LLMessageSystem::~LLMessageSystem()
+{
+ mMessageTemplates.clear(); // don't delete templates.
+ for_each(mMessageNumbers.begin(), mMessageNumbers.end(), DeletePairedPointer());
+ mMessageNumbers.clear();
+
+ if (!mbError)
+ {
+ end_net();
+ }
+
+ delete mCurrentRMessageData;
+ mCurrentRMessageData = NULL;
+
+ delete mCurrentSMessageData;
+ mCurrentSMessageData = NULL;
+
+ delete mPollInfop;
+ mPollInfop = NULL;
+}
+
+void LLMessageSystem::clearReceiveState()
+{
+ mReceiveSize = -1;
+ mCurrentRecvPacketID = 0;
+ mCurrentRMessageTemplate = NULL;
+ delete mCurrentRMessageData;
+ mCurrentRMessageData = NULL;
+ mIncomingCompressedSize = 0;
+ mLastSender.invalidate();
+}
+
+
+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;
+ }
+}
+
+
+// Returns TRUE if a valid, on-circuit message has been received.
+BOOL LLMessageSystem::checkMessages( S64 frame_count )
+{
+ 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.
+ mCurrentMessageTimeSeconds = totalTime() * SEC_PER_USEC;
+ mMessageCountTime = getMessageTimeSeconds();
+ }
+
+ // loop until either no packets or a valid packet
+ // i.e., burn through packets from unregistered circuits
+ 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();
+
+ mReceiveSize = mTrueReceiveSize;
+ mLastSender = mPacketRing.getLastSender();
+
+ if (mReceiveSize < (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 (mReceiveSize > 0)
+ {
+ llwarns << "Invalid (too short) packet discarded " << mReceiveSize << llendl;
+ 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[--mReceiveSize];
+ true_rcv_size = mReceiveSize;
+ mReceiveSize -= acks * sizeof(TPACKETID);
+ }
+
+ // process the message as normal
+
+ mIncomingCompressedSize = zeroCodeExpand(&buffer,&mReceiveSize);
+ mCurrentRecvPacketID = buffer[1] + ((buffer[0] & 0x0f ) * 256);
+ if (sizeof(TPACKETID) == 4)
+ {
+ mCurrentRecvPacketID *= 256;
+ mCurrentRecvPacketID += buffer[2];
+ mCurrentRecvPacketID *= 256;
+ mCurrentRecvPacketID += buffer[3];
+ }
+
+ host = getSender();
+ //llinfos << host << ":" << mCurrentRecvPacketID << llendl;
+
+ // For testing the weird case we're having in the office where the first few packets
+ // on a connection get dropped
+ //if ((mCurrentRecvPacketID < 8) && !(buffer[0] & LL_RESENT_FLAG))
+ //{
+ // llinfos << "Evil! Dropping " << mCurrentRecvPacketID << " from " << host << " for fun!" << llendl;
+ // continue;
+ //}
+
+ 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);
+
+ // 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);
+
+ // reset packet in ID
+ cdp->setPacketInID(mCurrentRecvPacketID);
+ }
+ }
+ }
+
+ // 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);
+ //llinfos << "got ack: " << packet_id << llendl;
+ 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)
+ //{
+ // llwarns << "DISCARDED PACKET HOST MISMATCH! HOST: "
+ // << host << " CIRCUIT: "
+ // << mCircuitInfo.mCurrentCircuit->mHost
+ // << llendl;
+ //}
+ // ***************************************
+ //mCircuitInfo.mCurrentCircuit->mAcks.put(mCurrentRecvPacketID);
+ cdp->collectRAck(mCurrentRecvPacketID);
+ }
+
+ //llinfos << "Discarding duplicate resend from " << host << llendl;
+ if(mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << host;
+ char buffer[MAX_STRING]; /* Flawfinder: ignore*/
+ snprintf(buffer, MAX_STRING, "\t%6d\t%6d\t%6d ", mReceiveSize, (mIncomingCompressedSize ? mIncomingCompressedSize : mReceiveSize), mCurrentRecvPacketID);/* Flawfinder: ignore*/
+ str << buffer << "(unknown)"
+ << (recv_reliable ? " reliable" : "")
+ << " resent "
+ << ((acks > 0) ? "acks" : "")
+ << " DISCARD DUPLICATE";
+ llinfos << str.str() << llendl;
+ }
+ 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
+
+ valid_packet = decodeTemplate( buffer, mReceiveSize, &mCurrentRMessageTemplate );
+ if( valid_packet )
+ {
+ mCurrentRMessageTemplate->mReceiveCount++;
+ lldebugst(LLERR_MESSAGE) << "MessageRecvd:" << mCurrentRMessageTemplate->mName << " from " << host << llendl;
+ }
+
+ // UseCircuitCode is allowed in even from an invalid circuit, so that
+ // we can toss circuits around.
+ if (valid_packet && !cdp && (mCurrentRMessageTemplate->mName != _PREHASH_UseCircuitCode) )
+ {
+ logMsgFromInvalidCircuit( host, recv_reliable );
+ clearReceiveState();
+ valid_packet = FALSE;
+ }
+
+ if (valid_packet && cdp && !cdp->getTrusted() && (mCurrentRMessageTemplate->getTrust() == MT_TRUST) )
+ {
+ logTrustedMsgFromUntrustedCircuit( host );
+ clearReceiveState();
+
+ sendDenyTrustedCircuit(host);
+ valid_packet = FALSE;
+ }
+
+ if (valid_packet
+ && mCurrentRMessageTemplate->isBanned(cdp && cdp->getTrusted()))
+ {
+ llwarns << "LLMessageSystem::checkMessages "
+ << "received banned message "
+ << mCurrentRMessageTemplate->mName
+ << " from "
+ << ((cdp && cdp->getTrusted()) ? "trusted " : "untrusted ")
+ << host << llendl;
+ clearReceiveState();
+ valid_packet = FALSE;
+ }
+
+ if( valid_packet )
+ {
+ logValidMsg(cdp, host, recv_reliable, recv_resent, (BOOL)(acks>0) );
+
+ valid_packet = decodeData( 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)
+ {
+ /* Code for dumping the complete contents of a message. Keep for future use in optimizing messages.
+ if( 1 )
+ {
+ static char* object_update = gMessageStringTable.getString("ObjectUpdate");
+ if(object_update == mCurrentRMessageTemplate->mName )
+ {
+ llinfos << "ObjectUpdate:" << llendl;
+ U32 i;
+ llinfos << " Zero Encoded: " << zero_unexpanded_size << llendl;
+ for( i = 0; i<zero_unexpanded_size; i++ )
+ {
+ llinfos << " " << i << ": " << (U32) zero_unexpanded_buffer[i] << llendl;
+ }
+ llinfos << "" << llendl;
+
+ llinfos << " Zero Unencoded: " << mReceiveSize << llendl;
+ for( i = 0; i<mReceiveSize; i++ )
+ {
+ llinfos << " " << i << ": " << (U32) buffer[i] << llendl;
+ }
+ llinfos << "" << llendl;
+
+ llinfos << " Blocks and variables: " << llendl;
+ S32 byte_count = 0;
+ for (LLMessageTemplate::message_block_map_t::iterator
+ iter = mCurrentRMessageTemplate->mMemberBlocks.begin(),
+ end = mCurrentRMessageTemplate->mMemberBlocks.end();
+ iter != end; iter++)
+ {
+ LLMessageBlock* block = iter->second;
+ const char* block_name = block->mName;
+ for (LLMsgBlkData::msg_var_data_map_t::iterator
+ iter = block->mMemberVariables.begin(),
+ end = block->mMemberVariables.end();
+ iter != end; iter++)
+ {
+ const char* var_name = iter->first;
+
+ if( getNumberOfBlocksFast( block_name ) < 1 )
+ {
+ llinfos << var_name << " has no blocks" << llendl;
+ }
+ for( S32 blocknum = 0; blocknum < getNumberOfBlocksFast( block_name ); blocknum++ )
+ {
+ char *bnamep = (char *)block_name + blocknum; // this works because it's just a hash. The bnamep is never derefference
+ char *vnamep = (char *)var_name;
+
+ LLMsgBlkData *msg_block_data = mCurrentRMessageData->mMemberBlocks[bnamep];
+
+ char errmsg[1024];
+ if (!msg_block_data)
+ {
+ sprintf(errmsg, "Block %s #%d not in message %s", block_name, blocknum, mCurrentRMessageData->mName);
+ llerrs << errmsg << llendl;
+ }
+
+ LLMsgVarData vardata = msg_block_data->mMemberVarData[vnamep];
+
+ if (!vardata.getName())
+ {
+ sprintf(errmsg, "Variable %s not in message %s block %s", vnamep, mCurrentRMessageData->mName, bnamep);
+ llerrs << errmsg << llendl;
+ }
+
+ const S32 vardata_size = vardata.getSize();
+ if( vardata_size )
+ {
+ for( i = 0; i < vardata_size; i++ )
+ {
+ byte_count++;
+ llinfos << block_name << " " << var_name << " [" << blocknum << "][" << i << "]= " << (U32)(((U8*)vardata.getData())[i]) << llendl;
+ }
+ }
+ else
+ {
+ llinfos << block_name << " " << var_name << " [" << blocknum << "] 0 bytes" << llendl;
+ }
+ }
+ }
+ }
+ llinfos << "Byte count =" << byte_count << llendl;
+ }
+ }
+ */
+
+ 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))
+ {
+ llwarns << "Packet "
+ << (mCurrentRMessageTemplate ? mCurrentRMessageTemplate->mName : "")
+ << " from invalid circuit " << host << llendl;
+ mOffCircuitPackets++;
+ }
+ else
+ {
+ mInvalidOnCircuitPackets++;
+ }
+ }
+
+ // Code for dumping the complete contents of a message
+ // delete [] zero_unexpanded_buffer;
+ }
+ } while (!valid_packet && mReceiveSize > 0);
+
+ F64 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()
+{
+ F64 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();
+
+ if (!mDenyTrustedCircuitSet.empty())
+ {
+ llinfos << "Sending queued DenyTrustedCircuit messages." << llendl;
+ 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 >= 0.f)
+ {
+ // This is one of the only places where we're required to get REAL message system time.
+ mReceiveTime = (F32)(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::newMessageFast(const char *name)
+{
+ mbSBuilt = FALSE;
+ mbSClear = FALSE;
+
+ mCurrentSendTotal = 0;
+ mSendReliable = FALSE;
+
+ char *namep = (char *)name;
+
+ if (mMessageTemplates.count(namep) > 0)
+ {
+ mCurrentSMessageTemplate = mMessageTemplates[namep];
+ if (mCurrentSMessageData)
+ {
+ delete mCurrentSMessageData;
+ }
+ mCurrentSMessageData = new LLMsgData(namep);
+ mCurrentSMessageName = namep;
+ mCurrentSDataBlock = NULL;
+ mCurrentSBlockName = NULL;
+
+ // add at one of each block
+ LLMessageTemplate* msg_template = mMessageTemplates[namep];
+ for (LLMessageTemplate::message_block_map_t::iterator iter = msg_template->mMemberBlocks.begin();
+ iter != msg_template->mMemberBlocks.end(); iter++)
+ {
+ LLMessageBlock* ci = iter->second;
+ LLMsgBlkData *tblockp;
+ tblockp = new LLMsgBlkData(ci->mName, 0);
+ mCurrentSMessageData->addBlock(tblockp);
+ }
+ }
+ else
+ {
+ llerrs << "newMessage - Message " << name << " not registered" << llendl;
+ }
+}
+
+void LLMessageSystem::copyMessageRtoS()
+{
+ if (!mCurrentRMessageTemplate)
+ {
+ return;
+ }
+ newMessageFast(mCurrentRMessageTemplate->mName);
+
+ // 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::iterator iter = mCurrentRMessageData->mMemberBlocks.begin();
+ LLMsgData::msg_blk_data_map_t::iterator end = mCurrentRMessageData->mMemberBlocks.end();
+ for(; iter != end; ++iter)
+ {
+ 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--;
+
+ nextBlockFast(block_name);
+
+ // now loop through the variables
+ LLMsgBlkData::msg_var_data_map_t::iterator dit = mbci->mMemberVarData.begin();
+ LLMsgBlkData::msg_var_data_map_t::iterator dend = mbci->mMemberVarData.end();
+
+ for(; dit != dend; ++dit)
+ {
+ LLMsgVarData& mvci = *dit;
+ addDataFast(mvci.getName(), mvci.getData(), mvci.getType(), mvci.getSize());
+ }
+ }
+}
+
+void LLMessageSystem::clearMessage()
+{
+ mbSBuilt = FALSE;
+ mbSClear = TRUE;
+
+ mCurrentSendTotal = 0;
+ mSendReliable = FALSE;
+
+ mCurrentSMessageTemplate = NULL;
+
+ delete mCurrentSMessageData;
+ mCurrentSMessageData = NULL;
+
+ mCurrentSMessageName = NULL;
+ mCurrentSDataBlock = NULL;
+ mCurrentSBlockName = NULL;
+}
+
+
+// set block to add data to within current message
+void LLMessageSystem::nextBlockFast(const char *blockname)
+{
+ char *bnamep = (char *)blockname;
+
+ if (!mCurrentSMessageTemplate)
+ {
+ llerrs << "newMessage not called prior to setBlock" << llendl;
+ return;
+ }
+
+ // now, does this block exist?
+ LLMessageTemplate::message_block_map_t::iterator temp_iter = mCurrentSMessageTemplate->mMemberBlocks.find(bnamep);
+ if (temp_iter == mCurrentSMessageTemplate->mMemberBlocks.end())
+ {
+ llerrs << "LLMessageSystem::nextBlockFast " << bnamep
+ << " not a block in " << mCurrentSMessageTemplate->mName << llendl;
+ return;
+ }
+
+ LLMessageBlock* template_data = temp_iter->second;
+
+ // 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::iterator iter = template_data->mMemberVariables.begin();
+ iter != template_data->mMemberVariables.end(); iter++)
+ {
+ LLMessageVariable& ci = *(iter->second);
+ 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)
+ {
+ llerrs << "LLMessageSystem::nextBlockFast called multiple times"
+ << " for " << bnamep << " but is type MBT_SINGLE" << llendl;
+ 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))
+ {
+ llerrs << "LLMessageSystem::nextBlockFast called "
+ << mCurrentSDataBlock->mBlockNumber << " times for " << bnamep
+ << " exceeding " << template_data->mNumber
+ << " specified in type MBT_MULTIPLE." << llendl;
+ 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)
+ {
+ llerrs << "Trying to pack too many blocks into MBT_VARIABLE type (limited to " << MAX_BLOCKS << ")" << llendl;
+ }
+
+ // 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::iterator
+ iter = template_data->mMemberVariables.begin(),
+ end = template_data->mMemberVariables.end();
+ iter != end; iter++)
+ {
+ LLMessageVariable& ci = *(iter->second);
+ mCurrentSDataBlock->addVariable(ci.getName(), ci.getType());
+ }
+ return;
+ }
+}
+
+// add data to variable in current block
+void LLMessageSystem::addDataFast(const char *varname, const void *data, EMsgVariableType type, S32 size)
+{
+ char *vnamep = (char *)varname;
+
+ // do we have a current message?
+ if (!mCurrentSMessageTemplate)
+ {
+ llerrs << "newMessage not called prior to addData" << llendl;
+ return;
+ }
+
+ // do we have a current block?
+ if (!mCurrentSDataBlock)
+ {
+ llerrs << "setBlock not called prior to addData" << llendl;
+ return;
+ }
+
+ // kewl, add the data if it exists
+ LLMessageVariable* var_data = mCurrentSMessageTemplate->mMemberBlocks[mCurrentSBlockName]->mMemberVariables[vnamep];
+ if (!var_data || !var_data->getName())
+ {
+ llerrs << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << llendl;
+ 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))
+ {
+ llwarns << "Field " << varname << " is a Variable 1 but program "
+ << "attempted to stuff more than 255 bytes in "
+ << "(" << size << "). Clamping size and truncating data." << llendl;
+ size = 255;
+ char *truncate = (char *)data;
+ truncate[255] = 0;
+ }
+
+ // 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())
+ {
+ llerrs << varname << " is type MVT_FIXED but request size " << size << " doesn't match template size "
+ << var_data->getSize() << llendl;
+ 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 LLMessageSystem::addDataFast(const char *varname, const void *data, EMsgVariableType type)
+{
+ char *vnamep = (char *)varname;
+
+ // do we have a current message?
+ if (!mCurrentSMessageTemplate)
+ {
+ llerrs << "newMessage not called prior to addData" << llendl;
+ return;
+ }
+
+ // do we have a current block?
+ if (!mCurrentSDataBlock)
+ {
+ llerrs << "setBlock not called prior to addData" << llendl;
+ return;
+ }
+
+ // kewl, add the data if it exists
+ LLMessageVariable* var_data = mCurrentSMessageTemplate->mMemberBlocks[mCurrentSBlockName]->mMemberVariables[vnamep];
+ if (!var_data->getName())
+ {
+ llerrs << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << llendl;
+ return;
+ }
+
+ // ok, it seems ok. . . are we MVT_VARIABLE?
+ if (var_data->getType() == MVT_VARIABLE)
+ {
+ // nope
+ llerrs << vnamep << " is type MVT_VARIABLE. Call using addData(name, data, size)" << llendl;
+ return;
+ }
+ else
+ {
+ mCurrentSDataBlock->addData(vnamep, data, var_data->getSize(), type);
+ mCurrentSendTotal += var_data->getSize();
+ }
+}
+
+BOOL LLMessageSystem::isSendFull(const char* blockname)
+{
+ if(!blockname)
+ {
+ return (mCurrentSendTotal > MTUBYTES);
+ }
+ return isSendFullFast(gMessageStringTable.getString(blockname));
+}
+
+BOOL LLMessageSystem::isSendFullFast(const char* blockname)
+{
+ if(mCurrentSendTotal > MTUBYTES)
+ {
+ return TRUE;
+ }
+ if(!blockname)
+ {
+ return FALSE;
+ }
+ char* bnamep = (char*)blockname;
+ S32 max;
+
+ LLMessageBlock* template_data = mCurrentSMessageTemplate->mMemberBlocks[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;
+}
+
+
+// blow away the last block of a message, return FALSE if that leaves no blocks or there wasn't a block to remove
+BOOL LLMessageSystem::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.
+
+ LLMessageBlock* template_data = mCurrentSMessageTemplate->mMemberBlocks[mCurrentSBlockName];
+
+ for (LLMessageBlock::message_variable_map_t::iterator iter = template_data->mMemberVariables.begin();
+ iter != template_data->mMemberVariables.end(); iter++)
+ {
+ LLMessageVariable& ci = *(iter->second);
+ 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
+ return FALSE;
+ }
+ else
+ {
+ // Decrement the counter.
+ block_data->mBlockNumber--;
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+// make sure that all the desired data is in place and then copy the data into mSendBuffer
+void LLMessageSystem::buildMessage()
+{
+ // 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)
+ {
+ llerrs << "newMessage not called prior to buildMessage" << llendl;
+ return;
+ }
+
+ // zero out some useful values
+
+ // leave room for circuit counter
+ mSendSize = LL_PACKET_ID_SIZE;
+
+ // encode message number and adjust total_offset
+ if (mCurrentSMessageTemplate->mFrequency == MFT_HIGH)
+ {
+// old, endian-dependant way
+// memcpy(&mSendBuffer[mSendSize], &mCurrentMessageTemplate->mMessageNumber, sizeof(U8));
+
+// new, independant way
+ mSendBuffer[mSendSize] = (U8)mCurrentSMessageTemplate->mMessageNumber;
+ mSendSize += sizeof(U8);
+ }
+ else if (mCurrentSMessageTemplate->mFrequency == MFT_MEDIUM)
+ {
+ U8 temp = 255;
+ memcpy(&mSendBuffer[mSendSize], &temp, sizeof(U8)); /*Flawfinder: ignore*/
+ mSendSize += sizeof(U8);
+
+ // mask off unsightly bits
+ temp = mCurrentSMessageTemplate->mMessageNumber & 255;
+ memcpy(&mSendBuffer[mSendSize], &temp, sizeof(U8)); /*Flawfinder: ignore*/
+ mSendSize += sizeof(U8);
+ }
+ else if (mCurrentSMessageTemplate->mFrequency == MFT_LOW)
+ {
+ U8 temp = 255;
+ U16 message_num;
+ memcpy(&mSendBuffer[mSendSize], &temp, sizeof(U8)); /*Flawfinder: ignore*/
+ mSendSize += sizeof(U8);
+ memcpy(&mSendBuffer[mSendSize], &temp, sizeof(U8)); /*Flawfinder: ignore*/
+ mSendSize += sizeof(U8);
+
+ // mask off unsightly bits
+ message_num = mCurrentSMessageTemplate->mMessageNumber & 0xFFFF;
+
+ // convert to network byte order
+ message_num = htons(message_num);
+ memcpy(&mSendBuffer[mSendSize], &message_num, sizeof(U16)); /*Flawfinder: ignore*/
+ mSendSize += sizeof(U16);
+ }
+ else
+ {
+ llerrs << "unexpected message frequency in buildMessage" << llendl;
+ return;
+ }
+
+ // counting variables used to encode multiple block info
+ S32 block_count = 0;
+ U8 temp_block_number;
+
+ // loop through msg blocks to loop through variables, totalling up size data and copying into mSendBuffer
+ for (LLMsgData::msg_blk_data_map_t::iterator
+ iter = mCurrentSMessageData->mMemberBlocks.begin(),
+ end = mCurrentSMessageData->mMemberBlocks.end();
+ iter != end; iter++)
+ {
+ LLMsgBlkData* mbci = iter->second;
+ // do we need to encode a block code?
+ if (block_count == 0)
+ {
+ block_count = mbci->mBlockNumber;
+
+ LLMessageBlock* template_data = mCurrentSMessageTemplate->mMemberBlocks[mbci->mName];
+
+ // 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
+ if (template_data->mType == MBT_VARIABLE)
+ {
+ // remember that mBlockNumber is a S32
+ temp_block_number = (U8)mbci->mBlockNumber;
+ if ((S32)(mSendSize + sizeof(U8)) < MAX_BUFFER_SIZE)
+ {
+ memcpy(&mSendBuffer[mSendSize], &temp_block_number, sizeof(U8));
+ mSendSize += sizeof(U8);
+ }
+ else
+ {
+ // Just reporting error is likely not enough. Need
+ // to check how to abort or error out gracefully
+ // from this function. XXXTBD
+ llerrs << "buildMessage failed. Message excedding"
+ " sendBuffersize." << llendl;
+ }
+ }
+ else if (template_data->mType == MBT_MULTIPLE)
+ {
+ if (block_count != template_data->mNumber)
+ {
+ // nope! need to fill it in all the way!
+ llerrs << "Block " << mbci->mName
+ << " is type MBT_MULTIPLE but only has data for "
+ << block_count << " out of its "
+ << template_data->mNumber << " blocks" << llendl;
+ }
+ }
+ }
+
+ // counting down multiple blocks
+ block_count--;
+
+ // now loop through the variables
+ for (LLMsgBlkData::msg_var_data_map_t::iterator iter = mbci->mMemberVarData.begin();
+ iter != mbci->mMemberVarData.end(); iter++)
+ {
+ LLMsgVarData& mvci = *iter;
+ if (mvci.getSize() == -1)
+ {
+ // oops, this variable wasn't ever set!
+ llerrs << "The variable " << mvci.getName() << " in block "
+ << mbci->mName << " of message "
+ << mCurrentSMessageData->mName
+ << " wasn't set prior to buildMessage call" << llendl;
+ }
+ 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;
+ htonmemcpy(&mSendBuffer[mSendSize], &sizeb, MVT_U8, 1);
+ break;
+ case 2:
+ sizeh = size;
+ htonmemcpy(&mSendBuffer[mSendSize], &sizeh, MVT_U16, 2);
+ break;
+ case 4:
+ htonmemcpy(&mSendBuffer[mSendSize], &size, MVT_S32, 4);
+ break;
+ default:
+ llerrs << "Attempting to build variable field with unknown size of " << size << llendl;
+ break;
+ }
+ mSendSize += mvci.getDataSize();
+ }
+
+ // if there is any data to pack, pack it
+ if((mvci.getData() != NULL) && mvci.getSize())
+ {
+ if(mSendSize + mvci.getSize() < (S32)sizeof(mSendBuffer))
+ {
+ memcpy(
+ &mSendBuffer[mSendSize],
+ mvci.getData(),
+ mvci.getSize());
+ mSendSize += mvci.getSize();
+ }
+ else
+ {
+ // Just reporting error is likely not
+ // enough. Need to check how to abort or error
+ // out gracefully from this function. XXXTBD
+ llerrs << "LLMessageSystem::buildMessage failed. "
+ << "Attempted to pack "
+ << mSendSize + mvci.getSize()
+ << " bytes into a buffer with size "
+ << mSendBuffer << "." << llendl
+ }
+ }
+ }
+ }
+ }
+ mbSBuilt = TRUE;
+}
+
+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)
+{
+ F32 timeout;
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS,
+ LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged());
+ }
+ else
+ {
+ timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX;
+ }
+
+ return sendReliable(host, 0, FALSE, timeout, callback, callback_data);
+}
+
+// send the message via a UDP packet
+S32 LLMessageSystem::sendReliable( const LLHost &host,
+ S32 retries,
+ BOOL ping_based_timeout,
+ F32 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, LL_RELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged());
+ }
+ else
+ {
+ timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, LL_RELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX);
+ }
+ }
+
+ mSendReliable = TRUE;
+ mReliablePacketParams.set(host, retries, ping_based_timeout, timeout,
+ callback, callback_data, mCurrentSMessageName);
+ return sendMessage(host);
+}
+
+void LLMessageSystem::forwardMessage(const LLHost &host)
+{
+ copyMessageRtoS();
+ sendMessage(host);
+}
+
+void LLMessageSystem::forwardReliable(const LLHost &host)
+{
+ copyMessageRtoS();
+ sendReliable(host);
+}
+
+void LLMessageSystem::forwardReliable(const U32 circuit_code)
+{
+ copyMessageRtoS();
+ sendReliable(findHost(circuit_code));
+}
+
+S32 LLMessageSystem::flushSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data)
+{
+ F32 timeout;
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS,
+ LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged());
+ }
+ else
+ {
+ timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX;
+ }
+
+ S32 send_bytes = 0;
+ if (mCurrentSendTotal)
+ {
+ mSendReliable = TRUE;
+ // No need for ping-based retry as not going to retry
+ mReliablePacketParams.set(host, 0, FALSE, timeout, callback, callback_data, mCurrentSMessageName);
+ send_bytes = sendMessage(host);
+ clearMessage();
+ }
+ else
+ {
+ delete callback_data;
+ }
+ return send_bytes;
+}
+
+S32 LLMessageSystem::flushReliable(const LLHost &host)
+{
+ S32 send_bytes = 0;
+ if (mCurrentSendTotal)
+ {
+ send_bytes = sendReliable(host);
+ }
+ clearMessage();
+ return send_bytes;
+}
+
+
+// This can be called from signal handlers,
+// so should should not use llinfos.
+S32 LLMessageSystem::sendMessage(const LLHost &host)
+{
+ if (!mbSBuilt)
+ {
+ buildMessage();
+ }
+
+ mCurrentSendTotal = 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)
+ {
+ llinfos << "MSG: -> " << host << "\tUNKNOWN CIRCUIT:\t"
+ << mCurrentSMessageName << llendl;
+ }
+ llwarns << "sendMessage - Trying to send "
+ << mCurrentSMessageName << " on unknown circuit "
+ << host << llendl;
+ 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)
+ {
+ llinfos << "MSG: -> " << host << "\tDEAD CIRCUIT\t\t"
+ << mCurrentSMessageName << llendl;
+ }
+ llwarns << "sendMessage - Trying to send message "
+ << mCurrentSMessageName << " to dead circuit "
+ << host << llendl;
+ return 0;
+ }
+ }
+
+ memset(mSendBuffer,0,LL_PACKET_ID_SIZE); // zero out the packet ID field
+
+ // add the send id to the front of the message
+ cdp->nextPacketOutID();
+
+ // Packet ID size is always 4
+ *((S32*)&mSendBuffer[0]) = htonl(cdp->getPacketOutID());
+
+ // Compress the message, which will usually reduce its size.
+ U8 * buf_ptr = (U8 *)mSendBuffer;
+ S32 buffer_length = mSendSize;
+ if(ME_ZEROCODED == mCurrentSMessageTemplate->getEncoding())
+ {
+ zeroCode(&buf_ptr, &buffer_length);
+ }
+
+ if (buffer_length > 1500)
+ {
+ if((mCurrentSMessageName != _PREHASH_ChildAgentUpdate)
+ && (mCurrentSMessageName != _PREHASH_SendXferPacket))
+ {
+ llwarns << "sendMessage - Trying to send "
+ << ((buffer_length > 4000) ? "EXTRA " : "")
+ << "BIG message " << mCurrentSMessageName << " - "
+ << buffer_length << llendl;
+ }
+ }
+ if (mSendReliable)
+ {
+ buf_ptr[0] |= LL_RELIABLE_FLAG;
+
+ if (!cdp->getUnackedPacketCount())
+ {
+ // We are adding the first packed onto the unacked packet list(s)
+ // Add this circuit to the list of circuits with unacked packets
+ mCircuitInfo.mUnackedCircuitMap[cdp->mHost] = cdp;
+ }
+
+ cdp->addReliablePacket(mSocket,buf_ptr,buffer_length, &mReliablePacketParams);
+ mReliablePacketsOut++;
+ }
+
+ // tack packet acks onto the end of this message
+ S32 space_left = (MTUBYTES - buffer_length) / sizeof(TPACKETID); // space left for packet ids
+ S32 ack_count = (S32)cdp->mAcks.size();
+ BOOL is_ack_appended = FALSE;
+ std::vector<TPACKETID> acks;
+ if((space_left > 0) && (ack_count > 0) &&
+ (mCurrentSMessageName != _PREHASH_PacketAck))
+ {
+ buf_ptr[0] |= LL_ACK_FLAG;
+ S32 append_ack_count = llmin(space_left, ack_count);
+ const S32 MAX_ACKS = 250;
+ append_ack_count = llmin(append_ack_count, MAX_ACKS);
+ std::vector<TPACKETID>::iterator iter = cdp->mAcks.begin();
+ std::vector<TPACKETID>::iterator last = cdp->mAcks.begin();
+ last += append_ack_count;
+ TPACKETID packet_id;
+ for( ; iter != last ; ++iter)
+ {
+ // grab the next packet id.
+ packet_id = (*iter);
+ if(mVerboseLog)
+ {
+ acks.push_back(packet_id);
+ }
+
+ // put it on the end of the buffer
+ packet_id = htonl(packet_id);
+
+ if((S32)(buffer_length + sizeof(TPACKETID)) < MAX_BUFFER_SIZE)
+ {
+ memcpy(&buf_ptr[buffer_length], &packet_id, sizeof(TPACKETID));
+ // 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.
+ llerrs << "Buffer packing failed due to size.." << llendl;
+ }
+ }
+
+ // 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( buffer_length );
+ }
+
+ if(mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: -> " << host;
+ char buffer[MAX_STRING]; /* Flawfinder: ignore */
+ snprintf(buffer, MAX_STRING, "\t%6d\t%6d\t%6d ", mSendSize, buffer_length, cdp->getPacketOutID()); /* Flawfinder: ignore */
+ str << buffer
+ << mCurrentSMessageTemplate->mName
+ << (mSendReliable ? " reliable " : "");
+ if(is_ack_appended)
+ {
+ str << "\tACKS:\t";
+ std::ostream_iterator<TPACKETID> append(str, " ");
+ std::copy(acks.begin(), acks.end(), append);
+ }
+ llinfos << str.str() << llendl;
+ }
+
+ lldebugst(LLERR_MESSAGE) << "MessageSent at: " << (S32)totalTime()
+ << ", " << mCurrentSMessageTemplate->mName
+ << " to " << host
+ << llendl;
+
+ // ok, clean up temp data
+ delete mCurrentSMessageData;
+ mCurrentSMessageData = NULL;
+
+ mPacketsOut++;
+ mBytesOut += buffer_length;
+
+ return buffer_length;
+}
+
+
+// Returns template for the message contained in buffer
+BOOL LLMessageSystem::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)
+ {
+ llwarns << "No message waiting for decode!" << llendl;
+ 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)
+ {
+ llwarns << "Packet with unusable length received (too short): "
+ << buffer_size << llendl;
+ return(FALSE);
+ }
+
+ LLMessageTemplate* temp = get_ptr_in_map(mMessageNumbers,num);
+ if (temp)
+ {
+ *msg_template = temp;
+ }
+ else
+ {
+ llwarns << "Message #" << std::hex << num << std::dec
+ << " received but not registered!" << llendl;
+ callExceptionFunc(MX_UNREGISTERED_MESSAGE);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, BOOL recv_reliable )
+{
+ if(mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << host;
+ char buffer[MAX_STRING]; /* Flawfinder: ignore */
+ snprintf(buffer, MAX_STRING, "\t%6d\t%6d\t%6d ", mReceiveSize, (mIncomingCompressedSize ? mIncomingCompressedSize: mReceiveSize), mCurrentRecvPacketID); /* Flawfinder: ignore */
+ str << buffer
+ << mCurrentRMessageTemplate->mName
+ << (recv_reliable ? " reliable" : "")
+ << " REJECTED";
+ llinfos << str.str() << llendl;
+ }
+ // 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)
+ {
+ llwarns << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << llendl;
+ }
+ else
+ {
+ mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber;
+ mMessageCountList[mNumMessageCounts].mMessageBytes = mReceiveSize;
+ mMessageCountList[mNumMessageCounts].mInvalid = TRUE;
+ mNumMessageCounts++;
+ }
+}
+
+void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host )
+{
+ llwarns << "Recieved trusted message on untrusted circuit. "
+ << "Will reply with deny. "
+ << "Message: " << mCurrentRMessageTemplate->mName
+ << " Host: " << host << llendl;
+ if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM)
+ {
+ llwarns << "got more than " << MAX_MESSAGE_COUNT_NUM
+ << " packets without clearing counts"
+ << llendl;
+ }
+ else
+ {
+ mMessageCountList[mNumMessageCounts].mMessageNum
+ = mCurrentRMessageTemplate->mMessageNumber;
+ mMessageCountList[mNumMessageCounts].mMessageBytes
+ = mReceiveSize;
+ 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)
+ {
+ llwarns << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << llendl;
+ }
+ else
+ {
+ mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber;
+ mMessageCountList[mNumMessageCounts].mMessageBytes = mReceiveSize;
+ mMessageCountList[mNumMessageCounts].mInvalid = FALSE;
+ mNumMessageCounts++;
+ }
+
+ if (cdp)
+ {
+ // update circuit packet ID tracking (missing/out of order packets)
+ cdp->checkPacketInID( mCurrentRecvPacketID, recv_resent );
+ cdp->addBytesIn( mTrueReceiveSize );
+ }
+
+ if(mVerboseLog)
+ {
+ std::ostringstream str;
+ str << "MSG: <- " << host;
+ char buffer[MAX_STRING]; /* Flawfinder: ignore */
+ snprintf(buffer, MAX_STRING, "\t%6d\t%6d\t%6d ", mReceiveSize, (mIncomingCompressedSize ? mIncomingCompressedSize : mReceiveSize), mCurrentRecvPacketID); /* Flawfinder: ignore */
+ str << buffer
+ << mCurrentRMessageTemplate->mName
+ << (recv_reliable ? " reliable" : "")
+ << (recv_resent ? " resent" : "")
+ << (recv_acks ? " acks" : "");
+ llinfos << str.str() << llendl;
+ }
+}
+
+
+void LLMessageSystem::logRanOffEndOfPacket( const LLHost& host )
+{
+ // we've run off the end of the packet!
+ llwarns << "Ran off end of packet " << mCurrentRMessageTemplate->mName
+ << " with id " << mCurrentRecvPacketID << " from " << host
+ << llendl;
+ if(mVerboseLog)
+ {
+ llinfos << "MSG: -> " << host << "\tREAD PAST END:\t"
+ << mCurrentRecvPacketID << " "
+ << mCurrentSMessageTemplate->mName << llendl;
+ }
+ callExceptionFunc(MX_RAN_OFF_END_OF_PACKET);
+}
+
+
+// decode a given message
+BOOL LLMessageSystem::decodeData(const U8* buffer, const LLHost& sender )
+{
+ llassert( mReceiveSize >= 0 );
+ llassert( mCurrentRMessageTemplate);
+ llassert( !mCurrentRMessageData );
+ delete mCurrentRMessageData; // just to make sure
+
+ S32 decode_pos = LL_PACKET_ID_SIZE + (S32)(mCurrentRMessageTemplate->mFrequency);
+
+ // create base working data set
+ mCurrentRMessageData = new LLMsgData(mCurrentRMessageTemplate->mName);
+
+ // loop through the template building the data structure as we go
+ for (LLMessageTemplate::message_block_map_t::iterator iter = mCurrentRMessageTemplate->mMemberBlocks.begin();
+ iter != mCurrentRMessageTemplate->mMemberBlocks.end(); iter++)
+ {
+ LLMessageBlock* mbci = iter->second;
+ 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)
+ {
+ logRanOffEndOfPacket( sender );
+ return FALSE;
+ }
+ repeat_number = buffer[decode_pos];
+ decode_pos++;
+ }
+ else
+ {
+ llerrs << "Unknown block type" << llendl;
+ 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::iterator iter = mbci->mMemberVariables.begin();
+ iter != mbci->mMemberVariables.end(); iter++)
+ {
+ LLMessageVariable& mvci = *(iter->second);
+ // 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 );
+ return FALSE;
+ }
+ switch(data_size)
+ {
+ case 1:
+ htonmemcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1);
+ tsize = tsizeb;
+ break;
+ case 2:
+ htonmemcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2);
+ tsize = tsizeh;
+ break;
+ case 4:
+ htonmemcpy(&tsizeb, &buffer[decode_pos], MVT_U32, 4);
+ break;
+ default:
+ llerrs << "Attempting to read variable field with unknown size of " << data_size << llendl;
+ break;
+
+ }
+ decode_pos += data_size;
+
+ if ((decode_pos + (S32)tsize) > mReceiveSize)
+ {
+ logRanOffEndOfPacket( sender );
+ return FALSE;
+ }
+ 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 );
+ return FALSE;
+ }
+
+ cur_data_block->addData(mvci.getName(), &buffer[decode_pos], mvci.getSize(), mvci.getType());
+ decode_pos += mvci.getSize();
+ }
+ }
+ }
+ }
+
+ if (mCurrentRMessageData->mMemberBlocks.empty()
+ && !mCurrentRMessageTemplate->mMemberBlocks.empty())
+ {
+ lldebugs << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << llendl;
+ return FALSE;
+ }
+
+ {
+ static LLTimer decode_timer;
+
+ if( mTimeDecodes )
+ {
+ decode_timer.reset();
+ }
+
+ // if( mCurrentRMessageTemplate->mName == _PREHASH_AgentToNewRegion )
+ // {
+ // VTResume(); // VTune
+ // }
+
+ {
+ LLFastTimer t(LLFastTimer::FTM_PROCESS_MESSAGES);
+ if( !mCurrentRMessageTemplate->callHandlerFunc(this) )
+ {
+ llwarns << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << llendl;
+ }
+ }
+
+ // if( mCurrentRMessageTemplate->mName == _PREHASH_AgentToNewRegion )
+ // {
+ // VTPause(); // VTune
+ // }
+
+ if( mTimeDecodes )
+ {
+ F32 decode_time = decode_timer.getElapsedTimeF32();
+ mCurrentRMessageTemplate->mDecodeTimeThisFrame += decode_time;
+
+ mCurrentRMessageTemplate->mTotalDecoded++;
+ mCurrentRMessageTemplate->mTotalDecodeTime += decode_time;
+
+ if( mCurrentRMessageTemplate->mMaxDecodeTimePerMsg < decode_time )
+ {
+ mCurrentRMessageTemplate->mMaxDecodeTimePerMsg = decode_time;
+ }
+
+
+ if( decode_time > mTimeDecodesSpamThreshold )
+ {
+ lldebugs << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " << decode_time << " seconds. (" <<
+ mCurrentRMessageTemplate->mMaxDecodeTimePerMsg << " max, " <<
+ (mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate->mTotalDecoded) << " avg)" << llendl;
+ }
+ }
+ }
+ return TRUE;
+}
+
+void LLMessageSystem::getDataFast(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)
+ {
+ llerrs << "No message waiting for decode 2!" << llendl;
+ return;
+ }
+
+ if (!mCurrentRMessageData)
+ {
+ llerrs << "Invalid mCurrentMessageData in getData!" << llendl;
+ 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::iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep);
+
+ if (iter == mCurrentRMessageData->mMemberBlocks.end())
+ {
+ llerrs << "Block " << blockname << " #" << blocknum
+ << " not in message " << mCurrentRMessageData->mName << llendl;
+ return;
+ }
+
+ LLMsgBlkData *msg_block_data = iter->second;
+ LLMsgVarData& vardata = msg_block_data->mMemberVarData[vnamep];
+
+ if (!vardata.getName())
+ {
+ llerrs << "Variable "<< vnamep << " not in message "
+ << mCurrentRMessageData->mName<< " block " << bnamep << llendl;
+ return;
+ }
+
+ if (size && size != vardata.getSize())
+ {
+ llerrs << "Msg " << mCurrentRMessageData->mName
+ << " variable " << vnamep
+ << " is size " << vardata.getSize()
+ << " but copying into buffer of size " << size
+ << llendl;
+ 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
+ {
+ llwarns << "Msg " << mCurrentRMessageData->mName
+ << " variable " << vnamep
+ << " is size " << vardata.getSize()
+ << " but truncated to max size of " << max_size
+ << llendl;
+
+ memcpy(datap, vardata.getData(), max_size);
+ }
+}
+
+S32 LLMessageSystem::getNumberOfBlocksFast(const char *blockname)
+{
+ // is there a message ready to go?
+ if (mReceiveSize == -1)
+ {
+ llerrs << "No message waiting for decode 3!" << llendl;
+ return -1;
+ }
+
+ if (!mCurrentRMessageData)
+ {
+ llerrs << "Invalid mCurrentRMessageData in getData!" << llendl;
+ return -1;
+ }
+
+ char *bnamep = (char *)blockname;
+
+ LLMsgData::msg_blk_data_map_t::iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep);
+
+ if (iter == mCurrentRMessageData->mMemberBlocks.end())
+ {
+// sprintf(errmsg, "Block %s not in message %s", bnamep, mCurrentRMessageData->mName);
+// llerrs << errmsg << llendl;
+// return -1;
+ return 0;
+ }
+
+ return (iter->second)->mBlockNumber;
+}
+
+S32 LLMessageSystem::getSizeFast(const char *blockname, const char *varname)
+{
+ // is there a message ready to go?
+ if (mReceiveSize == -1)
+ {
+ llerrs << "No message waiting for decode 4!" << llendl;
+ return -1;
+ }
+
+ if (!mCurrentRMessageData)
+ {
+ llerrs << "Invalid mCurrentRMessageData in getData!" << llendl;
+ return -1;
+ }
+
+ char *bnamep = (char *)blockname;
+
+ LLMsgData::msg_blk_data_map_t::iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep);
+
+ if (iter == mCurrentRMessageData->mMemberBlocks.end())
+ {
+ llerrs << "Block " << bnamep << " not in message "
+ << mCurrentRMessageData->mName << llendl;
+ return -1;
+ }
+
+ char *vnamep = (char *)varname;
+
+ LLMsgBlkData* msg_data = iter->second;
+ LLMsgVarData& vardata = msg_data->mMemberVarData[vnamep];
+
+ if (!vardata.getName())
+ {
+ llerrs << "Variable " << varname << " not in message "
+ << mCurrentRMessageData->mName << " block " << bnamep << llendl;
+ return -1;
+ }
+
+ if (mCurrentRMessageTemplate->mMemberBlocks[bnamep]->mType != MBT_SINGLE)
+ {
+ llerrs << "Block " << bnamep << " isn't type MBT_SINGLE,"
+ " use getSize with blocknum argument!" << llendl;
+ return -1;
+ }
+
+ return vardata.getSize();
+}
+
+
+S32 LLMessageSystem::getSizeFast(const char *blockname, S32 blocknum, const char *varname)
+{
+ // is there a message ready to go?
+ if (mReceiveSize == -1)
+ {
+ llerrs << "No message waiting for decode 5!" << llendl;
+ return -1;
+ }
+
+ if (!mCurrentRMessageData)
+ {
+ llerrs << "Invalid mCurrentRMessageData in getData!" << llendl;
+ return -1;
+ }
+
+ char *bnamep = (char *)blockname + blocknum;
+ char *vnamep = (char *)varname;
+
+ LLMsgData::msg_blk_data_map_t::iterator iter = mCurrentRMessageData->mMemberBlocks.find(bnamep);
+
+ if (iter == mCurrentRMessageData->mMemberBlocks.end())
+ {
+ llerrs << "Block " << bnamep << " not in message "
+ << mCurrentRMessageData->mName << llendl;
+ return -1;
+ }
+
+ LLMsgBlkData* msg_data = iter->second;
+ LLMsgVarData& vardata = msg_data->mMemberVarData[vnamep];
+
+ if (!vardata.getName())
+ {
+ llerrs << "Variable " << vnamep << " not in message "
+ << mCurrentRMessageData->mName << " block " << bnamep << llendl;
+ return -1;
+ }
+
+ return vardata.getSize();
+}
+
+
+void LLMessageSystem::sanityCheck()
+{
+ if (!mCurrentRMessageData)
+ {
+ llerrs << "mCurrentRMessageData is NULL" << llendl;
+ }
+
+ if (!mCurrentRMessageTemplate)
+ {
+ llerrs << "mCurrentRMessageTemplate is NULL" << llendl;
+ }
+
+// if (!mCurrentRTemplateBlock)
+// {
+// llerrs << "mCurrentRTemplateBlock is NULL" << llendl;
+// }
+
+// if (!mCurrentRDataBlock)
+// {
+// llerrs << "mCurrentRDataBlock is NULL" << llendl;
+// }
+
+ if (!mCurrentSMessageData)
+ {
+ llerrs << "mCurrentSMessageData is NULL" << llendl;
+ }
+
+ if (!mCurrentSMessageTemplate)
+ {
+ llerrs << "mCurrentSMessageTemplate is NULL" << llendl;
+ }
+
+// if (!mCurrentSTemplateBlock)
+// {
+// llerrs << "mCurrentSTemplateBlock is NULL" << llendl;
+// }
+
+ if (!mCurrentSDataBlock)
+ {
+ llerrs << "mCurrentSDataBlock is NULL" << llendl;
+ }
+}
+
+void LLMessageSystem::showCircuitInfo()
+{
+ llinfos << mCircuitInfo << llendl;
+}
+
+
+void LLMessageSystem::dumpCircuitInfo()
+{
+ lldebugst(LLERR_CIRCUIT_INFO) << mCircuitInfo << llendl;
+}
+
+/* virtual */
+U32 LLMessageSystem::getOurCircuitCode()
+{
+ return mOurCircuitCode;
+}
+
+LLString LLMessageSystem::getCircuitInfoString()
+{
+ LLString info_string;
+
+ info_string += mCircuitInfo.getInfoString();
+ return info_string;
+}
+
+// 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)
+{
+ llinfos << "LLMessageSystem::disableCircuit for " << host << llendl;
+ 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())
+ {
+ llinfos << "Circuit " << code << " removed from list" << llendl;
+ //mCircuitCodes.removeData(code);
+ mCircuitCodes.erase(it);
+ }
+
+ U64 ip_port = 0;
+ std::map<U32, U64>::iterator iter = gMessageSystem->mCircuitCodeToIPPort.find(code);
+ if (iter != gMessageSystem->mCircuitCodeToIPPort.end())
+ {
+ ip_port = iter->second;
+
+ gMessageSystem->mCircuitCodeToIPPort.erase(iter);
+
+ U32 old_port = (U32)(ip_port & (U64)0xFFFFFFFF);
+ U32 old_ip = (U32)(ip_port >> 32);
+
+ llinfos << "Host " << LLHost(old_ip, old_port) << " circuit " << code << " removed from lookup table" << llendl;
+ gMessageSystem->mIPPortToCircuitCode.erase(ip_port);
+ }
+ }
+ else
+ {
+ // Sigh, since we can open circuits which don't have circuit
+ // codes, it's possible for this to happen...
+
+ //llwarns << "Couldn't find circuit code for " << host << llendl;
+ }
+
+ mCircuitInfo.removeCircuitData(host);
+}
+
+
+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())
+ {
+ //llinfos << "checkCircuitBlocked: Unknown circuit " << circuit << llendl;
+ return TRUE;
+ }
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ return cdp->isBlocked();
+ }
+ else
+ {
+ llinfos << "checkCircuitBlocked(circuit): Unknown host - " << host << llendl;
+ return FALSE;
+ }
+}
+
+BOOL LLMessageSystem::checkCircuitAlive(const U32 circuit)
+{
+ LLHost host = findHost(circuit);
+
+ if (!host.isOk())
+ {
+ //llinfos << "checkCircuitAlive: Unknown circuit " << circuit << llendl;
+ return FALSE;
+ }
+
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ return cdp->isAlive();
+ }
+ else
+ {
+ llinfos << "checkCircuitAlive(circuit): Unknown host - " << host << llendl;
+ return FALSE;
+ }
+}
+
+BOOL LLMessageSystem::checkCircuitAlive(const LLHost &host)
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (cdp)
+ {
+ return cdp->isAlive();
+ }
+ else
+ {
+ //llinfos << "checkCircuitAlive(host): Unknown host - " << host << llendl;
+ 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::invalid;
+ }
+}
+
+void LLMessageSystem::setMaxMessageTime(const F32 seconds)
+{
+ mMaxMessageTime = 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;
+}
+
+LLMessageSystem *gMessageSystem = NULL;
+
+// 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())
+ {
+ llwarns << "AssignCircuitCode, bad session id. Expecting "
+ << msg->getMySessionID() << " but got " << session_id
+ << llendl;
+ return;
+ }
+ U32 code;
+ msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, code);
+ if (!code)
+ {
+ llerrs << "Assigning circuit code of zero!" << llendl;
+ }
+
+ msg->mOurCircuitCode = code;
+ llinfos << "Circuit code " << code << " assigned." << llendl;
+}
+*/
+
+// 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)
+ {
+ llwarns << "addCircuitCode: zero circuit code" << llendl;
+ return false;
+ }
+ code_session_map_t::iterator it = mCircuitCodes.find(code);
+ if(it == mCircuitCodes.end())
+ {
+ llinfos << "New circuit code " << code << " added" << llendl;
+ //msg->mCircuitCodes[circuit_code] = circuit_code;
+
+ mCircuitCodes.insert(code_session_map_t::value_type(code, session_id));
+ }
+ else
+ {
+ llinfos << "Duplicate circuit code " << code << " added" << llendl;
+ }
+ 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**)
+{
+ 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.
+ llwarns << "UseCircuitCode for " << circuit_code_in
+ << " received without AddCircuitCode message - aborting"
+ << llendl;
+ 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)
+ {
+ llwarns << "UseCircuitCode unmatched session id. Got "
+ << session_id << " but expected " << (*it).second
+ << llendl;
+ 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
+ llinfos << "Got duplicate UseCircuitCode for circuit " << circuit_code_in << " to " << msg->getSender() << llendl;
+ 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);
+ llinfos << "Removing derelict lookup entry for circuit " << circuit_code_old << " to " << LLHost(old_ip, old_port) << llendl;
+ }
+
+ if (circuit_code_old)
+ {
+ LLHost cur_host(ip, port);
+
+ llwarns << "Disabling existing circuit for " << cur_host << llendl;
+ msg->disableCircuit(cur_host);
+ if (circuit_code_old == circuit_code_in)
+ {
+ llwarns << "Asymmetrical circuit to ip/port lookup!" << llendl;
+ llwarns << "Multiple circuit codes for " << cur_host << " probably!" << llendl;
+ llwarns << "Permanently disabling circuit" << llendl;
+ return;
+ }
+ else
+ {
+ llwarns << "Circuit code changed for " << msg->getSender()
+ << " from " << circuit_code_old << " to "
+ << circuit_code_in << llendl;
+ }
+ }
+
+ // Since this comes from the viewer, it's untrusted, but it
+ // passed the circuit code and session id check, so we will go
+ // ahead and persist the ID associated.
+ LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
+ BOOL had_circuit_already = cdp ? TRUE : FALSE;
+
+ msg->enableCircuit(msg->getSender(), FALSE);
+ cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
+ if(cdp)
+ {
+ cdp->setRemoteID(id);
+ cdp->setRemoteSessionID(session_id);
+ }
+
+ if (!had_circuit_already)
+ {
+ //
+ // HACK HACK HACK HACK HACK!
+ //
+ // This would NORMALLY happen inside logValidMsg, but at the point that this happens
+ // inside logValidMsg, there's no circuit for this message yet. So the awful thing that
+ // we do here is do it inside this message handler immediately AFTER the message is
+ // handled.
+ //
+ // We COULD not do this, but then what happens is that some of the circuit bookkeeping
+ // gets broken, especially the packets in count. That causes some later packets to flush
+ // the RecentlyReceivedReliable list, resulting in an error in which UseCircuitCode
+ // doesn't get properly duplicate suppressed. Not a BIG deal, but it's somewhat confusing
+ // (and bad from a state point of view). DJS 9/23/04
+ //
+ cdp->checkPacketInID(gMessageSystem->mCurrentRecvPacketID, FALSE ); // Since this is the first message on the circuit, by definition it's not resent.
+ }
+
+ msg->mIPPortToCircuitCode[ip_port_in] = circuit_code_in;
+ msg->mCircuitCodeToIPPort[circuit_code_in] = ip_port_in;
+
+ llinfos << "Circuit code " << circuit_code_in << " from "
+ << msg->getSender() << " for agent " << id << " in session "
+ << session_id << llendl;
+ }
+ else
+ {
+ llwarns << "Got zero circuit code in use_circuit_code" << llendl;
+ }
+}
+
+
+
+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 = gMessageStringTable.getString(iter->first.c_str());
+
+ if (templates.find(name) == templates.end())
+ {
+ llinfos << " " << type
+ << " ban list contains unrecognized message "
+ << name << llendl;
+ }
+ }
+}
+
+void LLMessageSystem::setMessageBans(
+ const LLSD& trusted, const LLSD& untrusted)
+{
+ llinfos << "LLMessageSystem::setMessageBans:" << llendl;
+ 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)
+ {
+ llinfos << " " << name << " banned from "
+ << (ban_from_trusted ? "TRUSTED " : " ")
+ << (ban_from_untrusted ? "UNTRUSTED " : " ")
+ << llendl;
+ any_set = true;
+ }
+ }
+
+ if (!any_set)
+ {
+ llinfos << " no messages banned" << llendl;
+ }
+
+ check_for_unrecognized_messages("trusted", trusted, mMessageTemplates);
+ check_for_unrecognized_messages("untrusted", untrusted, mMessageTemplates);
+}
+
+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);
+// llinfos << "ack recvd' from " << host << " for packet " << (TPACKETID)packet_id << llendl;
+ cdp->ackReliablePacket(packet_id);
+ }
+ if (!cdp->getUnackedPacketCount())
+ {
+ // Remove this circuit from the list of circuits with unacked packets
+ gMessageSystem->mCircuitInfo.mUnackedCircuitMap.erase(host);
+ }
+ }
+}
+
+void send_template_reply(LLMessageSystem* msg, const LLUUID& token)
+{
+ msg->newMessageFast(_PREHASH_TemplateChecksumReply);
+ msg->nextBlockFast(_PREHASH_DataBlock);
+ msg->addU32Fast(_PREHASH_Checksum, msg->mMessageFileChecksum);
+ msg->addU8Fast(_PREHASH_MajorVersion, U8(msg->mSystemVersionMajor) );
+ msg->addU8Fast(_PREHASH_MinorVersion, U8(msg->mSystemVersionMinor) );
+ msg->addU8Fast(_PREHASH_PatchVersion, U8(msg->mSystemVersionPatch) );
+ msg->addU8Fast(_PREHASH_ServerVersion, U8(msg->mSystemVersionServer) );
+ msg->addU32Fast(_PREHASH_Flags, msg->mVersionFlags);
+ msg->nextBlockFast(_PREHASH_TokenBlock);
+ msg->addUUIDFast(_PREHASH_Token, token);
+ msg->sendMessage(msg->getSender());
+}
+
+void process_template_checksum_request(LLMessageSystem* msg, void**)
+{
+ llinfos << "Message template checksum request received from "
+ << msg->getSender() << llendl;
+ send_template_reply(msg, LLUUID::null);
+}
+
+void process_secured_template_checksum_request(LLMessageSystem* msg, void**)
+{
+ llinfos << "Secured message template checksum request received from "
+ << msg->getSender() << llendl;
+ LLUUID token;
+ msg->getUUIDFast(_PREHASH_TokenBlock, _PREHASH_Token, token);
+ send_template_reply(msg, token);
+}
+
+void process_log_control(LLMessageSystem* msg, void**)
+{
+ U8 level;
+ U32 mask;
+ BOOL time;
+ BOOL location;
+ BOOL remote_infos;
+
+ msg->getU8Fast(_PREHASH_Options, _PREHASH_Level, level);
+ msg->getU32Fast(_PREHASH_Options, _PREHASH_Mask, mask);
+ msg->getBOOLFast(_PREHASH_Options, _PREHASH_Time, time);
+ msg->getBOOLFast(_PREHASH_Options, _PREHASH_Location, location);
+ msg->getBOOLFast(_PREHASH_Options, _PREHASH_RemoteInfos, remote_infos);
+
+ gErrorStream.setLevel(LLErrorStream::ELevel(level));
+ gErrorStream.setDebugMask(mask);
+ gErrorStream.setTime(time);
+ gErrorStream.setPrintLocation(location);
+ gErrorStream.setElevatedRemote(remote_infos);
+
+ llinfos << "Logging set to level " << gErrorStream.getLevel()
+ << " mask " << std::hex << gErrorStream.getDebugMask() << std::dec
+ << " time " << gErrorStream.getTime()
+ << " loc " << gErrorStream.getPrintLocation()
+ << llendl;
+}
+
+void process_log_messages(LLMessageSystem* msg, void**)
+{
+ U8 log_message;
+
+ msg->getU8Fast(_PREHASH_Options, _PREHASH_Enable, log_message);
+
+ if (log_message)
+ {
+ llinfos << "Starting logging via message" << llendl;
+ msg->startLogging();
+ }
+ else
+ {
+ llinfos << "Stopping logging via message" << llendl;
+ 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)
+ {
+ llwarns << "Attempt to create trusted circuit without circuit data: "
+ << msg->getSender() << llendl;
+ 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;
+ }
+
+ char their_digest[MD5HEX_STR_SIZE];
+ msg->getBinaryDataFast(_PREHASH_DataBlock, _PREHASH_Digest, their_digest, 32);
+ their_digest[MD5HEX_STR_SIZE - 1] = '\0';
+ if(msg->isMatchingDigestForWindowAndUUIDs(their_digest, TRUST_TIME_WINDOW, local_id, remote_id))
+ {
+ cdp->setTrusted(TRUE);
+ llinfos << "Trusted digest from " << msg->getSender() << llendl;
+ 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.
+ llwarns << "Ignoring bad digest from known trusted circuit: " << their_digest
+ << " host: " << msg->getSender() << llendl;
+ return;
+ }
+ else
+ {
+ llwarns << "Bad digest from known circuit: " << their_digest
+ << " host: " << msg->getSender() << llendl;
+ 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;
+ }
+
+ // 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.
+ // FIXME: probably should keep a count of number of resends
+ // per circuit, and stop resending after a while.
+ llinfos << "Got DenyTrustedCircuit. Sending CreateTrustedCircuit to "
+ << msg->getSender() << llendl;
+ msg->sendCreateTrustedCircuit(msg->getSender(), local_id, remote_id);
+}
+
+#define LL_ENCRYPT_BUF_LENGTH 16384
+
+void encrypt_template(const char *src_name, const char *dest_name)
+{
+ // encrypt and decrypt are symmetric
+ decrypt_template(src_name, dest_name);
+}
+
+BOOL decrypt_template(const char *src_name, const char *dest_name)
+{
+ S32 buf_length = LL_ENCRYPT_BUF_LENGTH;
+ char buf[LL_ENCRYPT_BUF_LENGTH];
+
+ FILE* infp = NULL;
+ FILE* outfp = NULL;
+ BOOL success = FALSE;
+ char* bufp = NULL;
+ U32 key = 0;
+ S32 more_data = 0;
+
+ if(src_name==NULL)
+ {
+ llwarns << "Input src_name is NULL!!" << llendl;
+ goto exit;
+ }
+
+ infp = LLFile::fopen(src_name,"rb");
+ if (!infp)
+ {
+ llwarns << "could not open " << src_name << " for reading" << llendl;
+ goto exit;
+ }
+
+ if(dest_name==NULL)
+ {
+ llwarns << "Output dest_name is NULL!!" << llendl;
+ goto exit;
+ }
+
+ outfp = LLFile::fopen(dest_name,"w+b");
+ if (!outfp)
+ {
+ llwarns << "could not open " << src_name << " for writing" << llendl;
+ goto exit;
+ }
+
+ while ((buf_length = (S32)fread(buf,1,LL_ENCRYPT_BUF_LENGTH,infp)))
+ {
+ // unscrozzle bits here
+ bufp = buf;
+ more_data = buf_length;
+ while (more_data--)
+ {
+ *bufp = *bufp ^ ((key * 43) % 256);
+ key++;
+ bufp++;
+ }
+
+ if(buf_length != (S32)fwrite(buf,1,buf_length,outfp))
+ {
+ goto exit;
+ }
+ }
+ success = TRUE;
+
+ exit:
+ if(infp) fclose(infp);
+ if(outfp) fclose(outfp);
+ return success;
+}
+
+void dump_prehash_files()
+{
+ U32 i;
+ FILE *fp = LLFile::fopen("../../indra/llmessage/message_prehash.h", "w");
+ if (fp)
+ {
+ fprintf(
+ fp,
+ "/**\n"
+ " * @file message_prehash.h\n"
+ " * @brief header file of externs of prehashed variables plus defines.\n"
+ " *\n"
+ " * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.\n"
+ " * $License$\n"
+ " */\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 gPrehashVersionNumber;\n\n");
+ for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
+ {
+ if (!gMessageStringTable.mEmpty[i] && gMessageStringTable.mString[i][0] != '.')
+ {
+ fprintf(fp, "extern char * _PREHASH_%s;\n", gMessageStringTable.mString[i]);
+ }
+ }
+ fprintf(fp, "\n\nvoid init_prehash_data();\n\n");
+ fprintf(fp, "\n\n");
+ fprintf(fp, "\n\n#endif\n");
+ fclose(fp);
+ }
+ fp = LLFile::fopen("../../indra/llmessage/message_prehash.cpp", "w");
+ if (fp)
+ {
+ fprintf(
+ fp,
+ "/**\n"
+ " * @file message_prehash.cpp\n"
+ " * @brief file of prehashed variables\n"
+ " *\n"
+ " * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.\n"
+ " * $License$\n"
+ " */\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 gPrehashVersionNumber = %.3ff;\n\n", gMessageSystem->mMessageFileVersionNumber);
+ for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
+ {
+ if (!gMessageStringTable.mEmpty[i] && gMessageStringTable.mString[i][0] != '.')
+ {
+ fprintf(fp, "char * _PREHASH_%s;\n", gMessageStringTable.mString[i]);
+ }
+ }
+ fprintf(fp, "\nvoid init_prehash_data()\n");
+ fprintf(fp, "{\n");
+ for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
+ {
+ if (!gMessageStringTable.mEmpty[i] && gMessageStringTable.mString[i][0] != '.')
+ {
+ fprintf(fp, "\t_PREHASH_%s = gMessageStringTable.getString(\"%s\");\n", gMessageStringTable.mString[i], gMessageStringTable.mString[i]);
+ }
+ }
+ fprintf(fp, "}\n");
+ 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)
+{
+ gMessageSystem = new LLMessageSystem(
+ template_name.c_str(),
+ port,
+ version_major,
+ version_minor,
+ version_patch);
+ g_shared_secret.assign(secret);
+
+ if (!gMessageSystem)
+ {
+ llerrs << "Messaging system initialization failed." << llendl;
+ return FALSE;
+ }
+
+ // bail if system encountered an error.
+ if(!gMessageSystem->isOK())
+ {
+ return FALSE;
+ }
+
+ if (b_dump_prehash_file)
+ {
+ dump_prehash_files();
+ exit(0);
+ }
+ else
+ {
+ init_prehash_data();
+ if (gMessageSystem->mMessageFileVersionNumber != gPrehashVersionNumber)
+ {
+ llinfos << "Message template version does not match prehash version number" << llendl;
+ llinfos << "Run simulator with -prehash command line option to rebuild prehash data" << llendl;
+ }
+ else
+ {
+ llinfos << "Message template version matches prehash version number" << llendl;
+ }
+ }
+
+ 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);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_PacketAck, process_packet_ack, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_TemplateChecksumRequest, process_template_checksum_request, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_SecuredTemplateChecksumRequest, process_secured_template_checksum_request, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_LogControl, process_log_control, 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);
+
+ // We can hand this to the null_message_callback since it is a
+ // trusted message, so it will automatically be denied if it isn't
+ // trusted and ignored if it is -- exactly what we want.
+ gMessageSystem->setHandlerFunc(
+ "RequestTrustedCircuit",
+ null_message_callback,
+ NULL);
+
+ // Initialize the transfer manager
+ gTransferManager.init();
+
+ return TRUE;
+}
+
+void LLMessageSystem::startLogging()
+{
+ mVerboseLog = TRUE;
+ std::ostringstream str;
+ str << "START MESSAGE LOG" << std::endl;
+ str << "Legend:" << std::endl;
+ str << "\t<-\tincoming message" <<std::endl;
+ str << "\t->\toutgoing message" << std::endl;
+ str << " <> host size zero id name";
+ llinfos << str.str() << llendl;
+}
+
+void LLMessageSystem::stopLogging()
+{
+ if(mVerboseLog)
+ {
+ mVerboseLog = FALSE;
+ llinfos << "END MESSAGE LOG" << llendl;
+ }
+}
+
+void LLMessageSystem::summarizeLogs(std::ostream& str)
+{
+ char buffer[MAX_STRING]; /* Flawfinder: ignore */
+ char tmp_str[MAX_STRING]; /* Flawfinder: ignore */
+ F32 run_time = mMessageSystemTimer.getElapsedTimeF32();
+ str << "START MESSAGE LOG SUMMARY" << std::endl;
+ snprintf(buffer, MAX_STRING, "Run time: %12.3f seconds", run_time); /* Flawfinder: ignore */
+
+ // Incoming
+ str << buffer << std::endl << "Incoming:" << std::endl;
+ U64_to_str(mTotalBytesIn, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total bytes received: %20s (%5.2f kbits per second)", tmp_str, ((F32)mTotalBytesIn * 0.008f) / run_time); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(mPacketsIn, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total packets received: %20s (%5.2f packets per second)", tmp_str, ((F32) mPacketsIn / run_time)); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ snprintf(buffer, MAX_STRING, "Average packet size: %20.0f bytes", (F32)mTotalBytesIn / (F32)mPacketsIn); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(mReliablePacketsIn, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total reliable packets: %20s (%5.2f%%)", tmp_str, 100.f * ((F32) mReliablePacketsIn)/((F32) mPacketsIn + 1)); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(mCompressedPacketsIn, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total compressed packets: %20s (%5.2f%%)", tmp_str, 100.f * ((F32) mCompressedPacketsIn)/((F32) mPacketsIn + 1)); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ S64 savings = mUncompressedBytesIn - mCompressedBytesIn;
+ U64_to_str(savings, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total compression savings: %20s bytes", tmp_str); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(savings/(mCompressedPacketsIn +1), tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str, ((F32) mUncompressedBytesIn)/((F32) mCompressedBytesIn+1)); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(savings/(mPacketsIn+1), tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str, ((F32) mTotalBytesIn + (F32) savings)/((F32) mTotalBytesIn + 1.f)); /* Flawfinder: ignore */
+
+ // Outgoing
+ str << buffer << std::endl << std::endl << "Outgoing:" << std::endl;
+ U64_to_str(mTotalBytesOut, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total bytes sent: %20s (%5.2f kbits per second)", tmp_str, ((F32)mTotalBytesOut * 0.008f) / run_time ); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(mPacketsOut, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total packets sent: %20s (%5.2f packets per second)", tmp_str, ((F32)mPacketsOut / run_time)); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ snprintf(buffer, MAX_STRING, "Average packet size: %20.0f bytes", (F32)mTotalBytesOut / (F32)mPacketsOut); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(mReliablePacketsOut, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total reliable packets: %20s (%5.2f%%)", tmp_str, 100.f * ((F32) mReliablePacketsOut)/((F32) mPacketsOut + 1)); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(mCompressedPacketsOut, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total compressed packets: %20s (%5.2f%%)", tmp_str, 100.f * ((F32) mCompressedPacketsOut)/((F32) mPacketsOut + 1)); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ savings = mUncompressedBytesOut - mCompressedBytesOut;
+ U64_to_str(savings, tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Total compression savings: %20s bytes", tmp_str); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(savings/(mCompressedPacketsOut +1), tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str, ((F32) mUncompressedBytesOut)/((F32) mCompressedBytesOut+1)); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ U64_to_str(savings/(mPacketsOut+1), tmp_str, sizeof(tmp_str));
+ snprintf(buffer, MAX_STRING, "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str, ((F32) mTotalBytesOut + (F32) savings)/((F32) mTotalBytesOut + 1.f)); /* Flawfinder: ignore */
+ str << buffer << std::endl << std::endl;
+ snprintf(buffer, MAX_STRING, "SendPacket failures: %20d", mSendPacketFailureCount); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ snprintf(buffer, MAX_STRING, "Dropped packets: %20d", mDroppedPackets); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ snprintf(buffer, MAX_STRING, "Resent packets: %20d", mResentPackets); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ snprintf(buffer, MAX_STRING, "Failed reliable resends: %20d", mFailedResendPackets); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ snprintf(buffer, MAX_STRING, "Off-circuit rejected packets: %17d", mOffCircuitPackets); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ snprintf(buffer, MAX_STRING, "On-circuit invalid packets: %17d", mInvalidOnCircuitPackets); /* Flawfinder: ignore */
+ str << buffer << std::endl << std::endl;
+
+ str << "Decoding: " << std::endl;
+ snprintf(buffer, MAX_STRING, "%35s%10s%10s%10s%10s", "Message", "Count", "Time", "Max", "Avg"); /* Flawfinder: ignore */
+ str << buffer << std:: endl;
+ F32 avg;
+ for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(),
+ end = mMessageTemplates.end();
+ iter != end; iter++)
+ {
+ LLMessageTemplate* mt = iter->second;
+ if(mt->mTotalDecoded > 0)
+ {
+ avg = mt->mTotalDecodeTime / (F32)mt->mTotalDecoded;
+ snprintf(buffer, MAX_STRING, "%35s%10u%10f%10f%10f", mt->mName, mt->mTotalDecoded, mt->mTotalDecodeTime, mt->mMaxDecodeTimePerMsg, avg); /* Flawfinder: ignore */
+ str << buffer << std::endl;
+ }
+ }
+ str << "END MESSAGE LOG SUMMARY" << std::endl;
+}
+
+void end_messaging_system()
+{
+ gTransferManager.cleanup();
+ LLTransferTargetVFile::updateQueue(true); // shutdown LLTransferTargetVFile
+ if (gMessageSystem)
+ {
+ gMessageSystem->stopLogging();
+
+ std::ostringstream str;
+ gMessageSystem->summarizeLogs(str);
+ llinfos << str.str().c_str() << llendl;
+
+ delete 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)
+ {
+ llinfos << "Dump: " << mNumMessageCounts << " messages processed in " << mReceiveTime << " seconds" << llendl;
+ for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(),
+ end = mMessageTemplates.end();
+ iter != end; iter++)
+ {
+ LLMessageTemplate* mt = iter->second;
+ if (mt->mReceiveCount > 0)
+ {
+ llinfos << "Num: " << std::setw(3) << mt->mReceiveCount << " Bytes: " << std::setw(6) << mt->mReceiveBytes
+ << " Invalid: " << std::setw(3) << mt->mReceiveInvalid << " " << mt->mName << " " << llround(100 * mt->mDecodeTimeThisFrame / mReceiveTime) << "%" << llendl;
+ }
+ }
+ }
+}
+
+
+
+BOOL LLMessageSystem::isClear() const
+{
+ return mbSClear;
+}
+
+
+S32 LLMessageSystem::flush(const LLHost &host)
+{
+ if (mCurrentSendTotal)
+ {
+ S32 sentbytes = sendMessage(host);
+ clearMessage();
+ return sentbytes;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+U32 LLMessageSystem::getListenPort( void ) const
+{
+ return mPort;
+}
+
+
+S32 LLMessageSystem::zeroCode(U8 **data, S32 *data_size)
+{
+ S32 count = *data_size;
+
+ S32 net_gain = 0;
+ U8 num_zeroes = 0;
+
+ U8 *inptr = (U8 *)*data;
+ U8 *outptr = (U8 *)mEncodedSendBuffer;
+
+// skip the packet id field
+
+ for (U32 i=0;i<LL_PACKET_ID_SIZE;i++)
+ {
+ 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)
+ {
+ mCompressedPacketsOut++;
+ mUncompressedBytesOut += *data_size;
+
+ *data = mEncodedSendBuffer;
+ *data_size += net_gain;
+ mEncodedSendBuffer[0] |= LL_ZERO_CODE_FLAG; // set the head bit to indicate zero coding
+
+ mCompressedBytesOut += *data_size;
+
+ }
+ mTotalBytesOut += *data_size;
+
+ return(net_gain);
+}
+
+S32 LLMessageSystem::zeroCodeAdjustCurrentSendTotal()
+{
+ if (!mbSBuilt)
+ {
+ buildMessage();
+ }
+ mbSBuilt = FALSE;
+
+ S32 count = mSendSize;
+
+ S32 net_gain = 0;
+ U8 num_zeroes = 0;
+
+ U8 *inptr = (U8 *)mSendBuffer;
+
+// skip the packet id field
+
+ for (U32 i=0;i<LL_PACKET_ID_SIZE;i++)
+ {
+ 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_PACKET_ID_SIZE)
+ {
+ llwarns << "zeroCodeExpand() called with data_size of " << *data_size << llendl;
+ }
+
+ mTotalBytesIn += *data_size;
+
+ if (!(*data[0] & LL_ZERO_CODE_FLAG)) // if we're not zero-coded, just go 'way
+ {
+ 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 i=0;i<LL_PACKET_ID_SIZE;i++)
+ {
+ 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]))
+ {
+ llwarns << "attempt to write past reasonable encoded buffer size 1" << llendl;
+ callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE);
+ outptr = mEncodedRecvBuffer;
+ break;
+ }
+ if (!((*outptr++ = *inptr++)))
+ {
+ while (((count--)) && (!(*inptr)))
+ {
+ *outptr++ = *inptr++;
+ if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-256]))
+ {
+ llwarns << "attempt to write past reasonable encoded buffer size 2" << llendl;
+ 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)]))
+ {
+ llwarns << "attempt to write past reasonable encoded buffer size 3" << llendl;
+ 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)
+ {
+ llerrs << templatep->mName << " already used as a template name!"
+ << llendl;
+ }
+ 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
+ {
+ llerrs << name << " is not a known message name!" << llendl;
+ }
+}
+
+
+bool LLMessageSystem::callHandler(const char *name,
+ bool trustedSource, LLMessageSystem* msg)
+{
+ name = gMessageStringTable.getString(name);
+ LLMessageTemplate* msg_template = mMessageTemplates[(char*)name];
+ if (!msg_template)
+ {
+ llwarns << "LLMessageSystem::callHandler: unknown message "
+ << name << llendl;
+ return false;
+ }
+
+ if (msg_template->isBanned(trustedSource))
+ {
+ llwarns << "LLMessageSystem::callHandler: banned message "
+ << name
+ << " from "
+ << (trustedSource ? "trusted " : "untrusted ")
+ << "source" << llendl;
+ 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())
+ {
+ ((*it).second.first)(this, (*it).second.second,exception);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL LLMessageSystem::isCircuitCodeKnown(U32 code) const
+{
+ if(mCircuitCodes.find(code) == mCircuitCodes.end())
+ return FALSE;
+ return TRUE;
+}
+
+BOOL LLMessageSystem::isMessageFast(const char *msg)
+{
+ if (mCurrentRMessageTemplate)
+ {
+ return(msg == mCurrentRMessageTemplate->mName);
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+char* LLMessageSystem::getMessageName()
+{
+ if (mCurrentRMessageTemplate)
+ {
+ return mCurrentRMessageTemplate->mName;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+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;
+}
+
+void LLMessageSystem::addVector3Fast(const char *varname, const LLVector3& vec)
+{
+ addDataFast(varname, vec.mV, MVT_LLVector3, sizeof(vec.mV));
+}
+
+void LLMessageSystem::addVector3(const char *varname, const LLVector3& vec)
+{
+ addDataFast(gMessageStringTable.getString(varname), vec.mV, MVT_LLVector3, sizeof(vec.mV));
+}
+
+void LLMessageSystem::addVector4Fast(const char *varname, const LLVector4& vec)
+{
+ addDataFast(varname, vec.mV, MVT_LLVector4, sizeof(vec.mV));
+}
+
+void LLMessageSystem::addVector4(const char *varname, const LLVector4& vec)
+{
+ addDataFast(gMessageStringTable.getString(varname), vec.mV, MVT_LLVector4, sizeof(vec.mV));
+}
+
+
+void LLMessageSystem::addVector3dFast(const char *varname, const LLVector3d& vec)
+{
+ addDataFast(varname, vec.mdV, MVT_LLVector3d, sizeof(vec.mdV));
+}
+
+void LLMessageSystem::addVector3d(const char *varname, const LLVector3d& vec)
+{
+ addDataFast(gMessageStringTable.getString(varname), vec.mdV, MVT_LLVector3d, sizeof(vec.mdV));
+}
+
+
+void LLMessageSystem::addQuatFast(const char *varname, const LLQuaternion& quat)
+{
+ addDataFast(varname, quat.packToVector3().mV, MVT_LLQuaternion, sizeof(LLVector3));
+}
+
+void LLMessageSystem::addQuat(const char *varname, const LLQuaternion& quat)
+{
+ addDataFast(gMessageStringTable.getString(varname), quat.packToVector3().mV, MVT_LLQuaternion, sizeof(LLVector3));
+}
+
+
+void LLMessageSystem::addUUIDFast(const char *varname, const LLUUID& uuid)
+{
+ addDataFast(varname, uuid.mData, MVT_LLUUID, sizeof(uuid.mData));
+}
+
+void LLMessageSystem::addUUID(const char *varname, const LLUUID& uuid)
+{
+ addDataFast(gMessageStringTable.getString(varname), uuid.mData, MVT_LLUUID, sizeof(uuid.mData));
+}
+
+void LLMessageSystem::getF32Fast(const char *block, const char *var, F32 &d, S32 blocknum)
+{
+ getDataFast(block, var, &d, sizeof(F32), blocknum);
+
+ if( !llfinite( d ) )
+ {
+ llwarns << "non-finite in getF32Fast " << block << " " << var << llendl;
+ d = 0;
+ }
+}
+
+void LLMessageSystem::getF32(const char *block, const char *var, F32 &d, S32 blocknum)
+{
+ getDataFast(gMessageStringTable.getString(block), gMessageStringTable.getString(var), &d, sizeof(F32), blocknum);
+
+ if( !llfinite( d ) )
+ {
+ llwarns << "non-finite in getF32 " << block << " " << var << llendl;
+ d = 0;
+ }
+}
+
+void LLMessageSystem::getF64Fast(const char *block, const char *var, F64 &d, S32 blocknum)
+{
+ getDataFast(block, var, &d, sizeof(F64), blocknum);
+
+ if( !llfinite( d ) )
+ {
+ llwarns << "non-finite in getF64Fast " << block << " " << var << llendl;
+ d = 0;
+ }
+}
+
+void LLMessageSystem::getF64(const char *block, const char *var, F64 &d, S32 blocknum)
+{
+ getDataFast(gMessageStringTable.getString(block), gMessageStringTable.getString(var), &d, sizeof(F64), blocknum);
+
+ if( !llfinite( d ) )
+ {
+ llwarns << "non-finite in getF64 " << block << " " << var << llendl;
+ d = 0;
+ }
+}
+
+
+void LLMessageSystem::getVector3Fast(const char *block, const char *var, LLVector3 &v, S32 blocknum )
+{
+ getDataFast(block, var, v.mV, sizeof(v.mV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ llwarns << "non-finite in getVector3Fast " << block << " " << var << llendl;
+ v.zeroVec();
+ }
+}
+
+void LLMessageSystem::getVector3(const char *block, const char *var, LLVector3 &v, S32 blocknum )
+{
+ getDataFast(gMessageStringTable.getString(block), gMessageStringTable.getString(var), v.mV, sizeof(v.mV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ llwarns << "non-finite in getVector4 " << block << " " << var << llendl;
+ v.zeroVec();
+ }
+}
+
+void LLMessageSystem::getVector4Fast(const char *block, const char *var, LLVector4 &v, S32 blocknum )
+{
+ getDataFast(block, var, v.mV, sizeof(v.mV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ llwarns << "non-finite in getVector4Fast " << block << " " << var << llendl;
+ v.zeroVec();
+ }
+}
+
+void LLMessageSystem::getVector4(const char *block, const char *var, LLVector4 &v, S32 blocknum )
+{
+ getDataFast(gMessageStringTable.getString(block), gMessageStringTable.getString(var), v.mV, sizeof(v.mV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ llwarns << "non-finite in getVector3 " << block << " " << var << llendl;
+ v.zeroVec();
+ }
+}
+
+void LLMessageSystem::getVector3dFast(const char *block, const char *var, LLVector3d &v, S32 blocknum )
+{
+ getDataFast(block, var, v.mdV, sizeof(v.mdV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ llwarns << "non-finite in getVector3dFast " << block << " " << var << llendl;
+ v.zeroVec();
+ }
+
+}
+
+void LLMessageSystem::getVector3d(const char *block, const char *var, LLVector3d &v, S32 blocknum )
+{
+ getDataFast(gMessageStringTable.getString(block), gMessageStringTable.getString(var), v.mdV, sizeof(v.mdV), blocknum);
+
+ if( !v.isFinite() )
+ {
+ llwarns << "non-finite in getVector3d " << block << " " << var << llendl;
+ v.zeroVec();
+ }
+}
+
+void LLMessageSystem::getQuatFast(const char *block, const char *var, LLQuaternion &q, S32 blocknum )
+{
+ LLVector3 vec;
+ getDataFast(block, var, vec.mV, sizeof(vec.mV), blocknum);
+ if( vec.isFinite() )
+ {
+ q.unpackFromVector3( vec );
+ }
+ else
+ {
+ llwarns << "non-finite in getQuatFast " << block << " " << var << llendl;
+ q.loadIdentity();
+ }
+}
+
+void LLMessageSystem::getQuat(const char *block, const char *var, LLQuaternion &q, S32 blocknum )
+{
+ LLVector3 vec;
+ getDataFast(gMessageStringTable.getString(block), gMessageStringTable.getString(var), vec.mV, sizeof(vec.mV), blocknum);
+ if( vec.isFinite() )
+ {
+ q.unpackFromVector3( vec );
+ }
+ else
+ {
+ llwarns << "non-finite in getQuat " << block << " " << var << llendl;
+ q.loadIdentity();
+ }
+}
+
+void LLMessageSystem::getUUIDFast(const char *block, const char *var, LLUUID &u, S32 blocknum )
+{
+ getDataFast(block, var, u.mData, sizeof(u.mData), blocknum);
+}
+
+void LLMessageSystem::getUUID(const char *block, const char *var, LLUUID &u, S32 blocknum )
+{
+ getDataFast(gMessageStringTable.getString(block), gMessageStringTable.getString(var), u.mData, sizeof(u.mData), blocknum);
+}
+
+bool LLMessageSystem::generateDigestForNumberAndUUIDs(char* digest, const U32 number, const LLUUID &id1, const LLUUID &id2) const
+{
+ const char *colon = ":";
+ char tbuf[16]; /* Flawfinder: ignore */
+ LLMD5 d;
+ LLString id1string = id1.getString();
+ LLString id2string = id2.getString();
+ 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));
+ }
+
+ 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));
+ }
+ d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
+
+ if( (char*) id2str != NULL)
+ {
+ d.update(id2str, (U32)strlen((char *) id2str));
+ }
+
+ 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())
+ {
+ llerrs << "Trying to generate complex digest on a machine without a shared secret!" << llendl;
+ }
+
+ U32 now = 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())
+ {
+ llerrs << "Trying to compare complex digests on a machine without a shared secret!" << llendl;
+ }
+
+ char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
+ U32 now = 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())
+ {
+ llerrs << "Trying to generate simple digest on a machine without a shared secret!" << llendl;
+ }
+
+ U32 now = 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())
+ {
+ llerrs << "Trying to compare simple digests on a machine without a shared secret!" << llendl;
+ }
+
+ 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())
+ {
+ llwarns << "Can't send CreateTrustedCircuit to " << host << " because we don't have the local end point ID" << llendl;
+ return;
+ }
+ if (id2.isNull())
+ {
+ llwarns << "Can't send CreateTrustedCircuit to " << host << " because we don't have the remote end point ID" << llendl;
+ 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);
+ llinfos << "xmitting digest: " << digest << " Host: " << host << llendl;
+ sendMessage(host);
+}
+
+void LLMessageSystem::sendDenyTrustedCircuit(const LLHost &host)
+{
+ mDenyTrustedCircuitSet.insert(host);
+}
+
+void LLMessageSystem::reallySendDenyTrustedCircuit(const LLHost &host)
+{
+ LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
+ if (!cdp)
+ {
+ llwarns << "Not sending DenyTrustedCircuit to host without a circuit." << llendl;
+ return;
+ }
+ llinfos << "Sending DenyTrustedCircuit to " << host << llendl;
+ 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 )
+{
+ std::string shared_secret = get_shared_secret();
+ if(shared_secret.empty())
+ {
+ llerrs << "Trying to establish bidirectional trust on a machine without a shared secret!" << llendl;
+ }
+ 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 (checkMessages( frame_count ))
+ {
+ if (isMessageFast(_PREHASH_CompletePingCheck) &&
+ (getSender() == host))
+ {
+ break;
+ }
+ }
+ 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.
+ checkMessages(frame_count);
+ processAcks();
+ ms_sleep(1);
+ }
+}
+
+
+void LLMessageSystem::dumpPacketToLog()
+{
+ llwarns << "Packet Dump from:" << mPacketRing.getLastSender() << llendl;
+ llwarns << "Packet Size:" << mTrueReceiveSize << llendl;
+ char line_buffer[256]; /* Flawfinder: ignore */
+ S32 i;
+ S32 cur_line_pos = 0;
+
+ S32 cur_line = 0;
+ for (i = 0; i < mTrueReceiveSize; i++)
+ {
+ snprintf(line_buffer + cur_line_pos*3, sizeof(line_buffer),"%02x ", mTrueReceiveBuffer[i]); /* Flawfinder: ignore */
+ cur_line_pos++;
+ if (cur_line_pos >= 16)
+ {
+ cur_line_pos = 0;
+ llwarns << "PD:" << cur_line << "PD:" << line_buffer << llendl;
+ cur_line++;
+ }
+ }
+ if (cur_line_pos)
+ {
+ llwarns << "PD:" << cur_line << "PD:" << line_buffer << llendl;
+ }
+}
+
+//static
+U64 LLMessageSystem::getMessageTimeUsecs(const BOOL update)
+{
+ if (gMessageSystem)
+ {
+ if (update)
+ {
+ gMessageSystem->mCurrentMessageTimeSeconds = totalTime()*SEC_PER_USEC;
+ }
+ return (U64)(gMessageSystem->mCurrentMessageTimeSeconds * USEC_PER_SEC);
+ }
+ else
+ {
+ return totalTime();
+ }
+}
+
+//static
+F64 LLMessageSystem::getMessageTimeSeconds(const BOOL update)
+{
+ if (gMessageSystem)
+ {
+ if (update)
+ {
+ gMessageSystem->mCurrentMessageTimeSeconds = totalTime()*SEC_PER_USEC;
+ }
+ return gMessageSystem->mCurrentMessageTimeSeconds;
+ }
+ else
+ {
+ return totalTime()*SEC_PER_USEC;
+ }
+}
+
+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;
+}
+