diff options
| author | Erik Kundiman <erik@megapahit.org> | 2026-09-01 18:35:23 +0800 |
|---|---|---|
| committer | Erik Kundiman <erik@megapahit.org> | 2026-09-04 21:58:53 +0800 |
| commit | 00bb3bb6f07660bd914d29a1389342bb3060d254 (patch) | |
| tree | 431f574922494d2201718f13085f17bc6bd7fb42 /indra/llmessage | |
| parent | a8636720129952c10cf49ab80da21bf8b340b96c (diff) | |
| parent | 4ef9f8f14b35ed388c294d53767a0dca0e890924 (diff) | |
Merge remote-tracking branch 'secondlife/release/26.4' into 26.4
Diffstat (limited to 'indra/llmessage')
47 files changed, 7412 insertions, 2629 deletions
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 61c54d6313..a2aa9c8914 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -81,7 +81,6 @@ set(llmessage_SOURCE_FILES message_prehash.cpp message_string_table.cpp net.cpp - partsyspacket.cpp patch_code.cpp patch_dct.cpp patch_idct.cpp @@ -169,12 +168,12 @@ set(llmessage_HEADER_FILES llxfer_mem.h llxfer_vfile.h llxorcipher.h + llzerocode.h machine.h mean_collision_data.h message.h message_prehash.h net.h - partsyspacket.h patch_code.h patch_dct.h sound_ids.h @@ -195,10 +194,18 @@ target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) if (CMAKE_CXX_COMPILER_ID MATCHES GNU) set_source_files_properties(llnamevalue.cpp PROPERTIES COMPILE_FLAGS -Wno-stringop-truncation) + set_source_files_properties( + lldatapacker.cpp + message.cpp + PROPERTIES COMPILE_FLAGS -Wno-format-truncation) endif () include(LibraryInstall) +if (USE_PRECOMPILED_HEADERS) + target_precompile_headers(llmessage REUSE_FROM llprecompiled) +endif () + # tests if (LL_TESTS) SET(llmessage_TEST_SOURCE_FILES @@ -220,9 +227,23 @@ if (LL_TESTS) llcommon ) - #LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(io "tests/llpipeutil.cpp" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llbuffer "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(lldatapacker "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llhttpnode "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(lliohttpserver "tests/llpipeutil.cpp" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llsdmessagebuilder "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llsdmessagereader "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llmessageconfig "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llmessagetemplateparser "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llservicebuilder "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(lltemplatemessagebuilder "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llzerocode "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llxorcipher "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(message "" "${test_libs}") endif (LL_TESTS) diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index b6a98575f9..321b2e04b7 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -468,7 +468,7 @@ bool LLAssetStorage::findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetTyp else { LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type - << " found in static cache with bad size " << file.getSize() << ", ignoring" << LL_ENDL; + << " found in static cache with bad size " << size << ", ignoring" << LL_ENDL; } } return false; @@ -1406,7 +1406,7 @@ void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, uuid.toString(uuid_str); filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); - LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (fp) { const S32 buf_size = 65536; diff --git a/indra/llmessage/llavatarname.h b/indra/llmessage/llavatarname.h index eec966d51b..86b2931ed9 100644 --- a/indra/llmessage/llavatarname.h +++ b/indra/llmessage/llavatarname.h @@ -32,7 +32,7 @@ class LLSD; -class LL_COMMON_API LLAvatarName +class LLAvatarName { public: LLAvatarName(); diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp index 2c745f6fe4..cb5a4c1824 100644 --- a/indra/llmessage/llbufferstream.cpp +++ b/indra/llmessage/llbufferstream.cpp @@ -234,17 +234,10 @@ int LLBufferStreamBuf::sync() } // virtual -#if( LL_WINDOWS || __GNUC__ > 2) LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff( LLBufferStreamBuf::off_type off, std::ios::seekdir way, std::ios::openmode which) -#else -streampos LLBufferStreamBuf::seekoff( - streamoff off, - std::ios::seekdir way, - std::ios::openmode which) -#endif { if(!mBuffer || ((way == std::ios::beg) && (off < 0)) @@ -319,12 +312,8 @@ streampos LLBufferStreamBuf::seekoff( } } -#if( LL_WINDOWS || __GNUC__ > 2 ) S32 rv = (S32)(intptr_t)address; return (pos_type)rv; -#else - return (streampos)address; -#endif } diff --git a/indra/llmessage/llbufferstream.h b/indra/llmessage/llbufferstream.h index ac1aa49e81..e0a7d8c642 100644 --- a/indra/llmessage/llbufferstream.h +++ b/indra/llmessage/llbufferstream.h @@ -48,10 +48,8 @@ public: virtual ~LLBufferStreamBuf(); protected: -#if( LL_WINDOWS || __GNUC__ > 2 ) typedef std::streambuf::pos_type pos_type; typedef std::streambuf::off_type off_type; -#endif /* @name streambuf vrtual implementations */ @@ -87,17 +85,10 @@ protected: * or both masked together. * @return Returns the new position or an invalid position on failure. */ -#if( LL_WINDOWS || __GNUC__ > 2) virtual pos_type seekoff( off_type off, std::ios::seekdir way, std::ios::openmode which); -#else - virtual streampos seekoff( - streamoff off, - std::ios::seekdir way, - std::ios::openmode which); -#endif /* * @brief Get s sequence of characters from the input diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index c2b1a2f069..eaee7b0112 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -346,8 +346,7 @@ S32 LLCircuitData::resendUnackedPackets(const F64Seconds now) packetp->mBuffer[0] |= LL_RESENT_FLAG; // tag packet id as being a resend - gMessageSystem->mPacketRing.sendPacket(packetp->mSocket, - (char *)packetp->mBuffer, packetp->mBufferLength, + gMessageSystem->sendPacketToSocket((char *)packetp->mBuffer, packetp->mBufferLength, packetp->mHost); mThrottles.throttleOverflow(TC_RESEND, packetp->mBufferLength * 8.f); @@ -973,7 +972,7 @@ bool LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) { // let's call this one a loss! mPacketsLost++; - gMessageSystem->mDroppedPackets++; + gMessageSystem->mLostPackets++; if(gMessageSystem->mVerboseLog) { std::ostringstream str; diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 647064f607..7e619d45e3 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -40,7 +40,7 @@ #include "workqueue.h" #include "message.h" // for getting the port - +#include "llstl.h" using namespace LLCore; @@ -113,15 +113,17 @@ bool responseToLLSD(HttpResponse * response, bool log, LLSD & out_llsd) { // Convert response to LLSD BufferArray * body(response->getBody()); - if (!body || !body->size()) + size_t body_size(body ? body->size() : 0); + if (!body || !body_size) { return false; } LLCore::BufferArrayStream bas(body); LLSD body_llsd; - S32 parse_status(LLSDSerialize::fromXML(body_llsd, bas, log)); - if (LLSDParser::PARSE_FAILURE == parse_status){ + + if (!LLSDSerialize::deserialize(body_llsd, bas, body_size)) + { return false; } out_llsd = body_llsd; @@ -467,28 +469,6 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: result = parseBody(response, success); -#if 0 - bool parsed = !((response->getBodySize() == 0) || - !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, result)); - - if (!parsed) - { - // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' - LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); - const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL; - - if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType)) - { - std::string thebody = LLCoreHttpUtil::responseToString(response); - LL_WARNS("CoreHTTP") << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] " - << " body: " << thebody << LL_ENDL; - - // Replace the status with a new one indicating the failure. - status = LLCore::HttpStatus(499, "Failed to deserialize LLSD."); - } - } -#endif - if (!success) { #if 1 @@ -1013,7 +993,6 @@ LLSD HttpCoroutineAdapter::getJsonAndSuspend(LLCore::HttpRequest::ptr_t request, return getAndSuspend_(request, url, options, headers, httpHandler); } - LLSD HttpCoroutineAdapter::getAndSuspend_(LLCore::HttpRequest::ptr_t &request, const std::string & url, LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index 3072f78911..17d59092a2 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -484,7 +484,6 @@ public: headers); } - /// Execute a DELETE transaction on the supplied URL and yield execution of /// the coroutine until a result is available. /// diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index e4c7deb1c5..07d11932bc 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -23,6 +23,8 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llexperiencecache.h" #include "llavatarname.h" diff --git a/indra/llmessage/llpacketbuffer.h b/indra/llmessage/llpacketbuffer.h index ac4012d330..a08e6c22e5 100644 --- a/indra/llmessage/llpacketbuffer.h +++ b/indra/llmessage/llpacketbuffer.h @@ -38,6 +38,9 @@ public: LLPacketBuffer(S32 hSocket); // receive a packet ~LLPacketBuffer(); + LLPacketBuffer(const LLPacketBuffer&) = default; + LLPacketBuffer& operator=(const LLPacketBuffer&) = default; + S32 getSize() const { return mSize; } const char *getData() const { return mData; } LLHost getHost() const { return mHost; } @@ -46,11 +49,18 @@ public: void init(S32 hSocket); void init(const char* buffer, S32 data_size, const LLHost& host); + // Whether LLCircuitData::checkPacketInID() has already been run for this + // packet (done at socket-read time, before this packet was sorted into + // the high/low priority inbound queue). + bool getPacketIDChecked() const { return mPacketIDChecked; } + void setPacketIDChecked(bool checked) { mPacketIDChecked = checked; } + protected: char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */ S32 mSize; // size of buffer in bytes LLHost mHost; // source/dest IP and port LLHost mReceivingIF; // source/dest IP and port + bool mPacketIDChecked = false; }; #endif diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index b8284334ea..bade413e61 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -28,344 +28,121 @@ #include "llpacketring.h" -#if LL_WINDOWS - #include <winsock2.h> -#else - #include <sys/socket.h> - #include <netinet/in.h> -#endif - -// linden library includes #include "llerror.h" -#include "lltimer.h" -#include "llproxy.h" -#include "llrand.h" -#include "message.h" -#include "u64.h" -constexpr S16 MAX_BUFFER_RING_SIZE = 1024; +constexpr S16 MAX_BUFFER_RING_SIZE = 8192; + +// DANGER: don't adjust DEFAULT_BUFFER_RING_SIZE unless you know what +// you're doing. Its value affects the "buffer load rate" which is used +// to supply backpressure to an overloaded nework queue. constexpr S16 DEFAULT_BUFFER_RING_SIZE = 256; -LLPacketRing::LLPacketRing () - : mPacketRing(DEFAULT_BUFFER_RING_SIZE, nullptr) +LLPacketRing::LLPacketRing() + : mRing(DEFAULT_BUFFER_RING_SIZE, nullptr) { LLHost invalid_host; - for (size_t i = 0; i < mPacketRing.size(); ++i) + for (size_t i = 0; i < mRing.size(); ++i) { - mPacketRing[i] = new LLPacketBuffer(invalid_host, nullptr, 0); + mRing[i] = new LLPacketBuffer(invalid_host, nullptr, 0); } } -LLPacketRing::~LLPacketRing () +LLPacketRing::~LLPacketRing() { - for (auto packet : mPacketRing) + for (auto* packet : mRing) { delete packet; } - mPacketRing.clear(); + mRing.clear(); mNumBufferedPackets = 0; mNumBufferedBytes = 0; mHeadIndex = 0; } -S32 LLPacketRing::receivePacket (S32 socket, char *datap) -{ - bool drop = computeDrop(); - return (mNumBufferedPackets > 0) ? - receiveOrDropBufferedPacket(datap, drop) : - receiveOrDropPacket(socket, datap, drop); -} - -bool send_packet_helper(int socket, const char * datap, S32 data_size, LLHost host) -{ - if (!LLProxy::isSOCKSProxyEnabled()) - { - return send_packet(socket, datap, data_size, host.getAddress(), host.getPort()); - } - - char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; - - proxywrap_t *socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer)); - socks_header->rsv = 0; - socks_header->addr = host.getAddress(); - socks_header->port = htons(host.getPort()); - socks_header->atype = ADDRESS_IPV4; - socks_header->frag = 0; - - memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, datap, data_size); - - return send_packet( socket, - headered_send_buffer, - data_size + SOCKS_HEADER_SIZE, - LLProxy::getInstance()->getUDPProxy().getAddress(), - LLProxy::getInstance()->getUDPProxy().getPort()); -} - -bool LLPacketRing::sendPacket(int socket, const char * datap, S32 data_size, LLHost host) +void LLPacketRing::pushPacket(const LLPacketBuffer& packet) { - mActualBytesOut += data_size; - return send_packet_helper(socket, datap, data_size, host); -} - -void LLPacketRing::dropPackets (U32 num_to_drop) -{ - mPacketsToDrop += num_to_drop; -} - -void LLPacketRing::setDropPercentage (F32 percent_to_drop) -{ - mDropPercentage = percent_to_drop; -} - -bool LLPacketRing::computeDrop() -{ - bool drop= (mDropPercentage > 0.0f && (ll_frand(100.f) < mDropPercentage)); - if (drop) - { - ++mPacketsToDrop; - } - if (mPacketsToDrop > 0) - { - --mPacketsToDrop; - drop = true; - } - return drop; -} - -S32 LLPacketRing::receiveOrDropPacket(S32 socket, char *datap, bool drop) -{ - S32 packet_size = 0; - - // pull straight from socket - if (LLProxy::isSOCKSProxyEnabled()) + S16 ring_size = (S16)mRing.size(); + if (mNumBufferedPackets >= ring_size && ring_size < MAX_BUFFER_RING_SIZE) { - char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */ - packet_size = receive_packet(socket, buffer); - if (packet_size > 0) - { - mActualBytesIn += packet_size; - } - - if (packet_size > SOCKS_HEADER_SIZE) - { - if (drop) - { - packet_size = 0; - } - else - { - // *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6) - packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size - memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size); - proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer)); - mLastSender.setAddress(header->addr); - mLastSender.setPort(ntohs(header->port)); - mLastReceivingIF = ::get_receiving_interface(); - } - } - else - { - packet_size = 0; - } - } - else - { - packet_size = receive_packet(socket, datap); - if (packet_size > 0) - { - mActualBytesIn += packet_size; - if (drop) - { - packet_size = 0; - } - else - { - mLastSender = ::get_sender(); - mLastReceivingIF = ::get_receiving_interface(); - } - } + expandRing(); + ring_size = (S16)mRing.size(); } - return packet_size; -} -S32 LLPacketRing::receiveOrDropBufferedPacket(char *datap, bool drop) -{ - assert(mNumBufferedPackets > 0); - S32 packet_size = 0; + LLPacketBuffer* slot = mRing[mHeadIndex]; + S32 old_size = slot->getSize(); - S16 ring_size = (S16)(mPacketRing.size()); - S16 packet_index = (mHeadIndex + ring_size - mNumBufferedPackets) % ring_size; - LLPacketBuffer* packet = mPacketRing[packet_index]; - packet_size = packet->getSize(); - mLastSender = packet->getHost(); - mLastReceivingIF = packet->getReceivingInterface(); + *slot = packet; - --mNumBufferedPackets; - mNumBufferedBytes -= packet_size; - if (mNumBufferedPackets == 0) - { - assert(mNumBufferedBytes == 0); - } + mHeadIndex = (mHeadIndex + 1) % ring_size; - if (!drop) + if (mNumBufferedPackets < ring_size) { - if (packet_size > 0) - { - memcpy(datap, packet->getData(), packet_size); - } - else - { - assert(false); - } + ++mNumBufferedPackets; + mNumBufferedBytes += packet.getSize(); } else { - packet_size = 0; + // Ring is at maximum capacity; oldest packet was overwritten. + // This is VERY BAD because we've already ACKed the packet we're loosing + // (if it was "reliable"). + LL_WARNS("PacketRing") << "buffer overflow at " << mNumBufferedPackets << " packets" << LL_ENDL; + mNumBufferedBytes += packet.getSize() - old_size; } - return packet_size; } -S32 LLPacketRing::bufferInboundPacket(S32 socket) +bool LLPacketRing::popPacket(LLPacketBuffer& packet) { - if (mNumBufferedPackets == mPacketRing.size() && mNumBufferedPackets < MAX_BUFFER_RING_SIZE) + if (mNumBufferedPackets <= 0) { - expandRing(); + return false; } - LLPacketBuffer* packet = mPacketRing[mHeadIndex]; - S32 old_packet_size = packet->getSize(); - S32 packet_size = 0; - if (LLProxy::isSOCKSProxyEnabled()) - { - char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */ - packet_size = receive_packet(socket, buffer); - if (packet_size > 0) - { - mActualBytesIn += packet_size; - if (packet_size > SOCKS_HEADER_SIZE) - { - // *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6) + S16 ring_size = (S16)mRing.size(); + S16 tail_index = (mHeadIndex + ring_size - mNumBufferedPackets) % ring_size; - proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer)); - LLHost sender; - sender.setAddress(header->addr); - sender.setPort(ntohs(header->port)); + LLPacketBuffer* slot = mRing[tail_index]; + S32 packet_size = slot->getSize(); - packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size - packet->init(buffer + SOCKS_HEADER_SIZE, packet_size, sender); + packet = *slot; - mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size()); - if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE) - { - ++mNumBufferedPackets; - mNumBufferedBytes += packet_size; - } - else - { - // we overwrote an older packet - mNumBufferedBytes += packet_size - old_packet_size; - } - } - else - { - packet_size = 0; - } - } - } - else - { - packet->init(socket); - packet_size = packet->getSize(); - if (packet_size > 0) - { - mActualBytesIn += packet_size; + --mNumBufferedPackets; + mNumBufferedBytes -= packet_size; - mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size()); - if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE) - { - ++mNumBufferedPackets; - mNumBufferedBytes += packet_size; - } - else - { - // we overwrote an older packet - mNumBufferedBytes += packet_size - old_packet_size; - } - } - } - return packet_size; -} + llassert(mNumBufferedPackets > 0 || mNumBufferedBytes == 0); -S32 LLPacketRing::drainSocket(S32 socket) -{ - // drain into buffer - S32 packet_size = 1; - S32 num_loops = 0; - S32 old_num_packets = mNumBufferedPackets; - while (packet_size > 0) - { - packet_size = bufferInboundPacket(socket); - ++num_loops; - } - S32 num_dropped_packets = (num_loops - 1 + old_num_packets) - mNumBufferedPackets; - if (num_dropped_packets > 0) - { - // It will eventually be accounted by mDroppedPackets - // and mPacketsLost, but track it here for logging purposes. - mNumDroppedPackets += num_dropped_packets; - } - return (S32)(mNumBufferedPackets); + return true; } bool LLPacketRing::expandRing() { - // compute larger size - constexpr S16 BUFFER_RING_EXPANSION = 256; - S16 old_size = (S16)(mPacketRing.size()); + constexpr S16 BUFFER_RING_EXPANSION = 512; + S16 old_size = (S16)mRing.size(); S16 new_size = llmin(old_size + BUFFER_RING_EXPANSION, MAX_BUFFER_RING_SIZE); if (new_size == old_size) { - // mPacketRing is already maxed out return false; } - // make a larger ring and copy packet pointers + // Lay existing entries out linearly in FIFO order starting at index 0. std::vector<LLPacketBuffer*> new_ring(new_size, nullptr); for (S16 i = 0; i < old_size; ++i) { S16 j = (mHeadIndex + i) % old_size; - new_ring[i] = mPacketRing[j]; + new_ring[i] = mRing[j]; } - // allocate new packets for the remainder of new_ring LLHost invalid_host; for (S16 i = old_size; i < new_size; ++i) { new_ring[i] = new LLPacketBuffer(invalid_host, nullptr, 0); } - // swap the rings and reset mHeadIndex - mPacketRing.swap(new_ring); + mRing.swap(new_ring); mHeadIndex = mNumBufferedPackets; return true; } F32 LLPacketRing::getBufferLoadRate() const { - // goes up to MAX_BUFFER_RING_SIZE return (F32)mNumBufferedPackets / (F32)DEFAULT_BUFFER_RING_SIZE; } - -void LLPacketRing::dumpPacketRingStats() -{ - mNumDroppedPacketsTotal += mNumDroppedPackets; - LL_INFOS("Messaging") << "Packet ring stats: " << std::endl - << "Buffered packets: " << mNumBufferedPackets << std::endl - << "Buffered bytes: " << mNumBufferedBytes << std::endl - << "Dropped packets current: " << mNumDroppedPackets << std::endl - << "Dropped packets total: " << mNumDroppedPacketsTotal << std::endl - << "Dropped packets percentage: " << mDropPercentage << "%" << std::endl - << "Actual in bytes: " << mActualBytesIn << std::endl - << "Actual out bytes: " << mActualBytesOut << LL_ENDL; - mNumDroppedPackets = 0; -} diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index 572dcbd271..5315e5a5bd 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -1,7 +1,16 @@ /** * @file llpacketring.h - * @brief definition of LLPacketRing class for implementing a resend, - * drop, or delay in packet transmissions + * @brief LLPacketRing: a simple ring buffer for LLPacketBuffers. + * + * LLPacketRing stores incoming UDP packets that have already been received + * from the network socket. It has no socket or proxy awareness; callers + * push packets in with pushPacket() and retrieve them in FIFO order with + * popPacket(). + * + * The ring starts at DEFAULT_BUFFER_RING_SIZE slots and grows in increments + * of BUFFER_RING_EXPANSION up to MAX_BUFFER_RING_SIZE. Once at the ceiling, + * pushPacket() silently overwrites the oldest queued packet to make room for + * the incoming one. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code @@ -29,9 +38,7 @@ #include <vector> -#include "llhost.h" #include "llpacketbuffer.h" -#include "llthrottle.h" class LLPacketRing @@ -40,71 +47,26 @@ public: LLPacketRing(); ~LLPacketRing(); - // receive one packet: either buffered or from the socket - S32 receivePacket (S32 socket, char *datap); - - // send one packet - bool sendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host); - - // drains packets from socket and returns final mNumBufferedPackets - S32 drainSocket(S32 socket); + // Copy 'packet' onto the tail of the ring, growing the ring or + // overwriting the oldest entry when the ring is at capacity. + void pushPacket(const LLPacketBuffer& packet); - void dropPackets(U32); - void setDropPercentage (F32 percent_to_drop); - - inline LLHost getLastSender() const; - inline LLHost getLastReceivingInterface() const; - - S32 getActualInBytes() const { return mActualBytesIn; } - S32 getActualOutBytes() const { return mActualBytesOut; } - S32 getAndResetActualInBits() { S32 bits = mActualBytesIn * 8; mActualBytesIn = 0; return bits;} - S32 getAndResetActualOutBits() { S32 bits = mActualBytesOut * 8; mActualBytesOut = 0; return bits;} + // Copy the head (oldest) packet into 'packet'. + // Returns true if a packet was available, false if the ring was empty. + bool popPacket(LLPacketBuffer& packet); S32 getNumBufferedPackets() const { return (S32)(mNumBufferedPackets); } - S32 getNumBufferedBytes() const { return mNumBufferedBytes; } - S32 getNumDroppedPackets() const { return mNumDroppedPacketsTotal + mNumDroppedPackets; } - - F32 getBufferLoadRate() const; // from 0 to 4 (0 - empty, 1 - default size is full) - void dumpPacketRingStats(); -protected: - // returns 'true' if we should intentionally drop a packet - bool computeDrop(); - - // returns packet_size of received packet, zero or less if no packet found - S32 receiveOrDropPacket(S32 socket, char *datap, bool drop); - S32 receiveOrDropBufferedPacket(char *datap, bool drop); + S32 getNumBufferedBytes() const { return mNumBufferedBytes; } - // returns packet_size of packet buffered - S32 bufferInboundPacket(S32 socket); + // Ratio of buffered packets to DEFAULT_BUFFER_RING_SIZE (0 = empty, 1 = nominal full). + F32 getBufferLoadRate() const; - // returns 'true' if ring was expanded +private: + // Returns true if the ring was expanded, false if already at the ceiling. bool expandRing(); -protected: - std::vector<LLPacketBuffer*> mPacketRing; - S16 mHeadIndex { 0 }; + std::vector<LLPacketBuffer*> mRing; + S16 mHeadIndex { 0 }; S16 mNumBufferedPackets { 0 }; - S32 mNumDroppedPackets { 0 }; - S32 mNumDroppedPacketsTotal { 0 }; - S32 mNumBufferedBytes { 0 }; - - S32 mActualBytesIn { 0 }; - S32 mActualBytesOut { 0 }; - F32 mDropPercentage { 0.0f }; // % of inbound packets to drop - U32 mPacketsToDrop { 0 }; // drop next inbound n packets - - // These are the sender and receiving_interface for the last packet delivered by receivePacket() - LLHost mLastSender; - LLHost mLastReceivingIF; + S32 mNumBufferedBytes { 0 }; }; - - -inline LLHost LLPacketRing::getLastSender() const -{ - return mLastSender; -} - -inline LLHost LLPacketRing::getLastReceivingInterface() const -{ - return mLastReceivingIF; -} diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp index d4cf95c1e3..b626637862 100644 --- a/indra/llmessage/llpartdata.cpp +++ b/indra/llmessage/llpartdata.cpp @@ -331,7 +331,7 @@ bool LLPartSysData::isNullPS(const S32 block_num) S32 size; // Check size of block - size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock"); + size = gMessageSystem->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_PSBlock); if (!size) { @@ -344,7 +344,7 @@ bool LLPartSysData::isNullPS(const S32 block_num) return true; } - gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); + gMessageSystem->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_PSBlock, ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); LLDataPackerBinaryBuffer dp(ps_data_block, size); if (size > PS_LEGACY_DATA_BLOCK_SIZE) @@ -373,7 +373,7 @@ bool LLPartSysData::unpackBlock(const S32 block_num) U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE]; // Check size of block - S32 size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock"); + S32 size = gMessageSystem->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_PSBlock); if (size > PS_MAX_DATA_BLOCK_SIZE) { @@ -382,7 +382,7 @@ bool LLPartSysData::unpackBlock(const S32 block_num) } // Get from message - gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); + gMessageSystem->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_PSBlock, ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); LLDataPackerBinaryBuffer dp(ps_data_block, size); diff --git a/indra/llmessage/llqueryflags.h b/indra/llmessage/llqueryflags.h index 227d28ba5c..8dfb74aab0 100644 --- a/indra/llmessage/llqueryflags.h +++ b/indra/llmessage/llqueryflags.h @@ -56,8 +56,8 @@ const U32 DFQ_NAME_SORT = 0x1 << 19; const U32 DFQ_LIMIT_BY_PRICE = 0x1 << 20; const U32 DFQ_LIMIT_BY_AREA = 0x1 << 21; -const U32 DFQ_FILTER_MATURE = 0x1 << 22; -const U32 DFQ_PG_PARCELS_ONLY = 0x1 << 23; +const U32 DFQ_FILTER_MATURE = 0x1 << 22; // legacy, will not work with any from DFQ_INC_NEW_VIEWER +const U32 DFQ_PG_PARCELS_ONLY = 0x1 << 23; // legacy, will not work with any from DFQ_INC_NEW_VIEWER const U32 DFQ_INC_PG = 0x1 << 24; // Flags appear in 1.23 viewer or later const U32 DFQ_INC_MATURE = 0x1 << 25; diff --git a/indra/llmessage/llstoredmessage.cpp b/indra/llmessage/llstoredmessage.cpp index 39696ea235..ff8afde657 100644 --- a/indra/llmessage/llstoredmessage.cpp +++ b/indra/llmessage/llstoredmessage.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llstoredmessage.h" LLStoredMessage::LLStoredMessage(const std::string& name, const LLSD& message) : mMessage(message), mName(name) diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index 883c84c6a5..2b39b11ad9 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -33,6 +33,7 @@ #endif #include "llmessagetemplate.h" +#include "llzerocode.h" #include "llmath.h" #include "llquaternion.h" #include "u64.h" @@ -496,93 +497,29 @@ void LLTemplateMessageBuilder::addUUID(const char *varname, const LLUUID& uuid) addData(varname, uuid.mData, MVT_LLUUID, sizeof(uuid.mData)); } -static S32 zero_code(U8 **data, U32 *data_size) +void LLTemplateMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length) { - // Encoded send buffer needs to be slightly larger since the zero - // coding can potentially increase the size of the send data. - static U8 encodedSendBuffer[2 * MAX_BUFFER_SIZE]; - - S32 count = *data_size; - - S32 net_gain = 0; - U8 num_zeroes = 0; - - U8 *inptr = (U8 *)*data; - U8 *outptr = (U8 *)encodedSendBuffer; - -// skip the packet id field - - for (U32 ii = 0; ii < LL_PACKET_ID_SIZE ; ++ii) - { - count--; - *outptr++ = *inptr++; - } - -// build encoded packet, keeping track of net size gain - -// sequential zero bytes are encoded as 0 [U8 count] -// with 0 0 [count] representing wrap (>256 zeroes) - - while (count--) + if(ME_ZEROCODED != mCurrentSMessageTemplate->getEncoding()) { - if (!(*inptr)) // in a zero count - { - if (num_zeroes) - { - if (++num_zeroes > 254) - { - *outptr++ = num_zeroes; - num_zeroes = 0; - } - net_gain--; // subseqent zeroes save one - } - else - { - *outptr++ = 0; - net_gain++; // starting a zero count adds one - num_zeroes = 1; - } - inptr++; - } - else - { - if (num_zeroes) - { - *outptr++ = num_zeroes; - num_zeroes = 0; - } - *outptr++ = *inptr++; - } + return; } - if (num_zeroes) - { - *outptr++ = num_zeroes; - } + // Encoded send buffer needs to be slightly larger since the zero + // coding can potentially increase the size of the send data. + static U8 encodedSendBuffer[2 * MAX_BUFFER_SIZE]; - if (net_gain < 0) + S32 encoded_size = LLZeroCode::encode(buf_ptr, buffer_length, + encodedSendBuffer, sizeof(encodedSendBuffer), + LL_PACKET_ID_SIZE); + if (encoded_size >= 0) { // TODO: babbage: reinstate stat collecting... //mCompressedPacketsOut++; - //mUncompressedBytesOut += *data_size; - - *data = encodedSendBuffer; - *data_size += net_gain; - encodedSendBuffer[0] |= LL_ZERO_CODE_FLAG; // set the head bit to indicate zero coding - - //mCompressedBytesOut += *data_size; - - } - //mTotalBytesOut += *data_size; + //mUncompressedBytesOut += buffer_length; + //mCompressedBytesOut += encoded_size; - return(net_gain); -} - -void LLTemplateMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length) -{ - if(ME_ZEROCODED == mCurrentSMessageTemplate->getEncoding()) - { - zero_code(&buf_ptr, &buffer_length); + buf_ptr = encodedSendBuffer; + buffer_length = (U32)encoded_size; } } diff --git a/indra/llmessage/lltemplatemessagedispatcher.cpp b/indra/llmessage/lltemplatemessagedispatcher.cpp index edbeb4acc1..02e5b56c8d 100644 --- a/indra/llmessage/lltemplatemessagedispatcher.cpp +++ b/indra/llmessage/lltemplatemessagedispatcher.cpp @@ -24,6 +24,7 @@ * $/LicenseInfo$ */ +#include "linden_common.h" #include "lltemplatemessagedispatcher.h" diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index f12e4dc2d5..0c1531cecb 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -122,6 +122,9 @@ void LLTemplateMessageReader::getData(const char *blockname, const char *varname { switch( vardata_size ) { + case 0: + // This is here to prevent a memcpy from a null value which is undefined behavior. + break; case 1: *((U8*)datap) = *((U8*)vardata.getData()); break; diff --git a/indra/llmessage/lltransfersourcefile.cpp b/indra/llmessage/lltransfersourcefile.cpp index 77a6c466c7..d2d264c520 100644 --- a/indra/llmessage/lltransfersourcefile.cpp +++ b/indra/llmessage/lltransfersourcefile.cpp @@ -62,7 +62,7 @@ void LLTransferSourceFile::initTransfer() return; } // Look for the file. - mFP = LLFile::fopen(mParams.getFilename(), "rb"); /* Flawfinder: ignore */ + mFP = LLFile::fopen(mParams.getFilename(), LLFILE_MODE("rb")); /* Flawfinder: ignore */ if (!mFP) { sendTransferStatus(LLTS_ERROR); diff --git a/indra/llmessage/lltransfertargetfile.cpp b/indra/llmessage/lltransfertargetfile.cpp index 6d8b69fa6f..05dba219ed 100644 --- a/indra/llmessage/lltransfertargetfile.cpp +++ b/indra/llmessage/lltransfertargetfile.cpp @@ -75,7 +75,7 @@ LLTSCode LLTransferTargetFile::dataCallback(const S32 packet_id, U8 *in_datap, c if (!mFP) { - mFP = LLFile::fopen(mParams.mFilename, "wb"); /* Flawfinder: ignore */ + mFP = LLFile::fopen(mParams.mFilename, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (!mFP) { diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index 71b910297b..5f27cc4827 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -161,7 +161,7 @@ S32 LLXfer_File::initializeRequest(U64 xfer_id, S32 LLXfer_File::startDownload() { S32 retval = 0; // presume success - mFp = LLFile::fopen(mTempFilename,"w+b"); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mTempFilename,LLFILE_MODE("w+b")); /* Flawfinder : ignore */ if (mFp) { fclose(mFp); @@ -209,7 +209,7 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) mBufferStartOffset = 0; // We leave the file open, assuming we'll start reading and sending soon - mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mLocalFilename, LLFILE_MODE("rb")); /* Flawfinder : ignore */ if (mFp) { fseek(mFp,0,SEEK_END); @@ -252,7 +252,7 @@ S32 LLXfer_File::reopenFileHandle() if (mFp == NULL) { - mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mLocalFilename, LLFILE_MODE("rb")); /* Flawfinder : ignore */ if (mFp == NULL) { LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL; @@ -313,7 +313,7 @@ S32 LLXfer_File::flush() { LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL; } - mFp = LLFile::fopen(mTempFilename,"a+b"); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mTempFilename, LLFILE_MODE("a+b")); /* Flawfinder : ignore */ if (mFp) { @@ -381,11 +381,11 @@ S32 LLXfer_File::processEOF() } else { - //LLFILE* fp = LLFile::fopen(mTempFilename, "r"); + //LLFILE* fp = LLFile::fopen(mTempFilename, LLFILE_MODE("r")); //LL_WARNS() << "File " << mTempFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); - //fp = LLFile::fopen(mLocalFilename, "r"); + //fp = LLFile::fopen(mLocalFilename, LLFILE_MODE("r")); //LL_WARNS() << "File " << mLocalFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); @@ -452,8 +452,8 @@ U32 LLXfer_File::getXferTypeTag() S32 copy_file(const std::string& from, const std::string& to) { S32 rv = 0; - LLFILE* in = LLFile::fopen(from, "rb"); /*Flawfinder: ignore*/ - LLFILE* out = LLFile::fopen(to, "wb"); /*Flawfinder: ignore*/ + LLFILE* in = LLFile::fopen(from, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ + LLFILE* out = LLFile::fopen(to, LLFILE_MODE("wb")); /*Flawfinder: ignore*/ if(in && out) { S32 read = 0; diff --git a/indra/llmessage/llzerocode.h b/indra/llmessage/llzerocode.h new file mode 100644 index 0000000000..7246c9d946 --- /dev/null +++ b/indra/llmessage/llzerocode.h @@ -0,0 +1,211 @@ +/** + * @file llzerocode.h + * @brief Zero-code run-length compression used by the LLMessageSystem UDP protocol. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLZEROCODE_H +#define LL_LLZEROCODE_H + +#include <cstring> + +#include "stdtypes.h" + +// Zero-coding compresses runs of zero bytes in a packet body, leaving the +// first header_size bytes of the buffer (the packet header - flags, +// sequence number, offset, etc.) untouched aside from the flag bit below. +// +// Runs of zero bytes in the body are replaced by a two-byte token: +// 0x00 N - represents N zero bytes, for N in 1..254 +// 0x00 0x00 N - represents (255 + N) zero bytes (wrap/overflow case, +// produced by decode()'s wire format but never emitted +// by encode(), which instead starts a fresh 0x00 token +// every 255 zero bytes) +namespace LLZeroCode +{ + // High bit of the first header byte: set by encode() and cleared by + // decode() to indicate whether the body that follows is zero-coded. + const U8 FLAG = 0x80; + + // Zero-codes src (src_size bytes, the first header_size of which are the + // packet header and are copied verbatim) into dst. + // + // dst_capacity must be at least 2 * src_size: a pathological body of + // isolated zero bytes can nearly double in size when encoded. + // + // Returns the encoded size (with FLAG set in dst[0]) if doing so made the + // packet smaller. Returns -1 if compression would not help (or the + // arguments are invalid), in which case dst is left untouched and the + // caller should keep using the original, uncompressed buffer. + inline S32 encode(const U8* src, U32 src_size, U8* dst, U32 dst_capacity, U32 header_size) + { + if (src_size < header_size || dst_capacity < 2 * src_size) + { + return -1; + } + + S32 count = (S32)(src_size - header_size); + S32 net_gain = 0; + U8 num_zeroes = 0; + + const U8* inptr = src; + U8* outptr = dst; + + // copy the header verbatim + for (U32 ii = 0; ii < header_size; ++ii) + { + *outptr++ = *inptr++; + } + + // sequential zero bytes are encoded as 0 [U8 count]; a run longer + // than 254 bytes is split into consecutive 0 [U8 count] tokens. + while (count--) + { + if (!(*inptr)) // in a zero count + { + if (num_zeroes) + { + if (++num_zeroes > 254) + { + *outptr++ = num_zeroes; + num_zeroes = 0; + } + net_gain--; // subsequent zeroes save one + } + else + { + *outptr++ = 0; + net_gain++; // starting a zero count adds one + num_zeroes = 1; + } + inptr++; + } + else + { + if (num_zeroes) + { + *outptr++ = num_zeroes; + num_zeroes = 0; + } + *outptr++ = *inptr++; + } + } + + if (num_zeroes) + { + *outptr++ = num_zeroes; + } + + if (net_gain >= 0) + { + // compression did not shrink the packet; caller should keep the original + return -1; + } + + dst[0] |= FLAG; + return (S32)src_size + net_gain; + } + + // Expands a zero-coded src (src_size bytes) into dst. + // + // If FLAG is not set in src[0], the body is not zero-coded: no work is + // done and the function returns 0. + // + // On success, returns the number of bytes written to dst (always includes + // the header_size header bytes, copied verbatim except for FLAG being + // cleared from dst[0]). + // + // If expansion would write past dst_capacity - which only a malformed or + // malicious packet should cause - decoding is aborted, *overflow is set + // true, and the returned size reflects however much (if anything) was + // salvaged; the caller should treat the packet as invalid. + inline U32 decode(const U8* src, U32 src_size, U8* dst, U32 dst_capacity, U32 header_size, bool& overflow) + { + overflow = false; + + if (src_size < header_size || !(src[0] & FLAG)) + { + return 0; + } + + S32 count = (S32)(src_size - header_size); + + const U8* inptr = src; + U8* outptr = dst; + + for (U32 ii = 0; ii < header_size; ++ii) + { + *outptr++ = *inptr++; + } + dst[0] &= ~FLAG; + + // reconstruct the body: a 0x00 byte starts a run; the byte(s) that + // follow give its length (see the wire format described above). + while (count--) + { + if (outptr > &dst[dst_capacity - 1]) + { + overflow = true; + outptr = dst; + break; + } + + if (!((*outptr++ = *inptr++))) + { + while ((count--) && (!(*inptr))) + { + if (outptr > &dst[dst_capacity - 256]) + { + overflow = true; + outptr = dst; + count = -1; + break; + } + *outptr++ = *inptr++; + memset(outptr, 0, 255); + outptr += 255; + } + + if (count < 0) + { + break; + } + else + { + if (outptr > &dst[dst_capacity - (*inptr)]) + { + overflow = true; + outptr = dst; + } + memset(outptr, 0, (*inptr) - 1); + outptr += ((*inptr) - 1); + inptr++; + } + } + } + + return (U32)(outptr - dst); + } +} + +#endif // LL_LLZEROCODE_H diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index e2937490ba..71210f7535 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -67,6 +67,7 @@ #include "llsdmessagereader.h" #include "llsdserialize.h" #include "llstring.h" +#include "llzerocode.h" #include "lltransfermanager.h" #include "lluuid.h" #include "llxfermanager.h" @@ -78,6 +79,8 @@ #include "lltransfertargetvfile.h" #include "llcorehttputil.h" #include "llpounceable.h" +#include "llproxy.h" +#include "llrand.h" // Constants //const char* MESSAGE_LOG_FILENAME = "message.log"; @@ -173,7 +176,7 @@ void LLMessageSystem::init() mTotalBytesIn = 0; mTotalBytesOut = 0; - mDroppedPackets = 0; // total dropped packets in + mLostPackets = 0; // total lost packets out mResentPackets = 0; // total resent packets out mFailedResendPackets = 0; // total resend failure packets out mOffCircuitPackets = 0; // total # of off-circuit packets rejected @@ -184,6 +187,13 @@ void LLMessageSystem::init() mIncomingCompressedSize = 0; mCurrentRecvPacketID = 0; + mActualBytesIn = 0; + mActualBytesOut = 0; + mDropPercentage = 0.0f; + mPacketsToDrop = 0; + mNumDroppedPackets = 0; + mNumDroppedPacketsTotal = 0; + mMessageFileVersionNumber = 0.f; mTimingCallback = NULL; @@ -508,18 +518,17 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) bool recv_reliable = false; bool recv_resent = false; - S32 acks = 0; + S32 num_acks = 0; S32 true_rcv_size = 0; + bool recv_packet_id_checked = false; U8* buffer = mTrueReceiveBuffer; - mTrueReceiveSize = mPacketRing.receivePacket(mSocket, (char *)mTrueReceiveBuffer); + mTrueReceiveSize = receivePacketOrDrop((char *)mTrueReceiveBuffer, recv_packet_id_checked); // 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) { @@ -535,24 +544,23 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) } else { - LLHost host; - LLCircuitData* cdp; - - // note if packet acks are appended. + // handle any packet ACKs (for outbound messages) found at tail of inbound message if(buffer[0] & LL_ACK_FLAG) { - acks += buffer[--receive_size]; + // Note: these ACKs may have already been handled if this was a buffered message + // but it doesn't hurt to handle them again. + num_acks += buffer[--receive_size]; true_rcv_size = receive_size; - if(receive_size >= ((S32)(acks * sizeof(TPACKETID) + LL_MINIMUM_VALID_PACKET_SIZE))) + if(receive_size >= ((S32)(num_acks * sizeof(TPACKETID) + LL_MINIMUM_VALID_PACKET_SIZE))) { - receive_size -= acks * sizeof(TPACKETID); + receive_size -= num_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 + << receive_size << " with invalid no. of acks " << num_acks << LL_ENDL; valid_packet = false; continue; @@ -562,20 +570,20 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) // process the message as normal mIncomingCompressedSize = zeroCodeExpand(&buffer, &receive_size); mCurrentRecvPacketID = ntohl(*((U32*)(&buffer[1]))); - host = getSender(); + LLHost host = getSender(); const bool resetPacketId = true; - cdp = findCircuit(host, resetPacketId); + LLCircuitData* 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))) + if(cdp && (num_acks > 0) && ((S32)(num_acks * sizeof(TPACKETID)) < (true_rcv_size))) { TPACKETID packet_id; U32 mem_id=0; - for(S32 i = 0; i < acks; ++i) + for(S32 i = 0; i < num_acks; ++i) { true_rcv_size -= sizeof(TPACKETID); memcpy(&mem_id, &mTrueReceiveBuffer[true_rcv_size], /* Flawfinder: ignore*/ @@ -630,7 +638,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) str << tbuf << "(unknown)" << (recv_reliable ? " reliable" : "") << " resent " - << ((acks > 0) ? "acks" : "") + << ((num_acks > 0) ? "acks" : "") << " DISCARD DUPLICATE"; LL_INFOS("Messaging") << str.str() << LL_ENDL; } @@ -680,7 +688,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) if ( valid_packet ) { - logValidMsg(cdp, host, recv_reliable, recv_resent, acks>0 ); + logValidMsg(cdp, host, recv_reliable, recv_resent, num_acks>0, recv_packet_id_checked ); valid_packet = mTemplateMessageReader->readMessage(buffer, host); } @@ -724,7 +732,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count ) // Check to see if we need to print debug info if ((mt_sec - mCircuitPrintTime) > mCircuitPrintFreq) { - mPacketRing.dumpPacketRingStats(); + dumpPacketRingStats(); dumpCircuitInfo(); mCircuitPrintTime = mt_sec; } @@ -749,6 +757,10 @@ S32 LLMessageSystem::getReceiveBytes() const } } +F32 LLMessageSystem::getBufferLoadRate() const +{ + return llmax(mHighPriorityInbound.getBufferLoadRate(), mLowPriorityInbound.getBufferLoadRate()); +} void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time) { @@ -822,7 +834,300 @@ void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time) S32 LLMessageSystem::drainUdpSocket() { - return mPacketRing.drainSocket(mSocket); + S32 packet_size = 1; + S32 num_loops = 0; + S32 old_num_buffered_packets = getNumBufferedPackets(); + while (packet_size > 0) + { + packet_size = bufferInboundPacket(); + ++num_loops; + } + S32 num_dropped_packets = (num_loops - 1 + old_num_buffered_packets) - getNumBufferedPackets(); + if (num_dropped_packets > 0) + { + mNumDroppedPackets += num_dropped_packets; + } + return getNumBufferedPackets(); +} + +bool LLMessageSystem::computeDrop() +{ + bool drop = (mDropPercentage > 0.0f && (ll_frand(100.f) < mDropPercentage)); + if (drop) + { + ++mPacketsToDrop; + } + if (mPacketsToDrop > 0) + { + --mPacketsToDrop; + drop = true; + } + return drop; +} + +bool LLMessageSystem::isHighPriorityMessage(const LLPacketBuffer& pkt) const +{ + S32 size = pkt.getSize(); + + // avoid stepping out of bounds + const S32 MIN_VALID_PACKET_SIZE = LL_PACKET_ID_SIZE + 4; + if (size < MIN_VALID_PACKET_SIZE) + { + return false; + } + + // We want to prioritize crucial messages used to establish viewer <--> simulator connection, + // which are all low-frequency. A simple approximation is to just prioritize all non high- + // frequency messages. + // + // High frequency messages use a single byte for message_id whereas medium- and low- + // frequency messages have 255 at the first byte (which is after the LL_PACKET_ID_SIZE + // bytes of packet_id). + const U8* header = (const U8*)pkt.getData() + LL_PACKET_ID_SIZE; + if (header[0] != 255) + { + // high-frequency message + return false; + } + + // BUG: The low-frequency AvatarAppearance message will be ignored if its agent is unknown + // and the agent is created upon receipt of its first high-frequency ObjectUpdate message. + // This race condition will be exacerbated by our default prioritization strategy. + // + // WORKAROUND: All middle- and low-frequency messages are high-priority except AvatarAppearance + // + // AvatarAppearance is "Low 158" which means it is stored in four bytes: 0xff 0xff 0x00 0x9E + // the last two bytes represent 158 in a BigEndian U16 + return header[1] != 255 && header[2] != 0 && header[3] != 158; +} + +void LLMessageSystem::dropPackets(U32 num_to_drop) +{ + mPacketsToDrop += num_to_drop; +} + +void LLMessageSystem::setDropPercentage(F32 percent_to_drop) +{ + mDropPercentage = percent_to_drop; +} + +S32 LLMessageSystem::receivePacketOrDrop(char* datap, bool& packet_id_already_checked) +{ + packet_id_already_checked = false; + + if (getNumBufferedPackets() > 0) + { + LLHost invalid_host; + LLPacketBuffer pkt(invalid_host, nullptr, 0); + if (!mHighPriorityInbound.popPacket(pkt)) + { + mLowPriorityInbound.popPacket(pkt); + } + + S32 packet_size = pkt.getSize(); + mLastSender = pkt.getHost(); + mLastReceivingIF = pkt.getReceivingInterface(); + packet_id_already_checked = pkt.getPacketIDChecked(); + + if (packet_size > 0) + { + memcpy(datap, pkt.getData(), packet_size); + } + return packet_size; + } + + // Read directly from the socket. checkPacketInID() has not run yet for + // this packet. + bool drop = computeDrop(); + S32 packet_size = 0; + if (LLProxy::isSOCKSProxyEnabled()) + { + char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */ + packet_size = receive_packet(mSocket, buffer); + if (packet_size > 0) + { + mActualBytesIn += packet_size; + } + if (packet_size > SOCKS_HEADER_SIZE) + { + if (drop) + { + packet_size = 0; + } + else + { + // *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6) + packet_size -= SOCKS_HEADER_SIZE; + memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size); + proxywrap_t* header = static_cast<proxywrap_t*>(static_cast<void*>(buffer)); + mLastSender.setAddress(header->addr); + mLastSender.setPort(ntohs(header->port)); + mLastReceivingIF = ::get_receiving_interface(); + } + } + else + { + packet_size = 0; + } + } + else + { + packet_size = receive_packet(mSocket, datap); + if (packet_size > 0) + { + mActualBytesIn += packet_size; + if (drop) + { + packet_size = 0; + } + else + { + mLastSender = ::get_sender(); + mLastReceivingIF = ::get_receiving_interface(); + } + } + } + return packet_size; +} + +S32 LLMessageSystem::bufferInboundPacket() +{ + LLHost invalid_host; + LLPacketBuffer pkt(invalid_host, nullptr, 0); + S32 packet_size = 0; + + if (LLProxy::isSOCKSProxyEnabled()) + { + char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */ + packet_size = receive_packet(mSocket, buffer); + if (packet_size > 0) + { + mActualBytesIn += packet_size; + if (packet_size > SOCKS_HEADER_SIZE) + { + // *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6) + proxywrap_t* header = static_cast<proxywrap_t*>(static_cast<void*>(buffer)); + LLHost sender; + sender.setAddress(header->addr); + sender.setPort(ntohs(header->port)); + packet_size -= SOCKS_HEADER_SIZE; + pkt.init(buffer + SOCKS_HEADER_SIZE, packet_size, sender); + } + else + { + packet_size = 0; + } + } + } + else + { + pkt.init(mSocket); + packet_size = pkt.getSize(); + if (packet_size > 0) + { + mActualBytesIn += packet_size; + } + } + + if (packet_size >= (S32)LL_MINIMUM_VALID_PACKET_SIZE && !computeDrop()) + { + const char* data = pkt.getData(); + LLCircuitData* cdp = mCircuitInfo.findCircuit(pkt.getHost()); + TPACKETID recv_packet_id = ntohl(*((U32*)(&data[1]))); + + // Harvest piggybacked ACKs for outbound messages from the packet tail of this inbound message + if (cdp && (data[0] & LL_ACK_FLAG)) + { + U8 num_acks = (U8)data[packet_size - 1]; + S32 true_rcv_size = packet_size - 1; + if (true_rcv_size >= (S32)(num_acks * sizeof(TPACKETID) + LL_MINIMUM_VALID_PACKET_SIZE)) + { + TPACKETID ack_id; + U32 mem_id = 0; + for (S32 i = 0; i < num_acks; ++i) + { + true_rcv_size -= sizeof(TPACKETID); + memcpy(&mem_id, &data[true_rcv_size], sizeof(TPACKETID)); /* Flawfinder: ignore */ + ack_id = ntohl(mem_id); + cdp->ackReliablePacket(ack_id); + } + if (!cdp->getUnackedPacketCount()) + { + mCircuitInfo.mUnackedCircuitMap.erase(cdp->mHost); + } + } + } + + if (cdp) + { + // ACK inbound reliable packet ASAP + if ((data[0] & LL_RELIABLE_FLAG)) + { + cdp->collectRAck(recv_packet_id); + } + + // Check packet sequencing here, in true socket-arrival order, before + // this packet is sorted into the high/low priority inbound queue. + // Skip genuine duplicate resends, same as checkMessages()/logValidMsg() + // would do further downstream. + bool recv_resent = (data[0] & LL_RESENT_FLAG) != 0; + if (!recv_resent || !cdp->isDuplicateResend(recv_packet_id)) + { + cdp->checkPacketInID(recv_packet_id, recv_resent); + pkt.setPacketIDChecked(true); + } + } + + if (isHighPriorityMessage(pkt)) + { + mHighPriorityInbound.pushPacket(pkt); + } + else + { + mLowPriorityInbound.pushPacket(pkt); + } + } + + return packet_size; +} + +bool LLMessageSystem::sendPacketToSocket(const char* datap, S32 data_size, LLHost host) +{ + mActualBytesOut += data_size; + if (!LLProxy::isSOCKSProxyEnabled()) + { + return send_packet(mSocket, datap, data_size, host.getAddress(), host.getPort()); + } + + char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; + + proxywrap_t* socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer)); + socks_header->rsv = 0; + socks_header->addr = host.getAddress(); + socks_header->port = htons(host.getPort()); + socks_header->atype = ADDRESS_IPV4; + socks_header->frag = 0; + + memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, datap, data_size); + + return send_packet(mSocket, + headered_send_buffer, + data_size + SOCKS_HEADER_SIZE, + LLProxy::getInstance()->getUDPProxy().getAddress(), + LLProxy::getInstance()->getUDPProxy().getPort()); +} + +void LLMessageSystem::dumpPacketRingStats() +{ + mNumDroppedPacketsTotal += mNumDroppedPackets; + LL_INFOS("Messaging") << "buffered_packets=" << getNumBufferedPackets() + << "buffered_bytes=" << (mHighPriorityInbound.getNumBufferedBytes() + mLowPriorityInbound.getNumBufferedBytes()) + << "recently_dropped=" << mNumDroppedPackets + << "total_dropped=" << mNumDroppedPacketsTotal + << "dropped_percentage=" << mDropPercentage << "%" + << "bytes_IN=" << mActualBytesIn + << "bytes_OUT=" << mActualBytesOut << LL_ENDL; + mNumDroppedPackets = 0; } void LLMessageSystem::copyMessageReceivedToSend() @@ -1277,7 +1582,7 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) } bool success; - success = mPacketRing.sendPacket(mSocket, (char *)buf_ptr, buffer_length, host); + success = sendPacketToSocket((char *)buf_ptr, buffer_length, host); if (!success) { @@ -1401,7 +1706,13 @@ void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host ) } } -void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, bool recv_reliable, bool recv_resent, bool recv_acks ) +void LLMessageSystem::logValidMsg( + LLCircuitData *cdp, + const LLHost& host, + bool recv_reliable, + bool recv_resent, + bool recv_acks, + bool skip_packet_id_check ) { if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM) { @@ -1418,8 +1729,13 @@ void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, bool r if (cdp) { - // update circuit packet ID tracking (missing/out of order packets) - cdp->checkPacketInID( mCurrentRecvPacketID, recv_resent ); + if (!skip_packet_id_check) + { + // update circuit packet ID tracking (missing/out of order packets) + // Already done in bufferInboundPacket(), in true socket-arrival + // order, if this packet came off the high/low priority queues. + cdp->checkPacketInID( mCurrentRecvPacketID, recv_resent ); + } cdp->addBytesIn( (S32Bytes)mTrueReceiveSize ); } @@ -2376,7 +2692,7 @@ void dump_prehash_files() { U32 i; std::string filename("../../indra/llmessage/message_prehash.h"); - LLFILE* fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("w")); /* Flawfinder: ignore */ if (fp) { fprintf( @@ -2407,7 +2723,7 @@ void dump_prehash_files() fclose(fp); } filename = std::string("../../indra/llmessage/message_prehash.cpp"); - fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */ + fp = LLFile::fopen(filename, LLFILE_MODE("w")); /* Flawfinder: ignore */ if (fp) { fprintf( @@ -2607,7 +2923,7 @@ void LLMessageSystem::summarizeLogs(std::ostream& str) str << buffer << std::endl << std::endl; buffer = llformat( "SendPacket failures: %20d", mSendPacketFailureCount); str << buffer << std::endl; - buffer = llformat( "Dropped packets: %20d", mDroppedPackets); + buffer = llformat( "Dropped packets: %20d", getTotalNumDroppedPackets()); str << buffer << std::endl; buffer = llformat( "Resent packets: %20d", mResentPackets); str << buffer << std::endl; @@ -2639,6 +2955,7 @@ void LLMessageSystem::summarizeLogs(std::ostream& str) void end_messaging_system(bool print_summary) { + LL_PROFILE_ZONE_SCOPED; gTransferManager.cleanup(); LLTransferTargetVFile::updateQueue(true); // shutdown LLTransferTargetVFile if (gMessageSystem) @@ -2744,85 +3061,6 @@ 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) @@ -2843,74 +3081,18 @@ S32 LLMessageSystem::zeroCodeExpand(U8** data, S32* 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) + bool overflow = false; + U32 decoded_size = LLZeroCode::decode(*data, (U32)*data_size, + mEncodedRecvBuffer, sizeof(mEncodedRecvBuffer), + LL_PACKET_ID_SIZE, overflow); + if (overflow) { - 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++; - } - } + LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size" << LL_ENDL; + callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE); } *data = mEncodedRecvBuffer; - *data_size = (S32)(outptr - mEncodedRecvBuffer); + *data_size = (S32)decoded_size; mUncompressedBytesIn += *data_size; return(in_size); @@ -3333,7 +3515,7 @@ void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_ void LLMessageSystem::dumpPacketToLog() { - LL_WARNS("Messaging") << "Packet Dump from:" << mPacketRing.getLastSender() << LL_ENDL; + LL_WARNS("Messaging") << "Packet Dump from:" << mLastSender << LL_ENDL; LL_WARNS("Messaging") << "Packet Size:" << mTrueReceiveSize << LL_ENDL; char line_buffer[256]; /* Flawfinder: ignore */ S32 i; diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 14cdc48a07..2e19e567e6 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -119,6 +119,49 @@ public: // Repeat for number of messages in file // +// UDP Packet Buffer Layout +// +// Every UDP message sent or received by LLMessageSystem uses the following +// on-wire layout. Offsets are defined in EPacketHeaderLayout below. +// +// Byte(s) Name Description +// ------- ---- ----------- +// 0 Flags Bit-field (see flag constants below): +// 0x80 LL_ZERO_CODE_FLAG – body is zero-run-length encoded +// 0x40 LL_RELIABLE_FLAG – sender expects a packet ACK +// 0x20 LL_RESENT_FLAG – this is a retransmission +// 0x10 LL_ACK_FLAG – piggybacked ACKs are appended +// at the tail of this packet +// 1-4 Packet ID Sequence number, U32 in network (big-endian) byte order. +// 5 Offset Byte offset from PHL_NAME to the start of the message +// body (past the message-ID bytes). Zero for most messages. +// 6+ Message ID Variable-length message type identifier: +// High-frequency (1 byte, values 0x01–0xFE) +// Medium-frequency (2 bytes, 0xFF hh) +// Low-frequency (4 bytes, 0xFF 0xFF hh ll) +// ... Body Message block data, described by the message template. +// Present only when LL_ZERO_CODE_FLAG is clear; otherwise +// the body (everything after byte 5) is zero-coded (see +// below). The 6-byte header is never zero-coded. +// +// Optional ACK tail (present when LL_ACK_FLAG is set in the flags byte): +// +// ... ACK IDs N packet-sequence IDs being acknowledged, each a U32 in +// network byte order, packed contiguously immediately before +// the ACK count byte. Read in reverse: walk backwards from +// just before the count byte, 4 bytes at a time. +// last ACK Count U8 giving N, the number of appended ACK IDs (max 255). +// This is the very last byte of the UDP payload. +// +// Zero-coding (applied when LL_ZERO_CODE_FLAG is set): +// +// Runs of zero bytes in the body are replaced by a two-byte token: +// 0x00 N – represents (N + 1) zero bytes, for N in 1..254 +// 0x00 0x00 N – represents (256 + N) zero bytes (wrap/overflow case) +// A literal 0x00 byte that starts no run is encoded as 0x00 0x00 0x00. +// The six-byte packet header is excluded from zero-coding and is always +// transmitted as-is. + // Constants const S32 MAX_MESSAGE_INTERNAL_NAME_SIZE = 255; const S32 MAX_BUFFER_SIZE = NET_BUFFER_SIZE; @@ -291,8 +334,11 @@ class LLMessageSystem : public LLMessageSenderInterface bool mBlockUntrustedInterface; LLHost mUntrustedInterface; + protected: + LLPacketRing mHighPriorityInbound; + LLPacketRing mLowPriorityInbound; + public: - LLPacketRing mPacketRing; LLReliablePacketParams mReliablePacketParams; // Set this flag to true when you want *very* verbose logs. @@ -334,7 +380,7 @@ public: U32 mReliablePacketsIn; // total reliable packets in U32 mReliablePacketsOut; // total reliable packets out - U32 mDroppedPackets; // total dropped packets in + U32 mLostPackets; // total reliable outbound packets declared lost U32 mResentPackets; // total resent packets out U32 mFailedResendPackets; // total resend failure packets out U32 mOffCircuitPackets; // total # of off-circuit packets rejected @@ -420,6 +466,25 @@ public: // returns total number of buffered packets after the drain S32 drainUdpSocket(); + // Inbound Packet-loss simulation controls + void dropPackets(U32 num_to_drop); + void setDropPercentage(F32 percent_to_drop); + + // UDP byte-accounting + S32 getActualInBytes() const { return mActualBytesIn; } + S32 getActualOutBytes() const { return mActualBytesOut; } + S32 getAndResetActualInBits() { S32 bits = mActualBytesIn * 8; mActualBytesIn = 0; return bits; } + S32 getAndResetActualOutBits() { S32 bits = mActualBytesOut * 8; mActualBytesOut = 0; return bits; } + + // Get number of "dropped" inbound packets + S32 getTotalNumDroppedPackets() const { return mNumDroppedPacketsTotal + mNumDroppedPackets; } + + S32 getNumBufferedPackets() const { return mHighPriorityInbound.getNumBufferedPackets() + mLowPriorityInbound.getNumBufferedPackets(); } + void dumpPacketRingStats(); + + // Send datap to host via mSocket (with SOCKS proxy support if enabled). + bool sendPacketToSocket(const char* datap, S32 data_size, LLHost host); + bool isMessageFast(const char *msg); bool isMessage(const char *msg) { @@ -539,7 +604,6 @@ public: //void buildMessage(); S32 zeroCodeExpand(U8 **data, S32 *data_size); - S32 zeroCodeAdjustCurrentSendTotal(); // Uses ping-based retry S32 sendReliable(const LLHost &host); @@ -754,7 +818,7 @@ public: S32 getReceiveBytes() const; S32 getUnackedListSize() const { return mUnackedListSize; } - F32 getBufferLoadRate() const { return mPacketRing.getBufferLoadRate(); } + F32 getBufferLoadRate() const; //const char* getCurrentSMessageName() const { return mCurrentSMessageName; } //const char* getCurrentSBlockName() const { return mCurrentSBlockName; } @@ -845,7 +909,7 @@ private: void logMsgFromInvalidCircuit( const LLHost& sender, bool recv_reliable ); void logTrustedMsgFromUntrustedCircuit( const LLHost& sender ); - void logValidMsg(LLCircuitData *cdp, const LLHost& sender, bool recv_reliable, bool recv_resent, bool recv_acks ); + void logValidMsg(LLCircuitData *cdp, const LLHost& sender, bool recv_reliable, bool recv_resent, bool recv_acks, bool skip_packet_id_check ); class LLMessageCountInfo { @@ -898,6 +962,34 @@ private: S32 mIncomingCompressedSize; // original size of compressed msg (0 if uncomp.) TPACKETID mCurrentRecvPacketID; // packet ID of current receive packet (for reporting) + // Socket I/O helpers + + // Receive one packet: pop from ring if buffered, else read from mSocket. + // Sets mLastSender and mLastReceivingIF. + // Sets packet_id_already_checked to whether checkPacketInID() was already + // run for this packet back when it was buffered (see bufferInboundPacket()). + // Returns packet_size, or 0 if no packet or packet was dropped. + S32 receivePacketOrDrop(char* datap, bool& packet_id_already_checked); + + // Read one raw packet from mSocket into inbound message queues + // Returns packet_size (0 if no packet was available). + S32 bufferInboundPacket(); + + // Returns true if the next inbound packet should be intentionally dropped. + bool computeDrop(); + + // Returns true if pkt carries a high-priority message and should be queued + // in mHighPriorityInbound. + bool isHighPriorityMessage(const LLPacketBuffer& pkt) const; + + // Packet-loss simulation and byte-accounting state + S32 mActualBytesIn; + S32 mActualBytesOut; + F32 mDropPercentage; // % of inbound packets to drop + U32 mPacketsToDrop; // drop next N inbound packets + S32 mNumDroppedPackets; // inbound + S32 mNumDroppedPacketsTotal;// inbound + LLMessageBuilder* mMessageBuilder; LLTemplateMessageBuilder* mTemplateMessageBuilder; LLSDMessageBuilder* mLLSDMessageBuilder; diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 21dbf35783..f42cbfdac7 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -714,6 +714,9 @@ char const* const _PREHASH_FirstName = LLMessageStringTable::getInstance()->getS char const* const _PREHASH_AttachedSoundGainChange = LLMessageStringTable::getInstance()->getString("AttachedSoundGainChange"); char const* const _PREHASH_LocationID = LLMessageStringTable::getInstance()->getString("LocationID"); char const* const _PREHASH_Running = LLMessageStringTable::getInstance()->getString("Running"); +char const* const _PREHASH_Mono = LLMessageStringTable::getInstance()->getString("Mono"); +char const* const _PREHASH_Luau = LLMessageStringTable::getInstance()->getString("Luau"); +char const* const _PREHASH_LuauLanguage = LLMessageStringTable::getInstance()->getString("LuauLanguage"); char const* const _PREHASH_AgentThrottle = LLMessageStringTable::getInstance()->getString("AgentThrottle"); char const* const _PREHASH_NeighborList = LLMessageStringTable::getInstance()->getString("NeighborList"); char const* const _PREHASH_PathTaperX = LLMessageStringTable::getInstance()->getString("PathTaperX"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 8a2ad1587c..53f8123b35 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -714,6 +714,9 @@ extern char const* const _PREHASH_FirstName; extern char const* const _PREHASH_AttachedSoundGainChange; extern char const* const _PREHASH_LocationID; extern char const* const _PREHASH_Running; +extern char const* const _PREHASH_Mono; +extern char const* const _PREHASH_Luau; +extern char const* const _PREHASH_LuauLanguage; extern char const* const _PREHASH_AgentThrottle; extern char const* const _PREHASH_NeighborList; extern char const* const _PREHASH_PathTaperX; diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 2be5a9e5b6..0df38d040a 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -326,7 +326,7 @@ S32 receive_packet(int hSocket, char * receiveBuffer) return 0; if (WSAECONNRESET == WSAGetLastError()) return 0; - LL_INFOS() << "receivePacket() failed, Error: " << WSAGetLastError() << LL_ENDL; + LL_INFOS() << "receive_packet() failed, Error: " << WSAGetLastError() << LL_ENDL; } return nRet; diff --git a/indra/llmessage/partsyspacket.cpp b/indra/llmessage/partsyspacket.cpp deleted file mode 100644 index 6113adbfcf..0000000000 --- a/indra/llmessage/partsyspacket.cpp +++ /dev/null @@ -1,1297 +0,0 @@ -/** - * @file partsyspacket.cpp - * @brief Object for packing particle system initialization parameters - * before sending them over the network. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "partsyspacket.h" -#include "indra_constants.h" - -// this function is global -void gSetInitDataDefaults(LLPartInitData *setMe) -{ - U32 i; - - //for(i = 0; i < 18; i++) - //{ - // setMe->k[i] = 0.0f; - //} - - //setMe->kill_p[0] = setMe->kill_p[1] = setMe->kill_p[2] = 0.0f; - //setMe->kill_p[3] = -0.2f; // time parameter, die when t= 5.0f - //setMe->kill_p[4] = 1.0f; - //setMe->kill_p[5] = -0.5f; // or radius == 2 (contracting) - - //setMe->bounce_p[0] = setMe->bounce_p[1] = - // setMe->bounce_p[2] = setMe->bounce_p[3] = 0.0f; - //setMe->bounce_p[4] = 1.0f; - - setMe->bounce_b = 1.0f; - // i just changed the meaning of bounce_b - // its now the attenuation from revlecting your velocity across the normal - // set by bounce_p - - //setMe->pos_ranges[0] = setMe->pos_ranges[2] = setMe->pos_ranges[4] = -1.0f; - //setMe->pos_ranges[1] = setMe->pos_ranges[3] = setMe->pos_ranges[5] = 1.0f; - - //setMe->vel_ranges[0] = setMe->vel_ranges[2] = setMe->vel_ranges[4] = -1.0f; - //setMe->vel_ranges[1] = setMe->vel_ranges[3] = setMe->vel_ranges[5] = 1.0f; - - for(i = 0; i < 3; i++) - { - setMe->diffEqAlpha[i] = 0.0f; - setMe->diffEqScale[i] = 0.0f; - } - - setMe->scale_range[0] = 1.00f; - setMe->scale_range[1] = 5.00f; - setMe->scale_range[2] = setMe->scale_range[3] = 0.0f; - - setMe->alpha_range[0] = setMe->alpha_range[1] = 1.0f; - setMe->alpha_range[2] = setMe->alpha_range[3] = 0.0f; - - setMe->vel_offset[0] = 0.0f; - setMe->vel_offset[1] = 0.0f; - setMe->vel_offset[2] = 0.0f; - - // start dropping particles when I'm more then one sim away - setMe->mDistBeginFadeout = 256.0f; - setMe->mDistEndFadeout = 1.414f * 512.0f; - // stop displaying particles when I'm more then two sim diagonals away - - setMe->mImageUuid = IMG_SHOT; - - for(i = 0; i < 8; i++) - { - setMe->mFlags[i] = 0x00; - } - - setMe->createMe = true; - - setMe->maxParticles = 25; - setMe->initialParticles = 25; - - //These defaults are for an explosion - a short lived set of debris affected by gravity. - //Action flags default to PART_SYS_AFFECTED_BY_WIND + PART_SYS_AFFECTED_BY_GRAVITY + PART_SYS_DISTANCE_DEATH - setMe->mFlags[PART_SYS_ACTION_BYTE] = PART_SYS_AFFECTED_BY_WIND | PART_SYS_AFFECTED_BY_GRAVITY | PART_SYS_DISTANCE_DEATH; - setMe->mFlags[PART_SYS_KILL_BYTE] = PART_SYS_DISTANCE_DEATH + PART_SYS_TIME_DEATH; - - setMe->killPlaneNormal[0] = 0.0f;setMe->killPlaneNormal[1] = 0.0f;setMe->killPlaneNormal[2] = 1.0f; //Straight up - setMe->killPlaneZ = 0.0f; //get local ground z as an approximation if turn on PART_SYS_KILL_PLANE - setMe->bouncePlaneNormal[0] = 0.0f;setMe->bouncePlaneNormal[1] = 0.0f;setMe->bouncePlaneNormal[2] = 1.0f; //Straight up - setMe->bouncePlaneZ = 0.0f; //get local ground z as an approximation if turn on PART_SYS_BOUNCE - setMe->spawnRange = 1.0f; - setMe->spawnFrequency = 0.0f; //Create the instant one dies - setMe->spawnFreqencyRange = 0.0f; - setMe->spawnDirection[0] = 0.0f;setMe->spawnDirection[1] = 0.0f;setMe->spawnDirection[2] = 1.0f; //Straight up - setMe->spawnDirectionRange = 1.0f; //global scattering - setMe->spawnVelocity = 0.75f; - setMe->spawnVelocityRange = 0.25f; //velocity +/- 0.25 - setMe->speedLimit = 1.0f; - - setMe->windWeight = 0.5f; //0.0f means looks like a heavy object (if gravity is on), 1.0f means light and fluffy - setMe->currentGravity[0] = 0.0f;setMe->currentGravity[1] = 0.0f;setMe->currentGravity[2] = -9.81f; - //This has to be constant to allow for compression - - setMe->gravityWeight = 0.5f; //0.0f means boyed by air, 1.0f means it's a lead weight - setMe->globalLifetime = 0.0f; //Arbitrary, but default is no global die, so doesn't matter - setMe->individualLifetime = 5.0f; - setMe->individualLifetimeRange = 1.0f; //Particles last 5 secs +/- 1 - setMe->alphaDecay = 1.0f; //normal alpha fadeout - setMe->scaleDecay = 0.0f; //no scale decay - setMe->distanceDeath = 10.0f; //die if hit unit radius - setMe->dampMotionFactor = 0.0f; - - setMe->windDiffusionFactor[0] = 0.0f; - setMe->windDiffusionFactor[1] = 0.0f; - setMe->windDiffusionFactor[2] = 0.0f; -} - -LLPartSysCompressedPacket::LLPartSysCompressedPacket() -{ - // default constructor for mDefaults called implicitly/automatically here - for(int i = 0; i < MAX_PART_SYS_PACKET_SIZE; i++) - { - mData[i] = '\0'; - } - - mNumBytes = 0; - - gSetInitDataDefaults(&mDefaults); -} - -LLPartSysCompressedPacket::~LLPartSysCompressedPacket() -{ - // no dynamic data is stored by this class, do nothing. -} - -void LLPartSysCompressedPacket::writeFlagByte(LLPartInitData *in) -{ - mData[0] = mData[1] = mData[2] = '\0'; - - U32 i; - //for(i = 1; i < 18; i++) { - // if(in->k[i] != mDefaults.k[i]) - // { - // mData[0] |= PART_SYS_K_MASK; - // break; - // } - //} - - if(in->killPlaneZ != mDefaults.killPlaneZ || - in->killPlaneNormal[0] != mDefaults.killPlaneNormal[0] || - in->killPlaneNormal[1] != mDefaults.killPlaneNormal[1] || - in->killPlaneNormal[2] != mDefaults.killPlaneNormal[2] || - in->distanceDeath != mDefaults.distanceDeath) - { - mData[0] |= PART_SYS_KILL_P_MASK; - } - - - - if(in->bouncePlaneZ != mDefaults.bouncePlaneZ || - in->bouncePlaneNormal[0] != mDefaults.bouncePlaneNormal[0] || - in->bouncePlaneNormal[1] != mDefaults.bouncePlaneNormal[1] || - in->bouncePlaneNormal[2] != mDefaults.bouncePlaneNormal[2]) - { - mData[0] |= PART_SYS_BOUNCE_P_MASK; - } - - if(in->bounce_b != mDefaults.bounce_b) - { - mData[0] |= PART_SYS_BOUNCE_B_MASK; - } - - - //if(in->pos_ranges[0] != mDefaults.pos_ranges[0] || in->pos_ranges[1] != mDefaults.pos_ranges[1] || - // in->pos_ranges[2] != mDefaults.pos_ranges[2] || in->pos_ranges[3] != mDefaults.pos_ranges[3] || - // in->pos_ranges[4] != mDefaults.pos_ranges[4] || in->pos_ranges[5] != mDefaults.pos_ranges[5]) - //{ - // mData[0] |= PART_SYS_POS_RANGES_MASK; - //} - - //if(in->vel_ranges[0] != mDefaults.vel_ranges[0] || in->vel_ranges[1] != mDefaults.vel_ranges[1] || - // in->vel_ranges[2] != mDefaults.vel_ranges[2] || in->vel_ranges[3] != mDefaults.vel_ranges[3] || - // in->vel_ranges[4] != mDefaults.vel_ranges[4] || in->vel_ranges[5] != mDefaults.vel_ranges[5]) - //{ -// mData[0] |= PART_SYS_VEL_RANGES_MASK; - //} - - - if(in->diffEqAlpha[0] != mDefaults.diffEqAlpha[0] || - in->diffEqAlpha[1] != mDefaults.diffEqAlpha[1] || - in->diffEqAlpha[2] != mDefaults.diffEqAlpha[2] || - in->diffEqScale[0] != mDefaults.diffEqScale[0] || - in->diffEqScale[1] != mDefaults.diffEqScale[1] || - in->diffEqScale[2] != mDefaults.diffEqScale[2]) - { - mData[0] |= PART_SYS_ALPHA_SCALE_DIFF_MASK; - } - - - if(in->scale_range[0] != mDefaults.scale_range[0] || - in->scale_range[1] != mDefaults.scale_range[1] || - in->scale_range[2] != mDefaults.scale_range[2] || - in->scale_range[3] != mDefaults.scale_range[3]) - { - mData[0] |= PART_SYS_SCALE_RANGE_MASK; - } - - - if(in->alpha_range[0] != mDefaults.alpha_range[0] || - in->alpha_range[1] != mDefaults.alpha_range[1] || - in->alpha_range[2] != mDefaults.alpha_range[2] || - in->alpha_range[3] != mDefaults.alpha_range[3]) - { - mData[2] |= PART_SYS_BYTE_3_ALPHA_MASK; - } - - if(in->vel_offset[0] != mDefaults.vel_offset[0] || - in->vel_offset[1] != mDefaults.vel_offset[1] || - in->vel_offset[2] != mDefaults.vel_offset[2]) - { - mData[0] |= PART_SYS_VEL_OFFSET_MASK; - } - - - if(in->mImageUuid != mDefaults.mImageUuid) - { - mData[0] |= PART_SYS_M_IMAGE_UUID_MASK; - } - - for( i = 0; i < 8; i++) - { - if(in->mFlags[i]) - { - mData[1] |= 1<<i; -// llprintline("Flag \"%x\" gets byte \"%x\"\n", i<<i, in->mFlags[i]); - } - } - - - if(in->spawnRange != mDefaults.spawnRange || - in->spawnFrequency != mDefaults.spawnFrequency || - in->spawnFreqencyRange != mDefaults.spawnFreqencyRange || - in->spawnDirection[0] != mDefaults.spawnDirection[0] || - in->spawnDirection[1] != mDefaults.spawnDirection[1] || - in->spawnDirection[2] != mDefaults.spawnDirection[2] || - in->spawnDirectionRange != mDefaults.spawnDirectionRange || - in->spawnVelocity != mDefaults.spawnVelocity || - in->spawnVelocityRange != mDefaults.spawnVelocityRange) - { - mData[3] |= PART_SYS_BYTE_SPAWN_MASK; - } - - - if(in->windWeight != mDefaults.windWeight || - in->currentGravity[0] != mDefaults.currentGravity[0] || - in->currentGravity[1] != mDefaults.currentGravity[1] || - in->currentGravity[2] != mDefaults.currentGravity[2] || - in->gravityWeight != mDefaults.gravityWeight) - { - mData[3] |= PART_SYS_BYTE_ENVIRONMENT_MASK; - } - - - if(in->globalLifetime != mDefaults.globalLifetime || - in->individualLifetime != mDefaults.individualLifetime || - in->individualLifetimeRange != mDefaults.individualLifetimeRange) - { - mData[3] |= PART_SYS_BYTE_LIFESPAN_MASK; - } - - - if(in->speedLimit != mDefaults.speedLimit || - in->alphaDecay != mDefaults.alphaDecay || - in->scaleDecay != mDefaults.scaleDecay || - in->dampMotionFactor != mDefaults.dampMotionFactor) - { - mData[3] |= PART_SYS_BYTE_DECAY_DAMP_MASK; - } - - if(in->windDiffusionFactor[0] != mDefaults.windDiffusionFactor[0] || - in->windDiffusionFactor[1] != mDefaults.windDiffusionFactor[1] || - in->windDiffusionFactor[2] != mDefaults.windDiffusionFactor[2]) - { - mData[3] |= PART_SYS_BYTE_WIND_DIFF_MASK; - } -} - -F32 floatFromTwoBytes(S8 bMant, S8 bExp) -{ - F32 result = bMant; - while(bExp > 0) - { - result *= 2.0f; - bExp--; - } - while(bExp < 0) - { - result *= 0.5f; - bExp++; - } - return result; -} - -void twoBytesFromFloat(F32 fIn, S8 &bMant, S8 &bExp) -{ - bExp = 0; - if(fIn > 127.0f) - { - fIn = 127.0f; - } - if(fIn < -127.0f) - { - fIn = -127.0f; - } - while(fIn < 64 && fIn > -64 && bExp > -127) - { - fIn *= 2.0f; - bExp--; - } - while((fIn > 128 || fIn < -128) && bExp < 127) - { - fIn *= 0.5f; - bExp++; - } - bMant = (S8)fIn; -} - - - -/* -U32 LLPartSysCompressedPacket::writeK(LLPartInitData *in, U32 startByte) -{ - U32 i, kFlag, i_mod_eight; - S8 bMant, bExp; - - kFlag = startByte; - - startByte += 3; // 3 bytes contain enough room for 18 flag bits - mData[kFlag] = 0x00; -// llprintline("In the writeK\n"); - - i_mod_eight = 0; - for(i = 0; i < 18; i++) - { - if(in->k[i] != mDefaults.k[i]) - { - - mData[kFlag] |= 1<<i_mod_eight; - twoBytesFromFloat(in->k[i], bMant, bExp); - - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - i_mod_eight++; - while(i_mod_eight >= 8) - { - kFlag++; - i_mod_eight -= 8; - } - } - - return startByte; -}*/ - -U32 LLPartSysCompressedPacket::writeKill_p(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - twoBytesFromFloat(in->killPlaneNormal[0], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->killPlaneNormal[1], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->killPlaneNormal[2], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->killPlaneZ, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->distanceDeath, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - -U32 LLPartSysCompressedPacket::writeBounce_p(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - twoBytesFromFloat(in->bouncePlaneNormal[0], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->bouncePlaneNormal[1], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->bouncePlaneNormal[2], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - - twoBytesFromFloat(in->bouncePlaneZ, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - -U32 LLPartSysCompressedPacket::writeBounce_b(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - twoBytesFromFloat(in->bounce_b, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - return startByte; -} - -//U32 LLPartSysCompressedPacket::writePos_ranges(LLPartInitData *in, U32 startByte) -//{ -// S8 tmp; -// int i; -// for(i = 0; i < 6; i++) -// { -// tmp = (S8) in->pos_ranges[i]; // float to int conversion (keep the sign) -// mData[startByte++] = (U8)tmp; // signed to unsigned typecast -// } -// return startByte; -//} - -//U32 LLPartSysCompressedPacket::writeVel_ranges(LLPartInitData *in, U32 startByte) -//{ -// S8 tmp; -// int i; -// for(i = 0; i < 6; i++) -// { -// tmp = (S8) in->vel_ranges[i]; // float to int conversion (keep the sign) -// mData[startByte++] = (U8)tmp; // signed to unsigned typecast -// } -// return startByte; -//} - -U32 LLPartSysCompressedPacket::writeAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->diffEqAlpha[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->diffEqScale[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - return startByte; -} - -U32 LLPartSysCompressedPacket::writeScale_range(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - for(i = 0; i < 4; i++) - { - twoBytesFromFloat(in->scale_range[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - return startByte; -} - - -U32 LLPartSysCompressedPacket::writeAlpha_range(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - for(i = 0; i < 4; i++) - { - twoBytesFromFloat(in->alpha_range[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - return startByte; -} - -U32 LLPartSysCompressedPacket::writeVelocityOffset(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->vel_offset[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - return startByte; -} - -U32 LLPartSysCompressedPacket::writeUUID(LLPartInitData *in, U32 startByte) -{ - U8 * bufPtr = mData + startByte; - if(in->mImageUuid == IMG_SHOT) { - mData[startByte++] = 0x01; - return startByte; - } - - if(in->mImageUuid == IMG_SPARK) { - mData[startByte++] = 0x02; - return startByte; - } - - - if(in->mImageUuid == IMG_BIG_EXPLOSION_1) { - mData[startByte++] = 0x03; - return startByte; - } - - if(in->mImageUuid == IMG_BIG_EXPLOSION_2) { - mData[startByte++] = 0x04; - return startByte; - } - - - if(in->mImageUuid == IMG_SMOKE_POOF) { - mData[startByte++] = 0x05; - return startByte; - } - - if(in->mImageUuid == IMG_FIRE) { - mData[startByte++] = 0x06; - return startByte; - } - - - if(in->mImageUuid == IMG_EXPLOSION) { - mData[startByte++] = 0x07; - return startByte; - } - - if(in->mImageUuid == IMG_EXPLOSION_2) { - mData[startByte++] = 0x08; - return startByte; - } - - - if(in->mImageUuid == IMG_EXPLOSION_3) { - mData[startByte++] = 0x09; - return startByte; - } - - if(in->mImageUuid == IMG_EXPLOSION_4) { - mData[startByte++] = 0x0A; - return startByte; - } - - mData[startByte++] = 0x00; // flag for "read whole UUID" - - memcpy(bufPtr, in->mImageUuid.mData, 16); /* Flawfinder: ignore */ - return (startByte+16); -} - -U32 LLPartSysCompressedPacket::writeSpawn(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - - twoBytesFromFloat(in->spawnRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->spawnFrequency, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->spawnFreqencyRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - - - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->spawnDirection[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - - twoBytesFromFloat(in->spawnDirectionRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->spawnVelocity, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - twoBytesFromFloat(in->spawnVelocityRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - -U32 LLPartSysCompressedPacket::writeEnvironment(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - int i; - - twoBytesFromFloat(in->windWeight, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - for(i = 0; i < 3; i++) - { - twoBytesFromFloat(in->currentGravity[i], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - } - - twoBytesFromFloat(in->gravityWeight, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - return startByte; -} - -U32 LLPartSysCompressedPacket::writeLifespan(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - - twoBytesFromFloat(in->globalLifetime, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->individualLifetime, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->individualLifetimeRange, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - - -U32 LLPartSysCompressedPacket::writeDecayDamp(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - - twoBytesFromFloat(in->speedLimit, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->alphaDecay, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->scaleDecay, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->dampMotionFactor, bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - -U32 LLPartSysCompressedPacket::writeWindDiffusionFactor(LLPartInitData *in, U32 startByte) -{ - S8 bExp, bMant; - - twoBytesFromFloat(in->windDiffusionFactor[0], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->windDiffusionFactor[1], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - twoBytesFromFloat(in->windDiffusionFactor[2], bMant, bExp); - mData[startByte++] = bMant; - mData[startByte++] = bExp; - - return startByte; -} - - - - - - -/* -U32 LLPartSysCompressedPacket::readK(LLPartInitData *in, U32 startByte) -{ - U32 i, i_mod_eight, kFlag; - S8 bMant, bExp; // 1 bytes mantissa and exponent for a float - kFlag = startByte; - startByte += 3; // 3 bytes has enough room for 18 bits - - i_mod_eight = 0; - for(i = 0; i < 18; i++) - { - if(mData[kFlag]&(1<<i_mod_eight)) - { - - - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - - - in->k[i] = floatFromTwoBytes(bMant, bExp); // much tighter platform-independent - // way to ship floats - - } - i_mod_eight++; - if(i_mod_eight >= 8) - { - i_mod_eight -= 8; - kFlag++; - } - } - - return startByte; -} -*/ - -U32 LLPartSysCompressedPacket::readKill_p(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->killPlaneNormal[0] = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->killPlaneNormal[1] = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->killPlaneNormal[2] = floatFromTwoBytes(bMant, bExp); - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->killPlaneZ = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->distanceDeath = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readBounce_p(LLPartInitData *in, U32 startByte) -{ - - S8 bMant, bExp; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bouncePlaneNormal[0] = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bouncePlaneNormal[1] = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bouncePlaneNormal[2] = floatFromTwoBytes(bMant, bExp); - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bouncePlaneZ = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readBounce_b(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->bounce_b = floatFromTwoBytes(bMant, bExp); - return startByte; -} - - -//U32 LLPartSysCompressedPacket::readPos_ranges(LLPartInitData *in, U32 startByte) -//{ -// S8 tmp; -// int i; -// for(i = 0; i < 6; i++) -// { -// tmp = (S8)mData[startByte++]; -// in->pos_ranges[i] = tmp; -// } -// return startByte; -//} - -//U32 LLPartSysCompressedPacket::readVel_ranges(LLPartInitData *in, U32 startByte) -//{ -// S8 tmp; -// int i; -// for(i = 0; i < 6; i++) -// { -// tmp = (S8)mData[startByte++]; -// in->vel_ranges[i] = tmp; -// } -// return startByte; -//} - - - -U32 LLPartSysCompressedPacket::readAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->diffEqAlpha[i] = floatFromTwoBytes(bMant, bExp); - } - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->diffEqScale[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -U32 LLPartSysCompressedPacket::readAlpha_range(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 4; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->alpha_range[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -U32 LLPartSysCompressedPacket::readScale_range(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 4; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->scale_range[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -U32 LLPartSysCompressedPacket::readVelocityOffset(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->vel_offset[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -U32 LLPartSysCompressedPacket::readUUID(LLPartInitData *in, U32 startByte) -{ - U8 * bufPtr = mData + startByte; - - if(mData[startByte] == 0x01) - { - in->mImageUuid = IMG_SHOT; - return startByte+1; - } - if(mData[startByte] == 0x02) - { - in->mImageUuid = IMG_SPARK; - return startByte+1; - } - if(mData[startByte] == 0x03) - { - in->mImageUuid = IMG_BIG_EXPLOSION_1; - return startByte+1; - } - if(mData[startByte] == 0x04) - { - in->mImageUuid = IMG_BIG_EXPLOSION_2; - return startByte+1; - } - if(mData[startByte] == 0x05) - { - in->mImageUuid = IMG_SMOKE_POOF; - return startByte+1; - } - if(mData[startByte] == 0x06) - { - in->mImageUuid = IMG_FIRE; - return startByte+1; - } - if(mData[startByte] == 0x07) - { - in->mImageUuid = IMG_EXPLOSION; - return startByte+1; - } - if(mData[startByte] == 0x08) - { - in->mImageUuid = IMG_EXPLOSION_2; - return startByte+1; - } - if(mData[startByte] == 0x09) - { - in->mImageUuid = IMG_EXPLOSION_3; - return startByte+1; - } - if(mData[startByte] == 0x0A) - { - in->mImageUuid = IMG_EXPLOSION_4; - return startByte+1; - } - - startByte++; // cause we actually have to read the UUID now. - memcpy(in->mImageUuid.mData, bufPtr, 16); /* Flawfinder: ignore */ - return (startByte+16); -} - - - - -U32 LLPartSysCompressedPacket::readSpawn(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - U32 i; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnRange = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnFrequency = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnFreqencyRange = floatFromTwoBytes(bMant, bExp); - - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnDirection[i] = floatFromTwoBytes(bMant, bExp); - } - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnDirectionRange = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnVelocity = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->spawnVelocityRange = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readEnvironment(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - U32 i; - - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->windWeight = floatFromTwoBytes(bMant, bExp); - - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->currentGravity[i] = floatFromTwoBytes(bMant, bExp); - } - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->gravityWeight = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readLifespan(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->globalLifetime = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->individualLifetime = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->individualLifetimeRange = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readDecayDamp(LLPartInitData *in, U32 startByte) -{ - S8 bMant, bExp; - - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->speedLimit = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->alphaDecay = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->scaleDecay = floatFromTwoBytes(bMant, bExp); - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->dampMotionFactor = floatFromTwoBytes(bMant, bExp); - - return startByte; -} - -U32 LLPartSysCompressedPacket::readWindDiffusionFactor(LLPartInitData *in, U32 startByte) -{ - int i; - S8 bMant, bExp; - for(i = 0; i < 3; i++) - { - bMant = mData[startByte++]; - bExp = mData[startByte++]; - in->windDiffusionFactor[i] = floatFromTwoBytes(bMant, bExp); - } - return startByte; -} - -bool LLPartSysCompressedPacket::fromLLPartInitData(LLPartInitData *in, U32 &bytesUsed) -{ - - writeFlagByte(in); - U32 currByte = 4; - -// llprintline("calling \"fromLLPartInitData\"\n"); - - //if(mData[0] & PART_SYS_K_MASK) - //{ - // currByte = writeK(in, 3); // first 3 bytes are reserved for header data - //} - - - - if(mData[0] & PART_SYS_KILL_P_MASK) - { - currByte = writeKill_p(in, currByte); - } - - if(mData[0] & PART_SYS_BOUNCE_P_MASK) - { - currByte = writeBounce_p(in, currByte); - } - - if(mData[0] & PART_SYS_BOUNCE_B_MASK) - { - currByte = writeBounce_b(in, currByte); - } - - //if(mData[0] & PART_SYS_POS_RANGES_MASK) - //{ - // currByte = writePos_ranges(in, currByte); - //} - - //if(mData[0] & PART_SYS_VEL_RANGES_MASK) - //{ - // currByte = writeVel_ranges(in, currByte); - //} - - if(mData[0] & PART_SYS_ALPHA_SCALE_DIFF_MASK) - { - currByte = writeAlphaScaleDiffEqn_range(in, currByte); - } - - if(mData[0] & PART_SYS_SCALE_RANGE_MASK) - { - currByte = writeScale_range(in, currByte); - } - - if(mData[0] & PART_SYS_VEL_OFFSET_MASK) - { - currByte = writeVelocityOffset(in, currByte); - } - - if(mData[0] & PART_SYS_M_IMAGE_UUID_MASK) - { - currByte = writeUUID(in, currByte); - } - - - if(mData[3] & PART_SYS_BYTE_SPAWN_MASK) - { - currByte = writeSpawn(in, currByte); - } - - if(mData[3] & PART_SYS_BYTE_ENVIRONMENT_MASK) - { - currByte = writeEnvironment(in, currByte); - } - - if(mData[3] & PART_SYS_BYTE_LIFESPAN_MASK) - { - currByte = writeLifespan(in, currByte); - } - - if(mData[3] & PART_SYS_BYTE_DECAY_DAMP_MASK) - { - currByte = writeDecayDamp(in, currByte); - } - - if(mData[3] & PART_SYS_BYTE_WIND_DIFF_MASK) - { - currByte = writeWindDiffusionFactor(in, currByte); - } - - - if(mData[2] & PART_SYS_BYTE_3_ALPHA_MASK) - { - currByte = writeAlpha_range(in, currByte); - } - - mData[currByte++] = (U8)in->maxParticles; - mData[currByte++] = (U8)in->initialParticles; - - - U32 flagFlag = 1; // flag indicating which flag bytes are non-zero - // yeah, I know, the name sounds funny - for(U32 i = 0; i < 8; i++) - { - -// llprintline("Flag \"%x\" gets byte \"%x\"\n", flagFlag, in->mFlags[i]); - if(mData[1] & flagFlag) - { - mData[currByte++] = in->mFlags[i]; -// llprintline("and is valid...\n"); - } - flagFlag <<= 1; - } - - bytesUsed = mNumBytes = currByte; - - - -// llprintline("returning from \"fromLLPartInitData\" with %d bytes\n", bytesUsed); - - return true; -} - -bool LLPartSysCompressedPacket::toLLPartInitData(LLPartInitData *out, U32 *bytesUsed) -{ - U32 currByte = 4; - - gSetInitDataDefaults(out); - - if(mData[0] & PART_SYS_KILL_P_MASK) - { - currByte = readKill_p(out, currByte); - } - - if(mData[0] & PART_SYS_BOUNCE_P_MASK) - { - currByte = readBounce_p(out, currByte); - } - - if(mData[0] & PART_SYS_BOUNCE_B_MASK) - { - currByte = readBounce_b(out, currByte); - } - - if(mData[0] & PART_SYS_ALPHA_SCALE_DIFF_MASK) - { - currByte = readAlphaScaleDiffEqn_range(out, currByte); - } - - if(mData[0] & PART_SYS_SCALE_RANGE_MASK) - { - currByte = readScale_range(out, currByte); - } - - if(mData[0] & PART_SYS_VEL_OFFSET_MASK) - { - currByte = readVelocityOffset(out, currByte); - } - - if(mData[0] & PART_SYS_M_IMAGE_UUID_MASK) - { - currByte = readUUID(out, currByte); - } - - - if(mData[3] & PART_SYS_BYTE_SPAWN_MASK) - { - currByte = readSpawn(out, currByte); - } - - if(mData[3] & PART_SYS_BYTE_ENVIRONMENT_MASK) - { - currByte = readEnvironment(out, currByte); - } - - if(mData[3] & PART_SYS_BYTE_LIFESPAN_MASK) - { - currByte = readLifespan(out, currByte); - } - - if(mData[3] & PART_SYS_BYTE_DECAY_DAMP_MASK) - { - currByte = readDecayDamp(out, currByte); - } - - if(mData[3] & PART_SYS_BYTE_WIND_DIFF_MASK) - { - currByte = readWindDiffusionFactor(out, currByte); - } - - if(mData[2] & PART_SYS_BYTE_3_ALPHA_MASK) - { - currByte = readAlpha_range(out, currByte); - } - - out->maxParticles = mData[currByte++]; - out->initialParticles = mData[currByte++]; - - U32 flagFlag = 1; // flag indicating which flag bytes are non-zero - // yeah, I know, the name sounds funny - for(U32 i = 0; i < 8; i++) - { - flagFlag = 1<<i; - - if((mData[1] & flagFlag)) - { - out->mFlags[i] = mData[currByte++]; - } - } - - *bytesUsed = currByte; - return true; -} - -bool LLPartSysCompressedPacket::fromUnsignedBytes(U8 *in, U32 bytesUsed) -{ - if ((in != NULL) && (bytesUsed <= sizeof(mData))) - { - memcpy(mData, in, bytesUsed); /* Flawfinder: ignore */ - mNumBytes = bytesUsed; - return true; - } - else - { - LL_ERRS() << "NULL input data or number of bytes exceed mData size" << LL_ENDL; - return false; - } -} - - -U32 LLPartSysCompressedPacket::bufferSize() -{ - return mNumBytes; -} - -bool LLPartSysCompressedPacket::toUnsignedBytes(U8 *out) -{ - memcpy(out, mData, mNumBytes); /* Flawfinder: ignore */ - return true; -} - -U8 * LLPartSysCompressedPacket::getBytePtr() -{ - return mData; -} - - diff --git a/indra/llmessage/partsyspacket.h b/indra/llmessage/partsyspacket.h deleted file mode 100644 index 23307f3409..0000000000 --- a/indra/llmessage/partsyspacket.h +++ /dev/null @@ -1,261 +0,0 @@ -/** - * @file partsyspacket.h - * @brief Object for packing particle system initialization parameters - * before sending them over the network - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_PARTSYSPACKET_H -#define LL_PARTSYSPACKET_H - -#include "lluuid.h" - -// Particle system stuff - -const U64 PART_SYS_MAX_TIME_IN_USEC = 1000000; // 1 second, die not quite near instantaneously - - -// this struct is for particle system initialization parameters -// I'm breaking some rules here, but I need a storage structure to hold initialization data -// for these things. Sorry guys, they're not simple enough (yet) to avoid this cleanly -struct LLPartInitData { - // please do not add functions to this class -- data only! - //F32 k[18]; // first 9 --> x,y,z last 9 --> scale, alpha, rot - //F32 kill_p[6]; // last one is for particles that die when they reach a spherical bounding radius - //F32 kill_plane[3]; - //F32 bounce_p[5]; - F32 bounce_b; // recently changed - // no need to store orientation and position here, as they're sent over seperately - //F32 pos_ranges[6]; - //F32 vel_ranges[6]; - F32 scale_range[4]; - F32 alpha_range[4]; - F32 vel_offset[3]; //new - more understandable! - - F32 mDistBeginFadeout; // for fadeout LOD optimization - F32 mDistEndFadeout; - - LLUUID mImageUuid; - //U8 n; // number of particles - U8 mFlags[8]; // for miscellaneous data --> its interpretation can change at my whim! - U8 createMe; // do I need to be created? or has the work allready been done? - //ActionFlag is now mFlags[PART_SYS_ACTION_BYTE] - //Spawn point is initially object creation center - - F32 diffEqAlpha[3]; - F32 diffEqScale[3]; - - U8 maxParticles; - //How many particles exist at any time within the system? - U8 initialParticles; - //How many particles exist when the system is created? - F32 killPlaneZ; - //For simplicity assume the XY plane, so this sets an altitude at which to die - F32 killPlaneNormal[3]; - //Normal if not planar XY - F32 bouncePlaneZ; - //For simplicity assume the XY plane, so this sets an altitude at which to bounce - F32 bouncePlaneNormal[3]; - //Normal if not planar XY - F32 spawnRange; - //Range of emission points about the mSpawnPoint - F32 spawnFrequency; - //Required if the system is to spawn new particles. - //This variable determines the time after a particle dies when it is respawned. - F32 spawnFreqencyRange; - //Determines the random range of time until a new particle is spawned. - F32 spawnDirection[3]; - //Direction vector giving the mean direction in which particles are spawned - F32 spawnDirectionRange; - //Direction limiting the angular range of emissions about the mean direction. 1.0f means everywhere, 0.0f means uni-directional - F32 spawnVelocity; - //The mean speed at which particles are emitted - F32 spawnVelocityRange; - //The range of speeds about the mean at which particles are emitted. - F32 speedLimit; - //Used to constrain particle maximum velocity - F32 windWeight; - //How much of an effect does wind have - F32 currentGravity[3]; - //Gravity direction used in update calculations - F32 gravityWeight; - //How much of an effect does gravity have - F32 globalLifetime; - //If particles re-spawn, a system can exist forever. - //If (ActionFlags & PART_SYS_GLOBAL_DIE) is true this variable is used to determine how long the system lasts. - F32 individualLifetime; - //How long does each particle last if nothing else happens to it - F32 individualLifetimeRange; - //Range of variation in individual lifetimes - F32 alphaDecay; - //By what factor does alpha decrease as the lifetime of a particle is approached. - F32 scaleDecay; - //By what factor does scale decrease as the lifetime of a particle is approached. - F32 distanceDeath; - //With the increased functionality, particle systems can expand to indefinite size - //(e.g. wind can chaotically move particles into a wide spread). - //To avoid particles exceeding normal object size constraints, - //set the PART_SYS_DISTANCE_DEATH flag, and set a distance value here, representing a radius around the spawn point. - F32 dampMotionFactor; - //How much to damp motion - F32 windDiffusionFactor[3]; - //Change the size and alpha of particles as wind speed increases (scale gets bigger, alpha smaller) -}; - -// constants for setting flag values -// BYTES are in range 0-8, bits are in range 2^0 - 2^8 and can only be powers of two -const int PART_SYS_NO_Z_BUFFER_BYTE = 0; // option to turn off z-buffer when rendering -const int PART_SYS_NO_Z_BUFFER_BIT = 2; // particle systems -- -// I advise against using this, as it looks bad in every case I've tried - -const int PART_SYS_SLOW_ANIM_BYTE = 0; // slow animation down by a factor of 10 -const int PART_SYS_SLOW_ANIM_BIT = 1; // useful for tweaking anims during debugging - -const int PART_SYS_FOLLOW_VEL_BYTE = 0; // indicates whether to orient sprites towards -const int PART_SYS_FOLLOW_VEL_BIT = 4; // their velocity vector -- default is false - -const int PART_SYS_IS_LIGHT_BYTE = 0; // indicates whether a particular particle system -const int PART_SYS_IS_LIGHT_BIT = 8; // is also a light object -- for andrew -// should deprecate this once there is a general method for setting light properties of objects - -const int PART_SYS_SPAWN_COPY_BYTE = 0; // indicates whether to spawn baby particle systems on -const int PART_SYS_SPAWN_COPY_BIT = 0x10; // particle death -- intended for smoke trails - -const int PART_SYS_COPY_VEL_BYTE = 0; // indicates whether baby particle systems inherit parents vel -const int PART_SYS_COPY_VEL_BIT = 0x20; // (by default they don't) - -const int PART_SYS_INVISIBLE_BYTE = 0; // optional -- turn off display, just simulate -const int PART_SYS_INVISIBLE_BIT = 0x40; // useful for smoke trails - -const int PART_SYS_ADAPT_TO_FRAMERATE_BYTE = 0; // drop sprites from render call proportionally -const int PART_SYS_ADAPT_TO_FRAMERATE_BIT = 0x80; // to how far we are below 60 fps - - -// 26 September 2001 - not even big enough to hold all changes, so should enlarge anyway -//const U16 MAX_PART_SYS_PACKET_SIZE = 180; -const U16 MAX_PART_SYS_PACKET_SIZE = 256; - -//const U8 PART_SYS_K_MASK = 0x01; -const U8 PART_SYS_KILL_P_MASK = 0x02; -const U8 PART_SYS_BOUNCE_P_MASK = 0x04; -const U8 PART_SYS_BOUNCE_B_MASK = 0x08; -//const U8 PART_SYS_POS_RANGES_MASK = 0x10; -//const U8 PART_SYS_VEL_RANGES_MASK = 0x20; -const U8 PART_SYS_VEL_OFFSET_MASK = 0x10; //re-use one of the original slots now commented out -const U8 PART_SYS_ALPHA_SCALE_DIFF_MASK = 0x20; //re-use one of the original slots now commented out -const U8 PART_SYS_SCALE_RANGE_MASK = 0x40; -const U8 PART_SYS_M_IMAGE_UUID_MASK = 0x80; -const U8 PART_SYS_BYTE_3_ALPHA_MASK = 0x01; // wrapped around, didn't we? - -const U8 PART_SYS_BYTE_SPAWN_MASK = 0x01; -const U8 PART_SYS_BYTE_ENVIRONMENT_MASK = 0x02; -const U8 PART_SYS_BYTE_LIFESPAN_MASK = 0x04; -const U8 PART_SYS_BYTE_DECAY_DAMP_MASK = 0x08; -const U8 PART_SYS_BYTE_WIND_DIFF_MASK = 0x10; - - -// 26 September 2001 - new constants for mActionFlags -const int PART_SYS_ACTION_BYTE = 1; -const U8 PART_SYS_SPAWN = 0x01; -const U8 PART_SYS_BOUNCE = 0x02; -const U8 PART_SYS_AFFECTED_BY_WIND = 0x04; -const U8 PART_SYS_AFFECTED_BY_GRAVITY = 0x08; -const U8 PART_SYS_EVALUATE_WIND_PER_PARTICLE = 0x10; -const U8 PART_SYS_DAMP_MOTION = 0x20; -const U8 PART_SYS_WIND_DIFFUSION = 0x40; - -// 26 September 2001 - new constants for mKillFlags -const int PART_SYS_KILL_BYTE = 2; -const U8 PART_SYS_KILL_PLANE = 0x01; -const U8 PART_SYS_GLOBAL_DIE = 0x02; -const U8 PART_SYS_DISTANCE_DEATH = 0x04; -const U8 PART_SYS_TIME_DEATH = 0x08; - - -// global, because the sim-side also calls it in the LLPartInitDataFactory - - -void gSetInitDataDefaults(LLPartInitData *setMe); - -class LLPartSysCompressedPacket -{ -public: - LLPartSysCompressedPacket(); - ~LLPartSysCompressedPacket(); - bool fromLLPartInitData(LLPartInitData *in, U32 &bytesUsed); - bool toLLPartInitData(LLPartInitData *out, U32 *bytesUsed); - bool fromUnsignedBytes(U8 *in, U32 bytesUsed); - bool toUnsignedBytes(U8 *out); - U32 bufferSize(); - U8 *getBytePtr(); - -protected: - U8 mData[MAX_PART_SYS_PACKET_SIZE]; - U32 mNumBytes; - LLPartInitData mDefaults; // this is intended to hold default LLPartInitData values - // please do not modify it - LLPartInitData mWorkingCopy; // uncompressed data I'm working with - -protected: - // private functions (used only to break up code) - void writeFlagByte(LLPartInitData *in); - //U32 writeK(LLPartInitData *in, U32 startByte); - U32 writeKill_p(LLPartInitData *in, U32 startByte); - U32 writeBounce_p(LLPartInitData *in, U32 startByte); - U32 writeBounce_b(LLPartInitData *in, U32 startByte); - //U32 writePos_ranges(LLPartInitData *in, U32 startByte); - //U32 writeVel_ranges(LLPartInitData *in, U32 startByte); - U32 writeAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte); - U32 writeScale_range(LLPartInitData *in, U32 startByte); - U32 writeAlpha_range(LLPartInitData *in, U32 startByte); - U32 writeUUID(LLPartInitData *in, U32 startByte); - - U32 writeVelocityOffset(LLPartInitData *in, U32 startByte); - U32 writeSpawn(LLPartInitData *in, U32 startByte); //all spawn data - U32 writeEnvironment(LLPartInitData *in, U32 startByte); //wind and gravity - U32 writeLifespan(LLPartInitData *in, U32 startByte); //lifespan data - individual and global - U32 writeDecayDamp(LLPartInitData *in, U32 startByte); //alpha and scale, and motion damp - U32 writeWindDiffusionFactor(LLPartInitData *in, U32 startByte); - - - //U32 readK(LLPartInitData *in, U32 startByte); - U32 readKill_p(LLPartInitData *in, U32 startByte); - U32 readBounce_p(LLPartInitData *in, U32 startByte); - U32 readBounce_b(LLPartInitData *in, U32 startByte); - //U32 readPos_ranges(LLPartInitData *in, U32 startByte); - //U32 readVel_ranges(LLPartInitData *in, U32 startByte); - U32 readAlphaScaleDiffEqn_range(LLPartInitData *in, U32 startByte); - U32 readScale_range(LLPartInitData *in, U32 startByte); - U32 readAlpha_range(LLPartInitData *in, U32 startByte); - U32 readUUID(LLPartInitData *in, U32 startByte); - - U32 readVelocityOffset(LLPartInitData *in, U32 startByte); - U32 readSpawn(LLPartInitData *in, U32 startByte); //all spawn data - U32 readEnvironment(LLPartInitData *in, U32 startByte); //wind and gravity - U32 readLifespan(LLPartInitData *in, U32 startByte); //lifespan data - individual and global - U32 readDecayDamp(LLPartInitData *in, U32 startByte); //alpha and scale, and motion damp - U32 readWindDiffusionFactor(LLPartInitData *in, U32 startByte); -}; - -#endif - diff --git a/indra/llmessage/tests/io_test.cpp b/indra/llmessage/tests/io_test.cpp new file mode 100644 index 0000000000..f77402065a --- /dev/null +++ b/indra/llmessage/tests/io_test.cpp @@ -0,0 +1,1181 @@ +/** + * @file io.cpp + * @author Phoenix + * @date 2005-10-02 + * @brief Tests for io classes and helpers + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" + +#include <iterator> + +#include "apr_pools.h" + +#include "llbuffer.h" +#include "llbufferstream.h" +#include "lliosocket.h" +#include "llioutil.h" +#include "llmemorystream.h" +#include "llpipeutil.h" +#include "llpumpio.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llcommon.h" +#include "lluuid.h" +#include "llinstantmessage.h" + +namespace tut +{ + struct heap_buffer_data + { + heap_buffer_data() : mBuffer(NULL) {} + ~heap_buffer_data() { if(mBuffer) delete mBuffer; } + LLHeapBuffer* mBuffer; + }; + typedef test_group<heap_buffer_data> heap_buffer_test; + typedef heap_buffer_test::object heap_buffer_object; + tut::heap_buffer_test thb("heap_buffer"); + + template<> template<> + void heap_buffer_object::test<1>() + { + const S32 BUF_SIZE = 100; + mBuffer = new LLHeapBuffer(BUF_SIZE); + ensure_equals("empty buffer capacity", mBuffer->capacity(), BUF_SIZE); + const S32 SEGMENT_SIZE = 50; + LLSegment segment; + mBuffer->createSegment(0, SEGMENT_SIZE, segment); + ensure_equals("used buffer capacity", mBuffer->capacity(), BUF_SIZE); + } + + template<> template<> + void heap_buffer_object::test<2>() + { + const S32 BUF_SIZE = 10; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment segment; + mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("segment is in buffer", mBuffer->containsSegment(segment)); + ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); + bool created; + created = mBuffer->createSegment(0, 0, segment); + ensure("Create zero size segment fails", !created); + created = mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("Create segment fails", !created); + } + + template<> template<> + void heap_buffer_object::test<3>() + { + const S32 BUF_SIZE = 10; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment segment; + mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("segment is in buffer", mBuffer->containsSegment(segment)); + ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); + bool reclaimed = mBuffer->reclaimSegment(segment); + ensure("buffer reclaimed.", reclaimed); + ensure_equals("buffer available", mBuffer->bytesLeft(), BUF_SIZE); + bool created; + created = mBuffer->createSegment(0, 0, segment); + ensure("Create zero size segment fails", !created); + created = mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("Create another segment succeeds", created); + } + + template<> template<> + void heap_buffer_object::test<4>() + { + const S32 BUF_SIZE = 10; + const S32 SEGMENT_SIZE = 4; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment seg1; + mBuffer->createSegment(0, SEGMENT_SIZE, seg1); + ensure("segment is in buffer", mBuffer->containsSegment(seg1)); + LLSegment seg2; + mBuffer->createSegment(0, SEGMENT_SIZE, seg2); + ensure("segment is in buffer", mBuffer->containsSegment(seg2)); + LLSegment seg3; + mBuffer->createSegment(0, SEGMENT_SIZE, seg3); + ensure("segment is in buffer", mBuffer->containsSegment(seg3)); + ensure_equals("segment is truncated", seg3.size(), 2); + LLSegment seg4; + bool created; + created = mBuffer->createSegment(0, SEGMENT_SIZE, seg4); + ensure("Create segment fails", !created); + bool reclaimed; + reclaimed = mBuffer->reclaimSegment(seg1); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("no buffer available", mBuffer->bytesLeft(), 0); + reclaimed = mBuffer->reclaimSegment(seg2); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), 0); + reclaimed = mBuffer->reclaimSegment(seg3); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), BUF_SIZE); + created = mBuffer->createSegment(0, SEGMENT_SIZE, seg1); + ensure("segment is in buffer", mBuffer->containsSegment(seg1)); + ensure("Create segment succeds", created); + } +} + +namespace tut +{ + struct buffer_data + { + LLBufferArray mBuffer; + }; + typedef test_group<buffer_data> buffer_test; + typedef buffer_test::object buffer_object; + tut::buffer_test tba("buffer_array"); + + template<> template<> + void buffer_object::test<1>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = static_cast<S32>(strlen(HELLO_WORLD)); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("total append size", count, str_len); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* first = (*it).data(); + count = mBuffer.countAfter(ch.in(), first); + ensure_equals("offset append size", count, str_len - 1); + } + + template<> template<> + void buffer_object::test<2>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = static_cast<S32>(strlen(HELLO_WORLD)); /* Flawfinder: ignore */ + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("total append size", count, 2 * str_len); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* first = (*it).data(); + count = mBuffer.countAfter(ch.in(), first); + ensure_equals("offset append size", count, (2 * str_len) - 1); + } + + template<> template<> + void buffer_object::test<3>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected(ONE); + expected.append(TWO); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)ONE, 3); + mBuffer.append(ch.in(), (U8*)TWO, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 6; + mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); + ensure_equals(len, 6); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<4>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected(ONE); + expected.append(TWO); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)TWO, 3); + mBuffer.prepend(ch.in(), (U8*)ONE, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 6; + mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); + ensure_equals(len, 6); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<5>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected("netwo"); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)TWO, 3); + mBuffer.prepend(ch.in(), (U8*)ONE, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 5; + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* addr = (*it).data(); + mBuffer.readAfter(ch.in(), addr, (U8*)buffer, len); + ensure_equals(len, 5); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<6>() + { + std::string request("The early bird catches the worm."); + std::string response("If you're a worm, sleep late."); + std::ostringstream expected; + expected << "ContentLength: " << response.length() << "\r\n\r\n" + << response; + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)request.c_str(), static_cast<S32>(request.length())); + mBuffer.append(ch.out(), (U8*)response.c_str(), static_cast<S32>(response.length())); + S32 count = mBuffer.countAfter(ch.out(), NULL); + std::ostringstream header; + header << "ContentLength: " << count << "\r\n\r\n"; + std::string head(header.str()); + mBuffer.prepend(ch.out(), (U8*)head.c_str(), static_cast<S32>(head.length())); + char buffer[1024]; /* Flawfinder: ignore */ + S32 len = static_cast<S32>(response.size() + head.length()); + ensure_equals("same length", len, (S32)expected.str().length()); + mBuffer.readAfter(ch.out(), NULL, (U8*)buffer, len); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("threaded writes", actual, expected.str()); + } + + template<> template<> + void buffer_object::test<7>() + { + const S32 LINE_COUNT = 3; + std::string lines[LINE_COUNT] = + { + std::string("GET /index.htm HTTP/1.0\r\n"), + std::string("User-Agent: Wget/1.9.1\r\n"), + std::string("Host: localhost:8008\r\n") + }; + std::string text; + S32 i; + for(i = 0; i < LINE_COUNT; ++i) + { + text.append(lines[i]); + } + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)text.c_str(), static_cast<S32>(text.length())); + const S32 BUFFER_LEN = 1024; + char buf[BUFFER_LEN]; + S32 len; + U8* last = NULL; + std::string last_line; + for(i = 0; i < LINE_COUNT; ++i) + { + len = BUFFER_LEN; + last = mBuffer.readAfter(ch.in(), last, (U8*)buf, len); + char* newline = strchr((char*)buf, '\n'); + S32 offset = -((len - 1) - (S32)(newline - buf)); + ++newline; + *newline = '\0'; + last_line.assign(buf); + std::ostringstream message; + message << "line reads in line[" << i << "]"; + ensure_equals(message.str().c_str(), last_line, lines[i]); + last = mBuffer.seek(ch.in(), last, offset); + } + } + + template<> template<> + void buffer_object::test<8>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)"1", 1); + LLBufferArray buffer; + buffer.append(ch.in(), (U8*)"2", 1); + mBuffer.takeContents(buffer); + mBuffer.append(ch.in(), (U8*)"3", 1); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("buffer size", count, 3); + U8* temp = new U8[count]; + mBuffer.readAfter(ch.in(), NULL, temp, count); + ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); + delete[] temp; + } + + template<> template<> + void buffer_object::test<9>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)"1", 1); + S32 capacity = mBuffer.capacity(); + ensure("has capacity", capacity > 0); + U8* temp = new U8[capacity - 1]; + mBuffer.append(ch.in(), temp, capacity - 1); + capacity = mBuffer.capacity(); + ensure("has capacity when full", capacity > 0); + S32 used = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("used equals capacity", used, capacity); + + LLBufferArray::segment_iterator_t iter = mBuffer.beginSegment(); + while(iter != mBuffer.endSegment()) + { + mBuffer.eraseSegment(iter++); + } + + used = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("used is zero", used, 0); + S32 capacity2 = mBuffer.capacity(); + ensure_equals("capacity the same after erase", capacity2, capacity); + mBuffer.append(ch.in(), temp, capacity - 1); + capacity2 = mBuffer.capacity(); + ensure_equals("capacity the same after append", capacity2, capacity); + + delete[] temp; + } + +#if 0 + template<> template<> + void buffer_object::test<9>() + { + char buffer[1024]; /* Flawfinder: ignore */ + S32 size = sprintf(buffer, + "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x", + 7, + 7, + "Hang Glider INFO", + "18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a", + "0e346d8b-4433-4d66-a6b0-fd37083abc4c", + "0e346d8b-4433-4d66-a6b0-fd37083abc4c", + "00000000-0000-0000-0000-000000000000", + 0x7fffffff, + 0x7fffffff, + 0, + 0, + 0x7fffffff, + "69e0d357-2e7c-8990-a2bc-7f61c868e5a3", + "2004-06-04 16:09:17 note card", + 0, + 10, + 0) + 1; + + //const char* expected = "7|7|Hang Glider INFO|18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a|0e346d8b-4433-4d66-a6b0-fd37083abc4c|0e346d8b-4433-4d66-a6b0-fd37083abc4c|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|7fffffff|69e0d357-2e7c-8990-a2bc-7f61c868e5a3|2004-06-04 16:09:17 note card|0|10|0\0"; + + LLSD* bin_bucket = LLIMInfo::buildSDfrombuffer((U8*)buffer,size); + + char post_buffer[1024]; + U32 post_size; + LLIMInfo::getBinaryBucket(bin_bucket,(U8*)post_buffer,post_size); + ensure_equals("Buffer sizes",size,(S32)post_size); + ensure("Buffer content",!strcmp(buffer,post_buffer)); + } +#endif + + /* + template<> template<> + void buffer_object::test<>() + { + } + */ +} + +namespace tut +{ + struct buffer_and_stream_data + { + LLBufferArray mBuffer; + }; + typedef test_group<buffer_and_stream_data> bas_test; + typedef bas_test::object bas_object; + tut::bas_test tbs("buffer_stream"); + + template<> template<> + void bas_object::test<1>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = static_cast<S32>(strlen(HELLO_WORLD)); /* Flawfinder: ignore */ + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + std::string hello; + std::string world; + str >> hello >> world; + ensure_equals("first word", hello, std::string("hello")); + ensure_equals("second word", world, std::string("world")); + } + + template<> template<> + void bas_object::test<2>() + { + std::string part1("Eat my shor"); + std::string part2("ts ho"); + std::string part3("mer"); + std::string ignore("ignore me"); + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + mBuffer.append(ch.in(), (U8*)part1.c_str(), static_cast<S32>(part1.length())); + mBuffer.append(ch.in(), (U8*)part2.c_str(), static_cast<S32>(part2.length())); + mBuffer.append(ch.out(), (U8*)ignore.c_str(), static_cast<S32>(ignore.length())); + mBuffer.append(ch.in(), (U8*)part3.c_str(), static_cast<S32>(part3.length())); + std::string eat; + std::string my; + std::string shorts; + std::string homer; + str >> eat >> my >> shorts >> homer; + ensure_equals("word1", eat, std::string("Eat")); + ensure_equals("word2", my, std::string("my")); + ensure_equals("word3", shorts, std::string("shorts")); + ensure_equals("word4", homer, std::string("homer")); + } + + template<> template<> + void bas_object::test<3>() + { + std::string part1("junk in "); + std::string part2("the trunk"); + const S32 CHANNEL = 0; + mBuffer.append(CHANNEL, (U8*)part1.c_str(), static_cast<S32>(part1.length())); + mBuffer.append(CHANNEL, (U8*)part2.c_str(), static_cast<S32>(part2.length())); + U8* last = 0; + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 len = 11; + last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); + buf[len] = '\0'; + std::string actual(buf); + ensure_equals("first read", actual, std::string("junk in the")); + last = mBuffer.seek(CHANNEL, last, -6); + len = 12; + last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); + buf[len] = '\0'; + actual.assign(buf); + ensure_equals("seek and read", actual, std::string("in the trunk")); + } + + template<> template<> + void bas_object::test<4>() + { + std::string phrase("zippity do da!"); + const S32 CHANNEL = 0; + mBuffer.append(CHANNEL, (U8*)phrase.c_str(), static_cast<S32>(phrase.length())); + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 len = 7; + U8* last = mBuffer.readAfter(CHANNEL, NULL, (U8*)buf, len); + mBuffer.splitAfter(last); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + LLBufferArray::segment_iterator_t end = mBuffer.endSegment(); + std::string first((char*)((*it).data()), (*it).size()); + ensure_equals("first part", first, std::string("zippity")); + ++it; + std::string second((char*)((*it).data()), (*it).size()); + ensure_equals("second part", second, std::string(" do da!")); + ++it; + ensure("iterators equal", (it == end)); + } + + template<> template<> + void bas_object::test<5>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + std::string h1("hello"); + std::string h2(", how are you doing?"); + std::string expected(h1); + expected.append(h2); + str << h1 << h2; + str.flush(); + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 actual_len = BUF_LEN; + S32 expected_len = static_cast<S32>(h1.size() + h2.size()); + (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); + ensure_equals("streamed size", actual_len, expected_len); + buf[actual_len] = '\0'; + std::string actual(buf); + ensure_equals("streamed to buf", actual, expected); + } + + template<> template<> + void bas_object::test<6>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream bstr(ch, &mBuffer); + std::ostringstream ostr; + std::vector<LLUUID> ids; + LLUUID id; + for(int i = 0; i < 5; ++i) + { + id.generate(); + ids.push_back(id); + } + bstr << "SELECT concat(u.username, ' ', l.name) " + << "FROM user u, user_last_name l " + << "WHERE u.last_name_id = l.last_name_id" + << " AND u.agent_id IN ('"; + ostr << "SELECT concat(u.username, ' ', l.name) " + << "FROM user u, user_last_name l " + << "WHERE u.last_name_id = l.last_name_id" + << " AND u.agent_id IN ('"; + std::copy( + ids.begin(), + ids.end(), + std::ostream_iterator<LLUUID>(bstr, "','")); + std::copy( + ids.begin(), + ids.end(), + std::ostream_iterator<LLUUID>(ostr, "','")); + bstr.seekp(-2, std::ios::cur); + ostr.seekp(-2, std::ios::cur); + bstr << ") "; + ostr << ") "; + bstr.flush(); + const S32 BUF_LEN = 512; + char buf[BUF_LEN]; /* Flawfinder: ignore */ + S32 actual_len = BUF_LEN; + (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); + buf[actual_len] = '\0'; + std::string actual(buf); + std::string expected(ostr.str()); + ensure_equals("size of string in seek",actual.size(),expected.size()); + ensure_equals("seek in ostream", actual, expected); + } + + template<> template<> + void bas_object::test<7>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream bstr(ch, &mBuffer); + bstr << "1"; + bstr.flush(); + S32 count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 1", count, 1); + LLBufferArray buffer; + buffer.append(ch.out(), (U8*)"2", 1); + mBuffer.takeContents(buffer); + count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 2", count, 2); + bstr << "3"; + bstr.flush(); + count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 3", count, 3); + U8* temp = new U8[count]; + mBuffer.readAfter(ch.out(), NULL, temp, count); + ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); + delete[] temp; + } + + template<> template<> + void bas_object::test<8>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream ostr(ch, &mBuffer); + typedef std::vector<U8> buf_t; + typedef std::vector<buf_t> actual_t; + actual_t actual; + buf_t source; + bool need_comma = false; + ostr << "["; + S32 total_size = 1; + for(S32 i = 2000; i < 2003; ++i) + { + if(need_comma) + { + ostr << ","; + ++total_size; + } + need_comma = true; + srand(69 + i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 1000; + std::generate_n( + std::back_insert_iterator<buf_t>(source), + size, + rand); + actual.push_back(source); + ostr << "b(" << size << ")\""; + total_size += 8; + ostr.write((const char*)(&source[0]), size); + total_size += size; + source.clear(); + ostr << "\""; + ++total_size; + } + ostr << "]"; + ++total_size; + ostr.flush(); + + // now that we have a bunch of data on a stream, parse it all. + ch = mBuffer.nextChannel(); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("size of buffer", count, total_size); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + count = LLSDSerialize::fromNotation(data, istr, total_size); + ensure("sd parsed", data.isDefined()); + + for(S32 j = 0; j < 3; ++j) + { + std::ostringstream name; + LLSD child(data[j]); + name << "found buffer " << j; + ensure(name.str(), child.isDefined()); + source = child.asBinary(); + name.str(""); + name << "buffer " << j << " size"; + ensure_equals(name.str().c_str(), source.size(), actual[j].size()); + name.str(""); + name << "buffer " << j << " contents"; + ensure( + name.str(), + (0 == memcmp(&source[0], &actual[j][0], source.size()))); + } + } + + template<> template<> + void bas_object::test<9>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream ostr(ch, &mBuffer); + typedef std::vector<U8> buf_t; + buf_t source; + bool need_comma = false; + ostr << "{"; + S32 total_size = 1; + for(S32 i = 1000; i < 3000; ++i) + { + if(need_comma) + { + ostr << ","; + ++total_size; + } + need_comma = true; + ostr << "'" << i << "':"; + total_size += 7; + srand(69 + i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 1000; + std::generate_n( + std::back_insert_iterator<buf_t>(source), + size, + rand); + ostr << "b(" << size << ")\""; + total_size += 8; + ostr.write((const char*)(&source[0]), size); + total_size += size; + source.clear(); + ostr << "\""; + ++total_size; + } + ostr << "}"; + ++total_size; + ostr.flush(); + + // now that we have a bunch of data on a stream, parse it all. + ch = mBuffer.nextChannel(); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("size of buffer", count, total_size); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + count = LLSDSerialize::fromNotation(data, istr, total_size); + ensure("sd parsed", data.isDefined()); + } + + template<> template<> + void bas_object::test<10>() + { +//#if LL_WINDOWS && _MSC_VER >= 1400 +// skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); +//#endif + const char LOGIN_STREAM[] = "{'method':'login', 'parameter': [ {" + "'uri': 'sl-am:kellys.region.siva.lindenlab.com/location?start=url&px=128&py=128&pz=128&lx=0&ly=0&lz=0'}, " + "{'version': i1}, {'texture_data': [ '61d724fb-ad79-f637-2186-5cf457560daa', '6e38b9be-b7cc-e77a-8aec-029a42b0b416', " + "'a9073524-e89b-2924-ca6e-a81944109a1a', '658f18b5-5f1e-e593-f5d5-36c3abc7249a', '0cc799f4-8c99-6b91-bd75-b179b12429e2', " + "'59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '5748decc-f629-461c-9a36-a35a221fe21f', " + "'b8fc9be2-26a6-6b47-690b-0e902e983484', 'a13ca0fe-3802-dc97-e79a-70d12171c724', 'dd9643cf-fd5d-0376-ed4a-b1cc646a97d5', " + "'4ad13ae9-a112-af09-210a-cf9353a7a9e7', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " + "'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " + "'5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97']," + "'session_id': '324cfa9f-fe5d-4d1c-a317-35f20a86a4d1','position': [ i128, i128, i128],'last_name': 'Linden','group_title': '-> !BLING! <-','group_name': 'test!','agent_access': 'M'," + "'attachment_data': [ {'asset_id': 'aaede2b1-9955-09d4-5c93-2b557c778cf3','attachment_point': i6,'item_id': 'f3694abc-5122-db33-73d9-e0f4288dc2bf'}]," + "'buddy_ids': [ '101358d5-469d-4b24-9b85-4dc3c05e635d', '1b00fec7-6265-4875-acac-80d9cfe9295c', '203ad6df-b522-491d-ba48-4e24eb57aeff', " + "'22d4dcdb-aebb-47fa-b925-a871cc75ee48','27da3df5-1339-4463-80aa-40504ee3b3e5', '299d1720-b61f-4268-8c29-9614aa2d44c2', " + "'2b048a24-2737-4994-9fa5-becc8e466253', '2cd5dc14-a853-49a4-be3c-a5a7178e37bc', '3de548e1-57be-cfea-2b78-83ae3ad95998', " + "'3dee98e4-a6a3-4543-91c3-bbd528447ba7', '3e2d81a3-6263-6ffe-ad5c-8ce04bee07e9', '40e70b98-fed7-47f3-9700-1bce93f9350b', " + "'50a9b68e-b5aa-4d35-9137-3cfebda0a15c', '54295571-9357-43ff-ae74-a83b5138160f', '6191e2d7-5f96-4856-bdab-af0f79f47ae4', " + "'63e577d8-cd34-4235-a0a3-de0500133364', '79cfb666-4fd0-4af7-95df-fb7d96b4e24d', '8121c2f3-4a88-4c33-9899-8fc1273f47ee', " + "'909da964-ef23-4f2a-ba13-f2a8cfd454b6','a2e76fcd-9360-4f6d-a924-000000000001', 'aaa6d664-527e-4d83-9cbb-7ef79ccc7cc8', " + "'b79bfb6c-23be-49eb-b35b-30ff2f501b37', 'ba0d9c79-148c-4a79-8e3c-0665eebe2427', 'bc9bda98-57cd-498f-b993-4ff1ac9dec93', " + "'c62d16f6-81cb-419d-9cac-e46dc394084d', 'd48f8fa7-2512-4fe5-80c8-c0a923412e07', 'd77e3e24-7e6c-4c3f-96d0-a1746337f8fb', " + "'da615c63-a84b-4592-a3d6-a90dd3e92e6e', 'df47190a-7eb7-4aff-985f-2d1d3ad6c6e9', 'e3380196-72cd-499c-a2ba-caa180bd5fe4', " + "'e937863f-f134-4207-803b-d6e686651d6c', 'efcdf98b-5269-45ef-ac7a-0671f09ea9d9']," + "'circuit_code': i124,'group_id': '8615c885-9cf0-bf0a-6e40-0c11462aa652','limited_to_estate': i1,'look_at': [ i0, i0, i0]," + "'agent_id': '0e346d8b-4433-4d66-a6b0-fd37083abc4c','first_name': 'Kelly','start': 'url'}]}"; + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, static_cast<S32>(strlen(LOGIN_STREAM))); /* Flawfinder: ignore */ + ch = mBuffer.nextChannel(); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + S32 count = LLSDSerialize::fromNotation( + data, + istr, + mBuffer.count(ch.in())); + ensure("parsed something", (count > 0)); + ensure("sd parsed", data.isDefined()); + ensure_equals("sd type", data.type(), LLSD::TypeMap); + ensure("has method", data.has("method")); + ensure("has parameter", data.has("parameter")); + LLSD parameter = data["parameter"]; + ensure_equals("parameter is array", parameter.type(), LLSD::TypeArray); + LLSD agent_params = parameter[2]; + std::string s_value; + s_value = agent_params["last_name"].asString(); + ensure_equals("last name", s_value, std::string("Linden")); + s_value = agent_params["first_name"].asString(); + ensure_equals("first name", s_value, std::string("Kelly")); + s_value = agent_params["agent_access"].asString(); + ensure_equals("agent access", s_value, std::string("M")); + s_value = agent_params["group_name"].asString(); + ensure_equals("group name", s_value, std::string("test!")); + s_value = agent_params["group_title"].asString(); + ensure_equals("group title", s_value, std::string("-> !BLING! <-")); + + LLUUID agent_id("0e346d8b-4433-4d66-a6b0-fd37083abc4c"); + LLUUID id = agent_params["agent_id"]; + ensure_equals("agent id", id, agent_id); + LLUUID session_id("324cfa9f-fe5d-4d1c-a317-35f20a86a4d1"); + id = agent_params["session_id"]; + ensure_equals("session id", id, session_id); + LLUUID group_id ("8615c885-9cf0-bf0a-6e40-0c11462aa652"); + id = agent_params["group_id"]; + ensure_equals("group id", id, group_id); + + S32 i_val = agent_params["limited_to_estate"]; + ensure_equals("limited to estate", i_val, 1); + i_val = agent_params["circuit_code"]; + ensure_equals("circuit code", i_val, 124); + } + + + template<> template<> + void bas_object::test<11>() + { + std::string val = "{!'foo'@:#'bar'}"; + std::istringstream istr; + istr.str(val); + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parser error return value", count, -1); + ensure("data undefined", sd.isUndefined()); + } + + template<> template<> + void bas_object::test<12>() + { +//#if LL_WINDOWS && _MSC_VER >= 1400 +// skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); +//#endif + std::string val = "{!'foo':[i1,'hi',{@'bar'#:[$i2%,^'baz'&]*}+]=}"; + std::istringstream istr; + istr.str(val); + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parser error return value", count, -1); + ensure("data undefined", sd.isUndefined()); + } + +/* + template<> template<> + void bas_object::test<13>() + { + } + template<> template<> + void bas_object::test<14>() + { + } + template<> template<> + void bas_object::test<15>() + { + } +*/ +} + + +namespace tut +{ + class PumpAndChainTestData + { + protected: + apr_pool_t* mPool; + LLPumpIO* mPump; + LLPumpIO::chain_t mChain; + + public: + PumpAndChainTestData() + { + apr_pool_create(&mPool, NULL); + mPump = new LLPumpIO(mPool); + } + + ~PumpAndChainTestData() + { + mChain.clear(); + delete mPump; + apr_pool_destroy(mPool); + } + }; + typedef test_group<PumpAndChainTestData> PumpAndChainTestGroup; + typedef PumpAndChainTestGroup::object PumpAndChainTestObject; + PumpAndChainTestGroup pumpAndChainTestGroup("pump_and_chain"); + + template<> template<> + void PumpAndChainTestObject::test<1>() + { + LLPipeStringExtractor* extractor = new LLPipeStringExtractor(); + + mChain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); + mChain.push_back(LLIOPipe::ptr_t(extractor)); + + LLTimer timer; + timer.setTimerExpirySec(100.0f); + + mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS); + while(!extractor->done() && !timer.hasExpired()) + { + mPump->pump(); + mPump->callback(); + } + + ensure("reading string finished", extractor->done()); + ensure_equals("string was empty", extractor->string(), ""); + } +} + +/* +namespace tut +{ + struct double_construct + { + public: + double_construct() + { + LL_INFOS() << "constructed" << LL_ENDL; + } + ~double_construct() + { + LL_INFOS() << "destroyed" << LL_ENDL; + } + }; + typedef test_group<double_construct> double_construct_test_group; + typedef double_construct_test_group::object dc_test_object; + double_construct_test_group dctest("double construct"); + template<> template<> + void dc_test_object::test<1>() + { + ensure("test 1", true); + } +} +*/ + +namespace tut +{ + /** + * @brief we want to test the pipes & pumps under bad conditions. + */ + struct pipe_and_pump_fitness + { + public: + enum + { + SERVER_LISTEN_PORT = 13050 + }; + + pipe_and_pump_fitness() + { + LLFrameTimer::updateFrameTime(); + apr_pool_create(&mPool, NULL); + mPump = new LLPumpIO(mPool); + mSocket = LLSocket::create( + mPool, + LLSocket::STREAM_TCP, + SERVER_LISTEN_PORT, + "127.0.0.1"); + } + + ~pipe_and_pump_fitness() + { + mSocket.reset(); + delete mPump; + apr_pool_destroy(mPool); + } + + protected: + apr_pool_t* mPool; + LLPumpIO* mPump; + LLSocket::ptr_t mSocket; + }; + typedef test_group<pipe_and_pump_fitness> fitness_test_group; + typedef fitness_test_group::object fitness_test_object; + fitness_test_group fitness("pipe and pump fitness"); + + template<> template<> + void fitness_test_object::test<1>() + { + LL_DEBUGS() << "fitness_test_object::test<1>()" << LL_ENDL; + + // Set up the server + //LL_DEBUGS() << "fitness_test_object::test<1> - setting up server." + // << LL_ENDL; + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLPipeStringInjector> emitter_t; + emitter_t* emitter = new emitter_t( + new LLPipeStringInjector("suckers never play me")); + std::shared_ptr<LLChainIOFactory> factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + //LL_DEBUGS() << "fitness_test_object::test<1> - initializing server." + // << LL_ENDL; + pump_loop(mPump, 0.1f); + + // Set up the client + //LL_DEBUGS() << "fitness_test_object::test<1> - connecting client." + // << LL_ENDL; + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, 1.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, 2.0f); + ensure("Did not take too long", (elapsed < 3.0f)); + } + + template<> template<> + void fitness_test_object::test<2>() + { + LL_DEBUGS() << "fitness_test_object::test<2>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLIOFuzz> emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr<LLChainIOFactory> factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS / 2.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f); + ensure("Did not take too long", (elapsed < 3.0f)); + } + + template<> template<> + void fitness_test_object::test<3>() + { + LL_DEBUGS() << "fitness_test_object::test<3>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLIOFuzz> emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr<LLChainIOFactory> factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS * 2.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f + 1.0f); + ensure("Did not take too long", (elapsed < 4.0f)); + } + + template<> template<> + void fitness_test_object::test<4>() + { + LL_DEBUGS() << "fitness_test_object::test<4>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLIOFuzz> emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr<LLChainIOFactory> factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS + 1.80f); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS + 3.0f); + ensure("Did not take too long", (elapsed < DEFAULT_CHAIN_EXPIRY_SECS)); + } + + template<> template<> + void fitness_test_object::test<5>() + { + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLIOSleeper> sleeper_t; + sleeper_t* sleeper = new sleeper_t(new LLIOSleeper); + std::shared_ptr<LLChainIOFactory> factory(sleeper); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(1.0); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + auto count = mPump->runningChains(); + ensure_equals("server chain onboard", count, 1); + LL_DEBUGS() << "** Server is up." << LL_ENDL; + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + pump_loop(mPump,0.1f); + count = mPump->runningChains(); + ensure_equals("server chain onboard", count, 2); + LL_DEBUGS() << "** Client is connected." << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, 0.2f); + chain.clear(); + + // pump for a bit and make sure all 3 chains are running + pump_loop(mPump,0.1f); + count = mPump->runningChains(); + // ensure_equals("client chain onboard", count, 3); commented out because it fails frequently - appears to be timing sensitive + LL_DEBUGS() << "** request should have been sent." << LL_ENDL; + + // pump for long enough the the client socket closes, and the + // server socket should not be closed yet. + pump_loop(mPump,0.2f); + count = mPump->runningChains(); + ensure_equals("client chain timed out ", count, 2); + LL_DEBUGS() << "** client chain should be closed." << LL_ENDL; + + // At this point, the socket should be closed by the timeout + pump_loop(mPump,1.0f); + count = mPump->runningChains(); + ensure_equals("accepted socked close", count, 1); + LL_DEBUGS() << "** Sleeper should have timed out.." << LL_ENDL; + } +} + +/* +'asset_data':b(12100)"{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemID STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n" +*/ diff --git a/indra/llmessage/tests/llbuffer_test.cpp b/indra/llmessage/tests/llbuffer_test.cpp new file mode 100644 index 0000000000..330a4f288f --- /dev/null +++ b/indra/llmessage/tests/llbuffer_test.cpp @@ -0,0 +1,271 @@ +/** + * @file llbuffer_tut.cpp + * @author Adroit + * @date 2007-03 + * @brief llbuffer test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include <tut/tut.hpp> + +#include "linden_common.h" +#include "lltut.h" +#include "llbuffer.h" +#include "llerror.h" + + +namespace tut +{ + struct buffer + { + }; + + typedef test_group<buffer> buffer_t; + typedef buffer_t::object buffer_object_t; + tut::buffer_t tut_buffer("buffer"); + + template<> template<> + void buffer_object_t::test<1>() + { + LLChannelDescriptors channelDescriptors; + ensure("in() and out() functions Failed", (0 == channelDescriptors.in() && 1 == channelDescriptors.out())); + + S32 val = 50; + LLChannelDescriptors channelDescriptors1(val); + ensure("LLChannelDescriptors in() and out() functions Failed", (50 == channelDescriptors1.in() && 51 == channelDescriptors1.out())); + } + + template<> template<> + void buffer_object_t::test<2>() + { + LLSegment segment; + ensure("LLSegment get functions failed", (0 == segment.getChannel() && NULL == segment.data() && 0 == segment.size())); + segment.setChannel(50); + ensure_equals("LLSegment setChannel() function failed", segment.getChannel(), 50); + ensure("LLSegment isOnChannel() function failed", (true == segment.isOnChannel(50))); + } + + template<> template<> + void buffer_object_t::test<3>() + { + S32 channel = 30; + const char str[] = "SecondLife"; + S32 len = sizeof(str); + LLSegment segment(channel, (U8*)str, len); + ensure("LLSegment get functions failed", (30 == segment.getChannel() && len == segment.size() && (U8*)str == segment.data())); + ensure_memory_matches("LLSegment::data() failed", segment.data(), segment.size(), (U8*)str, len); + ensure("LLSegment isOnChannel() function failed", (true == segment.isOnChannel(channel))); + } + + template<> template<> + void buffer_object_t::test<4>() + { + S32 channel = 50; + S32 bigSize = 16384*2; + char str[] = "SecondLife"; + S32 smallSize = sizeof(str); + + LLSegment segment; + LLHeapBuffer buf; // use default size of DEFAULT_HEAP_BUFFER_SIZE = 16384 + + S32 requestSize; + + requestSize = 16384-1; + ensure("1. LLHeapBuffer createSegment failed", (true == buf.createSegment(channel, requestSize, segment)) && segment.size() == requestSize); + // second request for remainign 1 byte + + requestSize = 1; + ensure("2. LLHeapBuffer createSegment failed", (true == buf.createSegment(channel, requestSize, segment)) && segment.size() == requestSize); + + // it should fail now. + requestSize = 1; + ensure("3. LLHeapBuffer createSegment failed", (false == buf.createSegment(channel, requestSize, segment))); + + LLHeapBuffer buf1(bigSize); + + // requst for more than default size but less than total sizeit should fail now. + requestSize = 16384 + 1; + ensure("4. LLHeapBuffer createSegment failed", (true == buf1.createSegment(channel, requestSize, segment)) && segment.size() == requestSize); + + LLHeapBuffer buf2((U8*) str, smallSize); + requestSize = smallSize; + ensure("5. LLHeapBuffer createSegment failed", (true == buf2.createSegment(channel, requestSize, segment)) && segment.size() == requestSize && memcmp(segment.data(), (U8*) str, requestSize) == 0); + requestSize = smallSize+1; + ensure("6. LLHeapBuffer createSegment failed", (false == buf2.createSegment(channel, requestSize, segment))); + } + + //makeChannelConsumer() + template<> template<> + void buffer_object_t::test<5>() + { + LLChannelDescriptors inchannelDescriptors(20); + LLChannelDescriptors outchannelDescriptors = LLBufferArray::makeChannelConsumer(inchannelDescriptors); + ensure("LLBufferArray::makeChannelConsumer() function Failed", (21 == outchannelDescriptors.in())); + } + + template<> template<> + void buffer_object_t::test<6>() + { + LLBufferArray bufferArray; + const char array[] = "SecondLife"; + S32 len = static_cast<S32>(strlen(array)); + LLChannelDescriptors channelDescriptors = bufferArray.nextChannel(); + bufferArray.append(channelDescriptors.in(), (U8*)array, len); + S32 count = bufferArray.countAfter(channelDescriptors.in(), NULL); + ensure_equals("Appended size is:", count, len); + } + + //append() and prepend() + template<> template<> + void buffer_object_t::test<7>() + { + LLBufferArray bufferArray; + const char array[] = "SecondLife"; + S32 len = static_cast<S32>(strlen(array)); + const char array1[] = "LindenLabs"; + S32 len1 = static_cast<S32>(strlen(array1)); + + std::string str(array1); + str.append(array); + + LLChannelDescriptors channelDescriptors = bufferArray.nextChannel(); + bufferArray.append(channelDescriptors.in(), (U8*)array, len); + bufferArray.prepend(channelDescriptors.in(), (U8*)array1, len1); + char buf[100]; + S32 len2 = 20; + bufferArray.readAfter(channelDescriptors.in(), NULL, (U8*)buf, len2); + ensure_equals("readAfter length failed", len2, 20); + + buf[len2] = '\0'; + ensure_equals("readAfter/prepend/append failed", buf, str); + } + + //append() + template<> template<> + void buffer_object_t::test<8>() + { + LLBufferArray bufferArray; + const char array[] = "SecondLife"; + S32 len = static_cast<S32>(strlen(array)); + const char array1[] = "LindenLabs"; + S32 len1 = static_cast<S32>(strlen(array1)); + + std::string str(array); + str.append(array1); + + LLChannelDescriptors channelDescriptors = bufferArray.nextChannel(); + bufferArray.append(channelDescriptors.in(), (U8*)array, len); + bufferArray.append(channelDescriptors.in(), (U8*)array1, len1); + char buf[100]; + S32 len2 = 20; + bufferArray.readAfter(channelDescriptors.in(), NULL, (U8*)buf, len2); + ensure_equals("readAfter length failed", len2, 20); + + buf[len2] = '\0'; + ensure_equals("readAfter/append/append failed", buf, str); + } + + template<> template<> + void buffer_object_t::test<9>() + { + LLBufferArray bufferArray; + const char array[] = "SecondLife"; + S32 len = static_cast<S32>(strlen(array)) + 1; + std::string str(array); + LLChannelDescriptors channelDescriptors = bufferArray.nextChannel(); + bufferArray.append(channelDescriptors.in(), (U8*)array, len); + LLBufferArray bufferArray1; + ensure("Contents are not copied and the source buffer is not empty", (1 == bufferArray1.takeContents(bufferArray))); + + char buf[100]; + S32 len2 = len; + bufferArray1.readAfter(channelDescriptors.in(), NULL, (U8*)buf, len2); + ensure_equals("takeContents failed to copy", buf, str); + } + + //seek() + template<> template<> + void buffer_object_t::test<10>() + { + const char array[] = "SecondLife is a Virtual World"; + S32 len = static_cast<S32>(strlen(array)); + LLBufferArray bufferArray; + bufferArray.append(0, (U8*)array, len); + + char buf[255]; + S32 len1 = 16; + U8* last = bufferArray.readAfter(0, 0, (U8*)buf, len1); + buf[len1] = '\0'; + last = bufferArray.seek(0, last, -2); + + len1 = 15; + last = bufferArray.readAfter(0, last, (U8*)buf, len1); + buf[len1] = '\0'; + std::string str(buf); + ensure_equals("Seek does'nt worked", str, std::string("a Virtual World")); + } + + template<> template<> + void buffer_object_t::test<11>() + { + const char array[] = "SecondLife is a Virtual World"; + S32 len = static_cast<S32>(strlen(array)); + LLBufferArray bufferArray; + bufferArray.append(0, (U8*)array, len); + + char buf[255]; + S32 len1 = 10; + U8* last = bufferArray.readAfter(0, 0, (U8*)buf, len1); + bufferArray.splitAfter(last); + LLBufferArray::segment_iterator_t iterator = bufferArray.beginSegment(); + ++iterator; + std::string str(((char*)(*iterator).data()), (*iterator).size()); + ensure_equals("Strings are not equal;splitAfter() operation failed", str, std::string(" is a Virtual World")); + } + + //makeSegment()->eraseSegment() + template<> template<> + void buffer_object_t::test<12>() + { + LLBufferArray bufferArray; + LLChannelDescriptors channelDescriptors; + LLBufferArray::segment_iterator_t it; + S32 length = 1000; + it = bufferArray.makeSegment(channelDescriptors.out(), length); + ensure("makeSegment() function failed", (it != bufferArray.endSegment())); + ensure("eraseSegment() function failed", bufferArray.eraseSegment(it)); + ensure("eraseSegment() begin/end should now be same", bufferArray.beginSegment() == bufferArray.endSegment()); + } + + // constructSegmentAfter() + template<> template<> + void buffer_object_t::test<13>() + { + LLBufferArray bufferArray; + LLBufferArray::segment_iterator_t it; + LLSegment segment; + LLBufferArray::segment_iterator_t end = bufferArray.endSegment(); + it = bufferArray.constructSegmentAfter(NULL, segment); + ensure("constructSegmentAfter() function failed", (it == end)); + } +} diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp deleted file mode 100644 index 78c195580c..0000000000 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file llcurl_stub.cpp - * @brief stub class to allow unit testing - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_CURL_STUB_CPP -#define LL_CURL_STUB_CPP - - -#include "linden_common.h" -#include "llcurl.h" -#include "llhttpconstants.cpp" - -LLCurl::Responder::Responder() -{ -} - -void LLCurl::Responder::httpCompleted() -{ - if (isGoodStatus()) - { - httpSuccess(); - } - else - { - httpFailure(); - } -} - -void LLCurl::Responder::completedRaw(LLChannelDescriptors const&, - std::shared_ptr<LLBufferArray> const&) -{ -} - -void LLCurl::Responder::httpFailure() -{ -} - -LLCurl::Responder::~Responder () -{ -} - -void LLCurl::Responder::httpSuccess() -{ -} - -std::string LLCurl::Responder::dumpResponse() const -{ - return "dumpResponse()"; -} - -void LLCurl::Responder::successResult(const LLSD& content) -{ - setResult(HTTP_OK, "", content); - httpSuccess(); -} - -void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) -{ - setResult(status, reason, content); - httpFailure(); -} - - -void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content) -{ - setResult(status, reason, content); - httpCompleted(); -} - -void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) -{ - mStatus = status; - mReason = reason; - mContent = content; -} - -#endif diff --git a/indra/llmessage/tests/lldatapacker_test.cpp b/indra/llmessage/tests/lldatapacker_test.cpp new file mode 100644 index 0000000000..e4253ab140 --- /dev/null +++ b/indra/llmessage/tests/lldatapacker_test.cpp @@ -0,0 +1,572 @@ +/** + * @file lldatapacker_tut.cpp + * @author Adroit + * @date 2007-02 + * @brief LLDataPacker test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltut.h" + +#include "lldatapacker.h" +#include "v4color.h" +#include "v4coloru.h" +#include "v2math.h" +#include "v3math.h" +#include "v4math.h" +#include "llsdserialize.h" + +#define TEST_FILE_NAME "datapacker_test.txt" + +namespace tut +{ + struct datapacker_test + { + }; + typedef test_group<datapacker_test> datapacker_test_t; + typedef datapacker_test_t::object datapacker_test_object_t; + tut::datapacker_test_t tut_datapacker_test("datapacker_test"); + + //*********LLDataPackerBinaryBuffer + template<> template<> + void datapacker_test_object_t::test<1>() + { + U8 packbuf[128]; + F32 f_val1 = 44.44f, f_unpkval1; + F32 f_val2 = 12344.443232f, f_unpkval2; + F32 f_val3 = 44.4456789f, f_unpkval3; + LLDataPackerBinaryBuffer lldp(packbuf,128); + lldp.packFixed( f_val1, "linden_lab", FALSE, 8, 8); + lldp.packFixed( f_val2, "linden_lab", FALSE, 14, 16); + lldp.packFixed( f_val3, "linden_lab", FALSE, 8, 23); + + LLDataPackerBinaryBuffer lldp1(packbuf, lldp.getCurrentSize()); + lldp1.unpackFixed(f_unpkval1, "linden_lab", FALSE, 8, 8); + lldp1.unpackFixed(f_unpkval2, "linden_lab", FALSE, 14, 16); + lldp1.unpackFixed(f_unpkval3, "linden_lab", FALSE, 8, 23); + ensure_approximately_equals("LLDataPackerBinaryBuffer::packFixed 8 failed", f_val1, f_unpkval1, 8); + ensure_approximately_equals("LLDataPackerBinaryBuffer::packFixed 16 failed", f_val2, f_unpkval2, 16); + ensure_approximately_equals("LLDataPackerBinaryBuffer::packFixed 23 failed", f_val3, f_unpkval3, 31); + } + + template<> template<> + void datapacker_test_object_t::test<2>() + { + U8 packbuf[1024]; + + char str[] = "SecondLife is virtual World\0"; + char strBinary[] = "SecondLife is virtual World"; + char strBinaryFixed[] = "Fixed Data"; + S32 sizeBinaryFixed = sizeof(strBinaryFixed); + U8 valU8 = 'C'; + U16 valU16 = 0xFFFF; + U32 valU32 = 0xFFFFFFFF; + S32 valS32 = -94967295; + F32 valF32 = 4354355.44f ; + LLColor4 llcol4(3.3f, 0, 4.4f, 5.5f); + LLColor4U llcol4u(3, 128, 24, 33); + LLVector2 llvec2(333.33f, 444.44f); + LLVector3 llvec3(333.33f, 444.44f, 555.55f); + LLVector4 llvec4(333.33f, 444.44f, 555.55f, 666.66f); + LLUUID uuid; + + std::string unpkstr; + char unpkstrBinary[256]; + char unpkstrBinaryFixed[256]; + S32 unpksizeBinary; + U8 unpkvalU8; + U16 unpkvalU16; + U32 unpkvalU32; + S32 unpkvalS32; + F32 unpkvalF32; + LLColor4 unpkllcol4; + LLColor4U unpkllcol4u; + LLVector2 unpkllvec2; + LLVector3 unpkllvec3; + LLVector4 unpkllvec4; + LLUUID unpkuuid; + + LLDataPackerBinaryBuffer lldp(packbuf,1024); + lldp.packString(str , "linden_lab_str"); + lldp.packBinaryData((U8*)strBinary, sizeof(strBinary), "linden_lab_bd"); + lldp.packBinaryDataFixed((U8*)strBinaryFixed, sizeBinaryFixed, "linden_lab_bdf"); + lldp.packU8(valU8,"linden_lab_u8"); + lldp.packU16(valU16,"linden_lab_u16"); + lldp.packU32(valU32, "linden_lab_u32"); + lldp.packS32(valS32, "linden_lab_s32"); + lldp.packF32(valF32, "linden_lab_f32"); + lldp.packColor4(llcol4, "linden_lab_col4"); + lldp.packColor4U(llcol4u, "linden_lab_col4u"); + lldp.packVector2(llvec2, "linden_lab_vec2"); + lldp.packVector3(llvec3, "linden_lab_vec3"); + lldp.packVector4(llvec4, "linden_lab_vec4"); + uuid.generate(); + lldp.packUUID(uuid, "linden_lab_uuid"); + + S32 cur_size = lldp.getCurrentSize(); + + LLDataPackerBinaryBuffer lldp1(packbuf, cur_size); + lldp1.unpackString(unpkstr , "linden_lab_str"); + lldp1.unpackBinaryData((U8*)unpkstrBinary, 256, unpksizeBinary, "linden_lab_bd"); + lldp1.unpackBinaryDataFixed((U8*)unpkstrBinaryFixed, sizeBinaryFixed, "linden_lab_bdf"); + lldp1.unpackU8(unpkvalU8,"linden_lab_u8"); + lldp1.unpackU16(unpkvalU16,"linden_lab_u16"); + lldp1.unpackU32(unpkvalU32, "linden_lab_u32"); + lldp1.unpackS32(unpkvalS32, "linden_lab_s32"); + lldp1.unpackF32(unpkvalF32, "linden_lab_f32"); + lldp1.unpackColor4(unpkllcol4, "linden_lab_col4"); + lldp1.unpackColor4U(unpkllcol4u, "linden_lab_col4u"); + lldp1.unpackVector2(unpkllvec2, "linden_lab_vec2"); + lldp1.unpackVector3(unpkllvec3, "linden_lab_vec3"); + lldp1.unpackVector4(unpkllvec4, "linden_lab_vec4"); + lldp1.unpackUUID(unpkuuid, "linden_lab_uuid"); + + ensure("LLDataPackerBinaryBuffer::packString failed", strcmp(str, unpkstr.c_str()) == 0); + ensure("LLDataPackerBinaryBuffer::packBinaryData failed", strcmp(strBinary, unpkstrBinary) == 0); + ensure("LLDataPackerBinaryBuffer::packBinaryDataFixed failed", strcmp(strBinaryFixed, unpkstrBinaryFixed) == 0); + ensure_equals("LLDataPackerBinaryBuffer::packU8 failed", valU8, unpkvalU8); + ensure_equals("LLDataPackerBinaryBuffer::packU16 failed", valU16, unpkvalU16); + ensure_equals("LLDataPackerBinaryBuffer::packU32 failed", valU32, unpkvalU32); + ensure_equals("LLDataPackerBinaryBuffer::packS32 failed", valS32, unpkvalS32); + ensure("LLDataPackerBinaryBuffer::packF32 failed", is_approx_equal(valF32, unpkvalF32)); + ensure_equals("LLDataPackerBinaryBuffer::packColor4 failed", llcol4, unpkllcol4); + ensure_equals("LLDataPackerBinaryBuffer::packColor4U failed", llcol4u, unpkllcol4u); + ensure_equals("LLDataPackerBinaryBuffer::packVector2 failed", llvec2, unpkllvec2); + ensure_equals("LLDataPackerBinaryBuffer::packVector3 failed", llvec3, unpkllvec3); + ensure_equals("LLDataPackerBinaryBuffer::packVector4 failed", llvec4, unpkllvec4); + ensure_equals("LLDataPackerBinaryBuffer::packUUID failed", uuid, unpkuuid); + } + + template<> template<> + void datapacker_test_object_t::test<3>() + { + U8 packbuf[128]; + char str[] = "SecondLife is virtual World"; + S32 strSize = sizeof(str); // include '\0' + LLDataPackerBinaryBuffer lldp(packbuf, 128); + lldp.packString(str , "linden_lab"); + + ensure("LLDataPackerBinaryBuffer: current size is wrong", strSize == lldp.getCurrentSize()); + ensure("LLDataPackerBinaryBuffer: buffer size is wrong", 128 == lldp.getBufferSize()); + + lldp.reset(); + ensure("LLDataPackerBinaryBuffer::reset failed",0 == lldp.getCurrentSize()); + } + + template<> template<> + void datapacker_test_object_t::test<4>() + { + U8* packbuf = new U8[128]; + char str[] = "SecondLife is virtual World"; + LLDataPackerBinaryBuffer lldp(packbuf, 128); + lldp.packString(str , "linden_lab"); + lldp.freeBuffer(); + ensure("LLDataPackerBinaryBuffer.freeBuffer failed" , 0 == lldp.getBufferSize()); + + } + + template<> template<> + void datapacker_test_object_t::test<5>() + { + U8* buf = new U8[]("SecondLife is virtual World"); + S32 size = sizeof(buf); + LLDataPackerBinaryBuffer lldp(buf, size); + U8* new_buf = new U8[]("Its Amazing"); + size = sizeof(new_buf)-1; + lldp.assignBuffer(new_buf, size); + ensure("LLDataPackerBinaryBuffer::assignBuffer failed" , ((lldp.getBufferSize() == size) && (0 == lldp.getCurrentSize()))) ; + } + + template<> template<> + void datapacker_test_object_t::test<6>() + { + U8 packbuf[128]; + char str[] = "SecondLife is virtual World"; + LLDataPackerBinaryBuffer lldp(packbuf, 128); + lldp.packString(str , "linden_lab"); + U8 new_buffer[128]; + std::string unpkbuf; + LLDataPackerBinaryBuffer lldp1(new_buffer,128); + lldp1 = lldp; + lldp1.unpackString(unpkbuf, "linden_lab"); + ensure("1. LLDataPackerBinaryBuffer::operator= failed" , lldp1.getBufferSize() == lldp.getBufferSize()); + ensure_equals("2.LLDataPackerBinaryBuffer::operator= failed", str,unpkbuf); + } + + //*********LLDataPackerAsciiBuffer + + template<> template<> + void datapacker_test_object_t::test<7>() + { + char packbuf[128]; + F32 f_val = 44.44f, f_unpkval; + LLDataPackerAsciiBuffer lldp(packbuf,128); + lldp.packFixed( f_val, "linden_lab", FALSE, 8, 8); + + LLDataPackerAsciiBuffer lldp1(packbuf, lldp.getCurrentSize()); + lldp1.unpackFixed(f_unpkval, "linden_lab", FALSE, 8, 8); + ensure_approximately_equals("LLDataPackerAsciiBuffer::packFixed failed", f_val, f_unpkval, 8); + } + + template<> template<> + void datapacker_test_object_t::test<8>() + { + char packbuf[1024]; + + char str[] = "SecondLife is virtual World\0"; + char strBinary[] = "SecondLife is virtual World"; + char strBinaryFixed[] = "Fixed Data"; + S32 sizeBinaryFixed = sizeof(strBinaryFixed); + U8 valU8 = 'C'; + U16 valU16 = 0xFFFF; + U32 valU32 = 0xFFFFFFFF; + S32 valS32 = -94967295; + F32 valF32 = 4354355.44f ; + LLColor4 llcol4(3.3f, 0, 4.4f, 5.5f); + LLColor4U llcol4u(3, 128, 24, 33); + LLVector2 llvec2(333.33f, 444.44f); + LLVector3 llvec3(333.33f, 444.44f, 555.55f); + LLVector4 llvec4(4354355.44f, 444.44f, 555.55f, 666.66f); + LLUUID uuid; + + std::string unpkstr; + char unpkstrBinary[256]; + char unpkstrBinaryFixed[256]; + S32 unpksizeBinary; + U8 unpkvalU8; + U16 unpkvalU16; + U32 unpkvalU32; + S32 unpkvalS32; + F32 unpkvalF32; + LLColor4 unpkllcol4; + LLColor4U unpkllcol4u; + LLVector2 unpkllvec2; + LLVector3 unpkllvec3; + LLVector4 unpkllvec4; + LLUUID unpkuuid; + + LLDataPackerAsciiBuffer lldp(packbuf,1024); + lldp.packString(str , "linden_lab_str"); + lldp.packBinaryData((U8*)strBinary, sizeof(strBinary), "linden_lab_bd"); + lldp.packBinaryDataFixed((U8*)strBinaryFixed, sizeBinaryFixed, "linden_lab_bdf"); + lldp.packU8(valU8,"linden_lab_u8"); + lldp.packU16(valU16,"linden_lab_u16"); + lldp.packU32(valU32, "linden_lab_u32"); + lldp.packS32(valS32, "linden_lab_s32"); + lldp.packF32(valF32, "linden_lab_f32"); + lldp.packColor4(llcol4, "linden_lab_col4"); + lldp.packColor4U(llcol4u, "linden_lab_col4u"); + lldp.packVector2(llvec2, "linden_lab_vec2"); + lldp.packVector3(llvec3, "linden_lab_vec3"); + lldp.packVector4(llvec4, "linden_lab_vec4"); + uuid.generate(); + lldp.packUUID(uuid, "linden_lab_uuid"); + + S32 cur_size = lldp.getCurrentSize(); + + LLDataPackerAsciiBuffer lldp1(packbuf, cur_size); + lldp1.unpackString(unpkstr , "linden_lab_str"); + lldp1.unpackBinaryData((U8*)unpkstrBinary, 256, unpksizeBinary, "linden_lab_bd"); + lldp1.unpackBinaryDataFixed((U8*)unpkstrBinaryFixed, sizeBinaryFixed, "linden_lab_bdf"); + lldp1.unpackU8(unpkvalU8,"linden_lab_u8"); + lldp1.unpackU16(unpkvalU16,"linden_lab_u16"); + lldp1.unpackU32(unpkvalU32, "linden_lab_u32"); + lldp1.unpackS32(unpkvalS32, "linden_lab_s32"); + lldp1.unpackF32(unpkvalF32, "linden_lab_f32"); + lldp1.unpackColor4(unpkllcol4, "linden_lab_col4"); + lldp1.unpackColor4U(unpkllcol4u, "linden_lab_col4u"); + lldp1.unpackVector2(unpkllvec2, "linden_lab_vec2"); + lldp1.unpackVector3(unpkllvec3, "linden_lab_vec3"); + lldp1.unpackVector4(unpkllvec4, "linden_lab_vec4"); + lldp1.unpackUUID(unpkuuid, "linden_lab_uuid"); + + ensure("LLDataPackerAsciiBuffer::packString failed", strcmp(str, unpkstr.c_str()) == 0); + ensure("LLDataPackerAsciiBuffer::packBinaryData failed", strcmp(strBinary, unpkstrBinary) == 0); + ensure("LLDataPackerAsciiBuffer::packBinaryDataFixed failed", strcmp(strBinaryFixed, unpkstrBinaryFixed) == 0); + ensure_equals("LLDataPackerAsciiBuffer::packU8 failed", valU8, unpkvalU8); + ensure_equals("LLDataPackerAsciiBuffer::packU16 failed", valU16, unpkvalU16); + ensure_equals("LLDataPackerAsciiBuffer::packU32 failed", valU32, unpkvalU32); + ensure_equals("LLDataPackerAsciiBuffer::packS32 failed", valS32, unpkvalS32); + ensure("LLDataPackerAsciiBuffer::packF32 failed", is_approx_equal(valF32, unpkvalF32)); + ensure_equals("LLDataPackerAsciiBuffer::packColor4 failed", llcol4, unpkllcol4); + ensure_equals("LLDataPackerAsciiBuffer::packColor4U failed", llcol4u, unpkllcol4u); + ensure_equals("LLDataPackerAsciiBuffer::packVector2 failed", llvec2, unpkllvec2); + ensure_equals("LLDataPackerAsciiBuffer::packVector3 failed", llvec3, unpkllvec3); + ensure_equals("LLDataPackerAsciiBuffer::packVector4 failed", llvec4, unpkllvec4); + ensure_equals("LLDataPackerAsciiBuffer::packUUID failed", uuid, unpkuuid); + } + + template<> template<> + void datapacker_test_object_t::test<9>() + { + char* packbuf = new char[128]; + char str[] = "SecondLife is virtual World"; + LLDataPackerAsciiBuffer lldp(packbuf, 128); + lldp.packString(str , "linden_lab"); + lldp.freeBuffer(); + ensure("LLDataPackerAsciiBuffer::freeBuffer failed" , 0 == lldp.getBufferSize()); + } + + template<> template<> + void datapacker_test_object_t::test<10>() + { + char buf[] = "SecondLife is virtual World"; + S32 size = sizeof(buf); + LLDataPackerAsciiBuffer lldp(buf, size); + char new_buf[] = "Its Amazing"; + size = sizeof(new_buf); + lldp.assignBuffer(new_buf, size); + ensure("LLDataPackerAsciiBuffer::assignBuffer failed" , ((lldp.getBufferSize() == size) && (1 == lldp.getCurrentSize()))) ; + } + + //*********LLDataPackerAsciiFile + + template<> template<> + void datapacker_test_object_t::test<11>() + { + F32 f_val = 44.44f, f_unpkval; + + LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, LLFILE_MODE("w+")); + if(!fp) + { + LL_ERRS() << "File couldnt be open" << LL_ENDL; + return; + } + + LLDataPackerAsciiFile lldp(fp,2); + lldp.packFixed( f_val, "linden_lab", FALSE, 8, 8); + + fflush(fp); + fseek(fp,0,SEEK_SET); + LLDataPackerAsciiFile lldp1(fp,2); + + lldp1.unpackFixed(f_unpkval, "linden_lab", FALSE, 8, 8); + fclose(fp); + + ensure_approximately_equals("LLDataPackerAsciiFile::packFixed failed", f_val, f_unpkval, 8); + } + + template<> template<> + void datapacker_test_object_t::test<12>() + { + char str[] = "SecondLife is virtual World\0"; + char strBinary[] = "SecondLife is virtual World"; + char strBinaryFixed[] = "Fixed Data"; + S32 sizeBinaryFixed = sizeof(strBinaryFixed); + U8 valU8 = 'C'; + U16 valU16 = 0xFFFF; + U32 valU32 = 0xFFFFFFFF; + S32 valS32 = -94967295; + F32 valF32 = 4354355.44f ; + LLColor4 llcol4(3.3f, 0, 4.4f, 5.5f); + LLColor4U llcol4u(3, 128, 24, 33); + LLVector2 llvec2(333.33f, 444.44f); + LLVector3 llvec3(333.33f, 444.44f, 555.55f); + LLVector4 llvec4(333.33f, 444.44f, 555.55f, 666.66f); + LLUUID uuid; + + std::string unpkstr; + char unpkstrBinary[256]; + char unpkstrBinaryFixed[256]; + S32 unpksizeBinary; + U8 unpkvalU8; + U16 unpkvalU16; + U32 unpkvalU32; + S32 unpkvalS32; + F32 unpkvalF32; + LLColor4 unpkllcol4; + LLColor4U unpkllcol4u; + LLVector2 unpkllvec2; + LLVector3 unpkllvec3; + LLVector4 unpkllvec4; + LLUUID unpkuuid; + + LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, LLFILE_MODE("w+")); + if(!fp) + { + LL_ERRS() << "File couldnt be open" << LL_ENDL; + return; + } + + LLDataPackerAsciiFile lldp(fp,2); + + lldp.packString(str , "linden_lab_str"); + lldp.packBinaryData((U8*)strBinary, sizeof(strBinary), "linden_lab_bd"); + lldp.packBinaryDataFixed((U8*)strBinaryFixed, sizeBinaryFixed, "linden_lab_bdf"); + lldp.packU8(valU8,"linden_lab_u8"); + lldp.packU16(valU16,"linden_lab_u16"); + lldp.packU32(valU32, "linden_lab_u32"); + lldp.packS32(valS32, "linden_lab_s32"); + lldp.packF32(valF32, "linden_lab_f32"); + lldp.packColor4(llcol4, "linden_lab_col4"); + lldp.packColor4U(llcol4u, "linden_lab_col4u"); + lldp.packVector2(llvec2, "linden_lab_vec2"); + lldp.packVector3(llvec3, "linden_lab_vec3"); + lldp.packVector4(llvec4, "linden_lab_vec4"); + uuid.generate(); + lldp.packUUID(uuid, "linden_lab_uuid"); + + fflush(fp); + fseek(fp,0,SEEK_SET); + LLDataPackerAsciiFile lldp1(fp,2); + + lldp1.unpackString(unpkstr , "linden_lab_str"); + lldp1.unpackBinaryData((U8*)unpkstrBinary, 256, unpksizeBinary, "linden_lab_bd"); + lldp1.unpackBinaryDataFixed((U8*)unpkstrBinaryFixed, sizeBinaryFixed, "linden_lab_bdf"); + lldp1.unpackU8(unpkvalU8,"linden_lab_u8"); + lldp1.unpackU16(unpkvalU16,"linden_lab_u16"); + lldp1.unpackU32(unpkvalU32, "linden_lab_u32"); + lldp1.unpackS32(unpkvalS32, "linden_lab_s32"); + lldp1.unpackF32(unpkvalF32, "linden_lab_f32"); + lldp1.unpackColor4(unpkllcol4, "linden_lab_col4"); + lldp1.unpackColor4U(unpkllcol4u, "linden_lab_col4u"); + lldp1.unpackVector2(unpkllvec2, "linden_lab_vec2"); + lldp1.unpackVector3(unpkllvec3, "linden_lab_vec3"); + lldp1.unpackVector4(unpkllvec4, "linden_lab_vec4"); + lldp1.unpackUUID(unpkuuid, "linden_lab_uuid"); + + fclose(fp); + + ensure("LLDataPackerAsciiFile::packString failed", strcmp(str, unpkstr.c_str()) == 0); + ensure("LLDataPackerAsciiFile::packBinaryData failed", strcmp(strBinary, unpkstrBinary) == 0); + ensure("LLDataPackerAsciiFile::packBinaryDataFixed failed", strcmp(strBinaryFixed, unpkstrBinaryFixed) == 0); + ensure_equals("LLDataPackerAsciiFile::packU8 failed", valU8, unpkvalU8); + ensure_equals("LLDataPackerAsciiFile::packU16 failed", valU16, unpkvalU16); + ensure_equals("LLDataPackerAsciiFile::packU32 failed", valU32, unpkvalU32); + ensure_equals("LLDataPackerAsciiFile::packS32 failed", valS32, unpkvalS32); + ensure("LLDataPackerAsciiFile::packF32 failed", is_approx_equal(valF32, unpkvalF32)); + ensure_equals("LLDataPackerAsciiFile::packColor4 failed", llcol4, unpkllcol4); + ensure_equals("LLDataPackerAsciiFile::packColor4U failed", llcol4u, unpkllcol4u); + ensure_equals("LLDataPackerAsciiFile::packVector2 failed", llvec2, unpkllvec2); + ensure_equals("LLDataPackerAsciiFile::packVector3 failed", llvec3, unpkllvec3); + ensure_equals("LLDataPackerAsciiFile::packVector4 failed", llvec4, unpkllvec4); + ensure_equals("LLDataPackerAsciiFile::packUUID failed", uuid, unpkuuid); + } + + template<> template<> + void datapacker_test_object_t::test<13>() + { + F32 f_val = 44.44f, f_unpkval; + + std::ostringstream ostr; + LLDataPackerAsciiFile lldp(ostr,2); + lldp.packFixed( f_val, "linden_lab", FALSE, 8, 8); + + std::istringstream istr(ostr.str()); + LLDataPackerAsciiFile lldp1(istr,2); + + lldp1.unpackFixed(f_unpkval, "linden_lab", FALSE, 8, 8); + + ensure_approximately_equals("LLDataPackerAsciiFile::packFixed (iostring) failed", f_val, f_unpkval, 8); + } + + template<> template<> + void datapacker_test_object_t::test<14>() + { + char str[] = "SecondLife is virtual World\0"; + char strBinary[] = "SecondLife is virtual World"; + char strBinaryFixed[] = "Fixed Data"; + S32 sizeBinaryFixed = sizeof(strBinaryFixed); + U8 valU8 = 'C'; + U16 valU16 = 0xFFFF; + U32 valU32 = 0xFFFFFFFF; + S32 valS32 = -94967295; + F32 valF32 = 4354355.44f ; + LLColor4 llcol4(3.3f, 0, 4.4f, 5.5f); + LLColor4U llcol4u(3, 128, 24, 33); + LLVector2 llvec2(3333333.33f, 444.333344f); + LLVector3 llvec3(3323233.33f, 444.4324f, 555.553232f); + LLVector4 llvec4(333.33233f, 444.4323234f, 55323225.55f, 6323236.66f); + LLUUID uuid; + + std::string unpkstr; + char unpkstrBinary[256]; + char unpkstrBinaryFixed[256]; + S32 unpksizeBinary; + U8 unpkvalU8; + U16 unpkvalU16; + U32 unpkvalU32; + S32 unpkvalS32; + F32 unpkvalF32; + LLColor4 unpkllcol4; + LLColor4U unpkllcol4u; + LLVector2 unpkllvec2; + LLVector3 unpkllvec3; + LLVector4 unpkllvec4; + LLUUID unpkuuid; + + std::ostringstream ostr; + LLDataPackerAsciiFile lldp(ostr,2); + + lldp.packString(str , "linden_lab_str"); + lldp.packBinaryData((U8*)strBinary, sizeof(strBinary), "linden_lab_bd"); + lldp.packBinaryDataFixed((U8*)strBinaryFixed, sizeBinaryFixed, "linden_lab_bdf"); + lldp.packU8(valU8,"linden_lab_u8"); + lldp.packU16(valU16,"linden_lab_u16"); + lldp.packU32(valU32, "linden_lab_u32"); + lldp.packS32(valS32, "linden_lab_s32"); + lldp.packF32(valF32, "linden_lab_f32"); + lldp.packColor4(llcol4, "linden_lab_col4"); + lldp.packColor4U(llcol4u, "linden_lab_col4u"); + lldp.packVector2(llvec2, "linden_lab_vec2"); + lldp.packVector3(llvec3, "linden_lab_vec3"); + lldp.packVector4(llvec4, "linden_lab_vec4"); + uuid.generate(); + lldp.packUUID(uuid, "linden_lab_uuid"); + + std::istringstream istr(ostr.str()); + LLDataPackerAsciiFile lldp1(istr,2); + + lldp1.unpackString(unpkstr , "linden_lab_str"); + lldp1.unpackBinaryData((U8*)unpkstrBinary, 256, unpksizeBinary, "linden_lab_bd"); + lldp1.unpackBinaryDataFixed((U8*)unpkstrBinaryFixed, sizeBinaryFixed, "linden_lab_bdf"); + lldp1.unpackU8(unpkvalU8,"linden_lab_u8"); + lldp1.unpackU16(unpkvalU16,"linden_lab_u16"); + lldp1.unpackU32(unpkvalU32, "linden_lab_u32"); + lldp1.unpackS32(unpkvalS32, "linden_lab_s32"); + lldp1.unpackF32(unpkvalF32, "linden_lab_f32"); + lldp1.unpackColor4(unpkllcol4, "linden_lab_col4"); + lldp1.unpackColor4U(unpkllcol4u, "linden_lab_col4u"); + lldp1.unpackVector2(unpkllvec2, "linden_lab_vec2"); + lldp1.unpackVector3(unpkllvec3, "linden_lab_vec3"); + lldp1.unpackVector4(unpkllvec4, "linden_lab_vec4"); + lldp1.unpackUUID(unpkuuid, "linden_lab_uuid"); + + ensure("LLDataPackerAsciiFile::packString (iostring) failed", strcmp(str, unpkstr.c_str()) == 0); + ensure("LLDataPackerAsciiFile::packBinaryData (iostring) failed", strcmp(strBinary, unpkstrBinary) == 0); + ensure("LLDataPackerAsciiFile::packBinaryDataFixed (iostring) failed", strcmp(strBinaryFixed, unpkstrBinaryFixed) == 0); + ensure_equals("LLDataPackerAsciiFile::packU8 (iostring) failed", valU8, unpkvalU8); + ensure_equals("LLDataPackerAsciiFile::packU16 (iostring) failed", valU16, unpkvalU16); + ensure_equals("LLDataPackerAsciiFile::packU32 (iostring) failed", valU32, unpkvalU32); + ensure_equals("LLDataPackerAsciiFile::packS32 (iostring) failed", valS32, unpkvalS32); + ensure("LLDataPackerAsciiFile::packF32 (iostring) failed", is_approx_equal(valF32, unpkvalF32)); + ensure_equals("LLDataPackerAsciiFile::packColor4 (iostring) failed", llcol4, unpkllcol4); + ensure_equals("LLDataPackerAsciiFile::packColor4U (iostring) failed", llcol4u, unpkllcol4u); + ensure_equals("LLDataPackerAsciiFile::packVector2 (iostring) failed", llvec2, unpkllvec2); + ensure_equals("LLDataPackerAsciiFile::packVector3 (iostring) failed", llvec3, unpkllvec3); + ensure_equals("LLDataPackerAsciiFile::packVector4 (iostring) failed", llvec4, unpkllvec4); + ensure_equals("LLDataPackerAsciiFile::packUUID (iostring) failed", uuid, unpkuuid); + } +} diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp deleted file mode 100644 index 1881144d3e..0000000000 --- a/indra/llmessage/tests/llhttpclient_test.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/** - * @file llhttpclient_test.cpp - * @brief Testing the HTTP client classes. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -/** - * - * These classes test the HTTP client framework. - * - */ - -#include <tut/tut.hpp> -#include "linden_common.h" - -#include "lltut.h" -#include "llhttpclient.h" -#include "llformat.h" -#include "llpipeutil.h" -#include "llproxy.h" -#include "llpumpio.h" - -#include "lliosocket.h" -#include "llstring.h" -#include "stringize.h" -#include "llcleanup.h" - -namespace tut -{ - struct HTTPClientTestData - { - public: - HTTPClientTestData(): - PORT(LLStringUtil::getenv("PORT")), - // Turning NULL PORT into empty string doesn't make things work; - // that's just to keep this initializer from blowing up. We test - // PORT separately in the constructor body. - local_server(STRINGIZE("http://127.0.0.1:" << PORT << "/")) - { - ensure("Set environment variable PORT to local test server port", !PORT.empty()); - apr_pool_create(&mPool, NULL); - LLCurl::initClass(false); - mClientPump = new LLPumpIO(mPool); - - LLHTTPClient::setPump(*mClientPump); - } - - ~HTTPClientTestData() - { - delete mClientPump; - SUBSYSTEM_CLEANUP(LLProxy); - apr_pool_destroy(mPool); - } - - void runThePump(float timeout = 100.0f) - { - LLTimer timer; - timer.setTimerExpirySec(timeout); - - while(!mSawCompleted && !mSawCompletedHeader && !timer.hasExpired()) - { - LLFrameTimer::updateFrameTime(); - if (mClientPump) - { - mClientPump->pump(); - mClientPump->callback(); - } - } - } - - const std::string PORT; - const std::string local_server; - - private: - apr_pool_t* mPool; - LLPumpIO* mClientPump; - - protected: - void ensureStatusOK() - { - if (mSawError) - { - std::string msg = - llformat("httpFailure() called when not expected, status %d", - mStatus); - fail(msg); - } - } - - void ensureStatusError() - { - if (!mSawError) - { - fail("httpFailure() wasn't called"); - } - } - - LLSD getResult() - { - return mResult; - } - LLSD getHeader() - { - return mHeader; - } - - protected: - bool mSawError; - U32 mStatus; - std::string mReason; - bool mSawCompleted; - bool mSawCompletedHeader; - LLSD mResult; - LLSD mHeader; - bool mResultDeleted; - - class Result : public LLHTTPClient::Responder - { - protected: - Result(HTTPClientTestData& client) - : mClient(client) - { - } - - public: - static Result* build(HTTPClientTestData& client) - { - return new Result(client); - } - - ~Result() - { - mClient.mResultDeleted = true; - } - - protected: - virtual void httpFailure() - { - mClient.mSawError = true; - mClient.mStatus = getStatus(); - mClient.mReason = getReason(); - } - - virtual void httpSuccess() - { - mClient.mResult = getContent(); - } - - virtual void httpCompleted() - { - LLHTTPClient::Responder::httpCompleted(); - - mClient.mSawCompleted = true; - mClient.mSawCompletedHeader = true; - mClient.mHeader = getResponseHeaders(); - } - - private: - HTTPClientTestData& mClient; - }; - - friend class Result; - - protected: - LLHTTPClient::ResponderPtr newResult() - { - mSawError = false; - mStatus = 0; - mSawCompleted = false; - mSawCompletedHeader = false; - mResult.clear(); - mHeader.clear(); - mResultDeleted = false; - - return Result::build(*this); - } - }; - - - typedef test_group<HTTPClientTestData> HTTPClientTestGroup; - typedef HTTPClientTestGroup::object HTTPClientTestObject; - HTTPClientTestGroup httpClientTestGroup("http_client"); - - template<> template<> - void HTTPClientTestObject::test<1>() - { - LLHTTPClient::get(local_server, newResult()); - runThePump(); - ensureStatusOK(); - ensure("result object wasn't destroyed", mResultDeleted); - } - - template<> template<> - void HTTPClientTestObject::test<2>() - { - // Please nobody listen on this particular port... - LLHTTPClient::get("http://127.0.0.1:7950", newResult()); - runThePump(); - ensureStatusError(); - } - - template<> template<> - void HTTPClientTestObject::test<3>() - { - LLSD sd; - - sd["list"][0]["one"] = 1; - sd["list"][0]["two"] = 2; - sd["list"][1]["three"] = 3; - sd["list"][1]["four"] = 4; - - LLHTTPClient::post(local_server + "web/echo", sd, newResult()); - runThePump(); - ensureStatusOK(); - ensure_equals("echoed result matches", getResult(), sd); - } - - template<> template<> - void HTTPClientTestObject::test<4>() - { - LLSD sd; - - sd["message"] = "This is my test message."; - - LLHTTPClient::put(local_server + "test/storage", sd, newResult()); - runThePump(); - ensureStatusOK(); - - LLHTTPClient::get(local_server + "test/storage", newResult()); - runThePump(); - ensureStatusOK(); - ensure_equals("echoed result matches", getResult(), sd); - - } - - template<> template<> - void HTTPClientTestObject::test<5>() - { - LLSD sd; - sd["status"] = 543; - sd["reason"] = "error for testing"; - - LLHTTPClient::post(local_server + "test/error", sd, newResult()); - runThePump(); - ensureStatusError(); - ensure_contains("reason", mReason, sd["reason"]); - } - - template<> template<> - void HTTPClientTestObject::test<6>() - { - const F32 timeout = 1.0f; - LLHTTPClient::get(local_server + "test/timeout", newResult(), LLSD(), timeout); - runThePump(timeout * 5.0f); - ensureStatusError(); - ensure_equals("reason", mReason, "STATUS_EXPIRED"); - } - - template<> template<> - void HTTPClientTestObject::test<7>() - { - LLHTTPClient::get(local_server, newResult()); - runThePump(); - ensureStatusOK(); - LLSD expected = getResult(); - - LLSD result; - result = LLHTTPClient::blockingGet(local_server); - LLSD body = result["body"]; - ensure_equals("echoed result matches", body.size(), expected.size()); - } - template<> template<> - void HTTPClientTestObject::test<8>() - { - // This is testing for the presence of the Header in the returned results - // from an HTTP::get call. - LLHTTPClient::get(local_server, newResult()); - runThePump(); - ensureStatusOK(); - LLSD header = getHeader(); - ensure("got a header", ! header.emptyMap().asBoolean()); - } - template<> template<> - void HTTPClientTestObject::test<9>() - { - LLHTTPClient::head(local_server, newResult()); - runThePump(); - ensureStatusOK(); - ensure("result object wasn't destroyed", mResultDeleted); - } -} diff --git a/indra/llmessage/tests/llhttpnode_test.cpp b/indra/llmessage/tests/llhttpnode_test.cpp new file mode 100644 index 0000000000..c38dee120b --- /dev/null +++ b/indra/llmessage/tests/llhttpnode_test.cpp @@ -0,0 +1,428 @@ +/** + * @file lliohttpnode_tut.cpp + * @date May 2006 + * @brief HTTP server unit tests + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" +#include "llhttpnode.h" +#include "llsdhttpserver.h" + +namespace tut +{ + struct HTTPNodeTestData + { + LLHTTPNode mRoot; + LLSD mContext; + + const LLSD& context() { return mContext; } + + std::string remainderPath() + { + std::ostringstream pathOutput; + bool addSlash = false; + + LLSD& remainder = mContext[CONTEXT_REQUEST]["remainder"]; + for (LLSD::array_const_iterator i = remainder.beginArray(); + i != remainder.endArray(); + ++i) + { + if (addSlash) { pathOutput << '/'; } + pathOutput << i->asString(); + addSlash = true; + } + + return pathOutput.str(); + } + + void ensureRootTraversal(const std::string& path, + const LLHTTPNode* expectedNode, + const char* expectedRemainder) + { + mContext.clear(); + + const LLHTTPNode* actualNode = mRoot.traverse(path, mContext); + + ensure_equals("traverse " + path + " node", + actualNode, expectedNode); + ensure_equals("traverse " + path + " remainder", + remainderPath(), expectedRemainder); + } + + class Response : public LLHTTPNode::Response + { + public: + static LLPointer<Response> create() {return new Response();} + + LLSD mResult; + + void result(const LLSD& result) { mResult = result; } + void status(S32 code, const std::string& message) { } + void extendedResult(S32 code, const std::string& message, const LLSD& headers) { } + void extendedResult(S32 code, const LLSD& result, const LLSD& headers) { } + + private: + Response() {;} // Must be accessed through LLPointer. + }; + + typedef LLPointer<Response> ResponsePtr; + + LLSD get(const std::string& path) + { + mContext.clear(); + const LLHTTPNode* node = mRoot.traverse(path, mContext); + ensure(path + " found", node != NULL); + + ResponsePtr response = Response::create(); + node->get(LLHTTPNode::ResponsePtr(response), mContext); + return response->mResult; + } + + LLSD post(const std::string& path, const LLSD& input) + { + mContext.clear(); + const LLHTTPNode* node = mRoot.traverse(path, mContext); + ensure(path + " found", node != NULL); + + ResponsePtr response = Response::create(); + node->post(LLHTTPNode::ResponsePtr(response), mContext, input); + return response->mResult; + } + + void ensureMemberString(const std::string& name, + const LLSD& actualMap, const std::string& member, + const std::string& expectedValue) + { + ensure_equals(name + " " + member, + actualMap[member].asString(), expectedValue); + } + + + void ensureInArray(const LLSD& actualArray, + const std::string& expectedValue) + { + LLSD::array_const_iterator i = actualArray.beginArray(); + LLSD::array_const_iterator end = actualArray.endArray(); + + for (; i != end; ++i) + { + std::string path = i->asString(); + + if (path == expectedValue) + { + return; + } + } + + fail("didn't find " + expectedValue); + } + + }; + + typedef test_group<HTTPNodeTestData> HTTPNodeTestGroup; + typedef HTTPNodeTestGroup::object HTTPNodeTestObject; + HTTPNodeTestGroup httpNodeTestGroup("http node"); + + template<> template<> + void HTTPNodeTestObject::test<1>() + { + // traversal of the lone node + + ensureRootTraversal("", &mRoot, ""); + ensureRootTraversal("/", &mRoot, ""); + ensureRootTraversal("foo", NULL, "foo"); + ensureRootTraversal("foo/bar", NULL, "foo/bar"); + + ensure_equals("root of root", mRoot.rootNode(), &mRoot); + } + + template<> template<> + void HTTPNodeTestObject::test<2>() + { + // simple traversal of a single node + + LLHTTPNode* helloNode = new LLHTTPNode; + mRoot.addNode("hello", helloNode); + + ensureRootTraversal("hello", helloNode, ""); + ensureRootTraversal("/hello", helloNode, ""); + ensureRootTraversal("hello/", helloNode, ""); + ensureRootTraversal("/hello/", helloNode, ""); + + ensureRootTraversal("hello/there", NULL, "there"); + + ensure_equals("root of hello", helloNode->rootNode(), &mRoot); + } + + template<> template<> + void HTTPNodeTestObject::test<3>() + { + // traversal of mutli-branched tree + + LLHTTPNode* greekNode = new LLHTTPNode; + LLHTTPNode* alphaNode = new LLHTTPNode; + LLHTTPNode* betaNode = new LLHTTPNode; + LLHTTPNode* gammaNode = new LLHTTPNode; + + greekNode->addNode("alpha", alphaNode); + greekNode->addNode("beta", betaNode); + greekNode->addNode("gamma", gammaNode); + mRoot.addNode("greek", greekNode); + + LLHTTPNode* hebrewNode = new LLHTTPNode; + LLHTTPNode* alephNode = new LLHTTPNode; + + hebrewNode->addNode("aleph", alephNode); + mRoot.addNode("hebrew", hebrewNode); + + ensureRootTraversal("greek/alpha", alphaNode, ""); + ensureRootTraversal("greek/beta", betaNode, ""); + ensureRootTraversal("greek/delta", NULL, "delta"); + ensureRootTraversal("greek/gamma", gammaNode, ""); + ensureRootTraversal("hebrew/aleph", alephNode, ""); + + ensure_equals("root of greek", greekNode->rootNode(), &mRoot); + ensure_equals("root of alpha", alphaNode->rootNode(), &mRoot); + ensure_equals("root of beta", betaNode->rootNode(), &mRoot); + ensure_equals("root of gamma", gammaNode->rootNode(), &mRoot); + ensure_equals("root of hebrew", hebrewNode->rootNode(), &mRoot); + ensure_equals("root of aleph", alephNode->rootNode(), &mRoot); + } + + template<> template<> + void HTTPNodeTestObject::test<4>() + { + // automatic creation of parent nodes and not overriding existing nodes + + LLHTTPNode* alphaNode = new LLHTTPNode; + LLHTTPNode* betaNode = new LLHTTPNode; + LLHTTPNode* gammaNode = new LLHTTPNode; + LLHTTPNode* gamma2Node = new LLHTTPNode; + + mRoot.addNode("greek/alpha", alphaNode); + mRoot.addNode("greek/beta", betaNode); + + mRoot.addNode("greek/gamma", gammaNode); + mRoot.addNode("greek/gamma", gamma2Node); + + LLHTTPNode* alephNode = new LLHTTPNode; + + mRoot.addNode("hebrew/aleph", alephNode); + + ensureRootTraversal("greek/alpha", alphaNode, ""); + ensureRootTraversal("greek/beta", betaNode, ""); + ensureRootTraversal("greek/delta", NULL, "delta"); + ensureRootTraversal("greek/gamma", gammaNode, ""); + ensureRootTraversal("hebrew/aleph", alephNode, ""); + + ensure_equals("root of alpha", alphaNode->rootNode(), &mRoot); + ensure_equals("root of beta", betaNode->rootNode(), &mRoot); + ensure_equals("root of gamma", gammaNode->rootNode(), &mRoot); + ensure_equals("root of aleph", alephNode->rootNode(), &mRoot); + } + + class IntegerNode : public LLHTTPNode + { + public: + virtual void get(ResponsePtr response, const LLSD& context) const + { + int n = context["extra"]["value"]; + + LLSD info; + info["value"] = n; + info["positive"] = n > 0; + info["zero"] = n == 0; + info["negative"] = n < 0; + + response->result(info); + } + + virtual bool validate(const std::string& name, LLSD& context) const + { + int n; + std::istringstream i_stream(name); + i_stream >> n; + + if (i_stream.fail() || i_stream.get() != EOF) + { + return false; + } + + context["extra"]["value"] = n; + return true; + } + }; + + class SquareNode : public LLHTTPNode + { + public: + virtual void get(ResponsePtr response, const LLSD& context) const + { + int n = context["extra"]["value"]; + response->result(n*n); + } + }; + + template<> template<> + void HTTPNodeTestObject::test<5>() + { + // wildcard nodes + + LLHTTPNode* miscNode = new LLHTTPNode; + LLHTTPNode* iNode = new IntegerNode; + LLHTTPNode* sqNode = new SquareNode; + + mRoot.addNode("test/misc", miscNode); + mRoot.addNode("test/<int>", iNode); + mRoot.addNode("test/<int>/square", sqNode); + + ensureRootTraversal("test/42", iNode, ""); + ensure_equals("stored integer", + context()["extra"]["value"].asInteger(), 42); + + ensureRootTraversal("test/bob", NULL, "bob"); + ensure("nothing stored", + context()["extra"]["value"].isUndefined()); + + ensureRootTraversal("test/3/square", sqNode, ""); + ResponsePtr response = Response::create(); + sqNode->get(LLHTTPNode::ResponsePtr(response), context()); + ensure_equals("square result", response->mResult.asInteger(), 9); + } + + class AlphaNode : public LLHTTPNode + { + public: + virtual bool handles(const LLSD& remainder, LLSD& context) const + { + LLSD::array_const_iterator i = remainder.beginArray(); + LLSD::array_const_iterator end = remainder.endArray(); + + for (; i != end; ++i) + { + std::string s = i->asString(); + if (s.empty() || s[0] != 'a') + { + return false; + } + } + + return true; + } + }; + + template<> template<> + void HTTPNodeTestObject::test<6>() + { + // nodes that handle remainders + + LLHTTPNode* miscNode = new LLHTTPNode; + LLHTTPNode* aNode = new AlphaNode; + LLHTTPNode* zNode = new LLHTTPNode; + + mRoot.addNode("test/misc", miscNode); + mRoot.addNode("test/alpha", aNode); + mRoot.addNode("test/alpha/zebra", zNode); + + ensureRootTraversal("test/alpha", aNode, ""); + ensureRootTraversal("test/alpha/abe", aNode, "abe"); + ensureRootTraversal("test/alpha/abe/amy", aNode, "abe/amy"); + ensureRootTraversal("test/alpha/abe/bea", NULL, "abe/bea"); + ensureRootTraversal("test/alpha/bob", NULL, "bob"); + ensureRootTraversal("test/alpha/zebra", zNode, ""); + } + + template<> template<> + void HTTPNodeTestObject::test<7>() + { + // test auto registration + + LLHTTPStandardServices::useServices(); + LLHTTPRegistrar::buildAllServices(mRoot); + + { + LLSD result = get("web/hello"); + ensure_equals("hello result", result.asString(), "hello"); + } + { + LLSD stuff = 3.14159; + LLSD result = post("web/echo", stuff); + ensure_equals("echo result", result, stuff); + } + } + + template<> template<> + void HTTPNodeTestObject::test<8>() + { + // test introspection + + LLHTTPRegistrar::buildAllServices(mRoot); + + mRoot.addNode("test/misc", new LLHTTPNode); + mRoot.addNode("test/<int>", new IntegerNode); + mRoot.addNode("test/<int>/square", new SquareNode); + + const LLSD result = get("web/server/api"); + + ensure("result is array", result.isArray()); + ensure("result size", result.size() >= 2); + + ensureInArray(result, "web/echo"); + ensureInArray(result, "web/hello"); + ensureInArray(result, "test/misc"); + ensureInArray(result, "test/<int>"); + ensureInArray(result, "test/<int>/square"); + } + + template<> template<> + void HTTPNodeTestObject::test<9>() + { + // test introspection details + + LLHTTPRegistrar::buildAllServices(mRoot); + + const LLSD helloDetails = get("web/server/api/web/hello"); + + ensure_contains("hello description", + helloDetails["description"].asString(), "hello"); + ensure_equals("method name", helloDetails["api"][0].asString(), std::string("GET")); + ensureMemberString("hello", helloDetails, "output", "\"hello\""); + ensure_contains("hello __file__", + helloDetails["__file__"].asString(), "llsdhttpserver.cpp"); + ensure("hello line", helloDetails["__line__"].isInteger()); + + + const LLSD echoDetails = get("web/server/api/web/echo"); + + ensure_contains("echo description", + echoDetails["description"].asString(), "echo"); + ensure_equals("method name", echoDetails["api"][0].asString(), std::string("POST")); + ensureMemberString("echo", echoDetails, "input", "<any>"); + ensureMemberString("echo", echoDetails, "output", "<the input>"); + ensure_contains("echo __file__", + echoDetails["__file__"].asString(), "llsdhttpserver.cpp"); + ensure("echo", echoDetails["__line__"].isInteger()); + } +} diff --git a/indra/llmessage/tests/lliohttpserver_test.cpp b/indra/llmessage/tests/lliohttpserver_test.cpp new file mode 100644 index 0000000000..7034f4a063 --- /dev/null +++ b/indra/llmessage/tests/lliohttpserver_test.cpp @@ -0,0 +1,350 @@ +/** + * @file lliohttpserver_tut.cpp + * @date May 2006 + * @brief HTTP server unit tests + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" +#include "llbufferstream.h" +#include "lliohttpserver.h" +#include "llsdhttpserver.h" +#include "llsdserialize.h" +#include "llcommon.h" + +#include "llpipeutil.h" + + +namespace tut +{ + class HTTPServiceTestData + { + public: + class DelayedEcho : public LLHTTPNode + { + HTTPServiceTestData* mTester; + + public: + DelayedEcho(HTTPServiceTestData* tester) : mTester(tester) { } + + void post(ResponsePtr response, const LLSD& context, const LLSD& input) const + { + ensure("response already set", mTester->mResponse == ResponsePtr(NULL)); + mTester->mResponse = response; + mTester->mResult = input; + } + }; + + class WireHello : public LLIOPipe + { + protected: + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) + { + if(!eos) return STATUS_BREAK; + LLSD sd = "yo!"; + LLBufferStream ostr(channels, buffer.get()); + ostr << LLSDXMLStreamer(sd); + return STATUS_DONE; + } + }; + + HTTPServiceTestData() + : mResponse(NULL) + { + LLHTTPStandardServices::useServices(); + LLHTTPRegistrar::buildAllServices(mRoot); + mRoot.addNode("/delayed/echo", new DelayedEcho(this)); + mRoot.addNode("/wire/hello", new LLHTTPNodeForPipe<WireHello>); + } + + ~HTTPServiceTestData() + { + } + + LLHTTPNode mRoot; + LLHTTPNode::ResponsePtr mResponse; + LLSD mResult; + + void pumpPipe(LLPumpIO* pump, S32 iterations) + { + while(iterations > 0) + { + pump->pump(); + pump->callback(); + --iterations; + } + } + + std::string makeRequest( + const std::string& name, + const std::string& httpRequest, + bool timeout = false) + { + LLPipeStringInjector* injector = new LLPipeStringInjector(httpRequest); + LLPipeStringExtractor* extractor = new LLPipeStringExtractor(); + + apr_pool_t* pool; + apr_pool_create(&pool, NULL); + + LLPumpIO* pump; + pump = new LLPumpIO(pool); + + LLPumpIO::chain_t chain; + LLSD context; + + chain.push_back(LLIOPipe::ptr_t(injector)); + LLIOHTTPServer::createPipe(chain, mRoot, LLSD()); + chain.push_back(LLIOPipe::ptr_t(extractor)); + + pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS); + + pumpPipe(pump, 10); + if(mResponse.notNull() && (! timeout)) + { + mResponse->result(mResult); + mResponse = NULL; + } + pumpPipe(pump, 10); + + std::string httpResult = extractor->string(); + + chain.clear(); + delete pump; + apr_pool_destroy(pool); + + if(mResponse.notNull() && timeout) + { + mResponse->result(mResult); + mResponse = NULL; + } + + return httpResult; + } + + std::string httpGET(const std::string& uri, + bool timeout = false) + { + std::string httpRequest = "GET " + uri + " HTTP/1.0\r\n\r\n"; + return makeRequest(uri, httpRequest, timeout); + } + + std::string httpPOST(const std::string& uri, + const std::string& body, + bool timeout, + const std::string& evilExtra = "") + { + std::ostringstream httpRequest; + httpRequest << "POST " + uri + " HTTP/1.0\r\n"; + httpRequest << "Content-Length: " << body.size() << "\r\n"; + httpRequest << "\r\n"; + httpRequest << body; + httpRequest << evilExtra; + + return makeRequest(uri, httpRequest.str(), timeout); + } + + std::string httpPOST(const std::string& uri, + const std::string& body, + const std::string& evilExtra = "") + { + bool timeout = false; + return httpPOST(uri, body, timeout, evilExtra); + } + }; + + typedef test_group<HTTPServiceTestData> HTTPServiceTestGroup; + typedef HTTPServiceTestGroup::object HTTPServiceTestObject; + HTTPServiceTestGroup httpServiceTestGroup("http service"); + + template<> template<> + void HTTPServiceTestObject::test<1>() + { + std::string result = httpGET("web/hello"); + + ensure_starts_with("web/hello status", result, + "HTTP/1.0 200 OK\r\n"); + + ensure_contains("web/hello content type", result, + "Content-Type: application/llsd+xml\r\n"); + + ensure_contains("web/hello content length", result, + "Content-Length: 36\r\n"); + + ensure_contains("web/hello content", result, + "\r\n" + "<llsd><string>hello</string></llsd>" + ); + } + + template<> template<> + void HTTPServiceTestObject::test<2>() + { + // test various HTTP errors + + std::string actual; + + actual = httpGET("web/missing"); + ensure_starts_with("web/missing 404", actual, + "HTTP/1.0 404 Not Found\r\n"); + + actual = httpGET("web/echo"); + ensure_starts_with("web/echo 405", actual, + "HTTP/1.0 405 Method Not Allowed\r\n"); + } + + template<> template<> + void HTTPServiceTestObject::test<3>() + { + // test POST & content-length handling + + std::string result; + + result = httpPOST("web/echo", + "<llsd><integer>42</integer></llsd>"); + + ensure_starts_with("web/echo status", result, + "HTTP/1.0 200 OK\r\n"); + + ensure_contains("web/echo content type", result, + "Content-Type: application/llsd+xml\r\n"); + + ensure_contains("web/echo content length", result, + "Content-Length: 35\r\n"); + + ensure_contains("web/hello content", result, + "\r\n" + "<llsd><integer>42</integer></llsd>" + ); + +/* TO DO: this test doesn't pass!! + + result = httpPOST("web/echo", + "<llsd><string>evil</string></llsd>", + "really! evil!!!"); + + ensure_equals("web/echo evil result", result, + "HTTP/1.0 200 OK\r\n" + "Content-Length: 34\r\n" + "\r\n" + "<llsd><string>evil</string></llsd>" + ); +*/ + } + + template<> template<> + void HTTPServiceTestObject::test<4>() + { + // test calling things based on pipes + + std::string result; + + result = httpGET("wire/hello"); + + ensure_contains("wire/hello", result, "yo!"); + } + + template<> template<> + void HTTPServiceTestObject::test<5>() + { + // test timeout before async response + std::string result; + + bool timeout = true; + result = httpPOST("delayed/echo", + "<llsd><string>agent99</string></llsd>", timeout); + + ensure_equals("timeout delayed/echo status", result, std::string("")); + } + + template<> template<> + void HTTPServiceTestObject::test<6>() + { + // test delayed service + std::string result; + + result = httpPOST("delayed/echo", + "<llsd><string>agent99</string></llsd>"); + + ensure_starts_with("delayed/echo status", result, + "HTTP/1.0 200 OK\r\n"); + + ensure_contains("delayed/echo content", result, + "\r\n" + "<llsd><string>agent99</string></llsd>" + ); + } + + template<> template<> + void HTTPServiceTestObject::test<7>() + { + // test large request + std::stringstream stream; + + //U32 size = 36 * 1024 * 1024; + //U32 size = 36 * 1024; + //std::vector<char> data(size); + //memset(&(data[0]), '1', size); + //data[size - 1] = '\0'; + + + //std::string result = httpPOST("web/echo", &(data[0])); + + stream << "<llsd><array>"; + for(U32 i = 0; i < 1000000; ++i) + { + stream << "<integer>42</integer>"; + } + stream << "</array></llsd>"; + LL_INFOS() << "HTTPServiceTestObject::test<7>" + << stream.str().length() << LL_ENDL; + std::string result = httpPOST("web/echo", stream.str()); + ensure_starts_with("large echo status", result, "HTTP/1.0 200 OK\r\n"); + } + + template<> template<> + void HTTPServiceTestObject::test<8>() + { + // test the OPTIONS http method -- the default implementation + // should return the X-Documentation-URL + std::ostringstream http_request; + http_request << "OPTIONS / HTTP/1.0\r\nHost: localhost\r\n\r\n"; + bool timeout = false; + std::string result = makeRequest("/", http_request.str(), timeout); + ensure_starts_with("OPTIONS verb ok", result, "HTTP/1.0 200 OK\r\n"); + ensure_contains( + "Doc url header exists", + result, + "X-Documentation-URL: http://localhost"); + } + + + /* TO DO: + test generation of not found and method not allowed errors + */ +} diff --git a/indra/llmessage/tests/llmessageconfig_test.cpp b/indra/llmessage/tests/llmessageconfig_test.cpp new file mode 100644 index 0000000000..b8942e99b3 --- /dev/null +++ b/indra/llmessage/tests/llmessageconfig_test.cpp @@ -0,0 +1,236 @@ +/** + * @file llmessageconfig_tut.cpp + * @date March 2007 + * @brief LLMessageConfig unit tests + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llmessageconfig.h" +#include "lltut.h" +#include "llsdserialize.h" +#include "llfile.h" +#include "lltimer.h" +#include "llframetimer.h" +#include "llsdutil.h" + +namespace tut +{ + struct LLMessageConfigTestData { + std::string mTestConfigDir; + + LLMessageConfigTestData() + { + LLUUID random; + random.generate(); + // generate temp dir + std::ostringstream oStr; +#if LL_WINDOWS + oStr << "llmessage-config-test-" << random; +#else + oStr << "/tmp/llmessage-config-test-" << random; +#endif + mTestConfigDir = oStr.str(); + LLFile::mkdir(mTestConfigDir); + writeConfigFile(LLSD()); + LLMessageConfig::initClass("simulator", mTestConfigDir); + } + + ~LLMessageConfigTestData() + { + // rm contents of temp dir + int rmfile = LLFile::remove((mTestConfigDir + "/message.xml")); + ensure_equals("rmfile value", rmfile, 0); + // rm temp dir + int rmdir = LLFile::remove(mTestConfigDir); + ensure_equals("rmdir value", rmdir, 0); + } + + void writeConfigFile(const LLSD& config) + { + llofstream file((mTestConfigDir + "/message.xml").c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(config, file); + } + file.close(); + } + }; + + typedef test_group<LLMessageConfigTestData> LLMessageConfigTestGroup; + typedef LLMessageConfigTestGroup::object LLMessageConfigTestObject; + LLMessageConfigTestGroup llMessageConfigTestGroup("LLMessageConfig"); + + template<> template<> + void LLMessageConfigTestObject::test<1>() + // tests server defaults + { + LLSD config; + config["serverDefaults"]["simulator"] = "template"; + LLMessageConfig::useConfig(config); + ensure_equals("Ensure server default is not template", + LLMessageConfig::getServerDefaultFlavor(), + LLMessageConfig::TEMPLATE_FLAVOR); + } + + template<> template<> + void LLMessageConfigTestObject::test<2>() + // tests message flavors + { + LLSD config; + config["serverDefaults"]["simulator"] = "template"; + config["messages"]["msg1"]["flavor"] = "template"; + config["messages"]["msg2"]["flavor"] = "llsd"; + LLMessageConfig::useConfig(config); + ensure_equals("Ensure msg template flavor", + LLMessageConfig::getMessageFlavor("msg1"), + LLMessageConfig::TEMPLATE_FLAVOR); + ensure_equals("Ensure msg llsd flavor", + LLMessageConfig::getMessageFlavor("msg2"), + LLMessageConfig::LLSD_FLAVOR); + } + + template<> template<> + void LLMessageConfigTestObject::test<4>() + // tests message flavor defaults + { + LLSD config; + config["serverDefaults"]["simulator"] = "llsd"; + config["messages"]["msg1"]["trusted-sender"] = true; + LLMessageConfig::useConfig(config); + ensure_equals("Ensure missing message gives no flavor", + LLMessageConfig::getMessageFlavor("Test"), + LLMessageConfig::NO_FLAVOR); + ensure_equals("Ensure missing flavor is NO_FLAVOR even with sender trustedness set", + LLMessageConfig::getMessageFlavor("msg1"), + LLMessageConfig::NO_FLAVOR); + ensure_equals("Ensure server default is llsd", + LLMessageConfig::getServerDefaultFlavor(), + LLMessageConfig::LLSD_FLAVOR); + } + + template<> template<> + void LLMessageConfigTestObject::test<3>() + // tests trusted/untrusted senders + { + LLSD config; + config["serverDefaults"]["simulator"] = "template"; + config["messages"]["msg1"]["flavor"] = "llsd"; + config["messages"]["msg1"]["trusted-sender"] = false; + config["messages"]["msg2"]["flavor"] = "llsd"; + config["messages"]["msg2"]["trusted-sender"] = true; + LLMessageConfig::useConfig(config); + ensure_equals("Ensure untrusted is untrusted", + LLMessageConfig::getSenderTrustedness("msg1"), + LLMessageConfig::UNTRUSTED); + ensure_equals("Ensure trusted is trusted", + LLMessageConfig::getSenderTrustedness("msg2"), + LLMessageConfig::TRUSTED); + ensure_equals("Ensure missing trustedness is NOT_SET", + LLMessageConfig::getSenderTrustedness("msg3"), + LLMessageConfig::NOT_SET); + } + + template<> template<> + void LLMessageConfigTestObject::test<5>() + // tests trusted/untrusted without flag, only flavor + { + LLSD config; + config["serverDefaults"]["simulator"] = "template"; + config["messages"]["msg1"]["flavor"] = "llsd"; + LLMessageConfig::useConfig(config); + ensure_equals("Ensure msg1 exists, has llsd flavor", + LLMessageConfig::getMessageFlavor("msg1"), + LLMessageConfig::LLSD_FLAVOR); + ensure_equals("Ensure missing trusted is not set", + LLMessageConfig::getSenderTrustedness("msg1"), + LLMessageConfig::NOT_SET); + } + + template<> template<> + void LLMessageConfigTestObject::test<6>() + { + LLSD config; + config["capBans"]["MapLayer"] = true; + config["capBans"]["MapLayerGod"] = false; + LLMessageConfig::useConfig(config); + ensure_equals("Ensure cap ban true MapLayer", + LLMessageConfig::isCapBanned("MapLayer"), + true); + ensure_equals("Ensure cap ban false", + LLMessageConfig::isCapBanned("MapLayerGod"), + false); + } + + template<> template<> + void LLMessageConfigTestObject::test<7>() + // tests that config changes are picked up/refreshed periodically + { + LLSD config; + config["serverDefaults"]["simulator"] = "llsd"; + writeConfigFile(config); + + // wait for it to reload after N seconds + ms_sleep(6*1000); + LLFrameTimer::updateFrameTime(); + ensure_equals("Ensure reload after 6 seconds", + LLMessageConfig::getServerDefaultFlavor(), + LLMessageConfig::LLSD_FLAVOR); + } + + template<> template<> + void LLMessageConfigTestObject::test<8>() + // tests that config changes are picked up/refreshed periodically + { + LLSD config; + config["serverDefaults"]["simulator"] = "template"; + config["messages"]["msg1"]["flavor"] = "llsd"; + config["messages"]["msg1"]["only-send-latest"] = true; + config["messages"]["msg2"]["flavor"] = "llsd"; + config["messages"]["msg2"]["only-send-latest"] = false; + LLMessageConfig::useConfig(config); + ensure_equals("Ensure msg1 exists, sent latest-only", + LLMessageConfig::onlySendLatest("msg1"), + true); + ensure_equals("Ensure msg2 exists, sent latest-only", + LLMessageConfig::onlySendLatest("msg2"), + false); + } + + template<> template<> + void LLMessageConfigTestObject::test<9>() + // tests that event queue max is reloaded + { + LLSD config; + config["maxQueuedEvents"] = 200; + LLMessageConfig::useConfig(config); + ensure_equals("Ensure setting maxQueuedEvents", + LLMessageConfig::getMaxQueuedEvents(), + 200); + + LLMessageConfig::useConfig(LLSD()); + ensure_equals("Ensure default of event queue max 100", + LLMessageConfig::getMaxQueuedEvents(), + 100); + } +} diff --git a/indra/llmessage/tests/llmessagetemplateparser_test.cpp b/indra/llmessage/tests/llmessagetemplateparser_test.cpp new file mode 100644 index 0000000000..f665fdde4d --- /dev/null +++ b/indra/llmessage/tests/llmessagetemplateparser_test.cpp @@ -0,0 +1,368 @@ +/** + * @file llmessagetemplateparser_tut.cpp + * @date April 2007 + * @brief LLMessageTemplateParser unit tests + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llmessagetemplateparser.h" +#include "lltut.h" + +namespace tut +{ + struct LLMessageTemplateParserTestData { + LLMessageTemplateParserTestData() : mMessage("unset message") + { + } + + ~LLMessageTemplateParserTestData() + { + } + + void ensure_next(LLTemplateTokenizer & tokens, + std::string value, + U32 line) + { + std::string next = tokens.next(); + ensure_equals(mMessage + " token matches", next, value); + ensure_equals(mMessage + " line matches", tokens.line(), line); + } + + char * prehash(const char * name) + { + return LLMessageStringTable::getInstance()->getString(name); + } + + void ensure_block_attributes(std::string identifier, + const LLMessageTemplate * message, + const char * name, + EMsgBlockType type, + S32 number, + S32 total_size) + { + const LLMessageBlock * block = message->getBlock(prehash(name)); + identifier = identifier + ":" + message->mName + ":" + name + " block"; + ensure(identifier + " exists", block != NULL); + ensure_equals(identifier + " name", block->mName, prehash(name)); + ensure_equals(identifier + " type", block->mType, type); + ensure_equals(identifier + " number", block->mNumber, number); + ensure_equals(identifier + " total size", block->mTotalSize, total_size); + } + + void ensure_variable_attributes(std::string identifier, + const LLMessageBlock * block, + const char * name, + EMsgVariableType type, + S32 size) + { + const LLMessageVariable * var = block->getVariable(prehash(name)); + identifier = identifier + ":" + block->mName + ":" + name + " variable"; + ensure(identifier + " exists", var != NULL); + ensure_equals( + identifier + " name", var->getName(), prehash(name)); + ensure_equals( + identifier + " type", var->getType(), type); + ensure_equals(identifier + " size", var->getSize(), size); + } + + std::string mMessage; + + }; + + typedef test_group<LLMessageTemplateParserTestData> LLMessageTemplateParserTestGroup; + typedef LLMessageTemplateParserTestGroup::object LLMessageTemplateParserTestObject; + LLMessageTemplateParserTestGroup llMessageTemplateParserTestGroup("LLMessageTemplateParser"); + + template<> template<> + void LLMessageTemplateParserTestObject::test<1>() + // tests tokenizer constructor and next methods + { + mMessage = "test method 1 walkthrough"; + LLTemplateTokenizer tokens("first line\nnext\t line\n\nfourth"); + ensure_next(tokens, "first", 1); + ensure_next(tokens, "line", 1); + ensure_next(tokens, "next", 2); + ensure_next(tokens, "line", 2); + ensure_next(tokens, "fourth", 4); + + tokens = LLTemplateTokenizer("\n\t{ \t Test1 Fixed \n 523 }\n\n"); + ensure(tokens.want("{")); + ensure_next(tokens, "Test1", 2); + ensure_next(tokens, "Fixed", 2); + ensure_next(tokens, "523", 3); + ensure(tokens.want("}")); + + tokens = LLTemplateTokenizer("first line\nnext\t line\n\nfourth"); + ensure(tokens.want("first")); + ensure_next(tokens, "line", 1); + ensure_next(tokens, "next", 2); + ensure_next(tokens, "line", 2); + ensure(tokens.want("fourth")); + } + + template<> template<> + void LLMessageTemplateParserTestObject::test<2>() + // tests tokenizer want method + { + // *NOTE: order matters + LLTemplateTokenizer tokens("first line\nnext\t line\n\nfourth"); + ensure_equals("wants first token", tokens.want("first"), true); + ensure_equals("doesn't want blar token", tokens.want("blar"), false); + ensure_equals("wants line token", tokens.want("line"), true); + } + + template<> template<> + void LLMessageTemplateParserTestObject::test<3>() + // tests tokenizer eof methods + { + LLTemplateTokenizer tokens("single\n\n"); + ensure_equals("is not at eof at beginning", tokens.atEOF(), false); + ensure_equals("doesn't want eof", tokens.wantEOF(), false); + ensure_equals("wants the first token just to consume it", + tokens.want("single"), true); + ensure_equals("is not at eof in middle", tokens.atEOF(), false); + ensure_equals("wants eof", tokens.wantEOF(), true); + ensure_equals("is at eof at end", tokens.atEOF(), true); + } + + template<> template<> + void LLMessageTemplateParserTestObject::test<4>() + // tests variable parsing method + { + LLTemplateTokenizer tokens(std::string("{ Test0 \n\t\n U32 \n\n }")); + LLMessageVariable * var = LLTemplateParser::parseVariable(tokens); + + ensure("test0 var parsed", var != 0); + ensure_equals("name of variable", std::string(var->getName()), std::string("Test0")); + ensure_equals("type of variable is U32", var->getType(), MVT_U32); + ensure_equals("size of variable", var->getSize(), 4); + + delete var; + + std::string message_string("\n\t{ \t Test1 Fixed \n 523 }\n\n"); + tokens = LLTemplateTokenizer(message_string); + var = LLTemplateParser::parseVariable(tokens); + + ensure("test1 var parsed", var != 0); + ensure_equals("name of variable", std::string(var->getName()), std::string("Test1")); + ensure_equals("type of variable is Fixed", var->getType(), MVT_FIXED); + ensure_equals("size of variable", var->getSize(), 523); + + delete var; + + // *NOTE: the parsers call LL_ERRS() on invalid input, so we can't really + // test that :-( + } + + template<> template<> + void LLMessageTemplateParserTestObject::test<5>() + // tests block parsing method + { + LLTemplateTokenizer tokens("{ BlockA Single { VarX F32 } }"); + LLMessageBlock * block = LLTemplateParser::parseBlock(tokens); + + ensure("blockA block parsed", block != 0); + ensure_equals("name of block", std::string(block->mName), std::string("BlockA")); + ensure_equals("type of block is Single", block->mType, MBT_SINGLE); + ensure_equals("total size of block", block->mTotalSize, 4); + ensure_equals("number of block defaults to 1", block->mNumber, 1); + ensure_equals("variable type of VarX is F32", + block->getVariableType(prehash("VarX")), MVT_F32); + ensure_equals("variable size of VarX", + block->getVariableSize(prehash("VarX")), 4); + + delete block; + + tokens = LLTemplateTokenizer("{ Stuff Variable { Id LLUUID } }"); + block = LLTemplateParser::parseBlock(tokens); + + ensure("stuff block parsed", block != 0); + ensure_equals("name of block", std::string(block->mName), std::string("Stuff")); + ensure_equals("type of block is Multiple", block->mType, MBT_VARIABLE); + ensure_equals("total size of block", block->mTotalSize, 16); + ensure_equals("number of block defaults to 1", block->mNumber, 1); + ensure_equals("variable type of Id is LLUUID", + block->getVariableType(prehash("Id")), MVT_LLUUID); + ensure_equals("variable size of Id", + block->getVariableSize(prehash("Id")), 16); + + delete block; + + tokens = LLTemplateTokenizer("{ Stuff2 Multiple 45 { Shid LLVector3d } }"); + block = LLTemplateParser::parseBlock(tokens); + + ensure("stuff2 block parsed", block != 0); + ensure_equals("name of block", std::string(block->mName), std::string("Stuff2")); + ensure_equals("type of block is Multiple", block->mType, MBT_MULTIPLE); + ensure_equals("total size of block", block->mTotalSize, 24); + ensure_equals("number of blocks", block->mNumber, 45); + ensure_equals("variable type of Shid is Vector3d", + block->getVariableType(prehash("Shid")), MVT_LLVector3d); + ensure_equals("variable size of Shid", + block->getVariableSize(prehash("Shid")), 24); + + delete block; + } + + template<> template<> + void LLMessageTemplateParserTestObject::test<6>() + // tests message parsing method on a simple message + { + std::string message_skel( + "{\n" + "TestMessage Low 1 NotTrusted Zerocoded\n" + "// comment \n" + " {\n" + "TestBlock1 Single\n" + " { Test1 U32 }\n" + " }\n" + " {\n" + " NeighborBlock Multiple 4\n" + " { Test0 U32 }\n" + " { Test1 U32 }\n" + " { Test2 U32 }\n" + " }\n" + "}"); + LLTemplateTokenizer tokens(message_skel); + LLMessageTemplate * message = LLTemplateParser::parseMessage(tokens); + + ensure("simple message parsed", message != 0); + ensure_equals("name of message", std::string(message->mName), std::string("TestMessage")); + ensure_equals("frequency is Low", message->mFrequency, MFT_LOW); + ensure_equals("trust is untrusted", message->mTrust, MT_NOTRUST); + ensure_equals("message number", message->mMessageNumber, (U32)((255 << 24) | (255 << 16) | 1)); + ensure_equals("message encoding is zerocoded", message->mEncoding, ME_ZEROCODED); + ensure_equals("message deprecation is notdeprecated", message->mDeprecation, MD_NOTDEPRECATED); + + LLMessageBlock * block = message->getBlock(prehash("NonexistantBlock")); + ensure("Nonexistant block does not exist", block == 0); + + delete message; + } + + template<> template<> + void LLMessageTemplateParserTestObject::test<7>() + // tests message parsing method on a deprecated message + { + std::string message_skel( + "{\n" + "TestMessageDeprecated High 34 Trusted Unencoded Deprecated\n" + " {\n" + "TestBlock2 Single\n" + " { Test2 S32 }\n" + " }\n" + "}"); + LLTemplateTokenizer tokens(message_skel); + LLMessageTemplate * message = LLTemplateParser::parseMessage(tokens); + + ensure("deprecated message parsed", message != 0); + ensure_equals("name of message", std::string(message->mName), std::string("TestMessageDeprecated")); + ensure_equals("frequency is High", message->mFrequency, MFT_HIGH); + ensure_equals("trust is trusted", message->mTrust, MT_TRUST); + ensure_equals("message number", message->mMessageNumber, (U32)34); + ensure_equals("message encoding is unencoded", message->mEncoding, ME_UNENCODED); + ensure_equals("message deprecation is deprecated", message->mDeprecation, MD_DEPRECATED); + + delete message; + } + + template<> template<> void LLMessageTemplateParserTestObject::test<8>() + // tests message parsing on RezMultipleAttachmentsFromInv, a possibly-faulty message + { + std::string message_skel( + "{\n\ + RezMultipleAttachmentsFromInv Low 452 NotTrusted Zerocoded\n\ + {\n\ + AgentData Single\n\ + { AgentID LLUUID }\n\ + { SessionID LLUUID }\n\ + } \n\ + {\n\ + HeaderData Single\n\ + { CompoundMsgID LLUUID } // All messages a single \"compound msg\" must have the same id\n\ + { TotalObjects U8 }\n\ + { FirstDetachAll BOOL }\n\ + }\n\ + {\n\ + ObjectData Variable // 1 to 4 of these per packet\n\ + { ItemID LLUUID }\n\ + { OwnerID LLUUID }\n\ + { AttachmentPt U8 } // 0 for default\n\ + { ItemFlags U32 }\n\ + { GroupMask U32 }\n\ + { EveryoneMask U32 }\n\ + { NextOwnerMask U32 }\n\ + { Name Variable 1 }\n\ + { Description Variable 1 }\n\ + }\n\ + }\n\ + "); + LLTemplateTokenizer tokens(message_skel); + LLMessageTemplate * message = LLTemplateParser::parseMessage(tokens); + + ensure("RezMultipleAttachmentsFromInv message parsed", message != 0); + ensure_equals("name of message", message->mName, prehash("RezMultipleAttachmentsFromInv")); + ensure_equals("frequency is low", message->mFrequency, MFT_LOW); + ensure_equals("trust is not trusted", message->mTrust, MT_NOTRUST); + ensure_equals("message number", message->mMessageNumber, (U32)((255 << 24) | (255 << 16) | 452)); + ensure_equals("message encoding is zerocoded", message->mEncoding, ME_ZEROCODED); + + ensure_block_attributes( + "RMAFI", message, "AgentData", MBT_SINGLE, 1, 16+16); + LLMessageBlock * block = message->getBlock(prehash("AgentData")); + ensure_variable_attributes("RMAFI", + block, "AgentID", MVT_LLUUID, 16); + ensure_variable_attributes("RMAFI", + block, "SessionID", MVT_LLUUID, 16); + + ensure_block_attributes( + "RMAFI", message, "HeaderData", MBT_SINGLE, 1, 16+1+1); + block = message->getBlock(prehash("HeaderData")); + ensure_variable_attributes( + "RMAFI", block, "CompoundMsgID", MVT_LLUUID, 16); + ensure_variable_attributes( + "RMAFI", block, "TotalObjects", MVT_U8, 1); + ensure_variable_attributes( + "RMAFI", block, "FirstDetachAll", MVT_BOOL, 1); + + + ensure_block_attributes( + "RMAFI", message, "ObjectData", MBT_VARIABLE, 1, -1); + block = message->getBlock(prehash("ObjectData")); + ensure_variable_attributes("RMAFI", block, "ItemID", MVT_LLUUID, 16); + ensure_variable_attributes("RMAFI", block, "OwnerID", MVT_LLUUID, 16); + ensure_variable_attributes("RMAFI", block, "AttachmentPt", MVT_U8, 1); + ensure_variable_attributes("RMAFI", block, "ItemFlags", MVT_U32, 4); + ensure_variable_attributes("RMAFI", block, "GroupMask", MVT_U32, 4); + ensure_variable_attributes("RMAFI", block, "EveryoneMask", MVT_U32, 4); + ensure_variable_attributes("RMAFI", block, "NextOwnerMask", MVT_U32, 4); + ensure_variable_attributes("RMAFI", block, "Name", MVT_VARIABLE, 1); + ensure_variable_attributes("RMAFI", block, "Description", MVT_VARIABLE, 1); + + delete message; + } + + + +} diff --git a/indra/llmessage/tests/llpipeutil.cpp b/indra/llmessage/tests/llpipeutil.cpp new file mode 100644 index 0000000000..1dd4bdfa3c --- /dev/null +++ b/indra/llmessage/tests/llpipeutil.cpp @@ -0,0 +1,183 @@ +/** + * @file llpipeutil.cpp + * @date 2006-05-18 + * @brief Utility pipe fittings for injecting and extracting strings + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "linden_common.h" +#include "llpipeutil.h" + +#include <stdlib.h> +#include <sstream> + +#include "llbufferstream.h" +#include "lldefs.h" +#include "llframetimer.h" +#include "llpumpio.h" +#include "llrand.h" +#include "lltimer.h" + +F32 pump_loop(LLPumpIO* pump, F32 seconds) +{ + LLTimer timer; + timer.setTimerExpirySec(seconds); + while(!timer.hasExpired()) + { + LLFrameTimer::updateFrameTime(); + pump->pump(); + pump->callback(); + } + return timer.getElapsedTimeF32(); +} + +//virtual +LLIOPipe::EStatus LLPipeStringInjector::process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) +{ + buffer->append(channels.out(), (U8*) mString.data(), static_cast<S32>(mString.size())); + eos = true; + return STATUS_DONE; +} + + +LLIOPipe::EStatus LLPipeStringExtractor::process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) +{ + if(!eos) return STATUS_BREAK; + if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET; + + LLBufferStream istr(channels, buffer.get()); + std::ostringstream ostr; + while (istr.good()) + { + char buf[1024]; /* Flawfinder: ignore */ + istr.read(buf, sizeof(buf)); /* Flawfinder: ignore */ + ostr.write(buf, istr.gcount()); + } + mString = ostr.str(); + mDone = true; + + return STATUS_DONE; +} + + +// virtual +LLIOPipe::EStatus LLIOFuzz::process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) +{ + while(mByteCount) + { + std::vector<U8> data; + data.reserve(10000); + int size = llmin(10000, mByteCount); + std::generate_n( + std::back_insert_iterator< std::vector<U8> >(data), + size, + rand); + buffer->append(channels.out(), &data[0], size); + mByteCount -= size; + } + return STATUS_OK; +} + +struct random_ascii_generator +{ + random_ascii_generator() {} + U8 operator()() + { + int rv = rand(); + rv %= (127 - 32); + rv += 32; + return rv; + } +}; + +// virtual +LLIOPipe::EStatus LLIOASCIIFuzz::process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) +{ + while(mByteCount) + { + std::vector<U8> data; + data.reserve(10000); + int size = llmin(10000, mByteCount); + std::generate_n( + std::back_insert_iterator< std::vector<U8> >(data), + size, + random_ascii_generator()); + buffer->append(channels.out(), &data[0], size); + mByteCount -= size; + } + return STATUS_OK; +} + +// virtual +LLIOPipe::EStatus LLIONull::process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) +{ + return STATUS_OK; +} + +// virtual +LLIOPipe::EStatus LLIOSleeper::process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) +{ + if(!mRespond) + { + LL_DEBUGS() << "LLIOSleeper::process_impl() sleeping." << LL_ENDL; + mRespond = true; + static const F64 SLEEP_TIME = 2.0; + pump->sleepChain(SLEEP_TIME); + return STATUS_BREAK; + } + LL_DEBUGS() << "LLIOSleeper::process_impl() responding." << LL_ENDL; + LLBufferStream ostr(channels, buffer.get()); + ostr << "huh? sorry, I was sleeping." << std::endl; + return STATUS_DONE; +} diff --git a/indra/llmessage/tests/llpipeutil.h b/indra/llmessage/tests/llpipeutil.h new file mode 100644 index 0000000000..97d9e1c85c --- /dev/null +++ b/indra/llmessage/tests/llpipeutil.h @@ -0,0 +1,163 @@ +/** + * @file llpipeutil.h + * @date 2006-05-18 + * @brief Utility pipe fittings for injecting and extracting strings + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPIPEUTIL_H +#define LL_LLPIPEUTIL_H + +#include "lliopipe.h" + + +/** + * @brief Simple function which pumps for the specified time. + */ +F32 pump_loop(LLPumpIO* pump, F32 seconds); + +/** + * @brief Simple class which writes a string and then marks the stream + * as done. + */ +class LLPipeStringInjector : public LLIOPipe +{ +public: + LLPipeStringInjector(const std::string& string) + : mString(string) + { } + +protected: + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + +private: + std::string mString; +}; + + +class LLPipeStringExtractor : public LLIOPipe +{ +public: + LLPipeStringExtractor() : mDone(false) { } + + bool done() { return mDone; } + std::string string() { return mString; } + +protected: + // LLIOPipe API implementation. + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + LLIOPipe::buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + +private: + bool mDone; + std::string mString; +}; + +/** + * @brief Generate a specified number of bytes of random data + */ +class LLIOFuzz : public LLIOPipe +{ +public: + LLIOFuzz(int byte_count) : mByteCount(byte_count) {} + +protected: + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + +private: + int mByteCount; +}; + +/** + * @brief Generate some ascii fuz + */ +class LLIOASCIIFuzz : public LLIOPipe +{ +public: + LLIOASCIIFuzz(int byte_count) : mByteCount(byte_count) {} + +protected: + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + +private: + int mByteCount; +}; + + +/** + * @brief Pipe that does nothing except return STATUS_OK + */ +class LLIONull : public LLIOPipe +{ +public: + LLIONull() {} + +protected: + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); +}; + +/** + * @brief Pipe that sleeps, and then responds later. + */ +class LLIOSleeper : public LLIOPipe +{ +public: + LLIOSleeper() : mRespond(false) {} + +protected: + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); +private: + bool mRespond; + +}; + +#endif // LL_LLPIPEUTIL_H diff --git a/indra/llmessage/tests/llsdmessagebuilder_test.cpp b/indra/llmessage/tests/llsdmessagebuilder_test.cpp new file mode 100644 index 0000000000..6804c3e29e --- /dev/null +++ b/indra/llmessage/tests/llsdmessagebuilder_test.cpp @@ -0,0 +1,837 @@ +/** + * @file llsdmessagebuilder_tut.cpp + * @date February 2006 + * @brief LLSDMessageBuilder unit tests + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include <tut/tut.hpp> + +#include "linden_common.h" +#include "lltut.h" +#include "llmessagetemplate.h" +#include "llsdmessagebuilder.h" +#include "llsdmessagereader.h" +#include "llsdtraits.h" +#include "llmath.h" +#include "llquaternion.h" +#include "u64.h" +#include "v3dmath.h" +#include "v3math.h" +#include "v4math.h" +#include "llsdutil.h" +//#include "llsdutil.cpp" +#include "llsdutil_math.cpp" +#include "lltemplatemessagebuilder.h" + +namespace tut +{ + static LLTemplateMessageBuilder::message_template_name_map_t templateNameMap; + + LLMsgData* messageData = NULL; + LLMsgBlkData* messageBlockData = NULL; + + struct LLSDMessageBuilderTestData { + + LLSDMessageBuilderTestData() + { + messageData = new LLMsgData("testMessage"); + messageBlockData = new LLMsgBlkData("testBlock", 0); + } + + static LLSDMessageBuilder defaultBuilder() + { + LLSDMessageBuilder builder; + builder.newMessage("name"); + builder.nextBlock("block"); + return builder; + } + + static LLSDMessageReader setReader(const LLSDMessageBuilder& builder) + { + LLSDMessageReader reader; + reader.setMessage("name", builder.getMessage()); + return reader; + } + + static void addValue(LLMsgBlkData* mbd, char* name, void* v, EMsgVariableType type, int size, int data_size = -1) + { + LLMsgVarData tmp(name, type); + tmp.addData(v, size, type, data_size); + mbd->mMemberVarData[name] = tmp; + } + + + static LLMessageBlock* defaultTemplateBlock(const EMsgVariableType type = MVT_NULL, const S32 size = 0, EMsgBlockType block = MBT_VARIABLE) + { + return createTemplateBlock(_PREHASH_Test0, type, size, block); + } + + static LLMessageBlock* createTemplateBlock(const char* name, const EMsgVariableType type = MVT_NULL, const S32 size = 0, EMsgBlockType block = MBT_VARIABLE) + { + LLMessageBlock* result = new LLMessageBlock(name, block); + if(type != MVT_NULL) + { + result->addVariable(const_cast<char*>(_PREHASH_Test0), type, size); + } + return result; + } + + static LLTemplateMessageBuilder* defaultTemplateBuilder(LLMessageTemplate& messageTemplate, char* name = const_cast<char*>(_PREHASH_Test0)) + { + templateNameMap[_PREHASH_TestMessage] = &messageTemplate; + LLTemplateMessageBuilder* builder = new LLTemplateMessageBuilder(templateNameMap); + builder->newMessage(_PREHASH_TestMessage); + builder->nextBlock(name); + return builder; + } + + static LLMessageTemplate defaultTemplate() + { + return LLMessageTemplate(_PREHASH_TestMessage, 1, MFT_HIGH); + } + }; + + typedef test_group<LLSDMessageBuilderTestData> LLSDMessageBuilderTestGroup; + typedef LLSDMessageBuilderTestGroup::object LLSDMessageBuilderTestObject; + LLSDMessageBuilderTestGroup llsdMessageBuilderTestGroup("LLSDMessageBuilder"); + + template<> template<> + void LLSDMessageBuilderTestObject::test<1>() + // construction and test of undefined + { + LLSDMessageBuilder builder = defaultBuilder(); + LLSDMessageReader reader = setReader(builder); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<2>() + // bool + { + bool outValue, inValue = true; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addBOOL("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getBOOL("block", "var", outValue); + ensure_equals("Ensure bool", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<3>() + // U8 + { + U8 outValue, inValue = 2; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addU8("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getU8("block", "var", outValue); + ensure_equals("Ensure U8", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<4>() + // S16 + { + S16 outValue, inValue = 90; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addS16("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getS16("block", "var", outValue); + ensure_equals("Ensure S16", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<5>() + // U16 + { + U16 outValue, inValue = 3; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addU16("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getU16("block", "var", outValue); + ensure_equals("Ensure U16", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<6>() + // S32 + { + S32 outValue, inValue = 44; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addS32("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getS32("block", "var", outValue); + ensure_equals("Ensure S32", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<7>() + // F32 + { + F32 outValue, inValue = 121.44f; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addF32("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getF32("block", "var", outValue); + ensure_equals("Ensure F32", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<8>() + // U32 + { + U32 outValue, inValue = 88; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addU32("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getU32("block", "var", outValue); + ensure_equals("Ensure U32", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<9>() + // U64 + { + U64 outValue, inValue = 121; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addU64("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getU64("block", "var", outValue); + ensure_equals("Ensure U64", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<10>() + // F64 + { + F64 outValue, inValue = 3232143.33; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addF64("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getF64("block", "var", outValue); + ensure_equals("Ensure F64", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<11>() + // Vector3 + { + LLVector3 outValue, inValue = LLVector3(1,2,3); + LLSDMessageBuilder builder = defaultBuilder(); + builder.addVector3("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getVector3("block", "var", outValue); + ensure_equals("Ensure Vector3", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<12>() + // Vector4 + { + LLVector4 outValue, inValue = LLVector4(1,2,3,4); + LLSDMessageBuilder builder = defaultBuilder(); + builder.addVector4("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getVector4("block", "var", outValue); + ensure_equals("Ensure Vector4", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<13>() + // Vector3d + { + LLVector3d outValue, inValue = LLVector3d(1,2,3); + LLSDMessageBuilder builder = defaultBuilder(); + builder.addVector3d("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getVector3d("block", "var", outValue); + ensure_equals("Ensure Vector3d", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<14>() + // Quaternion + { + LLQuaternion outValue, inValue = LLQuaternion(1,LLVector3(2,3,4)); + LLSDMessageBuilder builder = defaultBuilder(); + builder.addQuat("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getQuat("block", "var", outValue); + ensure_equals("Ensure Quaternion", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<15>() + // UUID + { + LLUUID outValue, inValue; + inValue.generate(); + LLSDMessageBuilder builder = defaultBuilder(); + builder.addUUID("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getUUID("block", "var", outValue); + ensure_equals("Ensure UUID", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<16>() + // IPAddr + { + U32 outValue, inValue = 12344556; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addIPAddr("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getIPAddr("block", "var", outValue); + ensure_equals("Ensure IPAddr", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<17>() + // IPPort + { + U16 outValue, inValue = 80; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addIPPort("var", inValue); + LLSDMessageReader reader = setReader(builder); + reader.getIPPort("block", "var", outValue); + ensure_equals("Ensure IPPort", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<18>() + { + std::string outValue, inValue = "testing"; + LLSDMessageBuilder builder = defaultBuilder(); + builder.addString("var", inValue.c_str()); + LLSDMessageReader reader = setReader(builder); + char buffer[MAX_STRING]; + reader.getString("block", "var", MAX_STRING, buffer); + outValue = buffer; + ensure_equals("Ensure String", inValue, outValue); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<19>() + { + LLMsgBlkData* mbd = new LLMsgBlkData("testBlock", 0); + LLMsgData* md = new LLMsgData("testMessage"); + md->addBlock(mbd); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*md); + LLSD output = builder.getMessage(); + + ensure("Ensure message block created when copied from legacy message to llsd", output["testBlock"].isDefined()); + } + + // MVT_FIXED + template<> template<> + void LLSDMessageBuilderTestObject::test<20>() + { + char binData[] = "abcdefghijklmnop"; + + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_FIXED, sizeof(binData)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + std::vector<U8> v = output["testBlock"][0]["testBinData"].asBinary(); + ensure("Ensure MVT_S16Array data copied from legacy to llsd give a valid vector", v.size() > 0); + + ensure_memory_matches("Ensure fixed binary data works in a message copied from legacy to llsd", + &v[0], sizeof(binData), binData, sizeof(binData)); + } + + // MVT_VARIABLE data_size 1 (U8's) + template<> template<> + void LLSDMessageBuilderTestObject::test<21>() + { + /* U8 binData[] = "abcdefghijklmnop"; + + addValue(messageBlockData, "testBinData", &binData, MVT_VARIABLE, sizeof(binData), 1); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + std::vector<U8> v = output["testBlock"][0]["testBinData"].asBinary(); + ensure("Ensure MVT_S16Array data copied from legacy to llsd give a valid vector", v.size() > 0); + + ensure_memory_matches("Ensure MVT_VARIABLE U8 binary data works in a message copied from legacy to llsd", + &v[0], sizeof(binData), binData, sizeof(binData));*/ + } + + // MVT_VARIABLE data_size 2 (U16's) + template<> template<> + void LLSDMessageBuilderTestObject::test<22>() + { + U16 binData[] = {1,2,3,4,5,6,7,8,9}; //9 shorts + + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 1, 2); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + std::vector<U8> v = output["testBlock"][0]["testBinData"].asBinary(); + ensure("Ensure MVT_S16Array data copied from legacy to llsd give a valid vector", v.size() > 0); + + ensure_memory_matches("Ensure MVT_VARIABLE U16 binary data works in a message copied from legacy to llsd", + &v[0], sizeof(binData) >> 1, binData, sizeof(binData) >> 1); + } + + // MVT_VARIABLE data_size 4 (S32's) + template<> template<> + void LLSDMessageBuilderTestObject::test<23>() + { + U32 binData[] = {9,8,7,6,5,4,3,2,1}; + + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 2, 4); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + std::vector<U8> v = output["testBlock"][0]["testBinData"].asBinary(); + ensure("Ensure MVT_S16Array data copied from legacy to llsd give a valid vector", v.size() > 0); + + ensure_memory_matches("Ensure MVT_VARIABLE S32 binary data works in a message copied from legacy to llsd", + &v[0], sizeof(binData) >> 2, binData, sizeof(binData) >> 2); + } + + // MVT_U8 + template<> template<> + void LLSDMessageBuilderTestObject::test<24>() + { + U8 data = 0xa5; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U8, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_U8 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asInteger(), data); + } + + // MVT_U16 + template<> template<> + void LLSDMessageBuilderTestObject::test<25>() + { + U16 data = 0xa55a; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_U16 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asInteger(), data); + } + + // MVT_U32 + template<> template<> + void LLSDMessageBuilderTestObject::test<26>() + { + U32 data = 0xa55a7117; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U32, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_U32 data works in a message copied from legacy to llsd", + ll_U32_from_sd(output["testBlock"][0]["testBinData"]), data); + } + + // MVT_U64 - crush into an s32: LLSD does not support 64 bit values + template<> template<> + void LLSDMessageBuilderTestObject::test<27>() + { + U64 data = U64L(0xa55a711711223344); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U64, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_U64 data works in a message copied from legacy to llsd", + ll_U64_from_sd(output["testBlock"][0]["testBinData"]), data); + } + + // MVT_S8 + template<> template<> + void LLSDMessageBuilderTestObject::test<28>() + { + S8 data = -31; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S8, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_S8 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asInteger(), data); + } + + // MVT_S16 + template<> template<> + void LLSDMessageBuilderTestObject::test<29>() + { + S16 data = -31; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S16, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_S16 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asInteger(), data); + } + + // MVT_S32 + template<> template<> + void LLSDMessageBuilderTestObject::test<30>() + { + S32 data = -3100; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S32, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_S32 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asInteger(), data); + } + + // MVT_S64 - crush into an s32: LLSD does not support 64 bit values + template<> template<> + void LLSDMessageBuilderTestObject::test<31>() + { + S64 data = -31003100; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S64, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_S64 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asInteger(), (S32)data); + } + + // MVT_F32 + template<> template<> + void LLSDMessageBuilderTestObject::test<32>() + { + F32 data = 1234.1234f; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_F32, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_F32 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asReal(), data); + } + + // MVT_F64 + template<> template<> + void LLSDMessageBuilderTestObject::test<33>() + { + F64 data = 1234.1234; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_F64, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_F64 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asReal(), data); + } + + // MVT_LLVector3 + template<> template<> + void LLSDMessageBuilderTestObject::test<34>() + { + LLVector3 data(1,2,3); + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector3, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_LLVector3 data works in a message copied from legacy to llsd", + ll_vector3_from_sd(output["testBlock"][0]["testBinData"]), data); + } + + // MVT_LLVector3d + template<> template<> + void LLSDMessageBuilderTestObject::test<35>() + { + LLVector3d data(1,2,3); + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector3d, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_LLVector3 data works in a message copied from legacy to llsd", + ll_vector3d_from_sd(output["testBlock"][0]["testBinData"]), data); + } + + // MVT_LLVector4 + template<> template<> + void LLSDMessageBuilderTestObject::test<36>() + { + LLVector4 data(1,2,3,4); + LLSD v = ll_sd_from_vector4(data); + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector4, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_LLVector4 data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"], v); + } + + // MVT_LLQuaternion + template<> template<> + void LLSDMessageBuilderTestObject::test<37>() + { + LLQuaternion data(0.3713907f, 0.5570861f, 0.7427813f,0.0f); + + //we send a quaternion packed into a vec3 (w is infered) - so sizeof(vec) == 12 bytes not 16. + LLVector3 vec = data.packToVector3(); + + addValue(messageBlockData, (char *)"testBinData", &vec, MVT_LLQuaternion, sizeof(vec)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_LLQuaternion data works in a message copied from legacy to llsd", + ll_quaternion_from_sd(output["testBlock"][0]["testBinData"]), data); + } + + // MVT_LLUUID + template<> template<> + void LLSDMessageBuilderTestObject::test<38>() + { + LLUUID data("01234567-0123-0123-0123-234567abcdef"); + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLUUID, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + std::string v = output["testBlock"][0]["testBinData"].asUUID().asString(); + + ensure_equals("Ensure MVT_LLUUID data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asUUID(), data); + } + + // MVT_BOOL + template<> template<> + void LLSDMessageBuilderTestObject::test<39>() + { + bool valueTrue = true; + bool valueFalse = false; + + LLMsgData* md = new LLMsgData("testMessage"); + LLMsgBlkData* mbd = new LLMsgBlkData("testBlock", 0); + addValue(mbd, (char *)"testBoolFalse", &valueFalse, MVT_BOOL, sizeof(bool)); + addValue(mbd, (char *)"testBoolTrue", &valueTrue, MVT_BOOL, sizeof(bool)); + md->addBlock(mbd); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*md); + LLSD output = builder.getMessage(); + + ensure("Ensure bools work in a message copied from legacy to llsd", + output["testBlock"][0]["testBoolTrue"].asBoolean() && !output["testBlock"][0]["testBoolFalse"].asBoolean()); + } + + // MVT_IP_ADDR + template<> template<> + void LLSDMessageBuilderTestObject::test<40>() + { + U32 data(0xff887766); + LLSD v = ll_sd_from_ipaddr(data); + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_IP_ADDR, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_IP_ADDR data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"], v); + } + + // MVT_IP_PORT + template<> template<> + void LLSDMessageBuilderTestObject::test<41>() + { + U16 data = 0xff88; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_IP_PORT, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + ensure_equals("Ensure MVT_IP_PORT data works in a message copied from legacy to llsd", + output["testBlock"][0]["testBinData"].asInteger(), data); + } + + // MVT_U16Vec3 + template<> template<> + void LLSDMessageBuilderTestObject::test<42>() + { + U16 data[3] = {0,1,2}; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16Vec3, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + std::vector<U8> v = output["testBlock"][0]["testBinData"].asBinary(); + ensure("Ensure MVT_U16Vec3 data copied from legacy to llsd give a valid vector", v.size() > 0); + + ensure_memory_matches("Ensure MVT_U16Vec3 data works in a message copied from legacy to llsd", + (U16*)&v[0], 6, data, 6); + } + + // MVT_U16Quat + template<> template<> + void LLSDMessageBuilderTestObject::test<43>() + { + U16 data[4] = {0,1,2,4}; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16Quat, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + std::vector<U8> v = output["testBlock"][0]["testBinData"].asBinary(); + ensure("Ensure MVT_U16Quat data copied from legacy to llsd give a valid vector", v.size() > 0); + + ensure_memory_matches("Ensure MVT_U16Quat data works in a message copied from legacy to llsd", + (U16*)&v[0], 8, data, 8); + } + + // MVT_S16Array + template<> template<> + void LLSDMessageBuilderTestObject::test<44>() + { + S16 data[19] = {0,-1,2,-4,5,-6,7,-8,9,-10,11,-12,13,-14,15,16,17,18}; + + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S16Array, sizeof(data)); + messageData->addBlock(messageBlockData); + LLSDMessageBuilder builder = defaultBuilder(); + + builder.copyFromMessageData(*messageData); + LLSD output = builder.getMessage(); + + std::vector<U8> v = output["testBlock"][0]["testBinData"].asBinary(); + ensure("Ensure MVT_S16Array data copied from legacy to llsd give a valid vector", v.size() > 0); + + ensure_memory_matches("Ensure MVT_S16Array data works in a message copied from legacy to llsd", + (U16*)&v[0], 19, data, 19); + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<45>() + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultTemplateBlock(MVT_U8, 1)); + U8 inValue = 2; + LLTemplateMessageBuilder* template_builder = defaultTemplateBuilder(messageTemplate); + template_builder->addU8(_PREHASH_Test0, inValue); + + LLSDMessageBuilder builder; + builder.copyFromMessageData(*template_builder->getCurrentMessage()); + LLSD output = builder.getMessage(); + + ensure_equals(output["Test0"][0]["Test0"].asInteger(), 2); + + } + + template<> template<> + void LLSDMessageBuilderTestObject::test<46>() + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultTemplateBlock(MVT_VARIABLE, 1)); + std::string inValue = "testing"; + LLTemplateMessageBuilder* builder = defaultTemplateBuilder(messageTemplate); + builder->addString(_PREHASH_Test0, inValue.c_str()); + + LLSDMessageBuilder sd_builder; + sd_builder.copyFromMessageData(*builder->getCurrentMessage()); + LLSD output = sd_builder.getMessage(); + + ensure_equals(output["Test0"][0]["Test0"].asString(), std::string("testing")); + } + +} + diff --git a/indra/llmessage/tests/llsdmessagereader_test.cpp b/indra/llmessage/tests/llsdmessagereader_test.cpp new file mode 100644 index 0000000000..dd6520ea33 --- /dev/null +++ b/indra/llmessage/tests/llsdmessagereader_test.cpp @@ -0,0 +1,324 @@ +/** + * @file llsdmessagereader_tut.cpp + * @date February 2006 + * @brief LLSDMessageReader unit tests + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include <tut/tut.hpp> +#include "linden_common.h" +#include "lltut.h" +#include "v3dmath.h" +#include "v3math.h" +#include "v4math.h" +#include "llquaternion.h" + +#include "message.h" +#include "llsdmessagereader.h" +#include "llsdutil.h" +#include "llsdutil_math.h" + +namespace tut +{ + struct LLSDMessageReaderTestData { + static void ensureMessageName(const std::string& msg_name, + const LLSD& msg_data, + const std::string& expected_name) + { + LLSDMessageReader msg; + msg.setMessage(LLMessageStringTable::getInstance()->getString(msg_name.c_str()), msg_data); + ensure_equals("Ensure name", std::string(msg.getMessageName()), + expected_name); + } + + static void ensureNumberOfBlocks(const LLSD& msg_data, + const std::string& block, + S32 expected_number) + { + LLSDMessageReader msg; + msg.setMessage("fakename", msg_data); + ensure_equals("Ensure number of blocks", msg.getNumberOfBlocks(block.c_str()), + expected_number); + } + + static void ensureMessageSize(const LLSD& msg_data, + S32 expected_size) + { + LLSDMessageReader msg; + msg.setMessage("fakename", msg_data); + ensure_equals( "Ensure size", msg.getMessageSize(), expected_size); + } + + static void ensureBool(const LLSD& msg_data, + const std::string& block, + const std::string& var, + S32 blocknum, + bool expected) + { + LLSDMessageReader msg; + msg.setMessage("fakename", msg_data); + bool test_data; + msg.getBOOL(block.c_str(), var.c_str(), test_data, blocknum); + ensure_equals( "Ensure bool field", test_data, expected); + } + }; + + typedef test_group<LLSDMessageReaderTestData> LLSDMessageReaderTestGroup; + typedef LLSDMessageReaderTestGroup::object LLSDMessageReaderTestObject; + LLSDMessageReaderTestGroup llsdMessageReaderTestGroup("LLSDMessageReader"); + + template<> template<> + void LLSDMessageReaderTestObject::test<1>() + // construction and test of empty LLSD + { + LLSD message = LLSD::emptyMap(); + + ensureMessageName("", message, ""); + ensureNumberOfBlocks(message, "Fakeblock", 0); + ensureMessageSize(message, 0); + } + + template<> template<> + void LLSDMessageReaderTestObject::test<2>() + // construction and test of simple message with one block + { + LLSD message = LLSD::emptyMap(); + message["block1"] = LLSD::emptyArray(); + message["block1"][0] = LLSD::emptyMap(); + message["block1"][0]["Field1"] = 0; + + ensureMessageName("name2", message, "name2"); + ensureNumberOfBlocks(message, "block1", 1); + ensureMessageSize(message, 0); + } + + template<> template<> + void LLSDMessageReaderTestObject::test<3>() + // multiple blocks + { + LLSD message = LLSD::emptyMap(); + message["block1"] = LLSD::emptyArray(); + bool bool_true = true; + bool bool_false = false; + message["block1"][0] = LLSD::emptyMap(); + message["block1"][0]["BoolField1"] = bool_true; + message["block1"][1] = LLSD::emptyMap(); + message["block1"][1]["BoolField1"] = bool_false; + message["block1"][1]["BoolField2"] = bool_true; + + ensureMessageName("name3", message, "name3"); + ensureBool(message, "block1", "BoolField1", 0, true); + ensureBool(message, "block1", "BoolField1", 1, false); + ensureBool(message, "block1", "BoolField2", 1, true); + ensureNumberOfBlocks(message, "block1", 2); + ensureMessageSize(message, 0); + } + + template<typename T> + LLSDMessageReader testType(const T& value) + { + LLSD message = LLSD::emptyMap(); + message["block"][0]["var"] = value; + LLSDMessageReader msg; + msg.setMessage("fakename", message); + return msg; + } + + template<> template<> + void LLSDMessageReaderTestObject::test<4>() + // S8 + { + S8 outValue, inValue = -3; + LLSDMessageReader msg = testType(inValue); + msg.getS8("block", "var", outValue); + ensure_equals("Ensure S8", outValue, inValue); + } + template<> template<> + void + LLSDMessageReaderTestObject::test<5>() + // U8 + { + U8 outValue, inValue = 2; + LLSDMessageReader msg = testType(inValue); + msg.getU8("block", "var", outValue); + ensure_equals("Ensure U8", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<6>() + // S16 + { + S16 outValue, inValue = 90; + LLSDMessageReader msg = testType(inValue); + msg.getS16("block", "var", outValue); + ensure_equals("Ensure S16", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<7>() + // U16 + { + U16 outValue, inValue = 3; + LLSDMessageReader msg = testType(inValue); + msg.getU16("block", "var", outValue); + ensure_equals("Ensure S16", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<8>() + // S32 + { + S32 outValue, inValue = 44; + LLSDMessageReader msg = testType(inValue); + msg.getS32("block", "var", outValue); + ensure_equals("Ensure S32", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<9>() + // F32 + { + F32 outValue, inValue = 121.44f; + LLSDMessageReader msg = testType(inValue); + msg.getF32("block", "var", outValue); + ensure_equals("Ensure F32", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<10>() + // U32 + { + U32 outValue, inValue = 88; + LLSD sdValue = ll_sd_from_U32(inValue); + LLSDMessageReader msg = testType(sdValue); + msg.getU32("block", "var", outValue); + ensure_equals("Ensure U32", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<11>() + // U64 + { + U64 outValue, inValue = 121; + LLSD sdValue = ll_sd_from_U64(inValue); + LLSDMessageReader msg = testType(sdValue); + msg.getU64("block", "var", outValue); + ensure_equals("Ensure U64", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<12>() + // F64 + { + F64 outValue, inValue = 3232143.33; + LLSDMessageReader msg = testType(inValue); + msg.getF64("block", "var", outValue); + ensure_equals("Ensure F64", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<13>() + // String + { + std::string outValue, inValue = "testing"; + LLSDMessageReader msg = testType<std::string>(inValue.c_str()); + + char buffer[MAX_STRING]; + msg.getString("block", "var", MAX_STRING, buffer); + outValue = buffer; + ensure_equals("Ensure String", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<14>() + // Vector3 + { + LLVector3 outValue, inValue = LLVector3(1,2,3); + LLSD sdValue = ll_sd_from_vector3(inValue); + LLSDMessageReader msg = testType(sdValue); + msg.getVector3("block", "var", outValue); + ensure_equals("Ensure Vector3", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<15>() + // Vector4 + { + LLVector4 outValue, inValue = LLVector4(1,2,3,4); + LLSD sdValue = ll_sd_from_vector4(inValue); + LLSDMessageReader msg = testType(sdValue); + msg.getVector4("block", "var", outValue); + ensure_equals("Ensure Vector4", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<16>() + // Vector3d + { + LLVector3d outValue, inValue = LLVector3d(1,2,3); + LLSD sdValue = ll_sd_from_vector3d(inValue); + LLSDMessageReader msg = testType(sdValue); + msg.getVector3d("block", "var", outValue); + ensure_equals("Ensure Vector3d", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<17>() + // Quaternion + { + LLQuaternion outValue, inValue = LLQuaternion(1,LLVector3(2,3,4)); + LLSD sdValue = ll_sd_from_quaternion(inValue); + LLSDMessageReader msg = testType(sdValue); + msg.getQuat("block", "var", outValue); + ensure_equals("Ensure Quaternion", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<18>() + // UUID + { + LLUUID outValue, inValue; + inValue.generate(); + LLSDMessageReader msg = testType(inValue); + msg.getUUID("block", "var", outValue); + ensure_equals("Ensure UUID", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<19>() + // IPAddr + { + U32 outValue, inValue = 12344556; + LLSD sdValue = ll_sd_from_ipaddr(inValue); + LLSDMessageReader msg = testType(sdValue); + msg.getIPAddr("block", "var", outValue); + ensure_equals("Ensure IPAddr", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<20>() + // IPPort + { + U16 outValue, inValue = 80; + LLSDMessageReader msg = testType(inValue); + msg.getIPPort("block", "var", outValue); + ensure_equals("Ensure IPPort", outValue, inValue); + } + template<> template<> + void LLSDMessageReaderTestObject::test<21>() + // Binary + { + std::vector<U8> outValue(2), inValue(2); + inValue[0] = 0; + inValue[1] = 1; + + LLSDMessageReader msg = testType(inValue); + msg.getBinaryData("block", "var", &(outValue[0]), static_cast<S32>(inValue.size())); + ensure_equals("Ensure Binary", outValue, inValue); + } +} diff --git a/indra/llmessage/tests/llservicebuilder_test.cpp b/indra/llmessage/tests/llservicebuilder_test.cpp new file mode 100644 index 0000000000..0bc17865d6 --- /dev/null +++ b/indra/llmessage/tests/llservicebuilder_test.cpp @@ -0,0 +1,173 @@ +/** +* @file llservicebuilder_tut.cpp +* @brief LLServiceBuilder unit tests +* @date March 2007 +* +* $LicenseInfo:firstyear=2006&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include <tut/tut.hpp> + +#include "linden_common.h" +#include "lltut.h" +#include "llsd.h" +#include "llservicebuilder.h" + +namespace tut +{ + + struct ServiceBuilderTestData { + LLServiceBuilder mServiceBuilder; + }; + + typedef test_group<ServiceBuilderTestData> ServiceBuilderTestGroup; + typedef ServiceBuilderTestGroup::object ServiceBuilderTestObject; + + ServiceBuilderTestGroup serviceBuilderTestGroup("ServiceBuilder"); + + template<> template<> + void ServiceBuilderTestObject::test<1>() + { + //Simple service build and reply with no mapping + LLSD test_block; + test_block["service-builder"] = "/agent/name"; + mServiceBuilder.createServiceDefinition("ServiceBuilderTest", test_block["service-builder"]); + std::string test_url = mServiceBuilder.buildServiceURI("ServiceBuilderTest"); + ensure_equals("Basic URL Creation", test_url , "/agent/name"); + } + + template<> template<> + void ServiceBuilderTestObject::test<2>() + { + //Simple replace test + LLSD test_block; + test_block["service-builder"] = "/agent/{$agent-id}/name"; + mServiceBuilder.createServiceDefinition("ServiceBuilderTest", test_block["service-builder"]); + LLSD data_map; + data_map["agent-id"] = "257c631f-a0c5-4f29-8a9f-9031feaae6c6"; + std::string test_url = mServiceBuilder.buildServiceURI("ServiceBuilderTest", data_map); + ensure_equals("Replacement URL Creation", test_url , "/agent/257c631f-a0c5-4f29-8a9f-9031feaae6c6/name"); + } + + template<> template<> + void ServiceBuilderTestObject::test<3>() + { + //Incorrect service test + LLSD test_block; + test_block["service-builder"] = "/agent/{$agent-id}/name"; + mServiceBuilder.createServiceDefinition("ServiceBuilderTest", test_block["service-builder"]); + std::string test_url = mServiceBuilder.buildServiceURI("ServiceBuilder"); + ensure_equals("Replacement URL Creation for Non-existant Service", test_url , ""); + } + + template<> template<> + void ServiceBuilderTestObject::test<4>() + { + //Incorrect service test + LLSD test_block; + test_block["service-builder"] = "/agent/{$agent-id}/name"; + mServiceBuilder.createServiceDefinition("ServiceBuilderTest", test_block["service-builder"]); + LLSD data_map; + data_map["agent_id"] = "257c631f-a0c5-4f29-8a9f-9031feaae6c6"; + std::string test_url = mServiceBuilder.buildServiceURI("ServiceBuilderTest", data_map); + ensure_equals("Replacement URL Creation for Non-existant Service", test_url , "/agent/{$agent-id}/name"); + } + + template<> template<> + void ServiceBuilderTestObject::test<5>() + { + LLSD test_block; + test_block["service-builder"] = "/proc/{$proc}{%params}"; + mServiceBuilder.createServiceDefinition("ServiceBuilderTest", test_block["service-builder"]); + LLSD data_map; + data_map["proc"] = "do/something/useful"; + data_map["params"]["estate_id"] = 1; + data_map["params"]["query"] = "public"; + std::string test_url = mServiceBuilder.buildServiceURI("ServiceBuilderTest", data_map); + ensure_equals( + "two part URL Creation", + test_url , + "/proc/do/something/useful?estate_id=1&query=public"); + } + + template<> template<> + void ServiceBuilderTestObject::test<6>() + { + LLSD test_block; + test_block["service-builder"] = "Which way to the {${$baz}}?"; + mServiceBuilder.createServiceDefinition( + "ServiceBuilderTest", + test_block["service-builder"]); + + LLSD data_map; + data_map["foo"] = "bar"; + data_map["baz"] = "foo"; + std::string test_url = mServiceBuilder.buildServiceURI( + "ServiceBuilderTest", + data_map); + ensure_equals( + "recursive url creation", + test_url , + "Which way to the bar?"); + } + + template<> template<> + void ServiceBuilderTestObject::test<7>() + { + LLSD test_block; + test_block["service-builder"] = "Which way to the {$foo}?"; + mServiceBuilder.createServiceDefinition( + "ServiceBuilderTest", + test_block["service-builder"]); + + LLSD data_map; + data_map["baz"] = "foo"; + std::string test_url = mServiceBuilder.buildServiceURI( + "ServiceBuilderTest", + data_map); + ensure_equals( + "fails to do replacement", + test_url , + "Which way to the {$foo}?"); + } + + template<> template<> + void ServiceBuilderTestObject::test<8>() + { + LLSD test_block; + test_block["service-builder"] = "/proc/{$proc}{%params}"; + mServiceBuilder.createServiceDefinition( + "ServiceBuilderTest", + test_block["service-builder"]); + LLSD data_map; + data_map["proc"] = "do/something/useful"; + data_map["params"] = LLSD(); + std::string test_url = mServiceBuilder.buildServiceURI( + "ServiceBuilderTest", + data_map); + ensure_equals( + "strip params", + test_url , + "/proc/do/something/useful"); + } +} + diff --git a/indra/llmessage/tests/lltemplatemessagebuilder_test.cpp b/indra/llmessage/tests/lltemplatemessagebuilder_test.cpp new file mode 100644 index 0000000000..ddf1c3dbcc --- /dev/null +++ b/indra/llmessage/tests/lltemplatemessagebuilder_test.cpp @@ -0,0 +1,971 @@ +/** + * @file lltemplatemessagebuilder_tut.cpp + * @date 2007-04 + * @brief Tests for building messages. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include <tut/tut.hpp> +#include "linden_common.h" +#include "lltut.h" + +#include "llapr.h" +#include "llmessagetemplate.h" +#include "llmath.h" +#include "llquaternion.h" +#include "lltemplatemessagebuilder.h" +#include "lltemplatemessagereader.h" +#include "message_prehash.h" +#include "u64.h" +#include "v3dmath.h" +#include "v3math.h" +#include "v4math.h" + +namespace tut +{ + static LLTemplateMessageBuilder::message_template_name_map_t nameMap; + static LLTemplateMessageReader::message_template_number_map_t numberMap; + + struct LLTemplateMessageBuilderTestData + { + static LLMessageTemplate defaultTemplate() + { + static bool init = false; + if(! init) + { + ll_init_apr(); + const F32 circuit_heartbeat_interval=5; + const F32 circuit_timeout=100; + + start_messaging_system("notafile", 13035, + 1, + 0, + 0, + false, + "notasharedsecret", + NULL, + false, + circuit_heartbeat_interval, + circuit_timeout); + //init_prehash_data(); + init = true; + } + return LLMessageTemplate(_PREHASH_TestMessage, 1, MFT_HIGH); + } + + static LLMessageBlock* defaultBlock(const EMsgVariableType type = MVT_NULL, const S32 size = 0, EMsgBlockType block = MBT_VARIABLE) + { + return createBlock(const_cast<char*>(_PREHASH_Test0), type, size, block); + } + + static LLMessageBlock* createBlock(char* name, const EMsgVariableType type = MVT_NULL, const S32 size = 0, EMsgBlockType block = MBT_VARIABLE) + { + LLMessageBlock* result = new LLMessageBlock(name, block); + if(type != MVT_NULL) + { + result->addVariable(const_cast<char*>(_PREHASH_Test0), type, size); + } + return result; + } + + static LLTemplateMessageBuilder* defaultBuilder(LLMessageTemplate& messageTemplate, char* name = const_cast<char*>(_PREHASH_Test0)) + { + nameMap[_PREHASH_TestMessage] = &messageTemplate; + LLTemplateMessageBuilder* builder = new LLTemplateMessageBuilder(nameMap); + builder->newMessage(_PREHASH_TestMessage); + builder->nextBlock(name); + return builder; + } + + /** Takes ownership of builder */ + static LLTemplateMessageReader* setReader( + LLMessageTemplate& messageTemplate, + LLTemplateMessageBuilder* builder, + U8 offset = 0) + { + numberMap[1] = &messageTemplate; + const U32 bufferSize = 1024; + U8 buffer[bufferSize]; + // zero out the packet ID field + memset(buffer, 0, LL_PACKET_ID_SIZE); + U32 builtSize = builder->buildMessage(buffer, bufferSize, offset); + delete builder; + LLTemplateMessageReader* reader = new LLTemplateMessageReader(numberMap); + reader->validateMessage(buffer, builtSize, LLHost()); + reader->readMessage(buffer, LLHost()); + return reader; + } + + }; + + typedef test_group<LLTemplateMessageBuilderTestData> LLTemplateMessageBuilderTestGroup; + typedef LLTemplateMessageBuilderTestGroup::object LLTemplateMessageBuilderTestObject; + LLTemplateMessageBuilderTestGroup templateMessageBuilderTestGroup("LLTemplateMessageBuilder"); + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<1>() + // construction and test of undefined + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock()); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<2>() + // bool + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_BOOL, 1)); + bool outValue, inValue = true; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addBOOL(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getBOOL(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure bool", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<3>() + // U8 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U8, 1)); + U8 outValue, inValue = 2; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU8(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getU8(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure U8", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<4>() + // S16 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_S16, 2)); + S16 outValue, inValue = 90; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addS16(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getS16(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure S16", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<5>() + // U16 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U16, 2)); + U16 outValue, inValue = 3; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU16(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getU16(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure U16", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<6>() + // S32 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_S32, 4)); + S32 outValue, inValue = 44; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addS32(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getS32(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure S32", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<7>() + // F32 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_F32, 4)); + F32 outValue, inValue = 121.44f; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addF32(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getF32(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure F32", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<8>() + // U32 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U32, 4)); + U32 outValue, inValue = 88; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU32(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure U32", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<9>() + // U64 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U64, 8)); + U64 outValue, inValue = 121; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU64(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getU64(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure U64", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<10>() + // F64 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_F64, 8)); + F64 outValue, inValue = 3232143.33; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addF64(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getF64(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure F64", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<11>() + // Vector3 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLVector3, 12)); + LLVector3 outValue, inValue = LLVector3(1,2,3); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addVector3(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getVector3(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure LLVector3", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<12>() + // Vector4 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLVector4, 16)); + LLVector4 outValue, inValue = LLVector4(1,2,3,4); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addVector4(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getVector4(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure LLVector4", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<13>() + // Vector3d + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLVector3d, 24)); + LLVector3d outValue, inValue = LLVector3d(1,2,3); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addVector3d(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getVector3d(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure LLVector3d", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<14>() + // Quaternion + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLQuaternion, 12)); + LLQuaternion outValue, inValue = LLQuaternion(0.0f, LLVector3(0.3713907f, 0.5570861f, 0.7427813f)); + + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addQuat(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getQuat(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure LLQuaternion", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<15>() + // UUID + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLUUID, 16)); + LLUUID outValue, inValue; + inValue.generate(); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addUUID(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getUUID(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure UUID", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<16>() + // IPAddr + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_IP_ADDR, 4)); + U32 outValue, inValue = 12344556; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addIPAddr(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getIPAddr(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure IPAddr", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<17>() + // IPPort + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_IP_PORT, 2)); + U16 outValue, inValue = 80; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addIPPort(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getIPPort(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure IPPort", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<18>() + // String + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_VARIABLE, 1)); + std::string outValue, inValue = "testing"; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addString(_PREHASH_Test0, inValue.c_str()); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + char buffer[MAX_STRING]; + reader->getString(_PREHASH_Test0, _PREHASH_Test0, MAX_STRING, buffer); + outValue = buffer; + ensure_equals("Ensure String", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<19>() + // block name !-> binary order + { + U8 buffer1[MAX_BUFFER_SIZE]; + memset(buffer1, 0, MAX_BUFFER_SIZE); + U8 buffer2[MAX_BUFFER_SIZE]; + memset(buffer2, 0, MAX_BUFFER_SIZE); + U32 bufferSize1, bufferSize2; + + // build template: Test0 before Test1 + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE)); + + // build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0)); + builder->addU32(_PREHASH_Test0, 0xaaaa); + builder->nextBlock(_PREHASH_Test1); + builder->addU32(_PREHASH_Test0, 0xbbbb); + bufferSize1 = builder->buildMessage(buffer1, MAX_BUFFER_SIZE, 0); + delete builder; + + // build template: Test1 before Test0 + messageTemplate = defaultTemplate(); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE)); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); + + // build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb + builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test1)); + builder->addU32(_PREHASH_Test0, 0xaaaa); + builder->nextBlock(_PREHASH_Test0); + builder->addU32(_PREHASH_Test0, 0xbbbb); + bufferSize2 = builder->buildMessage(buffer2, MAX_BUFFER_SIZE, 0); + delete builder; + + ensure_equals("Ensure Buffer Sizes Equal", bufferSize1, bufferSize2); + ensure_equals("Ensure Buffer Contents Equal", memcmp(buffer1, buffer2, bufferSize1), 0); + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<20>() + // block build order !-> binary order + { + U8 buffer1[MAX_BUFFER_SIZE]; + memset(buffer1, 0, MAX_BUFFER_SIZE); + U8 buffer2[MAX_BUFFER_SIZE]; + memset(buffer2, 0, MAX_BUFFER_SIZE); + U32 bufferSize1, bufferSize2; + + // build template: Test0 before Test1 + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE)); + + // build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0)); + builder->addU32(_PREHASH_Test0, 0xaaaa); + builder->nextBlock(_PREHASH_Test1); + builder->addU32(_PREHASH_Test0, 0xbbbb); + bufferSize1 = builder->buildMessage(buffer1, MAX_BUFFER_SIZE, 0); + delete builder; + + // build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb + builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test1)); + builder->addU32(_PREHASH_Test0, 0xbbbb); + builder->nextBlock(_PREHASH_Test0); + builder->addU32(_PREHASH_Test0, 0xaaaa); + bufferSize2 = builder->buildMessage(buffer2, MAX_BUFFER_SIZE, 0); + delete builder; + + ensure_equals("Ensure Buffer Sizes Equal", bufferSize1, bufferSize2); + ensure_equals("Ensure Buffer Contents Equal", memcmp(buffer1, buffer2, bufferSize1), 0); + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<21>() + // block appended in declaration -> data appended in binary + { + U8 buffer1[MAX_BUFFER_SIZE]; + memset(buffer1, 0, MAX_BUFFER_SIZE); + U8 buffer2[MAX_BUFFER_SIZE]; + memset(buffer2, 0, MAX_BUFFER_SIZE); + U32 bufferSize1, bufferSize2; + + // Build template: Test0 only + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); + + // Build message + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0)); + builder->addU32(_PREHASH_Test0, 0xaaaa); + bufferSize1 = builder->buildMessage(buffer1, MAX_BUFFER_SIZE, 0); + delete builder; + + // Build template: Test0 before Test1 + messageTemplate = defaultTemplate(); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE)); + + // Build message + builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0)); + builder->addU32(_PREHASH_Test0, 0xaaaa); + builder->nextBlock(_PREHASH_Test1); + builder->addU32(_PREHASH_Test0, 0xbbbb); + bufferSize2 = builder->buildMessage(buffer2, MAX_BUFFER_SIZE, 0); + delete builder; + + ensure_not_equals("Ensure Buffer Sizes Not Equal", bufferSize1, bufferSize2); + ensure_equals("Ensure Buffer Prefix Equal", memcmp(buffer1, buffer2, bufferSize1), 0); + ensure_not_equals("Ensure Buffer Contents Not Equal", memcmp(buffer1, buffer2, bufferSize2), 0); + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<22>() + // repeated penultimate block (crashes when data in LLDynamicArrayIndexed) + { + U32 inTest00 = 0, inTest01 = 1, inTest1 = 2; + U32 outTest00, outTest01, outTest1; + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4)); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4)); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU32(_PREHASH_Test0, inTest00); + builder->nextBlock(_PREHASH_Test0); + builder->addU32(_PREHASH_Test0, inTest01); + builder->nextBlock(_PREHASH_Test1); + builder->addU32(_PREHASH_Test0, inTest1); + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outTest00, 0); + reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outTest01, 1); + reader->getU32(_PREHASH_Test1, _PREHASH_Test0, outTest1); + ensure_equals("Ensure Test0[0]", inTest00, outTest00); + ensure_equals("Ensure Test0[1]", inTest01, outTest01); + ensure_equals("Ensure Test1", inTest1, outTest1); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<23>() + // variable repeated block name never accessed + { + U32 inTest = 1, outTest; + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock( + createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4)); + + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU32(_PREHASH_Test0, inTest); + + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outTest); + S32 blockCount = reader->getNumberOfBlocks(const_cast<char*>(_PREHASH_Test1)); + ensure_equals("Ensure block count", blockCount, 0); + ensure_equals("Ensure Test0", inTest, outTest); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<24>() + // forwarding message + { + // build template + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4)); + + // build message + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU32(_PREHASH_Test0, 42); + + // read message + LLTemplateMessageReader* reader = setReader(messageTemplate, builder); + + // forward message + builder = defaultBuilder(messageTemplate); + builder->newMessage(_PREHASH_TestMessage); + reader->copyToBuilder(*builder); + U8 buffer[MAX_BUFFER_SIZE]; + builder->buildMessage(buffer, MAX_BUFFER_SIZE, 0); + + delete builder; + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<25>() + // non-zero offset with undefined + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock()); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 10); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<26>() + // non-zero offset with bool + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_BOOL, 1)); + bool outValue, inValue = true; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addBOOL(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 1); + reader->getBOOL(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure bool", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<27>() + // non-zero offset with U8 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U8, 1)); + U8 outValue, inValue = 2; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU8(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 255); + reader->getU8(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure U8", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<28>() + // non-zero offset with S16 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_S16, 2)); + S16 outValue, inValue = 90; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addS16(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 2); + reader->getS16(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure S16", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<29>() + // non-zero offset with U16 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U16, 2)); + U16 outValue, inValue = 3; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU16(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 4); + reader->getU16(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure U16", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<30>() + // non-zero offset with S32 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_S32, 4)); + S32 outValue, inValue = 44; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addS32(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 4); + reader->getS32(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure S32", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<31>() + // non-zero offset with F32 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_F32, 4)); + F32 outValue, inValue = 121.44f; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addF32(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 16); + reader->getF32(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure F32", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<32>() + // non-zero offset with U32 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U32, 4)); + U32 outValue, inValue = 88; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU32(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 127); + reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure U32", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<33>() + // non-zero offset with U64 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U64, 8)); + U64 outValue, inValue = 121; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU64(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 32); + reader->getU64(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure U64", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<34>() + // non-zero offset with F64 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_F64, 8)); + F64 outValue, inValue = 3232143.33; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addF64(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 128); + reader->getF64(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure F64", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<35>() + // non-zero offset with Vector3 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLVector3, 12)); + LLVector3 outValue, inValue = LLVector3(1,2,3); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addVector3(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 63); + reader->getVector3(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure LLVector3", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<36>() + // non-zero offset with Vector4 + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLVector4, 16)); + LLVector4 outValue, inValue = LLVector4(1,2,3,4); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addVector4(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 64); + reader->getVector4(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure LLVector4", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<37>() + // non-zero offset with Vector3d + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLVector3d, 24)); + LLVector3d outValue, inValue = LLVector3d(1,2,3); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addVector3d(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 64); + reader->getVector3d(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure LLVector3d", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<38>() + // non-zero offset with Quaternion + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLQuaternion, 12)); + LLQuaternion outValue, inValue = LLQuaternion(0.0f, LLVector3(0.3713907f, 0.5570861f, 0.7427813f)); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addQuat(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 12); + reader->getQuat(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure LLQuaternion", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<39>() + // non-zero offset with UUID + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_LLUUID, 16)); + LLUUID outValue, inValue; + inValue.generate(); + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addUUID(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 31); + reader->getUUID(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure UUID", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<40>() + // non-zero offset with IPAddr + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_IP_ADDR, 4)); + U32 outValue, inValue = 12344556; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addIPAddr(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 32); + reader->getIPAddr(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure IPAddr", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<41>() + // non-zero offset with IPPort + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_IP_PORT, 2)); + U16 outValue, inValue = 80; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addIPPort(_PREHASH_Test0, inValue); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 6); + reader->getIPPort(_PREHASH_Test0, _PREHASH_Test0, outValue); + ensure_equals("Ensure IPPort", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<42>() + // non-zero offset with String + { + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_VARIABLE, 1)); + std::string outValue, inValue = "testing"; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addString(_PREHASH_Test0, inValue.c_str()); + LLTemplateMessageReader* reader = setReader( + messageTemplate, builder, 255); + char buffer[MAX_STRING]; + reader->getString(_PREHASH_Test0, _PREHASH_Test0, MAX_STRING, buffer); + outValue = buffer; + ensure_equals("Ensure String", inValue, outValue); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<43>() + // read past end of message -> default values (forward compatibility) + { + // build message with single block + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U32, 4, MBT_SINGLE)); + U32 outValue, outValue2, inValue = 0xbbbbbbbb; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU32(_PREHASH_Test0, inValue); + const U32 bufferSize = 1024; + U8 buffer[bufferSize]; + memset(buffer, 0xaa, bufferSize); + memset(buffer, 0, LL_PACKET_ID_SIZE); + U32 builtSize = builder->buildMessage(buffer, bufferSize, 0); + delete builder; + + // add block to reader template + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE)); + + // read message value and default value + numberMap[1] = &messageTemplate; + LLTemplateMessageReader* reader = + new LLTemplateMessageReader(numberMap); + reader->validateMessage(buffer, builtSize, LLHost()); + reader->readMessage(buffer, LLHost()); + reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outValue); + reader->getU32(_PREHASH_Test1, _PREHASH_Test0, outValue2); + ensure_equals("Ensure present value ", outValue, inValue); + ensure_equals("Ensure default value ", outValue2, 0); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<44>() + // read variable block past end of message -> 0 repeats + { + // build message with single block + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U32, 4, MBT_SINGLE)); + U32 outValue, outValue2, inValue = 0xbbbbbbbb; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU32(_PREHASH_Test0, inValue); + const U32 bufferSize = 1024; + U8 buffer[bufferSize]; + memset(buffer, 0xaa, bufferSize); + memset(buffer, 0, LL_PACKET_ID_SIZE); + U32 builtSize = builder->buildMessage(buffer, bufferSize, 0); + delete builder; + + // add variable block to reader template + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4)); + + // read message value and check block repeat count + numberMap[1] = &messageTemplate; + LLTemplateMessageReader* reader = + new LLTemplateMessageReader(numberMap); + reader->validateMessage(buffer, builtSize, LLHost()); + reader->readMessage(buffer, LLHost()); + reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outValue); + outValue2 = reader->getNumberOfBlocks(_PREHASH_Test1); + ensure_equals("Ensure present value ", outValue, inValue); + ensure_equals("Ensure 0 repeats ", outValue2, 0); + delete reader; + } + + template<> template<> + void LLTemplateMessageBuilderTestObject::test<45>() + // read variable length data past end of message -> 0 length + { + // build message with single block + LLMessageTemplate messageTemplate = defaultTemplate(); + messageTemplate.addBlock(defaultBlock(MVT_U32, 4, MBT_SINGLE)); + U32 outValue, inValue = 0xbbbbbbbb; + LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); + builder->addU32(_PREHASH_Test0, inValue); + const U32 bufferSize = 1024; + U8 buffer[bufferSize]; + memset(buffer, 0xaa, bufferSize); + memset(buffer, 0, LL_PACKET_ID_SIZE); + U32 builtSize = builder->buildMessage(buffer, bufferSize, 0); + delete builder; + + // add variable block to reader template + messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_VARIABLE, 4, + MBT_SINGLE)); + + // read message value and default string + numberMap[1] = &messageTemplate; + LLTemplateMessageReader* reader = + new LLTemplateMessageReader(numberMap); + reader->validateMessage(buffer, builtSize, LLHost()); + reader->readMessage(buffer, LLHost()); + reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outValue); + (void)outValue; + char outBuffer[bufferSize]; + memset(buffer, 0xcc, bufferSize); + reader->getString(_PREHASH_Test1, _PREHASH_Test0, bufferSize, + outBuffer); + ensure_equals("Ensure present value ", outValue, inValue); + ensure_equals("Ensure unchanged buffer ", strlen(outBuffer), 0); + delete reader; + } +} + diff --git a/indra/llmessage/tests/llxorcipher_test.cpp b/indra/llmessage/tests/llxorcipher_test.cpp new file mode 100644 index 0000000000..9acac53604 --- /dev/null +++ b/indra/llmessage/tests/llxorcipher_test.cpp @@ -0,0 +1,131 @@ +/** + * @file llxorcipher_tut.cpp + * @author Adroit + * @date 2007-03 + * @brief llxorcipher, llnullcipher test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" +#include "llxorcipher.h" +#include "llnullcipher.h" + +namespace tut +{ + struct cipher + { + }; + typedef test_group<cipher> cipher_t; + typedef cipher_t::object cipher_object_t; + tut::cipher_t tut_cipher("cipher"); + + //encrypt->decrypt + template<> template<> + void cipher_object_t::test<1>() + { + const U32 len = 3; + const U8 pad[] = "abc"; + const char str[] = "SecondLife"; + const S32 str_len = sizeof(str); + U8 encrypted[str_len]; + U8 decrypted[str_len]; + LLXORCipher xorCipher(pad, len); + LLXORCipher xorCipher1(pad, len); + + U32 length = xorCipher.requiredEncryptionSpace(50); + ensure("requiredEncryptionSpace() function failed", (length == 50)); + + U32 lenEncrypted = xorCipher.encrypt((U8 *) str, str_len, encrypted, str_len); + ensure("Encryption failed", (lenEncrypted == str_len)); + U32 lenDecrypted = xorCipher1.decrypt(encrypted, str_len, decrypted, str_len); + ensure("Decryption failed", (lenDecrypted == str_len)); + ensure_memory_matches("LLXORCipher Encrypt/Decrypt failed", str, str_len, decrypted, lenDecrypted); + } + + // operator= + template<> template<> + void cipher_object_t::test<2>() + { + const U8 pad[] = "ABCDEFGHIJKLMNOPQ"; // pad len longer than data to be ciphered + const U32 pad_len = sizeof(pad); + const U8 pad1[] = "SecondLife"; + const U32 pad_len1 = sizeof(pad1); + const char str[] = "To Be Ciphered"; + const S32 str_len = sizeof(str); + U8 encrypted[str_len]; + U8 decrypted[str_len]; + + LLXORCipher xorCipher(pad, pad_len); + LLXORCipher xorCipher1(pad1, pad_len1); + + xorCipher.encrypt((U8 *) str, str_len, encrypted, str_len); + // make xorCipher1 same as xorCipher..so that xorCipher1 can decrypt what was + // encrypted using xorCipher + xorCipher1 = xorCipher; + U32 lenDecrypted = xorCipher1.decrypt(encrypted, str_len, decrypted, str_len); + ensure_memory_matches("LLXORCipher operator= failed", str, str_len, decrypted, lenDecrypted); + } + + //in place encrypt->decrypt + template<> template<> + void cipher_object_t::test<3>() + { + U32 padNum = 0x12349087; + const U8* pad = (U8*) &padNum; + const U32 pad_len = sizeof(U32); + char str[] = "To Be Ciphered a long string.........!!!."; + char str1[] = "To Be Ciphered a long string.........!!!."; // same as str + const S32 str_len = sizeof(str); + + LLXORCipher xorCipher(pad, pad_len); + LLXORCipher xorCipher1(pad, pad_len); + xorCipher.encrypt((U8 *) str, str_len); + // it should not be the same as original data! + ensure("LLXORCipher: In Place encrypt failed", memcmp(str, str1, str_len) != 0); + xorCipher1.decrypt((U8 *) str, str_len); + // it should not be the same as original data! + ensure_memory_matches("LLXORCipher: In Place decrypt failed", str, str_len, str1, str_len); + } + + //LLNullCipher encrypt->decrypt + template<> template<> + void cipher_object_t::test<4>() + { + const char str[] = "SecondLife"; + const S32 str_len = sizeof(str); + U8 encrypted[str_len]; + U8 decrypted[str_len]; + LLNullCipher nullCipher; + LLNullCipher nullCipher1; + + U32 length = nullCipher.requiredEncryptionSpace(50); + ensure("LLNullCipher::requiredEncryptionSpace() function failed", (length == 50)); + + U32 len1 = nullCipher.encrypt((U8 *) str, str_len, encrypted, str_len); + ensure_memory_matches("LLNullCipher - Source transformed during encryption.", encrypted, len1, str, str_len); + + U32 len2 = nullCipher1.decrypt(encrypted, str_len, decrypted, str_len); + ensure_memory_matches("LLNullCipher - Decryption failed", decrypted, len2, str, str_len); + } +} diff --git a/indra/llmessage/tests/llzerocode_test.cpp b/indra/llmessage/tests/llzerocode_test.cpp new file mode 100644 index 0000000000..1aba46149d --- /dev/null +++ b/indra/llmessage/tests/llzerocode_test.cpp @@ -0,0 +1,253 @@ +/** + * @file llzerocode_test.cpp + * @brief LLZeroCode test cases. + * + * $LicenseInfo:firstyear=2026&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 "../llzerocode.h" + +#include "../test/lltut.h" + +#include <vector> + +namespace tut +{ + struct zerocode_data + { + }; + typedef test_group<zerocode_data> zerocode_test; + typedef zerocode_test::object zerocode_object; + tut::zerocode_test zerocode_testcase("LLZeroCode"); + + // Builds header_size bytes of header (with header[0] == header0) followed by body. + static std::vector<U8> makeBuffer(U32 header_size, U8 header0, const std::vector<U8>& body) + { + std::vector<U8> buf(header_size, 0); + if (header_size) + { + buf[0] = header0; + } + buf.insert(buf.end(), body.begin(), body.end()); + return buf; + } + + // Runs src through encode() then decode(), and (when compression is expected to help) + // asserts the round trip reproduces src exactly, including untouched header bits other + // than the zero-code flag. When compression is not expected to help, asserts encode() + // refuses it. + static void ensureRoundTrip(const char* msg, U32 header_size, U8 header0, + const std::vector<U8>& body, bool expect_compressed) + { + std::vector<U8> src = makeBuffer(header_size, header0, body); + std::vector<U8> enc(2 * src.size() + 16, 0xAA); + + S32 enc_size = LLZeroCode::encode(src.data(), (U32)src.size(), + enc.data(), (U32)enc.size(), header_size); + + if (!expect_compressed) + { + ensure(std::string(msg) + ": encode should refuse (no benefit)", enc_size < 0); + return; + } + + ensure(std::string(msg) + ": encode should succeed", enc_size >= 0); + ensure(std::string(msg) + ": encoded size should be smaller", (U32)enc_size < src.size()); + ensure(std::string(msg) + ": FLAG should be set on encoded output", (enc[0] & LLZeroCode::FLAG) != 0); + if (header_size > 0) + { + ensure_equals(std::string(msg) + ": non-flag header bits preserved on encode", + (U8)(enc[0] & ~LLZeroCode::FLAG), (U8)(header0 & ~LLZeroCode::FLAG)); + } + + std::vector<U8> dec(src.size() + 16, 0xBB); + bool overflow = false; + U32 dec_size = LLZeroCode::decode(enc.data(), (U32)enc_size, + dec.data(), (U32)dec.size(), header_size, overflow); + ensure(std::string(msg) + ": decode should not overflow", !overflow); + ensure_equals(std::string(msg) + ": decoded size should match original", dec_size, (U32)src.size()); + ensure(std::string(msg) + ": decoded bytes should match original", + memcmp(dec.data(), src.data(), src.size()) == 0); + } + + // Basic mixed body; header carries an unrelated flag bit (0x40) that must survive untouched. + template<> template<> + void zerocode_object::test<1>() + { + ensureRoundTrip("mixed body", 6, 0x40, + {0,0,0,5,0,0,0,0,0,0,7,8,9,0,0}, true); + } + + // A body with no zero bytes at all cannot benefit from zero-coding. + template<> template<> + void zerocode_object::test<2>() + { + ensureRoundTrip("no zero bytes", 1, 0x00, {1,2,3,4,5,6,7,8,9}, false); + } + + // Isolated zero-byte runs of length 1 or 2 cost as much or more than they save + // (marker + terminator == 2 bytes), so encode must refuse them. + template<> template<> + void zerocode_object::test<3>() + { + ensureRoundTrip("isolated single zero", 1, 0x00, {5, 0}, false); + ensureRoundTrip("isolated double zero", 1, 0x00, {5, 0, 0, 9}, false); + } + + // A long enough zero run followed by other data pays off. + template<> template<> + void zerocode_object::test<4>() + { + std::vector<U8> body(20, 0); + body.push_back(99); + ensureRoundTrip("long zero run", 1, 0x00, body, true); + } + + // Wrap boundary: runs are split into chunks of at most 255 zero bytes each + // (encode never emits the doubled-0x00 wire form; see test<7> for that). + // A run only shrinks the packet once it is longer than 2 bytes. + template<> template<> + void zerocode_object::test<5>() + { + static const U32 lengths[] = {1, 2, 253, 254, 255, 256, 257, 300, 509, 510, 511, 1000}; + for (U32 n : lengths) + { + std::vector<U8> body(n, 0); + body.push_back(42); // trailing nonzero byte + ensureRoundTrip("wrap boundary (with trailing byte)", 1, 0x00, body, n > 2); + } + } + + // Same boundary check, but with the zero run flushed at end-of-buffer + // (no trailing nonzero byte to force the terminator write mid-loop). + template<> template<> + void zerocode_object::test<6>() + { + static const U32 lengths[] = {1, 2, 254, 255, 256, 300}; + for (U32 n : lengths) + { + std::vector<U8> body(n, 0); + ensureRoundTrip("wrap boundary (end-of-buffer flush)", 1, 0x00, body, n > 2); + } + } + + // decode() must also accept the "0x00 0x00 N" doubled-marker wire format + // (worth +255 zero bytes per extra marker) for compatibility with any + // encoder other than this one's chunking strategy, even though encode() + // itself never emits it. + template<> template<> + void zerocode_object::test<7>() + { + // header (1 byte, FLAG set) + [0x00 marker][0x00 extra-wrap-marker][terminator=5] + // decoded body length = 1 (marker) + 1 (extra marker) + 255 (memset) + (5 - 1) = 261 + std::vector<U8> encoded = {(U8)LLZeroCode::FLAG, 0x00, 0x00, 0x05}; + std::vector<U8> dec(1024, 0xDD); + bool overflow = false; + U32 dec_size = LLZeroCode::decode(encoded.data(), (U32)encoded.size(), + dec.data(), (U32)dec.size(), 1, overflow); + ensure("wrap format: no overflow", !overflow); + ensure_equals("wrap format: decoded size", dec_size, (U32)262); + ensure_equals("wrap format: FLAG cleared on header", dec[0], (U8)0x00); + for (U32 i = 1; i < dec_size; ++i) + { + ensure_equals("wrap format: decoded byte is zero", dec[i], (U8)0); + } + } + + // decode() is a no-op (returns 0, does not touch dst) when FLAG is not set. + template<> template<> + void zerocode_object::test<8>() + { + std::vector<U8> src = makeBuffer(6, 0x00, {1,2,3,0,0,0}); + std::vector<U8> dec(64, 0xCC); + bool overflow = false; + U32 dec_size = LLZeroCode::decode(src.data(), (U32)src.size(), + dec.data(), (U32)dec.size(), 6, overflow); + ensure_equals("not zero-coded: decode returns 0", dec_size, (U32)0); + ensure("not zero-coded: no overflow", !overflow); + } + + // encode() refuses to write into an undersized destination buffer. + template<> template<> + void zerocode_object::test<9>() + { + std::vector<U8> body(50, 0); + std::vector<U8> src = makeBuffer(1, 0, body); + std::vector<U8> enc(src.size(), 0); // smaller than the required 2 * src_size + S32 r = LLZeroCode::encode(src.data(), (U32)src.size(), enc.data(), (U32)enc.size(), 1); + ensure("encode: capacity guard rejects undersized dst", r < 0); + } + + // decode() reports overflow (rather than writing out of bounds) when dst is too small, + // whether the destination is smaller than a single byte's worth of headroom... + template<> template<> + void zerocode_object::test<10>() + { + std::vector<U8> body(500, 0); + std::vector<U8> src = makeBuffer(1, 0, body); + std::vector<U8> enc(2 * src.size() + 16, 0); + S32 enc_size = LLZeroCode::encode(src.data(), (U32)src.size(), enc.data(), (U32)enc.size(), 1); + ensure("decode overflow setup: encode succeeded", enc_size >= 0); + + std::vector<U8> dec(1, 0); // capacity == header_size exactly + bool overflow = false; + U32 dec_size = LLZeroCode::decode(enc.data(), (U32)enc_size, + dec.data(), (U32)dec.size(), 1, overflow); + ensure("decode overflow (minimal capacity): overflow flagged", overflow); + ensure("decode overflow (minimal capacity): size bounded by capacity", dec_size <= dec.size()); + } + + // ...or comfortably larger than 256 bytes but still short of the true decoded size. + template<> template<> + void zerocode_object::test<11>() + { + std::vector<U8> body(500, 0); + std::vector<U8> src = makeBuffer(1, 0, body); + std::vector<U8> enc(2 * src.size() + 16, 0); + S32 enc_size = LLZeroCode::encode(src.data(), (U32)src.size(), enc.data(), (U32)enc.size(), 1); + ensure("decode overflow setup: encode succeeded", enc_size >= 0); + + std::vector<U8> dec(300, 0); // > 256, but less than the true decoded size (~501) + bool overflow = false; + U32 dec_size = LLZeroCode::decode(enc.data(), (U32)enc_size, + dec.data(), (U32)dec.size(), 1, overflow); + ensure("decode overflow (insufficient capacity): overflow flagged", overflow); + ensure("decode overflow (insufficient capacity): size bounded by capacity", dec_size <= dec.size()); + } + + // A pathological alternating zero/non-zero pattern grows under zero-coding + // (every isolated zero costs 2 output bytes for 1 input byte), so encode + // must refuse it and leave the original buffer in use. + template<> template<> + void zerocode_object::test<12>() + { + std::vector<U8> body; + for (int i = 0; i < 200; ++i) + { + body.push_back(0); + body.push_back((U8)(i + 1)); + } + ensureRoundTrip("alternating pattern", 1, 0x00, body, false); + } +} diff --git a/indra/llmessage/tests/message_test.cpp b/indra/llmessage/tests/message_test.cpp new file mode 100644 index 0000000000..6fb2b92803 --- /dev/null +++ b/indra/llmessage/tests/message_test.cpp @@ -0,0 +1,147 @@ +/** + * @file lldatapacker_tut.cpp + * @date 2007-04 + * @brief LLDataPacker test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include <tut/tut.hpp> +#include "linden_common.h" +#include "lltut.h" +#include "llhttpconstants.h" +#include "llapr.h" +#include "llmessageconfig.h" +#include "llsdserialize.h" +#include "message.h" +#include "message_prehash.h" + +namespace +{ + struct Response : public LLHTTPNode::Response + { + virtual void result(const LLSD&) {} + virtual void status(S32 code, const std::string& message) + { + mStatus = code; + } + virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers) { } + virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers) { } + S32 mStatus; + }; +} + +namespace tut +{ + struct LLMessageSystemTestData + { + std::string mTestConfigDir; + std::string mSep; + + LLMessageSystemTestData() + { + static bool init = false; + if(!init) + { + ll_init_apr(); + //init_prehash_data(); + init = true; + } + const F32 circuit_heartbeat_interval=5; + const F32 circuit_timeout=100; + + + // currently test disconnected message system + start_messaging_system("notafile", 13035, + 1, + 0, + 0, + false, + "notasharedsecret", + NULL, + false, + circuit_heartbeat_interval, + circuit_timeout + ); + // generate temp dir + std::ostringstream ostr; +#if LL_WINDOWS + mSep = "\\"; + ostr << "C:" << mSep; +#else + mSep = "/"; + ostr << mSep << "tmp" << mSep; +#endif + LLUUID random; + random.generate(); + ostr << "message-test-" << random; + mTestConfigDir = ostr.str(); + LLFile::mkdir(mTestConfigDir); + writeConfigFile(LLSD()); + LLMessageConfig::initClass("simulator", ostr.str()); + } + + ~LLMessageSystemTestData() + { + // not end_messaging_system() + delete static_cast<LLMessageSystem*>(gMessageSystem); + gMessageSystem = NULL; + + // rm contents of temp dir + std::ostringstream ostr; + ostr << mTestConfigDir << mSep << "message.xml"; + int rmfile = LLFile::remove(ostr.str()); + ensure_equals("rmfile value", rmfile, 0); + + // rm temp dir + int rmdir = LLFile::remove(mTestConfigDir); + ensure_equals("rmdir value", rmdir, 0); + } + + void writeConfigFile(const LLSD& config) + { + std::string ostr(mTestConfigDir + mSep + "message.xml"); + llofstream file(ostr.c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(config, file); + } + file.close(); + } + }; + + typedef test_group<LLMessageSystemTestData> LLMessageSystemTestGroup; + typedef LLMessageSystemTestGroup::object LLMessageSystemTestObject; + LLMessageSystemTestGroup messageTestGroup("LLMessageSystem"); + + template<> template<> + void LLMessageSystemTestObject::test<1>() + // dispatch unknown message + { + const char* name = "notamessasge"; + const LLSD message; + const LLPointer<Response> response = new Response(); + gMessageSystem->dispatch(name, message, response); + ensure_equals(response->mStatus, HTTP_NOT_FOUND); + } +} + |
