1
0
mirror of https://github.com/qt/qtmqtt.git synced 2026-10-25 16:16:26 +00:00

Add Control Packet class

Helps for generalizing packet generation and later on for testing...
This commit is contained in:
Maurice Kalinowski 2017-01-20 08:08:23 +01:00
parent a89d471be5
commit ff5bca5436
5 changed files with 219 additions and 52 deletions

View File

@ -17,8 +17,10 @@ PRIVATE_HEADERS += \
SOURCES += \
qmqttclient.cpp \
qmqttconnection.cpp
qmqttconnection.cpp \
qmqttcontrolpacket.cpp
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS \
qmqttcontrolpacket_p.h
load(qt_module)

View File

@ -27,6 +27,7 @@
**
****************************************************************************/
#include "qmqttconnection_p.h"
#include "qmqttcontrolpacket_p.h"
#include <QtNetwork/QTcpSocket>
@ -109,36 +110,20 @@ bool QMqttConnection::ensureTransportOpen()
return true;
}
inline void addInt(QByteArray &data, quint16 n)
{
const quint16 msb = qToBigEndian<quint16>(n);
const char * msb_c = reinterpret_cast<const char*>(&msb);
data.append(msb_c[0]);
data.append(msb_c[1]);
return;
}
bool QMqttConnection::sendControlConnect()
{
QByteArray connectFrame;
// Fixed header
connectFrame += PacketType::CONNECT;
QMqttControlPacket packet(QMqttControlPacket::CONNECT);
connectFrame += char(0); // Length to be filled later
// Variable header
// 3.1.2.1 Protocol Name
// 3.1.2.2 Protocol Level
const quint8 protocolVersion = m_client->protocolVersion();
if (protocolVersion == 3) {
const QByteArray other("MQIsdp");
addInt(connectFrame, other.size());
connectFrame += other.data();
connectFrame += char(3); // Version 3.1
packet.append("MQIsdp");
packet.append(char(3)); // Version 3.1
} else if (protocolVersion == 4) {
connectFrame += char(0); // Length MSB
connectFrame += 4; // Length LSB
connectFrame += "MQTT";
connectFrame += char(4); // Version 3.1.1
packet.append("MQTT");
packet.append(char(4)); // Version 3.1.1
} else {
qFatal("Illegal MQTT VERSION");
}
@ -147,32 +132,29 @@ bool QMqttConnection::sendControlConnect()
quint8 flags = 0;
// Clean session
flags |= 1;
connectFrame += char(flags);
packet.append(char(flags));
// 3.1.2.10 Keep Alive
addInt(connectFrame, m_client->keepAlive());
packet.append(m_client->keepAlive());
// 3.1.3 Payload
// 3.1.3.1 Client Identifier
if (protocolVersion == 3) { // no username
connectFrame += char(0);
connectFrame += char(0);
packet.append(char(0));
packet.append(char(0));
} else if (protocolVersion == 4) {
// Client id maximum left is 23
const QByteArray clientStringArray = m_client->clientId().left(23).toUtf8();
if (clientStringArray.size()) {
addInt(connectFrame, clientStringArray.size());
connectFrame += clientStringArray;
packet.append(clientStringArray);
} else {
connectFrame += char(0);
connectFrame += char(0);
packet.append(char(0));
packet.append(char(0));
}
}
const quint8 frameLength = connectFrame.size();
connectFrame[1] = char(frameLength - 2); // The header bytes are not included
const qint64 res = m_transport->write(connectFrame.constData(), frameLength);
const QByteArray send = packet.serialize();
const qint64 res = m_transport->write(send.constData(), send.size());
if (Q_UNLIKELY(res == -1)) {
qWarning("Could not write CONNECT frame to transport");
return false;
@ -230,7 +212,7 @@ void QMqttConnection::transportReadReady()
Q_ASSERT(data.size());
const quint8 *ptr = reinterpret_cast<const quint8 *>(data.constData());
switch (data[0]) {
case PacketType::CONNACK: {
case QMqttControlPacket::CONNACK: {
if (m_internalState != BrokerWaitForConnectAck) {
qWarning("Received CONNACK at unexpected time!");
break;
@ -261,6 +243,7 @@ void QMqttConnection::transportReadReady()
if (connectResultValue != 0) {
qWarning("Connection has been rejected");
// MQTT-3.2.2-5
// ConnectionError
m_transport->close();
}
m_internalState = BrokerConnected;

View File

@ -49,22 +49,6 @@ QT_BEGIN_NAMESPACE
class QMqttConnection : public QObject
{
Q_OBJECT
enum PacketType {
CONNECT = 0x10,
CONNACK = 0x20,
PUBLISH = 0x30,
PUBACK = 0x40,
PUBREC = 0x50,
PUBREL = 0x60,
PUBCOMP = 0x70,
SUBSCRIBE = 0x80,
SUBACK = 0x90,
UNSUBSCRIBE = 0xA0,
UNSUBACK = 0xB0,
PINGREQ = 0xC0,
PINGRESP = 0xD0,
DISCONNECT = 0xE0
};
enum InternalConnectionState {
BrokerDisconnected = 0,
@ -72,6 +56,15 @@ class QMqttConnection : public QObject
BrokerConnected
};
enum ConnectionError {
NoError = 0,
InvalidProtocolVersion = 1,
IdRejected = 2,
ServerUnavailable = 3,
BadUsernameOrPassword = 4,
NotAuthorized = 5
};
public:
explicit QMqttConnection(QObject *parent = 0);
~QMqttConnection();

View File

@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Mqtt module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmqttcontrolpacket_p.h"
QT_BEGIN_NAMESPACE
QMqttControlPacket::QMqttControlPacket()
{
}
QMqttControlPacket::QMqttControlPacket(quint8 header)
: m_header(header)
{
}
QMqttControlPacket::QMqttControlPacket(quint8 header, const QByteArray &pay)
: m_header(header)
, m_payload(pay)
{
}
void QMqttControlPacket::clear()
{
m_header = 0;
m_payload.clear();
}
void QMqttControlPacket::setHeader(quint8 h)
{
m_header = h;
}
void QMqttControlPacket::append(char value)
{
m_payload.append(value);
}
void QMqttControlPacket::append(quint16 value)
{
const quint16 msb = qToBigEndian<quint16>(value);
const char * msb_c = reinterpret_cast<const char*>(&msb);
m_payload.append(msb_c[0]);
m_payload.append(msb_c[1]);
}
void QMqttControlPacket::append(const QByteArray &data)
{
append(static_cast<quint16>(data.size()));
m_payload.append(data.constData());
}
QByteArray QMqttControlPacket::serialize()
{
// Create ByteArray
QByteArray data;
// Add Header
data.append(char(m_header));
// Add length placeholder
const quint8 l = m_payload.size();
data.append(char(l));
// Add payload
data.append(m_payload);
return data;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,91 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Mqtt module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMQTTCONTROLPACKET_P_H
#define QMQTTCONTROLPACKET_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/QtGlobal>
#include <QtCore/QByteArray>
QT_BEGIN_NAMESPACE
class QMqttControlPacket
{
public:
enum PacketType {
CONNECT = 0x10,
CONNACK = 0x20,
PUBLISH = 0x30,
PUBACK = 0x40,
PUBREC = 0x50,
PUBREL = 0x60,
PUBCOMP = 0x70,
SUBSCRIBE = 0x80,
SUBACK = 0x90,
UNSUBSCRIBE = 0xA0,
UNSUBACK = 0xB0,
PINGREQ = 0xC0,
PINGRESP = 0xD0,
DISCONNECT = 0xE0
};
QMqttControlPacket();
QMqttControlPacket(quint8 header);
QMqttControlPacket(quint8 header, const QByteArray &pay);
void clear();
void setHeader(quint8 h);
inline quint8 header() const { return m_header; }
void append(char value);
void append(quint16 value);
void append(const QByteArray &data);
QByteArray serialize();
inline QByteArray payload() const { return m_payload; }
private:
quint8 m_header;
QByteArray m_payload;
};
QT_END_NAMESPACE
#endif // QMQTTCONTROLPACKET_P_H