4064 lines
110 KiB
C++
4064 lines
110 KiB
C++
/**
|
|
* @file message.cpp
|
|
* @brief LLMessageSystem class implementation
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "linden_common.h"
|
|
|
|
#include "message.h"
|
|
|
|
// system library includes
|
|
#if !LL_WINDOWS
|
|
// following header files required for inet_addr()
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
#include <iomanip>
|
|
#include <iterator>
|
|
#include <sstream>
|
|
|
|
#include "llapr.h"
|
|
#include "apr_portable.h"
|
|
#include "apr_network_io.h"
|
|
#include "apr_poll.h"
|
|
|
|
// linden library headers
|
|
#include "indra_constants.h"
|
|
#include "lldir.h"
|
|
#include "llerror.h"
|
|
#include "llfasttimer.h"
|
|
#include "llhttpclient.h"
|
|
#include "llhttpnodeadapter.h"
|
|
#include "llhttpsender.h"
|
|
#include "llmd5.h"
|
|
#include "llmessagebuilder.h"
|
|
#include "llmessageconfig.h"
|
|
#include "lltemplatemessagedispatcher.h"
|
|
#include "llpumpio.h"
|
|
#include "lltemplatemessagebuilder.h"
|
|
#include "lltemplatemessagereader.h"
|
|
#include "lltrustedmessageservice.h"
|
|
#include "llmessagetemplate.h"
|
|
#include "llmessagetemplateparser.h"
|
|
#include "llsd.h"
|
|
#include "llsdmessagebuilder.h"
|
|
#include "llsdmessagereader.h"
|
|
#include "llsdserialize.h"
|
|
#include "llstring.h"
|
|
#include "lltransfermanager.h"
|
|
#include "lluuid.h"
|
|
#include "llxfermanager.h"
|
|
#include "timing.h"
|
|
#include "llquaternion.h"
|
|
#include "v3dmath.h"
|
|
#include "v3math.h"
|
|
#include "v4math.h"
|
|
#include "lltransfertargetvfile.h"
|
|
#include "llpacketring.h"
|
|
|
|
class AIHTTPTimeoutPolicy;
|
|
extern AIHTTPTimeoutPolicy fnPtrResponder_timeout;
|
|
|
|
// Constants
|
|
//const char* MESSAGE_LOG_FILENAME = "message.log";
|
|
static const F32Seconds CIRCUIT_DUMP_TIMEOUT(30.f);
|
|
static const S32 TRUST_TIME_WINDOW = 3;
|
|
|
|
// *NOTE: This needs to be moved into a seperate file so that it never gets
|
|
// included in the viewer. 30 Sep 2002 mark
|
|
// *NOTE: I don't think it's important that the messgage system tracks
|
|
// this since it must get set externally. 2004.08.25 Phoenix.
|
|
static std::string g_shared_secret;
|
|
std::string get_shared_secret();
|
|
|
|
class LLMessagePollInfo
|
|
{
|
|
public:
|
|
apr_socket_t *mAPRSocketp;
|
|
apr_pollfd_t mPollFD;
|
|
};
|
|
|
|
namespace
|
|
{
|
|
class LLFnPtrResponder : public LLHTTPClient::ResponderWithResult
|
|
{
|
|
LOG_CLASS(LLFnPtrResponder);
|
|
public:
|
|
LLFnPtrResponder(void (*callback)(void **,S32), void **callbackData, const std::string& name) :
|
|
mCallback(callback),
|
|
mCallbackData(callbackData),
|
|
mMessageName(name)
|
|
{
|
|
}
|
|
|
|
/*virtual*/ void httpFailure(void)
|
|
{
|
|
// don't spam when agent communication disconnected already
|
|
if (mStatus != 410)
|
|
{
|
|
LL_WARNS("Messaging") << "error status " << mStatus
|
|
<< " for message " << mMessageName
|
|
<< " reason " << mReason << LL_ENDL;
|
|
}
|
|
// TODO: Map mStatus in to useful error code.
|
|
if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_TCP_TIMEOUT);
|
|
}
|
|
|
|
/*virtual*/ void httpSuccess(void)
|
|
{
|
|
if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR);
|
|
}
|
|
|
|
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return fnPtrResponder_timeout; }
|
|
/*virtual*/ char const* getName(void) const { return "LLFnPtrResponder"; }
|
|
|
|
private:
|
|
|
|
void (*mCallback)(void **,S32);
|
|
void **mCallbackData;
|
|
std::string mMessageName;
|
|
};
|
|
}
|
|
|
|
class LLMessageHandlerBridge : public LLHTTPNode
|
|
{
|
|
virtual bool validate(const std::string& name, LLSD& context) const
|
|
{ return true; }
|
|
|
|
virtual void post(LLHTTPNode::ResponsePtr response, const LLSD& context,
|
|
const LLSD& input) const;
|
|
};
|
|
|
|
//virtual
|
|
void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response,
|
|
const LLSD& context, const LLSD& input) const
|
|
{
|
|
std::string name = context["request"]["wildcard"]["message-name"];
|
|
char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str());
|
|
|
|
LL_DEBUGS() << "Setting mLastSender " << input["sender"].asString() << LL_ENDL;
|
|
gMessageSystem->mLastSender = LLHost(input["sender"].asString());
|
|
gMessageSystem->mPacketsIn += 1;
|
|
gMessageSystem->mLLSDMessageReader->setMessage(namePtr, input["body"]);
|
|
gMessageSystem->mMessageReader = gMessageSystem->mLLSDMessageReader;
|
|
|
|
if(gMessageSystem->callHandler(namePtr, false, gMessageSystem))
|
|
{
|
|
response->result(LLSD());
|
|
}
|
|
else
|
|
{
|
|
response->notFound();
|
|
}
|
|
}
|
|
|
|
LLHTTPRegistration<LLMessageHandlerBridge>
|
|
gHTTPRegistrationMessageWildcard("/message/<message-name>");
|
|
|
|
//virtual
|
|
LLUseCircuitCodeResponder::~LLUseCircuitCodeResponder()
|
|
{
|
|
// even abstract base classes need a concrete destructor
|
|
}
|
|
|
|
static const char* nullToEmpty(const char* s)
|
|
{
|
|
static char emptyString[] = "";
|
|
return s? s : emptyString;
|
|
}
|
|
|
|
void LLMessageSystem::init()
|
|
{
|
|
// initialize member variables
|
|
mVerboseLog = FALSE;
|
|
|
|
mbError = FALSE;
|
|
mErrorCode = 0;
|
|
mSendReliable = FALSE;
|
|
|
|
mUnackedListDepth = 0;
|
|
mUnackedListSize = 0;
|
|
mDSMaxListDepth = 0;
|
|
|
|
mNumberHighFreqMessages = 0;
|
|
mNumberMediumFreqMessages = 0;
|
|
mNumberLowFreqMessages = 0;
|
|
mPacketsIn = mPacketsOut = 0;
|
|
mBytesIn = mBytesOut = 0;
|
|
mCompressedPacketsIn = mCompressedPacketsOut = 0;
|
|
mReliablePacketsIn = mReliablePacketsOut = 0;
|
|
|
|
mCompressedBytesIn = 0;
|
|
mCompressedBytesOut = 0;
|
|
mUncompressedBytesIn = 0;
|
|
mUncompressedBytesOut = 0;
|
|
mTotalBytesIn = 0;
|
|
mTotalBytesOut = 0;
|
|
|
|
mDroppedPackets = 0; // total dropped packets in
|
|
mResentPackets = 0; // total resent packets out
|
|
mFailedResendPackets = 0; // total resend failure packets out
|
|
mOffCircuitPackets = 0; // total # of off-circuit packets rejected
|
|
mInvalidOnCircuitPackets = 0; // total # of on-circuit packets rejected
|
|
|
|
mOurCircuitCode = 0;
|
|
|
|
mIncomingCompressedSize = 0;
|
|
mCurrentRecvPacketID = 0;
|
|
|
|
mMessageFileVersionNumber = 0.f;
|
|
|
|
mTimingCallback = NULL;
|
|
mTimingCallbackData = NULL;
|
|
|
|
mMessageBuilder = NULL;
|
|
mMessageReader = NULL;
|
|
}
|
|
|
|
// Read file and build message templates
|
|
LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port,
|
|
S32 version_major,
|
|
S32 version_minor,
|
|
S32 version_patch,
|
|
bool failure_is_fatal,
|
|
const F32 circuit_heartbeat_interval, const F32 circuit_timeout) :
|
|
mCircuitInfo(F32Seconds(circuit_heartbeat_interval), F32Seconds(circuit_timeout)),
|
|
mLastMessageFromTrustedMessageService(false),
|
|
mPacketRing(new LLPacketRing)
|
|
{
|
|
init();
|
|
|
|
mSendSize = 0;
|
|
|
|
mSystemVersionMajor = version_major;
|
|
mSystemVersionMinor = version_minor;
|
|
mSystemVersionPatch = version_patch;
|
|
mSystemVersionServer = 0;
|
|
mVersionFlags = 0x0;
|
|
|
|
// default to not accepting packets from not alive circuits
|
|
mbProtected = TRUE;
|
|
|
|
// default to blocking trusted connections on a public interface if one is specified
|
|
mBlockUntrustedInterface = true;
|
|
|
|
mSendPacketFailureCount = 0;
|
|
|
|
mCircuitPrintFreq = F32Seconds(60.f);
|
|
|
|
loadTemplateFile(filename, failure_is_fatal);
|
|
|
|
mTemplateMessageBuilder = new LLTemplateMessageBuilder(mMessageTemplates);
|
|
mLLSDMessageBuilder = new LLSDMessageBuilder();
|
|
mMessageBuilder = NULL;
|
|
|
|
mTemplateMessageReader = new LLTemplateMessageReader(mMessageNumbers);
|
|
mLLSDMessageReader = new LLSDMessageReader();
|
|
mMessageReader = NULL;
|
|
|
|
// initialize various bits of net info
|
|
mSocket = 0;
|
|
mPort = port;
|
|
|
|
S32 error = start_net(mSocket, mPort);
|
|
if (error != 0)
|
|
{
|
|
mbError = TRUE;
|
|
mErrorCode = error;
|
|
}
|
|
// LL_DEBUGS("Messaging") << << "*** port: " << mPort << LL_ENDL;
|
|
|
|
//
|
|
// Create the data structure that we can poll on
|
|
//
|
|
apr_socket_t *aprSocketp = NULL;
|
|
apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, LLAPRRootPool::get()());
|
|
|
|
mPollInfop = new LLMessagePollInfo;
|
|
mPollInfop->mAPRSocketp = aprSocketp;
|
|
mPollInfop->mPollFD.p = LLAPRRootPool::get()();
|
|
mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET;
|
|
mPollInfop->mPollFD.reqevents = APR_POLLIN;
|
|
mPollInfop->mPollFD.rtnevents = 0;
|
|
mPollInfop->mPollFD.desc.s = aprSocketp;
|
|
mPollInfop->mPollFD.client_data = NULL;
|
|
|
|
F64Seconds mt_sec = getMessageTimeSeconds();
|
|
mResendDumpTime = mt_sec;
|
|
mMessageCountTime = mt_sec;
|
|
mCircuitPrintTime = mt_sec;
|
|
mCurrentMessageTime = F64Seconds(mt_sec);
|
|
|
|
// Constants for dumping output based on message processing time/count
|
|
mNumMessageCounts = 0;
|
|
mMaxMessageCounts = 200; // >= 0 means dump warnings
|
|
mMaxMessageTime = F32Seconds(1.f);
|
|
|
|
mTrueReceiveSize = 0;
|
|
|
|
mReceiveTime = F32Seconds(0.f);
|
|
}
|
|
|
|
|
|
|
|
// Read file and build message templates
|
|
void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure_is_fatal)
|
|
{
|
|
if(filename.empty())
|
|
{
|
|
LL_ERRS("Messaging") << "No template filename specified" << LL_ENDL;
|
|
mbError = TRUE;
|
|
return;
|
|
}
|
|
|
|
std::string template_body;
|
|
if(!_read_file_into_string(template_body, filename))
|
|
{
|
|
if (failure_is_fatal) {
|
|
LL_ERRS("Messaging") << "Failed to open template: " << filename << LL_ENDL;
|
|
} else {
|
|
LL_WARNS("Messaging") << "Failed to open template: " << filename << LL_ENDL;
|
|
}
|
|
mbError = TRUE;
|
|
return;
|
|
}
|
|
|
|
LLTemplateTokenizer tokens(template_body);
|
|
LLTemplateParser parsed(tokens);
|
|
mMessageFileVersionNumber = parsed.getVersion();
|
|
for(LLTemplateParser::message_iterator iter = parsed.getMessagesBegin();
|
|
iter != parsed.getMessagesEnd();
|
|
iter++)
|
|
{
|
|
addTemplate(*iter);
|
|
}
|
|
}
|
|
|
|
|
|
LLMessageSystem::~LLMessageSystem()
|
|
{
|
|
mMessageTemplates.clear(); // don't delete templates.
|
|
for_each(mMessageNumbers.begin(), mMessageNumbers.end(), DeletePairedPointer());
|
|
mMessageNumbers.clear();
|
|
|
|
if (!mbError)
|
|
{
|
|
end_net(mSocket);
|
|
}
|
|
mSocket = 0;
|
|
|
|
delete mTemplateMessageReader;
|
|
mTemplateMessageReader = NULL;
|
|
mMessageReader = NULL;
|
|
|
|
delete mTemplateMessageBuilder;
|
|
mTemplateMessageBuilder = NULL;
|
|
mMessageBuilder = NULL;
|
|
|
|
delete mLLSDMessageReader;
|
|
mLLSDMessageReader = NULL;
|
|
|
|
delete mLLSDMessageBuilder;
|
|
mLLSDMessageBuilder = NULL;
|
|
|
|
delete mPollInfop;
|
|
mPollInfop = NULL;
|
|
|
|
delete mPacketRing;
|
|
mPacketRing = NULL;
|
|
|
|
mIncomingCompressedSize = 0;
|
|
mCurrentRecvPacketID = 0;
|
|
}
|
|
|
|
void LLMessageSystem::clearReceiveState()
|
|
{
|
|
mCurrentRecvPacketID = 0;
|
|
mIncomingCompressedSize = 0;
|
|
mLastSender.invalidate();
|
|
mLastReceivingIF.invalidate();
|
|
mMessageReader->clearMessage();
|
|
mLastMessageFromTrustedMessageService = false;
|
|
}
|
|
|
|
|
|
BOOL LLMessageSystem::poll(F32 seconds)
|
|
{
|
|
S32 num_socks;
|
|
apr_status_t status;
|
|
status = apr_poll(&(mPollInfop->mPollFD), 1, &num_socks,(U64)(seconds*1000000.f));
|
|
if (status != APR_TIMEUP)
|
|
{
|
|
ll_apr_warn_status(status);
|
|
}
|
|
if (num_socks)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
bool LLMessageSystem::isTrustedSender(const LLHost& host) const
|
|
{
|
|
LLCircuitData* cdp = mCircuitInfo.findCircuit(host);
|
|
if(NULL == cdp)
|
|
{
|
|
return false;
|
|
}
|
|
return cdp->getTrusted();
|
|
}
|
|
|
|
void LLMessageSystem::receivedMessageFromTrustedSender()
|
|
{
|
|
mLastMessageFromTrustedMessageService = true;
|
|
}
|
|
|
|
bool LLMessageSystem::isTrustedSender() const
|
|
{
|
|
return mLastMessageFromTrustedMessageService ||
|
|
isTrustedSender(getSender());
|
|
}
|
|
|
|
static LLMessageSystem::message_template_name_map_t::const_iterator
|
|
findTemplate(const LLMessageSystem::message_template_name_map_t& templates,
|
|
std::string name)
|
|
{
|
|
const char* namePrehash = LLMessageStringTable::getInstance()->getString(name.c_str());
|
|
if(NULL == namePrehash) {return templates.end();}
|
|
return templates.find(namePrehash);
|
|
}
|
|
|
|
bool LLMessageSystem::isTrustedMessage(const std::string& name) const
|
|
{
|
|
message_template_name_map_t::const_iterator iter =
|
|
findTemplate(mMessageTemplates, name);
|
|
if(iter == mMessageTemplates.end()) {return false;}
|
|
return iter->second->getTrust() == MT_TRUST;
|
|
}
|
|
|
|
bool LLMessageSystem::isUntrustedMessage(const std::string& name) const
|
|
{
|
|
message_template_name_map_t::const_iterator iter =
|
|
findTemplate(mMessageTemplates, name);
|
|
if(iter == mMessageTemplates.end()) {return false;}
|
|
return iter->second->getTrust() == MT_NOTRUST;
|
|
}
|
|
|
|
LLCircuitData* LLMessageSystem::findCircuit(const LLHost& host,
|
|
bool resetPacketId)
|
|
{
|
|
LLCircuitData* cdp = mCircuitInfo.findCircuit(host);
|
|
if (!cdp)
|
|
{
|
|
// This packet comes from a circuit we don't know about.
|
|
|
|
// Are we rejecting off-circuit packets?
|
|
if (mbProtected)
|
|
{
|
|
// cdp is already NULL, so we don't need to unset it.
|
|
}
|
|
else
|
|
{
|
|
// nope, open the new circuit
|
|
cdp = mCircuitInfo.addCircuitData(host, mCurrentRecvPacketID);
|
|
|
|
if(resetPacketId)
|
|
{
|
|
// I added this - I think it's correct - DJS
|
|
// reset packet in ID
|
|
cdp->setPacketInID(mCurrentRecvPacketID);
|
|
}
|
|
// And claim the packet is on the circuit we just added.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this is an old circuit. . . is it still alive?
|
|
if (!cdp->isAlive())
|
|
{
|
|
// nope. don't accept if we're protected
|
|
if (mbProtected)
|
|
{
|
|
// don't accept packets from unexpected sources
|
|
cdp = NULL;
|
|
}
|
|
else
|
|
{
|
|
// wake up the circuit
|
|
cdp->setAlive(TRUE);
|
|
|
|
if(resetPacketId)
|
|
{
|
|
// reset packet in ID
|
|
cdp->setPacketInID(mCurrentRecvPacketID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return cdp;
|
|
}
|
|
|
|
// Returns TRUE if a valid, on-circuit message has been received.
|
|
BOOL LLMessageSystem::checkMessages( S64 frame_count )
|
|
{
|
|
// Pump
|
|
BOOL valid_packet = FALSE;
|
|
mMessageReader = mTemplateMessageReader;
|
|
|
|
LLTransferTargetVFile::updateQueue();
|
|
|
|
if (!mNumMessageCounts)
|
|
{
|
|
// This is the first message being handled after a resetReceiveCounts,
|
|
// we must be starting the message processing loop. Reset the timers.
|
|
mCurrentMessageTime = totalTime();
|
|
mMessageCountTime = getMessageTimeSeconds();
|
|
}
|
|
|
|
// loop until either no packets or a valid packet
|
|
// i.e., burn through packets from unregistered circuits
|
|
S32 receive_size = 0;
|
|
do
|
|
{
|
|
clearReceiveState();
|
|
|
|
BOOL recv_reliable = FALSE;
|
|
BOOL recv_resent = FALSE;
|
|
S32 acks = 0;
|
|
S32 true_rcv_size = 0;
|
|
|
|
U8* buffer = mTrueReceiveBuffer;
|
|
|
|
mTrueReceiveSize = mPacketRing->receivePacket(mSocket, (char *)mTrueReceiveBuffer);
|
|
// If you want to dump all received packets into SecondLife.log, uncomment this
|
|
//dumpPacketToLog();
|
|
|
|
receive_size = mTrueReceiveSize;
|
|
mLastSender = mPacketRing->getLastSender();
|
|
mLastReceivingIF = mPacketRing->getLastReceivingInterface();
|
|
|
|
if (receive_size < (S32) LL_MINIMUM_VALID_PACKET_SIZE)
|
|
{
|
|
// A receive size of zero is OK, that means that there are no more packets available.
|
|
// Ones that are non-zero but below the minimum packet size are worrisome.
|
|
if (receive_size > 0)
|
|
{
|
|
LL_WARNS("Messaging") << "Invalid (too short) packet discarded " << receive_size << LL_ENDL;
|
|
callExceptionFunc(MX_PACKET_TOO_SHORT);
|
|
}
|
|
// no data in packet receive buffer
|
|
valid_packet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
LLHost host;
|
|
LLCircuitData* cdp;
|
|
|
|
// note if packet acks are appended.
|
|
if(buffer[0] & LL_ACK_FLAG)
|
|
{
|
|
acks += buffer[--receive_size];
|
|
true_rcv_size = receive_size;
|
|
if(receive_size >= ((S32)(acks * sizeof(TPACKETID) + LL_MINIMUM_VALID_PACKET_SIZE)))
|
|
{
|
|
receive_size -= acks * sizeof(TPACKETID);
|
|
}
|
|
else
|
|
{
|
|
// mal-formed packet. ignore it and continue with
|
|
// the next one
|
|
LL_WARNS("Messaging") << "Malformed packet received. Packet size "
|
|
<< receive_size << " with invalid no. of acks " << acks
|
|
<< LL_ENDL;
|
|
valid_packet = FALSE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// process the message as normal
|
|
mIncomingCompressedSize = zeroCodeExpand(&buffer, &receive_size);
|
|
mCurrentRecvPacketID = ntohl(*((U32*)(&buffer[1])));
|
|
host = getSender();
|
|
|
|
const bool resetPacketId = true;
|
|
cdp = findCircuit(host, resetPacketId);
|
|
|
|
// At this point, cdp is now a pointer to the circuit that
|
|
// this message came in on if it's valid, and NULL if the
|
|
// circuit was bogus.
|
|
|
|
if(cdp && (acks > 0) && ((S32)(acks * sizeof(TPACKETID)) < (true_rcv_size)))
|
|
{
|
|
TPACKETID packet_id;
|
|
U32 mem_id=0;
|
|
for(S32 i = 0; i < acks; ++i)
|
|
{
|
|
true_rcv_size -= sizeof(TPACKETID);
|
|
memcpy(&mem_id, &mTrueReceiveBuffer[true_rcv_size], /* Flawfinder: ignore*/
|
|
sizeof(TPACKETID));
|
|
packet_id = ntohl(mem_id);
|
|
//LL_INFOS("Messaging") << "got ack: " << packet_id << LL_ENDL;
|
|
cdp->ackReliablePacket(packet_id);
|
|
}
|
|
if (!cdp->getUnackedPacketCount())
|
|
{
|
|
// Remove this circuit from the list of circuits with unacked packets
|
|
mCircuitInfo.mUnackedCircuitMap.erase(cdp->mHost);
|
|
}
|
|
}
|
|
|
|
if (buffer[0] & LL_RELIABLE_FLAG)
|
|
{
|
|
recv_reliable = TRUE;
|
|
}
|
|
if (buffer[0] & LL_RESENT_FLAG)
|
|
{
|
|
recv_resent = TRUE;
|
|
if (cdp && cdp->isDuplicateResend(mCurrentRecvPacketID))
|
|
{
|
|
// We need to ACK here to suppress
|
|
// further resends of packets we've
|
|
// already seen.
|
|
if (recv_reliable)
|
|
{
|
|
//mAckList.addData(new LLPacketAck(host, mCurrentRecvPacketID));
|
|
// ***************************************
|
|
// TESTING CODE
|
|
//if(mCircuitInfo.mCurrentCircuit->mHost != host)
|
|
//{
|
|
// LL_WARNS("Messaging") << "DISCARDED PACKET HOST MISMATCH! HOST: "
|
|
// << host << " CIRCUIT: "
|
|
// << mCircuitInfo.mCurrentCircuit->mHost
|
|
// << LL_ENDL;
|
|
//}
|
|
// ***************************************
|
|
//mCircuitInfo.mCurrentCircuit->mAcks.put(mCurrentRecvPacketID);
|
|
cdp->collectRAck(mCurrentRecvPacketID);
|
|
}
|
|
|
|
LL_DEBUGS("Messaging") << "Discarding duplicate resend from " << host << LL_ENDL;
|
|
if(mVerboseLog)
|
|
{
|
|
std::ostringstream str;
|
|
str << "MSG: <- " << host;
|
|
std::string tbuf;
|
|
tbuf = llformat( "\t%6d\t%6d\t%6d ", receive_size, (mIncomingCompressedSize ? mIncomingCompressedSize : receive_size), mCurrentRecvPacketID);
|
|
str << tbuf << "(unknown)"
|
|
<< (recv_reliable ? " reliable" : "")
|
|
<< " resent "
|
|
<< ((acks > 0) ? "acks" : "")
|
|
<< " DISCARD DUPLICATE";
|
|
LL_INFOS("Messaging") << str.str() << LL_ENDL;
|
|
}
|
|
mPacketsIn++;
|
|
valid_packet = FALSE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// UseCircuitCode can be a valid, off-circuit packet.
|
|
// But we don't want to acknowledge UseCircuitCode until the circuit is
|
|
// available, which is why the acknowledgement test is done above. JC
|
|
bool trusted = cdp && cdp->getTrusted();
|
|
valid_packet = mTemplateMessageReader->validateMessage(
|
|
buffer,
|
|
receive_size,
|
|
host,
|
|
trusted);
|
|
if (!valid_packet)
|
|
{
|
|
clearReceiveState();
|
|
}
|
|
|
|
// UseCircuitCode is allowed in even from an invalid circuit, so that
|
|
// we can toss circuits around.
|
|
if(
|
|
valid_packet &&
|
|
!cdp &&
|
|
(mTemplateMessageReader->getMessageName() !=
|
|
_PREHASH_UseCircuitCode))
|
|
{
|
|
logMsgFromInvalidCircuit( host, recv_reliable );
|
|
clearReceiveState();
|
|
valid_packet = FALSE;
|
|
}
|
|
|
|
if(
|
|
valid_packet &&
|
|
cdp &&
|
|
!cdp->getTrusted() &&
|
|
mTemplateMessageReader->isTrusted())
|
|
{
|
|
logTrustedMsgFromUntrustedCircuit( host );
|
|
clearReceiveState();
|
|
|
|
sendDenyTrustedCircuit(host);
|
|
valid_packet = FALSE;
|
|
}
|
|
|
|
if( valid_packet )
|
|
{
|
|
logValidMsg(cdp, host, recv_reliable, recv_resent, (BOOL)(acks>0) );
|
|
valid_packet = mTemplateMessageReader->readMessage(buffer, host);
|
|
}
|
|
|
|
// It's possible that the circuit went away, because ANY message can disable the circuit
|
|
// (for example, UseCircuit, CloseCircuit, DisableSimulator). Find it again.
|
|
cdp = mCircuitInfo.findCircuit(host);
|
|
|
|
if (valid_packet)
|
|
{
|
|
mPacketsIn++;
|
|
mBytesIn += mTrueReceiveSize;
|
|
|
|
// ACK here for valid packets that we've seen
|
|
// for the first time.
|
|
if (cdp && recv_reliable)
|
|
{
|
|
// Add to the recently received list for duplicate suppression
|
|
cdp->mRecentlyReceivedReliablePackets[mCurrentRecvPacketID] = getMessageTimeUsecs();
|
|
|
|
// Put it onto the list of packets to be acked
|
|
cdp->collectRAck(mCurrentRecvPacketID);
|
|
mReliablePacketsIn++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mbProtected && (!cdp))
|
|
{
|
|
LL_WARNS("Messaging") << "Invalid Packet from invalid circuit " << host << LL_ENDL;
|
|
mOffCircuitPackets++;
|
|
}
|
|
else
|
|
{
|
|
mInvalidOnCircuitPackets++;
|
|
}
|
|
}
|
|
}
|
|
} while (!valid_packet && receive_size > 0);
|
|
|
|
F64Seconds mt_sec = getMessageTimeSeconds();
|
|
// Check to see if we need to print debug info
|
|
if ((mt_sec - mCircuitPrintTime) > mCircuitPrintFreq)
|
|
{
|
|
dumpCircuitInfo();
|
|
mCircuitPrintTime = mt_sec;
|
|
}
|
|
|
|
if( !valid_packet )
|
|
{
|
|
clearReceiveState();
|
|
}
|
|
|
|
return valid_packet;
|
|
}
|
|
|
|
S32 LLMessageSystem::getReceiveBytes() const
|
|
{
|
|
if (getReceiveCompressedSize())
|
|
{
|
|
return getReceiveCompressedSize() * 8;
|
|
}
|
|
else
|
|
{
|
|
return getReceiveSize() * 8;
|
|
}
|
|
}
|
|
|
|
|
|
void LLMessageSystem::processAcks(F32 collect_time)
|
|
{
|
|
F64Seconds mt_sec = getMessageTimeSeconds();
|
|
{
|
|
gTransferManager.updateTransfers();
|
|
|
|
if (gXferManager)
|
|
{
|
|
gXferManager->retransmitUnackedPackets();
|
|
}
|
|
|
|
if (gAssetStorage)
|
|
{
|
|
gAssetStorage->checkForTimeouts();
|
|
}
|
|
}
|
|
|
|
BOOL dump = FALSE;
|
|
{
|
|
// Check the status of circuits
|
|
mCircuitInfo.updateWatchDogTimers(this);
|
|
|
|
//resend any necessary packets
|
|
mCircuitInfo.resendUnackedPackets(mUnackedListDepth, mUnackedListSize);
|
|
|
|
//cycle through ack list for each host we need to send acks to
|
|
mCircuitInfo.sendAcks(collect_time);
|
|
|
|
if (!mDenyTrustedCircuitSet.empty())
|
|
{
|
|
LL_INFOS("Messaging") << "Sending queued DenyTrustedCircuit messages." << LL_ENDL;
|
|
for (host_set_t::iterator hostit = mDenyTrustedCircuitSet.begin(); hostit != mDenyTrustedCircuitSet.end(); ++hostit)
|
|
{
|
|
reallySendDenyTrustedCircuit(*hostit);
|
|
}
|
|
mDenyTrustedCircuitSet.clear();
|
|
}
|
|
|
|
if (mMaxMessageCounts >= 0)
|
|
{
|
|
if (mNumMessageCounts >= mMaxMessageCounts)
|
|
{
|
|
dump = TRUE;
|
|
}
|
|
}
|
|
|
|
if (mMaxMessageTime >= F32Seconds(0.f))
|
|
{
|
|
// This is one of the only places where we're required to get REAL message system time.
|
|
mReceiveTime = getMessageTimeSeconds(TRUE) - mMessageCountTime;
|
|
if (mReceiveTime > mMaxMessageTime)
|
|
{
|
|
dump = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dump)
|
|
{
|
|
dumpReceiveCounts();
|
|
}
|
|
resetReceiveCounts();
|
|
|
|
if ((mt_sec - mResendDumpTime) > CIRCUIT_DUMP_TIMEOUT)
|
|
{
|
|
mResendDumpTime = mt_sec;
|
|
mCircuitInfo.dumpResends();
|
|
}
|
|
}
|
|
|
|
void LLMessageSystem::copyMessageReceivedToSend()
|
|
{
|
|
// NOTE: babbage: switch builder to match reader to avoid
|
|
// converting message format
|
|
if(mMessageReader == mTemplateMessageReader)
|
|
{
|
|
mMessageBuilder = mTemplateMessageBuilder;
|
|
}
|
|
else
|
|
{
|
|
mMessageBuilder = mLLSDMessageBuilder;
|
|
}
|
|
mSendReliable = FALSE;
|
|
mMessageBuilder->newMessage(mMessageReader->getMessageName());
|
|
mMessageReader->copyToBuilder(*mMessageBuilder);
|
|
}
|
|
|
|
LLSD LLMessageSystem::getReceivedMessageLLSD() const
|
|
{
|
|
LLSDMessageBuilder builder;
|
|
mMessageReader->copyToBuilder(builder);
|
|
return builder.getMessage();
|
|
}
|
|
|
|
LLSD LLMessageSystem::getBuiltMessageLLSD() const
|
|
{
|
|
LLSD result;
|
|
if (mLLSDMessageBuilder == mMessageBuilder)
|
|
{
|
|
result = mLLSDMessageBuilder->getMessage();
|
|
}
|
|
else
|
|
{
|
|
// TODO: implement as below?
|
|
LL_ERRS() << "Message not built as LLSD." << LL_ENDL;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
LLSD LLMessageSystem::wrapReceivedTemplateData() const
|
|
{
|
|
if(mMessageReader == mTemplateMessageReader)
|
|
{
|
|
LLTemplateMessageBuilder builder(mMessageTemplates);
|
|
builder.newMessage(mMessageReader->getMessageName());
|
|
mMessageReader->copyToBuilder(builder);
|
|
U8 buffer[MAX_BUFFER_SIZE];
|
|
const U8 offset_to_data = 0;
|
|
U32 size = builder.buildMessage(buffer, MAX_BUFFER_SIZE,
|
|
offset_to_data);
|
|
std::vector<U8> binary_data(buffer, buffer+size);
|
|
LLSD wrapped_data = LLSD::emptyMap();
|
|
wrapped_data["binary-template-data"] = binary_data;
|
|
return wrapped_data;
|
|
}
|
|
else
|
|
{
|
|
return getReceivedMessageLLSD();
|
|
}
|
|
}
|
|
|
|
LLSD LLMessageSystem::wrapBuiltTemplateData() const
|
|
{
|
|
LLSD result;
|
|
if (mLLSDMessageBuilder == mMessageBuilder)
|
|
{
|
|
result = getBuiltMessageLLSD();
|
|
}
|
|
else
|
|
{
|
|
U8 buffer[MAX_BUFFER_SIZE];
|
|
const U8 offset_to_data = 0;
|
|
U32 size = mTemplateMessageBuilder->buildMessage(
|
|
buffer, MAX_BUFFER_SIZE,
|
|
offset_to_data);
|
|
std::vector<U8> binary_data(buffer, buffer+size);
|
|
LLSD wrapped_data = LLSD::emptyMap();
|
|
wrapped_data["binary-template-data"] = binary_data;
|
|
result = wrapped_data;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
LLStoredMessagePtr LLMessageSystem::getReceivedMessage() const
|
|
{
|
|
const std::string& name = mMessageReader->getMessageName();
|
|
LLSD message = wrapReceivedTemplateData();
|
|
|
|
return LLStoredMessagePtr(new LLStoredMessage(name, message));
|
|
}
|
|
|
|
LLStoredMessagePtr LLMessageSystem::getBuiltMessage() const
|
|
{
|
|
const std::string& name = mMessageBuilder->getMessageName();
|
|
LLSD message = wrapBuiltTemplateData();
|
|
|
|
return LLStoredMessagePtr(new LLStoredMessage(name, message));
|
|
}
|
|
|
|
S32 LLMessageSystem::sendMessage(const LLHost &host, LLStoredMessagePtr message)
|
|
{
|
|
return sendMessage(host, message->mName.c_str(), message->mMessage);
|
|
}
|
|
|
|
|
|
void LLMessageSystem::clearMessage()
|
|
{
|
|
mSendReliable = FALSE;
|
|
mMessageBuilder->clearMessage();
|
|
}
|
|
|
|
// set block to add data to within current message
|
|
void LLMessageSystem::nextBlockFast(const char *blockname)
|
|
{
|
|
mMessageBuilder->nextBlock(blockname);
|
|
}
|
|
|
|
void LLMessageSystem::nextBlock(const char *blockname)
|
|
{
|
|
nextBlockFast(LLMessageStringTable::getInstance()->getString(blockname));
|
|
}
|
|
|
|
BOOL LLMessageSystem::isSendFull(const char* blockname)
|
|
{
|
|
char* stringTableName = NULL;
|
|
if(NULL != blockname)
|
|
{
|
|
stringTableName = LLMessageStringTable::getInstance()->getString(blockname);
|
|
}
|
|
return isSendFullFast(stringTableName);
|
|
}
|
|
|
|
BOOL LLMessageSystem::isSendFullFast(const char* blockname)
|
|
{
|
|
return mMessageBuilder->isMessageFull(blockname);
|
|
}
|
|
|
|
S32 LLMessageSystem::sendReliable(const LLHost &host)
|
|
{
|
|
return sendReliable(host, LL_DEFAULT_RELIABLE_RETRIES, TRUE, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL);
|
|
}
|
|
|
|
|
|
S32 LLMessageSystem::sendSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data)
|
|
{
|
|
F32Seconds timeout;
|
|
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS,
|
|
F32Seconds(LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()));
|
|
}
|
|
else
|
|
{
|
|
timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX;
|
|
}
|
|
|
|
const S32 retries = 0;
|
|
const BOOL ping_based_timeout = FALSE;
|
|
return sendReliable(host, retries, ping_based_timeout, timeout, callback, callback_data);
|
|
}
|
|
|
|
// send the message via a UDP packet
|
|
S32 LLMessageSystem::sendReliable( const LLHost &host,
|
|
S32 retries,
|
|
BOOL ping_based_timeout,
|
|
F32Seconds timeout,
|
|
void (*callback)(void **,S32),
|
|
void ** callback_data)
|
|
{
|
|
if (ping_based_timeout)
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()));
|
|
}
|
|
else
|
|
{
|
|
timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX));
|
|
}
|
|
}
|
|
|
|
mSendReliable = TRUE;
|
|
mReliablePacketParams.set(host, retries, ping_based_timeout, timeout,
|
|
callback, callback_data,
|
|
const_cast<char*>(mMessageBuilder->getMessageName()));
|
|
return sendMessage(host);
|
|
}
|
|
|
|
void LLMessageSystem::forwardMessage(const LLHost &host)
|
|
{
|
|
copyMessageReceivedToSend();
|
|
sendMessage(host);
|
|
}
|
|
|
|
void LLMessageSystem::forwardReliable(const LLHost &host)
|
|
{
|
|
copyMessageReceivedToSend();
|
|
sendReliable(host);
|
|
}
|
|
|
|
void LLMessageSystem::forwardReliable(const U32 circuit_code)
|
|
{
|
|
copyMessageReceivedToSend();
|
|
sendReliable(findHost(circuit_code));
|
|
}
|
|
|
|
S32 LLMessageSystem::forwardReliable( const LLHost &host,
|
|
S32 retries,
|
|
BOOL ping_based_timeout,
|
|
F32Seconds timeout,
|
|
void (*callback)(void **,S32),
|
|
void ** callback_data)
|
|
{
|
|
copyMessageReceivedToSend();
|
|
return sendReliable(host, retries, ping_based_timeout, timeout, callback, callback_data);
|
|
}
|
|
|
|
S32 LLMessageSystem::flushSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data)
|
|
{
|
|
F32Seconds timeout;
|
|
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS,
|
|
F32Seconds(LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()));
|
|
}
|
|
else
|
|
{
|
|
timeout = LL_SEMIRELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX;
|
|
}
|
|
|
|
S32 send_bytes = 0;
|
|
if (mMessageBuilder->getMessageSize())
|
|
{
|
|
mSendReliable = TRUE;
|
|
// No need for ping-based retry as not going to retry
|
|
mReliablePacketParams.set(host, 0, FALSE, timeout, callback,
|
|
callback_data,
|
|
const_cast<char*>(mMessageBuilder->getMessageName()));
|
|
send_bytes = sendMessage(host);
|
|
clearMessage();
|
|
}
|
|
else
|
|
{
|
|
delete callback_data;
|
|
}
|
|
return send_bytes;
|
|
}
|
|
|
|
S32 LLMessageSystem::flushReliable(const LLHost &host)
|
|
{
|
|
S32 send_bytes = 0;
|
|
if (mMessageBuilder->getMessageSize())
|
|
{
|
|
send_bytes = sendReliable(host);
|
|
}
|
|
clearMessage();
|
|
return send_bytes;
|
|
}
|
|
|
|
LLFnPtrResponder* LLMessageSystem::createResponder(const std::string& name)
|
|
{
|
|
if(mSendReliable)
|
|
{
|
|
return new LLFnPtrResponder(
|
|
mReliablePacketParams.mCallback,
|
|
mReliablePacketParams.mCallbackData,
|
|
name);
|
|
}
|
|
else
|
|
{
|
|
// These messages aren't really unreliable, they just weren't
|
|
// explicitly sent as reliable, so they don't have a callback
|
|
// LL_WARNS("Messaging") << "LLMessageSystem::sendMessage: Sending unreliable "
|
|
// << mMessageBuilder->getMessageName() << " message via HTTP"
|
|
// << LL_ENDL;
|
|
return new LLFnPtrResponder(
|
|
NULL,
|
|
NULL,
|
|
name);
|
|
}
|
|
}
|
|
|
|
// This can be called from signal handlers,
|
|
// so should should not use llinfos.
|
|
S32 LLMessageSystem::sendMessage(const LLHost &host)
|
|
{
|
|
if (! mMessageBuilder->isBuilt())
|
|
{
|
|
mSendSize = mMessageBuilder->buildMessage(
|
|
mSendBuffer,
|
|
MAX_BUFFER_SIZE,
|
|
0);
|
|
}
|
|
|
|
if (!(host.isOk())) // if port and ip are zero, don't bother trying to send the message
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (!cdp)
|
|
{
|
|
// this is a new circuit!
|
|
// are we protected?
|
|
if (mbProtected)
|
|
{
|
|
// yup! don't send packets to an unknown circuit
|
|
if(mVerboseLog)
|
|
{
|
|
LL_INFOS_ONCE("Messaging") << "MSG: -> " << host << "\tUNKNOWN CIRCUIT:\t"
|
|
<< mMessageBuilder->getMessageName() << LL_ENDL;
|
|
}
|
|
LL_WARNS_ONCE("Messaging") << "sendMessage - Trying to send "
|
|
<< mMessageBuilder->getMessageName() << " on unknown circuit "
|
|
<< host << LL_ENDL;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
// nope, open the new circuit
|
|
|
|
cdp = mCircuitInfo.addCircuitData(host, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this is an old circuit. . . is it still alive?
|
|
if (!cdp->isAlive())
|
|
{
|
|
// nope. don't send to dead circuits
|
|
if(mVerboseLog)
|
|
{
|
|
LL_INFOS("Messaging") << "MSG: -> " << host << "\tDEAD CIRCUIT\t\t"
|
|
<< mMessageBuilder->getMessageName() << LL_ENDL;
|
|
}
|
|
LL_WARNS("Messaging") << "sendMessage - Trying to send message "
|
|
<< mMessageBuilder->getMessageName() << " to dead circuit "
|
|
<< host << LL_ENDL;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// NOTE: babbage: LLSD message -> HTTP, template message -> UDP
|
|
if(mMessageBuilder == mLLSDMessageBuilder)
|
|
{
|
|
LLSD message = mLLSDMessageBuilder->getMessage();
|
|
|
|
const LLHTTPSender& sender = LLHTTPSender::getSender(host);
|
|
sender.send(
|
|
host,
|
|
mLLSDMessageBuilder->getMessageName(),
|
|
message,
|
|
createResponder(mLLSDMessageBuilder->getMessageName()));
|
|
|
|
mSendReliable = FALSE;
|
|
mReliablePacketParams.clear();
|
|
return 1;
|
|
}
|
|
|
|
// zero out the flags and packetid. Subtract 1 here so that we do
|
|
// not overwrite the offset if it was set set in buildMessage().
|
|
memset(mSendBuffer, 0, LL_PACKET_ID_SIZE - 1);
|
|
|
|
// add the send id to the front of the message
|
|
cdp->nextPacketOutID();
|
|
|
|
// Packet ID size is always 4
|
|
*((S32*)&mSendBuffer[PHL_PACKET_ID]) = htonl(cdp->getPacketOutID());
|
|
|
|
// Compress the message, which will usually reduce its size.
|
|
U8 * buf_ptr = (U8 *)mSendBuffer;
|
|
U32 buffer_length = mSendSize;
|
|
mMessageBuilder->compressMessage(buf_ptr, buffer_length);
|
|
|
|
if (buffer_length > 1500)
|
|
{
|
|
if((mMessageBuilder->getMessageName() != _PREHASH_ChildAgentUpdate)
|
|
&& (mMessageBuilder->getMessageName() != _PREHASH_SendXferPacket))
|
|
{
|
|
LL_WARNS("Messaging") << "sendMessage - Trying to send "
|
|
<< ((buffer_length > 4000) ? "EXTRA " : "")
|
|
<< "BIG message " << mMessageBuilder->getMessageName() << " - "
|
|
<< buffer_length << LL_ENDL;
|
|
}
|
|
}
|
|
if (mSendReliable)
|
|
{
|
|
buf_ptr[0] |= LL_RELIABLE_FLAG;
|
|
|
|
if (!cdp->getUnackedPacketCount())
|
|
{
|
|
// We are adding the first packed onto the unacked packet list(s)
|
|
// Add this circuit to the list of circuits with unacked packets
|
|
mCircuitInfo.mUnackedCircuitMap[cdp->mHost] = cdp;
|
|
}
|
|
|
|
cdp->addReliablePacket(mSocket,buf_ptr,buffer_length, &mReliablePacketParams);
|
|
mReliablePacketsOut++;
|
|
}
|
|
|
|
// tack packet acks onto the end of this message
|
|
S32 space_left = (MTUBYTES - buffer_length) / sizeof(TPACKETID); // space left for packet ids
|
|
S32 ack_count = (S32)cdp->mAcks.size();
|
|
BOOL is_ack_appended = FALSE;
|
|
std::vector<TPACKETID> acks;
|
|
if((space_left > 0) && (ack_count > 0) &&
|
|
(mMessageBuilder->getMessageName() != _PREHASH_PacketAck))
|
|
{
|
|
buf_ptr[0] |= LL_ACK_FLAG;
|
|
S32 append_ack_count = llmin(space_left, ack_count);
|
|
const S32 MAX_ACKS = 250;
|
|
append_ack_count = llmin(append_ack_count, MAX_ACKS);
|
|
std::vector<TPACKETID>::iterator iter = cdp->mAcks.begin();
|
|
std::vector<TPACKETID>::iterator last = cdp->mAcks.begin();
|
|
last += append_ack_count;
|
|
TPACKETID packet_id;
|
|
for( ; iter != last ; ++iter)
|
|
{
|
|
// grab the next packet id.
|
|
packet_id = (*iter);
|
|
if(mVerboseLog)
|
|
{
|
|
acks.push_back(packet_id);
|
|
}
|
|
|
|
// put it on the end of the buffer
|
|
packet_id = htonl(packet_id);
|
|
|
|
if((S32)(buffer_length + sizeof(TPACKETID)) < MAX_BUFFER_SIZE)
|
|
{
|
|
memcpy(&buf_ptr[buffer_length], &packet_id, sizeof(TPACKETID)); /* Flawfinder: ignore */
|
|
// Do the accounting
|
|
buffer_length += sizeof(TPACKETID);
|
|
}
|
|
else
|
|
{
|
|
// Just reporting error is likely not enough. Need to
|
|
// check how to abort or error out gracefully from
|
|
// this function. XXXTBD
|
|
// *NOTE: Actually hitting this error would indicate
|
|
// the calculation above for space_left, ack_count,
|
|
// append_acout_count is incorrect or that
|
|
// MAX_BUFFER_SIZE has fallen below MTU which is bad
|
|
// and probably programmer error.
|
|
LL_ERRS("Messaging") << "Buffer packing failed due to size.." << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
// clean up the source
|
|
cdp->mAcks.erase(cdp->mAcks.begin(), last);
|
|
|
|
// tack the count in the final byte
|
|
U8 count = (U8)append_ack_count;
|
|
buf_ptr[buffer_length++] = count;
|
|
is_ack_appended = TRUE;
|
|
}
|
|
|
|
BOOL success;
|
|
success = mPacketRing->sendPacket(mSocket, (char *)buf_ptr, buffer_length, host);
|
|
|
|
if (!success)
|
|
{
|
|
mSendPacketFailureCount++;
|
|
}
|
|
else
|
|
{
|
|
// mCircuitInfo already points to the correct circuit data
|
|
cdp->addBytesOut( (S32Bytes)buffer_length );
|
|
}
|
|
|
|
if(mVerboseLog)
|
|
{
|
|
std::ostringstream str;
|
|
str << "MSG: -> " << host;
|
|
std::string buffer;
|
|
buffer = llformat( "\t%6d\t%6d\t%6d ", mSendSize, buffer_length, cdp->getPacketOutID());
|
|
str << buffer
|
|
<< mMessageBuilder->getMessageName()
|
|
<< (mSendReliable ? " reliable " : "");
|
|
if(is_ack_appended)
|
|
{
|
|
str << "\tACKS:\t";
|
|
std::ostream_iterator<TPACKETID> append(str, " ");
|
|
std::copy(acks.begin(), acks.end(), append);
|
|
}
|
|
LL_INFOS("Messaging") << str.str() << LL_ENDL;
|
|
}
|
|
|
|
|
|
mPacketsOut++;
|
|
mBytesOut += buffer_length;
|
|
|
|
mSendReliable = FALSE;
|
|
mReliablePacketParams.clear();
|
|
return buffer_length;
|
|
}
|
|
|
|
void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, BOOL recv_reliable )
|
|
{
|
|
if(mVerboseLog)
|
|
{
|
|
std::ostringstream str;
|
|
str << "MSG: <- " << host;
|
|
std::string buffer;
|
|
buffer = llformat( "\t%6d\t%6d\t%6d ", mMessageReader->getMessageSize(), (mIncomingCompressedSize ? mIncomingCompressedSize: mMessageReader->getMessageSize()), mCurrentRecvPacketID);
|
|
str << buffer
|
|
<< nullToEmpty(mMessageReader->getMessageName())
|
|
<< (recv_reliable ? " reliable" : "")
|
|
<< " REJECTED";
|
|
LL_INFOS("Messaging") << str.str() << LL_ENDL;
|
|
}
|
|
// nope!
|
|
// cout << "Rejecting unexpected message " << mCurrentMessageTemplate->mName << " from " << hex << ip << " , " << dec << port << endl;
|
|
|
|
// Keep track of rejected messages as well
|
|
if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM)
|
|
{
|
|
LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
// TODO: babbage: work out if we need these
|
|
// mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber;
|
|
mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize();
|
|
mMessageCountList[mNumMessageCounts].mInvalid = TRUE;
|
|
mNumMessageCounts++;
|
|
}
|
|
}
|
|
|
|
S32 LLMessageSystem::sendMessage(
|
|
const LLHost &host,
|
|
const char* name,
|
|
const LLSD& message)
|
|
{
|
|
if (!(host.isOk()))
|
|
{
|
|
LL_WARNS("Messaging") << "trying to send message to invalid host" << LL_ENDL;
|
|
return 0;
|
|
}
|
|
|
|
const LLHTTPSender& sender = LLHTTPSender::getSender(host);
|
|
sender.send(host, name, message, createResponder(name));
|
|
return 1;
|
|
}
|
|
|
|
void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host )
|
|
{
|
|
// RequestTrustedCircuit is how we establish trust, so don't spam
|
|
// if it's received on a trusted circuit. JC
|
|
if (strcmp(mMessageReader->getMessageName(), "RequestTrustedCircuit"))
|
|
{
|
|
LL_WARNS("Messaging") << "Received trusted message on untrusted circuit. "
|
|
<< "Will reply with deny. "
|
|
<< "Message: " << nullToEmpty(mMessageReader->getMessageName())
|
|
<< " Host: " << host << LL_ENDL;
|
|
}
|
|
|
|
if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM)
|
|
{
|
|
LL_WARNS("Messaging") << "got more than " << MAX_MESSAGE_COUNT_NUM
|
|
<< " packets without clearing counts"
|
|
<< LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
// TODO: babbage: work out if we need these
|
|
//mMessageCountList[mNumMessageCounts].mMessageNum
|
|
// = mCurrentRMessageTemplate->mMessageNumber;
|
|
mMessageCountList[mNumMessageCounts].mMessageBytes
|
|
= mMessageReader->getMessageSize();
|
|
mMessageCountList[mNumMessageCounts].mInvalid = TRUE;
|
|
mNumMessageCounts++;
|
|
}
|
|
}
|
|
|
|
void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, BOOL recv_reliable, BOOL recv_resent, BOOL recv_acks )
|
|
{
|
|
if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM)
|
|
{
|
|
LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
// TODO: babbage: work out if we need these
|
|
//mMessageCountList[mNumMessageCounts].mMessageNum = mCurrentRMessageTemplate->mMessageNumber;
|
|
mMessageCountList[mNumMessageCounts].mMessageBytes = mMessageReader->getMessageSize();
|
|
mMessageCountList[mNumMessageCounts].mInvalid = FALSE;
|
|
mNumMessageCounts++;
|
|
}
|
|
|
|
if (cdp)
|
|
{
|
|
// update circuit packet ID tracking (missing/out of order packets)
|
|
cdp->checkPacketInID( mCurrentRecvPacketID, recv_resent );
|
|
cdp->addBytesIn( (S32Bytes)mTrueReceiveSize );
|
|
}
|
|
|
|
if(mVerboseLog)
|
|
{
|
|
std::ostringstream str;
|
|
str << "MSG: <- " << host;
|
|
std::string buffer;
|
|
buffer = llformat( "\t%6d\t%6d\t%6d ", mMessageReader->getMessageSize(), (mIncomingCompressedSize ? mIncomingCompressedSize : mMessageReader->getMessageSize()), mCurrentRecvPacketID);
|
|
str << buffer
|
|
<< nullToEmpty(mMessageReader->getMessageName())
|
|
<< (recv_reliable ? " reliable" : "")
|
|
<< (recv_resent ? " resent" : "")
|
|
<< (recv_acks ? " acks" : "");
|
|
LL_INFOS("Messaging") << str.str() << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
void LLMessageSystem::sanityCheck()
|
|
{
|
|
// TODO: babbage: reinstate
|
|
|
|
// if (!mCurrentRMessageData)
|
|
// {
|
|
// LL_ERRS("Messaging") << "mCurrentRMessageData is NULL" << LL_ENDL;
|
|
// }
|
|
|
|
// if (!mCurrentRMessageTemplate)
|
|
// {
|
|
// LL_ERRS("Messaging") << "mCurrentRMessageTemplate is NULL" << LL_ENDL;
|
|
// }
|
|
|
|
// if (!mCurrentRTemplateBlock)
|
|
// {
|
|
// LL_ERRS("Messaging") << "mCurrentRTemplateBlock is NULL" << LL_ENDL;
|
|
// }
|
|
|
|
// if (!mCurrentRDataBlock)
|
|
// {
|
|
// LL_ERRS("Messaging") << "mCurrentRDataBlock is NULL" << LL_ENDL;
|
|
// }
|
|
|
|
// if (!mCurrentSMessageData)
|
|
// {
|
|
// LL_ERRS("Messaging") << "mCurrentSMessageData is NULL" << LL_ENDL;
|
|
// }
|
|
|
|
// if (!mCurrentSMessageTemplate)
|
|
// {
|
|
// LL_ERRS("Messaging") << "mCurrentSMessageTemplate is NULL" << LL_ENDL;
|
|
// }
|
|
|
|
// if (!mCurrentSTemplateBlock)
|
|
// {
|
|
// LL_ERRS("Messaging") << "mCurrentSTemplateBlock is NULL" << LL_ENDL;
|
|
// }
|
|
|
|
// if (!mCurrentSDataBlock)
|
|
// {
|
|
// LL_ERRS("Messaging") << "mCurrentSDataBlock is NULL" << LL_ENDL;
|
|
// }
|
|
}
|
|
|
|
void LLMessageSystem::showCircuitInfo()
|
|
{
|
|
LL_INFOS("Messaging") << mCircuitInfo << LL_ENDL;
|
|
}
|
|
|
|
|
|
void LLMessageSystem::dumpCircuitInfo()
|
|
{
|
|
LL_DEBUGS("Messaging") << mCircuitInfo << LL_ENDL;
|
|
}
|
|
|
|
/* virtual */
|
|
U32 LLMessageSystem::getOurCircuitCode()
|
|
{
|
|
return mOurCircuitCode;
|
|
}
|
|
|
|
void LLMessageSystem::getCircuitInfo(LLSD& info) const
|
|
{
|
|
mCircuitInfo.getInfo(info);
|
|
}
|
|
|
|
// returns whether the given host is on a trusted circuit
|
|
BOOL LLMessageSystem::getCircuitTrust(const LLHost &host)
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
return cdp->getTrusted();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Activate a circuit, and set its trust level (TRUE if trusted,
|
|
// FALSE if not).
|
|
void LLMessageSystem::enableCircuit(const LLHost &host, BOOL trusted)
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (!cdp)
|
|
{
|
|
cdp = mCircuitInfo.addCircuitData(host, 0);
|
|
}
|
|
else
|
|
{
|
|
cdp->setAlive(TRUE);
|
|
}
|
|
cdp->setTrusted(trusted);
|
|
}
|
|
|
|
void LLMessageSystem::disableCircuit(const LLHost &host)
|
|
{
|
|
LL_INFOS("Messaging") << "LLMessageSystem::disableCircuit for " << host << LL_ENDL;
|
|
U32 code = gMessageSystem->findCircuitCode( host );
|
|
|
|
// Don't need to do this, as we're removing the circuit info anyway - djs 01/28/03
|
|
|
|
// don't clean up 0 circuit code entries
|
|
// because many hosts (neighbor sims, etc) can have the 0 circuit
|
|
if (code)
|
|
{
|
|
//if (mCircuitCodes.checkKey(code))
|
|
code_session_map_t::iterator it = mCircuitCodes.find(code);
|
|
if(it != mCircuitCodes.end())
|
|
{
|
|
LL_INFOS("Messaging") << "Circuit " << code << " removed from list" << LL_ENDL;
|
|
//mCircuitCodes.removeData(code);
|
|
mCircuitCodes.erase(it);
|
|
}
|
|
|
|
U64 ip_port = 0;
|
|
std::map<U32, U64>::iterator iter = gMessageSystem->mCircuitCodeToIPPort.find(code);
|
|
if (iter != gMessageSystem->mCircuitCodeToIPPort.end())
|
|
{
|
|
ip_port = iter->second;
|
|
|
|
gMessageSystem->mCircuitCodeToIPPort.erase(iter);
|
|
|
|
U32 old_port = (U32)(ip_port & (U64)0xFFFFFFFF);
|
|
U32 old_ip = (U32)(ip_port >> 32);
|
|
|
|
LL_INFOS("Messaging") << "Host " << LLHost(old_ip, old_port) << " circuit " << code << " removed from lookup table" << LL_ENDL;
|
|
gMessageSystem->mIPPortToCircuitCode.erase(ip_port);
|
|
}
|
|
mCircuitInfo.removeCircuitData(host);
|
|
}
|
|
else
|
|
{
|
|
// Sigh, since we can open circuits which don't have circuit
|
|
// codes, it's possible for this to happen...
|
|
|
|
LL_WARNS("Messaging") << "Couldn't find circuit code for " << host << LL_ENDL;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void LLMessageSystem::setCircuitAllowTimeout(const LLHost &host, BOOL allow)
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
cdp->setAllowTimeout(allow);
|
|
}
|
|
}
|
|
|
|
void LLMessageSystem::setCircuitTimeoutCallback(const LLHost &host, void (*callback_func)(const LLHost & host, void *user_data), void *user_data)
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
cdp->setTimeoutCallback(callback_func, user_data);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL LLMessageSystem::checkCircuitBlocked(const U32 circuit)
|
|
{
|
|
LLHost host = findHost(circuit);
|
|
|
|
if (!host.isOk())
|
|
{
|
|
LL_DEBUGS("Messaging") << "checkCircuitBlocked: Unknown circuit " << circuit << LL_ENDL;
|
|
return TRUE;
|
|
}
|
|
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
return cdp->isBlocked();
|
|
}
|
|
else
|
|
{
|
|
LL_INFOS("Messaging") << "checkCircuitBlocked(circuit): Unknown host - " << host << LL_ENDL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL LLMessageSystem::checkCircuitAlive(const U32 circuit)
|
|
{
|
|
LLHost host = findHost(circuit);
|
|
|
|
if (!host.isOk())
|
|
{
|
|
LL_DEBUGS("Messaging") << "checkCircuitAlive: Unknown circuit " << circuit << LL_ENDL;
|
|
return FALSE;
|
|
}
|
|
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
return cdp->isAlive();
|
|
}
|
|
else
|
|
{
|
|
LL_INFOS("Messaging") << "checkCircuitAlive(circuit): Unknown host - " << host << LL_ENDL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL LLMessageSystem::checkCircuitAlive(const LLHost &host)
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
return cdp->isAlive();
|
|
}
|
|
else
|
|
{
|
|
LL_DEBUGS("Messaging") << "checkCircuitAlive(host): Unknown host - " << host << LL_ENDL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
void LLMessageSystem::setCircuitProtection(BOOL b_protect)
|
|
{
|
|
mbProtected = b_protect;
|
|
}
|
|
|
|
|
|
U32 LLMessageSystem::findCircuitCode(const LLHost &host)
|
|
{
|
|
U64 ip64 = (U64) host.getAddress();
|
|
U64 port64 = (U64) host.getPort();
|
|
U64 ip_port = (ip64 << 32) | port64;
|
|
|
|
return get_if_there(mIPPortToCircuitCode, ip_port, U32(0));
|
|
}
|
|
|
|
LLHost LLMessageSystem::findHost(const U32 circuit_code)
|
|
{
|
|
if (mCircuitCodeToIPPort.count(circuit_code) > 0)
|
|
{
|
|
return LLHost(mCircuitCodeToIPPort[circuit_code]);
|
|
}
|
|
else
|
|
{
|
|
return LLHost::invalid;
|
|
}
|
|
}
|
|
|
|
void LLMessageSystem::setMaxMessageTime(const F32 seconds)
|
|
{
|
|
mMaxMessageTime = F32Seconds(seconds);
|
|
}
|
|
|
|
void LLMessageSystem::setMaxMessageCounts(const S32 num)
|
|
{
|
|
mMaxMessageCounts = num;
|
|
}
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg)
|
|
{
|
|
U32 i;
|
|
if (msg.mbError)
|
|
{
|
|
s << "Message system not correctly initialized";
|
|
}
|
|
else
|
|
{
|
|
s << "Message system open on port " << msg.mPort << " and socket " << msg.mSocket << "\n";
|
|
// s << "Message template file " << msg.mName << " loaded\n";
|
|
|
|
s << "\nHigh frequency messages:\n";
|
|
|
|
for (i = 1; msg.mMessageNumbers[i] && (i < 255); i++)
|
|
{
|
|
s << *(msg.mMessageNumbers[i]);
|
|
}
|
|
|
|
s << "\nMedium frequency messages:\n";
|
|
|
|
for (i = (255 << 8) + 1; msg.mMessageNumbers[i] && (i < (255 << 8) + 255); i++)
|
|
{
|
|
s << *msg.mMessageNumbers[i];
|
|
}
|
|
|
|
s << "\nLow frequency messages:\n";
|
|
|
|
for (i = (0xFFFF0000) + 1; msg.mMessageNumbers[i] && (i < 0xFFFFFFFF); i++)
|
|
{
|
|
s << *msg.mMessageNumbers[i];
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
LLMessageSystem *gMessageSystem = NULL;
|
|
|
|
// update appropriate ping info
|
|
void process_complete_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/)
|
|
{
|
|
U8 ping_id;
|
|
msgsystem->getU8Fast(_PREHASH_PingID, _PREHASH_PingID, ping_id);
|
|
|
|
LLCircuitData *cdp;
|
|
cdp = msgsystem->mCircuitInfo.findCircuit(msgsystem->getSender());
|
|
|
|
// stop the appropriate timer
|
|
if (cdp)
|
|
{
|
|
cdp->pingTimerStop(ping_id);
|
|
}
|
|
}
|
|
|
|
void process_start_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/)
|
|
{
|
|
U8 ping_id;
|
|
msgsystem->getU8Fast(_PREHASH_PingID, _PREHASH_PingID, ping_id);
|
|
|
|
LLCircuitData *cdp;
|
|
cdp = msgsystem->mCircuitInfo.findCircuit(msgsystem->getSender());
|
|
if (cdp)
|
|
{
|
|
// Grab the packet id of the oldest unacked packet
|
|
U32 packet_id;
|
|
msgsystem->getU32Fast(_PREHASH_PingID, _PREHASH_OldestUnacked, packet_id);
|
|
cdp->clearDuplicateList(packet_id);
|
|
}
|
|
|
|
// Send off the response
|
|
msgsystem->newMessageFast(_PREHASH_CompletePingCheck);
|
|
msgsystem->nextBlockFast(_PREHASH_PingID);
|
|
msgsystem->addU8(_PREHASH_PingID, ping_id);
|
|
msgsystem->sendMessage(msgsystem->getSender());
|
|
}
|
|
|
|
|
|
|
|
// Note: this is currently unused. --mark
|
|
void open_circuit(LLMessageSystem *msgsystem, void** /*user_data*/)
|
|
{
|
|
llassert_always(false);
|
|
return;
|
|
|
|
#if 0
|
|
U32 ip;
|
|
U16 port;
|
|
|
|
msgsystem->getIPAddrFast(_PREHASH_CircuitInfo, _PREHASH_IP, ip);
|
|
msgsystem->getIPPortFast(_PREHASH_CircuitInfo, _PREHASH_Port, port);
|
|
|
|
// By default, OpenCircuit's are untrusted
|
|
msgsystem->enableCircuit(LLHost(ip, port), FALSE);
|
|
#endif
|
|
}
|
|
|
|
void close_circuit(LLMessageSystem *msgsystem, void** /*user_data*/)
|
|
{
|
|
msgsystem->disableCircuit(msgsystem->getSender());
|
|
}
|
|
|
|
// static
|
|
/*
|
|
void LLMessageSystem::processAssignCircuitCode(LLMessageSystem* msg, void**)
|
|
{
|
|
// if we already have a circuit code, we can bail
|
|
if(msg->mOurCircuitCode) return;
|
|
LLUUID session_id;
|
|
msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id);
|
|
if(session_id != msg->getMySessionID())
|
|
{
|
|
LL_WARNS("Messaging") << "AssignCircuitCode, bad session id. Expecting "
|
|
<< msg->getMySessionID() << " but got " << session_id
|
|
<< LL_ENDL;
|
|
return;
|
|
}
|
|
U32 code;
|
|
msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, code);
|
|
if (!code)
|
|
{
|
|
LL_ERRS("Messaging") << "Assigning circuit code of zero!" << LL_ENDL;
|
|
}
|
|
|
|
msg->mOurCircuitCode = code;
|
|
LL_INFOS("Messaging") << "Circuit code " << code << " assigned." << LL_ENDL;
|
|
}
|
|
*/
|
|
|
|
// static
|
|
void LLMessageSystem::processAddCircuitCode(LLMessageSystem* msg, void**)
|
|
{
|
|
U32 code;
|
|
msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, code);
|
|
LLUUID session_id;
|
|
msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id);
|
|
(void)msg->addCircuitCode(code, session_id);
|
|
|
|
// Send the ack back
|
|
//msg->newMessageFast(_PREHASH_AckAddCircuitCode);
|
|
//msg->nextBlockFast(_PREHASH_CircuitCode);
|
|
//msg->addU32Fast(_PREHASH_Code, code);
|
|
//msg->sendMessage(msg->getSender());
|
|
}
|
|
|
|
bool LLMessageSystem::addCircuitCode(U32 code, const LLUUID& session_id)
|
|
{
|
|
if(!code)
|
|
{
|
|
LL_WARNS("Messaging") << "addCircuitCode: zero circuit code" << LL_ENDL;
|
|
return false;
|
|
}
|
|
code_session_map_t::iterator it = mCircuitCodes.find(code);
|
|
if(it == mCircuitCodes.end())
|
|
{
|
|
LL_INFOS("Messaging") << "New circuit code " << code << " added" << LL_ENDL;
|
|
//msg->mCircuitCodes[circuit_code] = circuit_code;
|
|
|
|
mCircuitCodes.insert(code_session_map_t::value_type(code, session_id));
|
|
}
|
|
else
|
|
{
|
|
LL_INFOS("Messaging") << "Duplicate circuit code " << code << " added" << LL_ENDL;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//void ack_add_circuit_code(LLMessageSystem *msgsystem, void** /*user_data*/)
|
|
//{
|
|
// By default, we do nothing. This particular message is only handled by the spaceserver
|
|
//}
|
|
|
|
// static
|
|
void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg,
|
|
void** user)
|
|
{
|
|
U32 circuit_code_in;
|
|
msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, circuit_code_in);
|
|
|
|
U32 ip = msg->getSenderIP();
|
|
U32 port = msg->getSenderPort();
|
|
|
|
U64 ip64 = ip;
|
|
U64 port64 = port;
|
|
U64 ip_port_in = (ip64 << 32) | port64;
|
|
|
|
if (circuit_code_in)
|
|
{
|
|
//if (!msg->mCircuitCodes.checkKey(circuit_code_in))
|
|
code_session_map_t::iterator it;
|
|
it = msg->mCircuitCodes.find(circuit_code_in);
|
|
if(it == msg->mCircuitCodes.end())
|
|
{
|
|
// Whoah, abort! We don't know anything about this circuit code.
|
|
LL_WARNS("Messaging") << "UseCircuitCode for " << circuit_code_in
|
|
<< " received without AddCircuitCode message - aborting"
|
|
<< LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
LLUUID id;
|
|
msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_ID, id);
|
|
LLUUID session_id;
|
|
msg->getUUIDFast(_PREHASH_CircuitCode, _PREHASH_SessionID, session_id);
|
|
if(session_id != (*it).second)
|
|
{
|
|
LL_WARNS("Messaging") << "UseCircuitCode unmatched session id. Got "
|
|
<< session_id << " but expected " << (*it).second
|
|
<< LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
// Clean up previous references to this ip/port or circuit
|
|
U64 ip_port_old = get_if_there(msg->mCircuitCodeToIPPort, circuit_code_in, U64(0));
|
|
U32 circuit_code_old = get_if_there(msg->mIPPortToCircuitCode, ip_port_in, U32(0));
|
|
|
|
if (ip_port_old)
|
|
{
|
|
if ((ip_port_old == ip_port_in) && (circuit_code_old == circuit_code_in))
|
|
{
|
|
// Current information is the same as incoming info, ignore
|
|
LL_INFOS("Messaging") << "Got duplicate UseCircuitCode for circuit " << circuit_code_in << " to " << msg->getSender() << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
// Hmm, got a different IP and port for the same circuit code.
|
|
U32 circut_code_old_ip_port = get_if_there(msg->mIPPortToCircuitCode, ip_port_old, U32(0));
|
|
msg->mCircuitCodeToIPPort.erase(circut_code_old_ip_port);
|
|
msg->mIPPortToCircuitCode.erase(ip_port_old);
|
|
U32 old_port = (U32)(ip_port_old & (U64)0xFFFFFFFF);
|
|
U32 old_ip = (U32)(ip_port_old >> 32);
|
|
LL_INFOS("Messaging") << "Removing derelict lookup entry for circuit " << circuit_code_old << " to " << LLHost(old_ip, old_port) << LL_ENDL;
|
|
}
|
|
|
|
if (circuit_code_old)
|
|
{
|
|
LLHost cur_host(ip, port);
|
|
|
|
LL_WARNS("Messaging") << "Disabling existing circuit for " << cur_host << LL_ENDL;
|
|
msg->disableCircuit(cur_host);
|
|
if (circuit_code_old == circuit_code_in)
|
|
{
|
|
LL_WARNS("Messaging") << "Asymmetrical circuit to ip/port lookup!" << LL_ENDL;
|
|
LL_WARNS("Messaging") << "Multiple circuit codes for " << cur_host << " probably!" << LL_ENDL;
|
|
LL_WARNS("Messaging") << "Permanently disabling circuit" << LL_ENDL;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("Messaging") << "Circuit code changed for " << msg->getSender()
|
|
<< " from " << circuit_code_old << " to "
|
|
<< circuit_code_in << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
// Since this comes from the viewer, it's untrusted, but it
|
|
// passed the circuit code and session id check, so we will go
|
|
// ahead and persist the ID associated.
|
|
LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
|
|
BOOL had_circuit_already = cdp ? TRUE : FALSE;
|
|
|
|
msg->enableCircuit(msg->getSender(), FALSE);
|
|
cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
|
|
if(cdp)
|
|
{
|
|
cdp->setRemoteID(id);
|
|
cdp->setRemoteSessionID(session_id);
|
|
}
|
|
|
|
if (!had_circuit_already)
|
|
{
|
|
//
|
|
// HACK HACK HACK HACK HACK!
|
|
//
|
|
// This would NORMALLY happen inside logValidMsg, but at the point that this happens
|
|
// inside logValidMsg, there's no circuit for this message yet. So the awful thing that
|
|
// we do here is do it inside this message handler immediately AFTER the message is
|
|
// handled.
|
|
//
|
|
// We COULD not do this, but then what happens is that some of the circuit bookkeeping
|
|
// gets broken, especially the packets in count. That causes some later packets to flush
|
|
// the RecentlyReceivedReliable list, resulting in an error in which UseCircuitCode
|
|
// doesn't get properly duplicate suppressed. Not a BIG deal, but it's somewhat confusing
|
|
// (and bad from a state point of view). DJS 9/23/04
|
|
//
|
|
cdp->checkPacketInID(gMessageSystem->mCurrentRecvPacketID, FALSE ); // Since this is the first message on the circuit, by definition it's not resent.
|
|
}
|
|
|
|
msg->mIPPortToCircuitCode[ip_port_in] = circuit_code_in;
|
|
msg->mCircuitCodeToIPPort[circuit_code_in] = ip_port_in;
|
|
|
|
LL_INFOS("Messaging") << "Circuit code " << circuit_code_in << " from "
|
|
<< msg->getSender() << " for agent " << id << " in session "
|
|
<< session_id << LL_ENDL;
|
|
|
|
const LLUseCircuitCodeResponder* responder =
|
|
(const LLUseCircuitCodeResponder*) user;
|
|
if(responder)
|
|
{
|
|
responder->complete(msg->getSender(), id);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("Messaging") << "Got zero circuit code in use_circuit_code" << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLMessageSystem::processError(LLMessageSystem* msg, void**)
|
|
{
|
|
S32 error_code = 0;
|
|
msg->getS32("Data", "Code", error_code);
|
|
std::string error_token;
|
|
msg->getString("Data", "Token", error_token);
|
|
|
|
LLUUID error_id;
|
|
msg->getUUID("Data", "ID", error_id);
|
|
std::string error_system;
|
|
msg->getString("Data", "System", error_system);
|
|
|
|
std::string error_message;
|
|
msg->getString("Data", "Message", error_message);
|
|
|
|
LL_WARNS("Messaging") << "Message error from " << msg->getSender() << " - "
|
|
<< error_code << " " << error_token << " " << error_id << " \""
|
|
<< error_system << "\" \"" << error_message << "\"" << LL_ENDL;
|
|
}
|
|
|
|
|
|
static LLHTTPNode& messageRootNode()
|
|
{
|
|
static LLHTTPNode root_node;
|
|
static bool initialized = false;
|
|
if (!initialized) {
|
|
initialized = true;
|
|
LLHTTPRegistrar::buildAllServices(root_node);
|
|
}
|
|
|
|
return root_node;
|
|
}
|
|
|
|
//static
|
|
void LLMessageSystem::dispatch(
|
|
const std::string& msg_name,
|
|
const LLSD& message)
|
|
{
|
|
LLPointer<LLSimpleResponse> responsep = LLSimpleResponse::create();
|
|
dispatch(msg_name, message, responsep);
|
|
}
|
|
|
|
//static
|
|
void LLMessageSystem::dispatch(
|
|
const std::string& msg_name,
|
|
const LLSD& message,
|
|
LLHTTPNode::ResponsePtr responsep)
|
|
{
|
|
if ((gMessageSystem->mMessageTemplates.find
|
|
(LLMessageStringTable::getInstance()->getString(msg_name.c_str())) ==
|
|
gMessageSystem->mMessageTemplates.end()) &&
|
|
!LLMessageConfig::isValidMessage(msg_name))
|
|
{
|
|
LL_WARNS("Messaging") << "Ignoring unknown message " << msg_name << LL_ENDL;
|
|
responsep->notFound("Invalid message name");
|
|
return;
|
|
}
|
|
|
|
std::string path = "/message/" + msg_name;
|
|
LLSD context;
|
|
const LLHTTPNode* handler = messageRootNode().traverse(path, context);
|
|
if (!handler)
|
|
{
|
|
LL_WARNS("Messaging") << "LLMessageService::dispatch > no handler for "
|
|
<< path << LL_ENDL;
|
|
return;
|
|
}
|
|
// enable this for output of message names
|
|
//LL_INFOS("Messaging") << "< \"" << msg_name << "\"" << LL_ENDL;
|
|
//LL_DEBUGS() << "data: " << LLSDNotationStreamer(message) << LL_ENDL;
|
|
|
|
handler->post(responsep, context, message);
|
|
}
|
|
|
|
//static
|
|
void LLMessageSystem::dispatchTemplate(const std::string& msg_name,
|
|
const LLSD& message,
|
|
LLHTTPNode::ResponsePtr responsep)
|
|
{
|
|
LLTemplateMessageDispatcher dispatcher(*(gMessageSystem->mTemplateMessageReader));
|
|
dispatcher.dispatch(msg_name, message, responsep);
|
|
}
|
|
|
|
static void check_for_unrecognized_messages(
|
|
const char* type,
|
|
const LLSD& map,
|
|
LLMessageSystem::message_template_name_map_t& templates)
|
|
{
|
|
for (LLSD::map_const_iterator iter = map.beginMap(),
|
|
end = map.endMap();
|
|
iter != end; ++iter)
|
|
{
|
|
const char* name = LLMessageStringTable::getInstance()->getString(iter->first.c_str());
|
|
|
|
if (templates.find(name) == templates.end())
|
|
{
|
|
LL_INFOS("AppInit") << " " << type
|
|
<< " ban list contains unrecognized message "
|
|
<< name << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLMessageSystem::setMessageBans(
|
|
const LLSD& trusted, const LLSD& untrusted)
|
|
{
|
|
LL_DEBUGS("AppInit") << "LLMessageSystem::setMessageBans:" << LL_ENDL;
|
|
bool any_set = false;
|
|
|
|
for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(),
|
|
end = mMessageTemplates.end();
|
|
iter != end; ++iter)
|
|
{
|
|
LLMessageTemplate* mt = iter->second;
|
|
|
|
std::string name(mt->mName);
|
|
bool ban_from_trusted
|
|
= trusted.has(name) && trusted.get(name).asBoolean();
|
|
bool ban_from_untrusted
|
|
= untrusted.has(name) && untrusted.get(name).asBoolean();
|
|
|
|
mt->mBanFromTrusted = ban_from_trusted;
|
|
mt->mBanFromUntrusted = ban_from_untrusted;
|
|
|
|
if (ban_from_trusted || ban_from_untrusted)
|
|
{
|
|
LL_INFOS("AppInit") << " " << name << " banned from "
|
|
<< (ban_from_trusted ? "TRUSTED " : " ")
|
|
<< (ban_from_untrusted ? "UNTRUSTED " : " ")
|
|
<< LL_ENDL;
|
|
any_set = true;
|
|
}
|
|
}
|
|
|
|
if (!any_set)
|
|
{
|
|
LL_DEBUGS("AppInit") << " no messages banned" << LL_ENDL;
|
|
}
|
|
|
|
check_for_unrecognized_messages("trusted", trusted, mMessageTemplates);
|
|
check_for_unrecognized_messages("untrusted", untrusted, mMessageTemplates);
|
|
}
|
|
|
|
S32 LLMessageSystem::sendError(
|
|
const LLHost& host,
|
|
const LLUUID& agent_id,
|
|
S32 code,
|
|
const std::string& token,
|
|
const LLUUID& id,
|
|
const std::string& system,
|
|
const std::string& message,
|
|
const LLSD& data)
|
|
{
|
|
newMessage("Error");
|
|
nextBlockFast(_PREHASH_AgentData);
|
|
addUUIDFast(_PREHASH_AgentID, agent_id);
|
|
nextBlockFast(_PREHASH_Data);
|
|
addS32("Code", code);
|
|
addString("Token", token);
|
|
addUUID("ID", id);
|
|
addString("System", system);
|
|
std::string temp;
|
|
temp = message;
|
|
if(temp.size() > (size_t)MTUBYTES) temp.resize((size_t)MTUBYTES);
|
|
addString("Message", message);
|
|
LLPointer<LLSDBinaryFormatter> formatter = new LLSDBinaryFormatter;
|
|
std::ostringstream ostr;
|
|
formatter->format(data, ostr);
|
|
temp = ostr.str();
|
|
bool pack_data = true;
|
|
static const std::string ERROR_MESSAGE_NAME("Error");
|
|
if (LLMessageConfig::getMessageFlavor(ERROR_MESSAGE_NAME) ==
|
|
LLMessageConfig::TEMPLATE_FLAVOR)
|
|
{
|
|
S32 msg_size = temp.size() + mMessageBuilder->getMessageSize();
|
|
if(msg_size >= ETHERNET_MTU_BYTES)
|
|
{
|
|
pack_data = false;
|
|
}
|
|
}
|
|
if(pack_data)
|
|
{
|
|
addBinaryData("Data", (void*)temp.c_str(), temp.size());
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("Messaging") << "Data and message were too large -- data removed."
|
|
<< LL_ENDL;
|
|
addBinaryData("Data", NULL, 0);
|
|
}
|
|
return sendReliable(host);
|
|
}
|
|
|
|
void process_packet_ack(LLMessageSystem *msgsystem, void** /*user_data*/)
|
|
{
|
|
TPACKETID packet_id;
|
|
|
|
LLHost host = msgsystem->getSender();
|
|
LLCircuitData *cdp = msgsystem->mCircuitInfo.findCircuit(host);
|
|
if (cdp)
|
|
{
|
|
|
|
S32 ack_count = msgsystem->getNumberOfBlocksFast(_PREHASH_Packets);
|
|
|
|
for (S32 i = 0; i < ack_count; i++)
|
|
{
|
|
msgsystem->getU32Fast(_PREHASH_Packets, _PREHASH_ID, packet_id, i);
|
|
// LL_DEBUGS("Messaging") << "ack recvd' from " << host << " for packet " << (TPACKETID)packet_id << LL_ENDL;
|
|
cdp->ackReliablePacket(packet_id);
|
|
}
|
|
if (!cdp->getUnackedPacketCount())
|
|
{
|
|
// Remove this circuit from the list of circuits with unacked packets
|
|
gMessageSystem->mCircuitInfo.mUnackedCircuitMap.erase(host);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
void process_log_messages(LLMessageSystem* msg, void**)
|
|
{
|
|
U8 log_message;
|
|
|
|
msg->getU8Fast(_PREHASH_Options, _PREHASH_Enable, log_message);
|
|
|
|
if (log_message)
|
|
{
|
|
LL_INFOS("Messaging") << "Starting logging via message" << LL_ENDL;
|
|
msg->startLogging();
|
|
}
|
|
else
|
|
{
|
|
LL_INFOS("Messaging") << "Stopping logging via message" << LL_ENDL;
|
|
msg->stopLogging();
|
|
}
|
|
}*/
|
|
|
|
// Make circuit trusted if the MD5 Digest matches, otherwise
|
|
// notify remote end that they are not trusted.
|
|
void process_create_trusted_circuit(LLMessageSystem *msg, void **)
|
|
{
|
|
// don't try to create trust on machines with no shared secret
|
|
std::string shared_secret = get_shared_secret();
|
|
if(shared_secret.empty()) return;
|
|
|
|
LLUUID remote_id;
|
|
msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_EndPointID, remote_id);
|
|
|
|
LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
|
|
if (!cdp)
|
|
{
|
|
LL_WARNS("Messaging") << "Attempt to create trusted circuit without circuit data: "
|
|
<< msg->getSender() << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
LLUUID local_id;
|
|
local_id = cdp->getLocalEndPointID();
|
|
if (remote_id == local_id)
|
|
{
|
|
// Don't respond to requests that use the same end point ID
|
|
return;
|
|
}
|
|
|
|
U32 untrusted_interface = msg->getUntrustedInterface().getAddress();
|
|
U32 last_interface = msg->getReceivingInterface().getAddress();
|
|
if ( ( untrusted_interface != INVALID_HOST_IP_ADDRESS ) && ( untrusted_interface == last_interface ) )
|
|
{
|
|
if( msg->getBlockUntrustedInterface() )
|
|
{
|
|
LL_WARNS("Messaging") << "Ignoring CreateTrustedCircuit on public interface from host: "
|
|
<< msg->getSender() << LL_ENDL;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("Messaging") << "Processing CreateTrustedCircuit on public interface from host: "
|
|
<< msg->getSender() << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
char their_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
|
|
S32 size = msg->getSizeFast(_PREHASH_DataBlock, _PREHASH_Digest);
|
|
if(size != MD5HEX_STR_BYTES)
|
|
{
|
|
// ignore requests which pack the wrong amount of data.
|
|
return;
|
|
}
|
|
msg->getBinaryDataFast(_PREHASH_DataBlock, _PREHASH_Digest, their_digest, MD5HEX_STR_BYTES);
|
|
their_digest[MD5HEX_STR_SIZE - 1] = '\0';
|
|
if(msg->isMatchingDigestForWindowAndUUIDs(their_digest, TRUST_TIME_WINDOW, local_id, remote_id))
|
|
{
|
|
cdp->setTrusted(TRUE);
|
|
LL_INFOS("Messaging") << "Trusted digest from " << msg->getSender() << LL_ENDL;
|
|
return;
|
|
}
|
|
else if (cdp->getTrusted())
|
|
{
|
|
// The digest is bad, but this circuit is already trusted.
|
|
// This means that this could just be the result of a stale deny sent from a while back, and
|
|
// the message system is being slow. Don't bother sending the deny, as it may continually
|
|
// ping-pong back and forth on a very hosed circuit.
|
|
LL_WARNS("Messaging") << "Ignoring bad digest from known trusted circuit: " << their_digest
|
|
<< " host: " << msg->getSender() << LL_ENDL;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("Messaging") << "Bad digest from known circuit: " << their_digest
|
|
<< " host: " << msg->getSender() << LL_ENDL;
|
|
msg->sendDenyTrustedCircuit(msg->getSender());
|
|
return;
|
|
}
|
|
}
|
|
|
|
void process_deny_trusted_circuit(LLMessageSystem *msg, void **)
|
|
{
|
|
// don't try to create trust on machines with no shared secret
|
|
std::string shared_secret = get_shared_secret();
|
|
if(shared_secret.empty()) return;
|
|
|
|
LLUUID remote_id;
|
|
msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_EndPointID, remote_id);
|
|
|
|
LLCircuitData *cdp = msg->mCircuitInfo.findCircuit(msg->getSender());
|
|
if (!cdp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLUUID local_id;
|
|
local_id = cdp->getLocalEndPointID();
|
|
if (remote_id == local_id)
|
|
{
|
|
// Don't respond to requests that use the same end point ID
|
|
return;
|
|
}
|
|
|
|
U32 untrusted_interface = msg->getUntrustedInterface().getAddress();
|
|
U32 last_interface = msg->getReceivingInterface().getAddress();
|
|
if ( ( untrusted_interface != INVALID_HOST_IP_ADDRESS ) && ( untrusted_interface == last_interface ) )
|
|
{
|
|
if( msg->getBlockUntrustedInterface() )
|
|
{
|
|
LL_WARNS("Messaging") << "Ignoring DenyTrustedCircuit on public interface from host: "
|
|
<< msg->getSender() << LL_ENDL;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("Messaging") << "Processing DenyTrustedCircuit on public interface from host: "
|
|
<< msg->getSender() << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
|
|
// Assume that we require trust to proceed, so resend.
|
|
// This catches the case where a circuit that was trusted
|
|
// times out, and allows us to re-establish it, but does
|
|
// mean that if our shared_secret or clock is wrong, we'll
|
|
// spin.
|
|
// *TODO: probably should keep a count of number of resends
|
|
// per circuit, and stop resending after a while.
|
|
LL_INFOS("Messaging") << "Got DenyTrustedCircuit. Sending CreateTrustedCircuit to "
|
|
<< msg->getSender() << LL_ENDL;
|
|
msg->sendCreateTrustedCircuit(msg->getSender(), local_id, remote_id);
|
|
}
|
|
|
|
|
|
void dump_prehash_files()
|
|
{
|
|
U32 i;
|
|
std::string filename("../../indra/llmessage/message_prehash.h");
|
|
LLFILE* fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */
|
|
if (fp)
|
|
{
|
|
fprintf(
|
|
fp,
|
|
"/**\n"
|
|
" * @file message_prehash.h\n"
|
|
" * @brief header file of externs of prehashed variables plus defines.\n"
|
|
" *\n"
|
|
" * $LicenseInfo:firstyear=2003&license=viewerlgpl$"
|
|
" * $/LicenseInfo$"
|
|
" */\n\n"
|
|
"#ifndef LL_MESSAGE_PREHASH_H\n#define LL_MESSAGE_PREHASH_H\n\n");
|
|
fprintf(
|
|
fp,
|
|
"/**\n"
|
|
" * Generated from message template version number %.3f\n"
|
|
" */\n",
|
|
gMessageSystem->mMessageFileVersionNumber);
|
|
fprintf(fp, "\n\nextern F32 const gPrehashVersionNumber;\n\n");
|
|
for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
|
|
{
|
|
if (!LLMessageStringTable::getInstance()->mEmpty[i] && LLMessageStringTable::getInstance()->mString[i][0] != '.')
|
|
{
|
|
fprintf(fp, "extern char const* const _PREHASH_%s;\n", LLMessageStringTable::getInstance()->mString[i]);
|
|
}
|
|
}
|
|
fprintf(fp, "\n\n#endif\n");
|
|
fclose(fp);
|
|
}
|
|
filename = std::string("../../indra/llmessage/message_prehash.cpp");
|
|
fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */
|
|
if (fp)
|
|
{
|
|
fprintf(
|
|
fp,
|
|
"/**\n"
|
|
" * @file message_prehash.cpp\n"
|
|
" * @brief file of prehashed variables\n"
|
|
" *\n"
|
|
" * $LicenseInfo:firstyear=2003&license=viewerlgpl$"
|
|
" * $/LicenseInfo$"
|
|
" */\n\n"
|
|
"/**\n"
|
|
" * Generated from message template version number %.3f\n"
|
|
" */\n",
|
|
gMessageSystem->mMessageFileVersionNumber);
|
|
fprintf(fp, "#include \"linden_common.h\"\n");
|
|
fprintf(fp, "#include \"message.h\"\n\n");
|
|
fprintf(fp, "\n\nF32 const gPrehashVersionNumber = %.3ff;\n\n", gMessageSystem->mMessageFileVersionNumber);
|
|
for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
|
|
{
|
|
if (!LLMessageStringTable::getInstance()->mEmpty[i] && LLMessageStringTable::getInstance()->mString[i][0] != '.')
|
|
{
|
|
fprintf(fp, "char const* const _PREHASH_%s = LLMessageStringTable::getInstance()->getString(\"%s\");\n", LLMessageStringTable::getInstance()->mString[i], LLMessageStringTable::getInstance()->mString[i]);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
bool start_messaging_system(
|
|
const std::string& template_name,
|
|
U32 port,
|
|
S32 version_major,
|
|
S32 version_minor,
|
|
S32 version_patch,
|
|
bool b_dump_prehash_file,
|
|
const std::string& secret,
|
|
const LLUseCircuitCodeResponder* responder,
|
|
bool failure_is_fatal,
|
|
const F32 circuit_heartbeat_interval,
|
|
const F32 circuit_timeout)
|
|
{
|
|
gMessageSystem = new LLMessageSystem(
|
|
template_name,
|
|
port,
|
|
version_major,
|
|
version_minor,
|
|
version_patch,
|
|
failure_is_fatal,
|
|
circuit_heartbeat_interval,
|
|
circuit_timeout);
|
|
g_shared_secret.assign(secret);
|
|
|
|
if (!gMessageSystem)
|
|
{
|
|
LL_ERRS("AppInit") << "Messaging system initialization failed." << LL_ENDL;
|
|
return FALSE;
|
|
}
|
|
|
|
// bail if system encountered an error.
|
|
if(!gMessageSystem->isOK())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (b_dump_prehash_file)
|
|
{
|
|
dump_prehash_files();
|
|
exit(0);
|
|
}
|
|
else
|
|
{
|
|
if (gMessageSystem->mMessageFileVersionNumber != gPrehashVersionNumber)
|
|
{
|
|
LL_INFOS("AppInit") << "Message template version does not match prehash version number" << LL_ENDL;
|
|
LL_INFOS("AppInit") << "Run simulator with -prehash command line option to rebuild prehash data" << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
LL_DEBUGS("AppInit") << "Message template version matches prehash version number" << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_StartPingCheck, process_start_ping_check, NULL);
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_CompletePingCheck, process_complete_ping_check, NULL);
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_OpenCircuit, open_circuit, NULL);
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_CloseCircuit, close_circuit, NULL);
|
|
|
|
//gMessageSystem->setHandlerFuncFast(_PREHASH_AssignCircuitCode, LLMessageSystem::processAssignCircuitCode);
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_AddCircuitCode, LLMessageSystem::processAddCircuitCode);
|
|
//gMessageSystem->setHandlerFuncFast(_PREHASH_AckAddCircuitCode, ack_add_circuit_code, NULL);
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_UseCircuitCode, LLMessageSystem::processUseCircuitCode, (void**)responder);
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_PacketAck, process_packet_ack, NULL);
|
|
//gMessageSystem->setHandlerFuncFast(_PREHASH_LogMessages, process_log_messages, NULL);
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_CreateTrustedCircuit,
|
|
process_create_trusted_circuit,
|
|
NULL);
|
|
gMessageSystem->setHandlerFuncFast(_PREHASH_DenyTrustedCircuit,
|
|
process_deny_trusted_circuit,
|
|
NULL);
|
|
gMessageSystem->setHandlerFunc("Error", LLMessageSystem::processError);
|
|
|
|
// We can hand this to the null_message_callback since it is a
|
|
// trusted message, so it will automatically be denied if it isn't
|
|
// trusted and ignored if it is -- exactly what we want.
|
|
gMessageSystem->setHandlerFunc(
|
|
"RequestTrustedCircuit",
|
|
null_message_callback,
|
|
NULL);
|
|
|
|
// Initialize the transfer manager
|
|
gTransferManager.init();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void LLMessageSystem::startLogging()
|
|
{
|
|
mVerboseLog = TRUE;
|
|
std::ostringstream str;
|
|
str << "START MESSAGE LOG" << std::endl;
|
|
str << "Legend:" << std::endl;
|
|
str << "\t<-\tincoming message" <<std::endl;
|
|
str << "\t->\toutgoing message" << std::endl;
|
|
str << " <> host size zero id name";
|
|
LL_INFOS("Messaging") << str.str() << LL_ENDL;
|
|
}
|
|
|
|
void LLMessageSystem::stopLogging()
|
|
{
|
|
if(mVerboseLog)
|
|
{
|
|
mVerboseLog = FALSE;
|
|
LL_INFOS("Messaging") << "END MESSAGE LOG" << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
void LLMessageSystem::summarizeLogs(std::ostream& str)
|
|
{
|
|
std::string buffer;
|
|
std::string tmp_str;
|
|
F32 run_time = mMessageSystemTimer.getElapsedTimeF32();
|
|
str << "START MESSAGE LOG SUMMARY" << std::endl;
|
|
buffer = llformat( "Run time: %12.3f seconds", run_time);
|
|
|
|
// Incoming
|
|
str << buffer << std::endl << "Incoming:" << std::endl;
|
|
tmp_str = fmt::to_string(mTotalBytesIn);
|
|
buffer = llformat( "Total bytes received: %20s (%5.2f kbits per second)", tmp_str.c_str(), ((F32)mTotalBytesIn * 0.008f) / run_time);
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(mPacketsIn);
|
|
buffer = llformat( "Total packets received: %20s (%5.2f packets per second)", tmp_str.c_str(), ((F32) mPacketsIn / run_time));
|
|
str << buffer << std::endl;
|
|
buffer = llformat( "Average packet size: %20.0f bytes", (F32)mTotalBytesIn / (F32)mPacketsIn);
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(mReliablePacketsIn);
|
|
buffer = llformat( "Total reliable packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mReliablePacketsIn)/((F32) mPacketsIn + 1));
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(mCompressedPacketsIn);
|
|
buffer = llformat( "Total compressed packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mCompressedPacketsIn)/((F32) mPacketsIn + 1));
|
|
str << buffer << std::endl;
|
|
S64 savings = mUncompressedBytesIn - mCompressedBytesIn;
|
|
tmp_str = fmt::to_string(savings);
|
|
buffer = llformat( "Total compression savings: %20s bytes", tmp_str.c_str());
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(savings/(mCompressedPacketsIn +1));
|
|
buffer = llformat( "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mUncompressedBytesIn)/((F32) mCompressedBytesIn+1));
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(savings/(mPacketsIn+1));
|
|
buffer = llformat( "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mTotalBytesIn + (F32) savings)/((F32) mTotalBytesIn + 1.f));
|
|
|
|
// Outgoing
|
|
str << buffer << std::endl << std::endl << "Outgoing:" << std::endl;
|
|
tmp_str = fmt::to_string(mTotalBytesOut);
|
|
buffer = llformat( "Total bytes sent: %20s (%5.2f kbits per second)", tmp_str.c_str(), ((F32)mTotalBytesOut * 0.008f) / run_time );
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(mPacketsOut);
|
|
buffer = llformat( "Total packets sent: %20s (%5.2f packets per second)", tmp_str.c_str(), ((F32)mPacketsOut / run_time));
|
|
str << buffer << std::endl;
|
|
buffer = llformat( "Average packet size: %20.0f bytes", (F32)mTotalBytesOut / (F32)mPacketsOut);
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(mReliablePacketsOut);
|
|
buffer = llformat( "Total reliable packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mReliablePacketsOut)/((F32) mPacketsOut + 1));
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(mCompressedPacketsOut);
|
|
buffer = llformat( "Total compressed packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mCompressedPacketsOut)/((F32) mPacketsOut + 1));
|
|
str << buffer << std::endl;
|
|
savings = mUncompressedBytesOut - mCompressedBytesOut;
|
|
tmp_str = fmt::to_string(savings);
|
|
buffer = llformat( "Total compression savings: %20s bytes", tmp_str.c_str());
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(savings/(mCompressedPacketsOut +1));
|
|
buffer = llformat( "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mUncompressedBytesOut)/((F32) mCompressedBytesOut+1));
|
|
str << buffer << std::endl;
|
|
tmp_str = fmt::to_string(savings/(mPacketsOut+1));
|
|
buffer = llformat( "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mTotalBytesOut + (F32) savings)/((F32) mTotalBytesOut + 1.f));
|
|
str << buffer << std::endl << std::endl;
|
|
buffer = llformat( "SendPacket failures: %20d", mSendPacketFailureCount);
|
|
str << buffer << std::endl;
|
|
buffer = llformat( "Dropped packets: %20d", mDroppedPackets);
|
|
str << buffer << std::endl;
|
|
buffer = llformat( "Resent packets: %20d", mResentPackets);
|
|
str << buffer << std::endl;
|
|
buffer = llformat( "Failed reliable resends: %20d", mFailedResendPackets);
|
|
str << buffer << std::endl;
|
|
buffer = llformat( "Off-circuit rejected packets: %17d", mOffCircuitPackets);
|
|
str << buffer << std::endl;
|
|
buffer = llformat( "On-circuit invalid packets: %17d", mInvalidOnCircuitPackets);
|
|
str << buffer << std::endl << std::endl;
|
|
|
|
str << "Decoding: " << std::endl;
|
|
buffer = llformat( "%35s%10s%10s%10s%10s", "Message", "Count", "Time", "Max", "Avg");
|
|
str << buffer << std:: endl;
|
|
F32 avg;
|
|
for (message_template_name_map_t::const_iterator iter = mMessageTemplates.begin(),
|
|
end = mMessageTemplates.end();
|
|
iter != end; iter++)
|
|
{
|
|
const LLMessageTemplate* mt = iter->second;
|
|
if(mt->mTotalDecoded > 0)
|
|
{
|
|
avg = mt->mTotalDecodeTime / (F32)mt->mTotalDecoded;
|
|
buffer = llformat( "%35s%10u%10f%10f%10f", mt->mName, mt->mTotalDecoded, mt->mTotalDecodeTime, mt->mMaxDecodeTimePerMsg, avg);
|
|
str << buffer << std::endl;
|
|
}
|
|
}
|
|
str << "END MESSAGE LOG SUMMARY" << std::endl;
|
|
}
|
|
|
|
void end_messaging_system(bool print_summary)
|
|
{
|
|
gTransferManager.cleanup();
|
|
LLTransferTargetVFile::updateQueue(true); // shutdown LLTransferTargetVFile
|
|
if (gMessageSystem)
|
|
{
|
|
gMessageSystem->stopLogging();
|
|
|
|
if (print_summary)
|
|
{
|
|
std::ostringstream str;
|
|
gMessageSystem->summarizeLogs(str);
|
|
LL_INFOS("Messaging") << str.str().c_str() << LL_ENDL;
|
|
}
|
|
|
|
delete gMessageSystem;
|
|
gMessageSystem = NULL;
|
|
}
|
|
}
|
|
|
|
void LLMessageSystem::resetReceiveCounts()
|
|
{
|
|
mNumMessageCounts = 0;
|
|
|
|
for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(),
|
|
end = mMessageTemplates.end();
|
|
iter != end; iter++)
|
|
{
|
|
LLMessageTemplate* mt = iter->second;
|
|
mt->mDecodeTimeThisFrame = 0.f;
|
|
}
|
|
}
|
|
|
|
|
|
void LLMessageSystem::dumpReceiveCounts()
|
|
{
|
|
LLMessageTemplate *mt;
|
|
|
|
for (message_template_name_map_t::iterator iter = mMessageTemplates.begin(),
|
|
end = mMessageTemplates.end();
|
|
iter != end; iter++)
|
|
{
|
|
LLMessageTemplate* mt = iter->second;
|
|
mt->mReceiveCount = 0;
|
|
mt->mReceiveBytes = 0;
|
|
mt->mReceiveInvalid = 0;
|
|
}
|
|
|
|
S32 i;
|
|
for (i = 0; i < mNumMessageCounts; i++)
|
|
{
|
|
mt = get_ptr_in_map(mMessageNumbers,mMessageCountList[i].mMessageNum);
|
|
if (mt)
|
|
{
|
|
mt->mReceiveCount++;
|
|
mt->mReceiveBytes += mMessageCountList[i].mMessageBytes;
|
|
if (mMessageCountList[i].mInvalid)
|
|
{
|
|
mt->mReceiveInvalid++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(mNumMessageCounts > 0)
|
|
{
|
|
LL_DEBUGS("Messaging") << "Dump: " << mNumMessageCounts << " messages processed in " << mReceiveTime << " seconds" << LL_ENDL;
|
|
for (message_template_name_map_t::const_iterator iter = mMessageTemplates.begin(),
|
|
end = mMessageTemplates.end();
|
|
iter != end; iter++)
|
|
{
|
|
const LLMessageTemplate* mt = iter->second;
|
|
if (mt->mReceiveCount > 0)
|
|
{
|
|
LL_INFOS("Messaging") << "Num: " << std::setw(3) << mt->mReceiveCount << " Bytes: " << std::setw(6) << mt->mReceiveBytes
|
|
<< " Invalid: " << std::setw(3) << mt->mReceiveInvalid << " " << mt->mName << " " << ll_round(100 * mt->mDecodeTimeThisFrame / mReceiveTime.value()) << "%" << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL LLMessageSystem::isClear() const
|
|
{
|
|
return mMessageBuilder->isClear();
|
|
}
|
|
|
|
|
|
S32 LLMessageSystem::flush(const LLHost &host)
|
|
{
|
|
if (mMessageBuilder->getMessageSize())
|
|
{
|
|
S32 sentbytes = sendMessage(host);
|
|
clearMessage();
|
|
return sentbytes;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
U32 LLMessageSystem::getListenPort( void ) const
|
|
{
|
|
return mPort;
|
|
}
|
|
|
|
// TODO: babbage: remove this horror!
|
|
S32 LLMessageSystem::zeroCodeAdjustCurrentSendTotal()
|
|
{
|
|
if(mMessageBuilder == mLLSDMessageBuilder)
|
|
{
|
|
// babbage: don't compress LLSD messages, so delta is 0
|
|
return 0;
|
|
}
|
|
|
|
if (! mMessageBuilder->isBuilt())
|
|
{
|
|
mSendSize = mMessageBuilder->buildMessage(
|
|
mSendBuffer,
|
|
MAX_BUFFER_SIZE,
|
|
0);
|
|
}
|
|
// TODO: babbage: remove this horror
|
|
mMessageBuilder->setBuilt(FALSE);
|
|
|
|
S32 count = mSendSize;
|
|
|
|
S32 net_gain = 0;
|
|
U8 num_zeroes = 0;
|
|
|
|
U8 *inptr = (U8 *)mSendBuffer;
|
|
|
|
// skip the packet id field
|
|
|
|
for (U32 ii = 0; ii < LL_PACKET_ID_SIZE; ++ii)
|
|
{
|
|
count--;
|
|
inptr++;
|
|
}
|
|
|
|
// don't actually build, just test
|
|
|
|
// sequential zero bytes are encoded as 0 [U8 count]
|
|
// with 0 0 [count] representing wrap (>256 zeroes)
|
|
|
|
while (count--)
|
|
{
|
|
if (!(*inptr)) // in a zero count
|
|
{
|
|
if (num_zeroes)
|
|
{
|
|
if (++num_zeroes > 254)
|
|
{
|
|
num_zeroes = 0;
|
|
}
|
|
net_gain--; // subseqent zeroes save one
|
|
}
|
|
else
|
|
{
|
|
net_gain++; // starting a zero count adds one
|
|
num_zeroes = 1;
|
|
}
|
|
inptr++;
|
|
}
|
|
else
|
|
{
|
|
if (num_zeroes)
|
|
{
|
|
num_zeroes = 0;
|
|
}
|
|
inptr++;
|
|
}
|
|
}
|
|
if (net_gain < 0)
|
|
{
|
|
return net_gain;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
S32 LLMessageSystem::zeroCodeExpand(U8** data, S32* data_size)
|
|
{
|
|
if ((*data_size ) < LL_MINIMUM_VALID_PACKET_SIZE)
|
|
{
|
|
LL_WARNS("Messaging") << "zeroCodeExpand() called with data_size of " << *data_size
|
|
<< LL_ENDL;
|
|
}
|
|
|
|
mTotalBytesIn += *data_size;
|
|
|
|
// if we're not zero-coded, simply return.
|
|
if (!(*data[0] & LL_ZERO_CODE_FLAG))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
S32 in_size = *data_size;
|
|
mCompressedPacketsIn++;
|
|
mCompressedBytesIn += *data_size;
|
|
|
|
*data[0] &= (~LL_ZERO_CODE_FLAG);
|
|
|
|
S32 count = (*data_size);
|
|
|
|
U8 *inptr = (U8 *)*data;
|
|
U8 *outptr = (U8 *)mEncodedRecvBuffer;
|
|
|
|
// skip the packet id field
|
|
|
|
for (U32 ii = 0; ii < LL_PACKET_ID_SIZE; ++ii)
|
|
{
|
|
count--;
|
|
*outptr++ = *inptr++;
|
|
}
|
|
|
|
// reconstruct encoded packet, keeping track of net size gain
|
|
|
|
// sequential zero bytes are encoded as 0 [U8 count]
|
|
// with 0 0 [count] representing wrap (>256 zeroes)
|
|
|
|
while (count--)
|
|
{
|
|
if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-1]))
|
|
{
|
|
LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 1" << LL_ENDL;
|
|
callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE);
|
|
outptr = mEncodedRecvBuffer;
|
|
break;
|
|
}
|
|
if (!((*outptr++ = *inptr++)))
|
|
{
|
|
while (((count--)) && (!(*inptr)))
|
|
{
|
|
*outptr++ = *inptr++;
|
|
if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-256]))
|
|
{
|
|
LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 2" << LL_ENDL;
|
|
callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE);
|
|
outptr = mEncodedRecvBuffer;
|
|
count = -1;
|
|
break;
|
|
}
|
|
memset(outptr,0,255);
|
|
outptr += 255;
|
|
}
|
|
|
|
if (count < 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
else
|
|
{
|
|
if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-(*inptr)]))
|
|
{
|
|
LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 3" << LL_ENDL;
|
|
callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE);
|
|
outptr = mEncodedRecvBuffer;
|
|
}
|
|
memset(outptr,0,(*inptr) - 1);
|
|
outptr += ((*inptr) - 1);
|
|
inptr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
*data = mEncodedRecvBuffer;
|
|
*data_size = (S32)(outptr - mEncodedRecvBuffer);
|
|
mUncompressedBytesIn += *data_size;
|
|
|
|
return(in_size);
|
|
}
|
|
|
|
|
|
void LLMessageSystem::addTemplate(LLMessageTemplate *templatep)
|
|
{
|
|
if (mMessageTemplates.count(templatep->mName) > 0)
|
|
{
|
|
LL_ERRS("Messaging") << templatep->mName << " already used as a template name!"
|
|
<< LL_ENDL;
|
|
}
|
|
mMessageTemplates[templatep->mName] = templatep;
|
|
mMessageNumbers[templatep->mMessageNumber] = templatep;
|
|
}
|
|
|
|
|
|
void LLMessageSystem::setHandlerFuncFast(const char *name, void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data)
|
|
{
|
|
LLMessageTemplate* msgtemplate = get_ptr_in_map(mMessageTemplates, name);
|
|
if (msgtemplate)
|
|
{
|
|
msgtemplate->setHandlerFunc(handler_func, user_data);
|
|
}
|
|
else
|
|
{
|
|
LL_ERRS("Messaging") << name << " is not a known message name!" << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
bool LLMessageSystem::callHandler(const char *name,
|
|
bool trustedSource, LLMessageSystem* msg)
|
|
{
|
|
name = LLMessageStringTable::getInstance()->getString(name);
|
|
message_template_name_map_t::const_iterator iter;
|
|
iter = mMessageTemplates.find(name);
|
|
if(iter == mMessageTemplates.end())
|
|
{
|
|
LL_WARNS("Messaging") << "LLMessageSystem::callHandler: unknown message "
|
|
<< name << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
const LLMessageTemplate* msg_template = iter->second;
|
|
if (msg_template->isBanned(trustedSource))
|
|
{
|
|
LL_WARNS("Messaging") << "LLMessageSystem::callHandler: banned message "
|
|
<< name
|
|
<< " from "
|
|
<< (trustedSource ? "trusted " : "untrusted ")
|
|
<< "source" << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
return msg_template->callHandlerFunc(msg);
|
|
}
|
|
|
|
|
|
void LLMessageSystem::setExceptionFunc(EMessageException e,
|
|
msg_exception_callback func,
|
|
void* data)
|
|
{
|
|
callbacks_t::iterator it = mExceptionCallbacks.find(e);
|
|
if(it != mExceptionCallbacks.end())
|
|
{
|
|
mExceptionCallbacks.erase(it);
|
|
}
|
|
if(func)
|
|
{
|
|
mExceptionCallbacks.insert(callbacks_t::value_type(e, exception_t(func, data)));
|
|
}
|
|
}
|
|
|
|
BOOL LLMessageSystem::callExceptionFunc(EMessageException exception)
|
|
{
|
|
callbacks_t::iterator it = mExceptionCallbacks.find(exception);
|
|
if(it == mExceptionCallbacks.end())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
exception_t& ex = it->second;
|
|
msg_exception_callback ex_cb = ex.first;
|
|
|
|
if (!ex_cb)
|
|
{
|
|
LL_WARNS("Messaging") << "LLMessageSystem::callExceptionFunc: bad message exception callback." << LL_ENDL;
|
|
return FALSE;
|
|
}
|
|
|
|
(ex_cb)(this, ex.second, exception);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void LLMessageSystem::setTimingFunc(msg_timing_callback func, void* data)
|
|
{
|
|
mTimingCallback = func;
|
|
mTimingCallbackData = data;
|
|
}
|
|
|
|
BOOL LLMessageSystem::isCircuitCodeKnown(U32 code) const
|
|
{
|
|
if(mCircuitCodes.find(code) == mCircuitCodes.end())
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLMessageSystem::isMessageFast(const char *msg)
|
|
{
|
|
return msg == mMessageReader->getMessageName();
|
|
}
|
|
|
|
|
|
char* LLMessageSystem::getMessageName()
|
|
{
|
|
return const_cast<char*>(mMessageReader->getMessageName());
|
|
}
|
|
|
|
const LLUUID& LLMessageSystem::getSenderID() const
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(mLastSender);
|
|
if (cdp)
|
|
{
|
|
return (cdp->mRemoteID);
|
|
}
|
|
|
|
return LLUUID::null;
|
|
}
|
|
|
|
const LLUUID& LLMessageSystem::getSenderSessionID() const
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(mLastSender);
|
|
if (cdp)
|
|
{
|
|
return (cdp->mRemoteSessionID);
|
|
}
|
|
return LLUUID::null;
|
|
}
|
|
|
|
bool LLMessageSystem::generateDigestForNumberAndUUIDs(
|
|
char* digest,
|
|
const U32 number,
|
|
const LLUUID& id1,
|
|
const LLUUID& id2) const
|
|
{
|
|
// *NOTE: This method is needlessly inefficient. Instead of
|
|
// calling LLUUID::asString, it should just call
|
|
// LLUUID::toString().
|
|
|
|
const char *colon = ":";
|
|
char tbuf[16]; /* Flawfinder: ignore */
|
|
LLMD5 d;
|
|
std::string id1string = id1.asString();
|
|
std::string id2string = id2.asString();
|
|
std::string shared_secret = get_shared_secret();
|
|
unsigned char * secret = (unsigned char*)shared_secret.c_str();
|
|
unsigned char * id1str = (unsigned char*)id1string.c_str();
|
|
unsigned char * id2str = (unsigned char*)id2string.c_str();
|
|
|
|
memset(digest, 0, MD5HEX_STR_SIZE);
|
|
|
|
if( secret != NULL)
|
|
{
|
|
d.update(secret, (U32)strlen((char *) secret)); /* Flawfinder: ignore */
|
|
}
|
|
|
|
d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
|
|
|
|
snprintf(tbuf, sizeof(tbuf),"%i", number); /* Flawfinder: ignore */
|
|
d.update((unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */
|
|
|
|
d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
|
|
if( (char*) id1str != NULL)
|
|
{
|
|
d.update(id1str, (U32)strlen((char *) id1str)); /* Flawfinder: ignore */
|
|
}
|
|
d.update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
|
|
|
|
if( (char*) id2str != NULL)
|
|
{
|
|
d.update(id2str, (U32)strlen((char *) id2str)); /* Flawfinder: ignore */
|
|
}
|
|
|
|
d.finalize();
|
|
d.hex_digest(digest);
|
|
digest[MD5HEX_STR_SIZE - 1] = '\0';
|
|
|
|
return true;
|
|
}
|
|
|
|
bool LLMessageSystem::generateDigestForWindowAndUUIDs(char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const
|
|
{
|
|
if(0 == window) return false;
|
|
std::string shared_secret = get_shared_secret();
|
|
if(shared_secret.empty())
|
|
{
|
|
LL_ERRS("Messaging") << "Trying to generate complex digest on a machine without a shared secret!" << LL_ENDL;
|
|
}
|
|
|
|
U32 now = (U32)time(NULL);
|
|
|
|
now /= window;
|
|
|
|
bool result = generateDigestForNumberAndUUIDs(digest, now, id1, id2);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool LLMessageSystem::isMatchingDigestForWindowAndUUIDs(const char* digest, const S32 window, const LLUUID &id1, const LLUUID &id2) const
|
|
{
|
|
if(0 == window) return false;
|
|
|
|
std::string shared_secret = get_shared_secret();
|
|
if(shared_secret.empty())
|
|
{
|
|
LL_ERRS("Messaging") << "Trying to compare complex digests on a machine without a shared secret!" << LL_ENDL;
|
|
}
|
|
|
|
char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
|
|
U32 now = (U32)time(NULL);
|
|
|
|
now /= window;
|
|
|
|
// Check 1 window ago, now, and one window from now to catch edge
|
|
// conditions. Process them as current window, one window ago, and
|
|
// one window in the future to catch the edges.
|
|
const S32 WINDOW_BIN_COUNT = 3;
|
|
U32 window_bin[WINDOW_BIN_COUNT];
|
|
window_bin[0] = now;
|
|
window_bin[1] = now - 1;
|
|
window_bin[2] = now + 1;
|
|
for(S32 i = 0; i < WINDOW_BIN_COUNT; ++i)
|
|
{
|
|
generateDigestForNumberAndUUIDs(our_digest, window_bin[i], id2, id1);
|
|
if(0 == strncmp(digest, our_digest, MD5HEX_STR_BYTES))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool LLMessageSystem::generateDigestForNumber(char* digest, const U32 number) const
|
|
{
|
|
memset(digest, 0, MD5HEX_STR_SIZE);
|
|
|
|
LLMD5 d;
|
|
std::string shared_secret = get_shared_secret();
|
|
d = LLMD5((const unsigned char *)shared_secret.c_str(), number);
|
|
d.hex_digest(digest);
|
|
digest[MD5HEX_STR_SIZE - 1] = '\0';
|
|
|
|
return true;
|
|
}
|
|
|
|
bool LLMessageSystem::generateDigestForWindow(char* digest, const S32 window) const
|
|
{
|
|
if(0 == window) return false;
|
|
|
|
std::string shared_secret = get_shared_secret();
|
|
if(shared_secret.empty())
|
|
{
|
|
LL_ERRS("Messaging") << "Trying to generate simple digest on a machine without a shared secret!" << LL_ENDL;
|
|
}
|
|
|
|
U32 now = (U32)time(NULL);
|
|
|
|
now /= window;
|
|
|
|
bool result = generateDigestForNumber(digest, now);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool LLMessageSystem::isMatchingDigestForWindow(const char* digest, S32 const window) const
|
|
{
|
|
if(0 == window) return false;
|
|
|
|
std::string shared_secret = get_shared_secret();
|
|
if(shared_secret.empty())
|
|
{
|
|
LL_ERRS("Messaging") << "Trying to compare simple digests on a machine without a shared secret!" << LL_ENDL;
|
|
}
|
|
|
|
char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
|
|
U32 now = (S32)time(NULL);
|
|
|
|
now /= window;
|
|
|
|
// Check 1 window ago, now, and one window from now to catch edge
|
|
// conditions. Process them as current window, one window ago, and
|
|
// one window in the future to catch the edges.
|
|
const S32 WINDOW_BIN_COUNT = 3;
|
|
U32 window_bin[WINDOW_BIN_COUNT];
|
|
window_bin[0] = now;
|
|
window_bin[1] = now - 1;
|
|
window_bin[2] = now + 1;
|
|
for(S32 i = 0; i < WINDOW_BIN_COUNT; ++i)
|
|
{
|
|
generateDigestForNumber(our_digest, window_bin[i]);
|
|
if(0 == strncmp(digest, our_digest, MD5HEX_STR_BYTES))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LLMessageSystem::sendCreateTrustedCircuit(const LLHost &host, const LLUUID & id1, const LLUUID & id2)
|
|
{
|
|
std::string shared_secret = get_shared_secret();
|
|
if(shared_secret.empty()) return;
|
|
char digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
|
|
if (id1.isNull())
|
|
{
|
|
LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the local end point ID" << LL_ENDL;
|
|
return;
|
|
}
|
|
if (id2.isNull())
|
|
{
|
|
LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the remote end point ID" << LL_ENDL;
|
|
return;
|
|
}
|
|
generateDigestForWindowAndUUIDs(digest, TRUST_TIME_WINDOW, id1, id2);
|
|
newMessageFast(_PREHASH_CreateTrustedCircuit);
|
|
nextBlockFast(_PREHASH_DataBlock);
|
|
addUUIDFast(_PREHASH_EndPointID, id1);
|
|
addBinaryDataFast(_PREHASH_Digest, digest, MD5HEX_STR_BYTES);
|
|
LL_INFOS("Messaging") << "xmitting digest: " << digest << " Host: " << host << LL_ENDL;
|
|
sendMessage(host);
|
|
}
|
|
|
|
void LLMessageSystem::sendDenyTrustedCircuit(const LLHost &host)
|
|
{
|
|
mDenyTrustedCircuitSet.insert(host);
|
|
}
|
|
|
|
void LLMessageSystem::reallySendDenyTrustedCircuit(const LLHost &host)
|
|
{
|
|
LLCircuitData *cdp = mCircuitInfo.findCircuit(host);
|
|
if (!cdp)
|
|
{
|
|
LL_WARNS("Messaging") << "Not sending DenyTrustedCircuit to host without a circuit." << LL_ENDL;
|
|
return;
|
|
}
|
|
LL_INFOS("Messaging") << "Sending DenyTrustedCircuit to " << host << LL_ENDL;
|
|
newMessageFast(_PREHASH_DenyTrustedCircuit);
|
|
nextBlockFast(_PREHASH_DataBlock);
|
|
addUUIDFast(_PREHASH_EndPointID, cdp->getLocalEndPointID());
|
|
sendMessage(host);
|
|
}
|
|
|
|
void null_message_callback(LLMessageSystem *msg, void **data)
|
|
{
|
|
// Nothing should ever go here, but we use this to register messages
|
|
// that we are expecting to see (and spinning on) at startup.
|
|
return;
|
|
}
|
|
|
|
// Try to establish a bidirectional trust metric by pinging a host until it's
|
|
// up, and then sending auth messages.
|
|
void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_count )
|
|
{
|
|
std::string shared_secret = get_shared_secret();
|
|
if(shared_secret.empty())
|
|
{
|
|
LL_ERRS("Messaging") << "Trying to establish bidirectional trust on a machine without a shared secret!" << LL_ENDL;
|
|
}
|
|
LLTimer timeout;
|
|
|
|
timeout.setTimerExpirySec(20.0);
|
|
setHandlerFuncFast(_PREHASH_StartPingCheck, null_message_callback, NULL);
|
|
setHandlerFuncFast(_PREHASH_CompletePingCheck, null_message_callback,
|
|
NULL);
|
|
|
|
while (! timeout.hasExpired())
|
|
{
|
|
newMessageFast(_PREHASH_StartPingCheck);
|
|
nextBlockFast(_PREHASH_PingID);
|
|
addU8Fast(_PREHASH_PingID, 0);
|
|
addU32Fast(_PREHASH_OldestUnacked, 0);
|
|
sendMessage(host);
|
|
if (checkMessages( frame_count ))
|
|
{
|
|
if (isMessageFast(_PREHASH_CompletePingCheck) &&
|
|
(getSender() == host))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
processAcks();
|
|
ms_sleep(1);
|
|
}
|
|
|
|
// Send a request, a deny, and give the host 2 seconds to complete
|
|
// the trust handshake.
|
|
newMessage("RequestTrustedCircuit");
|
|
sendMessage(host);
|
|
reallySendDenyTrustedCircuit(host);
|
|
setHandlerFuncFast(_PREHASH_StartPingCheck, process_start_ping_check, NULL);
|
|
setHandlerFuncFast(_PREHASH_CompletePingCheck, process_complete_ping_check, NULL);
|
|
|
|
timeout.setTimerExpirySec(2.0);
|
|
LLCircuitData* cdp = NULL;
|
|
while(!timeout.hasExpired())
|
|
{
|
|
cdp = mCircuitInfo.findCircuit(host);
|
|
if(!cdp) break; // no circuit anymore, no point continuing.
|
|
if(cdp->getTrusted()) break; // circuit is trusted.
|
|
checkMessages(frame_count);
|
|
processAcks();
|
|
ms_sleep(1);
|
|
}
|
|
}
|
|
|
|
|
|
void LLMessageSystem::dumpPacketToLog()
|
|
{
|
|
LL_WARNS("Messaging") << "Packet Dump from:" << mPacketRing->getLastSender() << LL_ENDL;
|
|
LL_WARNS("Messaging") << "Packet Size:" << mTrueReceiveSize << LL_ENDL;
|
|
char line_buffer[256]; /* Flawfinder: ignore */
|
|
S32 i;
|
|
S32 cur_line_pos = 0;
|
|
S32 cur_line = 0;
|
|
|
|
for (i = 0; i < mTrueReceiveSize; i++)
|
|
{
|
|
S32 offset = cur_line_pos * 3;
|
|
snprintf(line_buffer + offset, sizeof(line_buffer) - offset,
|
|
"%02x ", mTrueReceiveBuffer[i]); /* Flawfinder: ignore */
|
|
cur_line_pos++;
|
|
if (cur_line_pos >= 16)
|
|
{
|
|
cur_line_pos = 0;
|
|
LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << LL_ENDL;
|
|
cur_line++;
|
|
}
|
|
}
|
|
if (cur_line_pos)
|
|
{
|
|
LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
|
|
//static
|
|
U64Microseconds LLMessageSystem::getMessageTimeUsecs(const BOOL update)
|
|
{
|
|
if (gMessageSystem)
|
|
{
|
|
if (update)
|
|
{
|
|
gMessageSystem->mCurrentMessageTime = totalTime();
|
|
}
|
|
return gMessageSystem->mCurrentMessageTime;
|
|
}
|
|
else
|
|
{
|
|
return totalTime();
|
|
}
|
|
}
|
|
|
|
//static
|
|
F64Seconds LLMessageSystem::getMessageTimeSeconds(const BOOL update)
|
|
{
|
|
if (gMessageSystem)
|
|
{
|
|
if (update)
|
|
{
|
|
gMessageSystem->mCurrentMessageTime = totalTime();
|
|
}
|
|
return gMessageSystem->mCurrentMessageTime;
|
|
}
|
|
else
|
|
{
|
|
return F64Seconds(totalTime());
|
|
}
|
|
}
|
|
|
|
std::string get_shared_secret()
|
|
{
|
|
static const std::string SHARED_SECRET_KEY("shared_secret");
|
|
if(g_shared_secret.empty())
|
|
{
|
|
LLApp* app = LLApp::instance();
|
|
if(app) return app->getOption(SHARED_SECRET_KEY);
|
|
}
|
|
return g_shared_secret;
|
|
}
|
|
|
|
typedef std::map<const char*, LLMessageBuilder*> BuilderMap;
|
|
|
|
void LLMessageSystem::newMessageFast(const char *name)
|
|
{
|
|
LLMessageConfig::Flavor message_flavor =
|
|
LLMessageConfig::getMessageFlavor(name);
|
|
LLMessageConfig::Flavor server_flavor =
|
|
LLMessageConfig::getServerDefaultFlavor();
|
|
|
|
if(message_flavor == LLMessageConfig::TEMPLATE_FLAVOR)
|
|
{
|
|
mMessageBuilder = mTemplateMessageBuilder;
|
|
}
|
|
else if (message_flavor == LLMessageConfig::LLSD_FLAVOR)
|
|
{
|
|
mMessageBuilder = mLLSDMessageBuilder;
|
|
}
|
|
// NO_FLAVOR
|
|
else
|
|
{
|
|
if (server_flavor == LLMessageConfig::LLSD_FLAVOR)
|
|
{
|
|
mMessageBuilder = mLLSDMessageBuilder;
|
|
}
|
|
// TEMPLATE_FLAVOR or NO_FLAVOR
|
|
else
|
|
{
|
|
mMessageBuilder = mTemplateMessageBuilder;
|
|
}
|
|
}
|
|
mSendReliable = FALSE;
|
|
mMessageBuilder->newMessage(name);
|
|
}
|
|
|
|
void LLMessageSystem::newMessage(const char *name)
|
|
{
|
|
newMessageFast(LLMessageStringTable::getInstance()->getString(name));
|
|
}
|
|
|
|
void LLMessageSystem::addBinaryDataFast(const char *varname, const void *data, S32 size)
|
|
{
|
|
mMessageBuilder->addBinaryData(varname, data, size);
|
|
}
|
|
|
|
void LLMessageSystem::addBinaryData(const char *varname, const void *data, S32 size)
|
|
{
|
|
mMessageBuilder->addBinaryData(LLMessageStringTable::getInstance()->getString(varname),data, size);
|
|
}
|
|
|
|
void LLMessageSystem::addS8Fast(const char *varname, S8 v)
|
|
{
|
|
mMessageBuilder->addS8(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addS8(const char *varname, S8 v)
|
|
{
|
|
mMessageBuilder->addS8(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addU8Fast(const char *varname, U8 v)
|
|
{
|
|
mMessageBuilder->addU8(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addU8(const char *varname, U8 v)
|
|
{
|
|
mMessageBuilder->addU8(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addS16Fast(const char *varname, S16 v)
|
|
{
|
|
mMessageBuilder->addS16(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addS16(const char *varname, S16 v)
|
|
{
|
|
mMessageBuilder->addS16(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addU16Fast(const char *varname, U16 v)
|
|
{
|
|
mMessageBuilder->addU16(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addU16(const char *varname, U16 v)
|
|
{
|
|
mMessageBuilder->addU16(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addF32Fast(const char *varname, F32 v)
|
|
{
|
|
mMessageBuilder->addF32(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addF32(const char *varname, F32 v)
|
|
{
|
|
mMessageBuilder->addF32(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addS32Fast(const char *varname, S32 v)
|
|
{
|
|
mMessageBuilder->addS32(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addS32(const char *varname, S32 v)
|
|
{
|
|
mMessageBuilder->addS32(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addU32Fast(const char *varname, U32 v)
|
|
{
|
|
mMessageBuilder->addU32(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addU32(const char *varname, U32 v)
|
|
{
|
|
mMessageBuilder->addU32(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addU64Fast(const char *varname, U64 v)
|
|
{
|
|
mMessageBuilder->addU64(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addU64(const char *varname, U64 v)
|
|
{
|
|
mMessageBuilder->addU64(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addF64Fast(const char *varname, F64 v)
|
|
{
|
|
mMessageBuilder->addF64(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addF64(const char *varname, F64 v)
|
|
{
|
|
mMessageBuilder->addF64(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addIPAddrFast(const char *varname, U32 v)
|
|
{
|
|
mMessageBuilder->addIPAddr(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addIPAddr(const char *varname, U32 v)
|
|
{
|
|
mMessageBuilder->addIPAddr(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addIPPortFast(const char *varname, U16 v)
|
|
{
|
|
mMessageBuilder->addIPPort(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addIPPort(const char *varname, U16 v)
|
|
{
|
|
mMessageBuilder->addIPPort(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addBOOLFast(const char* varname, BOOL v)
|
|
{
|
|
mMessageBuilder->addBOOL(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addBOOL(const char* varname, BOOL v)
|
|
{
|
|
mMessageBuilder->addBOOL(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addStringFast(const char* varname, const char* v)
|
|
{
|
|
mMessageBuilder->addString(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addString(const char* varname, const char* v)
|
|
{
|
|
mMessageBuilder->addString(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addStringFast(const char* varname, const std::string& v)
|
|
{
|
|
mMessageBuilder->addString(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addString(const char* varname, const std::string& v)
|
|
{
|
|
mMessageBuilder->addString(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addVector3Fast(const char *varname, const LLVector3& v)
|
|
{
|
|
mMessageBuilder->addVector3(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addVector3(const char *varname, const LLVector3& v)
|
|
{
|
|
mMessageBuilder->addVector3(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addVector4Fast(const char *varname, const LLVector4& v)
|
|
{
|
|
mMessageBuilder->addVector4(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addVector4(const char *varname, const LLVector4& v)
|
|
{
|
|
mMessageBuilder->addVector4(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addVector3dFast(const char *varname, const LLVector3d& v)
|
|
{
|
|
mMessageBuilder->addVector3d(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addVector3d(const char *varname, const LLVector3d& v)
|
|
{
|
|
mMessageBuilder->addVector3d(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
void LLMessageSystem::addQuatFast(const char *varname, const LLQuaternion& v)
|
|
{
|
|
mMessageBuilder->addQuat(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addQuat(const char *varname, const LLQuaternion& v)
|
|
{
|
|
mMessageBuilder->addQuat(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
|
|
void LLMessageSystem::addUUIDFast(const char *varname, const LLUUID& v)
|
|
{
|
|
mMessageBuilder->addUUID(varname, v);
|
|
}
|
|
|
|
void LLMessageSystem::addUUID(const char *varname, const LLUUID& v)
|
|
{
|
|
mMessageBuilder->addUUID(LLMessageStringTable::getInstance()->getString(varname), v);
|
|
}
|
|
|
|
S32 LLMessageSystem::getCurrentSendTotal() const
|
|
{
|
|
return mMessageBuilder->getMessageSize();
|
|
}
|
|
|
|
void LLMessageSystem::getS8Fast(const char *block, const char *var, S8 &u,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getS8(block, var, u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getS8(const char *block, const char *var, S8 &u,
|
|
S32 blocknum)
|
|
{
|
|
getS8Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getU8Fast(const char *block, const char *var, U8 &u,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getU8(block, var, u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getU8(const char *block, const char *var, U8 &u,
|
|
S32 blocknum)
|
|
{
|
|
getU8Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getBOOLFast(const char *block, const char *var, BOOL &b,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getBOOL(block, var, b, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getBOOL(const char *block, const char *var, BOOL &b,
|
|
S32 blocknum)
|
|
{
|
|
getBOOLFast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), b, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getS16Fast(const char *block, const char *var, S16 &d,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getS16(block, var, d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getS16(const char *block, const char *var, S16 &d,
|
|
S32 blocknum)
|
|
{
|
|
getS16Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getU16Fast(const char *block, const char *var, U16 &d,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getU16(block, var, d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getU16(const char *block, const char *var, U16 &d,
|
|
S32 blocknum)
|
|
{
|
|
getU16Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getS32Fast(const char *block, const char *var, S32 &d,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getS32(block, var, d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getS32(const char *block, const char *var, S32 &d,
|
|
S32 blocknum)
|
|
{
|
|
getS32Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getU32Fast(const char *block, const char *var, U32 &d,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getU32(block, var, d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getU32(const char *block, const char *var, U32 &d,
|
|
S32 blocknum)
|
|
{
|
|
getU32Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getU64Fast(const char *block, const char *var, U64 &d,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getU64(block, var, d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getU64(const char *block, const char *var, U64 &d,
|
|
S32 blocknum)
|
|
{
|
|
|
|
getU64Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getBinaryDataFast(const char *blockname,
|
|
const char *varname,
|
|
void *datap, S32 size,
|
|
S32 blocknum, S32 max_size)
|
|
{
|
|
mMessageReader->getBinaryData(blockname, varname, datap, size, blocknum,
|
|
max_size);
|
|
}
|
|
|
|
void LLMessageSystem::getBinaryData(const char *blockname,
|
|
const char *varname,
|
|
void *datap, S32 size,
|
|
S32 blocknum, S32 max_size)
|
|
{
|
|
getBinaryDataFast(LLMessageStringTable::getInstance()->getString(blockname),
|
|
LLMessageStringTable::getInstance()->getString(varname),
|
|
datap, size, blocknum, max_size);
|
|
}
|
|
|
|
void LLMessageSystem::getF32Fast(const char *block, const char *var, F32 &d,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getF32(block, var, d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getF32(const char *block, const char *var, F32 &d,
|
|
S32 blocknum)
|
|
{
|
|
getF32Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getF64Fast(const char *block, const char *var, F64 &d,
|
|
S32 blocknum)
|
|
{
|
|
mMessageReader->getF64(block, var, d, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getF64(const char *block, const char *var, F64 &d,
|
|
S32 blocknum)
|
|
{
|
|
getF64Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), d, blocknum);
|
|
}
|
|
|
|
|
|
void LLMessageSystem::getVector3Fast(const char *block, const char *var,
|
|
LLVector3 &v, S32 blocknum )
|
|
{
|
|
mMessageReader->getVector3(block, var, v, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getVector3(const char *block, const char *var,
|
|
LLVector3 &v, S32 blocknum )
|
|
{
|
|
getVector3Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), v, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getVector4Fast(const char *block, const char *var,
|
|
LLVector4 &v, S32 blocknum )
|
|
{
|
|
mMessageReader->getVector4(block, var, v, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getVector4(const char *block, const char *var,
|
|
LLVector4 &v, S32 blocknum )
|
|
{
|
|
getVector4Fast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), v, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getVector3dFast(const char *block, const char *var,
|
|
LLVector3d &v, S32 blocknum )
|
|
{
|
|
mMessageReader->getVector3d(block, var, v, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getVector3d(const char *block, const char *var,
|
|
LLVector3d &v, S32 blocknum )
|
|
{
|
|
getVector3dFast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), v, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getQuatFast(const char *block, const char *var,
|
|
LLQuaternion &q, S32 blocknum )
|
|
{
|
|
mMessageReader->getQuat(block, var, q, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getQuat(const char *block, const char *var,
|
|
LLQuaternion &q, S32 blocknum)
|
|
{
|
|
getQuatFast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), q, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getUUIDFast(const char *block, const char *var,
|
|
LLUUID &u, S32 blocknum )
|
|
{
|
|
mMessageReader->getUUID(block, var, u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getUUID(const char *block, const char *var, LLUUID &u,
|
|
S32 blocknum )
|
|
{
|
|
getUUIDFast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getIPAddrFast(const char *block, const char *var,
|
|
U32 &u, S32 blocknum)
|
|
{
|
|
mMessageReader->getIPAddr(block, var, u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getIPAddr(const char *block, const char *var, U32 &u,
|
|
S32 blocknum)
|
|
{
|
|
getIPAddrFast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getIPPortFast(const char *block, const char *var,
|
|
U16 &u, S32 blocknum)
|
|
{
|
|
mMessageReader->getIPPort(block, var, u, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getIPPort(const char *block, const char *var, U16 &u,
|
|
S32 blocknum)
|
|
{
|
|
getIPPortFast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), u,
|
|
blocknum);
|
|
}
|
|
|
|
|
|
void LLMessageSystem::getStringFast(const char *block, const char *var,
|
|
S32 buffer_size, char *s, S32 blocknum)
|
|
{
|
|
if(buffer_size <= 0)
|
|
{
|
|
LL_WARNS("Messaging") << "buffer_size <= 0" << LL_ENDL;
|
|
}
|
|
mMessageReader->getString(block, var, buffer_size, s, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getString(const char *block, const char *var,
|
|
S32 buffer_size, char *s, S32 blocknum )
|
|
{
|
|
getStringFast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), buffer_size, s,
|
|
blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getStringFast(const char *block, const char *var,
|
|
std::string& outstr, S32 blocknum)
|
|
{
|
|
mMessageReader->getString(block, var, outstr, blocknum);
|
|
}
|
|
|
|
void LLMessageSystem::getString(const char *block, const char *var,
|
|
std::string& outstr, S32 blocknum )
|
|
{
|
|
getStringFast(LLMessageStringTable::getInstance()->getString(block),
|
|
LLMessageStringTable::getInstance()->getString(var), outstr,
|
|
blocknum);
|
|
}
|
|
|
|
BOOL LLMessageSystem::has(const char *blockname) const
|
|
{
|
|
return getNumberOfBlocks(blockname) > 0;
|
|
}
|
|
|
|
S32 LLMessageSystem::getNumberOfBlocksFast(const char *blockname) const
|
|
{
|
|
return mMessageReader->getNumberOfBlocks(blockname);
|
|
}
|
|
|
|
S32 LLMessageSystem::getNumberOfBlocks(const char *blockname) const
|
|
{
|
|
return getNumberOfBlocksFast(LLMessageStringTable::getInstance()->getString(blockname));
|
|
}
|
|
|
|
S32 LLMessageSystem::getSizeFast(const char *blockname, const char *varname) const
|
|
{
|
|
return mMessageReader->getSize(blockname, varname);
|
|
}
|
|
|
|
S32 LLMessageSystem::getSize(const char *blockname, const char *varname) const
|
|
{
|
|
return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname),
|
|
LLMessageStringTable::getInstance()->getString(varname));
|
|
}
|
|
|
|
// size in bytes of variable length data
|
|
S32 LLMessageSystem::getSizeFast(const char *blockname, S32 blocknum,
|
|
const char *varname) const
|
|
{
|
|
return mMessageReader->getSize(blockname, blocknum, varname);
|
|
}
|
|
|
|
S32 LLMessageSystem::getSize(const char *blockname, S32 blocknum,
|
|
const char *varname) const
|
|
{
|
|
return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname), blocknum,
|
|
LLMessageStringTable::getInstance()->getString(varname));
|
|
}
|
|
|
|
S32 LLMessageSystem::getReceiveSize() const
|
|
{
|
|
return mMessageReader->getMessageSize();
|
|
}
|
|
|
|
//static
|
|
void LLMessageSystem::setTimeDecodes( BOOL b )
|
|
{
|
|
LLMessageReader::setTimeDecodes(b);
|
|
}
|
|
|
|
//static
|
|
void LLMessageSystem::setTimeDecodesSpamThreshold( F32 seconds )
|
|
{
|
|
LLMessageReader::setTimeDecodesSpamThreshold(seconds);
|
|
}
|
|
|
|
// HACK! babbage: return true if message rxed via either UDP or HTTP
|
|
// TODO: babbage: move gServicePump in to LLMessageSystem?
|
|
bool LLMessageSystem::checkAllMessages(S64 frame_count, LLPumpIO* http_pump)
|
|
{
|
|
if(checkMessages(frame_count))
|
|
{
|
|
return true;
|
|
}
|
|
U32 packetsIn = mPacketsIn;
|
|
http_pump->pump();
|
|
http_pump->callback();
|
|
return (mPacketsIn - packetsIn) > 0;
|
|
}
|
|
|
|
void LLMessageSystem::banUdpMessage(const std::string& name)
|
|
{
|
|
message_template_name_map_t::iterator itt = mMessageTemplates.find(
|
|
LLMessageStringTable::getInstance()->getString(name.c_str())
|
|
);
|
|
if(itt != mMessageTemplates.end())
|
|
{
|
|
itt->second->banUdp();
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS() << "Attempted to ban an unknown message: " << name << "." << LL_ENDL;
|
|
}
|
|
}
|
|
const LLHost& LLMessageSystem::getSender() const
|
|
{
|
|
return mLastSender;
|
|
}
|
|
|
|
LLHTTPRegistration<LLHTTPNodeAdapter<LLTrustedMessageService> >
|
|
gHTTPRegistrationTrustedMessageWildcard("/trusted-message/<message-name>");
|
|
|