diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 844e38d0aa..30ce80e1eb 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -213,7 +213,7 @@ void AvatarMixer::broadcastAvatarData() { } // setup a PacketList for the avatarPackets - PacketList avatarPacketList(PacketType::AvatarData); + NLPacketList avatarPacketList(PacketType::AvatarData); // this is an AGENT we have received head data from // send back a packet with other active node data to this node @@ -305,9 +305,9 @@ void AvatarMixer::broadcastAvatarData() { || otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp || randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { - auto billboardPacket { NLPacket::create(PacketType::AvatarBillboard); } - billboardPacket.write(otherNode->getUUID().toRfc4122()); - billboardPacket.write(otherNodeData->getAvatar().getBillboard()); + auto billboardPacket = NLPacket::create(PacketType::AvatarBillboard); + billboardPacket->write(otherNode->getUUID().toRfc4122()); + billboardPacket->write(otherNodeData->getAvatar().getBillboard()); nodeList->sendPacket(std::move(billboardPacket), node); @@ -319,12 +319,12 @@ void AvatarMixer::broadcastAvatarData() { || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp || randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { - auto identityPacket { NLPacket::create(PacketType::AvatarIdentity); } + auto identityPacket = NLPacket::create(PacketType::AvatarIdentity); QByteArray individualData = otherNodeData->getAvatar().identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122()); - identityPacket.write(individualData); + identityPacket->write(individualData); nodeList->sendPacket(std::move(identityPacket), node); @@ -361,8 +361,8 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { // this was an avatar we were sending to other people // send a kill packet for it to our other nodes - auto killPacket { NLPacket::create(PacketType::KillAvatar); } - killPacket.write(killedNode->getUUID().toRfc4122()); + auto killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID); + killPacket->write(killedNode->getUUID().toRfc4122()); nodeList->broadcastToNodes(killPacket, NodeSet() << NodeType::Agent); diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index ee4fdcd8cf..678a448fce 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -235,14 +235,13 @@ void OctreeInboundPacketProcessor::trackInboundPacket(const QUuid& nodeUUID, uns } int OctreeInboundPacketProcessor::sendNackPackets() { - int packetsSent = 0; - if (_shuttingDown) { qDebug() << "OctreeInboundPacketProcessor::sendNackPackets() while shutting down... ignore"; - return packetsSent; + return 0; } - auto nackPacket { NLPacket::create(_myServer->getMyEditNackType(); } + NLPacketList nackPacketList(_myServer->getMyEditNackType(); + auto nodeList = DependencyManager::get(); NodeToSenderStatsMapIterator i = _singleSenderStats.begin(); while (i != _singleSenderStats.end()) { @@ -271,37 +270,25 @@ int OctreeInboundPacketProcessor::sendNackPackets() { // construct nack packet(s) for this node const QSet& missingSequenceNumbers = sequenceNumberStats.getMissingSet(); - int numSequenceNumbersAvailable = missingSequenceNumbers.size(); - QSet::const_iterator missingSequenceNumberIterator = missingSequenceNumbers.constBegin(); - while (numSequenceNumbersAvailable > 0) { - auto nodeList = DependencyManager::get(); + auto it = missingSequenceNumbers.constBegin(); - nackPacket->reset(); - - // calculate and pack the number of sequence numbers to nack - int numSequenceNumbersRoomFor = (nackPacket->getCapacity() - sizeof(uint16_t)) / sizeof(unsigned short int); - uint16_t numSequenceNumbers = std::min(numSequenceNumbersAvailable, numSequenceNumbersRoomFor); - - nackPacket->write(&numSequenceNumbers, sizeof(numSequenceNumbers)); - - // pack sequence numbers to nack - for (uint16_t i = 0; i < numSequenceNumbers; i++) { - unsigned short int sequenceNumber = *missingSequenceNumberIterator; - nackPacket->write(&sequenceNumber, sizeof(sequenceNumber)); - - missingSequenceNumberIterator++; - } - numSequenceNumbersAvailable -= numSequenceNumbers; - - // send it - nodeList->sendUnreliablePacket(nackPacket, destinationNode); - packetsSent++; - - qDebug() << "NACK Sent back to editor/client... destinationNode=" << nodeUUID; + while (it != missingSequenceNumbers.constEnd()) { + unsigned short int sequenceNumber = *it; + nackPacketList->write(&sequenceNumber, sizeof(sequenceNumber)); + ++it; } - i++; } + + int packetsSent = nackPacketList.getNumPackets(); + + if (packetsSent) { + qDebug() << "NACK Sent back to editor/client... destinationNode=" << nodeUUID; + } + + // send the list of nack packets + nodeList->sendPacketList(nackPacketList, destinationNode); + return packetsSent; } diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 3b7f7d1bd5..173c1dd840 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -108,9 +108,9 @@ bool OctreeQueryNode::packetIsDuplicate() const { // since our packets now include header information, like sequence number, and createTime, we can't just do a memcmp // of the entire packet, we need to compare only the packet content... - if (_lastOctreePacketLength == getPacketLength()) { + if (_lastOctreePacketLength == _octreePacket->getSizeUsed()) { if (memcmp(_lastOctreePayload + OCTREE_PACKET_EXTRA_HEADERS_SIZE, - _octreePacket->getPayload() + OCTREE_PACKET_EXTRA_HEADERS_SIZE, + _octreePacket->getPayload() + OCTREE_PACKET_EXTRA_HEADERS_SIZE, _octreePacket->getSizeUsed() - OCTREE_PACKET_EXTRA_HEADERS_SIZE) == 0) { return true; } @@ -379,6 +379,8 @@ void OctreeQueryNode::parseNackPacket(const QByteArray& packet) { int numBytesPacketHeader = numBytesForPacketHeader(packet); const unsigned char* dataAt = reinterpret_cast(packet.data()) + numBytesPacketHeader; + // TODO: This no longer has the number of sequence numbers - just read to the end of the packet in sequence number blocks + // read number of sequence numbers uint16_t numSequenceNumbers = (*(uint16_t*)dataAt); dataAt += sizeof(uint16_t); diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index d9ef20553f..e675431434 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -147,7 +147,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes NLPacket& statsPacket = nodeData->stats.getStatsMessage(); // If the size of the stats message and the octree message will fit in a packet, then piggyback them - if (nodeData->getPacket()->getSizeUsed() < statsPacket->bytesAvailable()) { + if (nodeData->getPacket()->getSizeWithHeader() < statsPacket->bytesAvailable()) { // copy octree message to back of stats message statsPacket->write(nodeData->getPacket()->getData(), nodeData->getPacket()->getSizeWithHeader()); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 4feb0ebe92..96980a6f48 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -622,8 +622,8 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock QByteArray utfString = reason.toUtf8(); int payloadSize = utfString.size(); - auto connectionDeniedPacket = NLPacket::make(PacketType::DomainConnectionDenied, payloadSize); - connectionDeniedPacket.write(utfString); + auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, payloadSize); + connectionDeniedPacket->write(utfString); // tell client it has been refused. limitedNodeList->sendPacket(std::move(connectionDeniedPacket, senderSockAddr); @@ -927,7 +927,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif const NodeSet& nodeInterestSet) { auto limitedNodeList = DependencyManager::get(); - PacketList domainListPackets(PacketType::DomainList); + NLPacketList domainListPackets(PacketType::DomainList); // always send the node their own UUID back QDataStream domainListStream(&domainListPackets); @@ -1448,7 +1448,7 @@ void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiS processICEPingReply(receivedPacket, senderSockAddr); break; } - case PacketTypeIceServerPeerInformation: + case PacketType::ICEServerPeerInformation: processICEPeerInformation(receivedPacket); break; default: diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 298d8ded8e..ec93204e85 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -127,7 +127,7 @@ SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(const QByteArray& incom } void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr) { - auto peerPacket { NLPacket::create(PacketType::IceServerPeerInformation); } + auto peerPacket = Packet::create(PacketType::IceServerPeerInformation); // get the byte array for this peer peerPacket->write(peer.toByteArray()); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 06aa5cd36d..d91575c950 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2660,9 +2660,7 @@ int Application::sendNackPackets() { return 0; } - int packetsSent = 0; - - auto nackPacket { NLPacket::create(PacketType::OctreeDataNack); } + NLPacketList nackPacketList(PacketType::OctreeDataNack); // iterates thru all nodes in NodeList auto nodeList = DependencyManager::get(); @@ -2676,7 +2674,7 @@ int Application::sendNackPackets() { // if there are octree packets from this node that are waiting to be processed, // don't send a NACK since the missing packets may be among those waiting packets. if (_octreeProcessor.hasPacketsToProcessFrom(nodeUUID)) { - return; + return 0; } _octreeSceneStatsLock.lockForRead(); @@ -2684,7 +2682,7 @@ int Application::sendNackPackets() { // retreive octree scene stats of this node if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) { _octreeSceneStatsLock.unlock(); - return; + return 0; } // get sequence number stats of node, prune its missing set, and make a copy of the missing set @@ -2696,34 +2694,23 @@ int Application::sendNackPackets() { // construct nack packet(s) for this node int numSequenceNumbersAvailable = missingSequenceNumbers.size(); - QSet::const_iterator missingSequenceNumbersIterator = missingSequenceNumbers.constBegin(); - while (numSequenceNumbersAvailable > 0) { - // reset the position we are writing at and the size we have used - nackPacket->seek(0); - nackPacket->setSizeUsed(0); - - // calculate and pack the number of sequence numbers - int numSequenceNumbersRoomFor = (nackPacket->size() - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE); - uint16_t numSequenceNumbers = min(numSequenceNumbersAvailable, numSequenceNumbersRoomFor); - - nackPacket->write(&numSequenceNumbers, sizeof(numSequenceNumbers)); - - // pack sequence numbers - for (int i = 0; i < numSequenceNumbers; i++) { - OCTREE_PACKET_SEQUENCE missingNumber = *missingSequenceNumbersIterator; - nackPacket->write(&missingNumber, sizeof(OCTREE_PACKET_SEQUENCE)); - missingSequenceNumbersIterator++; - } - numSequenceNumbersAvailable -= numSequenceNumbers; - - // send the packet - nodeList->sendUnreliablePacket(packet, node); - packetsSent++; + auto it = missingSequenceNumbers.constBegin(); + while (it != missingSequenceNumbers.constEnd()) { + OCTREE_PACKET_SEQUENCE missingNumber = *it; + nackPacketList->write(&missingNumber, sizeof(OCTREE_PACKET_SEQUENCE)); + ++it; } } }); + int packetsSent = nackPacketList.getNumPackets(); + + if (packetsSent) { + // send the packet list + nodeList->sendPacketList(nackPacketList, node); + } + return packetsSent; } @@ -2817,7 +2804,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType::Value packetTyp qCDebug(interfaceapp, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer); } - auto queryPacket { NLPacket::create(packetType); } + auto queryPacket = NLPacket::create(packetType); nodeList->eachNode([&](const SharedNodePointer& node){ // only send to the NodeTypes that are serverType @@ -2896,7 +2883,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType::Value packetTyp // encode the query data int packetSize = _octreeQuery.getBroadcastData(queryPacket.payload()); - queryPacket.setSizeUsed(packetSize); + queryPacket->setSizeUsed(packetSize); // make sure we still have an active socket nodeList->sendUnreliablePacket(queryPacket, node); diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index acca48ce35..57bbd5f292 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -853,11 +853,7 @@ void AudioClient::handleAudioInput() { } } - // seek to the beginning of the audio packet payload - _audioPacket->seek(0); - - // reset the size used in this packet so it will be correct once we are done writing - _audioPacket->setSizeUsed(0); + // reset the audio packet so we can start writing // write sequence number _audioPacket->write(&_outgoingAvatarAudioSequenceNumber, sizeof(quint16)); @@ -913,14 +909,14 @@ void AudioClient::sendMuteEnvironmentPacket() { int dataSize = sizeof(glm::vec3) + sizeof(float); - NodeList::Packet mutePacket = nodeList->makePacket(PacketType::MuteEnvironment, dataSize); + auto mutePacket = NLPacket::create(PacketType::MuteEnvironment, dataSize); const float MUTE_RADIUS = 50; glm::vec3 currentSourcePosition = _positionGetter(); - memcpy(mutePacket.payload().data(), ¤tSourcePosition, sizeof(glm::vec3)); - memcpy(mutePacket.payload() + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); + mutePacket->write(¤tSourcePosition, sizeof(currentSourcePosition)); + mutePacket->write(&MUTE_RADIUS, sizeof(MUTE_RADIUS)); // grab our audio mixer from the NodeList, if it exists SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 96bca798e3..7dfaa1fdb5 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -153,7 +153,7 @@ void AudioInjector::injectToMixer() { // make sure we actually have samples downloaded to inject if (_audioData.size()) { - auto audioPacket { NLPacket::create(PacketType::InjectAudio); } + auto audioPacket = NLPacket::create(PacketType::InjectAudio); // setup the packet for injected audio QDataStream audioPacketStream(&audioPacket); @@ -177,7 +177,6 @@ void AudioInjector::injectToMixer() { sizeof(_options.position)); // pack our orientation for injected audio - int orientationOptionOffset = audioPacket.pos(); audioPacketStream.writeRawData(reinterpret_cast(&_options.orientation), sizeof(_options.orientation)); @@ -216,23 +215,24 @@ void AudioInjector::injectToMixer() { } _loudness /= (float)(bytesToCopy / sizeof(int16_t)); - audioPacket.seek(positionOptionOffset); - audioPacket.write(&_options.position, sizeof(_options.position)); - - audioPacket.seek(orientationOptionOffset); + audioPacket->seek(positionOptionOffset); + audioPacket->write(&_options.position, sizeof(_options.position)); audioPacket.write(&_options.orientation, sizeof(_options.orientation)); volume = MAX_INJECTOR_VOLUME * _options.volume; - audioPacket.seek(volumeOptionOffset); - audioPacket.write(&volume, sizeof(volume)); + audioPacket->seek(volumeOptionOffset); + audioPacket->write(&volume, sizeof(volume)); - audioPacket.seek(audioDataOffset); + audioPacket->seek(audioDataOffset); // pack the sequence number - audioPacket.write(&outgoingInjectedAudioSequenceNumber, sizeof(quint16)); + audioPacket->write(&outgoingInjectedAudioSequenceNumber, sizeof(quint16)); // copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet - audioPacket.write(_audioData.data() + _currentSendPosition, bytesToCopy); + audioPacket->write(_audioData.data() + _currentSendPosition, bytesToCopy); + + // set the correct size used for this packet + audioPacket->setSizeUsed(audioPacket->pos()); // grab our audio mixer from the NodeList, if it exists SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 235427d705..e40f453238 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -521,11 +521,11 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t // return n; // } -NLPacket&& LimitedNodeList::constructPingPacket(PingType_t pingType) { +std::unique_ptr LimitedNodeList::constructPingPacket(PingType_t pingType) { int packetSize = sizeof(PingType_t) + sizeof(quint64); - auto pingPacket { NLPacket::create(PacketType::Ping, packetSize); } + auto pingPacket = NLPacket::create(PacketType::Ping, packetSize); - QDataStream packetStream(&pingPacket.payload(), QIODevice::Append); + QDataStream packetStream(&pingPacket); packetStream << pingType; packetStream << usecTimestampNow(); @@ -533,7 +533,7 @@ NLPacket&& LimitedNodeList::constructPingPacket(PingType_t pingType) { return pingPacket; } -NLPacket&& LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket) { +std::unique_ptr LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket) { QDataStream pingPacketStream(pingPacket); pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket)); @@ -545,37 +545,37 @@ NLPacket&& LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacke int packetSize = sizeof(PingType_t) + sizeof(quint64) + sizeof(quint64); - auto replyPacket { NLPacket::create(PacketType::Ping, packetSize); } + auto replyPacket = NLPacket::create(PacketType::Ping, packetSize); - QDataStream packetStream(&replyPacket, QIODevice::Append); + QDataStream packetStream(&replyPacket); packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); return replyPacket; } -NLPacket&& constructICEPingPacket(PingType_t pingType, const QUuid& iceID) { +std::unique_ptr constructICEPingPacket(PingType_t pingType, const QUuid& iceID) { int packetSize = NUM_BYTES_RFC4122_UUID + sizeof(PingType_t); - auto icePingPacket { NLPacket::create(PacketType::ICEPing, packetSize); } + auto icePingPacket = NLPacket::create(PacketType::ICEPing, packetSize); - icePingPacket.payload().replace(0, NUM_BYTES_RFC4122_UUID, iceID.toRfc4122().data()); - memcpy(icePingPacket.payload() + NUM_BYTES_RFC4122_UUID, &pingType, sizeof(PingType_t)); + icePingPacket->write(iceID.toRfc4122()); + icePingPacket->write(&pingType, sizeof(pingType)); return icePingPacket; } -NLPacket&& constructICEPingReplyPacket(const QByteArray& pingPacket, const QUuid& iceID) { +std::unique_ptr constructICEPingReplyPacket(const QByteArray& pingPacket, const QUuid& iceID) { // pull out the ping type so we can reply back with that PingType_t pingType; memcpy(&pingType, pingPacket.data() + NUM_BYTES_RFC4122_UUID, sizeof(PingType_t)); int packetSize = NUM_BYTES_RFC4122_UUID + sizeof(PingType_t); - auto icePingReplyPacket { NLPacket::create(PacketType::ICEPingReply, packetSize); } + auto icePingReplyPacket = NLPacket::create(PacketType::ICEPingReply, packetSize); // pack the ICE ID and then the ping type - memcpy(icePingReplyPacket.payload(), iceID.toRfc4122().data(), NUM_BYTES_RFC4122_UUID); - memcpy(icePingReplyPacket.payload() + NUM_BYTES_RFC4122_UUID, &pingType, sizeof(PingType_t)); + icePingReplyPacket->write(iceID.toRfc4122()); + icePingReplyPacket->write(&pingType, sizeof(pingType)); return icePingReplyPacket; } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index ceb0427ef0..078207077c 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -38,6 +38,7 @@ #include "Node.h" #include "NLPacket.h" #include "PacketHeaders.h" +#include "PacketList.h" #include "UUIDHasher.h" const int MAX_PACKET_SIZE = 1450; @@ -67,6 +68,7 @@ Q_DECLARE_METATYPE(SharedNodePointer) using namespace tbb; typedef std::pair UUIDNodePair; typedef concurrent_unordered_map NodeHash; +using NLPacketList = PacketList; typedef quint8 PingType_t; namespace PingType { @@ -143,12 +145,12 @@ public: // const HifiSockAddr& overridenSockAddr = HifiSockAddr()); // - qint64 sendUnreliablePacket(NLPacket& packet, const SharedNodePointer& destinationNode) {}; - qint64 sendUnreliablePacket(NLPacket& packet, const HifiSockAddr& sockAddr) {}; - qint64 sendPacket(NLPacket&& packet, const SharedNodePointer& destinationNode) {}; - qint64 sendPacket(NLPacket&& packet, const HifiSockAddr& sockAddr) {}; - qint64 sendPacketList(PacketList& packetList, const SharedNodePointer& destinationNode) {}; - qint64 sendPacketList(PacketList& packetList, const HifiSockAddr& sockAddr) {}; + qint64 sendUnreliablePacket(std::unique_ptr& packet, const SharedNodePointer& destinationNode) {}; + qint64 sendUnreliablePacket(std::unique_ptr& packet, const HifiSockAddr& sockAddr) {}; + qint64 sendPacket(std::unique_ptr packet, const SharedNodePointer& destinationNode) {}; + qint64 sendPacket(std::unique_ptr packet, const HifiSockAddr& sockAddr) {}; + qint64 sendPacketList(NLPacketList& packetList, const SharedNodePointer& destinationNode) {}; + qint64 sendPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr) {}; void (*linkedDataCreateCallback)(Node *); @@ -173,17 +175,17 @@ public: int updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray& packet); int findNodeAndUpdateWithDataFromPacket(const QByteArray& packet); - unsigned broadcastToNodes(PacketList& packetList, const NodeSet& destinationNodeTypes) {}; + unsigned broadcastToNodes(std::unique_ptr packet, const NodeSet& destinationNodeTypes) {}; SharedNodePointer soloNodeOfType(char nodeType); void getPacketStats(float &packetsPerSecond, float &bytesPerSecond); void resetPacketStats(); - NLPacket&& constructPingPacket(PingType_t pingType = PingType::Agnostic); - NLPacket&& constructPingReplyPacket(const QByteArray& pingPacket); + std::unique_ptr constructPingPacket(PingType_t pingType = PingType::Agnostic); + std::unique_ptr constructPingReplyPacket(const QByteArray& pingPacket); - NLPacket&& constructICEPingPacket(PingType_t pingType, const QUuid& iceID); - NLPacket&& constructICEPingReplyPacket(const QByteArray& pingPacket, const QUuid& iceID); + std::unique_ptr constructICEPingPacket(PingType_t pingType, const QUuid& iceID); + std::unique_ptr constructICEPingReplyPacket(const QByteArray& pingPacket, const QUuid& iceID); virtual bool processSTUNResponse(const QByteArray& packet); diff --git a/libraries/networking/src/NetworkPacket.cpp b/libraries/networking/src/NetworkPacket.cpp index fb1c90e392..26c7939aaa 100644 --- a/libraries/networking/src/NetworkPacket.cpp +++ b/libraries/networking/src/NetworkPacket.cpp @@ -24,7 +24,7 @@ NetworkPacket::NetworkPacket(const NetworkPacket& other) : } NetworkPacket::NetworkPacket(const SharedNodePointer& node, const NLPacket& packet) { - if (packet.getSizeWitHeader() && packet.getSizeWithHeader() <= MAX_nlPacket_SIZE) { + if (packet.getSizeWithHeader() && packet.getSizeWithHeader() <= MAX_PACKET_SIZE) { _node = node; _nlPacket = packet; } else { diff --git a/libraries/networking/src/NetworkPacket.h b/libraries/networking/src/NetworkPacket.h index c42ad286ae..a4484f31d5 100644 --- a/libraries/networking/src/NetworkPacket.h +++ b/libraries/networking/src/NetworkPacket.h @@ -19,7 +19,7 @@ /// Storage of not-yet processed inbound, or not yet sent outbound generic UDP network packet class NetworkPacket { public: - NetworkPacket() { } + NetworkPacket(); NetworkPacket(const NetworkPacket& packet); // copy constructor NetworkPacket& operator= (const NetworkPacket& other); // copy assignment diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index f329ec7333..21b3bdff96 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -422,10 +422,10 @@ void NodeList::sendDSPathQuery(const QString& newPath) { if (numPathBytes + sizeof(numPathBytes) < pathQueryPacket.size() ) { // append the size of the path to the query packet - pathQueryPacket.write(&numPathBytes, sizeof(numPathBytes)); + pathQueryPacket->write(&numPathBytes, sizeof(numPathBytes)); // append the path itself to the query packet - pathQueryPacket.write(pathQueryUTF8); + pathQueryPacket->write(pathQueryUTF8); qCDebug(networking) << "Sending a path query packet for path" << newPath << "to domain-server at" << _domainHandler.getSockAddr(); diff --git a/libraries/networking/src/Packet.cpp b/libraries/networking/src/Packet.cpp index ca49100efe..65d0899a94 100644 --- a/libraries/networking/src/Packet.cpp +++ b/libraries/networking/src/Packet.cpp @@ -38,6 +38,12 @@ std::unique_ptr Packet::create(PacketType::Value type, qint64 size) { return std::unique_ptr(new Packet(type, size)); } + +std::unique_ptr Packet::createCopy(const std::unique_ptr& other) { + Q_ASSERT(other); + return std::unique_ptr(new Packet(*other)); +} + qint64 Packet::totalHeadersSize() const { return localHeaderSize(); } @@ -56,11 +62,11 @@ Packet::Packet(PacketType::Value type, qint64 size) : Q_ASSERT(size <= maxPayloadSize(type)); // copy packet type and version in header - setPacketTypeAndVersion(type); + writePacketTypeAndVersion(type); // Set control bit and sequence number to 0 if necessary if (SEQUENCE_NUMBERED_PACKETS.contains(type)) { - setSequenceNumber(0); + writeSequenceNumber(0); } } @@ -74,7 +80,6 @@ Packet& Packet::operator=(const Packet& other) { memcpy(_packet.get(), other._packet.get(), _packetSize); _payloadStart = _packet.get() + (other._payloadStart - other._packet.get()); - _position = other._position; _capacity = other._capacity; _sizeUsed = other._sizeUsed; @@ -91,7 +96,6 @@ Packet& Packet::operator=(Packet&& other) { _packet = std::move(other._packet); _payloadStart = other._payloadStart; - _position = other._position; _capacity = other._capacity; _sizeUsed = other._sizeUsed; @@ -99,15 +103,24 @@ Packet& Packet::operator=(Packet&& other) { return *this; } -PacketType::Value Packet::getPacketType() const { +void Packet::setPacketType(PacketType::Value type) { + auto currentHeaderSize = totalHeadersSize(); + _type = type; + writePacketTypeAndVersion(_type); + + // Setting new packet type with a different header size not currently supported + Q_ASSERT(currentHeaderSize == totalHeadersSize()); +} + +PacketType::Value Packet::readPacketType() const { return (PacketType::Value)arithmeticCodingValueFromBuffer(_packet.get()); } -PacketVersion Packet::getPacketTypeVersion() const { +PacketVersion Packet::readPacketTypeVersion() const { return *reinterpret_cast(_packet.get() + numBytesForArithmeticCodedPacketType(_type)); } -Packet::SequenceNumber Packet::getSequenceNumber() const { +Packet::SequenceNumber Packet::readSequenceNumber() const { if (SEQUENCE_NUMBERED_PACKETS.contains(_type)) { SequenceNumber seqNum = *reinterpret_cast(_packet.get() + numBytesForArithmeticCodedPacketType(_type) + @@ -117,7 +130,7 @@ Packet::SequenceNumber Packet::getSequenceNumber() const { return -1; } -bool Packet::isControlPacket() const { +bool Packet::readIsControlPacket() const { if (SEQUENCE_NUMBERED_PACKETS.contains(_type)) { SequenceNumber seqNum = *reinterpret_cast(_packet.get() + numBytesForArithmeticCodedPacketType(_type) + @@ -127,16 +140,16 @@ bool Packet::isControlPacket() const { return false; } -void Packet::setPacketTypeAndVersion(PacketType::Value type) { +void Packet::writePacketTypeAndVersion(PacketType::Value type) { // Pack the packet type auto offset = packArithmeticallyCodedValue(type, _packet.get()); // Pack the packet version - auto version { versionForPacketType(type) }; + auto version = versionForPacketType(type); memcpy(_packet.get() + offset, &version, sizeof(version)); } -void Packet::setSequenceNumber(SequenceNumber seqNum) { +void Packet::writeSequenceNumber(SequenceNumber seqNum) { // Here we are overriding the control bit to 0. // But that is not an issue since we should only ever set the seqNum // for data packets going out @@ -144,14 +157,6 @@ void Packet::setSequenceNumber(SequenceNumber seqNum) { &seqNum, sizeof(seqNum)); } -bool Packet::seek(qint64 pos) { - bool valid = (pos >= 0) && (pos < size()); - if (valid) { - _position = pos; - } - return valid; -} - static const qint64 PACKET_WRITE_ERROR = -1; qint64 Packet::writeData(const char* data, qint64 maxSize) { // make sure we have the space required to write this block diff --git a/libraries/networking/src/Packet.h b/libraries/networking/src/Packet.h index 6177cbd60e..9d58d1e2e1 100644 --- a/libraries/networking/src/Packet.h +++ b/libraries/networking/src/Packet.h @@ -23,6 +23,8 @@ public: using SequenceNumber = uint16_t; static std::unique_ptr create(PacketType::Value type, int64_t size = -1); + // Provided for convenience, try to limit use + static std::unique_ptr createCopy(const std::unique_ptr& other); static qint64 localHeaderSize(PacketType::Value type); static qint64 maxPayloadSize(PacketType::Value type); @@ -30,56 +32,59 @@ public: virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers virtual qint64 localHeaderSize() const; // Current level's header size - // Payload direct access, use responsibly! + // Payload direct access to the payload, use responsibly! char* getPayload() { return _payloadStart; } const char* getPayload() const { return _payloadStart; } + // Return direct access to the entire packet, use responsibly! + char* getData() { return _packet.get(); } + const char* getData() const { return _packet.get(); } + + PacketType::Value getPacketType() const { return _type; } + void setPacketType(PacketType::Value type); + qint64 getSizeWithHeader() const { return localHeaderSize() + getSizeUsed(); } qint64 getSizeUsed() const { return _sizeUsed; } void setSizeUsed(qint64 sizeUsed) { _sizeUsed = sizeUsed; } // Header readers - PacketType::Value getPacketType() const; - PacketVersion getPacketTypeVersion() const; - SequenceNumber getSequenceNumber() const; - bool isControlPacket() const; + PacketType::Value readPacketType() const; + PacketVersion readPacketTypeVersion() const; + SequenceNumber readSequenceNumber() const; + bool readIsControlPacket() const; // QIODevice virtual functions // WARNING: Those methods all refer to the payload ONLY and NOT the entire packet - virtual bool atEnd() const { return _position == _capacity; } - virtual qint64 bytesAvailable() const { return size() - pos(); } - virtual bool canReadLine() const { return false; } virtual bool isSequential() const { return false; } - virtual qint64 pos() const { return _position; } - virtual bool reset() { return seek(0); } - virtual bool seek(qint64 pos); + virtual bool reset() { setSizeUsed(0); return QIODevice::reset(); } virtual qint64 size() const { return _capacity; } protected: Packet(PacketType::Value type, int64_t size); - Packet(const Packet& other); - Packet& operator=(const Packet& other); - Packet(Packet&& other); - Packet& operator=(Packet&& other); // QIODevice virtual functions virtual qint64 writeData(const char* data, qint64 maxSize); virtual qint64 readData(char* data, qint64 maxSize); // Header writers - void setPacketTypeAndVersion(PacketType::Value type); - void setSequenceNumber(SequenceNumber seqNum); + void writePacketTypeAndVersion(PacketType::Value type); + void writeSequenceNumber(SequenceNumber seqNum); - PacketType::Value _type; + PacketType::Value _type; // Packet type qint64 _packetSize = 0; // Total size of the allocated memory std::unique_ptr _packet; // Allocated memory char* _payloadStart = nullptr; // Start of the payload - qint64 _position = 0; // Current position in the payload qint64 _capacity = 0; // Total capacity of the payload qint64 _sizeUsed = 0; // How much of the payload is actually used + +private: + Packet(const Packet& other); + Packet& operator=(const Packet& other); + Packet(Packet&& other); + Packet& operator=(Packet&& other); }; #endif // hifi_Packet_h \ No newline at end of file diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 02097402c6..cab062165f 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -82,17 +82,23 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case DomainList: case DomainListRequest: return 5; + case DomainConnectRequest: + return 1; case CreateAssignment: case RequestAssignment: return 2; case OctreeStats: return 1; + case OctreeDataNack: + return 1; case StopNode: return 1; case EntityAdd: case EntityEdit: case EntityData: return VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE; + case EntityEditNack: + return 1; case EntityErase: return 2; case AudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index b164081d0d..132bff6419 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -52,8 +52,8 @@ namespace PacketType { DomainServerPathQuery, DomainServerPathResponse, DomainServerAddedNode, - IceServerPeerInformation, - IceServerQuery, // 25 + ICEServerPeerInformation, + ICEServerQuery, // 25 OctreeStats, Jurisdiction, JurisdictionRequest, diff --git a/libraries/networking/src/PacketList.cpp b/libraries/networking/src/PacketList.cpp index bb044d6ae7..01d4c61089 100644 --- a/libraries/networking/src/PacketList.cpp +++ b/libraries/networking/src/PacketList.cpp @@ -12,18 +12,17 @@ #include "PacketList.h" PacketList::PacketList(PacketType::Value packetType) : - _packetType(packetType), - _isOrdered(false) + _packetType(packetType) { } void PacketList::createPacketWithExtendedHeader() { // use the static create method to create a new packet - _currentPacket = T::create(_packetType); + auto packet = T::create(_packetType); // add the extended header to the front of the packet - if (_currentPacket.write(_extendedHeader) == -1) { + if (packet->write(_extendedHeader) == -1) { qDebug() << "Could not write extendedHeader in PacketList::createPacketWithExtendedHeader" << "- make sure that _extendedHeader is not larger than the payload capacity."; } @@ -32,7 +31,7 @@ void PacketList::createPacketWithExtendedHeader() { qint64 writeData(const char* data, qint64 maxSize) { if (!_currentPacket) { // we don't have a current packet, time to set one up - createPacketWithExtendedHeader(); + _currentPacket = createPacketWithExtendedHeader(); } // check if this block of data can fit into the currentPacket @@ -46,7 +45,7 @@ qint64 writeData(const char* data, qint64 maxSize) { // it does not fit - this may need to be in the next packet if (!_isOrdered) { - auto newPacket = T::create(_packetType); + auto newPacket = createPacketWithExtendedHeader(); if (_segmentStartIndex >= 0) { // We in the process of writing a segment for an unordered PacketList. @@ -64,7 +63,7 @@ qint64 writeData(const char* data, qint64 maxSize) { } // copy from currentPacket where the segment started to the beginning of the newPacket - newPacket.write(currentPacket.constData() + _segmentStartIndex, numBytesToEnd); + newPacket.write(currentPacket->getPayload() + _segmentStartIndex, numBytesToEnd); // the current segment now starts at the beginning of the new packet _segmentStartIndex = 0; @@ -89,7 +88,7 @@ qint64 writeData(const char* data, qint64 maxSize) { // into a new packet int numBytesToEnd = _currentPacket.size() - _currentPacket.sizeUsed(); - _currentPacket.write(data, numBytesToEnd); + _currentPacket->write(data, numBytesToEnd); // move the current packet to our list of packets _packets.insert(std::move(_currentPacket)); diff --git a/libraries/networking/src/PacketList.h b/libraries/networking/src/PacketList.h index ae94273953..e03e152532 100644 --- a/libraries/networking/src/PacketList.h +++ b/libraries/networking/src/PacketList.h @@ -12,7 +12,9 @@ #ifndef hifi_PacketList_h #define hifi_PacketList_h -#pragma once +#include + +#include "PacketHeaders.h" template class PacketList : public QIODevice { public: @@ -20,7 +22,7 @@ public: virtual bool isSequential() const { return true; } - void startSegment() { _segmentStartIndex = currentPacket->payload().pos(); } + void startSegment() { _segmentStartIndex = _currentPacket->payload().pos(); } void endSegment() { _segmentStartIndex = -1; } int getNumPackets() const { return _packets.size() + (_currentPacket ? 1 : 0); } @@ -30,19 +32,19 @@ public: void setExtendedHeader(const QByteArray& extendedHeader) { _extendedHeader = extendedHeader; } protected: qint64 writeData(const char* data, qint64 maxSize); - qint64 readData(const char* data, qint64 maxSize) { return 0 }; + qint64 readData(const char* data, qint64 maxSize) { return 0; }; private: - void createPacketWithExtendedHeader(); + std::unique_ptr createPacketWithExtendedHeader(); PacketType::Value _packetType; - bool isOrdered; + bool isOrdered = false; std::unique_ptr _currentPacket; std::list> _packets; int _segmentStartIndex = -1; - QByteArray _extendedHeader = extendedHeader; -} + QByteArray _extendedHeader; +}; #endif // hifi_PacketList_h diff --git a/libraries/networking/src/SentPacketHistory.cpp b/libraries/networking/src/SentPacketHistory.cpp index 3b0958f1ea..980646a082 100644 --- a/libraries/networking/src/SentPacketHistory.cpp +++ b/libraries/networking/src/SentPacketHistory.cpp @@ -30,7 +30,7 @@ void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& pack << "Expected:" << expectedSequenceNumber << "Actual:" << sequenceNumber; } _newestSequenceNumber = sequenceNumber; - _sentPackets.insert(new NLPacket(packet)); + _sentPackets.insert(NLPacket::createCopy(packet)); } const QByteArray* SentPacketHistory::getPacket(uint16_t sequenceNumber) const { diff --git a/libraries/networking/src/SentPacketHistory.h b/libraries/networking/src/SentPacketHistory.h index 566fd2dbfc..04cfdb3d36 100644 --- a/libraries/networking/src/SentPacketHistory.h +++ b/libraries/networking/src/SentPacketHistory.h @@ -23,10 +23,10 @@ public: SentPacketHistory(int size = MAX_REASONABLE_SEQUENCE_GAP); void packetSent(uint16_t sequenceNumber, const NLPacket& packet); - const NLPacket* getPacket(uint16_t sequenceNumber) const; + const std::unique_ptr& getPacket(uint16_t sequenceNumber) const; private: - RingBufferHistory _sentPackets; // circular buffer + RingBufferHistory> _sentPackets; // circular buffer uint16_t _newestSequenceNumber; }; diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index e6c1a2fa35..52c68c3e96 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -30,7 +30,7 @@ OctreeEditPacketSender::OctreeEditPacketSender() : _maxPacketSize(MAX_PACKET_SIZE), _destinationWalletUUID() { - + } OctreeEditPacketSender::~OctreeEditPacketSender() { @@ -52,10 +52,10 @@ OctreeEditPacketSender::~OctreeEditPacketSender() { bool OctreeEditPacketSender::serversExist() const { bool hasServers = false; bool atLeastOneJurisdictionMissing = false; // assume the best - + DependencyManager::get()->eachNodeBreakable([&](const SharedNodePointer& node){ if (node->getType() == getMyNodeType() && node->getActiveSocket()) { - + QUuid nodeUUID = node->getUUID(); // If we've got Jurisdictions set, then check to see if we know the jurisdiction for this server if (_serverJurisdictions) { @@ -69,7 +69,7 @@ bool OctreeEditPacketSender::serversExist() const { } hasServers = true; } - + if (atLeastOneJurisdictionMissing) { return false; // no point in looking further - return false from anonymous function } else { @@ -91,27 +91,27 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c if (node->getType() == getMyNodeType() && ((node->getUUID() == nodeUUID) || (nodeUUID.isNull())) && node->getActiveSocket()) { - + // pack sequence number int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(buffer)); unsigned char* sequenceAt = buffer + numBytesPacketHeader; quint16 sequence = _outgoingSequenceNumbers[nodeUUID]++; memcpy(sequenceAt, &sequence, sizeof(quint16)); - + // send packet QByteArray packet(reinterpret_cast(buffer), length); - + queuePacketForSending(node, packet); - + if (hasDestinationWalletUUID() && satoshiCost > 0) { // if we have a destination wallet UUID and a cost associated with this packet, signal that it // needs to be sent emit octreePaymentRequired(satoshiCost, nodeUUID, _destinationWalletUUID); } - + // add packet to history _sentPacketHistories[nodeUUID].packetSent(sequence, packet); - + // debugging output... if (wantDebug) { int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(buffer)); @@ -119,7 +119,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c quint64 createdAt = (*((quint64*)(buffer + numBytesPacketHeader + sizeof(sequence)))); quint64 queuedAt = usecTimestampNow(); quint64 transitTime = queuedAt - createdAt; - + qCDebug(octree) << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] << " - command to node bytes=" << length << " satoshiCost=" << satoshiCost << @@ -192,7 +192,7 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, size_t le // But we can't really do that with a packed message, since each edit message could be destined // for a different server... So we need to actually manage multiple queued packets... one // for each server - + DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ // only send to the NodeTypes that are getMyNodeType() if (node->getActiveSocket() && node->getType() == getMyNodeType()) { @@ -251,7 +251,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, unsi if (node->getActiveSocket() && node->getType() == getMyNodeType()) { QUuid nodeUUID = node->getUUID(); bool isMyJurisdiction = true; - + if (type == PacketTypeEntityErase) { isMyJurisdiction = true; // send erase messages to all servers } else if (_serverJurisdictions) { @@ -269,19 +269,19 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, unsi if (isMyJurisdiction) { EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID]; packetBuffer._nodeUUID = nodeUUID; - + // If we're switching type, then we send the last one and start over if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) || (packetBuffer._currentSize + length >= (size_t)_maxPacketSize)) { releaseQueuedPacket(packetBuffer); initializePacket(packetBuffer, type, node->getClockSkewUsec()); } - + // If the buffer is empty and not correctly initialized for our type... if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) { initializePacket(packetBuffer, type, node->getClockSkewUsec()); } - + // This is really the first time we know which server/node this particular edit message // is going to, so we couldn't adjust for clock skew till now. But here's our chance. // We call this virtual function that allows our specific type of EditPacketSender to @@ -289,7 +289,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, unsi if (node->getClockSkewUsec() != 0) { adjustEditPacketForClockSkew(type, editPacketBuffer, length, node->getClockSkewUsec()); } - + memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], editPacketBuffer, length); packetBuffer._currentSize += length; packetBuffer._satoshiCost += satoshiCost; @@ -341,7 +341,7 @@ void OctreeEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, Pa packetBuffer._currentSize += sizeof(quint64); // nudge past timestamp packetBuffer._currentType = type; - + // reset cost for packet to 0 packetBuffer._satoshiCost = 0; } @@ -360,20 +360,22 @@ bool OctreeEditPacketSender::process() { void OctreeEditPacketSender::processNackPacket(const QByteArray& packet) { // parse sending node from packet, retrieve packet history for that node QUuid sendingNodeUUID = uuidFromPacketHeader(packet); - + // if packet history doesn't exist for the sender node (somehow), bail if (!_sentPacketHistories.contains(sendingNodeUUID)) { return; } const SentPacketHistory& sentPacketHistory = _sentPacketHistories.value(sendingNodeUUID); + // TODO: these NAK packets no longer send the number of sequence numbers - just read out sequence numbers in blocks + int numBytesPacketHeader = numBytesForPacketHeader(packet); const unsigned char* dataAt = reinterpret_cast(packet.data()) + numBytesPacketHeader; // read number of sequence numbers uint16_t numSequenceNumbers = (*(uint16_t*)dataAt); dataAt += sizeof(uint16_t); - + // read sequence numbers and queue packets for resend for (int i = 0; i < numSequenceNumbers; i++) { unsigned short int sequenceNumber = (*(unsigned short int*)dataAt);