Shared pointer for the packet data

This commit is contained in:
Michael Zanetti 2020-12-15 22:46:20 +01:00
parent c2133e5539
commit f7962614f5
3 changed files with 121 additions and 53 deletions

View File

@ -48,12 +48,17 @@ Q_LOGGING_CATEGORY(dbgProto, "nymea.mqtt.protocol")
#define VERIFY_LEN(a, name) if (remainingLength != a) { qCWarning(dbgProto) << "Bad" << name << "packet. Data length unexpected."; return -1; } #define VERIFY_LEN(a, name) if (remainingLength != a) { qCWarning(dbgProto) << "Bad" << name << "packet. Data length unexpected."; return -1; }
MqttPacket::MqttPacket(): MqttPacket::MqttPacket():
d_ptr(new MqttPacketPrivate(this)) d_ptr(new MqttPacketPrivate())
{ {
} }
MqttPacket::MqttPacket(const MqttPacket &other)
{
d_ptr = other.d_ptr;
}
MqttPacket::MqttPacket(MqttPacket::Type type, quint16 packetId, Mqtt::QoS qos, bool retain, bool dup): MqttPacket::MqttPacket(MqttPacket::Type type, quint16 packetId, Mqtt::QoS qos, bool retain, bool dup):
d_ptr(new MqttPacketPrivate(this)) d_ptr(new MqttPacketPrivate())
{ {
d_ptr->packetId = packetId; d_ptr->packetId = packetId;
d_ptr->header = type; d_ptr->header = type;
@ -85,14 +90,19 @@ MqttPacket::MqttPacket(MqttPacket::Type type, quint16 packetId, Mqtt::QoS qos, b
} }
} }
MqttPacket::~MqttPacket()
{
}
MqttPacket::Type MqttPacket::type() const MqttPacket::Type MqttPacket::type() const
{ {
return static_cast<Type>(d_ptr->header & 0xF0); return d_ptr->type();
} }
bool MqttPacket::dup() const bool MqttPacket::dup() const
{ {
return d_ptr->header & 0x08; return d_ptr->dup();
} }
void MqttPacket::setDup(bool dup) void MqttPacket::setDup(bool dup)
@ -106,7 +116,7 @@ void MqttPacket::setDup(bool dup)
Mqtt::QoS MqttPacket::qos() const Mqtt::QoS MqttPacket::qos() const
{ {
return static_cast<Mqtt::QoS>((d_ptr->header & 0x06) >> 1); return d_ptr->qos();
} }
void MqttPacket::setQoS(Mqtt::QoS qoS) void MqttPacket::setQoS(Mqtt::QoS qoS)
@ -117,7 +127,7 @@ void MqttPacket::setQoS(Mqtt::QoS qoS)
bool MqttPacket::retain() const bool MqttPacket::retain() const
{ {
return d_ptr->header & 0x01; return d_ptr->retain();
} }
void MqttPacket::setRetain(bool retain) void MqttPacket::setRetain(bool retain)
@ -397,17 +407,17 @@ int MqttPacket::parse(const QByteArray &buffer)
switch (type()) { switch (type()) {
case TypeConnect: { case TypeConnect: {
ASSERT_LEN(2, "CONNECT"); ASSERT_LEN(2, "CONNECT")
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "CONNECT"); ASSERT_LEN(strLen, "CONNECT")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
d_ptr->protocolName = QByteArray(str); d_ptr->protocolName = QByteArray(str);
ASSERT_LEN(6, "CONNECT"); ASSERT_LEN(6, "CONNECT")
quint8 pl; quint8 pl;
inputStream >> pl; inputStream >> pl;
d_ptr->protocolLevel = static_cast<Mqtt::Protocol>(pl); d_ptr->protocolLevel = static_cast<Mqtt::Protocol>(pl);
@ -422,26 +432,26 @@ int MqttPacket::parse(const QByteArray &buffer)
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "CONNECT"); ASSERT_LEN(strLen, "CONNECT")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
d_ptr->clientId = QByteArray(str); d_ptr->clientId = QByteArray(str);
if (connectFlags().testFlag(Mqtt::ConnectFlagWill)) { if (connectFlags().testFlag(Mqtt::ConnectFlagWill)) {
ASSERT_LEN(2, "CONNECT"); ASSERT_LEN(2, "CONNECT")
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "CONNECT"); ASSERT_LEN(strLen, "CONNECT")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
d_ptr->willTopic = QByteArray(str); d_ptr->willTopic = QByteArray(str);
ASSERT_LEN(2, "CONNECT"); ASSERT_LEN(2, "CONNECT")
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "CONNECT"); ASSERT_LEN(strLen, "CONNECT")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
@ -454,10 +464,10 @@ int MqttPacket::parse(const QByteArray &buffer)
} }
if (connectFlags().testFlag(Mqtt::ConnectFlagUsername)) { if (connectFlags().testFlag(Mqtt::ConnectFlagUsername)) {
ASSERT_LEN(2, "CONNECT"); ASSERT_LEN(2, "CONNECT")
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "CONNECT"); ASSERT_LEN(strLen, "CONNECT")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
@ -470,20 +480,20 @@ int MqttPacket::parse(const QByteArray &buffer)
} }
if (connectFlags().testFlag(Mqtt::ConnectFlagPassword)) { if (connectFlags().testFlag(Mqtt::ConnectFlagPassword)) {
ASSERT_LEN(2, "CONNECT"); ASSERT_LEN(2, "CONNECT")
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "CONNECT"); ASSERT_LEN(strLen, "CONNECT")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
d_ptr->password = QByteArray(str); d_ptr->password = QByteArray(str);
} }
VERIFY_LEN(0, "CONNECT"); VERIFY_LEN(0, "CONNECT")
break; break;
} }
case TypeConnack: { case TypeConnack: {
VERIFY_LEN(2, "CONNACK"); VERIFY_LEN(2, "CONNACK")
quint8 connackFlags; quint8 connackFlags;
inputStream >> connackFlags; inputStream >> connackFlags;
remainingLength -= 1; remainingLength -= 1;
@ -492,21 +502,21 @@ int MqttPacket::parse(const QByteArray &buffer)
inputStream >> connectReturnCode; inputStream >> connectReturnCode;
d_ptr->connectReturnCode = static_cast<Mqtt::ConnectReturnCode>(connectReturnCode); d_ptr->connectReturnCode = static_cast<Mqtt::ConnectReturnCode>(connectReturnCode);
remainingLength -= 1; remainingLength -= 1;
VERIFY_LEN(0, "CONNACK"); VERIFY_LEN(0, "CONNACK")
break; break;
} }
case TypePublish: { case TypePublish: {
ASSERT_LEN(2, "PUBLISH"); ASSERT_LEN(2, "PUBLISH")
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "PUBLISH"); ASSERT_LEN(strLen, "PUBLISH")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
d_ptr->topic = QByteArray(str); d_ptr->topic = QByteArray(str);
if (qos() == Mqtt::QoS1 || qos() == Mqtt::QoS2) { if (qos() == Mqtt::QoS1 || qos() == Mqtt::QoS2) {
ASSERT_LEN(2, "PUBLISH"); ASSERT_LEN(2, "PUBLISH")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
remainingLength -= 2; remainingLength -= 2;
} }
@ -517,23 +527,23 @@ int MqttPacket::parse(const QByteArray &buffer)
break; break;
} }
case TypePuback: case TypePuback:
VERIFY_LEN(2, "PUBACK"); VERIFY_LEN(2, "PUBACK")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
break; break;
case TypePubrec: case TypePubrec:
VERIFY_LEN(2, "PUBREC"); VERIFY_LEN(2, "PUBREC")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
break; break;
case TypePubrel: case TypePubrel:
VERIFY_LEN(2, "PUBREL"); VERIFY_LEN(2, "PUBREL")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
break; break;
case TypePubcomp: case TypePubcomp:
VERIFY_LEN(2, "PUBCOMP"); VERIFY_LEN(2, "PUBCOMP")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
break; break;
case TypeSubscribe: { case TypeSubscribe: {
ASSERT_LEN(2, "SUBSCRIBE"); ASSERT_LEN(2, "SUBSCRIBE")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
remainingLength -= 2; remainingLength -= 2;
@ -542,17 +552,17 @@ int MqttPacket::parse(const QByteArray &buffer)
return -1; return -1;
} }
while (remainingLength > 0) { while (remainingLength > 0) {
ASSERT_LEN(2, "SUBSCRIBE"); ASSERT_LEN(2, "SUBSCRIBE")
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "SUBSCRIBE"); ASSERT_LEN(strLen, "SUBSCRIBE")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
MqttSubscription subscription; MqttSubscription subscription;
subscription.setTopicFilter(QByteArray(str)); subscription.setTopicFilter(QByteArray(str));
ASSERT_LEN(1, "SUBSCRIBE"); ASSERT_LEN(1, "SUBSCRIBE")
quint8 requestedQoS; quint8 requestedQoS;
inputStream >> requestedQoS; inputStream >> requestedQoS;
remainingLength -= 1; remainingLength -= 1;
@ -570,7 +580,7 @@ int MqttPacket::parse(const QByteArray &buffer)
break; break;
} }
case TypeSuback: case TypeSuback:
ASSERT_LEN(3, "SUBACK"); ASSERT_LEN(3, "SUBACK")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
remainingLength -= 2; remainingLength -= 2;
while (remainingLength > 0) { while (remainingLength > 0) {
@ -581,14 +591,14 @@ int MqttPacket::parse(const QByteArray &buffer)
} }
break; break;
case TypeUnsubscribe: { case TypeUnsubscribe: {
ASSERT_LEN(5, "UNSUBSCRIBE"); ASSERT_LEN(5, "UNSUBSCRIBE")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
remainingLength -= 2; remainingLength -= 2;
while (remainingLength > 0) { while (remainingLength > 0) {
ASSERT_LEN(2, "UNSUBSCRIBE"); ASSERT_LEN(2, "UNSUBSCRIBE")
inputStream >> strLen; inputStream >> strLen;
remainingLength -= 2; remainingLength -= 2;
ASSERT_LEN(strLen, "UNSUBSCRIBE"); ASSERT_LEN(strLen, "UNSUBSCRIBE")
memset(str, 0, MAX_STRLEN); memset(str, 0, MAX_STRLEN);
inputStream.readRawData(str, qMin(MAX_STRLEN, strLen)); inputStream.readRawData(str, qMin(MAX_STRLEN, strLen));
remainingLength -= strLen; remainingLength -= strLen;
@ -599,17 +609,17 @@ int MqttPacket::parse(const QByteArray &buffer)
} }
break; break;
case TypeUnsuback: case TypeUnsuback:
VERIFY_LEN(2, "UNSUBACK"); VERIFY_LEN(2, "UNSUBACK")
inputStream >> d_ptr->packetId; inputStream >> d_ptr->packetId;
break; break;
case TypePingreq: case TypePingreq:
VERIFY_LEN(0, "PINGREC"); VERIFY_LEN(0, "PINGREC")
break; break;
case TypePingresp: case TypePingresp:
VERIFY_LEN(0, "PINGRESP"); VERIFY_LEN(0, "PINGRESP")
break; break;
case TypeDisconnect: case TypeDisconnect:
VERIFY_LEN(0, "DISCONNECT"); VERIFY_LEN(0, "DISCONNECT")
break; break;
} }
return fullRemainingLength + 1 + lenFields; return fullRemainingLength + 1 + lenFields;
@ -776,11 +786,40 @@ bool MqttPacket::operator==(const MqttPacket &other) const
return serialize() == other.serialize(); return serialize() == other.serialize();
} }
MqttPacket &MqttPacket::operator =(const MqttPacket &other)
{
d_ptr = other.d_ptr;
return *this;
}
MqttPacketPrivate::MqttPacketPrivate(const MqttPacketPrivate &other):
QSharedData(other),
header(other.header),
protocolName(other.protocolName),
protocolLevel(other.protocolLevel),
connectFlags(other.connectFlags),
connackFlags(other.connackFlags),
keepAlive(other.keepAlive),
clientId(other.clientId),
willTopic(other.willTopic),
willMessage(other.willMessage),
username(other.username),
password(other.password),
packetId(other.packetId),
topic(other.topic),
payload(other.payload),
connectReturnCode(other.connectReturnCode),
subscriptions(other.subscriptions),
subscribeReturnCodes(other.subscribeReturnCodes)
{
}
bool MqttPacketPrivate::verifyHeaderFlags() bool MqttPacketPrivate::verifyHeaderFlags()
{ {
bool fail = false; bool fail = false;
switch (q_ptr->type()) { switch (type()) {
case MqttPacket::MqttPacket::TypeConnect: case MqttPacket::MqttPacket::TypeConnect:
case MqttPacket::TypeConnack: case MqttPacket::TypeConnack:
case MqttPacket::TypePuback: case MqttPacket::TypePuback:
@ -791,20 +830,40 @@ bool MqttPacketPrivate::verifyHeaderFlags()
case MqttPacket::TypePingreq: case MqttPacket::TypePingreq:
case MqttPacket::TypePingresp: case MqttPacket::TypePingresp:
case MqttPacket::TypeDisconnect: case MqttPacket::TypeDisconnect:
fail |= q_ptr->dup(); fail |= dup();
fail |= (q_ptr->qos() != Mqtt::QoS0); fail |= (qos() != Mqtt::QoS0);
fail |= q_ptr->retain(); fail |= retain();
break; break;
case MqttPacket::TypePublish: case MqttPacket::TypePublish:
fail |= (q_ptr->qos() == 0x03); fail |= (qos() == 0x03);
break; break;
case MqttPacket::TypeSubscribe: case MqttPacket::TypeSubscribe:
case MqttPacket::TypePubrel: case MqttPacket::TypePubrel:
case MqttPacket::TypeUnsubscribe: case MqttPacket::TypeUnsubscribe:
fail |= q_ptr->dup(); fail |= dup();
fail |= (q_ptr->qos() != Mqtt::QoS1); fail |= (qos() != Mqtt::QoS1);
fail |= q_ptr->retain(); fail |= retain();
break; break;
} }
return !fail; return !fail;
} }
bool MqttPacketPrivate::dup() const
{
return header & 0x08;
}
Mqtt::QoS MqttPacketPrivate::qos() const
{
return static_cast<Mqtt::QoS>((header & 0x06) >> 1);
}
bool MqttPacketPrivate::retain() const
{
return header & 0x01;
}
MqttPacket::Type MqttPacketPrivate::type() const
{
return static_cast<MqttPacket::Type>(header & 0xF0);
}

