summaryrefslogtreecommitdiff
path: root/indra/llmessage/message.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage/message.h')
-rw-r--r--indra/llmessage/message.h2342
1 files changed, 1171 insertions, 1171 deletions
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index 65c1e07a68..8f15bc266d 100644
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -1,1171 +1,1171 @@
-/**
- * @file message.h
- * @brief LLMessageSystem class header file
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_MESSAGE_H
-#define LL_MESSAGE_H
-
-#include <cstring>
-#include <set>
-
-#if LL_LINUX
-#include <endian.h>
-#include <netinet/in.h>
-#endif
-
-#if LL_WINDOWS
-#include "winsock2.h" // htons etc.
-#endif
-
-#include "llerror.h"
-#include "net.h"
-#include "llstringtable.h"
-#include "llcircuit.h"
-#include "lltimer.h"
-#include "llpacketring.h"
-#include "llhost.h"
-#include "llhttpnode.h"
-//#include "llpacketack.h"
-#include "llsingleton.h"
-#include "message_prehash.h"
-#include "llstl.h"
-#include "llmsgvariabletype.h"
-#include "llmessagesenderinterface.h"
-
-#include "llstoredmessage.h"
-#include "boost/function.hpp"
-#include "llpounceable.h"
-#include "llcoros.h"
-#include LLCOROS_MUTEX_HEADER
-
-const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
-const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
-
-const S32 MESSAGE_MAX_PER_FRAME = 400;
-
-class LLMessageStringTable : public LLSingleton<LLMessageStringTable>
-{
- LLSINGLETON(LLMessageStringTable);
- ~LLMessageStringTable();
-
-public:
- char *getString(const char *str);
-
- U32 mUsed;
- bool mEmpty[MESSAGE_NUMBER_OF_HASH_BUCKETS];
- char mString[MESSAGE_NUMBER_OF_HASH_BUCKETS][MESSAGE_MAX_STRINGS_LENGTH]; /* Flawfinder: ignore */
-};
-
-
-// Individual Messages are described with the following format
-// Note that to ease parsing, keywords are used
-//
-// // Comment (Comment like a C++ single line comment)
-// Comments can only be placed between Messages
-// {
-// MessageName (same naming restrictions as C variable)
-// Frequency ("High", "Medium", or "Low" - determines whether message ID is 8, 16, or 32-bits --
-// there can 254 messages in the first 2 groups, 32K in the last group)
-// (A message can be made up only of the Name if it is only a signal)
-// Trust ("Trusted", "NotTrusted" - determines if a message will be accepted
-// on a circuit. "Trusted" messages are not accepted from NotTrusted circuits
-// while NotTrusted messages are accepted on any circuit. An example of a
-// NotTrusted circuit is any circuit from the viewer.)
-// Encoding ("Zerocoded", "Unencoded" - zerocoded messages attempt to compress sequences of
-// zeros, but if there is no space win, it discards the compression and goes unencoded)
-// {
-// Block Name (same naming restrictions as C variable)
-// Block Type ("Single", "Multiple", or "Variable" - determines if the block is coded once,
-// a known number of times, or has a 8 bit argument encoded to tell the decoder
-// how many times the group is repeated)
-// Block Repeat Number (Optional - used only with the "Multiple" type - tells how many times the field is repeated
-// {
-// Variable 1 Name (same naming restrictions as C variable)
-// Variable Type ("Fixed" or "Variable" - determines if the variable is of fixed size or needs to
-// encode an argument describing the size in bytes)
-// Variable Size (In bytes, either of the "Fixed" variable itself or of the size argument)
-//
-// repeat variables
-//
-// }
-//
-// Repeat for number of variables in block
-// }
-//
-// Repeat for number of blocks in message
-// }
-// Repeat for number of messages in file
-//
-
-// Constants
-const S32 MAX_MESSAGE_INTERNAL_NAME_SIZE = 255;
-const S32 MAX_BUFFER_SIZE = NET_BUFFER_SIZE;
-const S32 MAX_BLOCKS = 255;
-
-const U8 LL_ZERO_CODE_FLAG = 0x80;
-const U8 LL_RELIABLE_FLAG = 0x40;
-const U8 LL_RESENT_FLAG = 0x20;
-const U8 LL_ACK_FLAG = 0x10;
-
-// 1 byte flags, 4 bytes sequence, 1 byte offset + 1 byte message name (high)
-const S32 LL_MINIMUM_VALID_PACKET_SIZE = LL_PACKET_ID_SIZE + 1;
-enum EPacketHeaderLayout
-{
- PHL_FLAGS = 0,
- PHL_PACKET_ID = 1,
- PHL_OFFSET = 5,
- PHL_NAME = 6
-};
-
-
-const S32 LL_DEFAULT_RELIABLE_RETRIES = 3;
-const F32Seconds LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS(1.f);
-const F32Seconds LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS(1.f);
-const F32Seconds LL_PING_BASED_TIMEOUT_DUMMY(0.0f);
-
-const F32 LL_SEMIRELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping
-const F32 LL_RELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping
-const F32 LL_LOST_TIMEOUT_FACTOR = 16.f; // averaged ping for marking packets "Lost"
-const F32Seconds LL_MAX_LOST_TIMEOUT(5.f); // Maximum amount of time before considering something "lost"
-
-const S32 MAX_MESSAGE_COUNT_NUM = 1024;
-
-// Forward declarations
-class LLVector3;
-class LLVector4;
-class LLVector3d;
-class LLQuaternion;
-class LLSD;
-class LLUUID;
-class LLMessageSystem;
-class LLPumpIO;
-
-// message system exceptional condition handlers.
-enum EMessageException
-{
- MX_UNREGISTERED_MESSAGE, // message number not part of template
- MX_PACKET_TOO_SHORT, // invalid packet, shorter than minimum packet size
- MX_RAN_OFF_END_OF_PACKET, // ran off the end of the packet during decode
- MX_WROTE_PAST_BUFFER_SIZE // wrote past buffer size in zero code expand
-};
-typedef void (*msg_exception_callback)(LLMessageSystem*,void*,EMessageException);
-
-
-// message data pieces are used to collect the data called for by the message template
-class LLMsgData;
-class LLMsgBlkData;
-class LLMessageTemplate;
-
-class LLMessagePollInfo;
-class LLMessageBuilder;
-class LLTemplateMessageBuilder;
-class LLSDMessageBuilder;
-class LLMessageReader;
-class LLTemplateMessageReader;
-class LLSDMessageReader;
-
-
-
-class LLUseCircuitCodeResponder
-{
- LOG_CLASS(LLMessageSystem);
-
-public:
- virtual ~LLUseCircuitCodeResponder();
- virtual void complete(const LLHost& host, const LLUUID& agent) const = 0;
-};
-
-/**
- * SL-12204: We've observed crashes when consumer code sets
- * LLMessageSystem::mMessageReader, assuming that all subsequent processing of
- * the current message will use the same mMessageReader value -- only to have
- * a different coroutine sneak in and replace mMessageReader before
- * completion. This is a limitation of sharing a stateful global resource for
- * message parsing; instead code receiving a new message should instantiate a
- * (trivially constructed) local message parser and use that.
- *
- * Until then, when one coroutine sets a particular LLMessageReader subclass
- * as the current message reader, ensure that no other coroutine can replace
- * it until the first coroutine has finished with its message.
- *
- * This is achieved with two helper classes. LLMessageSystem::mMessageReader
- * is now an LLMessageReaderPointer instance, which can efficiently compare or
- * dereference its contained LLMessageReader* but which cannot be directly
- * assigned. To change the value of LLMessageReaderPointer, you must
- * instantiate LockMessageReader with the LLMessageReader* you wish to make
- * current. mMessageReader will have that value for the lifetime of the
- * LockMessageReader instance, then revert to nullptr. Moreover, as its name
- * implies, LockMessageReader locks the mutex in LLMessageReaderPointer so
- * that any other coroutine instantiating LockMessageReader will block until
- * the first coroutine has destroyed its instance.
- */
-class LLMessageReaderPointer
-{
-public:
- LLMessageReaderPointer(): mPtr(nullptr) {}
- // It is essential that comparison and dereferencing must be fast, which
- // is why we don't check for nullptr when dereferencing.
- LLMessageReader* operator->() const { return mPtr; }
- bool operator==(const LLMessageReader* other) const { return mPtr == other; }
- bool operator!=(const LLMessageReader* other) const { return ! (*this == other); }
-private:
- // Only LockMessageReader can set mPtr.
- friend class LockMessageReader;
- LLMessageReader* mPtr;
- LLCoros::Mutex mMutex;
-};
-
-/**
- * To set mMessageReader to nullptr:
- *
- * @code
- * // use an anonymous instance that is destroyed immediately
- * LockMessageReader(gMessageSystem->mMessageReader, nullptr);
- * @endcode
- *
- * Why do we still require going through LockMessageReader at all? Because it
- * would be Bad if any coroutine set mMessageReader to nullptr while another
- * coroutine was still parsing a message.
- */
-class LockMessageReader
-{
-public:
- LockMessageReader(LLMessageReaderPointer& var, LLMessageReader* instance):
- mVar(var.mPtr),
- mLock(var.mMutex)
- {
- mVar = instance;
- }
- // Some compilers reportedly fail to suppress generating implicit copy
- // operations even though we have a move-only LockType data member.
- LockMessageReader(const LockMessageReader&) = delete;
- LockMessageReader& operator=(const LockMessageReader&) = delete;
- ~LockMessageReader()
- {
- mVar = nullptr;
- }
-private:
- // capture a reference to LLMessageReaderPointer::mPtr
- decltype(LLMessageReaderPointer::mPtr)& mVar;
- // while holding a lock on LLMessageReaderPointer::mMutex
- LLCoros::LockType mLock;
-};
-
-/**
- * LockMessageReader is great as long as you only need mMessageReader locked
- * during a single LLMessageSystem function call. However, empirically the
- * sequence from checkAllMessages() through processAcks() need mMessageReader
- * locked to LLTemplateMessageReader. Enforce that by making them require an
- * instance of LockMessageChecker.
- */
-class LockMessageChecker;
-
-class LLMessageSystem : public LLMessageSenderInterface
-{
- private:
- U8 mSendBuffer[MAX_BUFFER_SIZE];
- S32 mSendSize;
-
- bool mBlockUntrustedInterface;
- LLHost mUntrustedInterface;
-
- public:
- LLPacketRing mPacketRing;
- LLReliablePacketParams mReliablePacketParams;
-
- // Set this flag to true when you want *very* verbose logs.
- bool mVerboseLog;
-
- F32 mMessageFileVersionNumber;
-
- typedef std::map<const char *, LLMessageTemplate*> message_template_name_map_t;
- typedef std::map<U32, LLMessageTemplate*> message_template_number_map_t;
-
-private:
- message_template_name_map_t mMessageTemplates;
- message_template_number_map_t mMessageNumbers;
-
-public:
- S32 mSystemVersionMajor;
- S32 mSystemVersionMinor;
- S32 mSystemVersionPatch;
- S32 mSystemVersionServer;
- U32 mVersionFlags;
-
- bool mbProtected;
-
- U32 mNumberHighFreqMessages;
- U32 mNumberMediumFreqMessages;
- U32 mNumberLowFreqMessages;
- S32 mPort;
- S32 mSocket;
-
- U32 mPacketsIn; // total packets in, including compressed and uncompressed
- U32 mPacketsOut; // total packets out, including compressed and uncompressed
-
- U64 mBytesIn; // total bytes in, including compressed and uncompressed
- U64 mBytesOut; // total bytes out, including compressed and uncompressed
-
- U32 mCompressedPacketsIn; // total compressed packets in
- U32 mCompressedPacketsOut; // total compressed packets out
-
- U32 mReliablePacketsIn; // total reliable packets in
- U32 mReliablePacketsOut; // total reliable packets out
-
- U32 mDroppedPackets; // total dropped packets in
- U32 mResentPackets; // total resent packets out
- U32 mFailedResendPackets; // total resend failure packets out
- U32 mOffCircuitPackets; // total # of off-circuit packets rejected
- U32 mInvalidOnCircuitPackets; // total # of on-circuit but invalid packets rejected
-
- S64 mUncompressedBytesIn; // total uncompressed size of compressed packets in
- S64 mUncompressedBytesOut; // total uncompressed size of compressed packets out
- S64 mCompressedBytesIn; // total compressed size of compressed packets in
- S64 mCompressedBytesOut; // total compressed size of compressed packets out
- S64 mTotalBytesIn; // total size of all uncompressed packets in
- S64 mTotalBytesOut; // total size of all uncompressed packets out
-
- bool mSendReliable; // does the outgoing message require a pos ack?
-
- LLCircuit mCircuitInfo;
- F64Seconds mCircuitPrintTime; // used to print circuit debug info every couple minutes
- F32Seconds mCircuitPrintFreq;
-
- std::map<U64, U32> mIPPortToCircuitCode;
- std::map<U32, U64> mCircuitCodeToIPPort;
- U32 mOurCircuitCode;
- S32 mSendPacketFailureCount;
- S32 mUnackedListDepth;
- S32 mUnackedListSize;
- S32 mDSMaxListDepth;
-
-public:
- // Read file and build message templates
- LLMessageSystem(const std::string& filename, U32 port, S32 version_major,
- S32 version_minor, S32 version_patch,
- bool failure_is_fatal,
- const F32 circuit_heartbeat_interval, const F32 circuit_timeout);
-
- ~LLMessageSystem();
-
- bool isOK() const { return !mbError; }
- S32 getErrorCode() const { return mErrorCode; }
-
- // Read file and build message templates filename must point to a
- // valid string which specifies the path of a valid linden
- // template.
- void loadTemplateFile(const std::string& filename, bool failure_is_fatal);
-
-
- // methods for building, sending, receiving, and handling messages
- void setHandlerFuncFast(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data = NULL);
- void setHandlerFunc(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data = NULL)
- {
- setHandlerFuncFast(LLMessageStringTable::getInstance()->getString(name), handler_func, user_data);
- }
-
- // Set a callback function for a message system exception.
- void setExceptionFunc(EMessageException exception, msg_exception_callback func, void* data = NULL);
- // Call the specified exception func, and return true if a
- // function was found and called. Otherwise return false.
- bool callExceptionFunc(EMessageException exception);
-
- // Set a function that will be called once per packet processed with the
- // hashed message name and the time spent in the processing handler function
- // measured in seconds. JC
- typedef void (*msg_timing_callback)(const char* hashed_name, F32 time, void* data);
- void setTimingFunc(msg_timing_callback func, void* data = NULL);
- msg_timing_callback getTimingCallback()
- {
- return mTimingCallback;
- }
- void* getTimingCallbackData()
- {
- return mTimingCallbackData;
- }
-
- // This method returns true if the code is in the circuit codes map.
- bool isCircuitCodeKnown(U32 code) const;
-
- // usually called in response to an AddCircuitCode message, but
- // may also be called by the login process.
- bool addCircuitCode(U32 code, const LLUUID& session_id);
-
- bool poll(F32 seconds); // Number of seconds that we want to block waiting for data, returns if data was received
- bool checkMessages(LockMessageChecker&, S64 frame_count = 0 );
- void processAcks(LockMessageChecker&, F32 collect_time = 0.f);
-
- bool isMessageFast(const char *msg);
- bool isMessage(const char *msg)
- {
- return isMessageFast(LLMessageStringTable::getInstance()->getString(msg));
- }
-
- void dumpPacketToLog();
-
- char *getMessageName();
-
- const LLHost& getSender() const;
- U32 getSenderIP() const; // getSender() is preferred
- U32 getSenderPort() const; // getSender() is preferred
-
- const LLHost& getReceivingInterface() const;
-
- // This method returns the uuid associated with the sender. The
- // UUID will be null if it is not yet known or is a server
- // circuit.
- const LLUUID& getSenderID() const;
-
- // This method returns the session id associated with the last
- // sender.
- const LLUUID& getSenderSessionID() const;
-
- // set & get the session id (useful for viewers for now.)
- void setMySessionID(const LLUUID& session_id) { mSessionID = session_id; }
- const LLUUID& getMySessionID() { return mSessionID; }
-
- void newMessageFast(const char *name);
- void newMessage(const char *name);
-
-
-public:
- LLStoredMessagePtr getReceivedMessage() const;
- LLStoredMessagePtr getBuiltMessage() const;
- S32 sendMessage(const LLHost &host, LLStoredMessagePtr message);
-
-private:
- LLSD getReceivedMessageLLSD() const;
- LLSD getBuiltMessageLLSD() const;
-
- // NOTE: babbage: Only use to support legacy misuse of the
- // LLMessageSystem API where values are dangerously written
- // as one type and read as another. LLSD does not support
- // dangerous conversions and so converting the message to an
- // LLSD would result in the reads failing. All code which
- // misuses the message system in this way should be made safe
- // but while the unsafe code is run in old processes, this
- // method should be used to forward unsafe messages.
- LLSD wrapReceivedTemplateData() const;
- LLSD wrapBuiltTemplateData() const;
-
-public:
-
- void copyMessageReceivedToSend();
- void clearMessage();
-
- void nextBlockFast(const char *blockname);
- void nextBlock(const char *blockname);
-
-public:
- void addBinaryDataFast(const char *varname, const void *data, S32 size);
- void addBinaryData(const char *varname, const void *data, S32 size);
-
- void addBOOLFast( const char* varname, bool b); // typed, checks storage space
- void addBOOL( const char* varname, bool b); // typed, checks storage space
- void addS8Fast( const char *varname, S8 s); // typed, checks storage space
- void addS8( const char *varname, S8 s); // typed, checks storage space
- void addU8Fast( const char *varname, U8 u); // typed, checks storage space
- void addU8( const char *varname, U8 u); // typed, checks storage space
- void addS16Fast( const char *varname, S16 i); // typed, checks storage space
- void addS16( const char *varname, S16 i); // typed, checks storage space
- void addU16Fast( const char *varname, U16 i); // typed, checks storage space
- void addU16( const char *varname, U16 i); // typed, checks storage space
- void addF32Fast( const char *varname, F32 f); // typed, checks storage space
- void addF32( const char *varname, F32 f); // typed, checks storage space
- void addS32Fast( const char *varname, S32 s); // typed, checks storage space
- void addS32( const char *varname, S32 s); // typed, checks storage space
- void addU32Fast( const char *varname, U32 u); // typed, checks storage space
- void addU32( const char *varname, U32 u); // typed, checks storage space
- void addU64Fast( const char *varname, U64 lu); // typed, checks storage space
- void addU64( const char *varname, U64 lu); // typed, checks storage space
- void addF64Fast( const char *varname, F64 d); // typed, checks storage space
- void addF64( const char *varname, F64 d); // typed, checks storage space
- void addVector3Fast( const char *varname, const LLVector3& vec); // typed, checks storage space
- void addVector3( const char *varname, const LLVector3& vec); // typed, checks storage space
- void addVector4Fast( const char *varname, const LLVector4& vec); // typed, checks storage space
- void addVector4( const char *varname, const LLVector4& vec); // typed, checks storage space
- void addVector3dFast( const char *varname, const LLVector3d& vec); // typed, checks storage space
- void addVector3d( const char *varname, const LLVector3d& vec); // typed, checks storage space
- void addQuatFast( const char *varname, const LLQuaternion& quat); // typed, checks storage space
- void addQuat( const char *varname, const LLQuaternion& quat); // typed, checks storage space
- void addUUIDFast( const char *varname, const LLUUID& uuid); // typed, checks storage space
- void addUUID( const char *varname, const LLUUID& uuid); // typed, checks storage space
- void addIPAddrFast( const char *varname, const U32 ip); // typed, checks storage space
- void addIPAddr( const char *varname, const U32 ip); // typed, checks storage space
- void addIPPortFast( const char *varname, const U16 port); // typed, checks storage space
- void addIPPort( const char *varname, const U16 port); // typed, checks storage space
- void addStringFast( const char* varname, const char* s); // typed, checks storage space
- void addString( const char* varname, const char* s); // typed, checks storage space
- void addStringFast( const char* varname, const std::string& s); // typed, checks storage space
- void addString( const char* varname, const std::string& s); // typed, checks storage space
-
- S32 getCurrentSendTotal() const;
- TPACKETID getCurrentRecvPacketID() { return mCurrentRecvPacketID; }
-
- // This method checks for current send total and returns true if
- // you need to go to the next block type or need to start a new
- // message. Specify the current blockname to check block counts,
- // otherwise the method only checks against MTU.
- bool isSendFull(const char* blockname = NULL);
- bool isSendFullFast(const char* blockname = NULL);
-
- bool removeLastBlock();
-
- //void buildMessage();
-
- S32 zeroCode(U8 **data, S32 *data_size);
- S32 zeroCodeExpand(U8 **data, S32 *data_size);
- S32 zeroCodeAdjustCurrentSendTotal();
-
- // Uses ping-based retry
- S32 sendReliable(const LLHost &host);
-
- // Uses ping-based retry
- S32 sendReliable(const U32 circuit) { return sendReliable(findHost(circuit)); }
-
- // Use this one if you DON'T want automatic ping-based retry.
- S32 sendReliable( const LLHost &host,
- S32 retries,
- bool ping_based_retries,
- F32Seconds timeout,
- void (*callback)(void **,S32),
- void ** callback_data);
-
- S32 sendSemiReliable( const LLHost &host,
- void (*callback)(void **,S32), void ** callback_data);
-
- // flush sends a message only if data's been pushed on it.
- S32 flushSemiReliable( const LLHost &host,
- void (*callback)(void **,S32), void ** callback_data);
-
- S32 flushReliable( const LLHost &host );
-
- void forwardMessage(const LLHost &host);
- void forwardReliable(const LLHost &host);
- void forwardReliable(const U32 circuit_code);
- S32 forwardReliable(
- const LLHost &host,
- S32 retries,
- bool ping_based_timeout,
- F32Seconds timeout,
- void (*callback)(void **,S32),
- void ** callback_data);
-
- S32 sendMessage(const LLHost &host);
- S32 sendMessage(const U32 circuit);
-private:
- S32 sendMessage(const LLHost &host, const char* name,
- const LLSD& message);
-public:
- // bool decodeData(const U8 *buffer, const LLHost &host);
-
- /**
- gets binary data from the current message.
-
- @param blockname the name of the block in the message (from the message template)
-
- @param varname
-
- @param datap
-
- @param size expected size - set to zero to get any amount of data up to max_size.
- Make sure max_size is set in that case!
-
- @param blocknum
-
- @param max_size the max number of bytes to read
- */
- void getBinaryDataFast(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX);
- void getBinaryData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX);
- void getBOOLFast( const char *block, const char *var, bool &data, S32 blocknum = 0);
- void getBOOL( const char *block, const char *var, bool &data, S32 blocknum = 0);
- void getS8Fast( const char *block, const char *var, S8 &data, S32 blocknum = 0);
- void getS8( const char *block, const char *var, S8 &data, S32 blocknum = 0);
- void getU8Fast( const char *block, const char *var, U8 &data, S32 blocknum = 0);
- void getU8( const char *block, const char *var, U8 &data, S32 blocknum = 0);
- void getS16Fast( const char *block, const char *var, S16 &data, S32 blocknum = 0);
- void getS16( const char *block, const char *var, S16 &data, S32 blocknum = 0);
- void getU16Fast( const char *block, const char *var, U16 &data, S32 blocknum = 0);
- void getU16( const char *block, const char *var, U16 &data, S32 blocknum = 0);
- void getS32Fast( const char *block, const char *var, S32 &data, S32 blocknum = 0);
- void getS32( const char *block, const char *var, S32 &data, S32 blocknum = 0);
- void getF32Fast( const char *block, const char *var, F32 &data, S32 blocknum = 0);
- void getF32( const char *block, const char *var, F32 &data, S32 blocknum = 0);
- void getU32Fast( const char *block, const char *var, U32 &data, S32 blocknum = 0);
- void getU32( const char *block, const char *var, U32 &data, S32 blocknum = 0);
- void getU64Fast( const char *block, const char *var, U64 &data, S32 blocknum = 0);
- void getU64( const char *block, const char *var, U64 &data, S32 blocknum = 0);
- void getF64Fast( const char *block, const char *var, F64 &data, S32 blocknum = 0);
- void getF64( const char *block, const char *var, F64 &data, S32 blocknum = 0);
- void getVector3Fast( const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0);
- void getVector3( const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0);
- void getVector4Fast( const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0);
- void getVector4( const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0);
- void getVector3dFast(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0);
- void getVector3d(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0);
- void getQuatFast( const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0);
- void getQuat( const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0);
- void getUUIDFast( const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0);
- void getUUID( const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0);
- void getIPAddrFast( const char *block, const char *var, U32 &ip, S32 blocknum = 0);
- void getIPAddr( const char *block, const char *var, U32 &ip, S32 blocknum = 0);
- void getIPPortFast( const char *block, const char *var, U16 &port, S32 blocknum = 0);
- void getIPPort( const char *block, const char *var, U16 &port, S32 blocknum = 0);
- void getStringFast( const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0);
- void getString( const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0);
- void getStringFast( const char *block, const char *var, std::string& outstr, S32 blocknum = 0);
- void getString( const char *block, const char *var, std::string& outstr, S32 blocknum = 0);
-
-
- // Utility functions to generate a replay-resistant digest check
- // against the shared secret. The window specifies how much of a
- // time window is allowed - 1 second is good for tight
- // connections, but multi-process windows might want to be upwards
- // of 5 seconds. For generateDigest, you want to pass in a
- // character array of at least MD5HEX_STR_SIZE so that the hex
- // digest and null termination will fit.
- bool generateDigestForNumberAndUUIDs(char* digest, const U32 number, const LLUUID &id1, const LLUUID &id2) const;
- bool generateDigestForWindowAndUUIDs(char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const;
- bool isMatchingDigestForWindowAndUUIDs(const char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const;
-
- bool generateDigestForNumber(char* digest, const U32 number) const;
- bool generateDigestForWindow(char* digest, const S32 window) const;
- bool isMatchingDigestForWindow(const char* digest, const S32 window) const;
-
- void showCircuitInfo();
- void getCircuitInfo(LLSD& info) const;
-
- U32 getOurCircuitCode();
-
- void enableCircuit(const LLHost &host, bool trusted);
- void disableCircuit(const LLHost &host);
-
- // Use this to establish trust on startup and in response to
- // DenyTrustedCircuit.
- void sendCreateTrustedCircuit(const LLHost& host, const LLUUID & id1, const LLUUID & id2);
-
- // Use this to inform a peer that they aren't currently trusted...
- // This now enqueues the request so that we can ensure that we only send
- // one deny per circuit per message loop so that this doesn't become a DoS.
- // The actual sending is done by reallySendDenyTrustedCircuit()
- void sendDenyTrustedCircuit(const LLHost &host);
-
- /** Return false if host is unknown or untrusted */
- // Note:DaveH/Babbage some trusted messages can be received without a circuit
- bool isTrustedSender(const LLHost& host) const;
-
- /** Return true if current message is from trusted source */
- bool isTrustedSender() const;
-
- /** Return false true if name is unknown or untrusted */
- bool isTrustedMessage(const std::string& name) const;
-
- /** Return false true if name is unknown or trusted */
- bool isUntrustedMessage(const std::string& name) const;
-
- // Mark an interface ineligible for trust
- void setUntrustedInterface( const LLHost host ) { mUntrustedInterface = host; }
- LLHost getUntrustedInterface() const { return mUntrustedInterface; }
- void setBlockUntrustedInterface( bool block ) { mBlockUntrustedInterface = block; } // Throw a switch to allow, sending warnings only
- bool getBlockUntrustedInterface() const { return mBlockUntrustedInterface; }
-
- // Change this message to be UDP black listed.
- void banUdpMessage(const std::string& name);
-
-
-private:
- // A list of the circuits that need to be sent DenyTrustedCircuit messages.
- typedef std::set<LLHost> host_set_t;
- host_set_t mDenyTrustedCircuitSet;
-
- // Really sends the DenyTrustedCircuit message to a given host
- // related to sendDenyTrustedCircuit()
- void reallySendDenyTrustedCircuit(const LLHost &host);
-
-public:
- // Use this to establish trust to and from a host. This blocks
- // until trust has been established, and probably should only be
- // used on startup.
- void establishBidirectionalTrust(const LLHost &host, S64 frame_count = 0);
-
- // returns whether the given host is on a trusted circuit
- // Note:DaveH/Babbage some trusted messages can be received without a circuit
- bool getCircuitTrust(const LLHost &host);
-
- void setCircuitAllowTimeout(const LLHost &host, bool allow);
- void setCircuitTimeoutCallback(const LLHost &host, void (*callback_func)(const LLHost &host, void *user_data), void *user_data);
-
- bool checkCircuitBlocked(const U32 circuit);
- bool checkCircuitAlive(const U32 circuit);
- bool checkCircuitAlive(const LLHost &host);
- void setCircuitProtection(bool b_protect);
- U32 findCircuitCode(const LLHost &host);
- LLHost findHost(const U32 circuit_code);
- void sanityCheck();
-
- bool has(const char *blockname) const;
- S32 getNumberOfBlocksFast(const char *blockname) const;
- S32 getNumberOfBlocks(const char *blockname) const;
- S32 getSizeFast(const char *blockname, const char *varname) const;
- S32 getSize(const char *blockname, const char *varname) const;
- S32 getSizeFast(const char *blockname, S32 blocknum,
- const char *varname) const; // size in bytes of data
- S32 getSize(const char *blockname, S32 blocknum, const char *varname) const;
-
- void resetReceiveCounts(); // resets receive counts for all message types to 0
- void dumpReceiveCounts(); // dumps receive count for each message type to LL_INFOS()
- void dumpCircuitInfo(); // Circuit information to LL_INFOS()
-
- bool isClear() const; // returns mbSClear;
- S32 flush(const LLHost &host);
-
- U32 getListenPort( void ) const;
-
- void startLogging(); // start verbose logging
- void stopLogging(); // flush and close file
- void summarizeLogs(std::ostream& str); // log statistics
-
- S32 getReceiveSize() const;
- S32 getReceiveCompressedSize() const { return mIncomingCompressedSize; }
- S32 getReceiveBytes() const;
-
- S32 getUnackedListSize() const { return mUnackedListSize; }
-
- //const char* getCurrentSMessageName() const { return mCurrentSMessageName; }
- //const char* getCurrentSBlockName() const { return mCurrentSBlockName; }
-
- // friends
- friend std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg);
-
- void setMaxMessageTime(const F32 seconds); // Max time to process messages before warning and dumping (neg to disable)
- void setMaxMessageCounts(const S32 num); // Max number of messages before dumping (neg to disable)
-
- static U64Microseconds getMessageTimeUsecs(const bool update = false); // Get the current message system time in microseconds
- static F64Seconds getMessageTimeSeconds(const bool update = false); // Get the current message system time in seconds
-
- static void setTimeDecodes(bool b);
- static void setTimeDecodesSpamThreshold(F32 seconds);
-
- // message handlers internal to the message systesm
- //static void processAssignCircuitCode(LLMessageSystem* msg, void**);
- static void processAddCircuitCode(LLMessageSystem* msg, void**);
- static void processUseCircuitCode(LLMessageSystem* msg, void**);
- static void processError(LLMessageSystem* msg, void**);
-
- // dispatch llsd message to http node tree
- static void dispatch(const std::string& msg_name,
- const LLSD& message);
- static void dispatch(const std::string& msg_name,
- const LLSD& message,
- LLHTTPNode::ResponsePtr responsep);
-
- // this is added to support specific legacy messages and is
- // ***not intended for general use*** Si, Gabriel, 2009
- static void dispatchTemplate(const std::string& msg_name,
- const LLSD& message,
- LLHTTPNode::ResponsePtr responsep);
-
- void setMessageBans(const LLSD& trusted, const LLSD& untrusted);
-
- /**
- * @brief send an error message to the host. This is a helper method.
- *
- * @param host Destination host.
- * @param agent_id Destination agent id (may be null)
- * @param code An HTTP status compatible error code.
- * @param token A specific short string based message
- * @param id The transactionid/uniqueid/sessionid whatever.
- * @param system The hierarchical path to the system (255 bytes)
- * @param message Human readable message (1200 bytes)
- * @param data Extra info.
- * @return Returns value returned from sendReliable().
- */
- S32 sendError(
- const LLHost& host,
- const LLUUID& agent_id,
- S32 code,
- const std::string& token,
- const LLUUID& id,
- const std::string& system,
- const std::string& message,
- const LLSD& data);
-
- // Check UDP messages and pump http_pump to receive HTTP messages.
- bool checkAllMessages(LockMessageChecker&, S64 frame_count, LLPumpIO* http_pump);
-
- // Moved to allow access from LLTemplateMessageDispatcher
- void clearReceiveState();
-
- // This will cause all trust queries to return true until the next message
- // is read: use with caution!
- void receivedMessageFromTrustedSender();
-
-private:
- typedef boost::function<void(S32)> UntrustedCallback_t;
- void sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback);
-
-
- bool mLastMessageFromTrustedMessageService;
-
- // The mCircuitCodes is a map from circuit codes to session
- // ids. This allows us to verify sessions on connect.
- typedef std::map<U32, LLUUID> code_session_map_t;
- code_session_map_t mCircuitCodes;
-
- // Viewers need to track a process session in order to make sure
- // that no one gives them a bad circuit code.
- LLUUID mSessionID;
-
- void addTemplate(LLMessageTemplate *templatep);
- bool decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template );
-
- void logMsgFromInvalidCircuit( const LLHost& sender, bool recv_reliable );
- void logTrustedMsgFromUntrustedCircuit( const LLHost& sender );
- void logValidMsg(LLCircuitData *cdp, const LLHost& sender, bool recv_reliable, bool recv_resent, bool recv_acks );
- void logRanOffEndOfPacket( const LLHost& sender );
-
- class LLMessageCountInfo
- {
- public:
- U32 mMessageNum;
- U32 mMessageBytes;
- bool mInvalid;
- };
-
- LLMessagePollInfo *mPollInfop;
-
- U8 mEncodedRecvBuffer[MAX_BUFFER_SIZE];
- U8 mTrueReceiveBuffer[MAX_BUFFER_SIZE];
- S32 mTrueReceiveSize;
-
- // Must be valid during decode
-
- bool mbError;
- S32 mErrorCode;
-
- F64Seconds mResendDumpTime; // The last time we dumped resends
-
- LLMessageCountInfo mMessageCountList[MAX_MESSAGE_COUNT_NUM];
- S32 mNumMessageCounts;
- F32Seconds mReceiveTime;
- F32Seconds mMaxMessageTime; // Max number of seconds for processing messages
- S32 mMaxMessageCounts; // Max number of messages to process before dumping.
- F64Seconds mMessageCountTime;
-
- F64Seconds mCurrentMessageTime; // The current "message system time" (updated the first call to checkMessages after a resetReceiveCount
-
- // message system exceptions
- typedef std::pair<msg_exception_callback, void*> exception_t;
- typedef std::map<EMessageException, exception_t> callbacks_t;
- callbacks_t mExceptionCallbacks;
-
- // stuff for logging
- LLTimer mMessageSystemTimer;
-
- static F32 mTimeDecodesSpamThreshold; // If mTimeDecodes is on, all this many seconds for each msg decode before spamming
- static bool mTimeDecodes; // Measure time for all message decodes if true;
-
- msg_timing_callback mTimingCallback;
- void* mTimingCallbackData;
-
- void init(); // ctor shared initialisation.
-
- LLHost mLastSender;
- LLHost mLastReceivingIF;
- S32 mIncomingCompressedSize; // original size of compressed msg (0 if uncomp.)
- TPACKETID mCurrentRecvPacketID; // packet ID of current receive packet (for reporting)
-
- LLMessageBuilder* mMessageBuilder;
- LLTemplateMessageBuilder* mTemplateMessageBuilder;
- LLSDMessageBuilder* mLLSDMessageBuilder;
- LLMessageReaderPointer mMessageReader;
- LLTemplateMessageReader* mTemplateMessageReader;
- LLSDMessageReader* mLLSDMessageReader;
-
- friend class LLMessageHandlerBridge;
- friend class LockMessageChecker;
-
- bool callHandler(const char *name, bool trustedSource,
- LLMessageSystem* msg);
-
-
- /** Find, create or revive circuit for host as needed */
- LLCircuitData* findCircuit(const LLHost& host, bool resetPacketId);
-};
-
-
-// external hook into messaging system
-extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
-
-// Implementation of LockMessageChecker depends on definition of
-// LLMessageSystem, hence must follow it.
-class LockMessageChecker: public LockMessageReader
-{
-public:
- LockMessageChecker(LLMessageSystem* msgsystem);
-
- // For convenience, provide forwarding wrappers so you can call (e.g.)
- // checkAllMessages() on your LockMessageChecker instance instead of
- // passing the instance to LLMessageSystem::checkAllMessages(). Use
- // perfect forwarding to avoid having to maintain these wrappers in sync
- // with the target methods.
- template <typename... ARGS>
- bool checkAllMessages(ARGS&&... args)
- {
- return mMessageSystem->checkAllMessages(*this, std::forward<ARGS>(args)...);
- }
-
- template <typename... ARGS>
- bool checkMessages(ARGS&&... args)
- {
- return mMessageSystem->checkMessages(*this, std::forward<ARGS>(args)...);
- }
-
- template <typename... ARGS>
- void processAcks(ARGS&&... args)
- {
- return mMessageSystem->processAcks(*this, std::forward<ARGS>(args)...);
- }
-
-private:
- LLMessageSystem* mMessageSystem;
-};
-
-// Must specific overall system version, which is used to determine
-// if a patch is available in the message template checksum verification.
-// Return true if able to initialize system.
-bool start_messaging_system(
- const std::string& template_name,
- U32 port,
- S32 version_major,
- S32 version_minor,
- S32 version_patch,
- bool b_dump_prehash_file,
- const std::string& secret,
- const LLUseCircuitCodeResponder* responder,
- bool failure_is_fatal,
- const F32 circuit_heartbeat_interval,
- const F32 circuit_timeout);
-
-void end_messaging_system(bool print_summary = true);
-
-void null_message_callback(LLMessageSystem *msg, void **data);
-
-//
-// Inlines
-//
-
-#if !defined( LL_BIG_ENDIAN ) && !defined( LL_LITTLE_ENDIAN )
-#error Unknown endianness for htolememcpy. Did you miss a common include?
-#endif
-
-static inline void *htolememcpy(void *vs, const void *vct, EMsgVariableType type, size_t n)
-{
- char *s = (char *)vs;
- const char *ct = (const char *)vct;
-#ifdef LL_BIG_ENDIAN
- S32 i, length;
-#endif
- switch(type)
- {
- case MVT_FIXED:
- case MVT_VARIABLE:
- case MVT_U8:
- case MVT_S8:
- case MVT_BOOL:
- case MVT_LLUUID:
- case MVT_IP_ADDR: // these two are swizzled in the getters and setters
- case MVT_IP_PORT: // these two are swizzled in the getters and setters
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-
- case MVT_U16:
- case MVT_S16:
- if (n != 2)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- *(s + 1) = *(ct);
- *(s) = *(ct + 1);
- return(vs);
-#else
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-#endif
-
- case MVT_U32:
- case MVT_S32:
- case MVT_F32:
- if (n != 4)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- *(s + 3) = *(ct);
- *(s + 2) = *(ct + 1);
- *(s + 1) = *(ct + 2);
- *(s) = *(ct + 3);
- return(vs);
-#else
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-#endif
-
- case MVT_U64:
- case MVT_S64:
- case MVT_F64:
- if (n != 8)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- *(s + 7) = *(ct);
- *(s + 6) = *(ct + 1);
- *(s + 5) = *(ct + 2);
- *(s + 4) = *(ct + 3);
- *(s + 3) = *(ct + 4);
- *(s + 2) = *(ct + 5);
- *(s + 1) = *(ct + 6);
- *(s) = *(ct + 7);
- return(vs);
-#else
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-#endif
-
- case MVT_LLVector3:
- case MVT_LLQuaternion: // We only send x, y, z and infer w (we set x, y, z to ensure that w >= 0)
- if (n != 12)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- htolememcpy(s + 8, ct + 8, MVT_F32, 4);
- htolememcpy(s + 4, ct + 4, MVT_F32, 4);
- return(htolememcpy(s, ct, MVT_F32, 4));
-#else
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-#endif
-
- case MVT_LLVector3d:
- if (n != 24)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- htolememcpy(s + 16, ct + 16, MVT_F64, 8);
- htolememcpy(s + 8, ct + 8, MVT_F64, 8);
- return(htolememcpy(s, ct, MVT_F64, 8));
-#else
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-#endif
-
- case MVT_LLVector4:
- if (n != 16)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- htolememcpy(s + 12, ct + 12, MVT_F32, 4);
- htolememcpy(s + 8, ct + 8, MVT_F32, 4);
- htolememcpy(s + 4, ct + 4, MVT_F32, 4);
- return(htolememcpy(s, ct, MVT_F32, 4));
-#else
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-#endif
-
- case MVT_U16Vec3:
- if (n != 6)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- htolememcpy(s + 4, ct + 4, MVT_U16, 2);
- htolememcpy(s + 2, ct + 2, MVT_U16, 2);
- return(htolememcpy(s, ct, MVT_U16, 2));
-#else
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-#endif
-
- case MVT_U16Quat:
- if (n != 8)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- htolememcpy(s + 6, ct + 6, MVT_U16, 2);
- htolememcpy(s + 4, ct + 4, MVT_U16, 2);
- htolememcpy(s + 2, ct + 2, MVT_U16, 2);
- return(htolememcpy(s, ct, MVT_U16, 2));
-#else
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
-#endif
-
- case MVT_S16Array:
- if (n % 2)
- {
- LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
- }
-#ifdef LL_BIG_ENDIAN
- length = n % 2;
- for (i = 1; i < length; i++)
- {
- htolememcpy(s + i*2, ct + i*2, MVT_S16, 2);
- }
- return(htolememcpy(s, ct, MVT_S16, 2));
-#else
- return(memcpy(s,ct,n));
-#endif
-
- default:
- return(memcpy(s,ct,n)); /* Flawfinder: ignore */
- }
-}
-
-inline void *ntohmemcpy(void *s, const void *ct, EMsgVariableType type, size_t n)
-{
- return(htolememcpy(s,ct,type, n));
-}
-
-inline const LLHost& LLMessageSystem::getReceivingInterface() const {return mLastReceivingIF;}
-
-inline U32 LLMessageSystem::getSenderIP() const
-{
- return mLastSender.getAddress();
-}
-
-inline U32 LLMessageSystem::getSenderPort() const
-{
- return mLastSender.getPort();
-}
-
-
-//-----------------------------------------------------------------------------
-// Transmission aliases
-//-----------------------------------------------------------------------------
-
-inline S32 LLMessageSystem::sendMessage(const U32 circuit)
-{
- return sendMessage(findHost(circuit));
-}
-
-#endif
+/**
+ * @file message.h
+ * @brief LLMessageSystem class header file
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_MESSAGE_H
+#define LL_MESSAGE_H
+
+#include <cstring>
+#include <set>
+
+#if LL_LINUX
+#include <endian.h>
+#include <netinet/in.h>
+#endif
+
+#if LL_WINDOWS
+#include "winsock2.h" // htons etc.
+#endif
+
+#include "llerror.h"
+#include "net.h"
+#include "llstringtable.h"
+#include "llcircuit.h"
+#include "lltimer.h"
+#include "llpacketring.h"
+#include "llhost.h"
+#include "llhttpnode.h"
+//#include "llpacketack.h"
+#include "llsingleton.h"
+#include "message_prehash.h"
+#include "llstl.h"
+#include "llmsgvariabletype.h"
+#include "llmessagesenderinterface.h"
+
+#include "llstoredmessage.h"
+#include "boost/function.hpp"
+#include "llpounceable.h"
+#include "llcoros.h"
+#include LLCOROS_MUTEX_HEADER
+
+const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
+const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
+
+const S32 MESSAGE_MAX_PER_FRAME = 400;
+
+class LLMessageStringTable : public LLSingleton<LLMessageStringTable>
+{
+ LLSINGLETON(LLMessageStringTable);
+ ~LLMessageStringTable();
+
+public:
+ char *getString(const char *str);
+
+ U32 mUsed;
+ bool mEmpty[MESSAGE_NUMBER_OF_HASH_BUCKETS];
+ char mString[MESSAGE_NUMBER_OF_HASH_BUCKETS][MESSAGE_MAX_STRINGS_LENGTH]; /* Flawfinder: ignore */
+};
+
+
+// Individual Messages are described with the following format
+// Note that to ease parsing, keywords are used
+//
+// // Comment (Comment like a C++ single line comment)
+// Comments can only be placed between Messages
+// {
+// MessageName (same naming restrictions as C variable)
+// Frequency ("High", "Medium", or "Low" - determines whether message ID is 8, 16, or 32-bits --
+// there can 254 messages in the first 2 groups, 32K in the last group)
+// (A message can be made up only of the Name if it is only a signal)
+// Trust ("Trusted", "NotTrusted" - determines if a message will be accepted
+// on a circuit. "Trusted" messages are not accepted from NotTrusted circuits
+// while NotTrusted messages are accepted on any circuit. An example of a
+// NotTrusted circuit is any circuit from the viewer.)
+// Encoding ("Zerocoded", "Unencoded" - zerocoded messages attempt to compress sequences of
+// zeros, but if there is no space win, it discards the compression and goes unencoded)
+// {
+// Block Name (same naming restrictions as C variable)
+// Block Type ("Single", "Multiple", or "Variable" - determines if the block is coded once,
+// a known number of times, or has a 8 bit argument encoded to tell the decoder
+// how many times the group is repeated)
+// Block Repeat Number (Optional - used only with the "Multiple" type - tells how many times the field is repeated
+// {
+// Variable 1 Name (same naming restrictions as C variable)
+// Variable Type ("Fixed" or "Variable" - determines if the variable is of fixed size or needs to
+// encode an argument describing the size in bytes)
+// Variable Size (In bytes, either of the "Fixed" variable itself or of the size argument)
+//
+// repeat variables
+//
+// }
+//
+// Repeat for number of variables in block
+// }
+//
+// Repeat for number of blocks in message
+// }
+// Repeat for number of messages in file
+//
+
+// Constants
+const S32 MAX_MESSAGE_INTERNAL_NAME_SIZE = 255;
+const S32 MAX_BUFFER_SIZE = NET_BUFFER_SIZE;
+const S32 MAX_BLOCKS = 255;
+
+const U8 LL_ZERO_CODE_FLAG = 0x80;
+const U8 LL_RELIABLE_FLAG = 0x40;
+const U8 LL_RESENT_FLAG = 0x20;
+const U8 LL_ACK_FLAG = 0x10;
+
+// 1 byte flags, 4 bytes sequence, 1 byte offset + 1 byte message name (high)
+const S32 LL_MINIMUM_VALID_PACKET_SIZE = LL_PACKET_ID_SIZE + 1;
+enum EPacketHeaderLayout
+{
+ PHL_FLAGS = 0,
+ PHL_PACKET_ID = 1,
+ PHL_OFFSET = 5,
+ PHL_NAME = 6
+};
+
+
+const S32 LL_DEFAULT_RELIABLE_RETRIES = 3;
+const F32Seconds LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS(1.f);
+const F32Seconds LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS(1.f);
+const F32Seconds LL_PING_BASED_TIMEOUT_DUMMY(0.0f);
+
+const F32 LL_SEMIRELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping
+const F32 LL_RELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping
+const F32 LL_LOST_TIMEOUT_FACTOR = 16.f; // averaged ping for marking packets "Lost"
+const F32Seconds LL_MAX_LOST_TIMEOUT(5.f); // Maximum amount of time before considering something "lost"
+
+const S32 MAX_MESSAGE_COUNT_NUM = 1024;
+
+// Forward declarations
+class LLVector3;
+class LLVector4;
+class LLVector3d;
+class LLQuaternion;
+class LLSD;
+class LLUUID;
+class LLMessageSystem;
+class LLPumpIO;
+
+// message system exceptional condition handlers.
+enum EMessageException
+{
+ MX_UNREGISTERED_MESSAGE, // message number not part of template
+ MX_PACKET_TOO_SHORT, // invalid packet, shorter than minimum packet size
+ MX_RAN_OFF_END_OF_PACKET, // ran off the end of the packet during decode
+ MX_WROTE_PAST_BUFFER_SIZE // wrote past buffer size in zero code expand
+};
+typedef void (*msg_exception_callback)(LLMessageSystem*,void*,EMessageException);
+
+
+// message data pieces are used to collect the data called for by the message template
+class LLMsgData;
+class LLMsgBlkData;
+class LLMessageTemplate;
+
+class LLMessagePollInfo;
+class LLMessageBuilder;
+class LLTemplateMessageBuilder;
+class LLSDMessageBuilder;
+class LLMessageReader;
+class LLTemplateMessageReader;
+class LLSDMessageReader;
+
+
+
+class LLUseCircuitCodeResponder
+{
+ LOG_CLASS(LLMessageSystem);
+
+public:
+ virtual ~LLUseCircuitCodeResponder();
+ virtual void complete(const LLHost& host, const LLUUID& agent) const = 0;
+};
+
+/**
+ * SL-12204: We've observed crashes when consumer code sets
+ * LLMessageSystem::mMessageReader, assuming that all subsequent processing of
+ * the current message will use the same mMessageReader value -- only to have
+ * a different coroutine sneak in and replace mMessageReader before
+ * completion. This is a limitation of sharing a stateful global resource for
+ * message parsing; instead code receiving a new message should instantiate a
+ * (trivially constructed) local message parser and use that.
+ *
+ * Until then, when one coroutine sets a particular LLMessageReader subclass
+ * as the current message reader, ensure that no other coroutine can replace
+ * it until the first coroutine has finished with its message.
+ *
+ * This is achieved with two helper classes. LLMessageSystem::mMessageReader
+ * is now an LLMessageReaderPointer instance, which can efficiently compare or
+ * dereference its contained LLMessageReader* but which cannot be directly
+ * assigned. To change the value of LLMessageReaderPointer, you must
+ * instantiate LockMessageReader with the LLMessageReader* you wish to make
+ * current. mMessageReader will have that value for the lifetime of the
+ * LockMessageReader instance, then revert to nullptr. Moreover, as its name
+ * implies, LockMessageReader locks the mutex in LLMessageReaderPointer so
+ * that any other coroutine instantiating LockMessageReader will block until
+ * the first coroutine has destroyed its instance.
+ */
+class LLMessageReaderPointer
+{
+public:
+ LLMessageReaderPointer(): mPtr(nullptr) {}
+ // It is essential that comparison and dereferencing must be fast, which
+ // is why we don't check for nullptr when dereferencing.
+ LLMessageReader* operator->() const { return mPtr; }
+ bool operator==(const LLMessageReader* other) const { return mPtr == other; }
+ bool operator!=(const LLMessageReader* other) const { return ! (*this == other); }
+private:
+ // Only LockMessageReader can set mPtr.
+ friend class LockMessageReader;
+ LLMessageReader* mPtr;
+ LLCoros::Mutex mMutex;
+};
+
+/**
+ * To set mMessageReader to nullptr:
+ *
+ * @code
+ * // use an anonymous instance that is destroyed immediately
+ * LockMessageReader(gMessageSystem->mMessageReader, nullptr);
+ * @endcode
+ *
+ * Why do we still require going through LockMessageReader at all? Because it
+ * would be Bad if any coroutine set mMessageReader to nullptr while another
+ * coroutine was still parsing a message.
+ */
+class LockMessageReader
+{
+public:
+ LockMessageReader(LLMessageReaderPointer& var, LLMessageReader* instance):
+ mVar(var.mPtr),
+ mLock(var.mMutex)
+ {
+ mVar = instance;
+ }
+ // Some compilers reportedly fail to suppress generating implicit copy
+ // operations even though we have a move-only LockType data member.
+ LockMessageReader(const LockMessageReader&) = delete;
+ LockMessageReader& operator=(const LockMessageReader&) = delete;
+ ~LockMessageReader()
+ {
+ mVar = nullptr;
+ }
+private:
+ // capture a reference to LLMessageReaderPointer::mPtr
+ decltype(LLMessageReaderPointer::mPtr)& mVar;
+ // while holding a lock on LLMessageReaderPointer::mMutex
+ LLCoros::LockType mLock;
+};
+
+/**
+ * LockMessageReader is great as long as you only need mMessageReader locked
+ * during a single LLMessageSystem function call. However, empirically the
+ * sequence from checkAllMessages() through processAcks() need mMessageReader
+ * locked to LLTemplateMessageReader. Enforce that by making them require an
+ * instance of LockMessageChecker.
+ */
+class LockMessageChecker;
+
+class LLMessageSystem : public LLMessageSenderInterface
+{
+ private:
+ U8 mSendBuffer[MAX_BUFFER_SIZE];
+ S32 mSendSize;
+
+ bool mBlockUntrustedInterface;
+ LLHost mUntrustedInterface;
+
+ public:
+ LLPacketRing mPacketRing;
+ LLReliablePacketParams mReliablePacketParams;
+
+ // Set this flag to true when you want *very* verbose logs.
+ bool mVerboseLog;
+
+ F32 mMessageFileVersionNumber;
+
+ typedef std::map<const char *, LLMessageTemplate*> message_template_name_map_t;
+ typedef std::map<U32, LLMessageTemplate*> message_template_number_map_t;
+
+private:
+ message_template_name_map_t mMessageTemplates;
+ message_template_number_map_t mMessageNumbers;
+
+public:
+ S32 mSystemVersionMajor;
+ S32 mSystemVersionMinor;
+ S32 mSystemVersionPatch;
+ S32 mSystemVersionServer;
+ U32 mVersionFlags;
+
+ bool mbProtected;
+
+ U32 mNumberHighFreqMessages;
+ U32 mNumberMediumFreqMessages;
+ U32 mNumberLowFreqMessages;
+ S32 mPort;
+ S32 mSocket;
+
+ U32 mPacketsIn; // total packets in, including compressed and uncompressed
+ U32 mPacketsOut; // total packets out, including compressed and uncompressed
+
+ U64 mBytesIn; // total bytes in, including compressed and uncompressed
+ U64 mBytesOut; // total bytes out, including compressed and uncompressed
+
+ U32 mCompressedPacketsIn; // total compressed packets in
+ U32 mCompressedPacketsOut; // total compressed packets out
+
+ U32 mReliablePacketsIn; // total reliable packets in
+ U32 mReliablePacketsOut; // total reliable packets out
+
+ U32 mDroppedPackets; // total dropped packets in
+ U32 mResentPackets; // total resent packets out
+ U32 mFailedResendPackets; // total resend failure packets out
+ U32 mOffCircuitPackets; // total # of off-circuit packets rejected
+ U32 mInvalidOnCircuitPackets; // total # of on-circuit but invalid packets rejected
+
+ S64 mUncompressedBytesIn; // total uncompressed size of compressed packets in
+ S64 mUncompressedBytesOut; // total uncompressed size of compressed packets out
+ S64 mCompressedBytesIn; // total compressed size of compressed packets in
+ S64 mCompressedBytesOut; // total compressed size of compressed packets out
+ S64 mTotalBytesIn; // total size of all uncompressed packets in
+ S64 mTotalBytesOut; // total size of all uncompressed packets out
+
+ bool mSendReliable; // does the outgoing message require a pos ack?
+
+ LLCircuit mCircuitInfo;
+ F64Seconds mCircuitPrintTime; // used to print circuit debug info every couple minutes
+ F32Seconds mCircuitPrintFreq;
+
+ std::map<U64, U32> mIPPortToCircuitCode;
+ std::map<U32, U64> mCircuitCodeToIPPort;
+ U32 mOurCircuitCode;
+ S32 mSendPacketFailureCount;
+ S32 mUnackedListDepth;
+ S32 mUnackedListSize;
+ S32 mDSMaxListDepth;
+
+public:
+ // Read file and build message templates
+ LLMessageSystem(const std::string& filename, U32 port, S32 version_major,
+ S32 version_minor, S32 version_patch,
+ bool failure_is_fatal,
+ const F32 circuit_heartbeat_interval, const F32 circuit_timeout);
+
+ ~LLMessageSystem();
+
+ bool isOK() const { return !mbError; }
+ S32 getErrorCode() const { return mErrorCode; }
+
+ // Read file and build message templates filename must point to a
+ // valid string which specifies the path of a valid linden
+ // template.
+ void loadTemplateFile(const std::string& filename, bool failure_is_fatal);
+
+
+ // methods for building, sending, receiving, and handling messages
+ void setHandlerFuncFast(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data = NULL);
+ void setHandlerFunc(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data = NULL)
+ {
+ setHandlerFuncFast(LLMessageStringTable::getInstance()->getString(name), handler_func, user_data);
+ }
+
+ // Set a callback function for a message system exception.
+ void setExceptionFunc(EMessageException exception, msg_exception_callback func, void* data = NULL);
+ // Call the specified exception func, and return true if a
+ // function was found and called. Otherwise return false.
+ bool callExceptionFunc(EMessageException exception);
+
+ // Set a function that will be called once per packet processed with the
+ // hashed message name and the time spent in the processing handler function
+ // measured in seconds. JC
+ typedef void (*msg_timing_callback)(const char* hashed_name, F32 time, void* data);
+ void setTimingFunc(msg_timing_callback func, void* data = NULL);
+ msg_timing_callback getTimingCallback()
+ {
+ return mTimingCallback;
+ }
+ void* getTimingCallbackData()
+ {
+ return mTimingCallbackData;
+ }
+
+ // This method returns true if the code is in the circuit codes map.
+ bool isCircuitCodeKnown(U32 code) const;
+
+ // usually called in response to an AddCircuitCode message, but
+ // may also be called by the login process.
+ bool addCircuitCode(U32 code, const LLUUID& session_id);
+
+ bool poll(F32 seconds); // Number of seconds that we want to block waiting for data, returns if data was received
+ bool checkMessages(LockMessageChecker&, S64 frame_count = 0 );
+ void processAcks(LockMessageChecker&, F32 collect_time = 0.f);
+
+ bool isMessageFast(const char *msg);
+ bool isMessage(const char *msg)
+ {
+ return isMessageFast(LLMessageStringTable::getInstance()->getString(msg));
+ }
+
+ void dumpPacketToLog();
+
+ char *getMessageName();
+
+ const LLHost& getSender() const;
+ U32 getSenderIP() const; // getSender() is preferred
+ U32 getSenderPort() const; // getSender() is preferred
+
+ const LLHost& getReceivingInterface() const;
+
+ // This method returns the uuid associated with the sender. The
+ // UUID will be null if it is not yet known or is a server
+ // circuit.
+ const LLUUID& getSenderID() const;
+
+ // This method returns the session id associated with the last
+ // sender.
+ const LLUUID& getSenderSessionID() const;
+
+ // set & get the session id (useful for viewers for now.)
+ void setMySessionID(const LLUUID& session_id) { mSessionID = session_id; }
+ const LLUUID& getMySessionID() { return mSessionID; }
+
+ void newMessageFast(const char *name);
+ void newMessage(const char *name);
+
+
+public:
+ LLStoredMessagePtr getReceivedMessage() const;
+ LLStoredMessagePtr getBuiltMessage() const;
+ S32 sendMessage(const LLHost &host, LLStoredMessagePtr message);
+
+private:
+ LLSD getReceivedMessageLLSD() const;
+ LLSD getBuiltMessageLLSD() const;
+
+ // NOTE: babbage: Only use to support legacy misuse of the
+ // LLMessageSystem API where values are dangerously written
+ // as one type and read as another. LLSD does not support
+ // dangerous conversions and so converting the message to an
+ // LLSD would result in the reads failing. All code which
+ // misuses the message system in this way should be made safe
+ // but while the unsafe code is run in old processes, this
+ // method should be used to forward unsafe messages.
+ LLSD wrapReceivedTemplateData() const;
+ LLSD wrapBuiltTemplateData() const;
+
+public:
+
+ void copyMessageReceivedToSend();
+ void clearMessage();
+
+ void nextBlockFast(const char *blockname);
+ void nextBlock(const char *blockname);
+
+public:
+ void addBinaryDataFast(const char *varname, const void *data, S32 size);
+ void addBinaryData(const char *varname, const void *data, S32 size);
+
+ void addBOOLFast( const char* varname, bool b); // typed, checks storage space
+ void addBOOL( const char* varname, bool b); // typed, checks storage space
+ void addS8Fast( const char *varname, S8 s); // typed, checks storage space
+ void addS8( const char *varname, S8 s); // typed, checks storage space
+ void addU8Fast( const char *varname, U8 u); // typed, checks storage space
+ void addU8( const char *varname, U8 u); // typed, checks storage space
+ void addS16Fast( const char *varname, S16 i); // typed, checks storage space
+ void addS16( const char *varname, S16 i); // typed, checks storage space
+ void addU16Fast( const char *varname, U16 i); // typed, checks storage space
+ void addU16( const char *varname, U16 i); // typed, checks storage space
+ void addF32Fast( const char *varname, F32 f); // typed, checks storage space
+ void addF32( const char *varname, F32 f); // typed, checks storage space
+ void addS32Fast( const char *varname, S32 s); // typed, checks storage space
+ void addS32( const char *varname, S32 s); // typed, checks storage space
+ void addU32Fast( const char *varname, U32 u); // typed, checks storage space
+ void addU32( const char *varname, U32 u); // typed, checks storage space
+ void addU64Fast( const char *varname, U64 lu); // typed, checks storage space
+ void addU64( const char *varname, U64 lu); // typed, checks storage space
+ void addF64Fast( const char *varname, F64 d); // typed, checks storage space
+ void addF64( const char *varname, F64 d); // typed, checks storage space
+ void addVector3Fast( const char *varname, const LLVector3& vec); // typed, checks storage space
+ void addVector3( const char *varname, const LLVector3& vec); // typed, checks storage space
+ void addVector4Fast( const char *varname, const LLVector4& vec); // typed, checks storage space
+ void addVector4( const char *varname, const LLVector4& vec); // typed, checks storage space
+ void addVector3dFast( const char *varname, const LLVector3d& vec); // typed, checks storage space
+ void addVector3d( const char *varname, const LLVector3d& vec); // typed, checks storage space
+ void addQuatFast( const char *varname, const LLQuaternion& quat); // typed, checks storage space
+ void addQuat( const char *varname, const LLQuaternion& quat); // typed, checks storage space
+ void addUUIDFast( const char *varname, const LLUUID& uuid); // typed, checks storage space
+ void addUUID( const char *varname, const LLUUID& uuid); // typed, checks storage space
+ void addIPAddrFast( const char *varname, const U32 ip); // typed, checks storage space
+ void addIPAddr( const char *varname, const U32 ip); // typed, checks storage space
+ void addIPPortFast( const char *varname, const U16 port); // typed, checks storage space
+ void addIPPort( const char *varname, const U16 port); // typed, checks storage space
+ void addStringFast( const char* varname, const char* s); // typed, checks storage space
+ void addString( const char* varname, const char* s); // typed, checks storage space
+ void addStringFast( const char* varname, const std::string& s); // typed, checks storage space
+ void addString( const char* varname, const std::string& s); // typed, checks storage space
+
+ S32 getCurrentSendTotal() const;
+ TPACKETID getCurrentRecvPacketID() { return mCurrentRecvPacketID; }
+
+ // This method checks for current send total and returns true if
+ // you need to go to the next block type or need to start a new
+ // message. Specify the current blockname to check block counts,
+ // otherwise the method only checks against MTU.
+ bool isSendFull(const char* blockname = NULL);
+ bool isSendFullFast(const char* blockname = NULL);
+
+ bool removeLastBlock();
+
+ //void buildMessage();
+
+ S32 zeroCode(U8 **data, S32 *data_size);
+ S32 zeroCodeExpand(U8 **data, S32 *data_size);
+ S32 zeroCodeAdjustCurrentSendTotal();
+
+ // Uses ping-based retry
+ S32 sendReliable(const LLHost &host);
+
+ // Uses ping-based retry
+ S32 sendReliable(const U32 circuit) { return sendReliable(findHost(circuit)); }
+
+ // Use this one if you DON'T want automatic ping-based retry.
+ S32 sendReliable( const LLHost &host,
+ S32 retries,
+ bool ping_based_retries,
+ F32Seconds timeout,
+ void (*callback)(void **,S32),
+ void ** callback_data);
+
+ S32 sendSemiReliable( const LLHost &host,
+ void (*callback)(void **,S32), void ** callback_data);
+
+ // flush sends a message only if data's been pushed on it.
+ S32 flushSemiReliable( const LLHost &host,
+ void (*callback)(void **,S32), void ** callback_data);
+
+ S32 flushReliable( const LLHost &host );
+
+ void forwardMessage(const LLHost &host);
+ void forwardReliable(const LLHost &host);
+ void forwardReliable(const U32 circuit_code);
+ S32 forwardReliable(
+ const LLHost &host,
+ S32 retries,
+ bool ping_based_timeout,
+ F32Seconds timeout,
+ void (*callback)(void **,S32),
+ void ** callback_data);
+
+ S32 sendMessage(const LLHost &host);
+ S32 sendMessage(const U32 circuit);
+private:
+ S32 sendMessage(const LLHost &host, const char* name,
+ const LLSD& message);
+public:
+ // bool decodeData(const U8 *buffer, const LLHost &host);
+
+ /**
+ gets binary data from the current message.
+
+ @param blockname the name of the block in the message (from the message template)
+
+ @param varname
+
+ @param datap
+
+ @param size expected size - set to zero to get any amount of data up to max_size.
+ Make sure max_size is set in that case!
+
+ @param blocknum
+
+ @param max_size the max number of bytes to read
+ */
+ void getBinaryDataFast(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX);
+ void getBinaryData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX);
+ void getBOOLFast( const char *block, const char *var, bool &data, S32 blocknum = 0);
+ void getBOOL( const char *block, const char *var, bool &data, S32 blocknum = 0);
+ void getS8Fast( const char *block, const char *var, S8 &data, S32 blocknum = 0);
+ void getS8( const char *block, const char *var, S8 &data, S32 blocknum = 0);
+ void getU8Fast( const char *block, const char *var, U8 &data, S32 blocknum = 0);
+ void getU8( const char *block, const char *var, U8 &data, S32 blocknum = 0);
+ void getS16Fast( const char *block, const char *var, S16 &data, S32 blocknum = 0);
+ void getS16( const char *block, const char *var, S16 &data, S32 blocknum = 0);
+ void getU16Fast( const char *block, const char *var, U16 &data, S32 blocknum = 0);
+ void getU16( const char *block, const char *var, U16 &data, S32 blocknum = 0);
+ void getS32Fast( const char *block, const char *var, S32 &data, S32 blocknum = 0);
+ void getS32( const char *block, const char *var, S32 &data, S32 blocknum = 0);
+ void getF32Fast( const char *block, const char *var, F32 &data, S32 blocknum = 0);
+ void getF32( const char *block, const char *var, F32 &data, S32 blocknum = 0);
+ void getU32Fast( const char *block, const char *var, U32 &data, S32 blocknum = 0);
+ void getU32( const char *block, const char *var, U32 &data, S32 blocknum = 0);
+ void getU64Fast( const char *block, const char *var, U64 &data, S32 blocknum = 0);
+ void getU64( const char *block, const char *var, U64 &data, S32 blocknum = 0);
+ void getF64Fast( const char *block, const char *var, F64 &data, S32 blocknum = 0);
+ void getF64( const char *block, const char *var, F64 &data, S32 blocknum = 0);
+ void getVector3Fast( const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0);
+ void getVector3( const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0);
+ void getVector4Fast( const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0);
+ void getVector4( const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0);
+ void getVector3dFast(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0);
+ void getVector3d(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0);
+ void getQuatFast( const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0);
+ void getQuat( const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0);
+ void getUUIDFast( const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0);
+ void getUUID( const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0);
+ void getIPAddrFast( const char *block, const char *var, U32 &ip, S32 blocknum = 0);
+ void getIPAddr( const char *block, const char *var, U32 &ip, S32 blocknum = 0);
+ void getIPPortFast( const char *block, const char *var, U16 &port, S32 blocknum = 0);
+ void getIPPort( const char *block, const char *var, U16 &port, S32 blocknum = 0);
+ void getStringFast( const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0);
+ void getString( const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0);
+ void getStringFast( const char *block, const char *var, std::string& outstr, S32 blocknum = 0);
+ void getString( const char *block, const char *var, std::string& outstr, S32 blocknum = 0);
+
+
+ // Utility functions to generate a replay-resistant digest check
+ // against the shared secret. The window specifies how much of a
+ // time window is allowed - 1 second is good for tight
+ // connections, but multi-process windows might want to be upwards
+ // of 5 seconds. For generateDigest, you want to pass in a
+ // character array of at least MD5HEX_STR_SIZE so that the hex
+ // digest and null termination will fit.
+ bool generateDigestForNumberAndUUIDs(char* digest, const U32 number, const LLUUID &id1, const LLUUID &id2) const;
+ bool generateDigestForWindowAndUUIDs(char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const;
+ bool isMatchingDigestForWindowAndUUIDs(const char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const;
+
+ bool generateDigestForNumber(char* digest, const U32 number) const;
+ bool generateDigestForWindow(char* digest, const S32 window) const;
+ bool isMatchingDigestForWindow(const char* digest, const S32 window) const;
+
+ void showCircuitInfo();
+ void getCircuitInfo(LLSD& info) const;
+
+ U32 getOurCircuitCode();
+
+ void enableCircuit(const LLHost &host, bool trusted);
+ void disableCircuit(const LLHost &host);
+
+ // Use this to establish trust on startup and in response to
+ // DenyTrustedCircuit.
+ void sendCreateTrustedCircuit(const LLHost& host, const LLUUID & id1, const LLUUID & id2);
+
+ // Use this to inform a peer that they aren't currently trusted...
+ // This now enqueues the request so that we can ensure that we only send
+ // one deny per circuit per message loop so that this doesn't become a DoS.
+ // The actual sending is done by reallySendDenyTrustedCircuit()
+ void sendDenyTrustedCircuit(const LLHost &host);
+
+ /** Return false if host is unknown or untrusted */
+ // Note:DaveH/Babbage some trusted messages can be received without a circuit
+ bool isTrustedSender(const LLHost& host) const;
+
+ /** Return true if current message is from trusted source */
+ bool isTrustedSender() const;
+
+ /** Return false true if name is unknown or untrusted */
+ bool isTrustedMessage(const std::string& name) const;
+
+ /** Return false true if name is unknown or trusted */
+ bool isUntrustedMessage(const std::string& name) const;
+
+ // Mark an interface ineligible for trust
+ void setUntrustedInterface( const LLHost host ) { mUntrustedInterface = host; }
+ LLHost getUntrustedInterface() const { return mUntrustedInterface; }
+ void setBlockUntrustedInterface( bool block ) { mBlockUntrustedInterface = block; } // Throw a switch to allow, sending warnings only
+ bool getBlockUntrustedInterface() const { return mBlockUntrustedInterface; }
+
+ // Change this message to be UDP black listed.
+ void banUdpMessage(const std::string& name);
+
+
+private:
+ // A list of the circuits that need to be sent DenyTrustedCircuit messages.
+ typedef std::set<LLHost> host_set_t;
+ host_set_t mDenyTrustedCircuitSet;
+
+ // Really sends the DenyTrustedCircuit message to a given host
+ // related to sendDenyTrustedCircuit()
+ void reallySendDenyTrustedCircuit(const LLHost &host);
+
+public:
+ // Use this to establish trust to and from a host. This blocks
+ // until trust has been established, and probably should only be
+ // used on startup.
+ void establishBidirectionalTrust(const LLHost &host, S64 frame_count = 0);
+
+ // returns whether the given host is on a trusted circuit
+ // Note:DaveH/Babbage some trusted messages can be received without a circuit
+ bool getCircuitTrust(const LLHost &host);
+
+ void setCircuitAllowTimeout(const LLHost &host, bool allow);
+ void setCircuitTimeoutCallback(const LLHost &host, void (*callback_func)(const LLHost &host, void *user_data), void *user_data);
+
+ bool checkCircuitBlocked(const U32 circuit);
+ bool checkCircuitAlive(const U32 circuit);
+ bool checkCircuitAlive(const LLHost &host);
+ void setCircuitProtection(bool b_protect);
+ U32 findCircuitCode(const LLHost &host);
+ LLHost findHost(const U32 circuit_code);
+ void sanityCheck();
+
+ bool has(const char *blockname) const;
+ S32 getNumberOfBlocksFast(const char *blockname) const;
+ S32 getNumberOfBlocks(const char *blockname) const;
+ S32 getSizeFast(const char *blockname, const char *varname) const;
+ S32 getSize(const char *blockname, const char *varname) const;
+ S32 getSizeFast(const char *blockname, S32 blocknum,
+ const char *varname) const; // size in bytes of data
+ S32 getSize(const char *blockname, S32 blocknum, const char *varname) const;
+
+ void resetReceiveCounts(); // resets receive counts for all message types to 0
+ void dumpReceiveCounts(); // dumps receive count for each message type to LL_INFOS()
+ void dumpCircuitInfo(); // Circuit information to LL_INFOS()
+
+ bool isClear() const; // returns mbSClear;
+ S32 flush(const LLHost &host);
+
+ U32 getListenPort( void ) const;
+
+ void startLogging(); // start verbose logging
+ void stopLogging(); // flush and close file
+ void summarizeLogs(std::ostream& str); // log statistics
+
+ S32 getReceiveSize() const;
+ S32 getReceiveCompressedSize() const { return mIncomingCompressedSize; }
+ S32 getReceiveBytes() const;
+
+ S32 getUnackedListSize() const { return mUnackedListSize; }
+
+ //const char* getCurrentSMessageName() const { return mCurrentSMessageName; }
+ //const char* getCurrentSBlockName() const { return mCurrentSBlockName; }
+
+ // friends
+ friend std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg);
+
+ void setMaxMessageTime(const F32 seconds); // Max time to process messages before warning and dumping (neg to disable)
+ void setMaxMessageCounts(const S32 num); // Max number of messages before dumping (neg to disable)
+
+ static U64Microseconds getMessageTimeUsecs(const bool update = false); // Get the current message system time in microseconds
+ static F64Seconds getMessageTimeSeconds(const bool update = false); // Get the current message system time in seconds
+
+ static void setTimeDecodes(bool b);
+ static void setTimeDecodesSpamThreshold(F32 seconds);
+
+ // message handlers internal to the message systesm
+ //static void processAssignCircuitCode(LLMessageSystem* msg, void**);
+ static void processAddCircuitCode(LLMessageSystem* msg, void**);
+ static void processUseCircuitCode(LLMessageSystem* msg, void**);
+ static void processError(LLMessageSystem* msg, void**);
+
+ // dispatch llsd message to http node tree
+ static void dispatch(const std::string& msg_name,
+ const LLSD& message);
+ static void dispatch(const std::string& msg_name,
+ const LLSD& message,
+ LLHTTPNode::ResponsePtr responsep);
+
+ // this is added to support specific legacy messages and is
+ // ***not intended for general use*** Si, Gabriel, 2009
+ static void dispatchTemplate(const std::string& msg_name,
+ const LLSD& message,
+ LLHTTPNode::ResponsePtr responsep);
+
+ void setMessageBans(const LLSD& trusted, const LLSD& untrusted);
+
+ /**
+ * @brief send an error message to the host. This is a helper method.
+ *
+ * @param host Destination host.
+ * @param agent_id Destination agent id (may be null)
+ * @param code An HTTP status compatible error code.
+ * @param token A specific short string based message
+ * @param id The transactionid/uniqueid/sessionid whatever.
+ * @param system The hierarchical path to the system (255 bytes)
+ * @param message Human readable message (1200 bytes)
+ * @param data Extra info.
+ * @return Returns value returned from sendReliable().
+ */
+ S32 sendError(
+ const LLHost& host,
+ const LLUUID& agent_id,
+ S32 code,
+ const std::string& token,
+ const LLUUID& id,
+ const std::string& system,
+ const std::string& message,
+ const LLSD& data);
+
+ // Check UDP messages and pump http_pump to receive HTTP messages.
+ bool checkAllMessages(LockMessageChecker&, S64 frame_count, LLPumpIO* http_pump);
+
+ // Moved to allow access from LLTemplateMessageDispatcher
+ void clearReceiveState();
+
+ // This will cause all trust queries to return true until the next message
+ // is read: use with caution!
+ void receivedMessageFromTrustedSender();
+
+private:
+ typedef boost::function<void(S32)> UntrustedCallback_t;
+ void sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback);
+
+
+ bool mLastMessageFromTrustedMessageService;
+
+ // The mCircuitCodes is a map from circuit codes to session
+ // ids. This allows us to verify sessions on connect.
+ typedef std::map<U32, LLUUID> code_session_map_t;
+ code_session_map_t mCircuitCodes;
+
+ // Viewers need to track a process session in order to make sure
+ // that no one gives them a bad circuit code.
+ LLUUID mSessionID;
+
+ void addTemplate(LLMessageTemplate *templatep);
+ bool decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template );
+
+ void logMsgFromInvalidCircuit( const LLHost& sender, bool recv_reliable );
+ void logTrustedMsgFromUntrustedCircuit( const LLHost& sender );
+ void logValidMsg(LLCircuitData *cdp, const LLHost& sender, bool recv_reliable, bool recv_resent, bool recv_acks );
+ void logRanOffEndOfPacket( const LLHost& sender );
+
+ class LLMessageCountInfo
+ {
+ public:
+ U32 mMessageNum;
+ U32 mMessageBytes;
+ bool mInvalid;
+ };
+
+ LLMessagePollInfo *mPollInfop;
+
+ U8 mEncodedRecvBuffer[MAX_BUFFER_SIZE];
+ U8 mTrueReceiveBuffer[MAX_BUFFER_SIZE];
+ S32 mTrueReceiveSize;
+
+ // Must be valid during decode
+
+ bool mbError;
+ S32 mErrorCode;
+
+ F64Seconds mResendDumpTime; // The last time we dumped resends
+
+ LLMessageCountInfo mMessageCountList[MAX_MESSAGE_COUNT_NUM];
+ S32 mNumMessageCounts;
+ F32Seconds mReceiveTime;
+ F32Seconds mMaxMessageTime; // Max number of seconds for processing messages
+ S32 mMaxMessageCounts; // Max number of messages to process before dumping.
+ F64Seconds mMessageCountTime;
+
+ F64Seconds mCurrentMessageTime; // The current "message system time" (updated the first call to checkMessages after a resetReceiveCount
+
+ // message system exceptions
+ typedef std::pair<msg_exception_callback, void*> exception_t;
+ typedef std::map<EMessageException, exception_t> callbacks_t;
+ callbacks_t mExceptionCallbacks;
+
+ // stuff for logging
+ LLTimer mMessageSystemTimer;
+
+ static F32 mTimeDecodesSpamThreshold; // If mTimeDecodes is on, all this many seconds for each msg decode before spamming
+ static bool mTimeDecodes; // Measure time for all message decodes if true;
+
+ msg_timing_callback mTimingCallback;
+ void* mTimingCallbackData;
+
+ void init(); // ctor shared initialisation.
+
+ LLHost mLastSender;
+ LLHost mLastReceivingIF;
+ S32 mIncomingCompressedSize; // original size of compressed msg (0 if uncomp.)
+ TPACKETID mCurrentRecvPacketID; // packet ID of current receive packet (for reporting)
+
+ LLMessageBuilder* mMessageBuilder;
+ LLTemplateMessageBuilder* mTemplateMessageBuilder;
+ LLSDMessageBuilder* mLLSDMessageBuilder;
+ LLMessageReaderPointer mMessageReader;
+ LLTemplateMessageReader* mTemplateMessageReader;
+ LLSDMessageReader* mLLSDMessageReader;
+
+ friend class LLMessageHandlerBridge;
+ friend class LockMessageChecker;
+
+ bool callHandler(const char *name, bool trustedSource,
+ LLMessageSystem* msg);
+
+
+ /** Find, create or revive circuit for host as needed */
+ LLCircuitData* findCircuit(const LLHost& host, bool resetPacketId);
+};
+
+
+// external hook into messaging system
+extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
+
+// Implementation of LockMessageChecker depends on definition of
+// LLMessageSystem, hence must follow it.
+class LockMessageChecker: public LockMessageReader
+{
+public:
+ LockMessageChecker(LLMessageSystem* msgsystem);
+
+ // For convenience, provide forwarding wrappers so you can call (e.g.)
+ // checkAllMessages() on your LockMessageChecker instance instead of
+ // passing the instance to LLMessageSystem::checkAllMessages(). Use
+ // perfect forwarding to avoid having to maintain these wrappers in sync
+ // with the target methods.
+ template <typename... ARGS>
+ bool checkAllMessages(ARGS&&... args)
+ {
+ return mMessageSystem->checkAllMessages(*this, std::forward<ARGS>(args)...);
+ }
+
+ template <typename... ARGS>
+ bool checkMessages(ARGS&&... args)
+ {
+ return mMessageSystem->checkMessages(*this, std::forward<ARGS>(args)...);
+ }
+
+ template <typename... ARGS>
+ void processAcks(ARGS&&... args)
+ {
+ return mMessageSystem->processAcks(*this, std::forward<ARGS>(args)...);
+ }
+
+private:
+ LLMessageSystem* mMessageSystem;
+};
+
+// Must specific overall system version, which is used to determine
+// if a patch is available in the message template checksum verification.
+// Return true if able to initialize system.
+bool start_messaging_system(
+ const std::string& template_name,
+ U32 port,
+ S32 version_major,
+ S32 version_minor,
+ S32 version_patch,
+ bool b_dump_prehash_file,
+ const std::string& secret,
+ const LLUseCircuitCodeResponder* responder,
+ bool failure_is_fatal,
+ const F32 circuit_heartbeat_interval,
+ const F32 circuit_timeout);
+
+void end_messaging_system(bool print_summary = true);
+
+void null_message_callback(LLMessageSystem *msg, void **data);
+
+//
+// Inlines
+//
+
+#if !defined( LL_BIG_ENDIAN ) && !defined( LL_LITTLE_ENDIAN )
+#error Unknown endianness for htolememcpy. Did you miss a common include?
+#endif
+
+static inline void *htolememcpy(void *vs, const void *vct, EMsgVariableType type, size_t n)
+{
+ char *s = (char *)vs;
+ const char *ct = (const char *)vct;
+#ifdef LL_BIG_ENDIAN
+ S32 i, length;
+#endif
+ switch(type)
+ {
+ case MVT_FIXED:
+ case MVT_VARIABLE:
+ case MVT_U8:
+ case MVT_S8:
+ case MVT_BOOL:
+ case MVT_LLUUID:
+ case MVT_IP_ADDR: // these two are swizzled in the getters and setters
+ case MVT_IP_PORT: // these two are swizzled in the getters and setters
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+
+ case MVT_U16:
+ case MVT_S16:
+ if (n != 2)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ *(s + 1) = *(ct);
+ *(s) = *(ct + 1);
+ return(vs);
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_U32:
+ case MVT_S32:
+ case MVT_F32:
+ if (n != 4)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ *(s + 3) = *(ct);
+ *(s + 2) = *(ct + 1);
+ *(s + 1) = *(ct + 2);
+ *(s) = *(ct + 3);
+ return(vs);
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_U64:
+ case MVT_S64:
+ case MVT_F64:
+ if (n != 8)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ *(s + 7) = *(ct);
+ *(s + 6) = *(ct + 1);
+ *(s + 5) = *(ct + 2);
+ *(s + 4) = *(ct + 3);
+ *(s + 3) = *(ct + 4);
+ *(s + 2) = *(ct + 5);
+ *(s + 1) = *(ct + 6);
+ *(s) = *(ct + 7);
+ return(vs);
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_LLVector3:
+ case MVT_LLQuaternion: // We only send x, y, z and infer w (we set x, y, z to ensure that w >= 0)
+ if (n != 12)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 8, ct + 8, MVT_F32, 4);
+ htolememcpy(s + 4, ct + 4, MVT_F32, 4);
+ return(htolememcpy(s, ct, MVT_F32, 4));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_LLVector3d:
+ if (n != 24)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 16, ct + 16, MVT_F64, 8);
+ htolememcpy(s + 8, ct + 8, MVT_F64, 8);
+ return(htolememcpy(s, ct, MVT_F64, 8));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_LLVector4:
+ if (n != 16)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 12, ct + 12, MVT_F32, 4);
+ htolememcpy(s + 8, ct + 8, MVT_F32, 4);
+ htolememcpy(s + 4, ct + 4, MVT_F32, 4);
+ return(htolememcpy(s, ct, MVT_F32, 4));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_U16Vec3:
+ if (n != 6)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 4, ct + 4, MVT_U16, 2);
+ htolememcpy(s + 2, ct + 2, MVT_U16, 2);
+ return(htolememcpy(s, ct, MVT_U16, 2));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_U16Quat:
+ if (n != 8)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ htolememcpy(s + 6, ct + 6, MVT_U16, 2);
+ htolememcpy(s + 4, ct + 4, MVT_U16, 2);
+ htolememcpy(s + 2, ct + 2, MVT_U16, 2);
+ return(htolememcpy(s, ct, MVT_U16, 2));
+#else
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+#endif
+
+ case MVT_S16Array:
+ if (n % 2)
+ {
+ LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL;
+ }
+#ifdef LL_BIG_ENDIAN
+ length = n % 2;
+ for (i = 1; i < length; i++)
+ {
+ htolememcpy(s + i*2, ct + i*2, MVT_S16, 2);
+ }
+ return(htolememcpy(s, ct, MVT_S16, 2));
+#else
+ return(memcpy(s,ct,n));
+#endif
+
+ default:
+ return(memcpy(s,ct,n)); /* Flawfinder: ignore */
+ }
+}
+
+inline void *ntohmemcpy(void *s, const void *ct, EMsgVariableType type, size_t n)
+{
+ return(htolememcpy(s,ct,type, n));
+}
+
+inline const LLHost& LLMessageSystem::getReceivingInterface() const {return mLastReceivingIF;}
+
+inline U32 LLMessageSystem::getSenderIP() const
+{
+ return mLastSender.getAddress();
+}
+
+inline U32 LLMessageSystem::getSenderPort() const
+{
+ return mLastSender.getPort();
+}
+
+
+//-----------------------------------------------------------------------------
+// Transmission aliases
+//-----------------------------------------------------------------------------
+
+inline S32 LLMessageSystem::sendMessage(const U32 circuit)
+{
+ return sendMessage(findHost(circuit));
+}
+
+#endif