1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qmqttclient.h"
6#include "qmqttclient_p.h"
7
8#ifdef QT_MQTT_WITH_WEBSOCKETS
9#include "transportLayers/mqtt_websocket_io_p.h"
10#include "transportLayers/mqtt_secure_websocket_io_p.h"
11#endif // QT_MQTT_WITH_WEBSOCKETS
12
13#include <QtCore/QLoggingCategory>
14#include <QtCore/QUuid>
15#include <QtCore/QtEndian>
16
17QT_BEGIN_NAMESPACE
18
19Q_LOGGING_CATEGORY(lcMqttClient, "qt.mqtt.client")
20
21/*!
22 \class QMqttClient
23
24 \inmodule QtMqtt
25 \brief The QMqttClient class represents the central access communicating
26 with an MQTT broker.
27
28 An MQTT client is a program or device that uses MQTT to create a network
29 connection to an MQTT server, also called a \e broker. The connection
30 request must contain a unique client identifier. Optionally, it can contain
31 a Will Topic, Will Message, user name, and password.
32
33 Once a connection is created, a client can send messages that other clients
34 might be interested in receiving, subscribe to request notifications on
35 topics, unsubscribe to remove a request for notifications, and disconnect
36 from the broker.
37*/
38
39/*!
40 \property QMqttClient::clientId
41 \brief This property holds the client's identifier value.
42
43 Each client needs to have a unique ID to be able to connect to an MQTT
44 broker. If no client ID is specified by the user, one will be generated
45 automatically when a connection is established.
46*/
47
48/*!
49 \property QMqttClient::hostname
50 \brief This property holds the hostname of the MQTT broker to connect to.
51
52 If no transport is specified via setTransport(), the client will instantiate
53 a socket connection to the specified hostname itself.
54*/
55
56/*!
57 \property QMqttClient::port
58 \brief This property holds the port to connect to the MQTT broker.
59
60 If no transport is specified via setTransport(), the client will instantiate
61 a socket connection to a host with this port number.
62*/
63
64/*!
65 \property QMqttClient::keepAlive
66 \brief This property holds the interval at which regular ping messages are
67 sent to the broker.
68
69 Once a connection to a broker is established, the client needs to send
70 frequent updates to propagate it can still be reached. The interval between
71 those updates is specified by this property.
72
73 The interval is specified in seconds.
74
75 If the broker does not respond within a grace period the connection will be
76 closed.
77
78 \sa autoKeepAlive(), requestPing(), pingResponseReceived()
79*/
80
81/*!
82 \property QMqttClient::protocolVersion
83 \brief This property holds the MQTT standard version to use for connections.
84
85 Specifies the version of the standard the client uses for connecting to a
86 broker. Valid values are:
87
88 \list
89 \li 3: MQTT standard version 3.1.
90 \li 4: MQTT standard version 3.1.1, often referred to MQTT 4.
91 \li 5: MQTT Standard 5.0.
92 \endlist
93*/
94
95/*!
96 \property QMqttClient::state
97 \brief This property holds the current state of the client.
98*/
99
100/*!
101 \property QMqttClient::error
102 \brief Specifies the current error of the client.
103*/
104
105/*!
106 \property QMqttClient::username
107 \brief This property holds the user name for connecting to a broker.
108*/
109
110/*!
111 \property QMqttClient::password
112 \brief This property holds the password for connecting to a broker.
113*/
114
115/*!
116 \property QMqttClient::cleanSession
117 \brief This property holds the state after connecting to a broker.
118*/
119
120/*!
121 \property QMqttClient::willTopic
122 \brief This property holds the Will Topic.
123*/
124
125/*!
126 \property QMqttClient::willMessage
127 \brief This property holds the payload of a Will Message.
128*/
129
130/*!
131 \property QMqttClient::willQoS
132 \brief This property holds the level of QoS for sending and storing the
133 Will Message.
134*/
135
136/*!
137 \property QMqttClient::willRetain
138 \brief This property holds whether the Will Message should be retained on
139 the broker for future subscribers to receive.
140*/
141
142/*!
143 \property QMqttClient::autoKeepAlive
144 \since 5.14
145 \brief This property holds whether the client will automatically manage
146 keep alive messages to the server.
147
148 If this property is \c true, then the client will automatically send a
149 ping message to the server at the keepAlive interval.
150
151 Otherwise, a user will have to manually invoke requestPing
152 within the specified interval of the connection. If no ping has been
153 sent within the interval, the server will disconnect.
154
155 The default of this property is \c true.
156
157 \sa keepAlive(), requestPing(), serverConnectionProperties(), pingResponseReceived()
158*/
159
160/*!
161 \enum QMqttClient::TransportType
162
163 This enum type specifies the connection method to be used to instantiate a
164 connection to a broker.
165
166 \value IODevice
167 The transport uses a class based on a QIODevice.
168 \value AbstractSocket
169 The transport uses a class based on a QAbstractSocket.
170 \value SecureSocket
171 The transport uses a class based on a QSslSocket.
172 \value [since 6.10] WebSocket
173 The transport uses a class based on a QIODevice.
174 \value [since 6.10] SecureWebSocket
175 The transport uses a class based on a QIODevice.
176*/
177
178/*!
179 \enum QMqttClient::ClientState
180
181 This enum type specifies the states a client can enter.
182
183 \value Disconnected
184 The client is disconnected from the broker.
185 \value Connecting
186 A connection request has been made, but the broker has not approved
187 the connection yet.
188 \value Connected
189 The client is connected to the broker.
190*/
191
192/*!
193 \enum QMqttClient::ClientError
194
195 This enum type specifies the error state of a client.
196
197 \value NoError
198 No error occurred.
199 \value InvalidProtocolVersion
200 The broker does not accept a connection using the specified protocol
201 version.
202 \value IdRejected
203 The client ID is malformed. This might be related to its length.
204 \value ServerUnavailable
205 The network connection has been established, but the service is
206 unavailable on the broker side.
207 \value BadUsernameOrPassword
208 The data in the username or password is malformed.
209 \value NotAuthorized
210 The client is not authorized to connect.
211 \value TransportInvalid
212 The underlying transport caused an error. For example, the connection
213 might have been interrupted unexpectedly.
214 \value ProtocolViolation
215 The client encountered a protocol violation, and therefore closed the
216 connection.
217 \value UnknownError
218 An unknown error occurred.
219 \value Mqtt5SpecificError
220 The error is related to MQTT protocol level 5. A reason code might
221 provide more details.
222*/
223
224/*!
225 \enum QMqttClient::ProtocolVersion
226
227 This enum specifies the protocol version of the MQTT standard to use during
228 communication with a broker.
229
230 \value MQTT_3_1
231 MQTT Standard 3.1
232 \value MQTT_3_1_1
233 MQTT Standard 3.1.1, publicly referred to as version 4
234 \value MQTT_5_0
235 MQTT Standard 5.0
236*/
237
238/*!
239 \fn QMqttClient::connected()
240
241 This signal is emitted when a connection has been established.
242*/
243
244/*!
245 \fn QMqttClient::disconnected()
246
247 This signal is emitted when a connection has been closed. A connection may
248 be closed when disconnectFromHost() is called or when the broker
249 disconnects.
250*/
251
252/*!
253 \fn QMqttClient::messageReceived(const QByteArray &message, const QMqttTopicName &topic)
254
255 This signal is emitted when a new message has been received. The category of
256 the message is specified by \a topic with the content being \a message.
257*/
258
259/*!
260 \fn QMqttClient::messageStatusChanged(qint32 id, QMqtt::MessageStatus s, const QMqttMessageStatusProperties &properties);
261 \since 5.12
262
263 This signal is emitted when the status for the message identified by \a id
264 changes. \a s specifies the new status of the message, and
265 \a properties specify additional properties provided by the server.
266*/
267
268/*!
269 \fn QMqttClient::messageSent(qint32 id)
270
271 Indicates that a message that was sent via the publish() function has been
272 received by the broker. The \a id is the same as returned by \c publish() to
273 help tracking the status of the message.
274*/
275
276/*!
277 \fn QMqttClient::pingResponseReceived()
278
279 This signal is emitted after the broker responds to a requestPing() call or
280 a keepAlive() ping message, and the connection is still valid.
281*/
282
283/*!
284 \fn QMqttClient::brokerSessionRestored()
285
286 This signal is emitted after a client has successfully connected to a broker
287 with the cleanSession property set to \c false, and the broker has restored
288 the session.
289
290 Sessions can be restored if a client has connected previously using the same
291 clientId.
292*/
293
294/*!
295 \since 5.12
296 \fn QMqttClient::authenticationRequested(const QMqttAuthenticationProperties &p)
297
298 This signal is emitted after a client invoked QMqttClient::connectToHost or
299 QMqttClient::connectToHostEncrypted and before the connection is
300 established. In extended authentication, a broker might request additional
301 details which need to be provided by invoking QMqttClient::authenticate.
302 \a p specifies properties provided by the broker.
303
304 \note Extended authentication is part of the MQTT 5.0 standard and can
305 only be used when the client specifies MQTT_5_0 as ProtocolVersion.
306
307 \sa authenticationFinished(), authenticate()
308*/
309
310/*!
311 \since 5.12
312 \fn QMqttClient::authenticationFinished(const QMqttAuthenticationProperties &p)
313
314 This signal is emitted after extended authentication has finished. \a p
315 specifies available details on the authentication process.
316
317 After successful authentication QMqttClient::connected is emitted.
318
319 \note Extended authentication is part of the MQTT 5.0 standard and can
320 only be used when the client specifies MQTT_5_0 as ProtocolVersion.
321
322 \sa authenticationRequested(), authenticate()
323*/
324
325/*!
326 Creates a new MQTT client instance with the specified \a parent.
327 */
328QMqttClient::QMqttClient(QObject *parent) : QObject(*(new QMqttClientPrivate(this)), parent)
329{
330 Q_D(QMqttClient);
331 d->m_connection.setClientPrivate(d);
332}
333
334/*!
335 Deletes a MQTT client. If the MQTT client was not already disconnected from the MQTT broker,
336 it will be disconnected from automatically.
337 \note If a transport is specified with setTransport it must be valid at this point
338*/
339QMqttClient::~QMqttClient()
340{
341 Q_D(QMqttClient);
342 if (d->m_connection.internalState() == QMqttConnection::BrokerConnected) {
343 d->m_connection.setClientDestruction();
344 disconnectFromHost();
345 }
346 d->m_connection.disconnectAndResetTransport();
347}
348
349/*!
350 Sets the transport to \a device. A transport can be either a socket type
351 or derived from QIODevice and is specified by \a transport.
352
353 \note The transport can only be exchanged if the MQTT client is in the
354 \l Disconnected state.
355
356 \note Setting a custom transport for a client does not pass over responsibility
357 on connection management or ownership. The transport has to be opened for QIODevice based
358 transports or connected for socket type transports before calling QMqttClient::connectToHost().
359 */
360void QMqttClient::setTransport(QIODevice *device, QMqttClient::TransportType transport)
361{
362 Q_D(QMqttClient);
363
364 if (d->m_state != Disconnected) {
365 qCDebug(lcMqttClient) << "Changing transport layer while connected is not possible.";
366 return;
367 }
368 d->m_connection.setTransport(device, transport);
369}
370
371/*!
372 Returns the transport used for communication with the broker.
373 */
374QIODevice *QMqttClient::transport() const
375{
376 Q_D(const QMqttClient);
377 return d->m_connection.transport();
378}
379
380/*!
381 Adds a new subscription to receive notifications on \a topic. The parameter
382 \a qos specifies the level at which security messages are received. For more
383 information about the available QoS levels, see \l {Quality of Service}.
384
385 This function returns a pointer to a \l QMqttSubscription. If the same topic
386 is subscribed twice, the return value points to the same subscription
387 instance. The MQTT client is the owner of the subscription.
388 */
389QMqttSubscription *QMqttClient::subscribe(const QMqttTopicFilter &topic, quint8 qos)
390{
391 return subscribe(topic, properties: QMqttSubscriptionProperties(), qos);
392}
393
394/*!
395 \since 5.12
396
397 Adds a new subscription to receive notifications on \a topic. The parameter
398 \a properties specifies additional subscription properties to be validated
399 by the broker. The parameter \a qos specifies the level at which security
400 messages are received. For more information about the available QoS levels,
401 see \l {Quality of Service}.
402
403 This function returns a pointer to a \l QMqttSubscription. If the same topic
404 is subscribed twice, the return value points to the same subscription
405 instance. The MQTT client is the owner of the subscription.
406
407 \note \a properties will only be passed to the broker when the client
408 specifies MQTT_5_0 as ProtocolVersion.
409*/
410QMqttSubscription *QMqttClient::subscribe(const QMqttTopicFilter &topic, const QMqttSubscriptionProperties &properties, quint8 qos)
411{
412 Q_D(QMqttClient);
413
414 if (d->m_state != QMqttClient::Connected)
415 return nullptr;
416
417 return d->m_connection.sendControlSubscribe(topic, qos, properties);
418}
419
420/*!
421 Unsubscribes from \a topic. No notifications will be sent to any of the
422 subscriptions made by calling subscribe().
423
424 \note If a client disconnects from a broker without unsubscribing, the
425 broker will store all messages and publish them on the next reconnect.
426 */
427void QMqttClient::unsubscribe(const QMqttTopicFilter &topic)
428{
429 unsubscribe(topic, properties: QMqttUnsubscriptionProperties());
430}
431
432/*!
433 \since 5.12
434
435 Unsubscribes from \a topic. No notifications will be sent to any of the
436 subscriptions made by calling subscribe(). \a properties specifies
437 additional user properties to be passed to the broker.
438
439 \note If a client disconnects from a broker without unsubscribing, the
440 broker will store all messages and publish them on the next reconnect.
441
442 \note \a properties will only be passed to the broker when the client
443 specifies MQTT_5_0 as ProtocolVersion.
444*/
445void QMqttClient::unsubscribe(const QMqttTopicFilter &topic, const QMqttUnsubscriptionProperties &properties)
446{
447 Q_D(QMqttClient);
448 d->m_connection.sendControlUnsubscribe(topic, properties);
449}
450
451/*!
452 Publishes a \a message to the broker with the specified \a topic. \a qos
453 specifies the QoS level required for transferring the message.
454
455 If \a retain is set to \c true, the message will stay on the broker for
456 other clients to connect and receive the message.
457
458 Returns an ID that is used internally to identify the message.
459*/
460qint32 QMqttClient::publish(const QMqttTopicName &topic, const QByteArray &message, quint8 qos, bool retain)
461{
462 return publish(topic, properties: QMqttPublishProperties(), message, qos, retain);
463}
464
465/*!
466 \since 5.12
467
468 Publishes a \a message to the broker with the specified \a properties and
469 \a topic. \a qos specifies the QoS level required for transferring
470 the message.
471
472 If \a retain is set to \c true, the message will stay on the broker for
473 other clients to connect and receive the message.
474
475 Returns an ID that is used internally to identify the message.
476
477 \note \a properties will only be passed to the broker when the client
478 specifies MQTT_5_0 as ProtocolVersion.
479*/
480qint32 QMqttClient::publish(const QMqttTopicName &topic, const QMqttPublishProperties &properties,
481 const QByteArray &message, quint8 qos, bool retain)
482{
483 Q_D(QMqttClient);
484 if (qos > 2)
485 return -1;
486
487 if (d->m_state != QMqttClient::Connected)
488 return -1;
489
490 return d->m_connection.sendControlPublish(topic, message, qos, retain, properties);
491}
492
493/*!
494 Sends a ping message to the broker and expects a reply.
495
496 If the connection is active and \l autoKeepAlive is \c true, then calling this
497 function will fail as the client is responsible for managing this process.
498
499 Using \c requestPing() manually requires a call every time within the \l keepAlive
500 interval as long as the connection is active.
501
502 To check whether the ping is successful, connect to the
503 \l pingResponseReceived() signal.
504
505 Returns \c true if the ping request could be sent.
506
507 \sa pingResponseReceived(), autoKeepAlive(), keepAlive()
508 */
509bool QMqttClient::requestPing()
510{
511 Q_D(QMqttClient);
512 return d->m_connection.sendControlPingRequest(isAuto: false);
513}
514
515QString QMqttClient::hostname() const
516{
517 Q_D(const QMqttClient);
518 return d->m_hostname;
519}
520
521quint16 QMqttClient::port() const
522{
523 Q_D(const QMqttClient);
524 return d->m_port;
525}
526
527/*!
528 \since 6.10
529
530 Set a web socket transport type and initiates a connection to the MQTT broker.
531 Earlier transport type is replaced.
532 If \a webSocket is given, hostname and port is ignored, and connection is done
533 with that websocket. webSocket is owned by the calling code, and must be valid
534 for the lifetime of the QMqttClient object.
535 */
536void QMqttClient::connectToHostWebSocket(QWebSocket *webSocket)
537{
538#ifndef QT_MQTT_WITH_WEBSOCKETS
539 Q_UNUSED(webSocket);
540 qWarning() << " Qt built without websocket support, connect skipped";
541#else
542 Q_D(QMqttClient);
543
544 d->m_connection.connectTransport(
545 TransportType::WebSocket,
546 std::make_shared<QMqttWebSocketIO>(nullptr, webSocket));
547 connectToHost();
548 d->m_connection.m_transportIsSet = false;
549#endif // QT_MQTT_WITH_WEBSOCKETS
550}
551
552/*!
553 \since 6.10
554
555 Set a secure websocket transport type and initiates a connection to the MQTT broker.
556 Earlier transport type is replaced.
557 If \a webSocket is given, hostname and port is ignored, and connection is done
558 with that websocket. webSocket is owned by the calling code, and must be valid
559 for the lifetime of the QMqttClient object.
560 */
561void QMqttClient::connectToHostWebSocketEncrypted(QWebSocket *webSocket)
562{
563#ifndef QT_MQTT_WITH_WEBSOCKETS
564 Q_UNUSED(webSocket);
565 qWarning() << " Qt built without websocket support, connect skipped";
566#else
567 Q_D(QMqttClient);
568
569 d->m_connection.connectTransport(
570 TransportType::SecureWebSocket,
571 std::make_shared<QMqttSecureWebSocketIO>(nullptr, webSocket));
572 connectToHost();
573 d->m_connection.m_transportIsSet = false;
574#endif // QT_MQTT_WITH_WEBSOCKETS
575}
576
577/*!
578 Initiates a connection to the MQTT broker.
579 */
580void QMqttClient::connectToHost()
581{
582 connectToHost(encrypted: false, sslPeerName: QString());
583}
584
585#ifndef QT_NO_SSL
586/*!
587 \since 5.14
588 Initiates an encrypted connection to the MQTT broker.
589
590 \a conf specifies the SSL configuration to be used for the connection
591 */
592void QMqttClient::connectToHostEncrypted(const QSslConfiguration &conf)
593{
594 Q_D(QMqttClient);
595 d->m_connection.m_sslConfiguration = conf;
596 connectToHost(encrypted: true, sslPeerName: QString());
597}
598#endif
599
600void QMqttClient::connectToHost(bool encrypted, const QString &sslPeerName)
601{
602 Q_D(QMqttClient);
603
604 if (state() == QMqttClient::Connecting) {
605 qCDebug(lcMqttClient) << "Connection request currently ongoing.";
606 return;
607 }
608
609 if (state() == QMqttClient::Connected) {
610 qCDebug(lcMqttClient) << "Already connected to a broker. Rejecting connection request.";
611 return;
612 }
613
614 if (!d->m_connection.ensureTransport(createSecureIfNeeded: encrypted)) {
615 qCDebug(lcMqttClient) << "Could not ensure connection.";
616 d->setStateAndError(s: Disconnected, e: TransportInvalid);
617 return;
618 }
619 d->m_error = QMqttClient::NoError; // Fresh reconnect, unset error
620 d->setStateAndError(s: Connecting);
621
622 if (d->m_cleanSession)
623 d->m_connection.cleanSubscriptions();
624
625 if (!d->m_connection.ensureTransportOpen(sslPeerName)) {
626 qCDebug(lcMqttClient) << "Could not ensure that connection is open.";
627 d->setStateAndError(s: Disconnected, e: TransportInvalid);
628 return;
629 }
630
631 // Once transport has connected, it will invoke
632 // QMqttConnection::sendControlConnect to
633 // handshake with the broker
634}
635
636/*!
637 Disconnects from the MQTT broker.
638 */
639void QMqttClient::disconnectFromHost()
640{
641 Q_D(QMqttClient);
642
643 switch (d->m_connection.internalState()) {
644 case QMqttConnection::BrokerConnected:
645 case QMqttConnection::ClientDestruction:
646 d->m_connection.sendControlDisconnect();
647 break;
648 case QMqttConnection::BrokerDisconnected:
649 break;
650 case QMqttConnection::BrokerConnecting:
651 case QMqttConnection::BrokerWaitForConnectAck:
652 d->m_connection.m_transport->close();
653 break;
654 }
655}
656
657QMqttClient::ClientState QMqttClient::state() const
658{
659 Q_D(const QMqttClient);
660 return d->m_state;
661}
662
663QString QMqttClient::username() const
664{
665 Q_D(const QMqttClient);
666 return d->m_username;
667}
668
669QString QMqttClient::password() const
670{
671 Q_D(const QMqttClient);
672 return d->m_password;
673}
674
675bool QMqttClient::cleanSession() const
676{
677 Q_D(const QMqttClient);
678 return d->m_cleanSession;
679}
680
681QString QMqttClient::willTopic() const
682{
683 Q_D(const QMqttClient);
684 return d->m_willTopic;
685}
686
687quint8 QMqttClient::willQoS() const
688{
689 Q_D(const QMqttClient);
690 return d->m_willQoS;
691}
692
693QByteArray QMqttClient::willMessage() const
694{
695 Q_D(const QMqttClient);
696 return d->m_willMessage;
697}
698
699bool QMqttClient::willRetain() const
700{
701 Q_D(const QMqttClient);
702 return d->m_willRetain;
703}
704
705bool QMqttClient::autoKeepAlive() const
706{
707 Q_D(const QMqttClient);
708 return d->m_autoKeepAlive;
709}
710
711/*!
712 \since 5.12
713
714 Sets the connection properties to \a prop. \l QMqttConnectionProperties
715 can be used to ask the server to use a specific feature set. After a
716 connection request the server response can be obtained by calling
717 \l QMqttClient::serverConnectionProperties.
718
719 \note The connection properties can only be set if the MQTT client is in the
720 \l Disconnected state.
721
722 \note QMqttConnectionProperties can only be used when the client specifies
723 MQTT_5_0 as ProtocolVersion.
724*/
725void QMqttClient::setConnectionProperties(const QMqttConnectionProperties &prop)
726{
727 Q_D(QMqttClient);
728 d->m_connectionProperties = prop;
729}
730
731/*!
732 \since 5.12
733
734 Returns the connection properties the client requests to the broker.
735
736 \note QMqttConnectionProperties can only be used when the client specifies
737 MQTT_5_0 as ProtocolVersion.
738*/
739QMqttConnectionProperties QMqttClient::connectionProperties() const
740{
741 Q_D(const QMqttClient);
742 return d->m_connectionProperties;
743}
744
745/*!
746 \since 5.12
747
748 Sets the last will properties to \a prop. QMqttLastWillProperties allows
749 to set additional features for the last will message stored at the broker.
750
751 \note The connection properties can only be set if the MQTT client is in the
752 \l Disconnected state.
753
754 \note QMqttLastWillProperties can only be used when the client specifies
755 MQTT_5_0 as ProtocolVersion.
756*/
757void QMqttClient::setLastWillProperties(const QMqttLastWillProperties &prop)
758{
759 Q_D(QMqttClient);
760 d->m_lastWillProperties = prop;
761}
762
763/*!
764 \since 5.12
765
766 Returns the last will properties.
767
768 \note QMqttLastWillProperties can only be used when the client specifies
769 MQTT_5_0 as ProtocolVersion.
770*/
771QMqttLastWillProperties QMqttClient::lastWillProperties() const
772{
773 Q_D(const QMqttClient);
774 return d->m_lastWillProperties;
775}
776
777/*!
778 \since 5.12
779
780 Returns the QMqttServerConnectionProperties the broker returned after a
781 connection attempt.
782
783 This can be used to verify that client side connection properties set by
784 QMqttClient::setConnectionProperties have been accepted by the broker. Also,
785 in case of a failed connection attempt, it can be used for connection
786 diagnostics.
787
788 \note QMqttServerConnectionProperties can only be used when the client
789 specifies MQTT_5_0 as ProtocolVersion.
790
791 \sa connectionProperties()
792*/
793QMqttServerConnectionProperties QMqttClient::serverConnectionProperties() const
794{
795 Q_D(const QMqttClient);
796 return d->m_serverConnectionProperties;
797}
798
799/*!
800 \since 5.12
801
802 Sends an authentication request to the broker. \a prop specifies
803 the required information to fulfill the authentication request.
804
805 This function should only be called after a
806 QMqttClient::authenticationRequested signal has been emitted.
807
808 \note Extended authentication is part of the MQTT 5.0 standard and can
809 only be used when the client specifies MQTT_5_0 as ProtocolVersion.
810
811 \sa authenticationRequested(), authenticationFinished()
812*/
813void QMqttClient::authenticate(const QMqttAuthenticationProperties &prop)
814{
815 Q_D(QMqttClient);
816 if (protocolVersion() != QMqttClient::MQTT_5_0) {
817 qCDebug(lcMqttClient) << "Authentication is only supported on protocol level 5.";
818 return;
819 }
820 if (state() == QMqttClient::Disconnected) {
821 qCDebug(lcMqttClient) << "Cannot send authentication request while disconnected.";
822 return;
823 }
824 d->m_connection.sendControlAuthenticate(properties: prop);
825}
826
827QMqttClient::ClientError QMqttClient::error() const
828{
829 Q_D(const QMqttClient);
830 return d->m_error;
831}
832
833QMqttClient::ProtocolVersion QMqttClient::protocolVersion() const
834{
835 Q_D(const QMqttClient);
836 return d->m_protocolVersion;
837}
838
839QString QMqttClient::clientId() const
840{
841 Q_D(const QMqttClient);
842 return d->m_clientId;
843}
844
845quint16 QMqttClient::keepAlive() const
846{
847 Q_D(const QMqttClient);
848 return d->m_keepAlive;
849}
850
851void QMqttClient::setHostname(const QString &hostname)
852{
853 Q_D(QMqttClient);
854
855 if (state() != QMqttClient::Disconnected) {
856 qCDebug(lcMqttClient) << "Changing hostname while connected is not possible.";
857 return;
858 }
859
860 if (d->m_hostname == hostname)
861 return;
862
863 d->m_hostname = hostname;
864 emit hostnameChanged(hostname);
865}
866
867void QMqttClient::setPort(quint16 port)
868{
869 Q_D(QMqttClient);
870
871 if (state() != QMqttClient::Disconnected) {
872 qCDebug(lcMqttClient) << "Changing port while connected is not possible.";
873 return;
874 }
875
876 if (d->m_port == port)
877 return;
878
879 d->m_port = port;
880 emit portChanged(port);
881}
882
883void QMqttClient::setClientId(const QString &clientId)
884{
885 Q_D(QMqttClient);
886
887 if (state() != QMqttClient::Disconnected) {
888 qCDebug(lcMqttClient) << "Changing client ID while connected is not possible.";
889 return;
890 }
891 d->setClientId(clientId);
892}
893
894void QMqttClient::setKeepAlive(quint16 keepAlive)
895{
896 Q_D(QMqttClient);
897 if (d->m_keepAlive == keepAlive)
898 return;
899
900 if (state() != QMqttClient::Disconnected) {
901 qCDebug(lcMqttClient) << "Changing keepAlive while connected is not possible.";
902 return;
903 }
904
905 d->m_keepAlive = keepAlive;
906 emit keepAliveChanged(keepAlive);
907}
908
909void QMqttClient::setProtocolVersion(ProtocolVersion protocolVersion)
910{
911 Q_D(QMqttClient);
912
913 if (state() != QMqttClient::Disconnected) {
914 qCDebug(lcMqttClient) << "Changing protocol version while connected is not possible.";
915 return;
916 }
917
918 if (d->m_protocolVersion == protocolVersion)
919 return;
920
921 if (protocolVersion < 3 || protocolVersion > 5)
922 return;
923
924 d->m_protocolVersion = protocolVersion;
925 emit protocolVersionChanged(protocolVersion);
926}
927
928void QMqttClient::setState(ClientState state)
929{
930 Q_D(QMqttClient);
931 if (d->m_state == state)
932 return;
933
934 d->m_state = state;
935 emit stateChanged(state);
936 if (d->m_state == QMqttClient::Disconnected)
937 emit disconnected();
938 else if (d->m_state == QMqttClient::Connected)
939 emit connected();
940}
941
942void QMqttClient::setUsername(const QString &username)
943{
944 Q_D(QMqttClient);
945
946 if (state() != QMqttClient::Disconnected) {
947 qCDebug(lcMqttClient) << "Changing username while connected is not possible.";
948 return;
949 }
950
951 if (d->m_username == username)
952 return;
953
954 d->m_username = username;
955 emit usernameChanged(username);
956}
957
958void QMqttClient::setPassword(const QString &password)
959{
960 Q_D(QMqttClient);
961
962 if (state() != QMqttClient::Disconnected) {
963 qCDebug(lcMqttClient) << "Changing password while connected is not possible.";
964 return;
965 }
966
967 if (d->m_password == password)
968 return;
969
970 d->m_password = password;
971 emit passwordChanged(password);
972}
973
974void QMqttClient::setCleanSession(bool cleanSession)
975{
976 Q_D(QMqttClient);
977
978 if (state() != QMqttClient::Disconnected) {
979 qCDebug(lcMqttClient) << "Changing clean session while connected is not possible.";
980 return;
981 }
982
983 if (d->m_cleanSession == cleanSession)
984 return;
985
986 d->m_cleanSession = cleanSession;
987 emit cleanSessionChanged(cleanSession);
988}
989
990void QMqttClient::setWillTopic(const QString &willTopic)
991{
992 Q_D(QMqttClient);
993
994 if (state() != QMqttClient::Disconnected) {
995 qCDebug(lcMqttClient) << "Changing will topic while connected is not possible.";
996 return;
997 }
998
999 if (d->m_willTopic == willTopic)
1000 return;
1001
1002 d->m_willTopic = willTopic;
1003 emit willTopicChanged(willTopic);
1004}
1005
1006void QMqttClient::setWillQoS(quint8 willQoS)
1007{
1008 Q_D(QMqttClient);
1009
1010 if (state() != QMqttClient::Disconnected) {
1011 qCDebug(lcMqttClient) << "Changing will qos while connected is not possible.";
1012 return;
1013 }
1014
1015 if (d->m_willQoS == willQoS)
1016 return;
1017
1018 d->m_willQoS = willQoS;
1019 emit willQoSChanged(willQoS);
1020}
1021
1022void QMqttClient::setWillMessage(const QByteArray &willMessage)
1023{
1024 Q_D(QMqttClient);
1025
1026 if (state() != QMqttClient::Disconnected) {
1027 qCDebug(lcMqttClient) << "Changing will message while connected is not possible.";
1028 return;
1029 }
1030
1031 if (d->m_willMessage == willMessage)
1032 return;
1033
1034 d->m_willMessage = willMessage;
1035 emit willMessageChanged(willMessage);
1036}
1037
1038void QMqttClient::setWillRetain(bool willRetain)
1039{
1040 Q_D(QMqttClient);
1041
1042 if (state() != QMqttClient::Disconnected) {
1043 qCDebug(lcMqttClient) << "Changing will retain while connected is not possible.";
1044 return;
1045 }
1046
1047 if (d->m_willRetain == willRetain)
1048 return;
1049
1050 d->m_willRetain = willRetain;
1051 emit willRetainChanged(willRetain);
1052}
1053
1054void QMqttClient::setAutoKeepAlive(bool autoKeepAlive)
1055{
1056 Q_D(QMqttClient);
1057
1058 if (state() != QMqttClient::Disconnected) {
1059 qCDebug(lcMqttClient) << "Changing autoKeepAlive while connected is not possible.";
1060 return;
1061 }
1062
1063 if (d->m_autoKeepAlive == autoKeepAlive)
1064 return;
1065
1066 d->m_autoKeepAlive = autoKeepAlive;
1067 emit autoKeepAliveChanged(autoKeepAlive: d->m_autoKeepAlive);
1068}
1069
1070void QMqttClient::setError(ClientError e)
1071{
1072 Q_D(QMqttClient);
1073 if (d->m_error == e)
1074 return;
1075
1076 d->m_error = e;
1077 emit errorChanged(error: d->m_error);
1078}
1079
1080QMqttClientPrivate::QMqttClientPrivate(QMqttClient *c)
1081 : QObjectPrivate()
1082{
1083 m_client = c;
1084 m_clientId = QUuid::createUuid().toString();
1085 m_clientId.remove(c: QLatin1Char('{'));
1086 m_clientId.remove(c: QLatin1Char('}'));
1087 m_clientId.remove(c: QLatin1Char('-'));
1088 m_clientId.resize(size: 23);
1089#ifdef QT_BUILD_INTERNAL
1090 // Some test servers require a username token
1091 if (qEnvironmentVariableIsSet(varName: "QT_MQTT_TEST_USERNAME"))
1092 m_username = qEnvironmentVariable(varName: "QT_MQTT_TEST_USERNAME");
1093 if (qEnvironmentVariableIsSet(varName: "QT_MQTT_TEST_PASSWORD"))
1094 m_password = qEnvironmentVariable(varName: "QT_MQTT_TEST_PASSWORD");
1095 if (qEnvironmentVariableIsSet(varName: "QT_MQTT_TEST_CLIENTID"))
1096 m_clientId = qEnvironmentVariable(varName: "QT_MQTT_TEST_CLIENTID");
1097#endif
1098}
1099
1100QMqttClientPrivate::~QMqttClientPrivate()
1101{
1102}
1103
1104void QMqttClientPrivate::setStateAndError(QMqttClient::ClientState s, QMqttClient::ClientError e)
1105{
1106 Q_Q(QMqttClient);
1107
1108 if (e != QMqttClient::NoError)
1109 q->setError(e);
1110 q->setState(s);
1111}
1112
1113void QMqttClientPrivate::setClientId(const QString &id)
1114{
1115 Q_Q(QMqttClient);
1116
1117 if (m_clientId == id)
1118 return;
1119
1120 m_clientId = id;
1121 emit q->clientIdChanged(clientId: id);
1122}
1123
1124QT_END_NAMESPACE
1125

source code of qtmqtt/src/mqtt/qmqttclient.cpp