From c76ae56d64c6f8b25f5d1a55743d7a818807703c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 May 2015 11:00:27 -0700 Subject: [PATCH 01/19] allow optional sequence numbers in packets --- libraries/networking/src/LimitedNodeList.cpp | 33 ++++-- libraries/networking/src/LimitedNodeList.h | 12 ++- libraries/networking/src/PacketHeaders.cpp | 100 +++++++++++++------ libraries/networking/src/PacketHeaders.h | 45 ++++++--- 4 files changed, 135 insertions(+), 55 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index e5badc32eb..b125394103 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -231,20 +231,13 @@ qint64 LimitedNodeList::readDatagram(QByteArray& incomingPacket, QHostAddress* a } qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, - const QUuid& connectionSecret) { - QByteArray datagramCopy = datagram; - - if (!connectionSecret.isNull()) { - // setup the MD5 hash for source verification in the header - replaceHashInPacketGivenConnectionUUID(datagramCopy, connectionSecret); - } - + const QUuid& connectionSecret) { // XXX can BandwidthRecorder be used for this? // stat collection for packets ++_numCollectedPackets; _numCollectedBytes += datagram.size(); - qint64 bytesWritten = _nodeSocket.writeDatagram(datagramCopy, + qint64 bytesWritten = _nodeSocket.writeDatagram(datagram, destinationSockAddr.getAddress(), destinationSockAddr.getPort()); if (bytesWritten < 0) { @@ -270,6 +263,19 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, } } + QByteArray datagramCopy = datagram; + PacketType packetType = packetTypeForPacket(datagramCopy); + + // perform replacement of hash and optionally also sequence number in the header + if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { + PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType); + replaceHashAndSequenceNumberInPacketGivenType(datagramCopy, packetType, + destinationNode->getConnectionSecret(), + sequenceNumber); + } else { + replaceHashInPacketGivenType(datagramCopy, packetType, destinationNode->getConnectionSecret()); + } + emit dataSent(destinationNode->getType(), datagram.size()); auto bytesWritten = writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret()); // Keep track of per-destination-node bandwidth @@ -318,6 +324,15 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const char* data, qint64 size, c return writeUnverifiedDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } +PacketSequenceNumber LimitedNodeList::getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType) { + // Thanks to std::map and std::unordered_map this line either default constructs the + // PacketTypeSequenceMap and the PacketSequenceNumber or returns the existing value. + // We use the postfix increment so that the stored value is incremented and the next + // return gives the correct value. + + return _packetSequenceNumbers[nodeUUID][packetType]++; +} + void LimitedNodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) { // the node decided not to do anything with this packet // if it comes from a known source we should keep that node alive diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 6ebe30c930..93be4bcfc2 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -14,7 +14,9 @@ #include #include +#include #include +#include #ifndef _WIN32 #include // not on windows, not needed for mac or windows @@ -34,6 +36,7 @@ #include "DomainHandler.h" #include "Node.h" +#include "PacketHeaders.h" #include "UUIDHasher.h" const int MAX_PACKET_SIZE = 1450; @@ -76,6 +79,8 @@ namespace PingType { const PingType_t Symmetric = 3; } +typedef std::map PacketTypeSequenceMap; + class LimitedNodeList : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -224,8 +229,11 @@ protected: LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton - qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, + qint64 writeDatagram(const QByteArray& datagram, + const HifiSockAddr& destinationSockAddr, const QUuid& connectionSecret); + + PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType); void changeSocketBufferSizes(int numBytes); @@ -247,6 +255,8 @@ protected: QElapsedTimer _packetStatTimer; bool _thisNodeCanAdjustLocks; bool _thisNodeCanRez; + + std::unordered_map _packetSequenceNumbers; template void eachNodeHashIterator(IteratorLambda functor) { diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index a9ccec34bb..f7c43fffb9 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -45,8 +45,8 @@ int packArithmeticallyCodedValue(int value, char* destination) { } } -PacketVersion versionForPacketType(PacketType type) { - switch (type) { +PacketVersion versionForPacketType(PacketType packetType) { + switch (packetType) { case PacketTypeMicrophoneAudioNoEcho: case PacketTypeMicrophoneAudioWithEcho: return 2; @@ -86,8 +86,8 @@ PacketVersion versionForPacketType(PacketType type) { #define PACKET_TYPE_NAME_LOOKUP(x) case x: return QString(#x); -QString nameForPacketType(PacketType type) { - switch (type) { +QString nameForPacketType(PacketType packetType) { + switch (packetType) { PACKET_TYPE_NAME_LOOKUP(PacketTypeUnknown); PACKET_TYPE_NAME_LOOKUP(PacketTypeStunResponse); PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainList); @@ -132,30 +132,30 @@ QString nameForPacketType(PacketType type) { PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing); PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply); default: - return QString("Type: ") + QString::number((int)type); + return QString("Type: ") + QString::number((int)packetType); } return QString("unexpected"); } -QByteArray byteArrayWithPopulatedHeader(PacketType type, const QUuid& connectionUUID) { +QByteArray byteArrayWithPopulatedHeader(PacketType packetType, const QUuid& connectionUUID) { QByteArray freshByteArray(MAX_PACKET_HEADER_BYTES, 0); - freshByteArray.resize(populatePacketHeader(freshByteArray, type, connectionUUID)); + freshByteArray.resize(populatePacketHeader(freshByteArray, packetType, connectionUUID)); return freshByteArray; } -int populatePacketHeader(QByteArray& packet, PacketType type, const QUuid& connectionUUID) { - if (packet.size() < numBytesForPacketHeaderGivenPacketType(type)) { - packet.resize(numBytesForPacketHeaderGivenPacketType(type)); +int populatePacketHeader(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID) { + if (packet.size() < numBytesForPacketHeaderGivenPacketType(packetType)) { + packet.resize(numBytesForPacketHeaderGivenPacketType(packetType)); } - return populatePacketHeader(packet.data(), type, connectionUUID); + return populatePacketHeader(packet.data(), packetType, connectionUUID); } -int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionUUID) { - int numTypeBytes = packArithmeticallyCodedValue(type, packet); - packet[numTypeBytes] = versionForPacketType(type); +int populatePacketHeader(char* packet, PacketType packetType, const QUuid& connectionUUID) { + int numTypeBytes = packArithmeticallyCodedValue(packetType, packet); + packet[numTypeBytes] = versionForPacketType(packetType); char* position = packet + numTypeBytes + sizeof(PacketVersion); @@ -165,38 +165,46 @@ int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionU memcpy(position, rfcUUID.constData(), NUM_BYTES_RFC4122_UUID); position += NUM_BYTES_RFC4122_UUID; - if (!NON_VERIFIED_PACKETS.contains(type)) { + if (!NON_VERIFIED_PACKETS.contains(packetType)) { // pack 16 bytes of zeros where the md5 hash will be placed once data is packed memset(position, 0, NUM_BYTES_MD5_HASH); position += NUM_BYTES_MD5_HASH; } - + + if (!SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { + // Pack zeros for the number of bytes that the sequence number requires. + // The LimitedNodeList will handle packing in the sequence number when sending out the packet. + memset(position, 0, sizeof(PacketSequenceNumber)); + position += sizeof(PacketSequenceNumber); + } + // return the number of bytes written for pointer pushing return position - packet; } int numBytesForPacketHeader(const QByteArray& packet) { - // returns the number of bytes used for the type, version, and UUID - return numBytesArithmeticCodingFromBuffer(packet.data()) - + numHashBytesInPacketHeaderGivenPacketType(packetTypeForPacket(packet)) - + NUM_STATIC_HEADER_BYTES; + PacketType packetType = packetTypeForPacket(packet); + return numBytesForPacketHeaderGivenPacketType(packetType); } int numBytesForPacketHeader(const char* packet) { - // returns the number of bytes used for the type, version, and UUID - return numBytesArithmeticCodingFromBuffer(packet) - + numHashBytesInPacketHeaderGivenPacketType(packetTypeForPacket(packet)) + PacketType packetType = packetTypeForPacket(packet); + return numBytesForPacketHeaderGivenPacketType(packetType); +} + +int numBytesForPacketHeaderGivenPacketType(PacketType packetType) { + return (int) ceilf((float) packetType / 255) + + numHashBytesForType(packetType) + + numSequenceNumberBytesForType(packetType) + NUM_STATIC_HEADER_BYTES; } -int numBytesForPacketHeaderGivenPacketType(PacketType type) { - return (int) ceilf((float)type / 255) - + numHashBytesInPacketHeaderGivenPacketType(type) - + NUM_STATIC_HEADER_BYTES; +int numHashBytesForType(PacketType packetType) { + return (NON_VERIFIED_PACKETS.contains(packetType) ? 0 : NUM_BYTES_MD5_HASH); } -int numHashBytesInPacketHeaderGivenPacketType(PacketType type) { - return (NON_VERIFIED_PACKETS.contains(type) ? 0 : NUM_BYTES_MD5_HASH); +int numSequenceNumberBytesForType(PacketType packetType) { + return (SEQUENCE_NUMBERED_PACKETS.contains(packetType) ? sizeof(PacketSequenceNumber) : 0); } QUuid uuidFromPacketHeader(const QByteArray& packet) { @@ -204,8 +212,18 @@ QUuid uuidFromPacketHeader(const QByteArray& packet) { NUM_BYTES_RFC4122_UUID)); } +int hashOffsetForPacketType(PacketType packetType) { + return numBytesForPacketHeaderGivenPacketType(packetType) + - (SEQUENCE_NUMBERED_PACKETS.contains(packetType) ? sizeof(PacketSequenceNumber) : 0) + - NUM_BYTES_RFC4122_UUID; +} + +int sequenceNumberOffsetForPacketType(PacketType packetType) { + return numBytesForPacketHeaderGivenPacketType(packetType) - sizeof(PacketSequenceNumber); +} + QByteArray hashFromPacketHeader(const QByteArray& packet) { - return packet.mid(numBytesForPacketHeader(packet) - NUM_BYTES_MD5_HASH, NUM_BYTES_MD5_HASH); + return packet.mid(hashOffsetForPacketType(packetTypeForPacket(packet)), NUM_BYTES_MD5_HASH); } QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID) { @@ -213,9 +231,25 @@ QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& QCryptographicHash::Md5); } -void replaceHashInPacketGivenConnectionUUID(QByteArray& packet, const QUuid& connectionUUID) { - packet.replace(numBytesForPacketHeader(packet) - NUM_BYTES_MD5_HASH, NUM_BYTES_MD5_HASH, - hashForPacketAndConnectionUUID(packet, connectionUUID)); +void replaceHashInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID) { + packet.replace(hashOffsetForPacketType(packetType), NUM_BYTES_MD5_HASH, + hashForPacketAndConnectionUUID(packet, connectionUUID)); +} + +void replaceSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, PacketSequenceNumber sequenceNumber) { + packet.replace(sequenceNumberOffsetForPacketType(packetType), + sizeof(PacketTypeSequenceMap), reinterpret_cast(&sequenceNumber)); +} + +void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, + const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber) { + replaceHashInPacketGivenType(packet, packetType, connectionUUID); + replaceSequenceNumberInPacketGivenType(packet, packetType, sequenceNumber); +} + + +void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber) { + replaceHashAndSequenceNumberInPacketGivenType(packet, packetTypeForPacket(packet), connectionUUID, sequenceNumber); } PacketType packetTypeForPacket(const QByteArray& packet) { diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 7b12b1a089..dc80feed3c 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -12,14 +12,16 @@ #ifndef hifi_PacketHeaders_h #define hifi_PacketHeaders_h +#include + #include #include #include #include "UUID.h" -// NOTE: if adding a new packet type, you can replace one marked usable or add at the end -// NOTE: if you want the name of the packet type to be available for debugging or logging, update nameForPacketType() as well +// NOTE: if adding a new packet packetType, you can replace one marked usable or add at the end +// NOTE: if you want the name of the packet packetType to be available for debugging or logging, update nameForPacketType() as well enum PacketType { PacketTypeUnknown, // 0 PacketTypeStunResponse, @@ -78,6 +80,7 @@ enum PacketType { }; typedef char PacketVersion; +typedef uint16_t PacketSequenceNumber; const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest @@ -88,33 +91,51 @@ const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse << PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply << PacketTypeStopNode; +const QSet SEQUENCE_NUMBERED_PACKETS = QSet() + << PacketTypeAvatarData; + const int NUM_BYTES_MD5_HASH = 16; const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; const int MAX_PACKET_HEADER_BYTES = sizeof(PacketType) + NUM_BYTES_MD5_HASH + NUM_STATIC_HEADER_BYTES; -PacketVersion versionForPacketType(PacketType type); -QString nameForPacketType(PacketType type); +PacketType packetTypeForPacket(const QByteArray& packet); +PacketType packetTypeForPacket(const char* packet); + +PacketVersion versionForPacketType(PacketType packetType); +QString nameForPacketType(PacketType packetType); const QUuid nullUUID = QUuid(); -QByteArray byteArrayWithPopulatedHeader(PacketType type, const QUuid& connectionUUID = nullUUID); -int populatePacketHeader(QByteArray& packet, PacketType type, const QUuid& connectionUUID = nullUUID); -int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionUUID = nullUUID); +QByteArray byteArrayWithPopulatedHeader(PacketType packetType, const QUuid& connectionUUID = nullUUID); +int populatePacketHeader(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID = nullUUID); +int populatePacketHeader(char* packet, PacketType packetType, const QUuid& connectionUUID = nullUUID); -int numHashBytesInPacketHeaderGivenPacketType(PacketType type); +int numHashBytesForType(PacketType packetType); +int numSequenceNumberBytesForType(PacketType packetType); int numBytesForPacketHeader(const QByteArray& packet); int numBytesForPacketHeader(const char* packet); -int numBytesForPacketHeaderGivenPacketType(PacketType type); +int numBytesForPacketHeaderGivenPacketType(PacketType packetType); QUuid uuidFromPacketHeader(const QByteArray& packet); +int hashOffsetForPacketType(PacketType packetType); +int sequenceNumberOffsetForPacketType(PacketType packetType); + QByteArray hashFromPacketHeader(const QByteArray& packet); QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID); -void replaceHashInPacketGivenConnectionUUID(QByteArray& packet, const QUuid& connectionUUID); -PacketType packetTypeForPacket(const QByteArray& packet); -PacketType packetTypeForPacket(const char* packet); +void replaceHashInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID); +void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID) + { replaceHashInPacketGivenType(packet, packetTypeForPacket(packet), connectionUUID); } + +void replaceSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, PacketSequenceNumber sequenceNumber); +void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber) + { replaceSequenceNumberInPacketGivenType(packet, packetTypeForPacket(packet), sequenceNumber); } + +void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, + const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber); +void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber); int arithmeticCodingValueFromBuffer(const char* checkValue); int numBytesArithmeticCodingFromBuffer(const char* checkValue); From 6b3cf1ba4a5980570e8e835f44f4fa79b73fcbf9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 May 2015 12:19:42 -0700 Subject: [PATCH 02/19] remove dependency of PacketHeaders on NodeList --- .../src/AssignmentClientMonitor.cpp | 6 +-- assignment-client/src/audio/AudioMixer.cpp | 13 +++--- .../src/audio/AudioMixerClientData.cpp | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 15 +++---- .../src/entities/EntityServer.cpp | 6 ++- .../octree/OctreeInboundPacketProcessor.cpp | 6 ++- .../src/octree/OctreeQueryNode.cpp | 4 +- domain-server/src/DomainServer.cpp | 43 +++++++++---------- ice-server/src/IceServer.cpp | 4 +- interface/src/Application.cpp | 4 +- interface/src/avatar/MyAvatar.cpp | 5 ++- libraries/audio-client/src/AudioClient.cpp | 11 ++--- libraries/audio-client/src/AudioIOStats.cpp | 7 +-- libraries/audio/src/AudioInjector.cpp | 5 ++- libraries/avatars/src/AvatarData.cpp | 18 +++++--- libraries/entities/src/EntityTree.cpp | 3 +- libraries/networking/src/LimitedNodeList.cpp | 13 +++--- libraries/networking/src/LimitedNodeList.h | 7 +++ libraries/networking/src/NodeList.cpp | 2 +- libraries/networking/src/PacketHeaders.cpp | 30 +++++++------ libraries/networking/src/PacketHeaders.h | 14 +++--- libraries/octree/src/JurisdictionListener.cpp | 7 ++- libraries/octree/src/JurisdictionMap.cpp | 10 +++-- .../octree/src/OctreeEditPacketSender.cpp | 3 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 3 +- libraries/script-engine/src/ScriptEngine.cpp | 8 ++-- 27 files changed, 144 insertions(+), 107 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 12f5abc796..4157e55754 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -88,7 +88,7 @@ void AssignmentClientMonitor::stopChildProcesses() { nodeList->eachNode([&](const SharedNodePointer& node) { qDebug() << "asking child" << node->getUUID() << "to exit."; node->activateLocalSocket(); - QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); + QByteArray diePacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeStopNode); nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket()); }); @@ -193,7 +193,7 @@ void AssignmentClientMonitor::checkSpares() { qDebug() << "asking child" << aSpareId << "to exit."; SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId); childNode->activateLocalSocket(); - QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); + QByteArray diePacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeStopNode); nodeList->writeUnverifiedDatagram(diePacket, childNode); } } @@ -229,7 +229,7 @@ void AssignmentClientMonitor::readPendingDatagrams() { } else { // tell unknown assignment-client child to exit. qDebug() << "asking unknown child to exit."; - QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); + QByteArray diePacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeStopNode); nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr); } } diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 94439cb18b..a9c0e5ddf2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -514,7 +514,8 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) { bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND); if (sendData) { - int numBytesEnvPacketHeader = populatePacketHeader(clientEnvBuffer, PacketTypeAudioEnvironment); + auto nodeList = DependencyManager::get(); + int numBytesEnvPacketHeader = nodeList->populatePacketHeader(clientEnvBuffer, PacketTypeAudioEnvironment); char* envDataAt = clientEnvBuffer + numBytesEnvPacketHeader; unsigned char bitset = 0; @@ -531,7 +532,7 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) { memcpy(envDataAt, &wetLevel, sizeof(float)); envDataAt += sizeof(float); } - DependencyManager::get()->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node); + nodeList->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node); } } @@ -552,7 +553,7 @@ void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const Hif SharedNodePointer sendingNode = nodeList->sendingNodeForPacket(receivedPacket); if (sendingNode->getCanAdjustLocks()) { QByteArray packet = receivedPacket; - populatePacketHeader(packet, PacketTypeMuteEnvironment); + nodeList->populatePacketHeader(packet, PacketTypeMuteEnvironment); nodeList->eachNode([&](const SharedNodePointer& node){ if (node->getType() == NodeType::Agent && node->getActiveSocket() && @@ -794,7 +795,7 @@ void AudioMixer::run() { // if the stream should be muted, send mute packet if (nodeData->getAvatarAudioStream() && shouldMute(nodeData->getAvatarAudioStream()->getQuietestFrameLoudness())) { - QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeNoisyMute); + QByteArray packet = nodeList->byteArrayWithPopulatedHeader(PacketTypeNoisyMute); nodeList->writeDatagram(packet, node); } @@ -806,7 +807,7 @@ void AudioMixer::run() { char* mixDataAt; if (streamsMixed > 0) { // pack header - int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); + int numBytesMixPacketHeader = nodeList->populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); mixDataAt = clientMixBuffer + numBytesMixPacketHeader; // pack sequence number @@ -819,7 +820,7 @@ void AudioMixer::run() { mixDataAt += AudioConstants::NETWORK_FRAME_BYTES_STEREO; } else { // pack header - int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame); + int numBytesPacketHeader = nodeList->populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame); mixDataAt = clientMixBuffer + numBytesPacketHeader; // pack sequence number diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 4db5611bb5..8848758f86 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -157,7 +157,7 @@ void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer& quint8 appendFlag = 0; // pack header - int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeAudioStreamStats); + int numBytesPacketHeader = nodeList->populatePacketHeader(packet, PacketTypeAudioStreamStats); char* headerEndAt = packet + numBytesPacketHeader; // calculate how many stream stat structs we can fit in each packet diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 961cbecebb..99ae98fb14 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -129,10 +129,9 @@ void AvatarMixer::broadcastAvatarData() { static QByteArray mixedAvatarByteArray; - int numPacketHeaderBytes = populatePacketHeader(mixedAvatarByteArray, PacketTypeBulkAvatarData); - auto nodeList = DependencyManager::get(); - + int numPacketHeaderBytes = nodeList->populatePacketHeader(mixedAvatarByteArray, PacketTypeBulkAvatarData); + // setup for distributed random floating point values std::random_device randomDevice; std::mt19937 generator(randomDevice()); @@ -287,7 +286,7 @@ void AvatarMixer::broadcastAvatarData() { && (forceSend || otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp || randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { - QByteArray billboardPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard); + QByteArray billboardPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard); billboardPacket.append(otherNode->getUUID().toRfc4122()); billboardPacket.append(otherNodeData->getAvatar().getBillboard()); @@ -301,7 +300,7 @@ void AvatarMixer::broadcastAvatarData() { || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp || randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { - QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); + QByteArray identityPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); QByteArray individualData = otherNodeData->getAvatar().identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122()); @@ -334,13 +333,13 @@ void AvatarMixer::broadcastAvatarData() { void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { if (killedNode->getType() == NodeType::Agent && killedNode->getLinkedData()) { + auto nodeList = DependencyManager::get(); // this was an avatar we were sending to other people // send a kill packet for it to our other nodes - QByteArray killPacket = byteArrayWithPopulatedHeader(PacketTypeKillAvatar); + QByteArray killPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeKillAvatar); killPacket += killedNode->getUUID().toRfc4122(); - DependencyManager::get()->broadcastToNodes(killPacket, - NodeSet() << NodeType::Agent); + nodeList->broadcastToNodes(killPacket, NodeSet() << NodeType::Agent); } } diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index bb5042f4b4..0f5332192a 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -64,7 +64,9 @@ void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePo unsigned char outputBuffer[MAX_PACKET_SIZE]; unsigned char* copyAt = outputBuffer; - int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(outputBuffer), PacketTypeEntityAddResponse); + auto nodeList = DependencyManager::get(); + + int numBytesPacketHeader = nodeList->populatePacketHeader(reinterpret_cast(outputBuffer), PacketTypeEntityAddResponse); int packetLength = numBytesPacketHeader; copyAt += numBytesPacketHeader; @@ -81,7 +83,7 @@ void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePo copyAt += sizeof(entityID); packetLength += sizeof(entityID); - DependencyManager::get()->writeDatagram((char*) outputBuffer, packetLength, senderNode); + nodeList->writeDatagram((char*) outputBuffer, packetLength, senderNode); } diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index f6ab12f421..28506b033e 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -277,9 +277,11 @@ int OctreeInboundPacketProcessor::sendNackPackets() { char* dataAt = packet; int bytesRemaining = MAX_PACKET_SIZE; + + auto nodeList = DependencyManager::get(); // pack header - int numBytesPacketHeader = populatePacketHeader(packet, _myServer->getMyEditNackType()); + int numBytesPacketHeader = nodeList->populatePacketHeader(packet, _myServer->getMyEditNackType()); dataAt += numBytesPacketHeader; bytesRemaining -= numBytesPacketHeader; @@ -301,7 +303,7 @@ int OctreeInboundPacketProcessor::sendNackPackets() { numSequenceNumbersAvailable -= numSequenceNumbers; // send it - DependencyManager::get()->writeUnverifiedDatagram(packet, dataAt - packet, destinationNode); + nodeList->writeUnverifiedDatagram(packet, dataAt - packet, destinationNode); packetsSent++; qDebug() << "NACK Sent back to editor/client... destinationNode=" << nodeUUID; diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 2d8d8d357e..b6504863e0 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -189,7 +189,9 @@ void OctreeQueryNode::resetOctreePacket() { } _octreePacketAvailableBytes = MAX_PACKET_SIZE; - int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(_octreePacket), _myPacketType); + int numBytesPacketHeader = DependencyManager::get()->populatePacketHeader(reinterpret_cast(_octreePacket), + _myPacketType); + _octreePacketAt = _octreePacket + numBytesPacketHeader; _octreePacketAvailableBytes -= numBytesPacketHeader; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 6ee1d6c765..ea69b5bc95 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -619,10 +619,12 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock packetStream >> nodeInterestList >> username >> usernameSignature; + auto limitedNodeList = DependencyManager::get(); + QString reason; if (!isAssignment && !shouldAllowConnectionFromNode(username, usernameSignature, senderSockAddr, reason)) { // this is an agent and we've decided we won't let them connect - send them a packet to deny connection - QByteArray connectionDeniedByteArray = byteArrayWithPopulatedHeader(PacketTypeDomainConnectionDenied); + QByteArray connectionDeniedByteArray = limitedNodeList->byteArrayWithPopulatedHeader(PacketTypeDomainConnectionDenied); QDataStream out(&connectionDeniedByteArray, QIODevice::WriteOnly | QIODevice::Append); out << reason; // tell client it has been refused. @@ -664,10 +666,9 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock canRez = canAdjustLocks; } - SharedNodePointer newNode = - DependencyManager::get()->addOrUpdateNode(nodeUUID, nodeType, - publicSockAddr, localSockAddr, - canAdjustLocks, canRez); + SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeUUID, nodeType, + publicSockAddr, localSockAddr, + canAdjustLocks, canRez); // when the newNode is created the linked data is also created // if this was a static assignment set the UUID, set the sendingSockAddr DomainServerNodeData* nodeData = reinterpret_cast(newNode->getLinkedData()); @@ -926,8 +927,8 @@ NodeSet DomainServer::nodeInterestListFromPacket(const QByteArray& packet, int n void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr &senderSockAddr, const NodeSet& nodeInterestList) { - - QByteArray broadcastPacket = byteArrayWithPopulatedHeader(PacketTypeDomainList); + auto limitedNodeList = DependencyManager::get(); + QByteArray broadcastPacket = limitedNodeList->byteArrayWithPopulatedHeader(PacketTypeDomainList); // always send the node their own UUID back QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append); @@ -939,8 +940,6 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif DomainServerNodeData* nodeData = reinterpret_cast(node->getLinkedData()); - auto nodeList = DependencyManager::get(); - // if we've established a connection via ICE with this peer, use that socket // otherwise just try to reply back to them on their sending socket (although that may not work) HifiSockAddr destinationSockAddr = _connectedICEPeers.value(node->getUUID()); @@ -955,7 +954,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif if (nodeData->isAuthenticated()) { // if this authenticated node has any interest types, send back those nodes as well - nodeList->eachNode([&](const SharedNodePointer& otherNode){ + limitedNodeList->eachNode([&](const SharedNodePointer& otherNode){ // reset our nodeByteArray and nodeDataStream QByteArray nodeByteArray; QDataStream nodeDataStream(&nodeByteArray, QIODevice::Append); @@ -986,7 +985,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif // we need to break here and start a new packet // so send the current one - nodeList->writeDatagram(broadcastPacket, node, senderSockAddr); + limitedNodeList->writeDatagram(broadcastPacket, node, senderSockAddr); // reset the broadcastPacket structure broadcastPacket.resize(numBroadcastPacketLeadBytes); @@ -1001,24 +1000,24 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif } // always write the last broadcastPacket - nodeList->writeDatagram(broadcastPacket, node, senderSockAddr); + limitedNodeList->writeDatagram(broadcastPacket, node, senderSockAddr); } void DomainServer::readAvailableDatagrams() { - auto nodeList = DependencyManager::get(); + auto limitedNodeList = DependencyManager::get(); HifiSockAddr senderSockAddr; QByteArray receivedPacket; - static QByteArray assignmentPacket = byteArrayWithPopulatedHeader(PacketTypeCreateAssignment); + static QByteArray assignmentPacket = limitedNodeList->byteArrayWithPopulatedHeader(PacketTypeCreateAssignment); static int numAssignmentPacketHeaderBytes = assignmentPacket.size(); - while (nodeList->getNodeSocket().hasPendingDatagrams()) { - receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); - nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(), + while (limitedNodeList->getNodeSocket().hasPendingDatagrams()) { + receivedPacket.resize(limitedNodeList->getNodeSocket().pendingDatagramSize()); + limitedNodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(), senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); if (packetTypeForPacket(receivedPacket) == PacketTypeRequestAssignment - && nodeList->packetVersionAndHashMatch(receivedPacket)) { + && limitedNodeList->packetVersionAndHashMatch(receivedPacket)) { // construct the requested assignment from the packet data Assignment requestAssignment(receivedPacket); @@ -1059,7 +1058,7 @@ void DomainServer::readAvailableDatagrams() { assignmentStream << uniqueAssignment; - nodeList->getNodeSocket().writeDatagram(assignmentPacket, + limitedNodeList->getNodeSocket().writeDatagram(assignmentPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); // add the information for that deployed assignment to the hash of pending assigned nodes @@ -1081,16 +1080,16 @@ void DomainServer::readAvailableDatagrams() { processDatagram(receivedPacket, senderSockAddr); } else { // we're using DTLS, so tell the sender to get back to us using DTLS - static QByteArray dtlsRequiredPacket = byteArrayWithPopulatedHeader(PacketTypeDomainServerRequireDTLS); + static QByteArray dtlsRequiredPacket = limitedNodeList->byteArrayWithPopulatedHeader(PacketTypeDomainServerRequireDTLS); static int numBytesDTLSHeader = numBytesForPacketHeaderGivenPacketType(PacketTypeDomainServerRequireDTLS); if (dtlsRequiredPacket.size() == numBytesDTLSHeader) { // pack the port that we accept DTLS traffic on - unsigned short dtlsPort = nodeList->getDTLSSocket().localPort(); + unsigned short dtlsPort = limitedNodeList->getDTLSSocket().localPort(); dtlsRequiredPacket.replace(numBytesDTLSHeader, sizeof(dtlsPort), reinterpret_cast(&dtlsPort)); } - nodeList->writeUnverifiedDatagram(dtlsRequiredPacket, senderSockAddr); + limitedNodeList->writeUnverifiedDatagram(dtlsRequiredPacket, senderSockAddr); } } } diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 77deb6125b..e72555cac1 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -117,7 +117,7 @@ void IceServer::sendHeartbeatResponse(const HifiSockAddr& destinationSockAddr, Q QSet::iterator peerID = connections.begin(); QByteArray outgoingPacket(MAX_PACKET_SIZE, 0); - int currentPacketSize = populatePacketHeader(outgoingPacket, PacketTypeIceServerHeartbeatResponse, _id); + int currentPacketSize = populatePacketHeaderWithUUID(outgoingPacket, PacketTypeIceServerHeartbeatResponse, _id); int numHeaderBytes = currentPacketSize; // go through the connections, sending packets containing connection information for those nodes @@ -136,7 +136,7 @@ void IceServer::sendHeartbeatResponse(const HifiSockAddr& destinationSockAddr, Q destinationSockAddr.getAddress(), destinationSockAddr.getPort()); // reset the packet size to our number of header bytes - currentPacketSize = populatePacketHeader(outgoingPacket, PacketTypeIceServerHeartbeatResponse, _id); + currentPacketSize = populatePacketHeaderWithUUID(outgoingPacket, PacketTypeIceServerHeartbeatResponse, _id); } // append the current peer bytes diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1447478b5f..24f232993f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2478,7 +2478,7 @@ int Application::sendNackPackets() { int bytesRemaining = MAX_PACKET_SIZE; // pack header - int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack); + int numBytesPacketHeader = nodeList->populatePacketHeader(packet, PacketTypeOctreeDataNack); dataAt += numBytesPacketHeader; bytesRemaining -= numBytesPacketHeader; @@ -2672,7 +2672,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node unsigned char* endOfQueryPacket = queryPacket; // insert packet type/version and node UUID - endOfQueryPacket += populatePacketHeader(reinterpret_cast(endOfQueryPacket), packetType); + endOfQueryPacket += nodeList->populatePacketHeader(reinterpret_cast(endOfQueryPacket), packetType); // encode the query data... endOfQueryPacket += _octreeQuery.getBroadcastData(endOfQueryPacket); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 557d630ebf..0244446a81 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -846,8 +846,9 @@ int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) { } void MyAvatar::sendKillAvatar() { - QByteArray killPacket = byteArrayWithPopulatedHeader(PacketTypeKillAvatar); - DependencyManager::get()->broadcastToNodes(killPacket, NodeSet() << NodeType::AvatarMixer); + auto nodeList = DependencyManager::get(); + QByteArray killPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeKillAvatar); + nodeList->broadcastToNodes(killPacket, NodeSet() << NodeType::AvatarMixer); } void MyAvatar::updateLookAtTargetAvatar() { diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index e581105cd2..10e2bc3bbf 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -837,7 +837,7 @@ void AudioClient::handleAudioInput() { } } - char* currentPacketPtr = audioDataPacket + populatePacketHeader(audioDataPacket, packetType); + char* currentPacketPtr = audioDataPacket + nodeList->populatePacketHeader(audioDataPacket, packetType); // pack sequence number memcpy(currentPacketPtr, &_outgoingAvatarAudioSequenceNumber, sizeof(quint16)); @@ -899,7 +899,9 @@ void AudioClient::processReceivedSamples(const QByteArray& inputBuffer, QByteArr } void AudioClient::sendMuteEnvironmentPacket() { - QByteArray mutePacket = byteArrayWithPopulatedHeader(PacketTypeMuteEnvironment); + auto nodeList = DependencyManager::get(); + + QByteArray mutePacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeMuteEnvironment); int headerSize = mutePacket.size(); const float MUTE_RADIUS = 50; @@ -910,12 +912,11 @@ void AudioClient::sendMuteEnvironmentPacket() { memcpy(mutePacket.data() + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); // grab our audio mixer from the NodeList, if it exists - auto nodelist = DependencyManager::get(); - SharedNodePointer audioMixer = nodelist->soloNodeOfType(NodeType::AudioMixer); + SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); if (audioMixer) { // send off this mute packet - nodelist->writeDatagram(mutePacket, audioMixer); + nodeList->writeDatagram(mutePacket, audioMixer); } } diff --git a/libraries/audio-client/src/AudioIOStats.cpp b/libraries/audio-client/src/AudioIOStats.cpp index 88a1b96d4c..0a6c94671b 100644 --- a/libraries/audio-client/src/AudioIOStats.cpp +++ b/libraries/audio-client/src/AudioIOStats.cpp @@ -104,10 +104,12 @@ void AudioIOStats::sendDownstreamAudioStatsPacket() { // also, call _receivedAudioStream's per-second callback _receivedAudioStream->perSecondCallbackForUpdatingStats(); + auto nodeList = DependencyManager::get(); + char packet[MAX_PACKET_SIZE]; // pack header - int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeAudioStreamStats); + int numBytesPacketHeader = nodeList->populatePacketHeader(packet, PacketTypeAudioStreamStats); char* dataAt = packet + numBytesPacketHeader; // pack append flag @@ -126,7 +128,6 @@ void AudioIOStats::sendDownstreamAudioStatsPacket() { dataAt += sizeof(AudioStreamStats); // send packet - auto nodeList = DependencyManager::get(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); nodeList->writeDatagram(packet, dataAt - packet, audioMixer); -} \ No newline at end of file +} diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 26140b82c8..ae397ba97e 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -141,11 +141,13 @@ void AudioInjector::injectToMixer() { _currentSendPosition = 0; } + auto nodeList = DependencyManager::get(); + // make sure we actually have samples downloaded to inject if (_audioData.size()) { // setup the packet for injected audio - QByteArray injectAudioPacket = byteArrayWithPopulatedHeader(PacketTypeInjectAudio); + QByteArray injectAudioPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeInjectAudio); QDataStream packetStream(&injectAudioPacket, QIODevice::Append); // pack some placeholder sequence number for now @@ -226,7 +228,6 @@ void AudioInjector::injectToMixer() { _audioData.data() + _currentSendPosition, bytesToCopy); // grab our audio mixer from the NodeList, if it exists - auto nodeList = DependencyManager::get(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); // send off this audio packet diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index f0e4eb118b..c7ab6dce2e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1077,25 +1077,31 @@ void AvatarData::setJointMappingsFromNetworkReply() { } void AvatarData::sendAvatarDataPacket() { - QByteArray dataPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarData); + auto nodeList = DependencyManager::get(); + + QByteArray dataPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeAvatarData); dataPacket.append(toByteArray()); - DependencyManager::get()->broadcastToNodes(dataPacket, NodeSet() << NodeType::AvatarMixer); + nodeList->broadcastToNodes(dataPacket, NodeSet() << NodeType::AvatarMixer); } void AvatarData::sendIdentityPacket() { - QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); + auto nodeList = DependencyManager::get(); + + QByteArray identityPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); identityPacket.append(identityByteArray()); - DependencyManager::get()->broadcastToNodes(identityPacket, NodeSet() << NodeType::AvatarMixer); + nodeList->broadcastToNodes(identityPacket, NodeSet() << NodeType::AvatarMixer); } void AvatarData::sendBillboardPacket() { if (!_billboard.isEmpty()) { - QByteArray billboardPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard); + auto nodeList = DependencyManager::get(); + + QByteArray billboardPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard); billboardPacket.append(_billboard); - DependencyManager::get()->broadcastToNodes(billboardPacket, NodeSet() << NodeType::AvatarMixer); + nodeList->broadcastToNodes(billboardPacket, NodeSet() << NodeType::AvatarMixer); } } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f8f94f8d17..1d9cb25789 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -788,7 +788,8 @@ bool EntityTree::encodeEntitiesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumbe bool hasMoreToSend = true; unsigned char* copyAt = outputBuffer; - size_t numBytesPacketHeader = populatePacketHeader(reinterpret_cast(outputBuffer), PacketTypeEntityErase); + size_t numBytesPacketHeader = DependencyManager::get()->populatePacketHeader(reinterpret_cast(outputBuffer), + PacketTypeEntityErase); copyAt += numBytesPacketHeader; outputLength = numBytesPacketHeader; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index b125394103..0237121209 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "LimitedNodeList.h" + #include #include #include @@ -28,8 +30,6 @@ #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" -#include "LimitedNodeList.h" -#include "PacketHeaders.h" #include "UUID.h" #include "NetworkLogging.h" @@ -269,6 +269,7 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, // perform replacement of hash and optionally also sequence number in the header if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType); + qDebug() << "Sequence number for this packet is" << sequenceNumber; replaceHashAndSequenceNumberInPacketGivenType(datagramCopy, packetType, destinationNode->getConnectionSecret(), sequenceNumber); @@ -481,8 +482,8 @@ unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeS } QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVerified, const QUuid& packetHeaderID) { - QByteArray pingPacket = byteArrayWithPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing, - packetHeaderID); + QByteArray pingPacket = byteArrayWithUUIDPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing, + packetHeaderID); QDataStream packetStream(&pingPacket, QIODevice::Append); @@ -505,7 +506,7 @@ QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacke PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing) ? PacketTypePingReply : PacketTypeUnverifiedPingReply; - QByteArray replyPacket = byteArrayWithPopulatedHeader(replyType, packetHeaderID); + QByteArray replyPacket = byteArrayWithUUIDPopulatedHeader(replyType, packetHeaderID); QDataStream packetStream(&replyPacket, QIODevice::Append); packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); @@ -695,7 +696,7 @@ void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSock headerID = _sessionUUID; } - QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, headerID); + QByteArray iceRequestByteArray = byteArrayWithUUIDPopulatedHeader(PacketTypeIceServerHeartbeat, headerID); QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); iceDataStream << _publicSockAddr << _localSockAddr; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 93be4bcfc2..53bf6ea2d8 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -101,6 +101,13 @@ public: bool packetVersionAndHashMatch(const QByteArray& packet); + QByteArray byteArrayWithPopulatedHeader(PacketType packetType) + { return byteArrayWithUUIDPopulatedHeader(packetType, _sessionUUID); } + int populatePacketHeader(QByteArray& packet, PacketType packetType) + { return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); } + int populatePacketHeader(char* packet, PacketType packetType) + { return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); } + qint64 readDatagram(QByteArray& incomingPacket, QHostAddress* address, quint16 * port); qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode, diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 819c46cdf0..98cb0b1568 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -348,7 +348,7 @@ void NodeList::sendDomainServerCheckIn() { } } - QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); + QByteArray domainServerPacket = byteArrayWithUUIDPopulatedHeader(domainPacketType, packetUUID); QDataStream packetStream(&domainServerPacket, QIODevice::Append); // pack our data to send to the domain-server diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index f7c43fffb9..8e3f47a47e 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -9,14 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "PacketHeaders.h" + #include #include -#include "NodeList.h" - -#include "PacketHeaders.h" - int arithmeticCodingValueFromBuffer(const char* checkValue) { if (((uchar) *checkValue) < 255) { return *checkValue; @@ -139,29 +137,27 @@ QString nameForPacketType(PacketType packetType) { -QByteArray byteArrayWithPopulatedHeader(PacketType packetType, const QUuid& connectionUUID) { +QByteArray byteArrayWithUUIDPopulatedHeader(PacketType packetType, const QUuid& connectionUUID) { QByteArray freshByteArray(MAX_PACKET_HEADER_BYTES, 0); - freshByteArray.resize(populatePacketHeader(freshByteArray, packetType, connectionUUID)); + freshByteArray.resize(populatePacketHeaderWithUUID(freshByteArray, packetType, connectionUUID)); return freshByteArray; } -int populatePacketHeader(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID) { +int populatePacketHeaderWithUUID(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID) { if (packet.size() < numBytesForPacketHeaderGivenPacketType(packetType)) { packet.resize(numBytesForPacketHeaderGivenPacketType(packetType)); } - return populatePacketHeader(packet.data(), packetType, connectionUUID); + return populatePacketHeaderWithUUID(packet.data(), packetType, connectionUUID); } -int populatePacketHeader(char* packet, PacketType packetType, const QUuid& connectionUUID) { +int populatePacketHeaderWithUUID(char* packet, PacketType packetType, const QUuid& connectionUUID) { int numTypeBytes = packArithmeticallyCodedValue(packetType, packet); packet[numTypeBytes] = versionForPacketType(packetType); char* position = packet + numTypeBytes + sizeof(PacketVersion); - QUuid packUUID = connectionUUID.isNull() ? DependencyManager::get()->getSessionUUID() : connectionUUID; - - QByteArray rfcUUID = packUUID.toRfc4122(); + QByteArray rfcUUID = connectionUUID.toRfc4122(); memcpy(position, rfcUUID.constData(), NUM_BYTES_RFC4122_UUID); position += NUM_BYTES_RFC4122_UUID; @@ -236,11 +232,19 @@ void replaceHashInPacketGivenType(QByteArray& packet, PacketType packetType, con hashForPacketAndConnectionUUID(packet, connectionUUID)); } +void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID) { + replaceHashInPacketGivenType(packet, packetTypeForPacket(packet), connectionUUID); +} + void replaceSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, PacketSequenceNumber sequenceNumber) { packet.replace(sequenceNumberOffsetForPacketType(packetType), - sizeof(PacketTypeSequenceMap), reinterpret_cast(&sequenceNumber)); + sizeof(PacketSequenceNumber), reinterpret_cast(&sequenceNumber)); } +void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber) { + replaceSequenceNumberInPacketGivenType(packet, packetTypeForPacket(packet), sequenceNumber); +} + void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber) { replaceHashInPacketGivenType(packet, packetType, connectionUUID); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index dc80feed3c..c1e397022e 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -12,6 +12,8 @@ #ifndef hifi_PacketHeaders_h #define hifi_PacketHeaders_h +#pragma once + #include #include @@ -106,9 +108,9 @@ QString nameForPacketType(PacketType packetType); const QUuid nullUUID = QUuid(); -QByteArray byteArrayWithPopulatedHeader(PacketType packetType, const QUuid& connectionUUID = nullUUID); -int populatePacketHeader(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID = nullUUID); -int populatePacketHeader(char* packet, PacketType packetType, const QUuid& connectionUUID = nullUUID); +QByteArray byteArrayWithUUIDPopulatedHeader(PacketType packetType, const QUuid& connectionUUID); +int populatePacketHeaderWithUUID(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID); +int populatePacketHeaderWithUUID(char* packet, PacketType packetType, const QUuid& connectionUUID); int numHashBytesForType(PacketType packetType); int numSequenceNumberBytesForType(PacketType packetType); @@ -126,12 +128,10 @@ QByteArray hashFromPacketHeader(const QByteArray& packet); QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID); void replaceHashInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID); -void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID) - { replaceHashInPacketGivenType(packet, packetTypeForPacket(packet), connectionUUID); } +void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID); void replaceSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, PacketSequenceNumber sequenceNumber); -void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber) - { replaceSequenceNumberInPacketGivenType(packet, packetTypeForPacket(packet), sequenceNumber); } +void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber); void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber); diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index c050e0bffe..71c4feda96 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -35,10 +35,13 @@ void JurisdictionListener::nodeKilled(SharedNodePointer node) { bool JurisdictionListener::queueJurisdictionRequest() { static unsigned char buffer[MAX_PACKET_SIZE]; unsigned char* bufferOut = &buffer[0]; - int sizeOut = populatePacketHeader(reinterpret_cast(bufferOut), PacketTypeJurisdictionRequest); + + auto nodeList = DependencyManager::get(); + + int sizeOut = nodeList->populatePacketHeader(reinterpret_cast(bufferOut), PacketTypeJurisdictionRequest); int nodeCount = 0; - DependencyManager::get()->eachNode([&](const SharedNodePointer& node) { + nodeList->eachNode([&](const SharedNodePointer& node) { if (node->getType() == getNodeType() && node->getActiveSocket()) { _packetSender.queuePacketForSending(node, QByteArray(reinterpret_cast(bufferOut), sizeOut)); nodeCount++; diff --git a/libraries/octree/src/JurisdictionMap.cpp b/libraries/octree/src/JurisdictionMap.cpp index 79c1a96ccc..46e758cb42 100644 --- a/libraries/octree/src/JurisdictionMap.cpp +++ b/libraries/octree/src/JurisdictionMap.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -268,8 +270,9 @@ bool JurisdictionMap::writeToFile(const char* filename) { int JurisdictionMap::packEmptyJurisdictionIntoMessage(NodeType_t type, unsigned char* destinationBuffer, int availableBytes) { unsigned char* bufferStart = destinationBuffer; - - int headerLength = populatePacketHeader(reinterpret_cast(destinationBuffer), PacketTypeJurisdiction); + + int headerLength = DependencyManager::get()->populatePacketHeader(reinterpret_cast(destinationBuffer), + PacketTypeJurisdiction); destinationBuffer += headerLength; // Pack the Node Type in first byte @@ -287,7 +290,8 @@ int JurisdictionMap::packEmptyJurisdictionIntoMessage(NodeType_t type, unsigned int JurisdictionMap::packIntoMessage(unsigned char* destinationBuffer, int availableBytes) { unsigned char* bufferStart = destinationBuffer; - int headerLength = populatePacketHeader(reinterpret_cast(destinationBuffer), PacketTypeJurisdiction); + int headerLength = DependencyManager::get()->populatePacketHeader(reinterpret_cast(destinationBuffer), + PacketTypeJurisdiction); destinationBuffer += headerLength; // Pack the Node Type in first byte diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 65fbb0f983..9b1124a197 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -328,7 +328,8 @@ void OctreeEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) } void OctreeEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, PacketType type, int nodeClockSkew) { - packetBuffer._currentSize = populatePacketHeader(reinterpret_cast(&packetBuffer._currentBuffer[0]), type); + packetBuffer._currentSize = + DependencyManager::get()->populatePacketHeader(reinterpret_cast(&packetBuffer._currentBuffer[0]), type); // skip over sequence number for now; will be packed when packet is ready to be sent out packetBuffer._currentSize += sizeof(quint16); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index ea5c811ce1..63cd6d39a2 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -221,7 +221,7 @@ void OctreeHeadlessViewer::queryOctree() { unsigned char* endOfQueryPacket = queryPacket; // insert packet type/version and node UUID - endOfQueryPacket += populatePacketHeader(reinterpret_cast(endOfQueryPacket), packetType); + endOfQueryPacket += nodeList->populatePacketHeader(reinterpret_cast(endOfQueryPacket), packetType); // encode the query data... endOfQueryPacket += _octreeQuery.getBroadcastData(endOfQueryPacket); diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index c5a5678503..d12d4f1ba1 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -385,7 +385,8 @@ void OctreeSceneStats::childBitsRemoved(bool includesExistsBits, bool includesCo int OctreeSceneStats::packIntoMessage(unsigned char* destinationBuffer, int availableBytes) { unsigned char* bufferStart = destinationBuffer; - int headerLength = populatePacketHeader(reinterpret_cast(destinationBuffer), PacketTypeOctreeStats); + int headerLength = DependencyManager::get()->populatePacketHeader(reinterpret_cast(destinationBuffer), + PacketTypeOctreeStats); destinationBuffer += headerLength; memcpy(destinationBuffer, &_start, sizeof(_start)); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index ac2c212001..f02ef3a549 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -493,7 +493,7 @@ void ScriptEngine::run() { / (1000 * 1000)) + 0.5); const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); - QByteArray avatarPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarData); + QByteArray avatarPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeAvatarData); avatarPacket.append(_avatarData->toByteArray()); nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer); @@ -534,9 +534,9 @@ void ScriptEngine::run() { } } - QByteArray audioPacket = byteArrayWithPopulatedHeader(silentFrame - ? PacketTypeSilentAudioFrame - : PacketTypeMicrophoneAudioNoEcho); + QByteArray audioPacket = nodeList->byteArrayWithPopulatedHeader(silentFrame + ? PacketTypeSilentAudioFrame + : PacketTypeMicrophoneAudioNoEcho); QDataStream packetStream(&audioPacket, QIODevice::Append); From a481c573153ace2abb995e2c359d81cd22eabe15 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 May 2015 12:44:47 -0700 Subject: [PATCH 03/19] fix for writeDatagram with hash and sequence number --- libraries/networking/src/LimitedNodeList.cpp | 13 +++++++++---- libraries/networking/src/NodeList.cpp | 4 ++-- libraries/networking/src/PacketHeaders.cpp | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0237121209..61b98ffa44 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -278,7 +278,7 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, } emit dataSent(destinationNode->getType(), datagram.size()); - auto bytesWritten = writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret()); + auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr, destinationNode->getConnectionSecret()); // Keep track of per-destination-node bandwidth destinationNode->recordBytesSent(bytesWritten); return bytesWritten; @@ -482,8 +482,11 @@ unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeS } QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVerified, const QUuid& packetHeaderID) { + + QUuid packetUUID = packetHeaderID.isNull() ? _sessionUUID : packetHeaderID; + QByteArray pingPacket = byteArrayWithUUIDPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing, - packetHeaderID); + packetUUID); QDataStream packetStream(&pingPacket, QIODevice::Append); @@ -505,8 +508,10 @@ QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacke PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing) ? PacketTypePingReply : PacketTypeUnverifiedPingReply; - - QByteArray replyPacket = byteArrayWithUUIDPopulatedHeader(replyType, packetHeaderID); + + QUuid packetUUID = packetHeaderID.isNull() ? _sessionUUID : packetHeaderID; + + QByteArray replyPacket = byteArrayWithUUIDPopulatedHeader(replyType, packetUUID); QDataStream packetStream(&replyPacket, QIODevice::Append); packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 98cb0b1568..179f054e42 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -183,7 +183,7 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr } case PacketTypePingReply: { SharedNodePointer sendingNode = sendingNodeForPacket(packet); - + if (sendingNode) { sendingNode->setLastHeardMicrostamp(usecTimestampNow()); @@ -497,7 +497,7 @@ void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { QByteArray publicPingPacket = constructPingPacket(PingType::Public); writeDatagram(publicPingPacket, node, node->getPublicSocket()); - + if (!node->getSymmetricSocket().isNull()) { QByteArray symmetricPingPacket = constructPingPacket(PingType::Symmetric); writeDatagram(symmetricPingPacket, node, node->getSymmetricSocket()); diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 8e3f47a47e..b4fabc6340 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -167,7 +167,7 @@ int populatePacketHeaderWithUUID(char* packet, PacketType packetType, const QUui position += NUM_BYTES_MD5_HASH; } - if (!SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { + if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { // Pack zeros for the number of bytes that the sequence number requires. // The LimitedNodeList will handle packing in the sequence number when sending out the packet. memset(position, 0, sizeof(PacketSequenceNumber)); From 3887467048e0d9f37223b56bf0b71807a2211875 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 10:41:24 -0700 Subject: [PATCH 04/19] store last broadcasted sequence number --- .../src/avatars/AvatarMixerClientData.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index cccc5ee60f..d569a79e64 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -21,6 +21,7 @@ #include #include #include +#include #include const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps"; @@ -32,7 +33,10 @@ public: AvatarData& getAvatar() { return _avatar; } bool checkAndSetHasReceivedFirstPackets(); - + + PacketSequenceNumber getLastBroadcastSequenceNumber() const { return _lastBroadcastSequenceNumber; } + void setLastBroadcastSequenceNumber(PacketSequenceNumber sequenceNumber) { _lastBroadcastSequenceNumber = sequenceNumber; } + quint64 getBillboardChangeTimestamp() const { return _billboardChangeTimestamp; } void setBillboardChangeTimestamp(quint64 billboardChangeTimestamp) { _billboardChangeTimestamp = billboardChangeTimestamp; } @@ -61,13 +65,19 @@ public: void loadJSONStats(QJsonObject& jsonObject) const; private: AvatarData _avatar; + + PacketSequenceNumber _lastBroadcastSequenceNumber = 0; + bool _hasReceivedFirstPackets = false; quint64 _billboardChangeTimestamp = 0; quint64 _identityChangeTimestamp = 0; + float _fullRateDistance = FLT_MAX; float _maxAvatarDistance = FLT_MAX; + int _numAvatarsSentLastFrame = 0; int _numFramesSinceAdjustment = 0; + SimpleMovingAverage _avgOtherAvatarDataRate; }; From b0c7af1714d81f4ff7370a474a350521ea2a534a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 10:41:36 -0700 Subject: [PATCH 05/19] store last seq for node/packet type combo --- libraries/networking/src/LimitedNodeList.h | 3 --- libraries/networking/src/Node.cpp | 10 ++++++++++ libraries/networking/src/Node.h | 9 ++++++++- libraries/networking/src/PacketHeaders.h | 3 +++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 53bf6ea2d8..7c710185b1 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -14,7 +14,6 @@ #include #include -#include #include #include @@ -79,8 +78,6 @@ namespace PingType { const PingType_t Symmetric = 3; } -typedef std::map PacketTypeSequenceMap; - class LimitedNodeList : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 4abae367d7..cf0902556a 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -129,6 +129,16 @@ void Node::activateSymmetricSocket() { _activeSocket = &_symmetricSocket; } +PacketSequenceNumber Node::getLastSequenceNumberForPacketType(PacketType packetType) const { + const PacketSequenceNumber MISSING_SEQUENCE_NUMBER = 0; + auto typeMatch = _lastSequenceNumbers.find(packetType); + if (typeMatch != _lastSequenceNumbers.end()) { + return typeMatch->second; + } else { + return MISSING_SEQUENCE_NUMBER; + } +} + QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._type; out << node._uuid; diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 420c52b423..0836a448b2 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -23,6 +23,7 @@ #include "HifiSockAddr.h" #include "NetworkPeer.h" #include "NodeData.h" +#include "PacketHeaders.h" #include "SimpleMovingAverage.h" #include "MovingPercentile.h" @@ -43,7 +44,7 @@ namespace NodeType { class Node : public NetworkPeer { Q_OBJECT -public: +public: Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canAdjustLocks, bool canRez); ~Node(); @@ -86,6 +87,10 @@ public: void activatePublicSocket(); void activateLocalSocket(); void activateSymmetricSocket(); + + void setLastSequenceNumberForPacketType(PacketSequenceNumber sequenceNumber, PacketType packetType) + { _lastSequenceNumbers[packetType] = sequenceNumber; } + PacketSequenceNumber getLastSequenceNumberForPacketType(PacketType packetType) const; friend QDataStream& operator<<(QDataStream& out, const Node& node); friend QDataStream& operator>>(QDataStream& in, Node& node); @@ -109,6 +114,8 @@ private: MovingPercentile _clockSkewMovingPercentile; bool _canAdjustLocks; bool _canRez; + + PacketTypeSequenceMap _lastSequenceNumbers; }; QDebug operator<<(QDebug debug, const Node &message); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 280b5587eb..96b7850b3f 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -15,6 +15,7 @@ #pragma once #include +#include #include #include @@ -84,6 +85,8 @@ enum PacketType { typedef char PacketVersion; typedef uint16_t PacketSequenceNumber; +typedef std::map PacketTypeSequenceMap; + const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest << PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainConnectionDenied From e2986f57020faab69f6572ca6b9f9db1221698f4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 11:34:58 -0700 Subject: [PATCH 06/19] add get seq num, cleanup PacketHeaders methods --- libraries/networking/src/PacketHeaders.cpp | 50 ++++++++++++++++------ libraries/networking/src/PacketHeaders.h | 19 +++++--- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 6c4f2a1352..a4894e522e 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -227,33 +227,55 @@ QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& QCryptographicHash::Md5); } -void replaceHashInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID) { +PacketSequenceNumber sequenceNumberFromHeader(const QByteArray& packet, PacketType packetType) { + if (packetType == PacketTypeUnknown) { + packetType = packetTypeForPacket(packet); + } + + if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { + bool converted = false; + PacketSequenceNumber sequenceNumber = packet.mid(sequenceNumberOffsetForPacketType(packetType), + sizeof(PacketSequenceNumber)).toShort(&converted); + + if (converted) { + return sequenceNumber; + } + } + + return DEFAULT_SEQUENCE_NUMBER; +} + +void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketType packetType) { + if (packetType == PacketTypeUnknown) { + packetType = packetTypeForPacket(packet); + } + packet.replace(hashOffsetForPacketType(packetType), NUM_BYTES_MD5_HASH, - hashForPacketAndConnectionUUID(packet, connectionUUID)); + hashForPacketAndConnectionUUID(packet, connectionUUID)); } -void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID) { - replaceHashInPacketGivenType(packet, packetTypeForPacket(packet), connectionUUID); -} +void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber, PacketType packetType) { + if (packetType == PacketTypeUnknown) { + packetType = packetTypeForPacket(packet); + } -void replaceSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, PacketSequenceNumber sequenceNumber) { packet.replace(sequenceNumberOffsetForPacketType(packetType), sizeof(PacketSequenceNumber), reinterpret_cast(&sequenceNumber)); -} - -void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber) { - replaceSequenceNumberInPacketGivenType(packet, packetTypeForPacket(packet), sequenceNumber); } void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber) { - replaceHashInPacketGivenType(packet, packetType, connectionUUID); - replaceSequenceNumberInPacketGivenType(packet, packetType, sequenceNumber); + } +void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber, + PacketType packetType) { + if (packetType == PacketTypeUnknown) { + packetType = packetTypeForPacket(packet); + } -void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber) { - replaceHashAndSequenceNumberInPacketGivenType(packet, packetTypeForPacket(packet), connectionUUID, sequenceNumber); + replaceHashInPacket(packet, connectionUUID, packetType); + replaceSequenceNumberInPacket(packet, sequenceNumber, packetType); } PacketType packetTypeForPacket(const QByteArray& packet) { diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 96b7850b3f..1cbf2df196 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -83,7 +83,9 @@ enum PacketType { }; typedef char PacketVersion; + typedef uint16_t PacketSequenceNumber; +const PacketSequenceNumber DEFAULT_SEQUENCE_NUMBER = 0; typedef std::map PacketTypeSequenceMap; @@ -130,15 +132,18 @@ int sequenceNumberOffsetForPacketType(PacketType packetType); QByteArray hashFromPacketHeader(const QByteArray& packet); QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID); -void replaceHashInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID); -void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID); +// NOTE: The following four methods accept a PacketType which defaults to PacketTypeUnknown. +// If the caller has already looked at the packet type and can provide it then the methods below won't have to look it up. -void replaceSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, PacketSequenceNumber sequenceNumber); -void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber); +PacketSequenceNumber sequenceNumberFromHeader(const QByteArray& packet, PacketType packetType = PacketTypeUnknown); -void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, - const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber); -void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber); +void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketType packetType = PacketTypeUnknown); + +void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber, + PacketType packetType = PacketTypeUnknown); + +void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber, + PacketType packetType = PacketTypeUnknown); int arithmeticCodingValueFromBuffer(const char* checkValue); int numBytesArithmeticCodingFromBuffer(const char* checkValue); From ba9ed12415e8a5c09225d4505f0339ef7baa9a52 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 11:35:34 -0700 Subject: [PATCH 07/19] store last sequence number sent with data --- libraries/networking/src/LimitedNodeList.cpp | 7 +++++++ libraries/networking/src/Node.cpp | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 61b98ffa44..91716dca2f 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -348,6 +348,13 @@ int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& match matchingNode->setLastHeardMicrostamp(usecTimestampNow()); + // if this was a sequence numbered packet we should store the last seq number for + // a packet of this type for this node + PacketType packetType = packetTypeForPacket(packet); + if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { + matchingNode->setLastSequenceNumberForPacketType(sequenceNumberFromHeader(packet, packetType), packetType); + } + NodeData* linkedData = matchingNode->getLinkedData(); if (!linkedData && linkedDataCreateCallback) { linkedDataCreateCallback(matchingNode.data()); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index cf0902556a..ddc0571db4 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -130,12 +130,11 @@ void Node::activateSymmetricSocket() { } PacketSequenceNumber Node::getLastSequenceNumberForPacketType(PacketType packetType) const { - const PacketSequenceNumber MISSING_SEQUENCE_NUMBER = 0; auto typeMatch = _lastSequenceNumbers.find(packetType); if (typeMatch != _lastSequenceNumbers.end()) { return typeMatch->second; } else { - return MISSING_SEQUENCE_NUMBER; + return DEFAULT_SEQUENCE_NUMBER; } } From 460abd85b9d3f59ffba7cb7b5177914aba5e1edb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 11:35:45 -0700 Subject: [PATCH 08/19] don't double send data to a receiver --- assignment-client/src/avatars/AvatarMixer.cpp | 20 ++++++++++++++++++- .../src/avatars/AvatarMixerClientData.cpp | 10 ++++++++++ .../src/avatars/AvatarMixerClientData.h | 9 ++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 99ae98fb14..f401f62e99 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -160,7 +160,7 @@ void AvatarMixer::broadcastAvatarData() { // reset packet pointers for this node mixedAvatarByteArray.resize(numPacketHeaderBytes); - + AvatarData& avatar = nodeData->getAvatar(); glm::vec3 myPosition = avatar.getPosition(); @@ -256,8 +256,26 @@ void AvatarMixer::broadcastAvatarData() { && distribution(generator) > (nodeData->getFullRateDistance() / distanceToAvatar)) { return; } + + PacketSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID()); + PacketSequenceNumber lastSeqFromSender = otherNode->getLastSequenceNumberForPacketType(PacketTypeAvatarData); + assert(lastSeqToReceiver <= lastSeqFromSender); + + // make sure we haven't already sent this data from this sender to this receiver + // or that somehow we haven't sent + if (lastSeqToReceiver == lastSeqFromSender) { + return; + } + + // we're going to send this avatar + + // increment the number of avatars sent to this reciever nodeData->incrementNumAvatarsSentLastFrame(); + + // set the last sent sequence number for this sender on the receiver + nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), + otherNode->getLastSequenceNumberForPacketType(PacketTypeAvatarData)); QByteArray avatarByteArray; avatarByteArray.append(otherNode->getUUID().toRfc4122()); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 17330ac891..e3506a25e5 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -25,6 +25,16 @@ bool AvatarMixerClientData::checkAndSetHasReceivedFirstPackets() { return oldValue; } +PacketSequenceNumber AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const { + // return the matching PacketSequenceNumber, or the default if we don't have it + auto nodeMatch = _lastBroadcastSequenceNumbers.find(nodeUUID); + if (nodeMatch != _lastBroadcastSequenceNumbers.end()) { + return nodeMatch->second; + } else { + return DEFAULT_SEQUENCE_NUMBER; + } +} + void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { jsonObject["display_name"] = _avatar.getDisplayName(); jsonObject["full_rate_distance"] = _fullRateDistance; diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index d569a79e64..d1dc996e39 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps"; @@ -34,8 +36,9 @@ public: bool checkAndSetHasReceivedFirstPackets(); - PacketSequenceNumber getLastBroadcastSequenceNumber() const { return _lastBroadcastSequenceNumber; } - void setLastBroadcastSequenceNumber(PacketSequenceNumber sequenceNumber) { _lastBroadcastSequenceNumber = sequenceNumber; } + PacketSequenceNumber getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const; + void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, PacketSequenceNumber sequenceNumber) + { _lastBroadcastSequenceNumbers[nodeUUID] = sequenceNumber; } quint64 getBillboardChangeTimestamp() const { return _billboardChangeTimestamp; } void setBillboardChangeTimestamp(quint64 billboardChangeTimestamp) { _billboardChangeTimestamp = billboardChangeTimestamp; } @@ -66,7 +69,7 @@ public: private: AvatarData _avatar; - PacketSequenceNumber _lastBroadcastSequenceNumber = 0; + std::unordered_map _lastBroadcastSequenceNumbers; bool _hasReceivedFirstPackets = false; quint64 _billboardChangeTimestamp = 0; From 0d1c1bf8dd286161c4a4568ff9878062ed0c040c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 11:51:46 -0700 Subject: [PATCH 09/19] lock NodeData when attempting to read stats --- assignment-client/src/avatars/AvatarMixer.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index f401f62e99..f87c7e31a7 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -447,11 +447,14 @@ void AvatarMixer::sendStatsPacket() { AvatarMixerClientData* clientData = static_cast(node->getLinkedData()); if (clientData) { - clientData->loadJSONStats(avatarStats); + MutexTryLocker lock(clientData->getMutex()); + if (lock.isLocked()) { + clientData->loadJSONStats(avatarStats); - // add the diff between the full outbound bandwidth and the measured bandwidth for AvatarData send only - avatarStats["delta_full_vs_avatar_data_kbps"] = - avatarStats[NODE_OUTBOUND_KBPS_STAT_KEY].toDouble() - avatarStats[OUTBOUND_AVATAR_DATA_STATS_KEY].toDouble(); + // add the diff between the full outbound bandwidth and the measured bandwidth for AvatarData send only + avatarStats["delta_full_vs_avatar_data_kbps"] = + avatarStats[NODE_OUTBOUND_KBPS_STAT_KEY].toDouble() - avatarStats[OUTBOUND_AVATAR_DATA_STATS_KEY].toDouble(); + } } avatarsObject[uuidStringWithoutCurlyBraces(node->getUUID())] = avatarStats; From c5e189bbf2ece0d722d4945ec775cdbc1b1da3a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 11:52:03 -0700 Subject: [PATCH 10/19] use new PacketHeaders calls from LimitedNodeList --- libraries/networking/src/LimitedNodeList.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 91716dca2f..0c4943b6ae 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -270,11 +270,10 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType); qDebug() << "Sequence number for this packet is" << sequenceNumber; - replaceHashAndSequenceNumberInPacketGivenType(datagramCopy, packetType, - destinationNode->getConnectionSecret(), - sequenceNumber); + replaceHashAndSequenceNumberInPacket(datagramCopy, destinationNode->getConnectionSecret(), + sequenceNumber, packetType); } else { - replaceHashInPacketGivenType(datagramCopy, packetType, destinationNode->getConnectionSecret()); + replaceHashInPacket(datagramCopy, destinationNode->getConnectionSecret(), packetType); } emit dataSent(destinationNode->getType(), datagram.size()); From 1fdf2c78037292f4ad092dbe026248a2f2561ac0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 6 May 2015 13:35:53 -0700 Subject: [PATCH 11/19] Don't flash whole screen when audio clips --- interface/src/ui/ApplicationOverlay.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index c044bb0674..351db9996c 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -887,12 +887,6 @@ void ApplicationOverlay::renderAudioMeter() { } bool isClipping = ((audio->getTimeSinceLastClip() > 0.0f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)); - if ((audio->getTimeSinceLastClip() > 0.0f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) { - const float MAX_MAGNITUDE = 0.7f; - float magnitude = MAX_MAGNITUDE * (1 - audio->getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME); - renderCollisionOverlay(glCanvas->width(), glCanvas->height(), magnitude, 1.0f); - } - DependencyManager::get()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, cameraSpace, boxed); DependencyManager::get()->render(glCanvas->width(), glCanvas->height()); From ff676958e8ab8af43aedea008949647c9d34c067 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 14:24:11 -0700 Subject: [PATCH 12/19] fix hash replacement in PacketHeaders --- assignment-client/src/avatars/AvatarMixer.cpp | 5 +++++ libraries/networking/src/LimitedNodeList.cpp | 5 ++--- libraries/networking/src/PacketHeaders.cpp | 21 ++++++++----------- libraries/networking/src/PacketHeaders.h | 1 + 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index f87c7e31a7..3d0a71993a 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -259,12 +259,17 @@ void AvatarMixer::broadcastAvatarData() { PacketSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID()); PacketSequenceNumber lastSeqFromSender = otherNode->getLastSequenceNumberForPacketType(PacketTypeAvatarData); + + qDebug() << "Last sent to receiver" << node->getUUID() << "was" << lastSeqToReceiver; + qDebug() << "Last sent from sender" << otherNode->getUUID() << "was" << lastSeqFromSender; assert(lastSeqToReceiver <= lastSeqFromSender); // make sure we haven't already sent this data from this sender to this receiver // or that somehow we haven't sent if (lastSeqToReceiver == lastSeqFromSender) { + qDebug() << "Not sending a data for" << otherNode->getUUID() << "to" << node->getUUID() + << "since it has already been sent."; return; } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0c4943b6ae..5d04122d19 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -267,15 +267,14 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, PacketType packetType = packetTypeForPacket(datagramCopy); // perform replacement of hash and optionally also sequence number in the header - if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { + if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType); - qDebug() << "Sequence number for this packet is" << sequenceNumber; replaceHashAndSequenceNumberInPacket(datagramCopy, destinationNode->getConnectionSecret(), sequenceNumber, packetType); } else { replaceHashInPacket(datagramCopy, destinationNode->getConnectionSecret(), packetType); } - + emit dataSent(destinationNode->getType(), datagram.size()); auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr, destinationNode->getConnectionSecret()); // Keep track of per-destination-node bandwidth diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index a4894e522e..a214c9c9c4 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -55,7 +55,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketTypeInjectAudio: return 1; case PacketTypeAvatarData: - return 5; + return 6; case PacketTypeAvatarIdentity: return 1; case PacketTypeEnvironmentData: @@ -188,8 +188,12 @@ int numBytesForPacketHeader(const char* packet) { return numBytesForPacketHeaderGivenPacketType(packetType); } +int numBytesForArithmeticCodedPacketType(PacketType packetType) { + return (int) ceilf((float) packetType / 255); +} + int numBytesForPacketHeaderGivenPacketType(PacketType packetType) { - return (int) ceilf((float) packetType / 255) + return numBytesForArithmeticCodedPacketType(packetType) + numHashBytesForType(packetType) + numSequenceNumberBytesForType(packetType) + NUM_STATIC_HEADER_BYTES; @@ -209,9 +213,7 @@ QUuid uuidFromPacketHeader(const QByteArray& packet) { } int hashOffsetForPacketType(PacketType packetType) { - return numBytesForPacketHeaderGivenPacketType(packetType) - - (SEQUENCE_NUMBERED_PACKETS.contains(packetType) ? sizeof(PacketSequenceNumber) : 0) - - NUM_BYTES_RFC4122_UUID; + return numBytesForArithmeticCodedPacketType(packetType) + NUM_STATIC_HEADER_BYTES; } int sequenceNumberOffsetForPacketType(PacketType packetType) { @@ -249,7 +251,7 @@ void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID, Packet if (packetType == PacketTypeUnknown) { packetType = packetTypeForPacket(packet); } - + packet.replace(hashOffsetForPacketType(packetType), NUM_BYTES_MD5_HASH, hashForPacketAndConnectionUUID(packet, connectionUUID)); } @@ -260,14 +262,9 @@ void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequ } packet.replace(sequenceNumberOffsetForPacketType(packetType), - sizeof(PacketSequenceNumber), reinterpret_cast(&sequenceNumber)); + sizeof(PacketSequenceNumber), reinterpret_cast(&sequenceNumber), sizeof(PacketSequenceNumber)); } -void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, - const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber) { - -} - void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber, PacketType packetType) { if (packetType == PacketTypeUnknown) { diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 1cbf2df196..e057628924 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -122,6 +122,7 @@ int numSequenceNumberBytesForType(PacketType packetType); int numBytesForPacketHeader(const QByteArray& packet); int numBytesForPacketHeader(const char* packet); +int numBytesForArithmeticCodedPacketType(PacketType packetType); int numBytesForPacketHeaderGivenPacketType(PacketType packetType); QUuid uuidFromPacketHeader(const QByteArray& packet); From e540a6dbb34df936b5e04d47db15761ff73b3169 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 14:48:10 -0700 Subject: [PATCH 13/19] fix packet sequence number unmarshal --- assignment-client/src/avatars/AvatarMixer.cpp | 5 +---- libraries/networking/src/PacketHeaders.cpp | 12 ++++-------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 3d0a71993a..e77c518ead 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -260,14 +260,11 @@ void AvatarMixer::broadcastAvatarData() { PacketSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID()); PacketSequenceNumber lastSeqFromSender = otherNode->getLastSequenceNumberForPacketType(PacketTypeAvatarData); - qDebug() << "Last sent to receiver" << node->getUUID() << "was" << lastSeqToReceiver; - qDebug() << "Last sent from sender" << otherNode->getUUID() << "was" << lastSeqFromSender; - assert(lastSeqToReceiver <= lastSeqFromSender); // make sure we haven't already sent this data from this sender to this receiver // or that somehow we haven't sent - if (lastSeqToReceiver == lastSeqFromSender) { + if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { qDebug() << "Not sending a data for" << otherNode->getUUID() << "to" << node->getUUID() << "since it has already been sent."; return; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index a214c9c9c4..74484307d2 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -233,18 +233,14 @@ PacketSequenceNumber sequenceNumberFromHeader(const QByteArray& packet, PacketTy if (packetType == PacketTypeUnknown) { packetType = packetTypeForPacket(packet); } + + PacketSequenceNumber result = DEFAULT_SEQUENCE_NUMBER; if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { - bool converted = false; - PacketSequenceNumber sequenceNumber = packet.mid(sequenceNumberOffsetForPacketType(packetType), - sizeof(PacketSequenceNumber)).toShort(&converted); - - if (converted) { - return sequenceNumber; - } + memcpy(&result, packet.data() + sequenceNumberOffsetForPacketType(packetType), sizeof(PacketSequenceNumber)); } - return DEFAULT_SEQUENCE_NUMBER; + return result; } void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketType packetType) { From b3f7ec15451f08b2c1cb5553210611348e909ed5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 May 2015 16:49:51 -0700 Subject: [PATCH 14/19] keep track of starves and skips on other avatars --- assignment-client/src/avatars/AvatarMixer.cpp | 18 +++++++++++++++--- .../src/avatars/AvatarMixerClientData.cpp | 2 ++ .../src/avatars/AvatarMixerClientData.h | 9 +++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index e77c518ead..f18d19814a 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -178,7 +178,13 @@ void AvatarMixer::broadcastAvatarData() { // keep track of outbound data rate specifically for avatar data int numAvatarDataBytes = 0; - + + // keep track of the number of other avatars held back in this frame + int numAvatarsHeldBack = 0; + + // keep track of the number of other avatar frames skipped + int numAvatarsWithSkippedFrames = 0; + // use the data rate specifically for avatar data for FRD adjustment checks float avatarDataRateLastSecond = nodeData->getOutboundAvatarDataKbps(); @@ -265,9 +271,11 @@ void AvatarMixer::broadcastAvatarData() { // make sure we haven't already sent this data from this sender to this receiver // or that somehow we haven't sent if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { - qDebug() << "Not sending a data for" << otherNode->getUUID() << "to" << node->getUUID() - << "since it has already been sent."; + ++numAvatarsHeldBack; return; + } else if (lastSeqFromSender - lastSeqToReceiver > 1) { + // this is a skip - we still send the packet but capture the presence of the skip so we see it happening + ++numAvatarsWithSkippedFrames; } // we're going to send this avatar @@ -337,6 +345,10 @@ void AvatarMixer::broadcastAvatarData() { // record the bytes sent for other avatar data in the AvatarMixerClientData nodeData->recordSentAvatarData(numAvatarDataBytes + mixedAvatarByteArray.size()); + + // record the number of avatars held back this frame + nodeData->recordNumOtherAvatarStarves(numAvatarsHeldBack); + nodeData->recordNumOtherAvatarSkips(numAvatarsWithSkippedFrames); if (numOtherAvatars == 0) { // update the full rate distance to FLOAT_MAX since we didn't have any other avatars to send diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index e3506a25e5..dbdc573b96 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -40,6 +40,8 @@ void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { jsonObject["full_rate_distance"] = _fullRateDistance; jsonObject["max_avatar_distance"] = _maxAvatarDistance; jsonObject["num_avatars_sent_last_frame"] = _numAvatarsSentLastFrame; + jsonObject["avg_other_avatar_starves_per_second"] = getAvgNumOtherAvatarStarvesPerSecond(); + jsonObject["avg_other_avatar_skips_per_second"] = getAvgNumOtherAvatarSkipsPerSecond(); jsonObject[OUTBOUND_AVATAR_DATA_STATS_KEY] = getOutboundAvatarDataKbps(); } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index d1dc996e39..d91dccbdaa 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -56,6 +56,12 @@ public: void incrementNumAvatarsSentLastFrame() { ++_numAvatarsSentLastFrame; } int getNumAvatarsSentLastFrame() const { return _numAvatarsSentLastFrame; } + void recordNumOtherAvatarStarves(int numAvatarsHeldBack) { _otherAvatarStarves.updateAverage((float) numAvatarsHeldBack); } + float getAvgNumOtherAvatarStarvesPerSecond() const { return _otherAvatarStarves.getAverageSampleValuePerSecond(); } + + void recordNumOtherAvatarSkips(int numOtherAvatarSkips) { _otherAvatarSkips.updateAverage((float) numOtherAvatarSkips); } + float getAvgNumOtherAvatarSkipsPerSecond() const { return _otherAvatarSkips.getAverageSampleValuePerSecond(); } + int getNumFramesSinceFRDAdjustment() const { return _numFramesSinceAdjustment; } void incrementNumFramesSinceFRDAdjustment() { ++_numFramesSinceAdjustment; } void resetNumFramesSinceFRDAdjustment() { _numFramesSinceAdjustment = 0; } @@ -81,6 +87,9 @@ private: int _numAvatarsSentLastFrame = 0; int _numFramesSinceAdjustment = 0; + SimpleMovingAverage _otherAvatarStarves; + SimpleMovingAverage _otherAvatarSkips; + SimpleMovingAverage _avgOtherAvatarDataRate; }; From e3acf861ff36e1de82412f177228b98818b1208d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 May 2015 14:07:14 -0700 Subject: [PATCH 15/19] fix for unverified datagram writes --- domain-server/src/DomainServer.cpp | 6 +-- libraries/networking/src/LimitedNodeList.cpp | 42 +++++++++++++++----- libraries/networking/src/LimitedNodeList.h | 5 +-- libraries/networking/src/NodeList.cpp | 7 ++-- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ea69b5bc95..7841381422 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -985,7 +985,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif // we need to break here and start a new packet // so send the current one - limitedNodeList->writeDatagram(broadcastPacket, node, senderSockAddr); + limitedNodeList->writeUnverifiedDatagram(broadcastPacket, node, senderSockAddr); // reset the broadcastPacket structure broadcastPacket.resize(numBroadcastPacketLeadBytes); @@ -998,9 +998,9 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif }); } } - + // always write the last broadcastPacket - limitedNodeList->writeDatagram(broadcastPacket, node, senderSockAddr); + limitedNodeList->writeUnverifiedDatagram(broadcastPacket, node, senderSockAddr); } void DomainServer::readAvailableDatagrams() { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 5d04122d19..d8d1e9289b 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -230,8 +230,7 @@ qint64 LimitedNodeList::readDatagram(QByteArray& incomingPacket, QHostAddress* a return result; } -qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, - const QUuid& connectionSecret) { +qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr) { // XXX can BandwidthRecorder be used for this? // stat collection for packets ++_numCollectedPackets; @@ -251,6 +250,12 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr) { if (destinationNode) { + PacketType packetType = packetTypeForPacket(datagram); + + if (NON_VERIFIED_PACKETS.contains(packetType)) { + return writeUnverifiedDatagram(datagram, destinationNode, overridenSockAddr); + } + // if we don't have an overridden address, assume they want to send to the node's active socket const HifiSockAddr* destinationSockAddr = &overridenSockAddr; if (overridenSockAddr.isNull()) { @@ -264,8 +269,14 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, } QByteArray datagramCopy = datagram; - PacketType packetType = packetTypeForPacket(datagramCopy); + // if we're here and the connection secret is null, debug out - this could be a problem + if (destinationNode->getConnectionSecret().isNull()) { + qDebug() << "LimitedNodeList::writeDatagram called for verified datagram with null connection secret for" + << "destination node" << destinationNode->getUUID() << " - this is either not secure or will cause" + << "this packet to be unverifiable on the receiving side."; + } + // perform replacement of hash and optionally also sequence number in the header if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType); @@ -276,7 +287,7 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, } emit dataSent(destinationNode->getType(), datagram.size()); - auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr, destinationNode->getConnectionSecret()); + auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr); // Keep track of per-destination-node bandwidth destinationNode->recordBytesSent(bytesWritten); return bytesWritten; @@ -301,8 +312,21 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons } } - // don't use the node secret! - return writeDatagram(datagram, *destinationSockAddr, QUuid()); + PacketType packetType = packetTypeForPacket(datagram); + + // optionally peform sequence number replacement in the header + if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { + + QByteArray datagramCopy = datagram; + + PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType); + replaceSequenceNumberInPacket(datagramCopy, sequenceNumber, packetType); + + // send the datagram with sequence number replaced in header + return writeDatagram(datagramCopy, *destinationSockAddr); + } else { + return writeDatagram(datagram, *destinationSockAddr); + } } // didn't have a destinationNode to send to, return 0 @@ -310,7 +334,7 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons } qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr) { - return writeDatagram(datagram, destinationSockAddr, QUuid()); + return writeDatagram(datagram, destinationSockAddr); } qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, @@ -548,11 +572,11 @@ void LimitedNodeList::removeSilentNodes() { eachNodeHashIterator([&](NodeHash::iterator& it){ SharedNodePointer node = it->second; node->getMutex().lock(); - + if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) { // call the NodeHash erase to get rid of this node it = _nodeHash.unsafe_erase(it); - + killedNodes.insert(node); } else { // we didn't erase this node, push the iterator forwards diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 7c710185b1..9f8bf690bf 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -114,6 +114,7 @@ public: const HifiSockAddr& overridenSockAddr = HifiSockAddr()); qint64 writeUnverifiedDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr); + qint64 writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); @@ -233,9 +234,7 @@ protected: LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton - qint64 writeDatagram(const QByteArray& datagram, - const HifiSockAddr& destinationSockAddr, - const QUuid& connectionSecret); + qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr); PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 179f054e42..7a60c51986 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -369,7 +369,7 @@ void NodeList::sendDomainServerCheckIn() { } if (!isUsingDTLS) { - writeDatagram(domainServerPacket, _domainHandler.getSockAddr(), QUuid()); + writeUnverifiedDatagram(domainServerPacket, _domainHandler.getSockAddr()); } const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5; @@ -424,10 +424,9 @@ int NodeList::processDomainServerList(const QByteArray& packet) { _domainHandler.setUUID(uuidFromPacketHeader(packet)); _domainHandler.setIsConnected(true); } - + int readNodes = 0; - - + QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); From fe011e6752771e1587103e09ae4011b3c008eb81 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 May 2015 14:13:27 -0700 Subject: [PATCH 16/19] keep track of out of order sends in AM --- assignment-client/src/avatars/AvatarMixer.cpp | 8 ++++++++ assignment-client/src/avatars/AvatarMixerClientData.cpp | 1 + assignment-client/src/avatars/AvatarMixerClientData.h | 3 +++ 3 files changed, 12 insertions(+) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index f18d19814a..ed663cd01a 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -268,6 +268,14 @@ void AvatarMixer::broadcastAvatarData() { assert(lastSeqToReceiver <= lastSeqFromSender); + if (lastSeqToReceiver > lastSeqFromSender) { + // Did we somehow get out of order packets from the sender? + // We don't expect this to happen - in RELEASE we add this to a trackable stat + // and in DEBUG we crash on the assert above + + } + + // make sure we haven't already sent this data from this sender to this receiver // or that somehow we haven't sent if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index dbdc573b96..197e9baf5e 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -42,6 +42,7 @@ void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { jsonObject["num_avatars_sent_last_frame"] = _numAvatarsSentLastFrame; jsonObject["avg_other_avatar_starves_per_second"] = getAvgNumOtherAvatarStarvesPerSecond(); jsonObject["avg_other_avatar_skips_per_second"] = getAvgNumOtherAvatarSkipsPerSecond(); + jsonObject["total_num_out_of_order_sends"] = _numOutOfOrderSends; jsonObject[OUTBOUND_AVATAR_DATA_STATS_KEY] = getOutboundAvatarDataKbps(); } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index d91dccbdaa..7c7b1f585e 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -62,6 +62,8 @@ public: void recordNumOtherAvatarSkips(int numOtherAvatarSkips) { _otherAvatarSkips.updateAverage((float) numOtherAvatarSkips); } float getAvgNumOtherAvatarSkipsPerSecond() const { return _otherAvatarSkips.getAverageSampleValuePerSecond(); } + void incrementNumOutOfOrderSends() { ++_numOutOfOrderSends; } + int getNumFramesSinceFRDAdjustment() const { return _numFramesSinceAdjustment; } void incrementNumFramesSinceFRDAdjustment() { ++_numFramesSinceAdjustment; } void resetNumFramesSinceFRDAdjustment() { _numFramesSinceAdjustment = 0; } @@ -89,6 +91,7 @@ private: SimpleMovingAverage _otherAvatarStarves; SimpleMovingAverage _otherAvatarSkips; + int _numOutOfOrderSends = 0; SimpleMovingAverage _avgOtherAvatarDataRate; }; From 790f7a08cf2765ef4d5c1e54973e2b805e6b4a30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 May 2015 14:34:06 -0700 Subject: [PATCH 17/19] clean up sequence numbers for killed sending nodes --- assignment-client/src/avatars/AvatarMixer.cpp | 26 +++++++++++++++++-- .../src/avatars/AvatarMixerClientData.h | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index ed663cd01a..79b60ed3c4 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -272,9 +272,8 @@ void AvatarMixer::broadcastAvatarData() { // Did we somehow get out of order packets from the sender? // We don't expect this to happen - in RELEASE we add this to a trackable stat // and in DEBUG we crash on the assert above - + otherNodeData->incrementNumOutOfOrderSends(); } - // make sure we haven't already sent this data from this sender to this receiver // or that somehow we haven't sent @@ -374,12 +373,35 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { if (killedNode->getType() == NodeType::Agent && killedNode->getLinkedData()) { auto nodeList = DependencyManager::get(); + // this was an avatar we were sending to other people // send a kill packet for it to our other nodes QByteArray killPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeKillAvatar); killPacket += killedNode->getUUID().toRfc4122(); nodeList->broadcastToNodes(killPacket, NodeSet() << NodeType::Agent); + + // we also want to remove sequence number data for this avatar on our other avatars + // so invoke the appropriate method on the AvatarMixerClientData for other avatars + nodeList->eachMatchingNode( + [&](const SharedNodePointer& node)->bool { + if (!node->getLinkedData()) { + return false; + } + + if (node->getUUID() == killedNode->getUUID()) { + return false; + } + + return true; + }, + [&](const SharedNodePointer& node) { + QMetaObject::invokeMethod(node->getLinkedData(), + "removeLastBroadcastSequenceNumber", + Qt::AutoConnection, + Q_ARG(const QUuid&, QUuid(killedNode->getUUID()))); + } + ); } } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 7c7b1f585e..3e10b8473a 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -39,6 +39,7 @@ public: PacketSequenceNumber getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const; void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, PacketSequenceNumber sequenceNumber) { _lastBroadcastSequenceNumbers[nodeUUID] = sequenceNumber; } + Q_INVOKABLE void removeLastBroadcastSequenceNumber(const QUuid& nodeUUID) { _lastBroadcastSequenceNumbers.erase(nodeUUID); } quint64 getBillboardChangeTimestamp() const { return _billboardChangeTimestamp; } void setBillboardChangeTimestamp(quint64 billboardChangeTimestamp) { _billboardChangeTimestamp = billboardChangeTimestamp; } From bfccf02912fece35f185aa59af894d46b9e07dda Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 May 2015 15:37:02 -0700 Subject: [PATCH 18/19] use lamdbas for linkedDataCreateCallback --- assignment-client/src/audio/AudioMixer.cpp | 10 +++------- assignment-client/src/avatars/AvatarMixer.cpp | 12 +++--------- assignment-client/src/octree/OctreeServer.cpp | 14 +++++--------- assignment-client/src/octree/OctreeServer.h | 2 -- libraries/networking/src/LimitedNodeList.h | 2 +- 5 files changed, 12 insertions(+), 28 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index a9c0e5ddf2..098569b4f8 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -65,12 +65,6 @@ const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; const QString AUDIO_ENV_GROUP_KEY = "audio_env"; const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer"; -void attachNewNodeDataToNode(Node *newNode) { - if (!newNode->getLinkedData()) { - newNode->setLinkedData(new AudioMixerClientData()); - } -} - InboundAudioStream::Settings AudioMixer::_streamSettings; bool AudioMixer::_printStreamStats = false; @@ -687,7 +681,9 @@ void AudioMixer::run() { nodeList->addNodeTypeToInterestSet(NodeType::Agent); - nodeList->linkedDataCreateCallback = attachNewNodeDataToNode; + nodeList->linkedDataCreateCallback = [](Node* node) { + node->setLinkedData(new AudioMixerClientData()); + }; // wait until we have the domain-server settings, otherwise we bail DomainHandler& domainHandler = nodeList->getDomainHandler(); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 79b60ed3c4..ade1c5a444 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -56,14 +56,6 @@ AvatarMixer::~AvatarMixer() { _broadcastThread.wait(); } -void attachAvatarDataToNode(Node* newNode) { - if (!newNode->getLinkedData()) { - // setup the client linked data - default the number of frames since adjustment - // to our number of frames per second - newNode->setLinkedData(new AvatarMixerClientData()); - } -} - const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f; // NOTE: some additional optimizations to consider. @@ -519,7 +511,9 @@ void AvatarMixer::run() { auto nodeList = DependencyManager::get(); nodeList->addNodeTypeToInterestSet(NodeType::Agent); - nodeList->linkedDataCreateCallback = attachAvatarDataToNode; + nodeList->linkedDataCreateCallback = [] (Node* node) { + node->setLinkedData(new AvatarMixerClientData()); + }; // setup the timer that will be fired on the broadcast thread _broadcastTimer = new QTimer(); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9abace0c5b..361a619744 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -213,14 +213,6 @@ void OctreeServer::trackProcessWaitTime(float time) { _averageProcessWaitTime.updateAverage(time); } -void OctreeServer::attachQueryNodeToNode(Node* newNode) { - if (!newNode->getLinkedData() && _instance) { - OctreeQueryNode* newQueryNodeData = _instance->createOctreeQueryNode(); - newQueryNodeData->init(); - newNode->setLinkedData(newQueryNodeData); - } -} - OctreeServer::OctreeServer(const QByteArray& packet) : ThreadedAssignment(packet), _argc(0), @@ -1132,7 +1124,11 @@ void OctreeServer::run() { setvbuf(stdout, NULL, _IOLBF, 0); #endif - nodeList->linkedDataCreateCallback = &OctreeServer::attachQueryNodeToNode; + nodeList->linkedDataCreateCallback = [] (Node* node) { + OctreeQueryNode* newQueryNodeData = _instance->createOctreeQueryNode(); + newQueryNodeData->init(); + node->setLinkedData(newQueryNodeData); + }; srand((unsigned)time(0)); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 41cd3259cf..ab75efe346 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -75,8 +75,6 @@ public: virtual bool hasSpecialPacketToSend(const SharedNodePointer& node) { return false; } virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { return 0; } - static void attachQueryNodeToNode(Node* newNode); - static float SKIP_TIME; // use this for trackXXXTime() calls for non-times static void trackLoopTime(float time) { _averageLoopTime.updateAverage(time); } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 9f8bf690bf..9420b698ec 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -121,7 +121,7 @@ public: qint64 writeUnverifiedDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); - void(*linkedDataCreateCallback)(Node *); + void (*linkedDataCreateCallback)(Node *); int size() const { return _nodeHash.size(); } From 805250d1e1ec21ec84d51be0271447f857f9559b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 May 2015 09:25:44 -0700 Subject: [PATCH 19/19] don't double conditional to fire SN assert --- assignment-client/src/avatars/AvatarMixer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index ade1c5a444..0b510be151 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -258,13 +258,14 @@ void AvatarMixer::broadcastAvatarData() { PacketSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID()); PacketSequenceNumber lastSeqFromSender = otherNode->getLastSequenceNumberForPacketType(PacketTypeAvatarData); - assert(lastSeqToReceiver <= lastSeqFromSender); - if (lastSeqToReceiver > lastSeqFromSender) { // Did we somehow get out of order packets from the sender? // We don't expect this to happen - in RELEASE we add this to a trackable stat - // and in DEBUG we crash on the assert above + // and in DEBUG we crash on the assert + otherNodeData->incrementNumOutOfOrderSends(); + + assert(false); } // make sure we haven't already sent this data from this sender to this receiver