add a BasePacket class for headerless packets

This commit is contained in:
Stephen Birarda 2015-07-23 15:20:37 -07:00
parent e5955e39b7
commit df47f1dd0b
16 changed files with 358 additions and 296 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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() });

View 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;
}

View 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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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));

View file

@ -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;
};

View file

@ -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;

View file

@ -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());
}
}