From df47f1dd0bbfbfa54c51f5fa913c91c9d5851f14 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 15:20:37 -0700 Subject: [PATCH] add a BasePacket class for headerless packets --- libraries/avatars/src/AvatarData.cpp | 3 +- libraries/networking/src/LimitedNodeList.cpp | 19 +- libraries/networking/src/LimitedNodeList.h | 4 +- libraries/networking/src/NetworkPacket.cpp | 42 ----- libraries/networking/src/NetworkPacket.h | 37 ---- libraries/networking/src/PacketReceiver.cpp | 14 +- libraries/networking/src/udt/BasePacket.cpp | 175 ++++++++++++++++++ libraries/networking/src/udt/BasePacket.h | 116 ++++++++++++ libraries/networking/src/udt/Packet.cpp | 129 ++----------- libraries/networking/src/udt/Packet.h | 72 +------ .../networking/src/udt/PacketHeaders.cpp | 4 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/networking/src/udt/Socket.cpp | 14 +- libraries/networking/src/udt/Socket.h | 7 +- libraries/octree/src/OctreePacketData.h | 13 +- libraries/octree/src/OctreeSceneStats.cpp | 2 +- 16 files changed, 358 insertions(+), 296 deletions(-) delete mode 100644 libraries/networking/src/NetworkPacket.cpp delete mode 100644 libraries/networking/src/NetworkPacket.h create mode 100644 libraries/networking/src/udt/BasePacket.cpp create mode 100644 libraries/networking/src/udt/BasePacket.h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 19f1c35a2b..cb54278119 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -144,8 +144,7 @@ QByteArray AvatarData::toByteArray() { _headData->_isFaceTrackerConnected = true; } - QByteArray avatarDataByteArray; - avatarDataByteArray.resize(MAX_PACKET_SIZE); + QByteArray avatarDataByteArray(udt::MAX_PACKET_SIZE, 0); unsigned char* destinationBuffer = reinterpret_cast(avatarDataByteArray.data()); unsigned char* startPosition = destinationBuffer; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index acac81f8ff..66165a95cc 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -105,9 +105,6 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _nodeSocket.setPacketFilterOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); _packetStatTimer.start(); - - // make sure we handle STUN response packets - _packetReceiver->registerListener(PacketType::StunResponse, this, "processSTUNResponse"); } void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) { @@ -239,7 +236,7 @@ bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ \\([\\sa-zA-Z]+\\) received from unknown node with UUID"); - qCDebug(networking) << "Packet of type" << headerType << "(" << qPrintable(nameForPacketType(headerType)) << ")" + qCDebug(networking) << "Packet of type" << headerType << "received from unknown node with UUID" << qPrintable(uuidStringWithoutCurlyBraces(sourceID)); } } @@ -611,7 +608,7 @@ void LimitedNodeList::sendSTUNRequest() { _nodeSocket.writeDatagram(stunRequestPacket, sizeof(stunRequestPacket), _stunSockAddr); } -bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { +void LimitedNodeList::processSTUNResponse(std::unique_ptr packet) { // check the cookie to make sure this is actually a STUN response // and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4; @@ -672,8 +669,6 @@ bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { flagTimeForConnectionStep(ConnectionStep::SetPublicSocketFromSTUN); } - - return true; } } else { // push forward attributeStartIndex by the length of this attribute @@ -688,8 +683,6 @@ bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { } } } - - return false; } void LimitedNodeList::startSTUNPublicSocketUpdate() { @@ -699,7 +692,7 @@ void LimitedNodeList::startSTUNPublicSocketUpdate() { // if we don't know the STUN IP yet we need to have ourselves be called once it is known if (_stunSockAddr.getAddress().isNull()) { connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::startSTUNPublicSocketUpdate); - connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::addSTUNSockAddrToUnfiltered); + connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::addSTUNHandlerToUnfiltered); // in case we just completely fail to lookup the stun socket - add a 10s timeout that will trigger the fail case const quint64 STUN_DNS_LOOKUP_TIMEOUT_MSECS = 10 * 1000; @@ -730,6 +723,12 @@ void LimitedNodeList::possiblyTimeoutSTUNAddressLookup() { } } +void LimitedNodeList::addSTUNHandlerToUnfiltered() { + // make ourselves the handler of STUN packets when they come in + using std::placeholders::_1; + _nodeSocket.addUnfilteredHandler(_stunSockAddr, std::bind(&LimitedNodeList::processSTUNResponse, this, _1)); +} + void LimitedNodeList::stopInitialSTUNUpdate(bool success) { _hasCompletedInitialSTUN = true; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 4047668350..e09617b88f 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -225,7 +225,6 @@ public slots: void startSTUNPublicSocketUpdate(); virtual void sendSTUNRequest(); - bool processSTUNResponse(QSharedPointer packet); void killNodeWithUUID(const QUuid& nodeUUID); @@ -256,6 +255,7 @@ protected: bool isPacketVerified(const udt::Packet& packet); bool packetVersionMatch(const udt::Packet& packet); bool packetSourceAndHashMatch(const udt::Packet& packet); + void processSTUNResponse(std::unique_ptr packet); void handleNodeKill(const SharedNodePointer& node); @@ -310,7 +310,7 @@ protected: private slots: void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp); void possiblyTimeoutSTUNAddressLookup(); - void addSTUNSockAddrToUnfiltered() { _nodeSocket.addUnfilteredSockAddr(_stunSockAddr); } // called once STUN socket known + void addSTUNHandlerToUnfiltered(); // called once STUN socket known }; #endif // hifi_LimitedNodeList_h diff --git a/libraries/networking/src/NetworkPacket.cpp b/libraries/networking/src/NetworkPacket.cpp deleted file mode 100644 index e99ef1ab8b..0000000000 --- a/libraries/networking/src/NetworkPacket.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// -// NetworkPacket.cpp -// libraries/networking/src -// -// Created by Brad Hefta-Gaub on 8/9/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include - -#include "SharedUtil.h" -#include "NetworkLogging.h" - -#include "NetworkPacket.h" - -void NetworkPacket::copyContents(const SharedNodePointer& node, const QByteArray& packet) { - if (packet.size() && packet.size() <= MAX_PACKET_SIZE) { - _node = node; - _byteArray = packet; - } else { - qCDebug(networking, ">>> NetworkPacket::copyContents() unexpected length = %d", packet.size()); - } -} - -NetworkPacket::NetworkPacket(const NetworkPacket& packet) { - copyContents(packet.getNode(), packet.getByteArray()); -} - -NetworkPacket::NetworkPacket(const SharedNodePointer& node, const QByteArray& packet) { - copyContents(node, packet); -}; - -// copy assignment -NetworkPacket& NetworkPacket::operator=(NetworkPacket const& other) { - copyContents(other.getNode(), other.getByteArray()); - return *this; -} diff --git a/libraries/networking/src/NetworkPacket.h b/libraries/networking/src/NetworkPacket.h deleted file mode 100644 index a7e5a6b3cd..0000000000 --- a/libraries/networking/src/NetworkPacket.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// NetworkPacket.h -// libraries/networking/src -// -// Created by Brad Hefta-Gaub on 8/9/13. -// Copyright 2013 High Fidelity, Inc. -// -// A really simple class that stores a network packet between being received and being processed -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_NetworkPacket_h -#define hifi_NetworkPacket_h - -#include "NodeList.h" - -/// Storage of not-yet processed inbound, or not yet sent outbound generic UDP network packet -class NetworkPacket { -public: - NetworkPacket() { } - NetworkPacket(const NetworkPacket& packet); // copy constructor - NetworkPacket& operator= (const NetworkPacket& other); // copy assignment - NetworkPacket(const SharedNodePointer& node, const QByteArray& byteArray); - - const SharedNodePointer& getNode() const { return _node; } - const QByteArray& getByteArray() const { return _byteArray; } - -private: - void copyContents(const SharedNodePointer& node, const QByteArray& byteArray); - - SharedNodePointer _node; - QByteArray _byteArray; -}; - -#endif // hifi_NetworkPacket_h diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 1389f271bf..c2c65eed8f 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -139,8 +139,7 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* if (methodIndex < 0) { qDebug() << "PacketReceiver::registerListener expected a slot with one of the following signatures:" << possibleSignatures.toList() << "- but such a slot was not found." - << "Could not complete listener registration for type" - << type << "-" << nameForPacketType(type); + << "Could not complete listener registration for type" << type; } Q_ASSERT(methodIndex >= 0); @@ -160,7 +159,6 @@ void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, if (_packetListenerMap.contains(type)) { qDebug() << "Warning: Registering a packet listener for packet type" << type - << "(" << qPrintable(nameForPacketType(type)) << ")" << "that will remove a previously registered listener"; } @@ -204,7 +202,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // setup a HifiSockAddr to read into HifiSockAddr senderSockAddr; - // setup an NLPacket from the data we just read + // setup an NLPacket from the packet we were passed auto nlPacket = NLPacket::fromBase(std::move(packet)); _inPacketCount++; @@ -286,8 +284,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } if (!success) { - qDebug().nospace() << "Error delivering packet " << packetType - << " (" << qPrintable(nameForPacketType(packetType)) << ") to listener " + qDebug().nospace() << "Error delivering packet " << packetType << " to listener " << listener.first << "::" << qPrintable(listener.second.methodSignature()); } @@ -296,8 +293,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } if (listenerIsDead) { - qDebug().nospace() << "Listener for packet" << nlPacket->getType() - << " (" << qPrintable(nameForPacketType(nlPacket->getType())) << ")" + qDebug().nospace() << "Listener for packet " << nlPacket->getType() << " has been destroyed. Removing from listener map."; it = _packetListenerMap.erase(it); @@ -308,7 +304,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } } else { - qWarning() << "No listener found for packet type " << nameForPacketType(nlPacket->getType()); + qWarning() << "No listener found for packet type" << nlPacket->getType(); // insert a dummy listener so we don't print this again _packetListenerMap.insert(nlPacket->getType(), { nullptr, QMetaMethod() }); diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp new file mode 100644 index 0000000000..d615f0cc1e --- /dev/null +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -0,0 +1,175 @@ +// +// BasePacket.cpp +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-23. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BasePacket.h" + +using namespace udt; + +const qint64 BasePacket::PACKET_WRITE_ERROR = -1; + +std::unique_ptr BasePacket::create(qint64 size) { + auto packet = std::unique_ptr(new BasePacket(size)); + + packet->open(QIODevice::ReadWrite); + + return packet; +} + +std::unique_ptr BasePacket::fromReceivedPacket(std::unique_ptr data, + qint64 size, + const HifiSockAddr& senderSockAddr) { + // Fail with invalid size + Q_ASSERT(size >= 0); + + // allocate memory + auto packet = std::unique_ptr(new BasePacket(std::move(data), size, senderSockAddr)); + + packet->open(QIODevice::ReadOnly); + + return packet; +} + +BasePacket::BasePacket(qint64 size) { + auto maxPayload = maxPayloadSize(); + + if (size == -1) { + // default size of -1, means biggest packet possible + size = maxPayload; + } + + // Sanity check + Q_ASSERT(size >= 0 || size < maxPayload); + + _packetSize = size; + _packet.reset(new char[_packetSize]); + _payloadCapacity = _packetSize; + _payloadSize = 0; + _payloadStart = _packet.get(); +} + +BasePacket::BasePacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : + _packetSize(size), + _packet(std::move(data)), + _payloadStart(_packet.get()), + _payloadCapacity(size), + _payloadSize(size), + _senderSockAddr(senderSockAddr) +{ + +} + +BasePacket::BasePacket(const BasePacket& other) { + *this = other; +} + +BasePacket& BasePacket::operator=(const BasePacket& other) { + _packetSize = other._packetSize; + _packet = std::unique_ptr(new char[_packetSize]); + memcpy(_packet.get(), other._packet.get(), _packetSize); + + _payloadStart = _packet.get() + (other._payloadStart - other._packet.get()); + _payloadCapacity = other._payloadCapacity; + + _payloadSize = other._payloadSize; + + if (other.isOpen() && !isOpen()) { + open(other.openMode()); + } + + seek(other.pos()); + + return *this; +} + +BasePacket::BasePacket(BasePacket&& other) { + *this = std::move(other); +} + +BasePacket& BasePacket::operator=(BasePacket&& other) { + _packetSize = other._packetSize; + _packet = std::move(other._packet); + + _payloadStart = other._payloadStart; + _payloadCapacity = other._payloadCapacity; + + _payloadSize = other._payloadSize; + + _senderSockAddr = std::move(other._senderSockAddr); + + if (other.isOpen() && !isOpen()) { + open(other.openMode()); + } + + seek(other.pos()); + + return *this; +} + +void BasePacket::setPayloadSize(qint64 payloadSize) { + if (isWritable()) { + Q_ASSERT(payloadSize <= _payloadCapacity); + _payloadSize = payloadSize; + } else { + qDebug() << "You can not call setPayloadSize for a non-writeable Packet."; + Q_ASSERT(false); + } +} + +QByteArray BasePacket::read(qint64 maxSize) { + qint64 sizeToRead = std::min(size() - pos(), maxSize); + QByteArray data { QByteArray::fromRawData(getPayload() + pos(), sizeToRead) }; + seek(pos() + sizeToRead); + return data; +} + +bool BasePacket::reset() { + if (isWritable()) { + _payloadSize = 0; + } + + return QIODevice::reset(); +} + +qint64 BasePacket::writeData(const char* data, qint64 maxSize) { + + // make sure we have the space required to write this block + if (maxSize <= bytesAvailableForWrite()) { + qint64 currentPos = pos(); + + Q_ASSERT(currentPos < _payloadCapacity); + + // good to go - write the data + memcpy(_payloadStart + currentPos, data, maxSize); + + // keep track of _payloadSize so we can just write the actual data when packet is about to be sent + _payloadSize = std::max(currentPos + maxSize, _payloadSize); + + // return the number of bytes written + return maxSize; + } else { + // not enough space left for this write - return an error + return PACKET_WRITE_ERROR; + } +} + +qint64 BasePacket::readData(char* dest, qint64 maxSize) { + // we're either reading what is left from the current position or what was asked to be read + qint64 numBytesToRead = std::min(bytesLeftToRead(), maxSize); + + if (numBytesToRead > 0) { + int currentPosition = pos(); + + // read out the data + memcpy(dest, _payloadStart + currentPosition, numBytesToRead); + } + + return numBytesToRead; +} diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h new file mode 100644 index 0000000000..cd31240d67 --- /dev/null +++ b/libraries/networking/src/udt/BasePacket.h @@ -0,0 +1,116 @@ +// +// BasePacket.h +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-23. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#ifndef hifi_BasePacket_h +#define hifi_BasePacket_h + +#include + +#include "../HifiSockAddr.h" + +namespace udt { + +static const int MAX_PACKET_SIZE = 1450; + +class BasePacket : public QIODevice { + Q_OBJECT +public: + static const qint64 PACKET_WRITE_ERROR; + + static std::unique_ptr create(qint64 size = -1); + static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + + static qint64 maxPayloadSize() { return MAX_PACKET_SIZE; } // The maximum payload size this packet can use to fit in MTU + static qint64 localHeaderSize() { return 0; } // Current level's header size + + virtual qint64 totalHeadersSize() const { return 0; } // Cumulated size of all the headers + + // 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(); } + + // Returns the size of the packet, including the header + qint64 getDataSize() const { return totalHeadersSize() + _payloadSize; } + + // Returns the size of the payload only + qint64 getPayloadSize() const { return _payloadSize; } + + // Allows a writer to change the size of the payload used when writing directly + void setPayloadSize(qint64 payloadSize); + + // Returns the number of bytes allocated for the payload + qint64 getPayloadCapacity() const { return _payloadCapacity; } + + qint64 bytesLeftToRead() const { return _payloadSize - pos(); } + qint64 bytesAvailableForWrite() const { return _payloadCapacity - pos(); } + + HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } + const HifiSockAddr& getSenderSockAddr() const { return _senderSockAddr; } + + // QIODevice virtual functions + // WARNING: Those methods all refer to the payload ONLY and NOT the entire packet + virtual bool isSequential() const { return false; } + virtual bool reset(); + virtual qint64 size() const { return _payloadCapacity; } + + using QIODevice::read; + QByteArray read(qint64 maxSize); + + template qint64 peekPrimitive(T* data); + template qint64 readPrimitive(T* data); + template qint64 writePrimitive(const T& data); + +protected: + BasePacket(qint64 size); + BasePacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + BasePacket(const BasePacket& other); + BasePacket& operator=(const BasePacket& other); + BasePacket(BasePacket&& other); + BasePacket& operator=(BasePacket&& other); + + // QIODevice virtual functions + virtual qint64 writeData(const char* data, qint64 maxSize); + virtual qint64 readData(char* data, qint64 maxSize); + + qint64 _packetSize = 0; // Total size of the allocated memory + std::unique_ptr _packet; // Allocated memory + + char* _payloadStart = nullptr; // Start of the payload + qint64 _payloadCapacity = 0; // Total capacity of the payload + + qint64 _payloadSize = 0; // How much of the payload is actually used + + HifiSockAddr _senderSockAddr; // sender address for packet (only used on receiving end) +}; + +template qint64 BasePacket::peekPrimitive(T* data) { + return QIODevice::peek(reinterpret_cast(data), sizeof(T)); +} + +template qint64 BasePacket::readPrimitive(T* data) { + return QIODevice::read(reinterpret_cast(data), sizeof(T)); +} + +template qint64 BasePacket::writePrimitive(const T& data) { + static_assert(!std::is_pointer::value, "T must not be a pointer"); + return QIODevice::write(reinterpret_cast(&data), sizeof(T)); +} + +} // namespace udt + + +#endif // hifi_BasePacket_h diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 439b185661..3746f877ba 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -13,8 +13,6 @@ using namespace udt; -const qint64 Packet::PACKET_WRITE_ERROR = -1; - std::unique_ptr Packet::create(qint64 size, bool isReliable, bool isPartOfMessage) { auto packet = std::unique_ptr(new Packet(size, isReliable, isPartOfMessage)); @@ -60,32 +58,19 @@ qint64 Packet::localHeaderSize() const { } Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : + BasePacket(size), _isReliable(isReliable), _isPartOfMessage(isPartOfMessage) { - auto maxPayload = maxPayloadSize(); - - if (size == -1) { - // default size of -1, means biggest packet possible - size = maxPayload; - } - - _packetSize = localHeaderSize() + size; - _packet.reset(new char[_packetSize]); _payloadCapacity = size; _payloadStart = _packet.get() + (_packetSize - _payloadCapacity); - // Sanity check - Q_ASSERT(size >= 0 || size < maxPayload); - // set the UDT header to default values writeSequenceNumber(0); } Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : - _packetSize(size), - _packet(std::move(data)), - _senderSockAddr(senderSockAddr) + BasePacket(std::move(data), size, senderSockAddr) { readIsReliable(); readIsPartOfMessage(); @@ -97,72 +82,41 @@ Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& send } Packet::Packet(const Packet& other) : - QIODevice() + BasePacket(other) { - *this = other; + _isReliable = other._isReliable; + _isPartOfMessage = other._isPartOfMessage; + _sequenceNumber = other._sequenceNumber; } Packet& Packet::operator=(const Packet& other) { - _packetSize = other._packetSize; - _packet = std::unique_ptr(new char[_packetSize]); - memcpy(_packet.get(), other._packet.get(), _packetSize); - - _payloadStart = _packet.get() + (other._payloadStart - other._packet.get()); - _payloadCapacity = other._payloadCapacity; - - _payloadSize = other._payloadSize; + BasePacket::operator=(other); - if (other.isOpen() && !isOpen()) { - open(other.openMode()); - } - - seek(other.pos()); + _isReliable = other._isReliable; + _isPartOfMessage = other._isPartOfMessage; + _sequenceNumber = other._sequenceNumber; return *this; } -Packet::Packet(Packet&& other) { - *this = std::move(other); +Packet::Packet(Packet&& other) : + BasePacket(other) +{ + _isReliable = other._isReliable; + _isPartOfMessage = other._isPartOfMessage; + _sequenceNumber = other._sequenceNumber; } Packet& Packet::operator=(Packet&& other) { - _packetSize = other._packetSize; - _packet = std::move(other._packet); - - _payloadStart = other._payloadStart; - _payloadCapacity = other._payloadCapacity; - - _payloadSize = other._payloadSize; + BasePacket::operator=(std::move(other)); - _senderSockAddr = std::move(other._senderSockAddr); - - if (other.isOpen() && !isOpen()) { - open(other.openMode()); - } - - seek(other.pos()); + _isReliable = other._isReliable; + _isPartOfMessage = other._isPartOfMessage; + _sequenceNumber = other._sequenceNumber; return *this; } -void Packet::setPayloadSize(qint64 payloadSize) { - if (isWritable()) { - Q_ASSERT(payloadSize <= _payloadCapacity); - _payloadSize = payloadSize; - } else { - qDebug() << "You can not call setPayloadSize for a non-writeable Packet."; - Q_ASSERT(false); - } -} - -bool Packet::reset() { - if (isWritable()) { - _payloadSize = 0; - } - - return QIODevice::reset(); -} - static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); @@ -196,46 +150,3 @@ void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) { // write new value by ORing (old value & BIT_FIELD_MASK) with new seqNum *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | sequenceNumber; } - -QByteArray Packet::read(qint64 maxSize) { - qint64 sizeToRead = std::min(size() - pos(), maxSize); - QByteArray data { QByteArray::fromRawData(getPayload() + pos(), sizeToRead) }; - seek(pos() + sizeToRead); - return data; -} - -qint64 Packet::writeData(const char* data, qint64 maxSize) { - - // make sure we have the space required to write this block - if (maxSize <= bytesAvailableForWrite()) { - qint64 currentPos = pos(); - - Q_ASSERT(currentPos < _payloadCapacity); - - // good to go - write the data - memcpy(_payloadStart + currentPos, data, maxSize); - - // keep track of _payloadSize so we can just write the actual data when packet is about to be sent - _payloadSize = std::max(currentPos + maxSize, _payloadSize); - - // return the number of bytes written - return maxSize; - } else { - // not enough space left for this write - return an error - return PACKET_WRITE_ERROR; - } -} - -qint64 Packet::readData(char* dest, qint64 maxSize) { - // we're either reading what is left from the current position or what was asked to be read - qint64 numBytesToRead = std::min(bytesLeftToRead(), maxSize); - - if (numBytesToRead > 0) { - int currentPosition = pos(); - - // read out the data - memcpy(dest, _payloadStart + currentPosition, numBytesToRead); - } - - return numBytesToRead; -} diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 1bd9ee9619..e33a075a1f 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -16,12 +16,12 @@ #include -#include "../HifiSockAddr.h" +#include "BasePacket.h" #include "PacketHeaders.h" namespace udt { -class Packet : public QIODevice { +class Packet : public BasePacket { Q_OBJECT public: // NOTE: The SequenceNumber is only actually 29 bits to leave room for a bit field @@ -34,8 +34,6 @@ public: static const uint32_t DEFAULT_SEQUENCE_NUMBER = 0; - static const qint64 PACKET_WRITE_ERROR; - static std::unique_ptr create(qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); @@ -52,47 +50,8 @@ public: virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers - // 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(); } - - // Returns the size of the packet, including the header - qint64 getDataSize() const { return totalHeadersSize() + _payloadSize; } - - // Returns the size of the payload only - qint64 getPayloadSize() const { return _payloadSize; } - - // Allows a writer to change the size of the payload used when writing directly - void setPayloadSize(qint64 payloadSize); - - // Returns the number of bytes allocated for the payload - qint64 getPayloadCapacity() const { return _payloadCapacity; } - - qint64 bytesLeftToRead() const { return _payloadSize - pos(); } - qint64 bytesAvailableForWrite() const { return _payloadCapacity - pos(); } - - HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } - const HifiSockAddr& getSenderSockAddr() const { return _senderSockAddr; } - void writeSequenceNumber(SequenceNumber sequenceNumber); - // QIODevice virtual functions - // WARNING: Those methods all refer to the payload ONLY and NOT the entire packet - virtual bool isSequential() const { return false; } - virtual bool reset(); - virtual qint64 size() const { return _payloadCapacity; } - - using QIODevice::read; - QByteArray read(qint64 maxSize); - - template qint64 peekPrimitive(T* data); - template qint64 readPrimitive(T* data); - template qint64 writePrimitive(const T& data); - protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); @@ -101,42 +60,15 @@ protected: 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 readers - these read data to member variables after pulling packet off wire void readIsPartOfMessage(); void readIsReliable(); void readSequenceNumber(); - qint64 _packetSize = 0; // Total size of the allocated memory - std::unique_ptr _packet; // Allocated memory - - char* _payloadStart = nullptr; // Start of the payload - qint64 _payloadCapacity = 0; // Total capacity of the payload - - qint64 _payloadSize = 0; // How much of the payload is actually used - bool _isReliable { false }; bool _isPartOfMessage { false }; SequenceNumber _sequenceNumber { 0 }; - - HifiSockAddr _senderSockAddr; // sender address for packet (only used on receiving end) }; - -template qint64 Packet::peekPrimitive(T* data) { - return QIODevice::peek(reinterpret_cast(data), sizeof(T)); -} - -template qint64 Packet::readPrimitive(T* data) { - return QIODevice::read(reinterpret_cast(data), sizeof(T)); -} - -template qint64 Packet::writePrimitive(const T& data) { - static_assert(!std::is_pointer::value, "T must not be a pointer"); - return QIODevice::write(reinterpret_cast(&data), sizeof(T)); -} } // namespace udt diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index e3a8761e6d..f3d3042b34 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -65,9 +65,9 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_NEW_PROTOCOL_LAYER; + return VERSION_ENTITIES_PROTOCOL_HEADER_SWAP; default: - return 11; + return 12; } } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 2d3f7f25fe..0cb20b2247 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -76,8 +76,6 @@ enum class PacketType : uint8_t { }; const int NUM_BYTES_MD5_HASH = 16; - -const int MAX_PACKET_SIZE = 1450; const int MAX_PACKET_HEADER_BYTES = 4 + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; typedef char PacketVersion; @@ -135,5 +133,6 @@ const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 31; const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32; const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE = 33; const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35; +const PacketVersion VERSION_ENTITIES_PROTOCOL_HEADER_SWAP = 36; #endif // hifi_PacketHeaders_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8b912637a8..25afb5424d 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -88,11 +88,23 @@ void Socket::readPendingDatagrams() { _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); + auto it = _unfilteredHandlers.find(senderSockAddr); + + if (it != _unfilteredHandlers.end()) { + // we have a registered unfiltered handler for this HifiSockAddr - call that and return + if (it->second) { + auto basePacket = BasePacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); + it->second(std::move(basePacket)); + } + + return; + } + // setup a Packet from the data we just read auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); // call our verification operator to see if this packet is verified - if (_unfilteredSockAddrs.contains(senderSockAddr) || !_packetFilterOperator || _packetFilterOperator(*packet)) { + if (!_packetFilterOperator || _packetFilterOperator(*packet)) { if (_packetHandler) { // call the verified packet callback to let it handle this packet return _packetHandler(std::move(packet)); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index f4b4ea4ee0..68985133ac 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -26,6 +26,8 @@ namespace udt { using PacketFilterOperator = std::function; + +using BasePacketHandler = std::function)>; using PacketHandler = std::function)>; class Socket : public QObject { @@ -49,7 +51,8 @@ public: void setBufferSizes(int numBytes); - void addUnfilteredSockAddr(const HifiSockAddr& senderSockAddr) { _unfilteredSockAddrs.insert(senderSockAddr); } + void addUnfilteredHandler(const HifiSockAddr& senderSockAddr, BasePacketHandler handler) + { _unfilteredHandlers[senderSockAddr] = handler; } private slots: void readPendingDatagrams(); @@ -59,7 +62,7 @@ private: PacketFilterOperator _packetFilterOperator; PacketHandler _packetHandler; - QSet _unfilteredSockAddrs; + std::unordered_map _unfilteredHandlers; std::unordered_map _packetSequenceNumbers; }; diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 2c9d587254..a242f9117f 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -26,11 +26,11 @@ #include #include -#include // for MAX_PACKET_SIZE -#include // for MAX_PACKET_HEADER_BYTES +#include #include #include -#include +#include +#include #include "OctreeConstants.h" #include "OctreeElement.h" @@ -40,14 +40,13 @@ typedef uint16_t OCTREE_PACKET_SEQUENCE; const uint16_t MAX_OCTREE_PACKET_SEQUENCE = 65535; typedef quint64 OCTREE_PACKET_SENT_TIME; typedef uint16_t OCTREE_PACKET_INTERNAL_SECTION_SIZE; -const int MAX_OCTREE_PACKET_SIZE = MAX_PACKET_SIZE; +const int MAX_OCTREE_PACKET_SIZE = udt::MAX_PACKET_SIZE; -// this is overly conservative - sizeof(PacketType) is 8 bytes but a packed PacketType could be as small as one byte const unsigned int OCTREE_PACKET_EXTRA_HEADERS_SIZE = sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME); -const unsigned int MAX_OCTREE_PACKET_DATA_SIZE = MAX_PACKET_SIZE - (MAX_PACKET_HEADER_BYTES + OCTREE_PACKET_EXTRA_HEADERS_SIZE); - +const unsigned int MAX_OCTREE_PACKET_DATA_SIZE = + udt::MAX_PACKET_SIZE - (MAX_PACKET_HEADER_BYTES + OCTREE_PACKET_EXTRA_HEADERS_SIZE); const unsigned int MAX_OCTREE_UNCOMRESSED_PACKET_SIZE = MAX_OCTREE_PACKET_DATA_SIZE; const unsigned int MINIMUM_ATTEMPT_MORE_PACKING = sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) + 40; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 55213fdb7a..d83ee9a89e 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -791,6 +791,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(NLPacket& packet, bool wasStats _incomingPacket++; _incomingBytes += packet.getDataSize(); if (!wasStatsPacket) { - _incomingWastedBytes += (MAX_PACKET_SIZE - packet.getDataSize()); + _incomingWastedBytes += (udt::MAX_PACKET_SIZE - packet.getDataSize()); } }