1
0
mirror of https://github.com/qt/qtmqtt.git synced 2026-10-25 16:16:26 +00:00
qtmqtt/src/mqtt/qmqttconnection.cpp
Maurice Kalinowski d96011b080 Introduce custom buffer
A custom buffer is required for messages containing more content than
can fit into QTcpSocket's internal buffer. Hence a message cannot be
processed within a single invocation of transportReadReady.

Change-Id: I4eed8ebbc6393569c2266d0523228f24c4925084
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
2017-05-16 08:45:06 +00:00

790 lines
24 KiB
C++

/****************************************************************************
**
** 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 "qmqttconnection_p.h"
#include "qmqttcontrolpacket_p.h"
#include "qmqttsubscription_p.h"
#include <QtCore/QLoggingCategory>
#include <QtNetwork/QSslSocket>
#include <QtNetwork/QTcpSocket>
#include <stdint.h>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcMqttConnection, "qt.mqtt.connection")
Q_LOGGING_CATEGORY(lcMqttConnectionVerbose, "qt.mqtt.connection.verbose");
QMqttConnection::QMqttConnection(QObject *parent) : QObject(parent)
{
m_pingTimer.setSingleShot(false);
m_pingTimer.connect(&m_pingTimer, &QTimer::timeout, this, &QMqttConnection::sendControlPingRequest);
}
QMqttConnection::~QMqttConnection()
{
if (m_internalState == BrokerConnected)
sendControlDisconnect();
if (m_ownTransport && m_transport)
delete m_transport;
}
void QMqttConnection::setTransport(QIODevice *device, QMqttClient::TransportType transport)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << device << " Type:" << transport;
if (m_transport) {
disconnect(m_transport, &QIODevice::aboutToClose, this, &QMqttConnection::transportConnectionClosed);
disconnect(m_transport, &QIODevice::readyRead, this, &QMqttConnection::transportReadReady);
if (m_ownTransport)
delete m_transport;
}
m_transport = device;
m_transportType = transport;
m_ownTransport = false;
connect(m_transport, &QIODevice::aboutToClose, this, &QMqttConnection::transportConnectionClosed);
connect(m_transport, &QIODevice::readyRead, this, &QMqttConnection::transportReadReady);
}
QIODevice *QMqttConnection::transport() const
{
return m_transport;
}
bool QMqttConnection::ensureTransport(bool createSecureIfNeeded)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << m_transport;
if (m_transport)
return true;
// We are asked to create a transport layer
if (m_client->hostname().isEmpty() || m_client->port() == 0) {
qWarning("Trying to create a transport layer, but no hostname is specified");
return false;
}
auto socket = createSecureIfNeeded ? new QSslSocket() : new QTcpSocket();
m_transport = socket;
m_ownTransport = true;
m_transportType = createSecureIfNeeded ? QMqttClient::SecureSocket : QMqttClient::AbstractSocket;
connect(socket, &QAbstractSocket::disconnected, this, &QMqttConnection::transportConnectionClosed);
connect(m_transport, &QIODevice::aboutToClose, this, &QMqttConnection::transportConnectionClosed);
connect(m_transport, &QIODevice::readyRead, this, &QMqttConnection::transportReadReady);
return true;
}
bool QMqttConnection::ensureTransportOpen(const QString &sslPeerName)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << m_transportType;
if (m_transportType == QMqttClient::IODevice) {
if (m_transport->isOpen())
return true;
if (m_transport->open(QIODevice::ReadWrite)) {
qWarning("Could not open Transport IO device");
return false;
}
} else if (m_transportType == QMqttClient::AbstractSocket) {
auto socket = dynamic_cast<QTcpSocket*>(m_transport);
Q_ASSERT(socket);
if (socket->state() == QAbstractSocket::ConnectedState)
return true;
socket->connectToHost(m_client->hostname(), m_client->port());
if (!socket->waitForConnected()) {
qWarning("Could not establish socket connection for transport");
return false;
}
} else if (m_transportType == QMqttClient::SecureSocket) {
auto socket = dynamic_cast<QSslSocket*>(m_transport);
Q_ASSERT(socket);
if (socket->state() == QAbstractSocket::ConnectedState)
return true;
socket->connectToHostEncrypted(m_client->hostname(), m_client->port(), sslPeerName);
if (!socket->waitForConnected()) {
qWarning("Could not establish socket connection for transport");
return false;
}
if (!socket->waitForEncrypted()) {
qWarning("Could not initiate encryption.");
return false;
}
}
return true;
}
bool QMqttConnection::sendControlConnect()
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO;
QMqttControlPacket packet(QMqttControlPacket::CONNECT);
// Variable header
// 3.1.2.1 Protocol Name
// 3.1.2.2 Protocol Level
const quint8 protocolVersion = m_client->protocolVersion();
if (protocolVersion == 3) {
packet.append("MQIsdp");
packet.append(char(3)); // Version 3.1
} else if (protocolVersion == 4) {
packet.append("MQTT");
packet.append(char(4)); // Version 3.1.1
} else {
qFatal("Illegal MQTT VERSION");
}
// 3.1.2.3 Connect Flags
quint8 flags = 0;
// Clean session
if (m_client->cleanSession())
flags |= 1;
if (!m_client->willMessage().isEmpty()) {
flags |= 1 << 2;
if (m_client->willQoS() > 2) {
qWarning("Will QoS does not have a valid value");
return false;
}
if (m_client->willQoS() == 1)
flags |= 1 << 3;
else if (m_client->willQoS() == 2)
flags |= 1 << 4;
if (m_client->willRetain())
flags |= 1 << 5;
}
if (m_client->username().size())
flags |= 1 << 7;
if (m_client->password().size())
flags |= 1 << 6;
packet.append(char(flags));
// 3.1.2.10 Keep Alive
packet.append(m_client->keepAlive());
// 3.1.3 Payload
// 3.1.3.1 Client Identifier
// Client id maximum left is 23
const QByteArray clientStringArray = m_client->clientId().left(23).toUtf8();
if (clientStringArray.size()) {
packet.append(clientStringArray);
} else {
packet.append(char(0));
packet.append(char(0));
}
if (!m_client->willMessage().isEmpty()) {
packet.append(m_client->willTopic().toUtf8());
packet.append(m_client->willMessage());
}
if (m_client->username().size())
packet.append(m_client->username().toUtf8());
if (m_client->password().size())
packet.append(m_client->password().toUtf8());
if (!writePacketToTransport(packet)) {
qWarning("Could not write CONNECT frame to transport");
return false;
}
m_internalState = BrokerWaitForConnectAck;
return true;
}
qint32 QMqttConnection::sendControlPublish(const QString &topic, const QByteArray &message, quint8 qos, bool retain)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << topic << " Size:" << message.size() << " bytes."
<< "QoS:" << qos << " Retain:" << retain;
if (topic.contains(QLatin1Char('#')) || topic.contains('+'))
return -1;
quint8 header = QMqttControlPacket::PUBLISH;
if (qos == 1)
header |= 0x02;
else if (qos == 2)
header |= 0x04;
if (retain)
header |= 0x01;
QSharedPointer<QMqttControlPacket> packet(new QMqttControlPacket(header));
QByteArray topicArray = topic.toUtf8();
if (topicArray.size() > UINT16_MAX) {
qWarning("Published topic is too long. Need to truncate");
topicArray.truncate(UINT16_MAX);
}
packet->append(topicArray);
quint16 identifier = 0;
if (qos > 0) {
// Add Packet Identifier
static quint16 publishIdCounter = 0;
if (publishIdCounter + 1 == UINT16_MAX)
publishIdCounter = 0;
else
publishIdCounter++;
identifier = publishIdCounter;
packet->append(identifier);
}
packet->appendRaw(message);
if (qos)
m_pendingMessages.insert(identifier, packet);
const bool written = writePacketToTransport(*packet.data());
if (!written)
m_pendingMessages.remove(identifier);
return written ? identifier : -1;
}
bool QMqttConnection::sendControlPublishAcknowledge(quint16 id)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << id;
QMqttControlPacket packet(QMqttControlPacket::PUBACK);
packet.append(id);
return writePacketToTransport(packet);
}
bool QMqttConnection::sendControlPublishRelease(quint16 id)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << id;
QMqttControlPacket packet(QMqttControlPacket::PUBREL);
packet.append(id);
return writePacketToTransport(packet);
}
bool QMqttConnection::sendControlPublishReceive(quint16 id)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << id;
QMqttControlPacket packet(QMqttControlPacket::PUBREC);
packet.append(id);
return writePacketToTransport(packet);
}
bool QMqttConnection::sendControlPublishComp(quint16 id)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << id;
QMqttControlPacket packet(QMqttControlPacket::PUBCOMP);
packet.append(id);
return writePacketToTransport(packet);
}
QSharedPointer<QMqttSubscription> QMqttConnection::sendControlSubscribe(const QString &topic, quint8 qos)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << " Topic:" << topic << " qos:" << qos;
if (m_activeSubscriptions.contains(topic))
return m_activeSubscriptions[topic];
// has to have 0010 as bits 3-0, maybe update SUBSCRIBE instead?
// MQTT-3.8.1-1
const quint8 header = QMqttControlPacket::SUBSCRIBE + 0x02;
QMqttControlPacket packet(header);
// Add Packet Identifier
const quint16 identifier = qrand();
packet.append(identifier);
// Overflow protection
QByteArray topicArray = topic.toUtf8();
if (topicArray.size() > UINT16_MAX) {
qWarning("Subscribed topic is too long.");
return QSharedPointer<QMqttSubscription>();
}
packet.append(topicArray);
switch (qos) {
case 0: packet.append(char(0x0)); break;
case 1: packet.append(char(0x1)); break;
case 2: packet.append(char(0x2)); break;
default: return QSharedPointer<QMqttSubscription>();
}
QSharedPointer<QMqttSubscription> result(new QMqttSubscription);
result->setTopic(topicArray);
result->setClient(m_client);
result->setQos(qos);
result->setState(QMqttSubscription::SubscriptionPending);
if (!writePacketToTransport(packet))
return QSharedPointer<QMqttSubscription>();
// SUBACK must contain identifier MQTT-3.8.4-2
m_pendingSubscriptionAck.insert(identifier, result);
return result;
}
bool QMqttConnection::sendControlUnsubscribe(const QString &topic)
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO << " Topic:" << topic;
// MQTT-3.10.3-2
if (topic.isEmpty())
return false;
if (!m_activeSubscriptions.contains(topic))
return false;
if (m_internalState != QMqttConnection::BrokerConnected) {
m_activeSubscriptions.remove(topic);
return true;
}
// has to have 0010 as bits 3-0, maybe update UNSUBSCRIBE instead?
// MQTT-3.10.1-1
const quint8 header = QMqttControlPacket::UNSUBSCRIBE + 0x02;
QMqttControlPacket packet(header);
// Add Packet Identifier
const quint16 identifier = qrand();
packet.append(identifier);
packet.append(topic.toUtf8());
auto sub = m_activeSubscriptions[topic];
sub->setState(QMqttSubscription::UnsubscriptionPending);
if (!writePacketToTransport(packet))
return false;
// Do not remove from m_activeSubscriptions as there might be QoS1/2 messages to still
// be sent before UNSUBSCRIBE is acknowledged.
m_pendingUnsubscriptions.insert(identifier, sub);
return true;
}
bool QMqttConnection::sendControlPingRequest()
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO;
if (m_internalState != QMqttConnection::BrokerConnected)
return false;
const QMqttControlPacket packet(QMqttControlPacket::PINGREQ);
if (!writePacketToTransport(packet)) {
qWarning("Could not write DISCONNECT frame to transport");
return false;
}
return true;
}
bool QMqttConnection::sendControlDisconnect()
{
qCDebug(lcMqttConnection) << Q_FUNC_INFO;
m_pingTimer.stop();
for (auto sub : m_activeSubscriptions)
sub->unsubscribe();
m_activeSubscriptions.clear();
const QMqttControlPacket packet(QMqttControlPacket::DISCONNECT);
if (!writePacketToTransport(packet)) {
qWarning("Could not write DISCONNECT frame to transport");
return false;
}
m_internalState = BrokerDisconnected;
if (m_transport->waitForBytesWritten(30000)) {
// MQTT-3.14.4-1 must disconnect
m_transport->close();
return true;
}
return false;
}
void QMqttConnection::setClient(QMqttClient *client)
{
m_client = client;
}
void QMqttConnection::transportConnectionClosed()
{
m_readBuffer.clear();
m_pingTimer.stop();
m_client->setState(QMqttClient::Disconnected);
}
void QMqttConnection::transportReadReady()
{
qCDebug(lcMqttConnectionVerbose) << Q_FUNC_INFO;
m_readBuffer.append(m_transport->readAll());
processData();
}
void QMqttConnection::readBuffer(char *data, qint64 size)
{
memcpy(data, m_readBuffer.constData(), size);
m_readBuffer = m_readBuffer.mid(size);
}
QByteArray QMqttConnection::readBuffer(qint64 size)
{
QByteArray res = m_readBuffer.left(size);
m_readBuffer = m_readBuffer.mid(size);
return res;
}
void QMqttConnection::finalize_connack()
{
qCDebug(lcMqttConnectionVerbose) << "Finalize CONNACK";
quint8 ackFlags;
readBuffer((char*)&ackFlags, 1);
if (ackFlags > 1) { // MQTT-3.2.2.1
qWarning("Unexpected CONNACK Flags set");
// ## SET SOME ERROR
return;
}
bool sessionPresent = ackFlags == 1;
// MQTT-3.2.2-1 & MQTT-3.2.2-2
if (sessionPresent) {
emit m_client->brokerSessionRestored();
if (m_client->cleanSession()) {
qWarning("Connected with a clean session, ack contains session present");
// ### TODO: RABBIT MQ Spec Misalign
// If a clean session is requested by the client, the server has to have an empty
// session. However Rabbit MQ sends a 1 here for unknown reasons.
//break;
}
}
quint8 connectResultValue;
readBuffer((char*)&connectResultValue, 1);
if (connectResultValue != 0) {
qWarning("Connection has been rejected");
// MQTT-3.2.2-5
// ConnectionError
m_readBuffer.clear();
m_transport->close();
}
m_internalState = BrokerConnected;
m_client->setState(QMqttClient::Connected);
m_pingTimer.setInterval(m_client->keepAlive() * 1000);
m_pingTimer.start();
}
void QMqttConnection::finalize_suback()
{
quint16 id;
readBuffer((char*)&id, 2);
id = qFromBigEndian<quint16>(id);
if (!m_pendingSubscriptionAck.contains(id)) {
qWarning("Received SUBACK for unknown subscription request");
return;
}
quint8 result;
readBuffer((char*)&result, 1);
auto sub = m_pendingSubscriptionAck.take(id);
qCDebug(lcMqttConnectionVerbose) << "Finalize SUBACK: id:" << id << "qos:" << result;
if (result <= 2) {
// The broker might have a different support level for QoS than what
// the client requested
if (result != sub->qos()) {
sub->setQos(result);
emit sub->qosChanged(result);
}
sub->setState(QMqttSubscription::Subscribed);
m_activeSubscriptions.insert(sub->topic(), sub);
} else if (result == 0x80) {
qWarning() << "Subscription for id " << id << " failed.";
sub->setState(QMqttSubscription::Error);
} else {
qWarning("Received invalid SUBACK result value");
sub->setState(QMqttSubscription::Error);
}
}
void QMqttConnection::finalize_unsuback()
{
quint16 id;
readBuffer((char*)&id, 2);
id = qFromBigEndian<quint16>(id);
qCDebug(lcMqttConnectionVerbose) << "Finalize UNSUBACK: " << id;
if (!m_pendingUnsubscriptions.contains(id)) {
qWarning("Received UNSUBACK for unknown request");
return;
}
auto sub = m_pendingUnsubscriptions.take(id);
sub->setState(QMqttSubscription::Unsubscribed);
m_activeSubscriptions.remove(sub->topic());
}
void QMqttConnection::finalize_publish()
{
// String topic
const quint16 topicLength = qFromBigEndian<quint16>(reinterpret_cast<const quint16 *>(readBuffer(2).constData()));
const QString topic = QString::fromUtf8(reinterpret_cast<const char *>(readBuffer(topicLength).constData()));
quint16 id;
if (m_currentPublish.qos > 0) {
id = qFromBigEndian<quint16>(reinterpret_cast<const quint16 *>(readBuffer(2).constData()));
}
// message
qint64 payloadLength = m_missingData - (topicLength + 2) - (m_currentPublish.qos > 0 ? 2 : 0);
const QByteArray message = readBuffer(payloadLength);
qCDebug(lcMqttConnectionVerbose) << "Finalize PUBLISH: topic:" << topic
<< " payloadLength:" << payloadLength;;
emit m_client->messageReceived(message, topic);
for (auto sub = m_activeSubscriptions.constBegin(); sub != m_activeSubscriptions.constEnd(); sub++) {
const QString subTopic = sub.key();
if (subTopic == topic) {
emit sub.value()->messageReceived(message, topic);
continue;
} else if (subTopic.endsWith(QLatin1Char('#')) && topic.startsWith(subTopic.leftRef(subTopic.size() - 1))) {
emit sub.value()->messageReceived(message, topic);
continue;
}
if (!subTopic.contains(QLatin1Char('+')))
continue;
const QVector<QStringRef> subTopicSplit = subTopic.splitRef(QLatin1Char('/'));
const QVector<QStringRef> topicSplit = topic.splitRef(QLatin1Char('/'));
if (subTopicSplit.size() != topicSplit.size())
continue;
const QVector<QStringRef> subPlusSplit = subTopic.splitRef(QLatin1Char('+'));
if (topic.startsWith(subPlusSplit.at(0)) && topic.endsWith(subPlusSplit.at(1))) {
emit sub.value()->messageReceived(message, topic);
}
}
if (m_currentPublish.qos == 1)
sendControlPublishAcknowledge(id);
else if (m_currentPublish.qos == 2)
sendControlPublishReceive(id);
}
void QMqttConnection::finalize_pubAckRecComp()
{
qCDebug(lcMqttConnectionVerbose) << "Finalize PUBACK/REC/COMP";
quint16 id;
readBuffer((char*)&id, 2);
id = qFromBigEndian<quint16>(id);
if ((m_currentPacket & 0xF0) == QMqttControlPacket::PUBCOMP) {
qCDebug(lcMqttConnectionVerbose) << " PUBCOMP:" << id;
auto pendingRelease = m_pendingReleaseMessages.take(id);
if (!pendingRelease)
qWarning("Received PUBCOMP for unknown released message");
emit m_client->messageSent(id);
return;
}
auto pendingMsg = m_pendingMessages.take(id);
if (!pendingMsg) {
qWarning(qPrintable(QString::fromLatin1("Received PUBACK for unknown message: %1").arg(id)));
return;
}
if ((m_currentPacket & 0xF0) == QMqttControlPacket::PUBREC) {
qCDebug(lcMqttConnectionVerbose) << " PUBREC:" << id;
m_pendingReleaseMessages.insert(id, pendingMsg);
sendControlPublishRelease(id);
} else {
qCDebug(lcMqttConnectionVerbose) << " PUBACK:" << id;
emit m_client->messageSent(id);
}
}
void QMqttConnection::finalize_pubrel()
{
quint16 id;
readBuffer((char*)&id, 2);
id = qFromBigEndian<quint16>(id);
qCDebug(lcMqttConnectionVerbose) << "Finalize PUBREL:" << id;
// ### TODO: send to our app now or not???
// See standard Figure 4.3 Method A or B ???
sendControlPublishComp(id);
}
void QMqttConnection::finalize_pingresp()
{
qCDebug(lcMqttConnectionVerbose) << "Finalize PINGRESP";
quint8 v;
readBuffer((char*)&v, 1);
if (v != 0)
qWarning("Received a PINGRESP with payload!");
emit m_client->pingResponse();
}
void QMqttConnection::processData()
{
if (m_missingData > 0) {
if (m_readBuffer.size() < m_missingData)
return;
switch (m_currentPacket & 0xF0) {
case QMqttControlPacket::CONNACK:
finalize_connack();
break;
case QMqttControlPacket::SUBACK:
finalize_suback();
break;
case QMqttControlPacket::UNSUBACK:
finalize_unsuback();
break;
case QMqttControlPacket::PUBLISH:
finalize_publish();
break;
case QMqttControlPacket::PUBACK:
case QMqttControlPacket::PUBREC:
case QMqttControlPacket::PUBCOMP:
finalize_pubAckRecComp();
break;
case QMqttControlPacket::PINGRESP:
finalize_pingresp();
break;
case QMqttControlPacket::PUBREL: {
finalize_pubrel();
break;
}
default:
qFatal("Unknown packet to finalize");
break;
}
m_missingData = 0;
}
if (m_readBuffer.size() == 0)
return;
readBuffer((char*)&m_currentPacket, 1);
switch (m_currentPacket & 0xF0) {
case QMqttControlPacket::CONNACK: {
qCDebug(lcMqttConnectionVerbose) << "Received CONNACK";
if (m_internalState != BrokerWaitForConnectAck) {
qWarning("Received CONNACK at unexpected time!");
break;
}
quint8 payloadSize;
readBuffer((char*)&payloadSize, 1);
if (payloadSize != 2) {
qWarning("Unexpected FRAME size in CONNACK");
// ## SET SOME ERROR
break;
}
m_missingData = 2;
break;
}
case QMqttControlPacket::SUBACK: {
qCDebug(lcMqttConnectionVerbose) << "Received SUBACK";
quint8 remaining;
readBuffer((char*)&remaining, 1);
m_missingData = remaining;
break;
}
case QMqttControlPacket::PUBLISH: {
qCDebug(lcMqttConnectionVerbose) << "Received PUBLISH";
m_currentPublish.qos = (m_currentPacket & 0x06) >> 1;
m_currentPublish.retain = m_currentPacket & 0x01;
// remaining length
quint32 multiplier = 1;
quint32 msgLength = 0;
quint8 b = 0;
quint8 iteration = 0;
do {
readBuffer((char*)&b, 1);
msgLength += (b & 127) * multiplier;
multiplier *= 128;
iteration++;
if (iteration > 4)
qFatal("Publish message is too big to handle");
} while ((b & 128) != 0);
m_missingData = msgLength;
break;
}
case QMqttControlPacket::PINGRESP:
qCDebug(lcMqttConnectionVerbose) << "Received PINGRESP";
m_missingData = 1;
break;
case QMqttControlPacket::UNSUBACK:
case QMqttControlPacket::PUBACK:
case QMqttControlPacket::PUBREC:
case QMqttControlPacket::PUBCOMP:
case QMqttControlPacket::PUBREL: {
qCDebug(lcMqttConnectionVerbose) << "Received UNSUBACK/PUBACK/PUBREC/PUBCOMP/PUBREL";
char remaining;
readBuffer(&remaining, 1); // ### TODO: verify this is 2
if (remaining != 0x02)
qWarning("Received 2 byte message with invalid remaining length");
m_missingData = 2;
break;
}
default:
qFatal("Received unknown command");
break;
}
/* set current command CONNACK - PINGRESP */
/* read command size */
/* calculate missing_data */
processData(); // implicitly finishes and enqueues
return;
}
bool QMqttConnection::writePacketToTransport(const QMqttControlPacket &p)
{
const QByteArray writeData = p.serialize();
const qint64 res = m_transport->write(writeData.constData(), writeData.size());
if (Q_UNLIKELY(res == -1)) {
qWarning("Could not write frame to transport");
return false;
}
return true;
}
QT_END_NAMESPACE