diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/llmessage/message.h | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/llmessage/message.h')
-rw-r--r-- | indra/llmessage/message.h | 2342 |
1 files changed, 1171 insertions, 1171 deletions
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 8f15bc266d..b4b0d94021 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -1,1171 +1,1171 @@ -/**
- * @file message.h
- * @brief LLMessageSystem class header file
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_MESSAGE_H
-#define LL_MESSAGE_H
-
-#include <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 |