mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 21:54:10 +02:00
add a BasePacket class for headerless packets
This commit is contained in:
parent
e5955e39b7
commit
df47f1dd0b
16 changed files with 358 additions and 296 deletions
|
@ -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<unsigned char*>(avatarDataByteArray.data());
|
||||
unsigned char* startPosition = destinationBuffer;
|
||||
|
|
|
@ -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<NLPacket> packet) {
|
||||
void LimitedNodeList::processSTUNResponse(std::unique_ptr<udt::BasePacket> 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<NLPacket> packet) {
|
|||
|
||||
flagTimeForConnectionStep(ConnectionStep::SetPublicSocketFromSTUN);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// push forward attributeStartIndex by the length of this attribute
|
||||
|
@ -688,8 +683,6 @@ bool LimitedNodeList::processSTUNResponse(QSharedPointer<NLPacket> 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;
|
||||
|
||||
|
|
|
@ -225,7 +225,6 @@ public slots:
|
|||
|
||||
void startSTUNPublicSocketUpdate();
|
||||
virtual void sendSTUNRequest();
|
||||
bool processSTUNResponse(QSharedPointer<NLPacket> 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<udt::BasePacket> 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
|
||||
|
|
|
@ -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 <cassert>
|
||||
#include <cstring>
|
||||
#include <QtDebug>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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
|
|
@ -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<udt::Packet> 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<udt::Packet> 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<udt::Packet> 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<udt::Packet> 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() });
|
||||
|
|
175
libraries/networking/src/udt/BasePacket.cpp
Normal file
175
libraries/networking/src/udt/BasePacket.cpp
Normal file
|
@ -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> BasePacket::create(qint64 size) {
|
||||
auto packet = std::unique_ptr<BasePacket>(new BasePacket(size));
|
||||
|
||||
packet->open(QIODevice::ReadWrite);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
std::unique_ptr<BasePacket> BasePacket::fromReceivedPacket(std::unique_ptr<char> data,
|
||||
qint64 size,
|
||||
const HifiSockAddr& senderSockAddr) {
|
||||
// Fail with invalid size
|
||||
Q_ASSERT(size >= 0);
|
||||
|
||||
// allocate memory
|
||||
auto packet = std::unique_ptr<BasePacket>(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<char> 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<char>(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;
|
||||
}
|
116
libraries/networking/src/udt/BasePacket.h
Normal file
116
libraries/networking/src/udt/BasePacket.h
Normal file
|
@ -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 <QtCore/QIODevice>
|
||||
|
||||
#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<BasePacket> create(qint64 size = -1);
|
||||
static std::unique_ptr<BasePacket> fromReceivedPacket(std::unique_ptr<char> 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<typename T> qint64 peekPrimitive(T* data);
|
||||
template<typename T> qint64 readPrimitive(T* data);
|
||||
template<typename T> qint64 writePrimitive(const T& data);
|
||||
|
||||
protected:
|
||||
BasePacket(qint64 size);
|
||||
BasePacket(std::unique_ptr<char> 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<char> _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<typename T> qint64 BasePacket::peekPrimitive(T* data) {
|
||||
return QIODevice::peek(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> qint64 BasePacket::readPrimitive(T* data) {
|
||||
return QIODevice::read(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> qint64 BasePacket::writePrimitive(const T& data) {
|
||||
static_assert(!std::is_pointer<T>::value, "T must not be a pointer");
|
||||
return QIODevice::write(reinterpret_cast<const char*>(&data), sizeof(T));
|
||||
}
|
||||
|
||||
} // namespace udt
|
||||
|
||||
|
||||
#endif // hifi_BasePacket_h
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
using namespace udt;
|
||||
|
||||
const qint64 Packet::PACKET_WRITE_ERROR = -1;
|
||||
|
||||
std::unique_ptr<Packet> Packet::create(qint64 size, bool isReliable, bool isPartOfMessage) {
|
||||
auto packet = std::unique_ptr<Packet>(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<char> 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<char> 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<char>(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;
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
|
||||
#include <QtCore/QIODevice>
|
||||
|
||||
#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<Packet> create(qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false);
|
||||
static std::unique_ptr<Packet> fromReceivedPacket(std::unique_ptr<char> 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<typename T> qint64 peekPrimitive(T* data);
|
||||
template<typename T> qint64 readPrimitive(T* data);
|
||||
template<typename T> qint64 writePrimitive(const T& data);
|
||||
|
||||
protected:
|
||||
Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false);
|
||||
Packet(std::unique_ptr<char> 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<char> _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<typename T> qint64 Packet::peekPrimitive(T* data) {
|
||||
return QIODevice::peek(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> qint64 Packet::readPrimitive(T* data) {
|
||||
return QIODevice::read(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> qint64 Packet::writePrimitive(const T& data) {
|
||||
static_assert(!std::is_pointer<T>::value, "T must not be a pointer");
|
||||
return QIODevice::write(reinterpret_cast<const char*>(&data), sizeof(T));
|
||||
}
|
||||
|
||||
} // namespace udt
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
namespace udt {
|
||||
|
||||
using PacketFilterOperator = std::function<bool(const Packet&)>;
|
||||
|
||||
using BasePacketHandler = std::function<void(std::unique_ptr<BasePacket>)>;
|
||||
using PacketHandler = std::function<void(std::unique_ptr<Packet>)>;
|
||||
|
||||
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<HifiSockAddr> _unfilteredSockAddrs;
|
||||
std::unordered_map<HifiSockAddr, BasePacketHandler> _unfilteredHandlers;
|
||||
|
||||
std::unordered_map<HifiSockAddr, Packet::SequenceNumber> _packetSequenceNumbers;
|
||||
};
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
#include <QString>
|
||||
#include <QUuid>
|
||||
|
||||
#include <LimitedNodeList.h> // for MAX_PACKET_SIZE
|
||||
#include <udt/PacketHeaders.h> // for MAX_PACKET_HEADER_BYTES
|
||||
#include <BackgroundMode.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <ShapeInfo.h>
|
||||
#include <BackgroundMode.h>
|
||||
#include <udt/BasePacket.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue