/*! * * Copyright (c) 2026 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file MqttTcpTransport.h * \author (original) Stephen Quong * \date (original) 30-Jul-2026 * */ #pragma once #include #include #include #include #include #include #include "MqttPacket.h" #include "MqttTransport.h" /*! * \brief MqttTransport over a plain TCP socket. * \note No TLS. This is the test transport; the production path is the AWS * SDK transport, which mTLS is part of. Pointing this at AWS IoT Core * will be refused at the TCP layer. * \note Unlike the AWS transport, the callbacks fire on the Qt thread that owns * the socket rather than a foreign event loop. That makes MqttPublisher's * marshalling a same-thread queued call, so it exercises the ordering but * not the cross-thread hazard. */ class MqttTcpTransport : public QObject, public MqttTransport { Q_OBJECT public: explicit MqttTcpTransport(QObject *parent = nullptr); ~MqttTcpTransport() override; bool open(const Config &config) override; void close() override; bool isConnected() const override; bool publish(const QString &topic, const QByteArray &payload, qint64 messageId) override; void setCallbacks(StateCallback onState, AckCallback onAck) override; void clearCallbacks() override; private Q_SLOTS: void onSocketConnected(); void onSocketDisconnected(); void onReadyRead(); void onKeepAliveTimer(); private: void handlePacket(const Mqtt::Packet &packet); void setSessionState(bool established); void failPending(); quint16 nextPacketId(); QTcpSocket _socket; QTimer _keepAliveTimer; Config _config; QByteArray _rxBuf; QHash _pending; StateCallback _onState; AckCallback _onAck; quint16 _lastPacketId = 0; bool _sessionUp = false; };