View File

@ -32,6 +32,7 @@
#include <QByteArray> #include <QByteArray>
#include <QList> #include <QList>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QSharedDataPointer>
#include "mqtt.h" #include "mqtt.h"
#include "mqttsubscription.h" #include "mqttsubscription.h"
@ -60,9 +61,10 @@ public:
}; };
MqttPacket(); MqttPacket();
MqttPacket(const MqttPacket &other);
MqttPacket(Type type, quint16 packetId = 0, Mqtt::QoS qos = Mqtt::QoS0, bool retain = false, bool dup = false); MqttPacket(Type type, quint16 packetId = 0, Mqtt::QoS qos = Mqtt::QoS0, bool retain = false, bool dup = false);
~MqttPacket();
public:
Type type() const; Type type() const;
bool dup() const; bool dup() const;
void setDup(bool dup); void setDup(bool dup);
@ -129,9 +131,10 @@ public:
QByteArray serialize() const; QByteArray serialize() const;
bool operator==(const MqttPacket &other) const; bool operator==(const MqttPacket &other) const;
MqttPacket &operator=(const MqttPacket &other);
private: private:
MqttPacketPrivate *d_ptr = nullptr; QSharedDataPointer<MqttPacketPrivate> d_ptr;
}; };
typedef QList<MqttPacket> MqttPackets; typedef QList<MqttPacket> MqttPackets;

View File

@ -37,15 +37,21 @@
#include "mqttpacket.h" #include "mqttpacket.h"
#include "mqttsubscription.h" #include "mqttsubscription.h"
#include <QSharedData>
Q_DECLARE_LOGGING_CATEGORY(dbgProto) Q_DECLARE_LOGGING_CATEGORY(dbgProto)
class MqttPacketPrivate class MqttPacketPrivate: public QSharedData
{ {
public: public:
MqttPacketPrivate(MqttPacket *q) : q_ptr(q) { } MqttPacketPrivate(){ }
MqttPacket *q_ptr; MqttPacketPrivate(const MqttPacketPrivate &other);
bool verifyHeaderFlags(); bool verifyHeaderFlags();
MqttPacket::Type type() const;
bool dup() const;
Mqtt::QoS qos() const;
bool retain() const;
quint8 header = 0; quint8 header = 0;
QByteArray protocolName = "MQTT"; QByteArray protocolName = "MQTT";