diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 2e9bef09e1..b135788985 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -52,6 +52,19 @@ size_t PacketList::getDataSize() const { return totalBytes; } +size_t PacketList::getMessageSize() const { + size_t totalBytes = 0; + for (const auto& packet: _packets) { + totalBytes += packet->getPayloadSize(); + } + + if (_currentPacket) { + totalBytes += _currentPacket->getPayloadSize(); + } + + return totalBytes; +} + std::unique_ptr PacketList::fromReceivedPackets(std::list>&& packets) { auto packetList = std::unique_ptr(new PacketList(PacketType::Unknown, QByteArray(), true, true)); packetList->_packets = std::move(packets); diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 37c253ac08..05800a1b26 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -47,6 +47,7 @@ public: QByteArray getExtendedHeader() const { return _extendedHeader; } size_t getDataSize() const; + size_t getMessageSize() const; void closeCurrentPacket(bool shouldSendEmpty = false); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 4455ac586e..234ae1e93e 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -11,8 +11,6 @@ #include "UDTTest.h" -#include - #include #include @@ -49,7 +47,10 @@ const QCommandLineOption ORDERED_PACKETS { "ordered", "send ordered packets (default is unordered)" }; const QCommandLineOption MESSAGE_SIZE { - "message-size", "megabytes per message payload for ordered sending (default is 100)", "megabytes" + "message-size", "megabytes per message payload for ordered sending (default is 20)", "megabytes" +}; +const QCommandLineOption MESSAGE_SEED { + "message-seed", "seed used for random number generation to match ordered messages (default is 742272)", "integer" }; const QStringList CLIENT_STATS_TABLE_HEADERS { @@ -154,8 +155,26 @@ UDTTest::UDTTest(int& argc, char** argv) : } } + + // in case we're an ordered sender or receiver setup our random number generator now + static const int FIRST_MESSAGE_SEED = 742272; + + int messageSeed = FIRST_MESSAGE_SEED; + + if (_argumentParser.isSet(MESSAGE_SEED)) { + messageSeed = _argumentParser.value(MESSAGE_SEED).toInt(); + } + + // seed the generator with a value that the receiver will also use when verifying the ordered message + _generator.seed(messageSeed); + if (!_target.isNull()) { sendInitialPackets(); + } else { + // this is a receiver - in case there are ordered packets (messages) being sent to us make sure that we handle them + // so that they can be verified + using std::placeholders::_1; + _socket.setPacketListHandler(std::bind(&UDTTest::handlePacketList, this, _1)); } // the sender reports stats every 100 milliseconds @@ -176,7 +195,7 @@ void UDTTest::parseArguments() { _argumentParser.addOptions({ PORT_OPTION, TARGET_OPTION, PACKET_SIZE, MIN_PACKET_SIZE, MAX_PACKET_SIZE, MAX_SEND_BYTES, MAX_SEND_PACKETS, UNRELIABLE_PACKETS, ORDERED_PACKETS, - MESSAGE_SIZE + MESSAGE_SIZE, MESSAGE_SEED }); if (!_argumentParser.parse(arguments())) { @@ -206,8 +225,6 @@ void UDTTest::sendInitialPackets() { } } -static const int FIRST_MESSAGE_SEED = 742272; - void UDTTest::sendPacket() { if (_maxSendPackets != -1 && _totalQueuedPackets > _maxSendPackets) { @@ -238,7 +255,7 @@ void UDTTest::sendPacket() { // check if it is time to add another message - we do this every time 95% of the message size has been sent static int call = 0; static int packetSize = udt::Packet::maxPayloadSize(true); - static int messageSizePackets = (int) ceil(_messageSize / udt::Packet::maxPayloadSize()); + static int messageSizePackets = (int) ceil(_messageSize / udt::Packet::maxPayloadSize(true)); static int refillCount = (int) (messageSizePackets * 0.95); @@ -248,25 +265,14 @@ void UDTTest::sendPacket() { new udt::PacketList(PacketType::BulkAvatarData, QByteArray(), true, true) }); - static int currentSeed = FIRST_MESSAGE_SEED; - - std::random_device rd; - std::mt19937 generator(rd()); - - // seed the generator with a value that the receiver will also use when verifying the ordered message - generator.seed(currentSeed++); - - // setup a distribution for integer values - std::uniform_int_distribution<> dis(1, UINT64_MAX); - // fill the packet list with random data according to the constant seed (so receiver can verify) for (int i = 0; i < messageSizePackets; ++i) { // setup a QByteArray full of zeros for our random padded data QByteArray randomPaddedData { packetSize, 0 }; // generate a random integer for the first 8 bytes of the random data - uint64_t randomInt = dis(generator); - randomPaddedData.replace(0, sizeof(randomInt), reinterpret_cast(&randomInt)); + uint64_t randomInt = _distribution(_generator); + randomPaddedData.replace(0, sizeof(randomInt), reinterpret_cast(&randomInt), sizeof(randomInt)); // write this data to the PacketList packetList->write(randomPaddedData); @@ -298,6 +304,32 @@ void UDTTest::sendPacket() { } +void UDTTest::handlePacketList(std::unique_ptr packetList) { + // generate the byte array that should match this message - using the same seed the sender did + + int packetSize = udt::Packet::maxPayloadSize(true); + int messageSize = packetList->getMessageSize(); + + QByteArray messageData(messageSize, 0); + + for (int i = 0; i < messageSize; i += packetSize) { + // generate the random 64-bit unsigned integer that should lead this packet + uint64_t randomInt = _distribution(_generator); + + messageData.replace(i, sizeof(randomInt), reinterpret_cast(&randomInt), sizeof(randomInt)); + } + + bool dataMatch = messageData == packetList->getMessage(); + + Q_ASSERT_X(dataMatch, "UDTTest::handlePacketList", + "received message did not match expected message (from seeded random number generation)."); + + if (!dataMatch) { + qCritical() << "UDTTest::handlePacketList" << "received message did not match expected message" + << "(from seeded random number generation)."; + } +} + void UDTTest::sampleStats() { static bool first = true; static const double USECS_PER_MSEC = 1000.0; diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index 652a721cbc..376dc98bf6 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -14,6 +14,9 @@ #ifndef hifi_UDTTest_h #define hifi_UDTTest_h + +#include + #include #include @@ -31,6 +34,7 @@ public slots: private: void parseArguments(); + void handlePacketList(std::unique_ptr packetList); void sendInitialPackets(); // fills the queue with packets to start void sendPacket(); // constructs and sends a packet according to the test parameters @@ -50,6 +54,10 @@ private: int _messageSize { 10000000 }; // number of bytes per message while sending ordered + std::random_device _randomDevice; + std::mt19937 _generator { _randomDevice() }; // random number generator for ordered data testing + std::uniform_int_distribution _distribution { 1, UINT64_MAX }; // producer of random integer values + int _totalQueuedPackets { 0 }; // keeps track of the number of packets we have already queued int _totalQueuedBytes { 0 }; // keeps track of the number of bytes we have already queued };