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