mirror of
https://github.com/qt/qtmqtt.git
synced 2026-10-25 16:16:26 +00:00
Compare commits
230 Commits
v6.8.5-lts
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5238fdb1c3 | ||
|
|
407ac111fd | ||
|
|
d8fa0e633f | ||
|
|
51fe8b4f2e | ||
|
|
457877b453 | ||
|
|
529a2ed7d9 | ||
|
|
39f5d8bc63 | ||
|
|
a4ba93f3ca | ||
|
|
d24a6483d0 | ||
|
|
e147dedea3 | ||
|
|
1316c02fe7 | ||
|
|
ece01bf0ee | ||
|
|
24678da81e | ||
|
|
21b866609f | ||
|
|
6bdaef48c7 | ||
|
|
c58aedad7a | ||
|
|
dd767d7a57 | ||
|
|
06d301aa50 | ||
|
|
33538c5143 | ||
|
|
9e0428b917 | ||
|
|
c7f7555d8e | ||
|
|
011eb1e424 | ||
|
|
ee16836877 | ||
|
|
c94175ff43 | ||
|
|
13288574c1 | ||
|
|
ecaf42152e | ||
|
|
ba2b82223a | ||
|
|
90f2efdd5d | ||
|
|
b73e4d4ffc | ||
|
|
96d602b65f | ||
|
|
fe85eff00c | ||
|
|
16862e4fa7 | ||
|
|
2caa279c61 | ||
|
|
ebd3d87293 | ||
|
|
14de26f60b | ||
|
|
a85b5c3ecf | ||
|
|
2dc7e69f0e | ||
|
|
9cc2b3859d | ||
|
|
088b583810 | ||
|
|
fa9b04ab15 | ||
|
|
53aba306b9 | ||
|
|
3b476b23eb | ||
|
|
cf66710eb6 | ||
|
|
5d592b2aa3 | ||
|
|
ae08a87fc4 | ||
|
|
1d7f954339 | ||
|
|
f7267c6452 | ||
|
|
cefbe34e78 | ||
|
|
b7d124d65f | ||
|
|
e7616f09c1 | ||
|
|
ba85d5db5c | ||
|
|
396d0f90e7 | ||
|
|
468dfd5357 | ||
|
|
24ec59ffbb | ||
|
|
c0f5cee7eb | ||
|
|
5287cf1442 | ||
|
|
778fa2d33c | ||
|
|
92c214f82a | ||
|
|
ed2aeb5392 | ||
|
|
fe7422c165 | ||
|
|
8c32cf60c0 | ||
|
|
92de735434 | ||
|
|
a3c58404a4 | ||
|
|
3e904a3eb4 | ||
|
|
8931b61d89 | ||
|
|
0ec04b89e2 | ||
|
|
6d7b27ab94 | ||
|
|
00a8eb7b67 | ||
|
|
34656ac5ba | ||
|
|
39260ae2da | ||
|
|
b29077d7a8 | ||
|
|
3f7a78ee7a | ||
|
|
e67dafc7f0 | ||
|
|
d29b14762a | ||
|
|
9b6034ed76 | ||
|
|
3ba3066570 | ||
|
|
66508a4eb9 | ||
|
|
a7e5abab46 | ||
|
|
b4bcd45be0 | ||
|
|
2bc0a35600 | ||
|
|
9713f3ce3c | ||
|
|
e2ae1fc992 | ||
|
|
8e5acbae56 | ||
|
|
c588c20e66 | ||
|
|
f86a1256ea | ||
|
|
cf63fbc069 | ||
|
|
18f56919ea | ||
|
|
4f6e8dd0f1 | ||
|
|
10b203bfa2 | ||
|
|
b50be0baf7 | ||
|
|
1189064b88 | ||
|
|
977115a9cb | ||
|
|
db2c48bf61 | ||
|
|
c4be55826e | ||
|
|
c6ea0e6059 | ||
|
|
00190db47e | ||
|
|
f6a803d24c | ||
|
|
6372682e14 | ||
|
|
2b011198f1 | ||
|
|
f18faa609a | ||
|
|
f1cee95bbd | ||
|
|
0d21bdef58 | ||
|
|
ad34c67816 | ||
|
|
7bf74eac1d | ||
|
|
44c50b2b66 | ||
|
|
6e29d031b5 | ||
|
|
bd81918910 | ||
|
|
32f954d6c2 | ||
|
|
467f31cc1b | ||
|
|
b5c1e3aeb6 | ||
|
|
6740c49752 | ||
|
|
d2118973e7 | ||
|
|
9f1c2af872 | ||
|
|
13b1e8f4db | ||
|
|
ccb2349722 | ||
|
|
6624b461eb | ||
|
|
7cd379444a | ||
|
|
635ae612f1 | ||
|
|
2c9be38a7c | ||
|
|
d5c3a3334c | ||
|
|
fae7ba0455 | ||
|
|
1cc23b20ef | ||
|
|
96ec1750fe | ||
|
|
111328866c | ||
|
|
18548033e1 | ||
|
|
7674ec983f | ||
|
|
13a98e39e7 | ||
|
|
0342578df5 | ||
|
|
7a968c89c9 | ||
|
|
0cd68dbd7b | ||
|
|
06c368d44f | ||
|
|
f4398ac583 | ||
|
|
8141fbbb6c | ||
|
|
3f99de6d17 | ||
|
|
7cbde7dc91 | ||
|
|
f2c7593a55 | ||
|
|
c383083270 | ||
|
|
a0a4633308 | ||
|
|
b47cff69bf | ||
|
|
9c0cef3350 | ||
|
|
ae33492ca8 | ||
|
|
6eb01cac46 | ||
|
|
2978075162 | ||
|
|
951ea815b8 | ||
|
|
27a5c3ce6b | ||
|
|
d09d1fbf67 | ||
|
|
f542cfa1a4 | ||
|
|
22b5735162 | ||
|
|
5b5dee5f74 | ||
|
|
9c04ffb5c3 | ||
|
|
7ce0033a38 | ||
|
|
ec49cefbaf | ||
|
|
11172cfa34 | ||
|
|
9929b7c148 | ||
|
|
97fd1f585f | ||
|
|
2465b63c36 | ||
|
|
c04fcebf93 | ||
|
|
2cfbbfd24e | ||
|
|
b5bd818d22 | ||
|
|
0c91902e7e | ||
|
|
609f3fe7eb | ||
|
|
9048f80e3a | ||
|
|
6b9b462bb5 | ||
|
|
d0ee0581d0 | ||
|
|
af0893b8bb | ||
|
|
0473d461f5 | ||
|
|
5d29379dfb | ||
|
|
f9305b56d9 | ||
|
|
8316766cec | ||
|
|
967c70f1d5 | ||
|
|
dec643fc61 | ||
|
|
24f5eceea2 | ||
|
|
aa2fb73ac4 | ||
|
|
3543195ee0 | ||
|
|
937974f18c | ||
|
|
ceeb04c46f | ||
|
|
d1f445af72 | ||
|
|
7130aadcea | ||
|
|
b118aafb0b | ||
|
|
9aec010a74 | ||
|
|
aeac9f7e17 | ||
|
|
5a0b137e9e | ||
|
|
f6f8bc0fe4 | ||
|
|
45ab6b8cd2 | ||
|
|
8452101eca | ||
|
|
1de96c8ec1 | ||
|
|
048d6bebbb | ||
|
|
b539b0c38b | ||
|
|
83db4482e7 | ||
|
|
cb00ee0cff | ||
|
|
264ce67ade | ||
|
|
f17511d6f5 | ||
|
|
5400305ccf | ||
|
|
2bf9713ece | ||
|
|
5f8de4a443 | ||
|
|
fd2a5b9d4e | ||
|
|
e321f4663b | ||
|
|
f1b13c908a | ||
|
|
ba488ed615 | ||
|
|
06f07a00a8 | ||
|
|
50677c5da2 | ||
|
|
cec66481b3 | ||
|
|
575e141bb0 | ||
|
|
84888e818e | ||
|
|
fefcebc0f3 | ||
|
|
8dc327b4ba | ||
|
|
c15616b0a7 | ||
|
|
334f06a95f | ||
|
|
240875588c | ||
|
|
0eee872326 | ||
|
|
6490484c9d | ||
|
|
5fcdb78b9c | ||
|
|
3a7f631998 | ||
|
|
87d82a895f | ||
|
|
18bed862b2 | ||
|
|
314a9bd0f6 | ||
|
|
a87700e0d0 | ||
|
|
386ca7d5b8 | ||
|
|
362b9a9e08 | ||
|
|
3813cf3bdd | ||
|
|
45a786170c | ||
|
|
3f24adc297 | ||
|
|
a8125e63e4 | ||
|
|
5c5c9c44d7 | ||
|
|
dd6bf765ed | ||
|
|
a66f4ab2aa | ||
|
|
06e4c4e9b5 | ||
|
|
b1317fcbfe | ||
|
|
5ce02acf9b | ||
|
|
613fbbab5c |
@ -1,4 +1,5 @@
|
||||
set(QT_REPO_MODULE_VERSION "6.8.0")
|
||||
set(QT_REPO_MODULE_VERSION "6.13.0")
|
||||
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
|
||||
set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1")
|
||||
set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_QASCONST=1")
|
||||
list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_FOREACH=1")
|
||||
list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD=1")
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -68,6 +68,7 @@ Makefile*
|
||||
|
||||
# QtCtreator CMake
|
||||
CMakeLists.txt.user*
|
||||
CMakeUserPresets.json
|
||||
|
||||
## Visual Studio
|
||||
# User-specific files
|
||||
|
||||
4
.gitreview
Normal file
4
.gitreview
Normal file
@ -0,0 +1,4 @@
|
||||
[gerrit]
|
||||
host=codereview.qt-project.org
|
||||
project=qt/qtmqtt
|
||||
defaultbranch=dev
|
||||
@ -11,9 +11,14 @@ project(QtMqtt
|
||||
LANGUAGES CXX C
|
||||
)
|
||||
|
||||
find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core Network)
|
||||
find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Quick WebSockets # For tests
|
||||
Gui Widgets) # For examples
|
||||
find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals)
|
||||
|
||||
# This should be called as early as possible, just after find_package(BuildInternals) where it is
|
||||
# defined.
|
||||
qt_internal_project_setup()
|
||||
|
||||
find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core Network)
|
||||
find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Quick # For tests
|
||||
Gui Widgets WebSockets) # For examples
|
||||
|
||||
qt_build_repo()
|
||||
|
||||
11
CONTRIBUTING.md
Normal file
11
CONTRIBUTING.md
Normal file
@ -0,0 +1,11 @@
|
||||
## Qt contribution guidelines
|
||||
|
||||
We welcome contributions to Qt!
|
||||
|
||||
Note that we cannot accept pull requests on GitHub. All contributions
|
||||
to the Qt project are exclusively handled through the
|
||||
[Gerrit code review system](https://codereview.qt-project.org).
|
||||
|
||||
See
|
||||
[contribute.qt-project.org](https://contribute.qt-project.org/) to learn
|
||||
more.
|
||||
@ -1,22 +0,0 @@
|
||||
The Qt Company GPL Exception 1.0
|
||||
|
||||
Exception 1:
|
||||
|
||||
As a special exception you may create a larger work which contains the
|
||||
output of this application and distribute that work under terms of your
|
||||
choice, so long as the work is not otherwise derived from or based on
|
||||
this application and so long as the work does not in itself generate
|
||||
output that contains the output from this application in its original
|
||||
or modified form.
|
||||
|
||||
Exception 2:
|
||||
|
||||
As a special exception, you have permission to combine this application
|
||||
with Plugins licensed under the terms of your choice, to produce an
|
||||
executable, and to copy and distribute the resulting executable under
|
||||
the terms of your choice. However, the executable must be accompanied
|
||||
by a prominent notice offering all users of the executable the entire
|
||||
source code to this application, excluding the source code of the
|
||||
independent modules, but including any changes you have made to this
|
||||
application, under the terms of this license.
|
||||
|
||||
44
REUSE.toml
Normal file
44
REUSE.toml
Normal file
@ -0,0 +1,44 @@
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = [".cmake.conf", "**.yaml", "**/ci_config_linux.json", "**.pro", ".tag"]
|
||||
precedence = "closest"
|
||||
comment = "build system"
|
||||
SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
|
||||
SPDX-License-Identifier = "BSD-3-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = ["**/.gitattributes", "**.gitignore", "**.gitreview"]
|
||||
precedence = "closest"
|
||||
comment = "version control system. Infrastructure"
|
||||
SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
|
||||
SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = ["**/doc/images/**", "examples/**"]
|
||||
comment = "this must be after the build system table because example and snippets take precedence over build system"
|
||||
precedence = "closest"
|
||||
SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
|
||||
SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = ["**.qdocconf", "src/mqtt/doc/style/style.css",
|
||||
"tests/README.txt", "CONTRIBUTING.md"]
|
||||
comment = "documentation"
|
||||
precedence = "closest"
|
||||
SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
|
||||
SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"
|
||||
|
||||
[[annotations]]
|
||||
path = ["**.toml", "licenseRule.json"]
|
||||
comment = "infrastructure"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
|
||||
SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = ["**/qt_attribution.json"]
|
||||
comment = "currently not needed, but ready if such file is added. documentation."
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
|
||||
SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"
|
||||
@ -6,7 +6,23 @@ accept_configuration:
|
||||
|
||||
instructions:
|
||||
Build:
|
||||
- type: EnvironmentVariable
|
||||
variableName: VERIFY_SOURCE_SBOM
|
||||
variableValue: "ON"
|
||||
- type: EnvironmentVariable
|
||||
variableName: COIN_NO_MOSQUITTO
|
||||
variableValue: "1"
|
||||
enable_if:
|
||||
condition: and
|
||||
conditions:
|
||||
- condition: property
|
||||
property: host.os
|
||||
equals_value: Windows
|
||||
- condition: property
|
||||
property: target.arch
|
||||
in_values: ["AARCH64", "ARM64"]
|
||||
- !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml"
|
||||
|
||||
Test:
|
||||
- !include "{{qt/qtbase}}/coin_module_test_template_v2.yaml"
|
||||
- !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml"
|
||||
- !include "{{qt/qtbase}}/coin_module_test_docs.yaml"
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
dependencies:
|
||||
../qtbase:
|
||||
ref: 244964d06a3ffcfea922f79c726ba9182149e2c7
|
||||
ref: 537c0040b0c1a1b3bae99e9edca827c9e3a16ee7
|
||||
required: true
|
||||
../qtdeclarative:
|
||||
ref: 4ad3d0c6096e6caefec74681eed86c2fa92149fd
|
||||
ref: 3c20488ac4a676c612cef9539144194a4fb86801
|
||||
required: true
|
||||
../qtwebsockets:
|
||||
ref: 217120e4e991ed2de51cac910cccfbf51f912e65
|
||||
required: false
|
||||
|
||||
8
dist/REUSE.toml
vendored
Normal file
8
dist/REUSE.toml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = ["*"]
|
||||
precedence = "override"
|
||||
comment = "Licensed as documentation."
|
||||
SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
|
||||
SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@ -10,6 +10,8 @@
|
||||
topics.
|
||||
|
||||
\image quickpublication.png
|
||||
{MQTT publishing interface with Hostname, Port, Topic, Message, QoS,
|
||||
and Retain fields}
|
||||
|
||||
\e {Qt Quick Publication} demonstrates how to register QMqttClient as a QML type and
|
||||
use it in a Qt Quick application.
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
topics.
|
||||
|
||||
\image quicksubscription.png
|
||||
{MQTT subscription interface with Hostname, Port, Topic fields, Connect
|
||||
and Subscribe buttons}
|
||||
|
||||
\e {Qt Quick Subscription} demonstrates how to register QMqttClient as a QML type and
|
||||
use it in a Qt Quick application.
|
||||
|
||||
@ -9,18 +9,61 @@
|
||||
\brief Creating a minimalistic telemetry application.
|
||||
|
||||
\image simpleclient.png
|
||||
{MQTT client with Host, Port, Protocol fields, WebSockets and Secure
|
||||
options, Topic and Message inputs, and log showing state changes}
|
||||
|
||||
\e {Simple MQTT Client} demonstrates how to create a minimalistic client
|
||||
application.
|
||||
|
||||
To use the application, you first specify a broker, such as
|
||||
\e test.mosquitto.org or \e broker.hivemq.com and the port number 1883, and
|
||||
connect to it. You can then subscribe to a topic and send a message, which
|
||||
you will also receive.
|
||||
To use the application, you first specify a Host, a Port, Secure on/off,
|
||||
WebSockets on/off, and Protocol. Then click on connect. Afterward you can
|
||||
subscribe to a topic and send a message, which you will also receive.
|
||||
You may also run the application twice. Publish in one and Subscribe in
|
||||
the other, and the messages shall be transmitted.
|
||||
|
||||
\note Port number 1883 is not encrypted, and therefore it is suitable only
|
||||
for development and testing purposes. In production, always use encrypted
|
||||
connections.
|
||||
\section1 simpleclient Options
|
||||
\list
|
||||
\li Host - you may use test.mosquitto.org or broker.hivemq.com
|
||||
\li Port - port to connect to, will depend on WebSockets selection and Secure selection
|
||||
\li WebSockets - you may specify: selected (enabled) or not selected (disabled)
|
||||
\li Secure - you may specify: selected (enabled) or not selected (disabled)
|
||||
\li Protocol - you may specify
|
||||
\list
|
||||
\li mqtt 3.1
|
||||
\li mqtt 3.1.1
|
||||
\li mqtt 5.0
|
||||
\endlist
|
||||
\li Topic - A topic to publish or subscribe to
|
||||
\li Message - A message to send on the topic if you are publishing
|
||||
\endlist
|
||||
|
||||
\section1 Connection Settings
|
||||
These are the usual combinations, and will work with test.mosquitto.org.
|
||||
For broker.hivemq.com check the information in the links. Note that if
|
||||
Secure is enabled it might be necessary to install certificates on the
|
||||
computer. It might also be necessary to add the certificate to the mqtt
|
||||
client in code.
|
||||
|
||||
\section1
|
||||
\list
|
||||
\li Port 1883, Secure=disabled, WebSockets=disabled - mqtt over tcp
|
||||
\li Port 8883, Secure=enabled, WebSockets=disabled - mqtt over ssl
|
||||
\li Port 8080, Secure=disabled, WebSockets=enabled - mqtt over websockets
|
||||
\li Port 8081, Secure=enabled, WebSockets=enabled - mqtt over secure websockets
|
||||
\endlist
|
||||
|
||||
For more information about the brokers see:
|
||||
\list
|
||||
\li \l {https://test.mosquitto.org}
|
||||
\li \l {https://broker.hivemq.com}
|
||||
\li \l {https://www.hivemq.com/mqtt/public-mqtt-broker}
|
||||
\endlist
|
||||
|
||||
\note Port numbers 1883 and 8080 are not encrypted, and therefore they are
|
||||
suitable only for development and testing purposes. In production, always
|
||||
use encrypted connections.
|
||||
|
||||
\note WebAssembly only supports WebSockets enabled.
|
||||
|
||||
\section1 Creating a Client
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
\brief Creating a application that communicates with an MQTT broker.
|
||||
|
||||
\image subscriptions.png
|
||||
{Main window with connection and publishing controls, and two
|
||||
subscription windows showing received messages on qtmqtt/topic1}
|
||||
|
||||
\e {MQTT Subscriptions} shows how to create an application that communicates
|
||||
with an MQTT broker. A new dialog opens for each subscription, where you can
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
QIODevice to combine a \l {Qt WebSockets}{web socket} connection with
|
||||
QMqttClient.
|
||||
|
||||
\note Since Qt 6.10, WebSockets are supported natively by Qt MQTT.
|
||||
This example is retained to demonstrate how to implement a custom transport.
|
||||
|
||||
\section1 Creating a Custom QIODevice
|
||||
|
||||
The new custom device, \c WebSocketIODevice, has to be a subclass of
|
||||
|
||||
@ -9,7 +9,6 @@ QmlMqttSubscription::QmlMqttSubscription(QMqttSubscription *s, QmlMqttClient *c)
|
||||
, client(c)
|
||||
{
|
||||
connect(sub, &QMqttSubscription::messageReceived, this, &QmlMqttSubscription::handleMessage);
|
||||
m_topic = sub->topic();
|
||||
}
|
||||
|
||||
QmlMqttSubscription::~QmlMqttSubscription()
|
||||
|
||||
@ -15,14 +15,12 @@ class QmlMqttClient;
|
||||
class QmlMqttSubscription : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QMqttTopicFilter topic MEMBER m_topic NOTIFY topicChanged)
|
||||
QML_UNCREATABLE("Not intended to be creatable")
|
||||
public:
|
||||
QmlMqttSubscription(QMqttSubscription *s, QmlMqttClient *c);
|
||||
~QmlMqttSubscription();
|
||||
|
||||
Q_SIGNALS:
|
||||
void topicChanged(QString);
|
||||
void messageReceived(const QString &msg);
|
||||
|
||||
public slots:
|
||||
@ -32,7 +30,6 @@ private:
|
||||
Q_DISABLE_COPY(QmlMqttSubscription)
|
||||
QMqttSubscription *sub;
|
||||
QmlMqttClient *client;
|
||||
QMqttTopicFilter m_topic;
|
||||
};
|
||||
|
||||
class QmlMqttClient : public QObject
|
||||
|
||||
@ -41,6 +41,9 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
connect(ui->lineEditHost, &QLineEdit::textChanged, m_client, &QMqttClient::setHostname);
|
||||
connect(ui->spinBoxPort, QOverload<int>::of(&QSpinBox::valueChanged), this, &MainWindow::setClientPort);
|
||||
connect(ui->checkBoxWebSockets, &QCheckBox::checkStateChanged, this, [this](int ws) { setWebSockets(ws != 0); });
|
||||
connect(ui->checkBoxSecure, &QCheckBox::checkStateChanged, this, [this](int s) { setSecure(s != 0); } );
|
||||
connect(ui->comboBoxProtocol, &QComboBox::currentIndexChanged, this, [this](int p) { setProtocol(static_cast<QMqttClient::ProtocolVersion>(p + 3)); });
|
||||
updateLogStateChange();
|
||||
}
|
||||
|
||||
@ -55,7 +58,27 @@ void MainWindow::on_buttonConnect_clicked()
|
||||
ui->lineEditHost->setEnabled(false);
|
||||
ui->spinBoxPort->setEnabled(false);
|
||||
ui->buttonConnect->setText(tr("Disconnect"));
|
||||
m_client->connectToHost();
|
||||
|
||||
m_client->setProtocolVersion(m_protocol);
|
||||
|
||||
if (m_secure && m_webSockets)
|
||||
m_client->connectToHostWebSocketEncrypted();
|
||||
#if !defined(QT_NO_SSL) && !defined(Q_OS_WASM)
|
||||
if (m_secure && !m_webSockets)
|
||||
m_client->connectToHostEncrypted({});
|
||||
#endif
|
||||
if (!m_secure && m_webSockets)
|
||||
m_client->connectToHostWebSocket();
|
||||
#if !defined(Q_OS_WASM)
|
||||
if (!m_secure && !m_webSockets)
|
||||
m_client->connectToHost();
|
||||
#endif
|
||||
if (m_client->state() == QMqttClient::Disconnected) {
|
||||
ui->lineEditHost->setEnabled(true);
|
||||
ui->spinBoxPort->setEnabled(true);
|
||||
ui->buttonConnect->setText(tr("Connect"));
|
||||
m_client->disconnectFromHost();
|
||||
}
|
||||
} else {
|
||||
ui->lineEditHost->setEnabled(true);
|
||||
ui->spinBoxPort->setEnabled(true);
|
||||
@ -90,6 +113,21 @@ void MainWindow::setClientPort(int p)
|
||||
m_client->setPort(static_cast<quint16>(p));
|
||||
}
|
||||
|
||||
void MainWindow::setSecure(bool s)
|
||||
{
|
||||
m_secure = s;
|
||||
}
|
||||
|
||||
void MainWindow::setWebSockets(bool ws)
|
||||
{
|
||||
m_webSockets = ws;
|
||||
}
|
||||
|
||||
void MainWindow::setProtocol(QMqttClient::ProtocolVersion p)
|
||||
{
|
||||
m_protocol = p;
|
||||
}
|
||||
|
||||
void MainWindow::on_buttonPublish_clicked()
|
||||
{
|
||||
if (m_client->publish(ui->lineEditTopic->text(), ui->lineEditMessage->text().toUtf8()) == -1)
|
||||
|
||||
@ -23,7 +23,9 @@ public:
|
||||
|
||||
public slots:
|
||||
void setClientPort(int p);
|
||||
|
||||
void setSecure(bool s);
|
||||
void setWebSockets(bool ws);
|
||||
void setProtocol(QMqttClient::ProtocolVersion p);
|
||||
private slots:
|
||||
void on_buttonConnect_clicked();
|
||||
void on_buttonQuit_clicked();
|
||||
@ -36,8 +38,11 @@ private slots:
|
||||
void on_buttonSubscribe_clicked();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
QMqttClient *m_client;
|
||||
Ui::MainWindow *ui = nullptr;
|
||||
QMqttClient *m_client = nullptr;
|
||||
bool m_secure = false;
|
||||
bool m_webSockets = false;
|
||||
QMqttClient::ProtocolVersion m_protocol = QMqttClient::ProtocolVersion::MQTT_3_1_1;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
@ -18,9 +18,9 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<widget class="QLabel" name="labelHost">
|
||||
<property name="text">
|
||||
<string>Host:</string>
|
||||
</property>
|
||||
@ -33,8 +33,15 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="3">
|
||||
<widget class="QPushButton" name="buttonConnect">
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="labelPort">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
@ -43,51 +50,69 @@
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxPort">
|
||||
<property name="maximum">
|
||||
<number>99999</number>
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1883</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="labelWebSockets">
|
||||
<property name="text">
|
||||
<string>WebSockets:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="checkBoxWebSockets" />
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="labelSecure">
|
||||
<property name="text">
|
||||
<string>Secure:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="checkBoxSecure" />
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="labelProtocol">
|
||||
<property name="text">
|
||||
<string>Protocol:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="comboBoxProtocol">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>mqtt 3.1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>mqtt 3.1.1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>mqtt 5.0</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonConnect">
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEditMessage">
|
||||
<layout class="QGridLayout" name="gridLayout2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelTopic">
|
||||
<property name="text">
|
||||
<string>This is a test message</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Message:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="buttonSubscribe">
|
||||
<property name="text">
|
||||
<string>Subscribe</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="buttonPublish">
|
||||
<property name="text">
|
||||
<string>Publish</string>
|
||||
<string>Topic:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -98,10 +123,31 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="buttonSubscribe">
|
||||
<property name="text">
|
||||
<string>Topic:</string>
|
||||
<string>Subscribe</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMessage">
|
||||
<property name="text">
|
||||
<string>Message:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEditMessage">
|
||||
<property name="text">
|
||||
<string>This is a test message</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="buttonPublish">
|
||||
<property name="text">
|
||||
<string>Publish</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -114,7 +160,11 @@
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="editLog"/>
|
||||
<widget class="QPlainTextEdit" name="editLog">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -145,37 +195,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1024</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionQuit"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="mainToolBar">
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<action name="actionQuit">
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
|
||||
121
licenseRule.json
121
licenseRule.json
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"comment" : ["file_pattern_ending: strings matched against the end of a file name.",
|
||||
"comment": ["file_pattern_ending: strings matched against the end of a file name.",
|
||||
"location keys: regular expression matched against the beginning of",
|
||||
"the file path (relative to the git submodule root).",
|
||||
"spdx: list of SPDX-License-Expression's allowed in the matching files.",
|
||||
@ -9,75 +9,100 @@
|
||||
"unless they are examples",
|
||||
"Files with other endings can also be build system files"
|
||||
],
|
||||
"file_pattern_ending" : ["CMakeLists.txt", ".cmake", ".pro", ".pri", ".prf",
|
||||
"configure", "configure.bat", "cmake.in", "plist.in", "CMakeLists.txt.in"],
|
||||
"location" : {
|
||||
"" : {
|
||||
"comment" : "Default",
|
||||
"file type" : "build system",
|
||||
"spdx" : ["BSD-3-Clause"]
|
||||
"file_pattern_ending": ["CMakeLists.txt", ".cmake", ".pro", ".pri", ".prf",
|
||||
"configure", "configure.bat", "cmake.in", "plist.in", "CMakeLists.txt.in",
|
||||
".cmake.conf", ".tag", "ci_config_linux.json", ".yaml"],
|
||||
"location": {
|
||||
"": {
|
||||
"comment": "Default",
|
||||
"file type": "build system",
|
||||
"spdx": ["BSD-3-Clause"]
|
||||
},
|
||||
"(.*)(examples/|snippets/)" : {
|
||||
"comment" : "Example takes precedence",
|
||||
"file type" : "examples and snippets",
|
||||
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
|
||||
"(.*)(examples/|snippets/)": {
|
||||
"comment": "Example takes precedence",
|
||||
"file type": "examples and snippets",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"comments" : ["Files with the following endings are Tool licensed,",
|
||||
"comments": ["Files with the following endings are infrastructure licensed"],
|
||||
"file_pattern_ending": [".gitattributes", ".gitignore", ".gitmodules", ".gitreview",
|
||||
"_clang-format", "licenseRule.json", "REUSE.toml"],
|
||||
"location":{
|
||||
"": {
|
||||
"comment": "Default",
|
||||
"file type": "infrastructure",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"comments": ["Files with the following endings are Tool licensed,",
|
||||
"unless they are examples.",
|
||||
"Files with other endings can also be tool files."],
|
||||
"file_pattern_ending" : [".sh", ".py", ".pl", ".bat", ".ps1"],
|
||||
"location" :{
|
||||
"" : {
|
||||
"comment" : "Default",
|
||||
"file type" : "tools and utils",
|
||||
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"]
|
||||
"file_pattern_ending": [".sh", ".py", ".pl", ".bat", ".ps1"],
|
||||
"location":{
|
||||
"": {
|
||||
"comment": "Default",
|
||||
"file type": "tools and utils",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"]
|
||||
},
|
||||
"(.*)(examples/|snippets/)" : {
|
||||
"comment" : "Example takes precedence",
|
||||
"file type" : "examples and snippets",
|
||||
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
|
||||
"(.*)(examples/|snippets/)": {
|
||||
"comment": "Example takes precedence",
|
||||
"file type": "examples and snippets",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment" : "Files with the following endings are Documentation licensed.",
|
||||
"file_pattern_ending" : [".qdoc", ".qdocinc" , ".qdocconf", ".txt", "README", "qt_attribution.json"],
|
||||
"location" :{
|
||||
"" : {
|
||||
"comment" : "",
|
||||
"file type" : "documentation",
|
||||
"spdx" : ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"]
|
||||
"comment": "Files with the following endings are documentation licensed.",
|
||||
"file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", ".css",
|
||||
"README.txt", "CONTRIBUTING.md",
|
||||
"qt_attribution.json"],
|
||||
"location":{
|
||||
"": {
|
||||
"comment": "",
|
||||
"file type": "documentation",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment" : ["All other files",
|
||||
"comment": ["All other files",
|
||||
"The licensing is defined only by the file location in the Qt module repository.",
|
||||
"NO <file_pattern_ending> key for this case!",
|
||||
"This needs to be the last entry of the file."],
|
||||
"location" : {
|
||||
"" : {
|
||||
"comment" : "Default",
|
||||
"file type" : "module and plugin",
|
||||
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
|
||||
"location": {
|
||||
"": {
|
||||
"comment": "Default",
|
||||
"file type": "module and plugin",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
|
||||
},
|
||||
"src/" : {
|
||||
"comment" : "Default",
|
||||
"file type" : "module and plugin",
|
||||
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
|
||||
"dist/": {
|
||||
"comment": "Default",
|
||||
"file type": "documentation",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"]
|
||||
},
|
||||
"tests/" : {
|
||||
"comment" : "Default",
|
||||
"file type" : "test",
|
||||
"spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
|
||||
"src/": {
|
||||
"comment": "Default",
|
||||
"file type": "module and plugin",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
|
||||
},
|
||||
"(.*)(examples/|snippets/)" : {
|
||||
"comment" : "Default",
|
||||
"file type" : "examples and snippets",
|
||||
"spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
|
||||
"tests/": {
|
||||
"comment": "Default",
|
||||
"file type": "test",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
|
||||
},
|
||||
"(.*)(examples/|snippets/)": {
|
||||
"comment": "Default",
|
||||
"file type": "examples and snippets",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
|
||||
},
|
||||
".*/doc/images": {
|
||||
"comment": "Default",
|
||||
"file type": "examples and snippets",
|
||||
"spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
set(QT_SBOM_DEFAULT_QT_LICENSE_ID_LIBRARIES "QT_COMMERCIAL_OR_GPL3")
|
||||
|
||||
add_subdirectory(mqtt)
|
||||
|
||||
@ -12,7 +12,7 @@ qt_internal_add_module(Mqtt
|
||||
qmqttconnection.cpp qmqttconnection_p.h
|
||||
qmqttconnectionproperties.cpp qmqttconnectionproperties.h qmqttconnectionproperties_p.h
|
||||
qmqttcontrolpacket.cpp qmqttcontrolpacket_p.h
|
||||
qmqttglobal.h
|
||||
qmqttglobal.h qmqttglobal_p.h
|
||||
qmqttmessage.cpp qmqttmessage.h qmqttmessage_p.h
|
||||
qmqttpublishproperties.cpp qmqttpublishproperties.h qmqttpublishproperties_p.h
|
||||
qmqttsubscription.cpp qmqttsubscription.h qmqttsubscription_p.h
|
||||
@ -27,8 +27,24 @@ qt_internal_add_module(Mqtt
|
||||
Qt::Network
|
||||
PRIVATE_MODULE_INTERFACE
|
||||
Qt::CorePrivate
|
||||
GENERATE_CPP_EXPORTS
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Mqtt
|
||||
CONDITION
|
||||
TARGET Qt::WebSockets
|
||||
DEFINES
|
||||
QT_MQTT_WITH_WEBSOCKETS
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::WebSockets
|
||||
SOURCES
|
||||
transportLayers/mqtt_websocket_io_base.cpp
|
||||
transportLayers/mqtt_websocket_io_base_p.h
|
||||
transportLayers/mqtt_websocket_io.cpp
|
||||
transportLayers/mqtt_websocket_io_p.h
|
||||
transportLayers/mqtt_secure_websocket_io.cpp
|
||||
transportLayers/mqtt_secure_websocket_io_p.h
|
||||
)
|
||||
|
||||
qt_internal_add_docs(Mqtt
|
||||
doc/qtmqtt.qdocconf
|
||||
)
|
||||
|
||||
@ -14,15 +14,20 @@ qhp.QtMqtt.virtualFolder = qtmqtt
|
||||
qhp.QtMqtt.indexTitle = Qt MQTT
|
||||
qhp.QtMqtt.indexRoot =
|
||||
|
||||
qhp.QtMqtt.subprojects = classes examples
|
||||
qhp.QtMqtt.subprojects = overview classes examples
|
||||
|
||||
qhp.QtMqtt.subprojects.overview.title = Overview
|
||||
qhp.QtMqtt.subprojects.overview.indexTitle = Qt MQTT Overview
|
||||
qhp.QtMqtt.subprojects.overview.selectors = group:none
|
||||
|
||||
qhp.QtMqtt.subprojects.classes.title = C++ Classes
|
||||
qhp.QtMqtt.subprojects.classes.indexTitle = Qt MQTT C++ Classes
|
||||
qhp.QtMqtt.subprojects.classes.selectors = class fake:headerfile
|
||||
qhp.QtMqtt.subprojects.classes.selectors = class namespace headerfile
|
||||
qhp.QtMqtt.subprojects.classes.sortPages = true
|
||||
|
||||
qhp.QtMqtt.subprojects.examples.title = Examples
|
||||
qhp.QtMqtt.subprojects.examples.indexTitle = Qt MQTT Examples
|
||||
qhp.QtMqtt.subprojects.examples.selectors = fake:example
|
||||
qhp.QtMqtt.subprojects.examples.selectors = example
|
||||
qhp.QtMqtt.subprojects.examples.sortPages = true
|
||||
|
||||
headerdirs += ..
|
||||
@ -40,3 +45,6 @@ manifestmeta.thumbnail.names += "QtMqtt/WebSockets MQTT Subscription*"
|
||||
|
||||
navigation.landingpage = "Qt MQTT"
|
||||
navigation.cppclassespage = "Qt MQTT C++ Classes"
|
||||
|
||||
# Allow zero warnings when testing documentation in CI
|
||||
warninglimit = 0
|
||||
|
||||
@ -59,5 +59,5 @@
|
||||
In addition, it is available under the
|
||||
\l{GNU General Public License, version 3}.
|
||||
|
||||
\generatelist{groupsbymodule attributions-qtmqtt}
|
||||
\annotatedlist attributions-qtmqtt
|
||||
*/
|
||||
|
||||
@ -21,7 +21,8 @@
|
||||
broker. The other clients can subscribe to notifications on particular
|
||||
topics sent by the client.
|
||||
|
||||
\image mqtt.png
|
||||
\image mqtt.png {Broker distributing messages from Client 1 to Client 2
|
||||
(Topic A) and Client 3 (Topics A and B)}
|
||||
|
||||
For example, if \e {Client 2} subscribes to messages on \e {Topic A}, it
|
||||
receives a notification when \e {Client 1} sends a message on that topic.
|
||||
@ -178,4 +179,18 @@
|
||||
discarded. The broker \e{should} store the last message, but \e{may}
|
||||
also discard it. This depends on the implementation of the broker.
|
||||
|
||||
\section1 Threading and Blocking Operations
|
||||
|
||||
Consider running \l QMqttClient and its related classes in a thread
|
||||
separate from the UI thread.\l QMqttClient uses a \l QIODevice as
|
||||
its transport, and some transport operations may block. For example,
|
||||
QMqttClient::disconnectFromHost() may wait synchronously for pending
|
||||
data to be written, with a timeout of up to 30 seconds. Calling it from
|
||||
the UI thread can therefore block the UI event loop and make the
|
||||
application unresponsive. Keeping the MQTT client and its transport in
|
||||
a dedicated thread helps prevent potentially blocking I/O from affecting
|
||||
UI responsiveness. Use signals and slots or other mechanisms that queue
|
||||
work to the target thread to communicate between the MQTT thread and
|
||||
the UI thread.
|
||||
|
||||
*/
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#include "qmqttauthenticationproperties.h"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTAUTHENTICATIONPROPERTIES_H
|
||||
#define QMQTTAUTHENTICATIONPROPERTIES_H
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:critical reason:network-protocol
|
||||
|
||||
#include "qmqttclient.h"
|
||||
#include "qmqttclient_p.h"
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
#include "transportLayers/mqtt_websocket_io_p.h"
|
||||
#include "transportLayers/mqtt_secure_websocket_io_p.h"
|
||||
#endif // QT_MQTT_WITH_WEBSOCKETS
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtCore/QtEndian>
|
||||
@ -151,6 +157,21 @@ Q_LOGGING_CATEGORY(lcMqttClient, "qt.mqtt.client")
|
||||
\sa keepAlive(), requestPing(), serverConnectionProperties(), pingResponseReceived()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\property QMqttClient::readBufferSize
|
||||
\since 6.13
|
||||
\brief This property holds the size of the internal read buffer.
|
||||
|
||||
The property limits the amount of data that the client can receive
|
||||
before you call read() or readAll().
|
||||
|
||||
A read buffer size of 0 (the default) means that the buffer has no size
|
||||
limit, ensuring that no data is lost.
|
||||
|
||||
\note The limit is not applicable for a plain \c TransportType::IODevice
|
||||
transport type.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QMqttClient::TransportType
|
||||
|
||||
@ -163,6 +184,12 @@ Q_LOGGING_CATEGORY(lcMqttClient, "qt.mqtt.client")
|
||||
The transport uses a class based on a QAbstractSocket.
|
||||
\value SecureSocket
|
||||
The transport uses a class based on a QSslSocket.
|
||||
\value [since 6.10] WebSocket
|
||||
The transport uses a class based on a QIODevice,
|
||||
which uses a QWebSocket internally.
|
||||
\value [since 6.10] SecureWebSocket
|
||||
The transport uses a class based on a QIODevice,
|
||||
which uses a secure QWebSocket internally.
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -312,6 +339,15 @@ Q_LOGGING_CATEGORY(lcMqttClient, "qt.mqtt.client")
|
||||
\sa authenticationRequested(), authenticate()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.13
|
||||
\fn QMqttClient::readBufferSizeChanged(qint64 size)
|
||||
|
||||
This signal is emitted when the \a size of internal read buffer is changed.
|
||||
|
||||
\sa readBufferSize()
|
||||
*/
|
||||
|
||||
/*!
|
||||
Creates a new MQTT client instance with the specified \a parent.
|
||||
*/
|
||||
@ -324,6 +360,7 @@ QMqttClient::QMqttClient(QObject *parent) : QObject(*(new QMqttClientPrivate(thi
|
||||
/*!
|
||||
Deletes a MQTT client. If the MQTT client was not already disconnected from the MQTT broker,
|
||||
it will be disconnected from automatically.
|
||||
\note If a transport is specified with setTransport it must be valid at this point
|
||||
*/
|
||||
QMqttClient::~QMqttClient()
|
||||
{
|
||||
@ -332,6 +369,7 @@ QMqttClient::~QMqttClient()
|
||||
d->m_connection.setClientDestruction();
|
||||
disconnectFromHost();
|
||||
}
|
||||
d->m_connection.disconnectAndResetTransport();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -342,7 +380,7 @@ QMqttClient::~QMqttClient()
|
||||
\l Disconnected state.
|
||||
|
||||
\note Setting a custom transport for a client does not pass over responsibility
|
||||
on connection management. The transport has to be opened for QIODevice based
|
||||
on connection management or ownership. The transport has to be opened for QIODevice based
|
||||
transports or connected for socket type transports before calling QMqttClient::connectToHost().
|
||||
*/
|
||||
void QMqttClient::setTransport(QIODevice *device, QMqttClient::TransportType transport)
|
||||
@ -354,6 +392,8 @@ void QMqttClient::setTransport(QIODevice *device, QMqttClient::TransportType tra
|
||||
return;
|
||||
}
|
||||
d->m_connection.setTransport(device, transport);
|
||||
// Set the currently active buffer size for a new transport.
|
||||
d->m_connection.setReadBufferSize(d->m_readBufferSize);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -365,6 +405,74 @@ QIODevice *QMqttClient::transport() const
|
||||
return d->m_connection.transport();
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.13
|
||||
|
||||
Limits the read buffer of the transport used by this client to
|
||||
\a size bytes. Triggers warning message if the limit could not
|
||||
be applied.
|
||||
|
||||
The transport does not buffer more than \a size bytes: it stops
|
||||
reading from the network until the client has taken the data out of
|
||||
the buffer. Use this function to protect the application against a
|
||||
broker that sends more data than the application can handle, which
|
||||
could make it run out of memory. A size of \c 0 means that the buffer
|
||||
has no size limit, which is the default of the underlying transport.
|
||||
|
||||
\code
|
||||
QMqttClient client;
|
||||
client.setHostname(QStringLiteral("broker.example.com"));
|
||||
client.setPort(1883);
|
||||
client.setReadBufferSize(64 * 1024);
|
||||
client.connectToHost();
|
||||
\endcode
|
||||
|
||||
The size can be set before connecting. It is applied to the transport
|
||||
when connectToHost() creates it, or when setTransport() sets it. The size
|
||||
has no effect if the transport is a plain \l QMqttClient::IODevice.
|
||||
|
||||
Before Qt 6.13, the \c QMqttClient class provided no way to limit the
|
||||
amount of incoming data. However, applications using older versions of
|
||||
\c QMqttClient with certain types of transport, such as transports derived
|
||||
from \c AbstractSocket, can protect themselves against memory exhaustion
|
||||
caused by a broker, as shown in the example below:
|
||||
\code
|
||||
QMqttClient client;
|
||||
client.setHostname(QStringLiteral("broker.example.com"));
|
||||
client.setPort(1883);
|
||||
QObject::connect(&client, &QMqttClient::connected, &client, [&client]() {
|
||||
QAbstractSocket *socket = dynamic_cast<QAbstractSocket *>(client.transport());
|
||||
if (socket)
|
||||
socket->setReadBufferSize(64 * 1024);
|
||||
});
|
||||
client.connectToHost();
|
||||
\endcode
|
||||
|
||||
\note If you use a custom QIODevice-based transport, implement
|
||||
support for a read buffer limit in the device and configure it
|
||||
before calling setTransport(). Some devices already support it.
|
||||
For example, \l QSerialPort provides QSerialPort::setReadBufferSize().
|
||||
|
||||
\note This limit and the MQTT 5 maximum packet size protect against
|
||||
different things. The maximum packet size limits the size of an
|
||||
individual packet, not the total size of a buffer.
|
||||
|
||||
\sa setTransport(), QMqttConnectionProperties::setMaximumPacketSize()
|
||||
*/
|
||||
void QMqttClient::setReadBufferSize(qint64 size)
|
||||
{
|
||||
Q_D(QMqttClient);
|
||||
|
||||
if (d->m_readBufferSize == size)
|
||||
return;
|
||||
|
||||
// Store the size even if there is no transport yet. setTransport() and
|
||||
// connectToHost() apply it to the transport they set or create.
|
||||
d->m_readBufferSize = size;
|
||||
d->m_connection.setReadBufferSize(size);
|
||||
emit readBufferSizeChanged(d->m_readBufferSize);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a new subscription to receive notifications on \a topic. The parameter
|
||||
\a qos specifies the level at which security messages are received. For more
|
||||
@ -512,6 +620,56 @@ quint16 QMqttClient::port() const
|
||||
return d->m_port;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.10
|
||||
|
||||
Set a web socket transport type and initiates a connection to the MQTT broker.
|
||||
Earlier transport type is replaced.
|
||||
If \a webSocket is given, hostname and port is ignored, and connection is done
|
||||
with that websocket. webSocket is owned by the calling code, and must be valid
|
||||
for the lifetime of the QMqttClient object.
|
||||
*/
|
||||
void QMqttClient::connectToHostWebSocket(QWebSocket *webSocket)
|
||||
{
|
||||
#ifndef QT_MQTT_WITH_WEBSOCKETS
|
||||
Q_UNUSED(webSocket);
|
||||
qWarning() << " Qt built without websocket support, connect skipped";
|
||||
#else
|
||||
Q_D(QMqttClient);
|
||||
|
||||
d->m_connection.connectTransport(
|
||||
TransportType::WebSocket,
|
||||
std::make_shared<QMqttWebSocketIO>(nullptr, webSocket));
|
||||
connectToHost();
|
||||
d->m_connection.m_transportIsSet = false;
|
||||
#endif // QT_MQTT_WITH_WEBSOCKETS
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.10
|
||||
|
||||
Set a secure websocket transport type and initiates a connection to the MQTT broker.
|
||||
Earlier transport type is replaced.
|
||||
If \a webSocket is given, hostname and port is ignored, and connection is done
|
||||
with that websocket. webSocket is owned by the calling code, and must be valid
|
||||
for the lifetime of the QMqttClient object.
|
||||
*/
|
||||
void QMqttClient::connectToHostWebSocketEncrypted(QWebSocket *webSocket)
|
||||
{
|
||||
#ifndef QT_MQTT_WITH_WEBSOCKETS
|
||||
Q_UNUSED(webSocket);
|
||||
qWarning() << " Qt built without websocket support, connect skipped";
|
||||
#else
|
||||
Q_D(QMqttClient);
|
||||
|
||||
d->m_connection.connectTransport(
|
||||
TransportType::SecureWebSocket,
|
||||
std::make_shared<QMqttSecureWebSocketIO>(nullptr, webSocket));
|
||||
connectToHost();
|
||||
d->m_connection.m_transportIsSet = false;
|
||||
#endif // QT_MQTT_WITH_WEBSOCKETS
|
||||
}
|
||||
|
||||
/*!
|
||||
Initiates a connection to the MQTT broker.
|
||||
*/
|
||||
@ -566,6 +724,11 @@ void QMqttClient::connectToHost(bool encrypted, const QString &sslPeerName)
|
||||
return;
|
||||
}
|
||||
|
||||
// We can safely set the active buffer size for the new transport here,
|
||||
// as the transport type has been determined by ensureTransport() or
|
||||
// connectToHostWebSocket()/connectToHostWebSocketEncrypted() at this point.
|
||||
d->m_connection.setReadBufferSize(d->m_readBufferSize);
|
||||
|
||||
// Once transport has connected, it will invoke
|
||||
// QMqttConnection::sendControlConnect to
|
||||
// handshake with the broker
|
||||
@ -573,6 +736,11 @@ void QMqttClient::connectToHost(bool encrypted, const QString &sslPeerName)
|
||||
|
||||
/*!
|
||||
Disconnects from the MQTT broker.
|
||||
|
||||
\note This function may block while waiting for pending data
|
||||
to be written to the transport.
|
||||
See \l {Threading and Blocking Operations} for recommended approaches
|
||||
on handling it.
|
||||
*/
|
||||
void QMqttClient::disconnectFromHost()
|
||||
{
|
||||
@ -646,6 +814,12 @@ bool QMqttClient::autoKeepAlive() const
|
||||
return d->m_autoKeepAlive;
|
||||
}
|
||||
|
||||
qint64 QMqttClient::readBufferSize() const
|
||||
{
|
||||
Q_D(const QMqttClient);
|
||||
return d->m_readBufferSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.12
|
||||
|
||||
@ -1019,10 +1193,7 @@ QMqttClientPrivate::QMqttClientPrivate(QMqttClient *c)
|
||||
: QObjectPrivate()
|
||||
{
|
||||
m_client = c;
|
||||
m_clientId = QUuid::createUuid().toString();
|
||||
m_clientId.remove(QLatin1Char('{'));
|
||||
m_clientId.remove(QLatin1Char('}'));
|
||||
m_clientId.remove(QLatin1Char('-'));
|
||||
m_clientId = QUuid::createUuid().toString(QUuid::Id128);
|
||||
m_clientId.resize(23);
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
// Some test servers require a username token
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QTMQTTCLIENT_H
|
||||
#define QTMQTTCLIENT_H
|
||||
@ -22,6 +23,7 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWebSocket;
|
||||
class QMqttClientPrivate;
|
||||
|
||||
class Q_MQTT_EXPORT QMqttClient : public QObject
|
||||
@ -30,13 +32,15 @@ public:
|
||||
enum TransportType {
|
||||
IODevice = 0,
|
||||
AbstractSocket,
|
||||
SecureSocket
|
||||
SecureSocket,
|
||||
WebSocket,
|
||||
SecureWebSocket,
|
||||
};
|
||||
|
||||
enum ClientState {
|
||||
Disconnected = 0,
|
||||
Connecting,
|
||||
Connected
|
||||
Connected,
|
||||
};
|
||||
Q_ENUM(ClientState)
|
||||
|
||||
@ -52,22 +56,19 @@ public:
|
||||
TransportInvalid = 256,
|
||||
ProtocolViolation,
|
||||
UnknownError,
|
||||
Mqtt5SpecificError
|
||||
Mqtt5SpecificError,
|
||||
};
|
||||
Q_ENUM(ClientError)
|
||||
|
||||
enum ProtocolVersion {
|
||||
MQTT_3_1 = 3,
|
||||
MQTT_3_1_1 = 4,
|
||||
MQTT_5_0 = 5
|
||||
MQTT_5_0 = 5,
|
||||
};
|
||||
Q_ENUM(ProtocolVersion)
|
||||
|
||||
private:
|
||||
Q_OBJECT
|
||||
Q_ENUMS(ClientState)
|
||||
Q_ENUMS(ClientError)
|
||||
Q_ENUMS(ProtocolVersion)
|
||||
Q_PROPERTY(QString clientId READ clientId WRITE setClientId NOTIFY clientIdChanged)
|
||||
Q_PROPERTY(QString hostname READ hostname WRITE setHostname NOTIFY hostnameChanged)
|
||||
Q_PROPERTY(quint16 port READ port WRITE setPort NOTIFY portChanged)
|
||||
@ -83,12 +84,15 @@ private:
|
||||
Q_PROPERTY(quint8 willQoS READ willQoS WRITE setWillQoS NOTIFY willQoSChanged)
|
||||
Q_PROPERTY(bool willRetain READ willRetain WRITE setWillRetain NOTIFY willRetainChanged)
|
||||
Q_PROPERTY(bool autoKeepAlive READ autoKeepAlive WRITE setAutoKeepAlive NOTIFY autoKeepAliveChanged)
|
||||
Q_PROPERTY(qint64 readBufferSize READ readBufferSize WRITE setReadBufferSize NOTIFY readBufferSizeChanged)
|
||||
|
||||
public:
|
||||
explicit QMqttClient(QObject *parent = nullptr);
|
||||
~QMqttClient() override;
|
||||
|
||||
void setTransport(QIODevice *device, TransportType transport);
|
||||
QIODevice *transport() const;
|
||||
void setReadBufferSize(qint64 size);
|
||||
|
||||
QMqttSubscription *subscribe(const QMqttTopicFilter &topic, quint8 qos = 0);
|
||||
QMqttSubscription *subscribe(const QMqttTopicFilter &topic,
|
||||
@ -115,6 +119,8 @@ public:
|
||||
#ifndef QT_NO_SSL
|
||||
void connectToHostEncrypted(const QSslConfiguration &conf);
|
||||
#endif
|
||||
Q_INVOKABLE void connectToHostWebSocket(QWebSocket *webSocket = nullptr);
|
||||
Q_INVOKABLE void connectToHostWebSocketEncrypted(QWebSocket *webSocket = nullptr);
|
||||
Q_INVOKABLE void disconnectFromHost();
|
||||
|
||||
ClientState state() const;
|
||||
@ -129,6 +135,7 @@ public:
|
||||
QByteArray willMessage() const;
|
||||
bool willRetain() const;
|
||||
bool autoKeepAlive() const;
|
||||
qint64 readBufferSize() const;
|
||||
|
||||
void setConnectionProperties(const QMqttConnectionProperties &prop);
|
||||
QMqttConnectionProperties connectionProperties() const;
|
||||
@ -164,6 +171,7 @@ Q_SIGNALS:
|
||||
void willMessageChanged(QByteArray willMessage);
|
||||
void willRetainChanged(bool willRetain);
|
||||
void autoKeepAliveChanged(bool autoKeepAlive);
|
||||
void readBufferSizeChanged(qint64 size);
|
||||
|
||||
void authenticationRequested(const QMqttAuthenticationProperties &p);
|
||||
void authenticationFinished(const QMqttAuthenticationProperties &p);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTCLIENT_P_H
|
||||
#define QMQTTCLIENT_P_H
|
||||
@ -15,6 +16,7 @@
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "qmqttglobal_p.h"
|
||||
#include "qmqttclient.h"
|
||||
#include "qmqttconnection_p.h"
|
||||
|
||||
@ -46,6 +48,7 @@ public:
|
||||
quint8 m_willQoS{0};
|
||||
bool m_willRetain{false};
|
||||
bool m_autoKeepAlive{true};
|
||||
qint64 m_readBufferSize{0};
|
||||
QString m_username;
|
||||
QString m_password;
|
||||
bool m_cleanSession{true};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTCONNECTION_P_H
|
||||
#define QMQTTCONNECTION_P_H
|
||||
@ -26,6 +27,9 @@
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QtEndian>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMqttClientPrivate;
|
||||
@ -45,7 +49,9 @@ public:
|
||||
explicit QMqttConnection(QObject *parent = nullptr);
|
||||
~QMqttConnection() override;
|
||||
|
||||
void disconnectAndResetTransport();
|
||||
void setTransport(QIODevice *device, QMqttClient::TransportType transport);
|
||||
void connectTransport(QMqttClient::TransportType transport, const std::shared_ptr<QIODevice> &device);
|
||||
QIODevice *transport() const;
|
||||
|
||||
bool ensureTransport(bool createSecureIfNeeded = false);
|
||||
@ -62,8 +68,8 @@ public:
|
||||
QMqttSubscription *sendControlSubscribe(const QMqttTopicFilter &topic, quint8 qos, const QMqttSubscriptionProperties &properties);
|
||||
bool sendControlUnsubscribe(const QMqttTopicFilter &topic, const QMqttUnsubscriptionProperties &properties);
|
||||
bool sendControlPingRequest(bool isAuto = true);
|
||||
bool sendControlDisconnect();
|
||||
|
||||
bool sendControlDisconnect(std::optional<QMqtt::ReasonCode> reasonCode = std::nullopt);
|
||||
void setReadBufferSize(qint64 size);
|
||||
void setClientPrivate(QMqttClientPrivate *clientPrivate);
|
||||
|
||||
inline quint16 unusedPacketIdentifier() const;
|
||||
@ -82,9 +88,10 @@ protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
public:
|
||||
QIODevice *m_transport{nullptr};
|
||||
std::shared_ptr<QIODevice> m_transport;
|
||||
QMqttClient::TransportType m_transportType{QMqttClient::IODevice};
|
||||
bool m_ownTransport{false};
|
||||
bool m_transportIsSet{false}; // connectTo* does not reset m_transport;
|
||||
bool m_connectedTransport{false}; // We have connected the signals for m_transport if true
|
||||
QMqttClientPrivate *m_clientPrivate{nullptr};
|
||||
#ifndef QT_NO_SSL
|
||||
QSslConfiguration m_sslConfiguration;
|
||||
@ -102,11 +109,11 @@ private:
|
||||
bool processDataHelper();
|
||||
bool readBuffer(char *data, quint64 size);
|
||||
qint32 readVariableByteInteger(qint64 *dataSize = nullptr);
|
||||
void readAuthProperties(QMqttAuthenticationProperties &properties);
|
||||
void readConnackProperties(QMqttServerConnectionProperties &properties);
|
||||
void readMessageStatusProperties(QMqttMessageStatusProperties &properties);
|
||||
void readPublishProperties(QMqttPublishProperties &properties);
|
||||
void readSubscriptionProperties(QMqttSubscription *sub);
|
||||
bool readAuthProperties(QMqttAuthenticationProperties &properties);
|
||||
bool readConnackProperties(QMqttServerConnectionProperties &properties);
|
||||
bool readMessageStatusProperties(QMqttMessageStatusProperties &properties);
|
||||
bool readPublishProperties(QMqttPublishProperties &properties);
|
||||
bool readSubscriptionProperties(QMqttSubscription *sub);
|
||||
QByteArray writeConnectProperties();
|
||||
QByteArray writeLastWillProperties() const;
|
||||
QByteArray writePublishProperties(const QMqttPublishProperties &properties);
|
||||
@ -114,8 +121,18 @@ private:
|
||||
QByteArray writeUnsubscriptionProperties(const QMqttUnsubscriptionProperties &properties);
|
||||
QByteArray writeAuthenticationProperties(const QMqttAuthenticationProperties &properties);
|
||||
void closeConnection(QMqttClient::ClientError error);
|
||||
void closeOnMalformedPacket();
|
||||
QByteArray readBuffer(quint64 size);
|
||||
template<typename T> T readBufferTyped(qint64 *dataSize = nullptr);
|
||||
template<typename T> std::optional<T> readBufferTyped(qint64 *dataSize = nullptr);
|
||||
bool isPendingUnsubscribe(QMqttSubscription *) const;
|
||||
QMqttSubscription *findActiveSubscription(const QMqttTopicFilter &topic) const;
|
||||
template <typename T>
|
||||
void setSocketBufferSize(qint64 size) {
|
||||
auto *socket = qobject_cast<T *>(m_transport.get());
|
||||
Q_ASSERT(socket);
|
||||
socket->setReadBufferSize(size);
|
||||
}
|
||||
|
||||
QByteArray m_readBuffer;
|
||||
int m_readPosition{0};
|
||||
qint64 m_missingData{0};
|
||||
@ -128,9 +145,13 @@ private:
|
||||
QMqttControlPacket::PacketType m_currentPacket{QMqttControlPacket::UNKNOWN};
|
||||
|
||||
bool writePacketToTransport(const QMqttControlPacket &p);
|
||||
|
||||
// I: There can be many occurences of different QMqttSubscription * with
|
||||
// the same QMqttTopicFilter, but only one that is not in
|
||||
// m_pendingUnsubscriptions.
|
||||
QHash<quint16, QMqttSubscription *> m_pendingSubscriptionAck;
|
||||
QHash<quint16, QMqttSubscription *> m_pendingUnsubscriptions;
|
||||
QHash<QMqttTopicFilter, QMqttSubscription *> m_activeSubscriptions;
|
||||
QMultiHash<QMqttTopicFilter, QMqttSubscription *> m_activeSubscriptions;
|
||||
QHash<quint16, QSharedPointer<QMqttControlPacket>> m_pendingMessages;
|
||||
QHash<quint16, QSharedPointer<QMqttControlPacket>> m_pendingReleaseMessages;
|
||||
InternalConnectionState m_internalState{BrokerDisconnected};
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#include "qmqttconnectionproperties.h"
|
||||
|
||||
#include "qmqttconnectionproperties_p.h"
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include <limits>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcMqttConnection)
|
||||
|
||||
/*!
|
||||
\class QMqttConnectionProperties
|
||||
|
||||
@ -307,6 +304,11 @@ void QMqttConnectionProperties::setMaximumReceive(quint16 maximumReceive)
|
||||
|
||||
If no maximum packet size is specified, no limit is imposed beyond the
|
||||
limitations of the protocol itself.
|
||||
|
||||
\note Since Qt 6.13, this limit can be applied to incoming packets
|
||||
when using MQTT 3.1 or MQTT 3.1.1. These protocol versions cannot announce
|
||||
the limit to the broker, but the client closes the connection with
|
||||
\l QMqttClient::ProtocolViolation when it receives a larger packet.
|
||||
*/
|
||||
void QMqttConnectionProperties::setMaximumPacketSize(quint32 packetSize)
|
||||
{
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTCONNECTIONPROPERTIES_H
|
||||
#define QMQTTCONNECTIONPROPERTIES_H
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTCONNECTIONPROPERTIES_P_H
|
||||
#define QMQTTCONNECTIONPROPERTIES_P_H
|
||||
@ -18,8 +19,12 @@
|
||||
#include "qmqttconnectionproperties.h"
|
||||
#include "private/qglobal_p.h"
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcMqttConnection)
|
||||
|
||||
class QMqttLastWillPropertiesData : public QSharedData
|
||||
{
|
||||
public:
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:critical reason:network-protocol
|
||||
|
||||
#include "qmqttcontrolpacket_p.h"
|
||||
|
||||
@ -8,8 +9,6 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcMqttClient)
|
||||
|
||||
QMqttControlPacket::QMqttControlPacket()
|
||||
{
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTCONTROLPACKET_P_H
|
||||
#define QMQTTCONTROLPACKET_P_H
|
||||
@ -14,7 +15,7 @@
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
#include "qmqttglobal.h"
|
||||
#include "qmqttglobal_p.h"
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QTQMQTTGLOBAL_H
|
||||
#define QTQMQTTGLOBAL_H
|
||||
|
||||
28
src/mqtt/qmqttglobal_p.h
Normal file
28
src/mqtt/qmqttglobal_p.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QTQMQTTGLOBAL_P_H
|
||||
#define QTQMQTTGLOBAL_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 <QtMqtt/qmqttglobal.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcMqttClient)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QTQMQTTGLOBAL_P_H
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#include "qmqttmessage.h"
|
||||
#include "qmqttmessage_p.h"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTMESSAGE_H
|
||||
#define QMQTTMESSAGE_H
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTMESSAGE_P_H
|
||||
#define QMQTTMESSAGE_P_H
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#include "qmqttpublishproperties.h"
|
||||
#include "qmqttpublishproperties_p.h"
|
||||
@ -9,8 +10,6 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcMqttClient)
|
||||
|
||||
/*!
|
||||
\class QMqttPublishProperties
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
#ifndef QMQTTPUBLISHPROPERTIES_H
|
||||
#define QMQTTPUBLISHPROPERTIES_H
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTPUBLISHPROPERTIES_P_H
|
||||
#define QMQTTPUBLISHPROPERTIES_P_H
|
||||
@ -15,7 +16,7 @@
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "qmqttglobal.h"
|
||||
#include "qmqttglobal_p.h"
|
||||
#include "qmqttpublishproperties.h"
|
||||
|
||||
#include <QtCore/QSharedData>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#include "qmqttsubscription.h"
|
||||
#include "qmqttsubscription_p.h"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTSUBSCRIPTION_H
|
||||
#define QMQTTSUBSCRIPTION_H
|
||||
@ -18,7 +19,6 @@ class QMqttSubscriptionPrivate;
|
||||
class Q_MQTT_EXPORT QMqttSubscription : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(SubscriptionState)
|
||||
Q_PROPERTY(SubscriptionState state READ state NOTIFY stateChanged)
|
||||
Q_PROPERTY(quint8 qos READ qos NOTIFY qosChanged)
|
||||
Q_PROPERTY(QMqttTopicFilter topic READ topic)
|
||||
@ -35,6 +35,7 @@ public:
|
||||
UnsubscriptionPending,
|
||||
Error
|
||||
};
|
||||
Q_ENUM(SubscriptionState)
|
||||
|
||||
SubscriptionState state() const;
|
||||
QMqttTopicFilter topic() const;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTSUBSCRIPTION_P_H
|
||||
#define QMQTTSUBSCRIPTION_P_H
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#include "qmqttsubscriptionproperties.h"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTSUBSCRIPTIONPROPERTIES_H
|
||||
#define QMQTTSUBSCRIPTIONPROPERTIES_H
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 Lorenz Haas
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:critical reason:data-parser
|
||||
|
||||
#include "qmqtttopicfilter.h"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 Lorenz Haas
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTTOPICFILTER_H
|
||||
#define QMQTTTOPICFILTER_H
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 Lorenz Haas
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:critical reason:data-parser
|
||||
|
||||
#include "qmqtttopicname.h"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2017 Lorenz Haas
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTTOPICNAME_H
|
||||
#define QMQTTTOPICNAME_H
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#include "qmqtttype.h"
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QMQTTTYPE_H
|
||||
#define QMQTTTYPE_H
|
||||
|
||||
45
src/mqtt/transportLayers/mqtt_secure_websocket_io.cpp
Normal file
45
src/mqtt/transportLayers/mqtt_secure_websocket_io.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
#include "mqtt_secure_websocket_io_p.h"
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
|
||||
QMqttSecureWebSocketIO::~QMqttSecureWebSocketIO()
|
||||
{
|
||||
disconnect(m_socket.get(), &QWebSocket::connected, this, &QMqttSecureWebSocketIO::doSocketEncrypted);
|
||||
}
|
||||
|
||||
QMqttSecureWebSocketIO::QMqttSecureWebSocketIO(QObject *parent, QWebSocket *webSocket)
|
||||
:
|
||||
QMqttWebSocketIOBase(parent, webSocket)
|
||||
{
|
||||
connect(m_socket.get(), &QWebSocket::connected, this, &QMqttSecureWebSocketIO::doSocketEncrypted);
|
||||
}
|
||||
|
||||
void QMqttSecureWebSocketIO::connectToHostEncrypted(const QString &hostname, quint16 port, QMqttClient::ProtocolVersion version)
|
||||
{
|
||||
setProtocol(version);
|
||||
if (!isExternalSocket()) {
|
||||
QUrl url(QString(u"wss://") + hostname + u":" + QString().setNum(port));
|
||||
QWebSocketHandshakeOptions options;
|
||||
options.setSubprotocols(QStringList{ QString::fromUtf8(m_protocol) });
|
||||
m_socket->open(url, options);
|
||||
}
|
||||
open(QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
void QMqttSecureWebSocketIO::close()
|
||||
{
|
||||
m_socket->close();
|
||||
QMqttWebSocketIOBase::close();
|
||||
}
|
||||
|
||||
void QMqttSecureWebSocketIO::doSocketEncrypted()
|
||||
{
|
||||
emit encrypted();
|
||||
}
|
||||
|
||||
#include "moc_mqtt_secure_websocket_io_p.cpp"
|
||||
|
||||
#endif /* QT_MQTT_WITH_WEBSOCKETS */
|
||||
53
src/mqtt/transportLayers/mqtt_secure_websocket_io_p.h
Normal file
53
src/mqtt/transportLayers/mqtt_secure_websocket_io_p.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QTMQTTCLIENT_SECURE_WEBSOCKET_IODEVICE_H
|
||||
#define QTMQTTCLIENT_SECURE_WEBSOCKET_IODEVICE_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.
|
||||
//
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
|
||||
#include <QtWebSockets/QWebSocketHandshakeOptions>
|
||||
#include <QtWebSockets/QWebSocket>
|
||||
#include <QtCore/QIODevice>
|
||||
#include "transportLayers/mqtt_websocket_io_base_p.h"
|
||||
#include "qmqttclient.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMqttSecureWebSocketIO : public QMqttWebSocketIOBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_DISABLE_COPY_MOVE(QMqttSecureWebSocketIO)
|
||||
|
||||
~QMqttSecureWebSocketIO() override;
|
||||
QMqttSecureWebSocketIO(QObject *parent = nullptr, QWebSocket *webSocket = nullptr);
|
||||
|
||||
void close() override;
|
||||
|
||||
void connectToHostEncrypted(const QString &hostname, quint16 port, QMqttClient::ProtocolVersion version);
|
||||
|
||||
Q_SIGNALS:
|
||||
void encrypted();
|
||||
|
||||
public slots:
|
||||
void doSocketEncrypted();
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif /* QT_MQTT_WITH_WEBSOCKETS */
|
||||
|
||||
#endif /* QTMQTTCLIENT_SECURE_WEBSOCKET_IODEVICE_H */
|
||||
45
src/mqtt/transportLayers/mqtt_websocket_io.cpp
Normal file
45
src/mqtt/transportLayers/mqtt_websocket_io.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
#include "mqtt_websocket_io_p.h"
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
|
||||
QMqttWebSocketIO::~QMqttWebSocketIO()
|
||||
{
|
||||
disconnect(m_socket.get(), &QWebSocket::connected, this, &QMqttWebSocketIO::doSocketConnected);
|
||||
}
|
||||
|
||||
QMqttWebSocketIO::QMqttWebSocketIO(QObject *parent, QWebSocket *webSocket)
|
||||
:
|
||||
QMqttWebSocketIOBase(parent, webSocket)
|
||||
{
|
||||
connect(m_socket.get(), &QWebSocket::connected, this, &QMqttWebSocketIO::doSocketConnected);
|
||||
}
|
||||
|
||||
void QMqttWebSocketIO::connectToHost(const QString &hostname, quint16 port, QMqttClient::ProtocolVersion version)
|
||||
{
|
||||
setProtocol(version);
|
||||
if (!isExternalSocket()) {
|
||||
QUrl url(QString(u"ws://") + hostname + u":" + QString().setNum(port));
|
||||
QWebSocketHandshakeOptions options;
|
||||
options.setSubprotocols(QStringList{ QString::fromUtf8(m_protocol) });
|
||||
m_socket->open(url, options);
|
||||
}
|
||||
open(QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
void QMqttWebSocketIO::close()
|
||||
{
|
||||
m_socket->close();
|
||||
QMqttWebSocketIOBase::close();
|
||||
}
|
||||
|
||||
void QMqttWebSocketIO::doSocketConnected()
|
||||
{
|
||||
emit connected();
|
||||
}
|
||||
|
||||
#include "moc_mqtt_websocket_io_p.cpp"
|
||||
|
||||
#endif /* QT_MQTT_WITH_WEBSOCKETS */
|
||||
103
src/mqtt/transportLayers/mqtt_websocket_io_base.cpp
Normal file
103
src/mqtt/transportLayers/mqtt_websocket_io_base.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
#include "mqtt_websocket_io_base_p.h"
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
|
||||
QMqttWebSocketIOBase::~QMqttWebSocketIOBase()
|
||||
{
|
||||
disconnect(m_socket.get(), &QWebSocket::disconnected, this, &QMqttWebSocketIOBase::doSocketDisconnected);
|
||||
disconnect(m_socket.get(), &QWebSocket::errorOccurred, this, &QMqttWebSocketIOBase::doSocketErrorOccured);
|
||||
disconnect(m_socket.get(), &QWebSocket::binaryMessageReceived, this, &QMqttWebSocketIOBase::doSocketHandleBinaryMessage);
|
||||
}
|
||||
|
||||
QMqttWebSocketIOBase::QMqttWebSocketIOBase(QObject *parent, QWebSocket *webSocket)
|
||||
:
|
||||
QIODevice(parent)
|
||||
{
|
||||
m_externalSocket = (webSocket != nullptr);
|
||||
|
||||
if (webSocket)
|
||||
m_socket = std::shared_ptr<QWebSocket>(webSocket, [](QWebSocket *) { ; }); // skip deleter
|
||||
else
|
||||
m_socket = std::make_shared<QWebSocket>();
|
||||
|
||||
connect(m_socket.get(), &QWebSocket::disconnected, this, &QMqttWebSocketIOBase::doSocketDisconnected);
|
||||
connect(m_socket.get(), &QWebSocket::errorOccurred, this, &QMqttWebSocketIOBase::doSocketErrorOccured);
|
||||
connect(m_socket.get(), &QWebSocket::binaryMessageReceived, this, &QMqttWebSocketIOBase::doSocketHandleBinaryMessage);
|
||||
|
||||
setProtocol(QMqttClient::ProtocolVersion::MQTT_3_1);
|
||||
}
|
||||
|
||||
bool QMqttWebSocketIOBase::open(QIODevice::OpenMode mode)
|
||||
{
|
||||
if (!QIODevice::open(mode))
|
||||
{
|
||||
close();
|
||||
emit errorOccurred(QAbstractSocket::SocketResourceError);
|
||||
}
|
||||
// Will emit onConnectionEstablished or onConnectionError
|
||||
return false;
|
||||
}
|
||||
|
||||
void QMqttWebSocketIOBase::close()
|
||||
{
|
||||
QIODevice::close();
|
||||
}
|
||||
|
||||
qint64 QMqttWebSocketIOBase::readData(char *data, qint64 maxlen)
|
||||
{
|
||||
qint64 bytesToRead = qMin(maxlen, (qint64)m_buffer.size());
|
||||
memcpy(data, m_buffer.constData(), bytesToRead);
|
||||
m_buffer = m_buffer.right(m_buffer.size() - bytesToRead);
|
||||
return bytesToRead;
|
||||
}
|
||||
|
||||
qint64 QMqttWebSocketIOBase::writeData(const char *data, qint64 len)
|
||||
{
|
||||
QByteArray msg(data, len);
|
||||
const int length = m_socket->sendBinaryMessage(msg);
|
||||
emit bytesWritten(length);
|
||||
return length;
|
||||
}
|
||||
|
||||
void QMqttWebSocketIOBase::setProtocol(QMqttClient::ProtocolVersion version)
|
||||
{
|
||||
switch (version) {
|
||||
case QMqttClient::ProtocolVersion::MQTT_3_1:
|
||||
setProtocol("mqttv3.1");
|
||||
break;
|
||||
case QMqttClient::ProtocolVersion::MQTT_3_1_1:
|
||||
setProtocol("mqtt");
|
||||
break;
|
||||
case QMqttClient::ProtocolVersion::MQTT_5_0:
|
||||
setProtocol("mqtt");
|
||||
break;
|
||||
} /* end-switch */
|
||||
}
|
||||
|
||||
void QMqttWebSocketIOBase::setProtocol(const QByteArray &data)
|
||||
{
|
||||
m_protocol = data;
|
||||
}
|
||||
|
||||
void QMqttWebSocketIOBase::doSocketHandleBinaryMessage(const QByteArray &msg)
|
||||
{
|
||||
m_buffer.append(msg);
|
||||
emit readyRead();
|
||||
}
|
||||
|
||||
void QMqttWebSocketIOBase::doSocketDisconnected()
|
||||
{
|
||||
emit disconnected();
|
||||
}
|
||||
|
||||
void QMqttWebSocketIOBase::doSocketErrorOccured(QAbstractSocket::SocketError error)
|
||||
{
|
||||
emit errorOccurred(error);
|
||||
}
|
||||
|
||||
#include "moc_mqtt_websocket_io_base_p.cpp"
|
||||
|
||||
#endif /* QT_MQTT_WITH_WEBSOCKETS */
|
||||
105
src/mqtt/transportLayers/mqtt_websocket_io_base_p.h
Normal file
105
src/mqtt/transportLayers/mqtt_websocket_io_base_p.h
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QTMQTTCLIENT_WEBSOCKET_IODEVICE_BASE_H
|
||||
#define QTMQTTCLIENT_WEBSOCKET_IODEVICE_BASE_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.
|
||||
//
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
|
||||
#include <QtWebSockets/QWebSocketHandshakeOptions>
|
||||
#include <QtWebSockets/QWebSocket>
|
||||
#include <QtCore/QIODevice>
|
||||
|
||||
#include "qmqttclient.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMqttWebSocketIOBase : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
QMqttWebSocketIOBase(QObject *parent = nullptr, QWebSocket *webSocket = nullptr);
|
||||
|
||||
public:
|
||||
Q_DISABLE_COPY_MOVE(QMqttWebSocketIOBase)
|
||||
|
||||
~QMqttWebSocketIOBase() override;
|
||||
|
||||
bool open(OpenMode mode) override;
|
||||
void close() override;
|
||||
|
||||
qint64 readData(char *data, qint64 maxlen) override;
|
||||
qint64 writeData(const char *data, qint64 len) override;
|
||||
|
||||
void setProtocol(QMqttClient::ProtocolVersion version);
|
||||
void setProtocol(const QByteArray &data);
|
||||
|
||||
bool isSequential() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
qint64 bytesAvailable() const override
|
||||
{
|
||||
return static_cast<qint64>(m_buffer.size()) + QIODevice::bytesAvailable();
|
||||
}
|
||||
|
||||
bool waitForBytesWritten(int msecs) override
|
||||
{
|
||||
Q_UNUSED(msecs);
|
||||
m_socket->flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isConnected() const
|
||||
{
|
||||
return (m_socket->state() == QAbstractSocket::ConnectedState);
|
||||
}
|
||||
|
||||
QAbstractSocket::SocketState state() const
|
||||
{
|
||||
return m_socket->state();
|
||||
}
|
||||
|
||||
bool isExternalSocket() const
|
||||
{
|
||||
return m_externalSocket;
|
||||
}
|
||||
|
||||
void setReadBufferSize(qint64 size)
|
||||
{
|
||||
m_socket->setReadBufferSize(size);
|
||||
}
|
||||
Q_SIGNALS:
|
||||
void disconnected();
|
||||
void errorOccurred(QAbstractSocket::SocketError error);
|
||||
|
||||
public slots:
|
||||
void doSocketHandleBinaryMessage(const QByteArray &msg);
|
||||
void doSocketDisconnected();
|
||||
void doSocketErrorOccured(QAbstractSocket::SocketError error);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<QWebSocket> m_socket;
|
||||
bool m_externalSocket = false;
|
||||
QByteArray m_protocol;
|
||||
QByteArray m_buffer;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif /* QT_MQTT_WITH_WEBSOCKETS */
|
||||
|
||||
#endif /* QTMQTTCLIENT_WEBSOCKET_IODEVICE_BASE_H */
|
||||
54
src/mqtt/transportLayers/mqtt_websocket_io_p.h
Normal file
54
src/mqtt/transportLayers/mqtt_websocket_io_p.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
// Qt-Security score:significant reason:default
|
||||
|
||||
#ifndef QTMQTTCLIENT_WEBSOCKET_IODEVICE_H
|
||||
#define QTMQTTCLIENT_WEBSOCKET_IODEVICE_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.
|
||||
//
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
|
||||
#include <QtWebSockets/QWebSocketHandshakeOptions>
|
||||
#include <QtWebSockets/QWebSocket>
|
||||
#include <QtCore/QIODevice>
|
||||
|
||||
#include "transportLayers/mqtt_websocket_io_base_p.h"
|
||||
#include "qmqttclient.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMqttWebSocketIO : public QMqttWebSocketIOBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_DISABLE_COPY_MOVE(QMqttWebSocketIO)
|
||||
|
||||
~QMqttWebSocketIO() override;
|
||||
QMqttWebSocketIO(QObject *parent = nullptr, QWebSocket *webSocket = nullptr);
|
||||
|
||||
void close() override;
|
||||
|
||||
void connectToHost(const QString &hostname, quint16 port, QMqttClient::ProtocolVersion version);
|
||||
|
||||
Q_SIGNALS:
|
||||
void connected();
|
||||
|
||||
public slots:
|
||||
void doSocketConnected();
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif /* QT_MQTT_WITH_WEBSOCKETS */
|
||||
|
||||
#endif /* QTMQTTCLIENT_WEBSOCKET_IODEVICE_H */
|
||||
@ -1,6 +1,122 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# Copyright (C) 2025 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# This function adds the test 12 times if run on a computer where the
|
||||
# mosquitto broker has been provisioned by running the corresponding
|
||||
# script located qt6/coin/provisioning/*/*mosquitto*
|
||||
#
|
||||
# The script adds the file /etc/mosquitto/conf.d/mqtt.conf on unix-like
|
||||
# systems, and the file C:\\Program Files\\mosquitto\\conf.d\\mqtt.conf
|
||||
# on windows like systems. So this is what we test for.
|
||||
#
|
||||
# If we are on a provisioned system as detected by the two files above
|
||||
# we define these variables which the test use
|
||||
# MQTT_TEST_TYPE= selection from; 3, 4, 5
|
||||
# 3 -> Vers 3.1
|
||||
# 4 -> Vers 3.1.1
|
||||
# 5 -> Vers 5.0
|
||||
# MQTT_TEST_PROTOCOL= selection from; Tcp,Ssl,Ws,Wss
|
||||
# MQTT_TEST_BROKER="localhost"
|
||||
#
|
||||
# If neither of these files are present, we use the existing
|
||||
# design which is to run for tcp,3.1.1 by default.
|
||||
# In this case set the environment variable MQTT_TEST_BROKER
|
||||
# to localhost
|
||||
#
|
||||
# Finally, we allow the test to override for individual test
|
||||
# cases, if wanted. This is mostly used for MQTT_TEST_TYPE
|
||||
#
|
||||
|
||||
function(qtmqtt_is_mosquitto_installed result)
|
||||
set(skip $ENV{COIN_NO_MOSQUITTO})
|
||||
if(skip)
|
||||
set(${result} FALSE PARENT_SCOPE)
|
||||
elseif(EXISTS "/etc/mosquitto/conf.d/mqtt.conf" OR
|
||||
EXISTS "C:\\Program Files\\mosquitto\\conf.d\\mqtt.conf")
|
||||
set(${result} ON PARENT_SCOPE)
|
||||
else()
|
||||
set(${result} FALSE PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(qtmqtt_add_test)
|
||||
|
||||
set(options)
|
||||
set(oneValueArgs TARGET)
|
||||
set(multiValueArgs SOURCES DEFINES INCLUDE_DIRECTORIES LIBRARIES)
|
||||
|
||||
cmake_parse_arguments(
|
||||
arg_mqtt
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
set(TYPES)
|
||||
set(PROTOCOLS)
|
||||
|
||||
qtmqtt_is_mosquitto_installed(is_installed)
|
||||
|
||||
if(${is_installed})
|
||||
if(WASM)
|
||||
if(TARGET Qt::WebSockets)
|
||||
set(TYPES Ws Wss)
|
||||
set(PROTOCOLS 3 4 5)
|
||||
endif()
|
||||
elseif(QT_FEATURE_ssl)
|
||||
if(TARGET Qt::WebSockets)
|
||||
set(TYPES Tcp Ssl Ws Wss)
|
||||
else()
|
||||
set(TYPES Tcp Ssl)
|
||||
endif()
|
||||
set(PROTOCOLS 3 4 5)
|
||||
else()
|
||||
if(TARGET Qt::WebSockets)
|
||||
set(TYPES Tcp Ws)
|
||||
else()
|
||||
set(TYPES Tcp)
|
||||
endif()
|
||||
set(PROTOCOLS 3 4 5)
|
||||
endif()
|
||||
elseif(NOT WASM)
|
||||
set(TYPES Tcp)
|
||||
set(PROTOCOLS 4)
|
||||
endif()
|
||||
|
||||
foreach(TYPE ${TYPES})
|
||||
foreach(PROTOCOL ${PROTOCOLS})
|
||||
set(EXTRA_DEFINES)
|
||||
set(EXTRA_LIBS)
|
||||
if(${is_installed})
|
||||
set(EXTRA_DEFINES MQTT_TEST_TYPE="${TYPE}" MQTT_TEST_PROTOCOL=${PROTOCOL} MQTT_TEST_BROKER="localhost")
|
||||
endif()
|
||||
|
||||
if(TARGET Qt::WebSockets)
|
||||
set(EXTRA_DEFINES ${EXTRA_DEFINES} QT_MQTT_WITH_WEBSOCKETS)
|
||||
set(EXTRA_LIBS Qt::WebSockets)
|
||||
endif()
|
||||
|
||||
qt_internal_add_test(
|
||||
${arg_mqtt_TARGET}_${TYPE}_${PROTOCOL}
|
||||
SOURCES
|
||||
${arg_mqtt_SOURCES}
|
||||
DEFINES
|
||||
${arg_mqtt_DEFINES} ${EXTRA_DEFINES}
|
||||
INCLUDE_DIRECTORIES
|
||||
${arg_mqtt_INCLUDE_DIRECTORIES}
|
||||
LIBRARIES
|
||||
${arg_mqtt_LIBRARIES} ${EXTRA_LIBS}
|
||||
TESTDATA
|
||||
"../../certificate/cert.crt"
|
||||
"../../certificate/cert.key"
|
||||
BUILTIN_TESTDATA
|
||||
)
|
||||
|
||||
endforeach()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
if(QT_BUILD_STANDALONE_TESTS)
|
||||
# Add qt_find_package calls for extra dependencies that need to be found when building
|
||||
# the standalone tests here.
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_conformance Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_conformance
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_conformance
|
||||
SOURCES
|
||||
../../common/broker_connection.h
|
||||
tst_conformance.cpp
|
||||
|
||||
@ -42,7 +42,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
QProcess m_brokerProcess;
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
quint16 m_port{0};
|
||||
};
|
||||
|
||||
Tst_MqttConformance::Tst_MqttConformance()
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqttclient Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqttclient
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqttclient
|
||||
SOURCES
|
||||
../../common/broker_connection.h
|
||||
tst_qmqttclient.cpp
|
||||
|
||||
@ -41,6 +41,11 @@ private Q_SLOTS:
|
||||
void reconnect_QTBUG65726();
|
||||
void openIODevice_QTBUG66955_data();
|
||||
void openIODevice_QTBUG66955();
|
||||
void subackLongRemainingLength();
|
||||
void pubackLongRemainingLength();
|
||||
void pubrelWithReasonCode();
|
||||
void shortRemainingLength_data();
|
||||
void shortRemainingLength();
|
||||
void staticProperties_QTBUG_67176_data();
|
||||
void staticProperties_QTBUG_67176();
|
||||
void authentication();
|
||||
@ -51,10 +56,11 @@ private Q_SLOTS:
|
||||
void subscriptionIdsOverlap();
|
||||
void keepAlive_data();
|
||||
void keepAlive();
|
||||
void reconnect();
|
||||
private:
|
||||
QProcess m_brokerProcess;
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
quint16 m_port{0};
|
||||
};
|
||||
|
||||
Tst_QMqttClient::Tst_QMqttClient()
|
||||
@ -173,7 +179,7 @@ void Tst_QMqttClient::sendReceive()
|
||||
bool verified = false;
|
||||
auto sub = subscriber.subscribe(testTopic, 1);
|
||||
QVERIFY(sub);
|
||||
connect(sub, &QMqttSubscription::messageReceived, [&](QMqttMessage msg) {
|
||||
connect(sub, &QMqttSubscription::messageReceived, sub, [&](QMqttMessage msg) {
|
||||
verified = msg.payload() == data;
|
||||
received = true;
|
||||
});
|
||||
@ -185,7 +191,7 @@ void Tst_QMqttClient::sendReceive()
|
||||
QSKIP("The MQTT 5 test broker does not support huge packages.", SkipOnce);
|
||||
publisher.publish(testTopic, data, 1);
|
||||
|
||||
QTRY_VERIFY2(received, "Subscriber did not receive message");
|
||||
QTRY_VERIFY2_WITH_TIMEOUT(received, "Subscriber did not receive message", std::chrono::seconds(180));
|
||||
QVERIFY2(verified, "Subscriber received different message");
|
||||
}
|
||||
|
||||
@ -226,7 +232,8 @@ void Tst_QMqttClient::retainMessage()
|
||||
sub.setClientId(QLatin1String("SubA"));
|
||||
sub.setHostname(m_testBroker);
|
||||
sub.setPort(m_port);
|
||||
connect(&sub, &QMqttClient::messageReceived, [&msgCount, testMessage](const QByteArray &msg) {
|
||||
connect(&sub, &QMqttClient::messageReceived, &sub,
|
||||
[&msgCount, testMessage](const QByteArray &msg) {
|
||||
if (msg == testMessage)
|
||||
msgCount++;
|
||||
});
|
||||
@ -270,8 +277,12 @@ void Tst_QMqttClient::willMessage()
|
||||
client1.connectToHost();
|
||||
QTRY_COMPARE(client1.state(), QMqttClient::Connected);
|
||||
|
||||
if (!client1.isTcp())
|
||||
QSKIP("This test is only for tcp");
|
||||
|
||||
auto client1Sub = client1.subscribe(willTopic, 1);
|
||||
connect(client1Sub, &QMqttSubscription::messageReceived, [=](QMqttMessage message) {
|
||||
connect(client1Sub, &QMqttSubscription::messageReceived,
|
||||
client1Sub, [=](QMqttMessage message) {
|
||||
Q_UNUSED(message);
|
||||
// Just debug purposes
|
||||
//qDebug() << "Got something:" << message;
|
||||
@ -282,7 +293,7 @@ void Tst_QMqttClient::willMessage()
|
||||
|
||||
// Client B connects (via TcpSocket)
|
||||
QTcpSocket sock;
|
||||
sock.connectToHost(m_testBroker, m_port);
|
||||
sock.connectToHost(client1.hostname(), client1.port());
|
||||
QVERIFY(sock.waitForConnected());
|
||||
|
||||
for (int i = 1; i > 0; --i) {
|
||||
@ -336,10 +347,12 @@ void Tst_QMqttClient::compliantTopic_data()
|
||||
void Tst_QMqttClient::compliantTopic()
|
||||
{
|
||||
QFETCH(QString, topic);
|
||||
QFETCH(QMqttClient::ProtocolVersion, mqttVersion);
|
||||
|
||||
QString truncTopic = topic;
|
||||
truncTopic.truncate(std::numeric_limits<std::uint16_t>::max());
|
||||
|
||||
QMqttClient publisher;
|
||||
VersionClient(mqttVersion, publisher);
|
||||
publisher.setClientId(QLatin1String("publisher"));
|
||||
publisher.setHostname(m_testBroker);
|
||||
publisher.setPort(m_port);
|
||||
@ -347,7 +360,7 @@ void Tst_QMqttClient::compliantTopic()
|
||||
publisher.connectToHost();
|
||||
QTRY_COMPARE(publisher.state(), QMqttClient::Connected);
|
||||
|
||||
QMqttClient subscriber;
|
||||
VersionClient(mqttVersion, subscriber);
|
||||
subscriber.setClientId(QLatin1String("subscriber"));
|
||||
subscriber.setHostname(m_testBroker);
|
||||
subscriber.setPort(m_port);
|
||||
@ -357,7 +370,8 @@ void Tst_QMqttClient::compliantTopic()
|
||||
|
||||
bool received = false;
|
||||
bool verified = false;
|
||||
connect(&subscriber, &QMqttClient::messageReceived, [&](const QByteArray &, const QMqttTopicName &t) {
|
||||
connect(&subscriber, &QMqttClient::messageReceived,
|
||||
&subscriber, [&](const QByteArray &, const QMqttTopicName &t) {
|
||||
received = true;
|
||||
verified = t == truncTopic;
|
||||
});
|
||||
@ -415,7 +429,8 @@ void Tst_QMqttClient::dataIncludingZero()
|
||||
const QString testTopic(QLatin1String("Qt/QMqttClient/some/topic"));
|
||||
auto sub = client.subscribe(testTopic, 1);
|
||||
QVERIFY(sub);
|
||||
connect(sub, &QMqttSubscription::messageReceived, [&](QMqttMessage msg) {
|
||||
connect(sub, &QMqttSubscription::messageReceived,
|
||||
sub, [&](QMqttMessage msg) {
|
||||
verified = msg.payload() == data;
|
||||
correctSize = msg.payload().size() == dataSize;
|
||||
received = true;
|
||||
@ -459,14 +474,25 @@ public:
|
||||
connect(server, &QTcpServer::newConnection, this, &FakeServer::createSocket);
|
||||
server->listen(QHostAddress::Any, 5726);
|
||||
}
|
||||
// Sends raw bytes to the client, so a test can drive the parser with an exact
|
||||
// byte sequence.
|
||||
void send(const QByteArray &data) { socket->write(data); }
|
||||
public slots:
|
||||
void createSocket() {
|
||||
socket = server->nextPendingConnection();
|
||||
connectionAcknowledged = false;
|
||||
lastRequest.clear();
|
||||
connect(socket, &QTcpSocket::readyRead, this, &FakeServer::connectionRequested);
|
||||
}
|
||||
|
||||
void connectionRequested() {
|
||||
// We assume it is always a connect statement, so no verification is done
|
||||
// We assume the first packet is always a connect statement, so no verification
|
||||
// is done. Everything after that is recorded for the test to answer itself.
|
||||
if (connectionAcknowledged) {
|
||||
lastRequest.append(socket->readAll());
|
||||
return;
|
||||
}
|
||||
connectionAcknowledged = true;
|
||||
socket->readAll();
|
||||
QByteArray response;
|
||||
response += 0x20;
|
||||
@ -490,6 +516,8 @@ public:
|
||||
QTcpSocket *socket;
|
||||
QMqttClient::ProtocolVersion version{QMqttClient::MQTT_3_1_1};
|
||||
bool connectionSuccess{false};
|
||||
bool connectionAcknowledged{false};
|
||||
QByteArray lastRequest;
|
||||
};
|
||||
|
||||
DefaultVersionTestData(Tst_QMqttClient::reconnect_QTBUG65726_data)
|
||||
@ -505,6 +533,9 @@ void Tst_QMqttClient::reconnect_QTBUG65726()
|
||||
client.setHostname(QLatin1String("localhost"));
|
||||
client.setPort(5726);
|
||||
|
||||
if (!client.isTcp())
|
||||
QSKIP("This test is only for tcp");
|
||||
|
||||
server.version = client.protocolVersion();
|
||||
|
||||
client.connectToHost();
|
||||
@ -557,6 +588,220 @@ void Tst_QMqttClient::openIODevice_QTBUG66955()
|
||||
QTRY_COMPARE(trans.written, 1);
|
||||
}
|
||||
|
||||
// A reason string property (0x1f) of the requested content length.
|
||||
static QByteArray reasonStringProperty(quint16 length)
|
||||
{
|
||||
QByteArray property;
|
||||
property.append(char(0x1f));
|
||||
property.append(char(length >> 8));
|
||||
property.append(char(length & 0xff));
|
||||
property.append(QByteArray(length, 'r'));
|
||||
return property;
|
||||
}
|
||||
|
||||
// The packet identifier of a packet the client wrote, skipping the packet type and
|
||||
// its variable byte remaining length.
|
||||
static quint16 packetIdentifier(const QByteArray &packet)
|
||||
{
|
||||
qsizetype pos = 1;
|
||||
while (pos < packet.size() && (packet.at(pos) & 128) != 0)
|
||||
++pos;
|
||||
Q_ASSERT(pos < packet.size() - 2);
|
||||
++pos;
|
||||
return quint16(quint8(packet.at(pos)) << 8 | quint8(packet.at(pos + 1)));
|
||||
}
|
||||
|
||||
static void appendPacketIdentifier(QByteArray *payload, quint16 id)
|
||||
{
|
||||
payload->append(char(id >> 8));
|
||||
payload->append(char(id & 0xff));
|
||||
}
|
||||
|
||||
// MQTT-2.2.3 (3.1.1) / MQTT-2.1.4 (5.0) The remaining length is a variable byte
|
||||
// integer, so a packet longer than 127 bytes carries a two byte length whose first
|
||||
// byte has the continuation bit set. Reading only that first byte consumes one byte
|
||||
// too few and leaves the rest of the payload to be parsed as the next packet's
|
||||
// fixed header.
|
||||
void Tst_QMqttClient::subackLongRemainingLength()
|
||||
{
|
||||
FakeServer server;
|
||||
server.version = QMqttClient::MQTT_5_0;
|
||||
server.connectionSuccess = true;
|
||||
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
if (!client.isTcp())
|
||||
QSKIP("This test is only for tcp");
|
||||
client.setHostname(QLatin1String("localhost"));
|
||||
client.setPort(5726);
|
||||
client.connectToHost();
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Connected);
|
||||
|
||||
auto sub = client.subscribe(QMqttTopicFilter(QLatin1String("a/b")), 1);
|
||||
QVERIFY(sub);
|
||||
QTRY_VERIFY(server.lastRequest.size() >= 4); // The SUBSCRIBE arrived
|
||||
|
||||
// SUBACK with a reason string, which pushes the remaining length past 127.
|
||||
QByteArray payload;
|
||||
appendPacketIdentifier(&payload, packetIdentifier(server.lastRequest));
|
||||
const QByteArray properties = reasonStringProperty(123);
|
||||
payload.append(char(properties.size())); // Property length, 126
|
||||
payload.append(properties);
|
||||
payload.append(char(0x01)); // Reason code: maximum QoS 1
|
||||
QCOMPARE(payload.size(), 130);
|
||||
|
||||
QByteArray packet;
|
||||
packet.append(char(0x90));
|
||||
packet.append(char(0x82)); // Remaining length 130, low seven bits plus continuation
|
||||
packet.append(char(0x01)); // Remaining length 130, remaining bits
|
||||
packet.append(payload);
|
||||
server.send(packet);
|
||||
|
||||
QTRY_COMPARE(sub->state(), QMqttSubscription::Subscribed);
|
||||
QCOMPARE(client.state(), QMqttClient::Connected);
|
||||
QCOMPARE(client.error(), QMqttClient::NoError);
|
||||
}
|
||||
|
||||
void Tst_QMqttClient::pubackLongRemainingLength()
|
||||
{
|
||||
FakeServer server;
|
||||
server.version = QMqttClient::MQTT_5_0;
|
||||
server.connectionSuccess = true;
|
||||
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
if (!client.isTcp())
|
||||
QSKIP("This test is only for tcp");
|
||||
client.setHostname(QLatin1String("localhost"));
|
||||
client.setPort(5726);
|
||||
client.connectToHost();
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Connected);
|
||||
|
||||
const qint32 id = client.publish(QMqttTopicName(QLatin1String("a/b")), QByteArray("x"), 1);
|
||||
QVERIFY(id > 0);
|
||||
QTRY_VERIFY(server.lastRequest.size() >= 4); // The PUBLISH arrived
|
||||
|
||||
QSignalSpy sentSpy(&client, &QMqttClient::messageSent);
|
||||
|
||||
// PUBACK with a reason string, which pushes the remaining length past 127.
|
||||
QByteArray payload;
|
||||
appendPacketIdentifier(&payload, quint16(id));
|
||||
payload.append(char(0x00)); // Reason code: Success
|
||||
const QByteArray properties = reasonStringProperty(123);
|
||||
payload.append(char(properties.size())); // Property length, 126
|
||||
payload.append(properties);
|
||||
QCOMPARE(payload.size(), 130);
|
||||
|
||||
QByteArray packet;
|
||||
packet.append(char(0x40));
|
||||
packet.append(char(0x82)); // Remaining length 130, low seven bits plus continuation
|
||||
packet.append(char(0x01)); // Remaining length 130, remaining bits
|
||||
packet.append(payload);
|
||||
server.send(packet);
|
||||
|
||||
QTRY_COMPARE(sentSpy.count(), 1);
|
||||
QCOMPARE(sentSpy.at(0).at(0).toInt(), id);
|
||||
QCOMPARE(client.state(), QMqttClient::Connected);
|
||||
QCOMPARE(client.error(), QMqttClient::NoError);
|
||||
}
|
||||
|
||||
// MQTT-3.6.2, MQTT-3.6.2.1 In MQTT 5.0 the PUBREL variable header holds a reason
|
||||
// code and properties in addition to the packet identifier. A remaining length of 2
|
||||
// only occurs when both are omitted, so a longer PUBREL must be accepted.
|
||||
void Tst_QMqttClient::pubrelWithReasonCode()
|
||||
{
|
||||
FakeServer server;
|
||||
server.version = QMqttClient::MQTT_5_0;
|
||||
server.connectionSuccess = true;
|
||||
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
if (!client.isTcp())
|
||||
QSKIP("This test is only for tcp");
|
||||
client.setHostname(QLatin1String("localhost"));
|
||||
client.setPort(5726);
|
||||
client.connectToHost();
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Connected);
|
||||
|
||||
QMqtt::MessageStatus status = QMqtt::MessageStatus::Unknown;
|
||||
QString reasonString;
|
||||
connect(&client, &QMqttClient::messageStatusChanged, &client,
|
||||
[&](qint32, QMqtt::MessageStatus s, const QMqttMessageStatusProperties &properties)
|
||||
{
|
||||
status = s;
|
||||
reasonString = properties.reason();
|
||||
});
|
||||
|
||||
// PUBLISH, QoS 2, topic "a/b", packet identifier 7, no properties, payload "x".
|
||||
// The client answers with a PUBREC, which puts it in the middle of the QoS 2
|
||||
// exchange and makes it expect a PUBREL.
|
||||
server.send(QByteArray::fromHex("34090003612f6200070078"));
|
||||
QTRY_VERIFY(server.lastRequest.size() >= 4); // The PUBREC arrived
|
||||
|
||||
// PUBREL, packet identifier 7, reason code Success, and a reason string. Remaining
|
||||
// length 12: 2 identifier + 1 reason code + 1 property length + 8 property bytes.
|
||||
server.send(QByteArray::fromHex("620c000700081f000568656c6c6f"));
|
||||
|
||||
QTRY_COMPARE(status, QMqtt::MessageStatus::Released);
|
||||
QCOMPARE(reasonString, QLatin1String("hello"));
|
||||
QCOMPARE(client.state(), QMqttClient::Connected);
|
||||
QCOMPARE(client.error(), QMqttClient::NoError);
|
||||
}
|
||||
|
||||
// The remaining length counts the bytes that follow the fixed header, so a packet
|
||||
// declaring less than the fields the specification requires is malformed. Accepting
|
||||
// one leaves the parser reading past the end of the packet: the reason code loops in
|
||||
// finalize_suback() and finalize_unsuback() read at least once regardless of what is
|
||||
// left, and finalize_pubAckRecRelComp() always reads a packet identifier. Each of
|
||||
// these packets must be rejected as a protocol violation instead.
|
||||
void Tst_QMqttClient::shortRemainingLength_data()
|
||||
{
|
||||
QTest::addColumn<QMqttClient::ProtocolVersion>("mqttVersion");
|
||||
QTest::addColumn<QByteArray>("packet");
|
||||
|
||||
// SUBACK, packet identifier 7, and nothing else. MQTT-3.9.3 requires at least one
|
||||
// reason code, so the shortest legal remaining length is 3.
|
||||
QTest::newRow("SUBACK 3.1.1, no reason code")
|
||||
<< QMqttClient::MQTT_3_1_1 << QByteArray::fromHex("90020007");
|
||||
// The same, plus an empty property block. MQTT-3.9.2.1 makes the property length
|
||||
// mandatory in MQTT 5.0, so the shortest legal remaining length is 4.
|
||||
QTest::newRow("SUBACK 5.0, no reason code")
|
||||
<< QMqttClient::MQTT_5_0 << QByteArray::fromHex("9003000700");
|
||||
// UNSUBACK, packet identifier 7, empty property block, no reason code. The
|
||||
// property length is mandatory (MQTT-3.11.2.1) and at least one reason code is
|
||||
// required (MQTT-3.11.3), so the shortest legal remaining length is 4.
|
||||
QTest::newRow("UNSUBACK 5.0, no reason code")
|
||||
<< QMqttClient::MQTT_5_0 << QByteArray::fromHex("b003000700");
|
||||
// PUBACK with half a packet identifier. The reason code and the property length may
|
||||
// both be omitted (MQTT-3.4.2.1), but the identifier may not, so the shortest legal
|
||||
// remaining length is 2.
|
||||
QTest::newRow("PUBACK 5.0, truncated packet identifier")
|
||||
<< QMqttClient::MQTT_5_0 << QByteArray::fromHex("400100");
|
||||
// The same for PUBREL, MQTT-3.6.2.1.
|
||||
QTest::newRow("PUBREL 5.0, truncated packet identifier")
|
||||
<< QMqttClient::MQTT_5_0 << QByteArray::fromHex("620100");
|
||||
}
|
||||
|
||||
void Tst_QMqttClient::shortRemainingLength()
|
||||
{
|
||||
QFETCH(QMqttClient::ProtocolVersion, mqttVersion);
|
||||
QFETCH(QByteArray, packet);
|
||||
|
||||
FakeServer server;
|
||||
server.version = mqttVersion;
|
||||
server.connectionSuccess = true;
|
||||
|
||||
VersionClient(mqttVersion, client);
|
||||
if (!client.isTcp())
|
||||
QSKIP("This test is only for tcp");
|
||||
client.setHostname(QLatin1String("localhost"));
|
||||
client.setPort(5726);
|
||||
client.connectToHost();
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Connected);
|
||||
|
||||
server.send(packet);
|
||||
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Disconnected);
|
||||
QCOMPARE(client.error(), QMqttClient::ProtocolViolation);
|
||||
}
|
||||
|
||||
DefaultVersionTestData(Tst_QMqttClient::staticProperties_QTBUG_67176_data)
|
||||
|
||||
void Tst_QMqttClient::staticProperties_QTBUG_67176()
|
||||
@ -567,6 +812,9 @@ void Tst_QMqttClient::staticProperties_QTBUG_67176()
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
auto clientVersion = client.protocolVersion();
|
||||
const QString hostname = client.hostname();
|
||||
const int port = client.port();
|
||||
const QString clientId = client.clientId();
|
||||
const quint16 keepAlive = client.keepAlive();
|
||||
const bool clean = client.cleanSession();
|
||||
@ -578,16 +826,16 @@ void Tst_QMqttClient::staticProperties_QTBUG_67176()
|
||||
QCOMPARE(client.clientId(), clientId);
|
||||
|
||||
client.setHostname(QLatin1String("some.domain.foo"));
|
||||
QCOMPARE(client.hostname(), m_testBroker);
|
||||
QCOMPARE(client.hostname(), hostname);
|
||||
|
||||
client.setPort(1234);
|
||||
QCOMPARE(client.port(), m_port);
|
||||
QCOMPARE(client.port(), port);
|
||||
|
||||
client.setKeepAlive(keepAlive + 10);
|
||||
QCOMPARE(client.keepAlive(), keepAlive);
|
||||
|
||||
client.setProtocolVersion(QMqttClient::MQTT_3_1);
|
||||
QCOMPARE(client.protocolVersion(), mqttVersion);
|
||||
QCOMPARE(client.protocolVersion(), clientVersion);
|
||||
|
||||
client.setUsername(QLatin1String("someUser"));
|
||||
QCOMPARE(client.username(), QLatin1String());
|
||||
@ -601,8 +849,7 @@ void Tst_QMqttClient::staticProperties_QTBUG_67176()
|
||||
|
||||
void Tst_QMqttClient::authentication()
|
||||
{
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
@ -610,12 +857,14 @@ void Tst_QMqttClient::authentication()
|
||||
connectionProperties.setAuthenticationMethod(QLatin1String("SCRAM-SHA-1"));
|
||||
client.setConnectionProperties(connectionProperties);
|
||||
|
||||
connect(&client, &QMqttClient::authenticationRequested, [](const QMqttAuthenticationProperties &prop)
|
||||
connect(&client, &QMqttClient::authenticationRequested, &client,
|
||||
[](const QMqttAuthenticationProperties &prop)
|
||||
{
|
||||
qDebug() << "Authentication requested:" << prop.authenticationMethod();
|
||||
});
|
||||
|
||||
connect(&client, &QMqttClient::authenticationFinished, [](const QMqttAuthenticationProperties &prop)
|
||||
connect(&client, &QMqttClient::authenticationFinished, &client,
|
||||
[](const QMqttAuthenticationProperties &prop)
|
||||
{
|
||||
qDebug() << "Authentication finished:" << prop.authenticationMethod();
|
||||
});
|
||||
@ -645,17 +894,18 @@ void Tst_QMqttClient::messageStatus()
|
||||
QFETCH(int, qos);
|
||||
QFETCH(QList<QMqtt::MessageStatus>, expectedStatus);
|
||||
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
client.connectToHost();
|
||||
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
|
||||
const QString topic = QLatin1String("Qt/client/statusCheck");
|
||||
|
||||
connect(&client, &QMqttClient::messageStatusChanged, [&expectedStatus](qint32,
|
||||
connect(&client, &QMqttClient::messageStatusChanged,
|
||||
&client, [&expectedStatus](qint32,
|
||||
QMqtt::MessageStatus s,
|
||||
const QMqttMessageStatusProperties &)
|
||||
{
|
||||
@ -684,16 +934,14 @@ void Tst_QMqttClient::messageStatusReceive()
|
||||
QFETCH(int, qos);
|
||||
QFETCH(QList<QMqtt::MessageStatus>, expectedStatus);
|
||||
|
||||
QMqttClient publisher;
|
||||
publisher.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, publisher);
|
||||
publisher.setHostname(m_testBroker);
|
||||
publisher.setPort(m_port);
|
||||
|
||||
publisher.connectToHost();
|
||||
QTRY_VERIFY2(publisher.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
|
||||
QMqttClient subscriber;
|
||||
subscriber.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, subscriber);
|
||||
subscriber.setHostname(m_testBroker);
|
||||
subscriber.setPort(m_port);
|
||||
|
||||
@ -706,9 +954,8 @@ void Tst_QMqttClient::messageStatusReceive()
|
||||
QTRY_VERIFY2(subscription->state() == QMqttSubscription::Subscribed, "Could not subscribe to topic");
|
||||
QVERIFY(subscription->qos() >= qos);
|
||||
|
||||
connect(&subscriber, &QMqttClient::messageStatusChanged, [&expectedStatus](qint32,
|
||||
QMqtt::MessageStatus s,
|
||||
const QMqttMessageStatusProperties &)
|
||||
connect(&subscriber, &QMqttClient::messageStatusChanged, &subscriber,
|
||||
[&expectedStatus](qint32, QMqtt::MessageStatus s, const QMqttMessageStatusProperties &)
|
||||
{
|
||||
QCOMPARE(s, expectedStatus.first());
|
||||
expectedStatus.takeFirst();
|
||||
@ -737,8 +984,7 @@ void Tst_QMqttClient::subscriptionIdsOverlap()
|
||||
|
||||
const QString topic = QLatin1String("Qt/client/idcheck");
|
||||
// Connect publisher
|
||||
QMqttClient pub;
|
||||
pub.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, pub);
|
||||
pub.setHostname(m_testBroker);
|
||||
pub.setPort(m_port);
|
||||
|
||||
@ -746,8 +992,7 @@ void Tst_QMqttClient::subscriptionIdsOverlap()
|
||||
QTRY_VERIFY2(pub.state() == QMqttClient::Connected, "Could not connect publisher.");
|
||||
|
||||
// Connect subA
|
||||
QMqttClient subClientA;
|
||||
subClientA.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, subClientA);
|
||||
subClientA.setHostname(m_testBroker);
|
||||
subClientA.setPort(m_port);
|
||||
|
||||
@ -760,7 +1005,8 @@ void Tst_QMqttClient::subscriptionIdsOverlap()
|
||||
QTRY_VERIFY2(subA->state() == QMqttSubscription::Subscribed, "Could not subscibe A.");
|
||||
|
||||
int receiveACounter = 0;
|
||||
connect(subA, &QMqttSubscription::messageReceived, [&receiveACounter](QMqttMessage msg) {
|
||||
connect(subA, &QMqttSubscription::messageReceived, subA,
|
||||
[&receiveACounter](QMqttMessage msg) {
|
||||
qDebug() << "Sub A received:" << msg.publishProperties().subscriptionIdentifiers();
|
||||
// ### TODO: Wait for fix at https://github.com/eclipse/paho.mqtt.testing/issues/56
|
||||
//QVERIFY(msg.publishProperties().subscriptionIdentifiers().size() == 1);
|
||||
@ -769,8 +1015,7 @@ void Tst_QMqttClient::subscriptionIdsOverlap()
|
||||
});
|
||||
|
||||
// Connect subB
|
||||
QMqttClient subClientB;
|
||||
subClientB.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, subClientB);
|
||||
subClientB.setHostname(m_testBroker);
|
||||
subClientB.setPort(m_port);
|
||||
|
||||
@ -783,7 +1028,8 @@ void Tst_QMqttClient::subscriptionIdsOverlap()
|
||||
QTRY_VERIFY2(subB->state() == QMqttSubscription::Subscribed, "Could not subscibe A.");
|
||||
|
||||
int receiveBCounter = 2;
|
||||
connect(subB, &QMqttSubscription::messageReceived, [&receiveBCounter](QMqttMessage msg) {
|
||||
connect(subB, &QMqttSubscription::messageReceived,
|
||||
subB, [&receiveBCounter](QMqttMessage msg) {
|
||||
qDebug() << "Sub B received:" << msg.publishProperties().subscriptionIdentifiers();
|
||||
QVERIFY(msg.publishProperties().subscriptionIdentifiers().size() > 0);
|
||||
receiveBCounter -= msg.publishProperties().subscriptionIdentifiers().size();
|
||||
@ -795,7 +1041,8 @@ void Tst_QMqttClient::subscriptionIdsOverlap()
|
||||
QTRY_VERIFY2(subB2->state() == QMqttSubscription::Subscribed, "Could not subscibe A.");
|
||||
|
||||
int receiveB2Counter = 2;
|
||||
connect(subB2, &QMqttSubscription::messageReceived, [&receiveB2Counter](QMqttMessage msg) {
|
||||
connect(subB2, &QMqttSubscription::messageReceived,
|
||||
subB2, [&receiveB2Counter](QMqttMessage msg) {
|
||||
qDebug() << "Sub B2 received:" << msg.publishProperties().subscriptionIdentifiers();
|
||||
QVERIFY(msg.publishProperties().subscriptionIdentifiers().size() > 0);
|
||||
receiveB2Counter -= msg.publishProperties().subscriptionIdentifiers().size();
|
||||
@ -869,11 +1116,11 @@ void Tst_QMqttClient::keepAlive()
|
||||
QTimer t;
|
||||
t.setInterval(keepAlive * 1000);
|
||||
t.setSingleShot(false);
|
||||
t.connect(&t, &QTimer::timeout, [&client]() {
|
||||
t.connect(&t, &QTimer::timeout, &client, [&client]() {
|
||||
client.requestPing();
|
||||
});
|
||||
|
||||
connect(&client, &QMqttClient::connected, [&t]() {
|
||||
connect(&client, &QMqttClient::connected, &t, [&t]() {
|
||||
t.start();
|
||||
});
|
||||
|
||||
@ -886,6 +1133,76 @@ void Tst_QMqttClient::keepAlive()
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Disconnected);
|
||||
}
|
||||
|
||||
void Tst_QMqttClient::reconnect()
|
||||
{
|
||||
VersionClient(QMqttClient::ProtocolVersion(0), client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
client.connectToHost();
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Connected);
|
||||
|
||||
client.disconnectFromHost();
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Disconnected);
|
||||
|
||||
/* The rest requires a mosquitto installation that runs
|
||||
on multiple ports.
|
||||
*/
|
||||
#if defined(MQTT_TEST_BROKER)
|
||||
client.setPort(client.port() + 1000);
|
||||
client.connectToHost();
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Connected);
|
||||
|
||||
client.disconnectFromHost();
|
||||
QTRY_COMPARE(client.state(), QMqttClient::Disconnected);
|
||||
|
||||
QMqttClient client2;
|
||||
client2.setHostname(client.hostname());
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
#if defined(QT_MQTT_WITH_WEBSOCKETS)
|
||||
client2.setPort(9080);
|
||||
client2.connectToHostWebSocket();
|
||||
QTRY_COMPARE(client2.state(), QMqttClient::Connected);
|
||||
|
||||
client2.disconnectFromHost();
|
||||
QTRY_COMPARE(client2.state(), QMqttClient::Disconnected);
|
||||
#endif
|
||||
|
||||
#if defined(QT_MQTT_WITH_WEBSOCKETS) && !defined(QT_NO_SSL)
|
||||
client2.setPort(9081);
|
||||
QUrl url(QString(u"wss://") + client2.hostname() + QString(u":") + QString::number(client2.port()));
|
||||
QWebSocketHandshakeOptions options;
|
||||
options.setSubprotocols(QStringList{ QString::fromUtf8("mqttv3.1") });
|
||||
QWebSocket socket;
|
||||
socket.setSslConfiguration(makeConfig(QString::fromUtf8(getenv("MQTT_TEST_BROKER_CERTIFICATE"))));
|
||||
socket.open(url, options);
|
||||
|
||||
client2.connectToHostWebSocketEncrypted(&socket);
|
||||
QTRY_COMPARE(client2.state(), QMqttClient::Connected);
|
||||
|
||||
client2.disconnectFromHost();
|
||||
QTRY_COMPARE(client2.state(), QMqttClient::Disconnected);
|
||||
#endif
|
||||
|
||||
#if !defined(QT_NO_SSL)
|
||||
client2.setPort(9883);
|
||||
client2.connectToHostEncrypted(makeConfig(QString::fromUtf8(getenv("MQTT_TEST_BROKER_CERTIFICATE"))));
|
||||
QTRY_COMPARE(client2.state(), QMqttClient::Connected);
|
||||
|
||||
client2.disconnectFromHost();
|
||||
QTRY_COMPARE(client2.state(), QMqttClient::Disconnected);
|
||||
#endif
|
||||
|
||||
client2.setPort(2883);
|
||||
client2.connectToHost();
|
||||
QTRY_COMPARE(client2.state(), QMqttClient::Connected);
|
||||
|
||||
client2.disconnectFromHost();
|
||||
QTRY_COMPARE(client2.state(), QMqttClient::Disconnected);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QTEST_MAIN(Tst_QMqttClient)
|
||||
|
||||
#include "tst_qmqttclient.moc"
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqttconnectionproperties Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqttconnectionproperties
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqttconnectionproperties
|
||||
SOURCES
|
||||
../../common/broker_connection.h
|
||||
tst_qmqttconnectionproperties.cpp
|
||||
|
||||
@ -31,7 +31,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
QProcess m_brokerProcess;
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
quint16 m_port{0};
|
||||
};
|
||||
|
||||
tst_QMqttConnectionProperties::tst_QMqttConnectionProperties()
|
||||
@ -100,8 +100,7 @@ void tst_QMqttConnectionProperties::getSet()
|
||||
|
||||
void tst_QMqttConnectionProperties::receiveServerProperties()
|
||||
{
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
QMqttServerConnectionProperties server = client.serverConnectionProperties();
|
||||
|
||||
QCOMPARE(server.isValid(), false);
|
||||
@ -156,8 +155,7 @@ void tst_QMqttConnectionProperties::receiveServerProperties()
|
||||
|
||||
void tst_QMqttConnectionProperties::maximumPacketSize()
|
||||
{
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
@ -205,8 +203,7 @@ void tst_QMqttConnectionProperties::maximumPacketSize()
|
||||
void tst_QMqttConnectionProperties::maximumTopicAlias()
|
||||
{
|
||||
const QByteArray msgContent("SomeContent");
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
@ -242,7 +239,7 @@ void tst_QMqttConnectionProperties::maximumTopicAlias()
|
||||
client.publish(topic, msgContent, 1);
|
||||
QTRY_VERIFY(publishSpy.size() == 1);
|
||||
|
||||
QVERIFY(transportSpy.size() == 1);
|
||||
QTRY_VERIFY(transportSpy.size() == 1);
|
||||
const int dataSize = transportSpy.at(0).at(0).toInt();
|
||||
if (publishTransportSize == 0) {
|
||||
publishTransportSize = dataSize;
|
||||
@ -291,7 +288,8 @@ void tst_QMqttConnectionProperties::maximumTopicAlias()
|
||||
QVERIFY(usageSize < overwriteSize);
|
||||
}
|
||||
|
||||
void createTopicAliasClient(QMqttClient &client, const QString &hostname, quint16 port)
|
||||
template<typename Client>
|
||||
void createTopicAliasClient(Client &client, const QString &hostname, quint16 port)
|
||||
{
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
client.setHostname(hostname);
|
||||
@ -308,13 +306,13 @@ void tst_QMqttConnectionProperties::maximumTopicAliasReceive()
|
||||
const QByteArray msgContent("SomeContent");
|
||||
const QString topic("Qt/connprop/receive/alias");
|
||||
|
||||
QMqttClient client;
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
createTopicAliasClient(client, m_testBroker, m_port);
|
||||
|
||||
client.connectToHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
|
||||
QMqttClient subscriber;
|
||||
VersionClient(QMqttClient::MQTT_5_0, subscriber);
|
||||
createTopicAliasClient(subscriber, m_testBroker, m_port);
|
||||
|
||||
subscriber.connectToHost();
|
||||
@ -344,8 +342,7 @@ void tst_QMqttConnectionProperties::maximumTopicAliasReceive()
|
||||
|
||||
void tst_QMqttConnectionProperties::assignedClientId()
|
||||
{
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
client.setClientId(QLatin1String(""));
|
||||
@ -361,8 +358,7 @@ void tst_QMqttConnectionProperties::assignedClientId()
|
||||
|
||||
void tst_QMqttConnectionProperties::userProperties()
|
||||
{
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
QMqttConnectionProperties p;
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqttcontrolpacket Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqttcontrolpacket
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqttcontrolpacket
|
||||
SOURCES
|
||||
tst_qmqttcontrolpacket.cpp
|
||||
DEFINES
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqttlastwillproperties Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqttlastwillproperties
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqttlastwillproperties
|
||||
SOURCES
|
||||
../../common/broker_connection.h
|
||||
tst_qmqttlastwillproperties.cpp
|
||||
|
||||
@ -27,7 +27,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
QProcess m_brokerProcess;
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
quint16 m_port{0};
|
||||
};
|
||||
|
||||
tst_QMqttLastWillProperties::tst_QMqttLastWillProperties()
|
||||
@ -87,8 +87,7 @@ void tst_QMqttLastWillProperties::getSet()
|
||||
|
||||
void tst_QMqttLastWillProperties::payloadFormat()
|
||||
{
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
@ -119,8 +118,7 @@ void tst_QMqttLastWillProperties::willDelay()
|
||||
QFETCH(int, delay);
|
||||
QFETCH(int, expiry);
|
||||
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
@ -145,8 +143,7 @@ void tst_QMqttLastWillProperties::willDelay()
|
||||
client.connectToHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker");
|
||||
|
||||
QMqttClient recipient;
|
||||
recipient.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, recipient);
|
||||
recipient.setHostname(m_testBroker);
|
||||
recipient.setPort(m_port);
|
||||
recipient.connectToHost();
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqttpublishproperties Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqttpublishproperties
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqttpublishproperties
|
||||
SOURCES
|
||||
../../common/broker_connection.h
|
||||
tst_qmqttpublishproperties.cpp
|
||||
|
||||
@ -26,7 +26,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
QProcess m_brokerProcess;
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
quint16 m_port{0};
|
||||
};
|
||||
|
||||
tst_QMqttPublishProperties::tst_QMqttPublishProperties()
|
||||
@ -112,17 +112,14 @@ void tst_QMqttPublishProperties::getSet()
|
||||
|
||||
void tst_QMqttPublishProperties::propertyConsistency()
|
||||
{
|
||||
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
client.connectToHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
|
||||
QMqttClient client2;
|
||||
client2.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client2);
|
||||
client2.setHostname(m_testBroker);
|
||||
client2.setPort(m_port);
|
||||
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqttsubscription Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqttsubscription
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqttsubscription
|
||||
SOURCES
|
||||
../../common/broker_connection.h
|
||||
tst_qmqttsubscription.cpp
|
||||
|
||||
@ -31,11 +31,15 @@ private Q_SLOTS:
|
||||
void noLocal();
|
||||
void qtbug_106203();
|
||||
void qtbug_104478();
|
||||
void qtbug_135653_connected();
|
||||
void qtbug_135653_not_connected();
|
||||
void qtbug_135653_not_unsubscribed();
|
||||
private:
|
||||
void createAndSubscribe(QMqttClient *c, QMqttSubscription **sub, const QString &topic);
|
||||
template<typename Client>
|
||||
void createAndSubscribe(Client *c, QMqttSubscription **sub, const QString &topic);
|
||||
QProcess m_brokerProcess;
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
quint16 m_port{0};
|
||||
};
|
||||
|
||||
Tst_QMqttSubscription::Tst_QMqttSubscription()
|
||||
@ -148,6 +152,9 @@ void Tst_QMqttSubscription::reconnect()
|
||||
client.connectToHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
|
||||
if (!client.isTcp() && !client.isSsl())
|
||||
QSKIP("This test only runs for tcp and ssl");
|
||||
|
||||
// - Subscribe to topic A
|
||||
const QString subscription("Qt/subscription/topics/resub");
|
||||
auto sub = client.subscribe(subscription, 1);
|
||||
@ -211,7 +218,8 @@ void Tst_QMqttSubscription::reconnect()
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Disconnected, "Could not disconnect.");
|
||||
}
|
||||
|
||||
void Tst_QMqttSubscription::createAndSubscribe(QMqttClient *c, QMqttSubscription **sub, const QString &topic)
|
||||
template<typename Client>
|
||||
void Tst_QMqttSubscription::createAndSubscribe(Client *c, QMqttSubscription **sub, const QString &topic)
|
||||
{
|
||||
c->setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
c->setHostname(m_testBroker);
|
||||
@ -227,8 +235,7 @@ void Tst_QMqttSubscription::createAndSubscribe(QMqttClient *c, QMqttSubscription
|
||||
void Tst_QMqttSubscription::sharedConnection()
|
||||
{
|
||||
// Create / Connect publisher
|
||||
QMqttClient sender;
|
||||
sender.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, sender);
|
||||
sender.setHostname(m_testBroker);
|
||||
sender.setPort(m_port);
|
||||
sender.connectToHost();
|
||||
@ -237,13 +244,16 @@ void Tst_QMqttSubscription::sharedConnection()
|
||||
// Create GroupA
|
||||
const int groupSizeA = 2;
|
||||
const QString groupTopicA{QLatin1String("$share/groupA/shared/sub")};
|
||||
QMqttClient listenersA[groupSizeA];
|
||||
|
||||
VersionClient(QMqttClient::MQTT_5_0, listenersA0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, listenersA1);
|
||||
std::vector listenersA = {&listenersA0, &listenersA1};
|
||||
QMqttSubscription *subsA[groupSizeA];
|
||||
int messageCounterA[groupSizeA] = {0};
|
||||
int messageSumA = 0;
|
||||
// listenerAx: $share/groupA/Qt/Subscription/shared_check/#
|
||||
for (int i = 0; i < groupSizeA; ++i) {
|
||||
createAndSubscribe(&listenersA[i], &subsA[i], groupTopicA);
|
||||
createAndSubscribe(listenersA[i], &subsA[i], groupTopicA);
|
||||
QCOMPARE(subsA[i]->isSharedSubscription(), true);
|
||||
QCOMPARE(subsA[i]->sharedSubscriptionName(), QLatin1String("groupA"));
|
||||
connect(subsA[i], &QMqttSubscription::messageReceived, [i, &messageCounterA, &messageSumA]() {
|
||||
@ -256,13 +266,18 @@ void Tst_QMqttSubscription::sharedConnection()
|
||||
// Create GroupB
|
||||
const int groupSizeB = 5;
|
||||
const QString groupTopicB{QLatin1String("$share/groupB/shared/#")};
|
||||
QMqttClient listenersB[groupSizeB];
|
||||
VersionClient(QMqttClient::MQTT_5_0, listenersB0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, listenersB1);
|
||||
VersionClient(QMqttClient::MQTT_5_0, listenersB2);
|
||||
VersionClient(QMqttClient::MQTT_5_0, listenersB3);
|
||||
VersionClient(QMqttClient::MQTT_5_0, listenersB4);
|
||||
std::vector listenersB ={&listenersB0, &listenersB1, &listenersB2, &listenersB3, &listenersB4};
|
||||
QMqttSubscription *subsB[groupSizeB];
|
||||
int messageCounterB[groupSizeB] = {0};
|
||||
int messageSumB = 0;
|
||||
// listenerBx: $share/groupB/Qt/Subscription/shared_check/#
|
||||
for (int i = 0; i < groupSizeB; ++i) {
|
||||
createAndSubscribe(&listenersB[i], &subsB[i], groupTopicB);
|
||||
createAndSubscribe(listenersB[i], &subsB[i], groupTopicB);
|
||||
QCOMPARE(subsB[i]->isSharedSubscription(), true);
|
||||
QCOMPARE(subsB[i]->sharedSubscriptionName(), QLatin1String("groupB"));
|
||||
connect(subsB[i], &QMqttSubscription::messageReceived, [i, &messageCounterB, &messageSumB]() {
|
||||
@ -322,8 +337,7 @@ void Tst_QMqttSubscription::sharedNonShared()
|
||||
QFETCH(bool, expected);
|
||||
|
||||
// Create / Connect publisher
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
client.connectToHost();
|
||||
@ -371,11 +385,13 @@ void Tst_QMqttSubscription::noLocal()
|
||||
QFETCH(QMqttClient::ProtocolVersion, version);
|
||||
QFETCH(bool, non);
|
||||
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(version);
|
||||
VersionClient(version, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
client.connectToHost();
|
||||
|
||||
const auto clientVersion = client.protocolVersion();
|
||||
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
|
||||
QMqttSubscriptionProperties subProps;
|
||||
@ -392,7 +408,7 @@ void Tst_QMqttSubscription::noLocal()
|
||||
client.publish(topic, "content", 1);
|
||||
QTRY_VERIFY(publishSpy.size() == 1);
|
||||
|
||||
if (version == QMqttClient::MQTT_3_1_1 || !non) { // 3.1.1 does not know NoLocal and sends to subscription
|
||||
if (clientVersion == QMqttClient::MQTT_3_1_1 || !non) { // 3.1.1 does not know NoLocal and sends to subscription
|
||||
QTRY_VERIFY(receivalSpy.size() == 1);
|
||||
} else {
|
||||
QTest::qWait(3000);
|
||||
@ -405,7 +421,7 @@ void Tst_QMqttSubscription::qtbug_106203()
|
||||
const QString topic(QLatin1String("Qt/qtbug106203/Identity"));
|
||||
|
||||
// Fill up sub-Topics with retained messages (ie connection state of devices)
|
||||
QMqttClient retainer;
|
||||
VersionClient(QMqttClient::MQTT_3_1_1, retainer);
|
||||
retainer.setHostname(m_testBroker);
|
||||
retainer.setPort(m_port);
|
||||
retainer.connectToHost();
|
||||
@ -422,7 +438,7 @@ void Tst_QMqttSubscription::qtbug_106203()
|
||||
retainer.disconnectFromHost();
|
||||
QTRY_VERIFY2(retainer.state() == QMqttClient::Disconnected, "Could not disconnect from broker.");
|
||||
|
||||
QMqttClient client;
|
||||
VersionClient(QMqttClient::MQTT_3_1_1, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
@ -453,7 +469,7 @@ void Tst_QMqttSubscription::qtbug_106203()
|
||||
|
||||
void Tst_QMqttSubscription::qtbug_104478()
|
||||
{
|
||||
QMqttClient client;
|
||||
VersionClient(QMqttClient::MQTT_3_1_1, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
@ -475,13 +491,99 @@ void Tst_QMqttSubscription::qtbug_104478()
|
||||
client.publish(topic, "Wildcard checks", 1);
|
||||
QTRY_VERIFY2(pubSpy.size() == 1, "Could not publish message.");
|
||||
|
||||
QTRY_VERIFY2(singleSpy.count() == 1, "Did not receive message");
|
||||
QTRY_VERIFY2(mixedSpy.count() == 1, "Did not receive message");
|
||||
QTRY_VERIFY2(singleSpy.count() >= 1, "Did not receive message");
|
||||
QTRY_VERIFY2(mixedSpy.count() >= 1, "Did not receive message");
|
||||
|
||||
client.disconnectFromHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Disconnected, "Could not disconnect from broker.");
|
||||
}
|
||||
|
||||
void Tst_QMqttSubscription::qtbug_135653_connected()
|
||||
{
|
||||
VersionClient(QMqttClient::ProtocolVersion(0), client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
client.connectToHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
|
||||
const QString topic(QLatin1String("test/foo/bar/test3"));
|
||||
|
||||
QMqttSubscription *subscriptions[10] = { 0 };
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
bool received = false;
|
||||
subscriptions[i] = client.subscribe(topic);
|
||||
connect(subscriptions[i], &QMqttSubscription::messageReceived, subscriptions[i],
|
||||
[topic, &received](QMqttMessage msg) {
|
||||
received = (msg.payload() == "Hello World");
|
||||
});
|
||||
client.publish(topic, QString(QLatin1String("Hello World")).toLocal8Bit(), 1, true);
|
||||
QTRY_VERIFY2(received, "Could not receive message.");
|
||||
client.unsubscribe(topic);
|
||||
client.unsubscribe(topic);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
QVERIFY(subscriptions[i]);
|
||||
for (int j = i + 1; j < 10; ++j)
|
||||
QVERIFY(subscriptions[i] != subscriptions[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void Tst_QMqttSubscription::qtbug_135653_not_connected()
|
||||
{
|
||||
VersionClient(QMqttClient::ProtocolVersion(0), client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
const QString topic(QLatin1String("test/foo/bar/test4"));
|
||||
|
||||
QMqttSubscription *subscriptions[10] = { 0 };
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
bool received = false;
|
||||
client.connectToHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
subscriptions[i] = client.subscribe(topic);
|
||||
connect(subscriptions[i], &QMqttSubscription::messageReceived,
|
||||
subscriptions[i], [topic, &received](QMqttMessage msg) {
|
||||
received = (msg.payload() == "Hello World");
|
||||
});
|
||||
client.publish(topic, QString(QLatin1String("Hello World")).toLocal8Bit(), 1, true);
|
||||
QTRY_VERIFY2(received, "Could not receive message.");
|
||||
client.disconnectFromHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Disconnected, "Could not disconnect from broker.");
|
||||
client.unsubscribe(topic);
|
||||
client.unsubscribe(topic);
|
||||
}
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
QVERIFY(subscriptions[i]);
|
||||
for (int j = i + 1; j < 10; ++j)
|
||||
QVERIFY(subscriptions[i] != subscriptions[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void Tst_QMqttSubscription::qtbug_135653_not_unsubscribed()
|
||||
{
|
||||
|
||||
const QString topic(QLatin1String("test/foo/bar/test5"));
|
||||
|
||||
QMqttSubscription *subscriptions[10] = { 0 };
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
bool received = false;
|
||||
VersionClient(QMqttClient::ProtocolVersion(0), client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
client.connectToHost();
|
||||
QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker.");
|
||||
subscriptions[i] = client.subscribe(topic);
|
||||
connect(subscriptions[i], &QMqttSubscription::messageReceived,
|
||||
subscriptions[i], [topic, &received](QMqttMessage msg) {
|
||||
received = (msg.payload() == "Hello World");
|
||||
});
|
||||
client.publish(topic, QString(QLatin1String("Hello World")).toLocal8Bit(), 1, true);
|
||||
QTRY_VERIFY2(received, "Could not receive message.");
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(Tst_QMqttSubscription)
|
||||
|
||||
#include "tst_qmqttsubscription.moc"
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqttsubscriptionproperties Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqttsubscriptionproperties
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqttsubscriptionproperties
|
||||
SOURCES
|
||||
../../common/broker_connection.h
|
||||
tst_qmqttsubscriptionproperties.cpp
|
||||
|
||||
@ -26,7 +26,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
QProcess m_brokerProcess;
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
quint16 m_port{0};
|
||||
};
|
||||
|
||||
tst_QMqttSubscriptionProperties::tst_QMqttSubscriptionProperties()
|
||||
@ -70,8 +70,7 @@ void tst_QMqttSubscriptionProperties::getSet()
|
||||
|
||||
void tst_QMqttSubscriptionProperties::subscribe()
|
||||
{
|
||||
QMqttClient client;
|
||||
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
||||
VersionClient(QMqttClient::MQTT_5_0, client);
|
||||
client.setHostname(m_testBroker);
|
||||
client.setPort(m_port);
|
||||
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqtttopicfilter Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqtttopicfilter
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqtttopicfilter
|
||||
SOURCES
|
||||
tst_qmqtttopicfilter.cpp
|
||||
DEFINES
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
## tst_qmqtttopicname Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qmqtttopicname
|
||||
qtmqtt_add_test(
|
||||
TARGET
|
||||
tst_qmqtttopicname
|
||||
SOURCES
|
||||
tst_qmqtttopicname.cpp
|
||||
DEFINES
|
||||
|
||||
@ -25,7 +25,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
QProcess m_brokerProcess;
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
quint16 m_port{0};
|
||||
};
|
||||
|
||||
Tst_QMqttClient::Tst_QMqttClient()
|
||||
@ -54,9 +54,8 @@ void Tst_QMqttClient::stressTest_data()
|
||||
void Tst_QMqttClient::stressTest()
|
||||
{
|
||||
QFETCH(int, qos);
|
||||
|
||||
QMqttClient subscriber;
|
||||
QMqttClient publisher;
|
||||
VersionClient(0, subscriber);
|
||||
VersionClient(0, publisher);
|
||||
|
||||
subscriber.setHostname(m_testBroker);
|
||||
subscriber.setPort(m_port);
|
||||
@ -110,7 +109,7 @@ void Tst_QMqttClient::stressTest2()
|
||||
QSet<qint32> msgIds;
|
||||
msgIds.reserve(msgCount);
|
||||
|
||||
QMqttClient publisher;
|
||||
VersionClient(0, publisher);
|
||||
publisher.setHostname(m_testBroker);
|
||||
publisher.setPort(m_port);
|
||||
|
||||
|
||||
27
tests/certificate/cert.crt
Normal file
27
tests/certificate/cert.crt
Normal file
@ -0,0 +1,27 @@
|
||||
# Copyright (C) 2025 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID6zCCAtOgAwIBAgIUbbY+pKEPOOytRZ3RujmmdriEAKcwDQYJKoZIhvcNAQEL
|
||||
BQAwgYMxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xv
|
||||
MQswCQYDVQQKDAJRdDELMAkGA1UECwwCUXQxEjAQBgNVBAMMCWxvY2FsaG9zdDEo
|
||||
MCYGCSqGSIb3DQEJARYZZXZlbi5vc2Nhci5hbmRlcnNlbkBxdC5pbzAgFw0yNDEw
|
||||
MzExMTMyNDdaGA8yMTI0MTAwNzExMzI0N1owgYMxCzAJBgNVBAYTAk5PMQ0wCwYD
|
||||
VQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMQswCQYDVQQKDAJRdDELMAkGA1UECwwC
|
||||
UXQxEjAQBgNVBAMMCWxvY2FsaG9zdDEoMCYGCSqGSIb3DQEJARYZZXZlbi5vc2Nh
|
||||
ci5hbmRlcnNlbkBxdC5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AJzWmpWU9f/baRi/Fhn362W488HzC2/MUdbTZGIQUqt1TwTLyYMEqkr6WMy/NdYL
|
||||
8X5oXW0uz8LttbFp98wJTkNirYBMxowxwWWePnqbK0iKaZTBvBzUh0vWvmtFzHUW
|
||||
E93K1NtKyL76Zj/EZv0I0CpkWMobpzEW/zquPj83Wxki0xp2rr/HHynqFv8KFMoJ
|
||||
pR1A6uWtly12V1aQyXZIyMoIUPgDPmsHtNZKBCcz7IsAYHjjfvEIJ+r4lOOsgTXj
|
||||
cdMU+0hHfyNCy1/6xmBwnchSqDZf3bTyFRu6GK+zzFKBSyt4MB7zQ2P29qYwoNJO
|
||||
buJkPRfqiQJJRLkwyu59TB0CAwEAAaNTMFEwHQYDVR0OBBYEFGGxHowwihBbJlM5
|
||||
2wzicQa2sCfwMB8GA1UdIwQYMBaAFGGxHowwihBbJlM52wzicQa2sCfwMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBACf4lUaBpw65tOZk32EpMD0D
|
||||
M0ilx1AwfUqliKdhVvkFJ6jN5h17YhVjFoGtSzE7ry5Rg5J07tUK5Xkjcfk39UWV
|
||||
RofVnRhrtiticXs0eXQkDXqao0aMjUjsWiokr4/cTNT5R3h9jmjzyjA6pWf2oSjT
|
||||
GTzZAHdcuBTUfvPy/Ff4M5AVNsI6geUqrUd6XzFwQsDWTT86sdWQIC8j+FMghhss
|
||||
9XRNOmhWtWGSRbP0HqlWOz5hFRPP/faI/FGTknzkkVYoWaB1CR+ThFK9jYi0FnFL
|
||||
2fIcJPt+6g6d01Ws5cb9HpL9joUloCjsZ+w6PXYNVyHTaG3Lg5o4nT1Oizvrq1k=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
32
tests/certificate/cert.key
Normal file
32
tests/certificate/cert.key
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright (C) 2025 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCc1pqVlPX/22kY
|
||||
vxYZ9+tluPPB8wtvzFHW02RiEFKrdU8Ey8mDBKpK+ljMvzXWC/F+aF1tLs/C7bWx
|
||||
affMCU5DYq2ATMaMMcFlnj56mytIimmUwbwc1IdL1r5rRcx1FhPdytTbSsi++mY/
|
||||
xGb9CNAqZFjKG6cxFv86rj4/N1sZItMadq6/xx8p6hb/ChTKCaUdQOrlrZctdldW
|
||||
kMl2SMjKCFD4Az5rB7TWSgQnM+yLAGB4437xCCfq+JTjrIE143HTFPtIR38jQstf
|
||||
+sZgcJ3IUqg2X9208hUbuhivs8xSgUsreDAe80Nj9vamMKDSTm7iZD0X6okCSUS5
|
||||
MMrufUwdAgMBAAECggEAKs2u9q/my2M4NZbBE2lEB0kIzZ/lOSfMFhMvTEwkI8Mq
|
||||
Q6bSYj19tGTKo2Zz7OzphZQ6GzgxX4O8mKTRChBoGZ/uths9/Lj/jRo49wEuOOf9
|
||||
lKmjC0M9gYckBObRvArAdUGMAiVQ0D5KdZDGgrxLA6bLTK1rXcxm777qIhqbdCpN
|
||||
i9RwW9wp9rMV53J8mmWWUDVpfbIKHAmp50JknXj07onPEqN6IKdZY7sYACfYiz/8
|
||||
l31rKfR/P5j/aRBOFwBnq7Z3JGfOEQPmE8bxQ2Vt3ZXPK2ekreDx4j2Tz+gSZmF3
|
||||
Ee8DonQtA1DTOlhMyb6FhJrEFmDr38jGQqDK4qV8iQKBgQDLoOSYzX0xcyK2dPMD
|
||||
woPGcKymI+XYx0Q6cVZo1GttNarhBN0w0ms9a4SYoTMhAI9tzjJw/sU5t9kLan6n
|
||||
m11PqQVK+Vbh1v2YICJW89LcOFYwyO6IAiMN1LUdy8las4GwcXRwBWWnXAnE+YJK
|
||||
AiXcmB1ZX3j8pgStCF9VApC50wKBgQDFLP87pGtWW3nvkxoDpgVb1CwpO1T1EsFF
|
||||
Yzv7eIkFQGUkqF7OlslhMCOERE8pj4dr4CoTIvVsYW+lYfBnFPpQ0pQ+BZ2meZ0u
|
||||
GfWBDYpNGTGrxEDBc923glb2oegQQirHpiWtlinp5nciOn/rqpUwJR3b46drFlNy
|
||||
26CTKA+8TwKBgQDKv8qdMo2i/QblMRD+/2CB55KgYkHrVI1ku5DUFB1awgMAxf0P
|
||||
LZRFtZZy+p6UD6DALn0e8S2jSKE9sq2laRbByINSoW2WtKAQJn7KoT+kshtvu8F1
|
||||
fts0XERyBITaYL2S14SePWF4ADZiACVwVy8ns/YVFPC8bvlc6Gczl7hOrQKBgQCP
|
||||
BUmJSIT3GdlDlq7q8JS4fBkgO0IvldAM9aL/j/nLjl8PDPXf4e3mihVpDmdhXRO8
|
||||
gtfiE5xzZeWmz3iiPMworeYLauVkaJhDZV73ogusStcFoY/bAqFTR76unNgIWwZO
|
||||
1MxFskNqvtmxQT+igJRAXNvgsKuyeHpFONurggaP7wKBgCj25sAxVcOuOcANQGcO
|
||||
wCNvt1pHDJengrzaKooCJqm5YxNhrcKlJsdQcQ1Mu+KyhcMY/WF/0UaJZytlHMWf
|
||||
aDlF7zKqhQFqFY7nk/C7+fED7Kg3XJR54qtweVNzD6k4yTeSsvBeTd2aaepzZvJI
|
||||
IOQ3RPVQNsdgjn3VTGs/rmrR
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@ -8,8 +8,16 @@
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
#include <QWebSocket>
|
||||
#include <QWebSocketHandshakeOptions>
|
||||
#endif
|
||||
|
||||
QString invokeOrInitializeBroker(QProcess *gBrokerProcess)
|
||||
{
|
||||
#if defined(MQTT_TEST_BROKER)
|
||||
return QString::fromLatin1(MQTT_TEST_BROKER);
|
||||
#endif
|
||||
const QString broker = qgetenv("MQTT_TEST_BROKER");
|
||||
if (broker.size()) {
|
||||
qDebug("Overwriting default test broker");
|
||||
@ -65,13 +73,264 @@ QString invokeOrInitializeBroker(QProcess *gBrokerProcess)
|
||||
return QString();
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QMqttClient::ProtocolVersion)
|
||||
#define VersionClient(MQTTVERSION, CLIENTNAME) QMqttClient CLIENTNAME; CLIENTNAME.setProtocolVersion(MQTTVERSION)
|
||||
#if !defined(QT_NO_SSL)
|
||||
QSslConfiguration makeConfig(QString certificateFile)
|
||||
{
|
||||
if (certificateFile.isEmpty())
|
||||
certificateFile=QString(u":/certificate/cert.crt");
|
||||
|
||||
QSslConfiguration config;
|
||||
QFile file(certificateFile);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << " Could not open certificate file " << certificateFile;
|
||||
} else {
|
||||
const auto bytes = file.readAll();
|
||||
const QSslCertificate certificate(bytes);
|
||||
|
||||
config.addCaCertificate(certificate);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
#endif /* !QT_NO_SSL */
|
||||
|
||||
int getBrokerPort(int defaultPort)
|
||||
{
|
||||
if (getenv("MQTT_TEST_BROKER_PORT"))
|
||||
return atoi(getenv("MQTT_TEST_BROKER_PORT"));
|
||||
|
||||
#if defined (MQTT_TEST_PROTOCOL)
|
||||
return defaultPort;
|
||||
#else
|
||||
return defaultPort - 1000; /* evaluates to 1883 for the old system */
|
||||
#endif
|
||||
}
|
||||
|
||||
QMqttClient::ProtocolVersion getProtocolVersion(int version)
|
||||
{
|
||||
#if defined (MQTT_TEST_PROTOCOL)
|
||||
if (version == 0)
|
||||
version=MQTT_TEST_PROTOCOL;
|
||||
#else
|
||||
if ((version == 0) && getenv("MQTT_TEST_PROTOCOL_VERSION")) {
|
||||
switch (atoi(getenv("MQTT_TEST_PROTOCOL_VERSION"))) {
|
||||
case 3: version = QMqttClient::MQTT_3_1; break;
|
||||
case 4: version = QMqttClient::MQTT_3_1_1; break;
|
||||
case 5: version = QMqttClient::MQTT_5_0; break;
|
||||
}
|
||||
}
|
||||
if (version == 0)
|
||||
version = QMqttClient::MQTT_5_0;
|
||||
#endif
|
||||
return (QMqttClient::ProtocolVersion)version;
|
||||
}
|
||||
|
||||
class MqTTTestClientBase : public QMqttClient
|
||||
{
|
||||
public:
|
||||
virtual bool isTcp() const { return false; }
|
||||
virtual bool isSsl() const { return false; }
|
||||
virtual bool isWs() const { return false; }
|
||||
virtual bool isWss() const { return false; }
|
||||
public:
|
||||
virtual void setPort(quint16 port) = 0;
|
||||
virtual void connectToHost() = 0;
|
||||
|
||||
void setTransport(QIODevice *device, TransportType transport)
|
||||
{
|
||||
m_transportSet = true;
|
||||
QMqttClient::setTransport(device, transport);
|
||||
}
|
||||
void disconnectFromHost()
|
||||
{
|
||||
m_transportSet = false;
|
||||
QMqttClient::disconnectFromHost();
|
||||
}
|
||||
protected:
|
||||
bool m_transportSet = false;
|
||||
};
|
||||
|
||||
class MqTTClientTcp : public MqTTTestClientBase
|
||||
{
|
||||
public:
|
||||
MqTTClientTcp() = default;
|
||||
|
||||
virtual bool isTcp() const override { return true; }
|
||||
void setPort(quint16 port) override
|
||||
{
|
||||
if (port == 0)
|
||||
port = getBrokerPort(2883);
|
||||
QMqttClient::setPort(port);
|
||||
}
|
||||
void connectToHost() override
|
||||
{
|
||||
QMqttClient::connectToHost();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
class MqTTClientWs : public MqTTTestClientBase
|
||||
{
|
||||
public:
|
||||
MqTTClientWs() = default;
|
||||
|
||||
virtual bool isWs() const override { return true; }
|
||||
|
||||
void setPort(quint16 port) override
|
||||
{
|
||||
if (port == 0)
|
||||
port = getBrokerPort(9080);
|
||||
QMqttClient::setPort(port);
|
||||
}
|
||||
|
||||
void connectToHost() override
|
||||
{
|
||||
if (m_transportSet)
|
||||
QMqttClient::connectToHost();
|
||||
else
|
||||
QMqttClient::connectToHostWebSocket();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef QT_MQTT_WITH_WEBSOCKETS
|
||||
class MqTTClientWss : public MqTTTestClientBase
|
||||
{
|
||||
public:
|
||||
MqTTClientWss()
|
||||
{
|
||||
#ifndef QT_NO_SSL
|
||||
const QString origin;
|
||||
const QWebSocketProtocol::Version version = QWebSocketProtocol::VersionLatest;
|
||||
socket = new QWebSocket(origin, version, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual bool isWss() const override { return true; }
|
||||
|
||||
void setPort(quint16 port) override
|
||||
{
|
||||
if (port == 0)
|
||||
port = getBrokerPort(9081);
|
||||
QMqttClient::setPort(port);
|
||||
}
|
||||
|
||||
void connectToHost() override
|
||||
{
|
||||
if (m_transportSet)
|
||||
QMqttClient::connectToHost();
|
||||
else {
|
||||
#ifndef QT_NO_SSL
|
||||
QUrl url(QString(u"wss://") + QMqttClient::hostname() + QString(u":") + QString::number(QMqttClient::port()));
|
||||
QWebSocketHandshakeOptions options;
|
||||
options.setSubprotocols(QStringList{ QString::fromUtf8("mqttv3.1") });
|
||||
socket->setSslConfiguration(makeConfig(QString::fromUtf8(getenv("MQTT_TEST_BROKER_CERTIFICATE"))));
|
||||
socket->open(url, options);
|
||||
#endif
|
||||
QMqttClient::connectToHostWebSocketEncrypted(socket);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QWebSocket *socket = nullptr;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef QT_NO_SSL
|
||||
class MqTTClientSsl : public MqTTTestClientBase
|
||||
{
|
||||
public:
|
||||
MqTTClientSsl() = default;
|
||||
|
||||
virtual bool isSsl() const override { return true; }
|
||||
|
||||
void setPort(quint16 port) override
|
||||
{
|
||||
if (port == 0)
|
||||
port = getBrokerPort(9883);
|
||||
QMqttClient::setPort(port);
|
||||
}
|
||||
|
||||
void connectToHost() override
|
||||
{
|
||||
if (m_transportSet)
|
||||
QMqttClient::connectToHost();
|
||||
else {
|
||||
QMqttClient::connectToHostEncrypted(makeConfig(QString::fromUtf8(getenv("MQTT_TEST_BROKER_CERTIFICATE"))));
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif /* !QT_NO_SSL */
|
||||
|
||||
Q_DECLARE_METATYPE(QMqttClient::ProtocolVersion)
|
||||
|
||||
#if !defined(QT_NO_SSL) && defined(QT_MQTT_WITH_WEBSOCKETS)
|
||||
#define VersionClientBase(MQTTVERSION, CLIENTNAME, TestType) \
|
||||
std::shared_ptr<MqTTTestClientBase> p##CLIENTNAME; \
|
||||
if (TestType == QString(u"Tcp")) p##CLIENTNAME = std::make_shared<MqTTClientTcp>(); \
|
||||
if (TestType == QString(u"Ws")) p##CLIENTNAME = std::make_shared<MqTTClientWs>(); \
|
||||
if (TestType == QString(u"Wss")) p##CLIENTNAME = std::make_shared<MqTTClientWss>(); \
|
||||
if (TestType == QString(u"Ssl")) p##CLIENTNAME = std::make_shared<MqTTClientSsl>(); \
|
||||
if (!p##CLIENTNAME) p##CLIENTNAME = std::make_shared<MqTTClientTcp>(); \
|
||||
MqTTTestClientBase &CLIENTNAME = *p##CLIENTNAME; \
|
||||
CLIENTNAME.setProtocolVersion(getProtocolVersion(MQTTVERSION))
|
||||
#endif
|
||||
|
||||
#if defined(QT_NO_SSL) && defined(QT_MQTT_WITH_WEBSOCKETS)
|
||||
#define VersionClientBase(MQTTVERSION, CLIENTNAME, TestType) \
|
||||
std::shared_ptr<MqTTTestClientBase> p##CLIENTNAME; \
|
||||
if (TestType == QString(u"Tcp")) p##CLIENTNAME = std::make_shared<MqTTClientTcp>(); \
|
||||
if (TestType == QString(u"Ws")) p##CLIENTNAME = std::make_shared<MqTTClientWs>(); \
|
||||
if (TestType == QString(u"Wss")) p##CLIENTNAME = std::make_shared<MqTTClientWss>(); \
|
||||
if (!p##CLIENTNAME) p##CLIENTNAME = std::make_shared<MqTTClientTcp>(); \
|
||||
MqTTTestClientBase &CLIENTNAME = *p##CLIENTNAME; \
|
||||
CLIENTNAME.setProtocolVersion(getProtocolVersion(MQTTVERSION))
|
||||
#endif
|
||||
|
||||
#if !defined(QT_NO_SSL) && !defined(QT_MQTT_WITH_WEBSOCKETS)
|
||||
#define VersionClientBase(MQTTVERSION, CLIENTNAME, TestType) \
|
||||
std::shared_ptr<MqTTTestClientBase> p##CLIENTNAME; \
|
||||
if (TestType == QString(u"Tcp")) p##CLIENTNAME = std::make_shared<MqTTClientTcp>(); \
|
||||
if (TestType == QString(u"Ssl")) p##CLIENTNAME = std::make_shared<MqTTClientSsl>(); \
|
||||
if (!p##CLIENTNAME) p##CLIENTNAME = std::make_shared<MqTTClientTcp>(); \
|
||||
MqTTTestClientBase &CLIENTNAME = *p##CLIENTNAME; \
|
||||
CLIENTNAME.setProtocolVersion(getProtocolVersion(MQTTVERSION))
|
||||
#endif
|
||||
|
||||
#if defined(QT_NO_SSL) && !defined(QT_MQTT_WITH_WEBSOCKETS)
|
||||
#define VersionClientBase(MQTTVERSION, CLIENTNAME, TestType) \
|
||||
std::shared_ptr<MqTTTestClientBase> p##CLIENTNAME; \
|
||||
if (TestType == QString(u"Tcp")) p##CLIENTNAME = std::make_shared<MqTTClientTcp>(); \
|
||||
if (!p##CLIENTNAME) p##CLIENTNAME = std::make_shared<MqTTClientTcp>(); \
|
||||
MqTTTestClientBase &CLIENTNAME = *p##CLIENTNAME; \
|
||||
CLIENTNAME.setProtocolVersion(getProtocolVersion(MQTTVERSION))
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MQTT_TEST_TYPE)
|
||||
#define VersionClient(MQTTVERSION, CLIENTNAME) \
|
||||
VersionClientBase(MQTTVERSION, CLIENTNAME, MQTT_TEST_TYPE)
|
||||
#else
|
||||
#define VersionClient(MQTTVERSION, CLIENTNAME) \
|
||||
VersionClientBase(MQTTVERSION, CLIENTNAME, qgetenv("MQTT_TEST_BROKER_TYPE"))
|
||||
#endif
|
||||
|
||||
#ifdef MQTT_TEST_PROTOCOL
|
||||
#define DefaultVersionTestData(FUNCTION) \
|
||||
void FUNCTION() \
|
||||
{ \
|
||||
QTest::addColumn<QMqttClient::ProtocolVersion>("mqttVersion"); \
|
||||
QTest::newRow("V3.1.1") << QMqttClient::MQTT_3_1_1; \
|
||||
QTest::newRow("V5.0.0") << QMqttClient::MQTT_5_0; \
|
||||
QTest::newRow("V0") << QMqttClient::ProtocolVersion(0); \
|
||||
}
|
||||
#else
|
||||
#define DefaultVersionTestData(FUNCTION) \
|
||||
void FUNCTION() \
|
||||
{ \
|
||||
QTest::addColumn<QMqttClient::ProtocolVersion>("mqttVersion"); \
|
||||
if (getenv("MQTT_TEST_PROTOCOL_VERSION"))\
|
||||
QTest::newRow("V0") << QMqttClient::ProtocolVersion(0); \
|
||||
else { \
|
||||
QTest::newRow("V3.1.1") << QMqttClient::MQTT_3_1_1; \
|
||||
QTest::newRow("V5.0.0") << QMqttClient::MQTT_5_0; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -16,7 +16,9 @@ endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/mqtt/consolepubsub")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Mqtt)
|
||||
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Mqtt)
|
||||
end()
|
||||
|
||||
#
|
||||
# Pub
|
||||
|
||||
Loading…
Reference in New Issue
Block a user