mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:24:00 +02:00
allow optional sequence numbers in packets
This commit is contained in:
parent
fa9dfbe073
commit
c76ae56d64
4 changed files with 135 additions and 55 deletions
|
@ -231,20 +231,13 @@ qint64 LimitedNodeList::readDatagram(QByteArray& incomingPacket, QHostAddress* a
|
|||
}
|
||||
|
||||
qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr,
|
||||
const QUuid& connectionSecret) {
|
||||
QByteArray datagramCopy = datagram;
|
||||
|
||||
if (!connectionSecret.isNull()) {
|
||||
// setup the MD5 hash for source verification in the header
|
||||
replaceHashInPacketGivenConnectionUUID(datagramCopy, connectionSecret);
|
||||
}
|
||||
|
||||
const QUuid& connectionSecret) {
|
||||
// XXX can BandwidthRecorder be used for this?
|
||||
// stat collection for packets
|
||||
++_numCollectedPackets;
|
||||
_numCollectedBytes += datagram.size();
|
||||
|
||||
qint64 bytesWritten = _nodeSocket.writeDatagram(datagramCopy,
|
||||
qint64 bytesWritten = _nodeSocket.writeDatagram(datagram,
|
||||
destinationSockAddr.getAddress(), destinationSockAddr.getPort());
|
||||
|
||||
if (bytesWritten < 0) {
|
||||
|
@ -270,6 +263,19 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
|
|||
}
|
||||
}
|
||||
|
||||
QByteArray datagramCopy = datagram;
|
||||
PacketType packetType = packetTypeForPacket(datagramCopy);
|
||||
|
||||
// perform replacement of hash and optionally also sequence number in the header
|
||||
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
||||
PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType);
|
||||
replaceHashAndSequenceNumberInPacketGivenType(datagramCopy, packetType,
|
||||
destinationNode->getConnectionSecret(),
|
||||
sequenceNumber);
|
||||
} else {
|
||||
replaceHashInPacketGivenType(datagramCopy, packetType, destinationNode->getConnectionSecret());
|
||||
}
|
||||
|
||||
emit dataSent(destinationNode->getType(), datagram.size());
|
||||
auto bytesWritten = writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret());
|
||||
// Keep track of per-destination-node bandwidth
|
||||
|
@ -318,6 +324,15 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const char* data, qint64 size, c
|
|||
return writeUnverifiedDatagram(QByteArray(data, size), destinationNode, overridenSockAddr);
|
||||
}
|
||||
|
||||
PacketSequenceNumber LimitedNodeList::getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType) {
|
||||
// Thanks to std::map and std::unordered_map this line either default constructs the
|
||||
// PacketTypeSequenceMap and the PacketSequenceNumber or returns the existing value.
|
||||
// We use the postfix increment so that the stored value is incremented and the next
|
||||
// return gives the correct value.
|
||||
|
||||
return _packetSequenceNumbers[nodeUUID][packetType]++;
|
||||
}
|
||||
|
||||
void LimitedNodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
|
||||
// the node decided not to do anything with this packet
|
||||
// if it comes from a known source we should keep that node alive
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h> // not on windows, not needed for mac or windows
|
||||
|
@ -34,6 +36,7 @@
|
|||
|
||||
#include "DomainHandler.h"
|
||||
#include "Node.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "UUIDHasher.h"
|
||||
|
||||
const int MAX_PACKET_SIZE = 1450;
|
||||
|
@ -76,6 +79,8 @@ namespace PingType {
|
|||
const PingType_t Symmetric = 3;
|
||||
}
|
||||
|
||||
typedef std::map<PacketType, PacketSequenceNumber> PacketTypeSequenceMap;
|
||||
|
||||
class LimitedNodeList : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
@ -224,8 +229,11 @@ protected:
|
|||
LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
|
||||
qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr,
|
||||
qint64 writeDatagram(const QByteArray& datagram,
|
||||
const HifiSockAddr& destinationSockAddr,
|
||||
const QUuid& connectionSecret);
|
||||
|
||||
PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType);
|
||||
|
||||
void changeSocketBufferSizes(int numBytes);
|
||||
|
||||
|
@ -247,6 +255,8 @@ protected:
|
|||
QElapsedTimer _packetStatTimer;
|
||||
bool _thisNodeCanAdjustLocks;
|
||||
bool _thisNodeCanRez;
|
||||
|
||||
std::unordered_map<QUuid, PacketTypeSequenceMap, UUIDHasher> _packetSequenceNumbers;
|
||||
|
||||
template<typename IteratorLambda>
|
||||
void eachNodeHashIterator(IteratorLambda functor) {
|
||||
|
|
|
@ -45,8 +45,8 @@ int packArithmeticallyCodedValue(int value, char* destination) {
|
|||
}
|
||||
}
|
||||
|
||||
PacketVersion versionForPacketType(PacketType type) {
|
||||
switch (type) {
|
||||
PacketVersion versionForPacketType(PacketType packetType) {
|
||||
switch (packetType) {
|
||||
case PacketTypeMicrophoneAudioNoEcho:
|
||||
case PacketTypeMicrophoneAudioWithEcho:
|
||||
return 2;
|
||||
|
@ -86,8 +86,8 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
|
||||
#define PACKET_TYPE_NAME_LOOKUP(x) case x: return QString(#x);
|
||||
|
||||
QString nameForPacketType(PacketType type) {
|
||||
switch (type) {
|
||||
QString nameForPacketType(PacketType packetType) {
|
||||
switch (packetType) {
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnknown);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeStunResponse);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainList);
|
||||
|
@ -132,30 +132,30 @@ QString nameForPacketType(PacketType type) {
|
|||
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
|
||||
default:
|
||||
return QString("Type: ") + QString::number((int)type);
|
||||
return QString("Type: ") + QString::number((int)packetType);
|
||||
}
|
||||
return QString("unexpected");
|
||||
}
|
||||
|
||||
|
||||
|
||||
QByteArray byteArrayWithPopulatedHeader(PacketType type, const QUuid& connectionUUID) {
|
||||
QByteArray byteArrayWithPopulatedHeader(PacketType packetType, const QUuid& connectionUUID) {
|
||||
QByteArray freshByteArray(MAX_PACKET_HEADER_BYTES, 0);
|
||||
freshByteArray.resize(populatePacketHeader(freshByteArray, type, connectionUUID));
|
||||
freshByteArray.resize(populatePacketHeader(freshByteArray, packetType, connectionUUID));
|
||||
return freshByteArray;
|
||||
}
|
||||
|
||||
int populatePacketHeader(QByteArray& packet, PacketType type, const QUuid& connectionUUID) {
|
||||
if (packet.size() < numBytesForPacketHeaderGivenPacketType(type)) {
|
||||
packet.resize(numBytesForPacketHeaderGivenPacketType(type));
|
||||
int populatePacketHeader(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID) {
|
||||
if (packet.size() < numBytesForPacketHeaderGivenPacketType(packetType)) {
|
||||
packet.resize(numBytesForPacketHeaderGivenPacketType(packetType));
|
||||
}
|
||||
|
||||
return populatePacketHeader(packet.data(), type, connectionUUID);
|
||||
return populatePacketHeader(packet.data(), packetType, connectionUUID);
|
||||
}
|
||||
|
||||
int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionUUID) {
|
||||
int numTypeBytes = packArithmeticallyCodedValue(type, packet);
|
||||
packet[numTypeBytes] = versionForPacketType(type);
|
||||
int populatePacketHeader(char* packet, PacketType packetType, const QUuid& connectionUUID) {
|
||||
int numTypeBytes = packArithmeticallyCodedValue(packetType, packet);
|
||||
packet[numTypeBytes] = versionForPacketType(packetType);
|
||||
|
||||
char* position = packet + numTypeBytes + sizeof(PacketVersion);
|
||||
|
||||
|
@ -165,38 +165,46 @@ int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionU
|
|||
memcpy(position, rfcUUID.constData(), NUM_BYTES_RFC4122_UUID);
|
||||
position += NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
if (!NON_VERIFIED_PACKETS.contains(type)) {
|
||||
if (!NON_VERIFIED_PACKETS.contains(packetType)) {
|
||||
// pack 16 bytes of zeros where the md5 hash will be placed once data is packed
|
||||
memset(position, 0, NUM_BYTES_MD5_HASH);
|
||||
position += NUM_BYTES_MD5_HASH;
|
||||
}
|
||||
|
||||
|
||||
if (!SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
||||
// Pack zeros for the number of bytes that the sequence number requires.
|
||||
// The LimitedNodeList will handle packing in the sequence number when sending out the packet.
|
||||
memset(position, 0, sizeof(PacketSequenceNumber));
|
||||
position += sizeof(PacketSequenceNumber);
|
||||
}
|
||||
|
||||
// return the number of bytes written for pointer pushing
|
||||
return position - packet;
|
||||
}
|
||||
|
||||
int numBytesForPacketHeader(const QByteArray& packet) {
|
||||
// returns the number of bytes used for the type, version, and UUID
|
||||
return numBytesArithmeticCodingFromBuffer(packet.data())
|
||||
+ numHashBytesInPacketHeaderGivenPacketType(packetTypeForPacket(packet))
|
||||
+ NUM_STATIC_HEADER_BYTES;
|
||||
PacketType packetType = packetTypeForPacket(packet);
|
||||
return numBytesForPacketHeaderGivenPacketType(packetType);
|
||||
}
|
||||
|
||||
int numBytesForPacketHeader(const char* packet) {
|
||||
// returns the number of bytes used for the type, version, and UUID
|
||||
return numBytesArithmeticCodingFromBuffer(packet)
|
||||
+ numHashBytesInPacketHeaderGivenPacketType(packetTypeForPacket(packet))
|
||||
PacketType packetType = packetTypeForPacket(packet);
|
||||
return numBytesForPacketHeaderGivenPacketType(packetType);
|
||||
}
|
||||
|
||||
int numBytesForPacketHeaderGivenPacketType(PacketType packetType) {
|
||||
return (int) ceilf((float) packetType / 255)
|
||||
+ numHashBytesForType(packetType)
|
||||
+ numSequenceNumberBytesForType(packetType)
|
||||
+ NUM_STATIC_HEADER_BYTES;
|
||||
}
|
||||
|
||||
int numBytesForPacketHeaderGivenPacketType(PacketType type) {
|
||||
return (int) ceilf((float)type / 255)
|
||||
+ numHashBytesInPacketHeaderGivenPacketType(type)
|
||||
+ NUM_STATIC_HEADER_BYTES;
|
||||
int numHashBytesForType(PacketType packetType) {
|
||||
return (NON_VERIFIED_PACKETS.contains(packetType) ? 0 : NUM_BYTES_MD5_HASH);
|
||||
}
|
||||
|
||||
int numHashBytesInPacketHeaderGivenPacketType(PacketType type) {
|
||||
return (NON_VERIFIED_PACKETS.contains(type) ? 0 : NUM_BYTES_MD5_HASH);
|
||||
int numSequenceNumberBytesForType(PacketType packetType) {
|
||||
return (SEQUENCE_NUMBERED_PACKETS.contains(packetType) ? sizeof(PacketSequenceNumber) : 0);
|
||||
}
|
||||
|
||||
QUuid uuidFromPacketHeader(const QByteArray& packet) {
|
||||
|
@ -204,8 +212,18 @@ QUuid uuidFromPacketHeader(const QByteArray& packet) {
|
|||
NUM_BYTES_RFC4122_UUID));
|
||||
}
|
||||
|
||||
int hashOffsetForPacketType(PacketType packetType) {
|
||||
return numBytesForPacketHeaderGivenPacketType(packetType)
|
||||
- (SEQUENCE_NUMBERED_PACKETS.contains(packetType) ? sizeof(PacketSequenceNumber) : 0)
|
||||
- NUM_BYTES_RFC4122_UUID;
|
||||
}
|
||||
|
||||
int sequenceNumberOffsetForPacketType(PacketType packetType) {
|
||||
return numBytesForPacketHeaderGivenPacketType(packetType) - sizeof(PacketSequenceNumber);
|
||||
}
|
||||
|
||||
QByteArray hashFromPacketHeader(const QByteArray& packet) {
|
||||
return packet.mid(numBytesForPacketHeader(packet) - NUM_BYTES_MD5_HASH, NUM_BYTES_MD5_HASH);
|
||||
return packet.mid(hashOffsetForPacketType(packetTypeForPacket(packet)), NUM_BYTES_MD5_HASH);
|
||||
}
|
||||
|
||||
QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID) {
|
||||
|
@ -213,9 +231,25 @@ QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid&
|
|||
QCryptographicHash::Md5);
|
||||
}
|
||||
|
||||
void replaceHashInPacketGivenConnectionUUID(QByteArray& packet, const QUuid& connectionUUID) {
|
||||
packet.replace(numBytesForPacketHeader(packet) - NUM_BYTES_MD5_HASH, NUM_BYTES_MD5_HASH,
|
||||
hashForPacketAndConnectionUUID(packet, connectionUUID));
|
||||
void replaceHashInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID) {
|
||||
packet.replace(hashOffsetForPacketType(packetType), NUM_BYTES_MD5_HASH,
|
||||
hashForPacketAndConnectionUUID(packet, connectionUUID));
|
||||
}
|
||||
|
||||
void replaceSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, PacketSequenceNumber sequenceNumber) {
|
||||
packet.replace(sequenceNumberOffsetForPacketType(packetType),
|
||||
sizeof(PacketTypeSequenceMap), reinterpret_cast<char*>(&sequenceNumber));
|
||||
}
|
||||
|
||||
void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType,
|
||||
const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber) {
|
||||
replaceHashInPacketGivenType(packet, packetType, connectionUUID);
|
||||
replaceSequenceNumberInPacketGivenType(packet, packetType, sequenceNumber);
|
||||
}
|
||||
|
||||
|
||||
void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber) {
|
||||
replaceHashAndSequenceNumberInPacketGivenType(packet, packetTypeForPacket(packet), connectionUUID, sequenceNumber);
|
||||
}
|
||||
|
||||
PacketType packetTypeForPacket(const QByteArray& packet) {
|
||||
|
|
|
@ -12,14 +12,16 @@
|
|||
#ifndef hifi_PacketHeaders_h
|
||||
#define hifi_PacketHeaders_h
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <QtCore/QCryptographicHash>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include "UUID.h"
|
||||
|
||||
// NOTE: if adding a new packet type, you can replace one marked usable or add at the end
|
||||
// NOTE: if you want the name of the packet type to be available for debugging or logging, update nameForPacketType() as well
|
||||
// NOTE: if adding a new packet packetType, you can replace one marked usable or add at the end
|
||||
// NOTE: if you want the name of the packet packetType to be available for debugging or logging, update nameForPacketType() as well
|
||||
enum PacketType {
|
||||
PacketTypeUnknown, // 0
|
||||
PacketTypeStunResponse,
|
||||
|
@ -78,6 +80,7 @@ enum PacketType {
|
|||
};
|
||||
|
||||
typedef char PacketVersion;
|
||||
typedef uint16_t PacketSequenceNumber;
|
||||
|
||||
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
||||
<< PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest
|
||||
|
@ -88,33 +91,51 @@ const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
|||
<< PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse
|
||||
<< PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply << PacketTypeStopNode;
|
||||
|
||||
const QSet<PacketType> SEQUENCE_NUMBERED_PACKETS = QSet<PacketType>()
|
||||
<< PacketTypeAvatarData;
|
||||
|
||||
const int NUM_BYTES_MD5_HASH = 16;
|
||||
const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
|
||||
const int MAX_PACKET_HEADER_BYTES = sizeof(PacketType) + NUM_BYTES_MD5_HASH + NUM_STATIC_HEADER_BYTES;
|
||||
|
||||
PacketVersion versionForPacketType(PacketType type);
|
||||
QString nameForPacketType(PacketType type);
|
||||
PacketType packetTypeForPacket(const QByteArray& packet);
|
||||
PacketType packetTypeForPacket(const char* packet);
|
||||
|
||||
PacketVersion versionForPacketType(PacketType packetType);
|
||||
QString nameForPacketType(PacketType packetType);
|
||||
|
||||
const QUuid nullUUID = QUuid();
|
||||
|
||||
QByteArray byteArrayWithPopulatedHeader(PacketType type, const QUuid& connectionUUID = nullUUID);
|
||||
int populatePacketHeader(QByteArray& packet, PacketType type, const QUuid& connectionUUID = nullUUID);
|
||||
int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionUUID = nullUUID);
|
||||
QByteArray byteArrayWithPopulatedHeader(PacketType packetType, const QUuid& connectionUUID = nullUUID);
|
||||
int populatePacketHeader(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID = nullUUID);
|
||||
int populatePacketHeader(char* packet, PacketType packetType, const QUuid& connectionUUID = nullUUID);
|
||||
|
||||
int numHashBytesInPacketHeaderGivenPacketType(PacketType type);
|
||||
int numHashBytesForType(PacketType packetType);
|
||||
int numSequenceNumberBytesForType(PacketType packetType);
|
||||
|
||||
int numBytesForPacketHeader(const QByteArray& packet);
|
||||
int numBytesForPacketHeader(const char* packet);
|
||||
int numBytesForPacketHeaderGivenPacketType(PacketType type);
|
||||
int numBytesForPacketHeaderGivenPacketType(PacketType packetType);
|
||||
|
||||
QUuid uuidFromPacketHeader(const QByteArray& packet);
|
||||
|
||||
int hashOffsetForPacketType(PacketType packetType);
|
||||
int sequenceNumberOffsetForPacketType(PacketType packetType);
|
||||
|
||||
QByteArray hashFromPacketHeader(const QByteArray& packet);
|
||||
QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID);
|
||||
void replaceHashInPacketGivenConnectionUUID(QByteArray& packet, const QUuid& connectionUUID);
|
||||
|
||||
PacketType packetTypeForPacket(const QByteArray& packet);
|
||||
PacketType packetTypeForPacket(const char* packet);
|
||||
void replaceHashInPacketGivenType(QByteArray& packet, PacketType packetType, const QUuid& connectionUUID);
|
||||
void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID)
|
||||
{ replaceHashInPacketGivenType(packet, packetTypeForPacket(packet), connectionUUID); }
|
||||
|
||||
void replaceSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType, PacketSequenceNumber sequenceNumber);
|
||||
void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequenceNumber)
|
||||
{ replaceSequenceNumberInPacketGivenType(packet, packetTypeForPacket(packet), sequenceNumber); }
|
||||
|
||||
void replaceHashAndSequenceNumberInPacketGivenType(QByteArray& packet, PacketType packetType,
|
||||
const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber);
|
||||
void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber);
|
||||
|
||||
int arithmeticCodingValueFromBuffer(const char* checkValue);
|
||||
int numBytesArithmeticCodingFromBuffer(const char* checkValue);
|
||||
|
|
Loading…
Reference in a new issue