diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-06-19 13:17:32 +0200 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2023-06-22 10:58:48 +0200 |
commit | e7cda476e73576edcbb5cfe5c6b0a9029d6a2f51 (patch) | |
tree | 7b597d1eec4cb9a5e239e177722978365b718faf /examples | |
parent | 967163e3d8fd31e2da77122023bd97ed0880484b (diff) |
Secure CoAP Client: update documentation
* Do not use the "Example" word in the title
* Set the proper example category
* Add a note about running the example from QtCreator
* Add a note on how to terminate docker containers after usage
* Update the documentation about exposing C++ types to QML. Describe
the modern way of doing it.
* Introduce a section about changes to build files.
Task-number: QTBUG-113858
Pick-to: 6.6 6.5
Change-Id: Iec125357001d950efe61b1ec0755d2feaba6b80f
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Diffstat (limited to 'examples')
-rw-r--r-- | examples/coap/doc/quicksecureclient.qdoc | 166 | ||||
-rw-r--r-- | examples/coap/quicksecureclient/FilePicker.qml | 2 | ||||
-rw-r--r-- | examples/coap/quicksecureclient/Main.qml | 8 | ||||
-rw-r--r-- | examples/coap/quicksecureclient/qmlcoapsecureclient.cpp | 10 | ||||
-rw-r--r-- | examples/coap/quicksecureclient/qmlcoapsecureclient.h | 4 |
5 files changed, 115 insertions, 75 deletions
diff --git a/examples/coap/doc/quicksecureclient.qdoc b/examples/coap/doc/quicksecureclient.qdoc index 0d6df66..d3798fe 100644 --- a/examples/coap/doc/quicksecureclient.qdoc +++ b/examples/coap/doc/quicksecureclient.qdoc @@ -1,9 +1,10 @@ -// Copyright (C) 2019 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \example quicksecureclient - \title Quick Secure CoAP Client Example + \title Quick Secure CoAP Client + \examplecategory {Connectivity} \ingroup qtcoap-examples \brief Securing the CoAP client and using it with a Qt Quick user interface. @@ -15,7 +16,7 @@ \note Qt CoAP does not provide a QML API in its current version. However, you can make the C++ classes of the module available to QML as it is shown in the example. - \section1 Running the Example + \include examples-run.qdocinc To run the example application, you first need to set up a secure CoAP server. You can run the example with any secure CoAP server supporting one of the @@ -23,116 +24,120 @@ information about setting up a secure CoAP server, see \l {Setting Up a Secure CoAP Server}. - \section1 Creating a Client and Linking It with QML + \section1 Exposing C++ Classes to QML - \c QmlCoapSecureClient wraps the functionality of QCoapClient to make it - available to QML. It also holds the selected security mode and security - configuration parameters. + In this example, you need to expose the \l QCoapClient class and the + \l {QtCoap Namespace}{QtCoap} namespace to QML. To achieve this, create a + custom wrapper class and use the special \l {Defining QML Types from C++} + {registration macros}. - \quotefromfile quicksecureclient/qmlcoapsecureclient.h - \skipto class QmlCoapSecureClient - \printuntil /^\}/ + Create the \c QmlCoapSecureClient class as a wrapper around \l QCoapClient. + This class also holds the selected security mode and security configuration + parameters. Use the \l Q_INVOKABLE macro to expose several methods to QML. + Also use the \l QML_NAMED_ELEMENT macro to register the class in QML as + \c {CoapSecureClient}. - In the main.cpp file, we register the \c QmlCoapSecureClient class as a QML type: + \snippet quicksecureclient/qmlcoapsecureclient.h coap_client - \quotefromfile quicksecureclient/main.cpp - \skipto qmlRegisterType - \printline qmlRegisterType + After that, register the \l {QtCoap Namespace}{QtCoap} namespace, so that + you can use the enums provided there: + \snippet quicksecureclient/qmlcoapsecureclient.h coap_namespace - We also register the QtCoap namespace, to be able to use it in QML code: + \section1 Adjusting Build Files - \skipto qmlRegisterUncreatableMetaObject - \printto const QUrl + To make the custom types available from QML, update the build system files + accordingly. - The instance of QCoapClient is created when the user selects or changes the - security mode in the UI. The \c {QmlCoapSecureClient::setSecurityMode()} method - is invoked from the QML code, when one of the security modes is selected: + \section2 CMake - \quotefromfile quicksecureclient/main.qml - \skipto ButtonGroup - \printto RowLayout + For a CMake-based build, add the following to the \c {CMakeLists.txt}: - And in the \c .cpp file: + \quotefromfile quicksecureclient/CMakeLists.txt + \skipto qt_add_qml_module + \printuntil ) - \quotefromfile quicksecureclient/qmlcoapsecureclient.cpp - \skipto QmlCoapSecureClient::setSecurityMode - \printto connect - \dots + \section2 qmake - Then we connect the signals of the client, to get notified when a CoAP reply is - received or a request has failed: + For a qmake build, modify the \c {quicksecureclient.pro} file in the + following way: + \quotefromfile quicksecureclient/quicksecureclient.pro + \skipto CONFIG + \printuntil QML_IMPORT_MAJOR_VERSION \dots - \skipto connect - \printuntil }); - \printuntil }); - \dots + \skipto qml_resources.files + \printuntil RESOURCES - The \c {QmlCoapSecureClient::finished()} signal triggers the \c onFinished signal - handler of \c CoapSecureClient, which handles the output: + \section1 Using New QML Types - \quotefromfile quicksecureclient/main.qml - \skipto CoapSecureClient { - \printto GridLayout - \dots + Now, when the C++ classes are properly exposed to QML, you can use the new + types. - \section1 Sending a Request + \section2 Creating the Client - When the user clicks on the \uicontrol {Send Request} button, we set the security - configuration based on the selected security mode and send a \c GET request: + \c CoapSecureClient is instantiated from the \c {Main.qml} file. It handles + the \c {QmlCoapSecureClient::finished()} signal and updates the UI + accordingly: - \dots - \skipto FilePicker { - \skipto Button { - \printuntil sendGetRequest - \dots + \snippet quicksecureclient/Main.qml client + + The instance of \l QCoapClient is created when the user selects or changes the + security mode in the UI. The \c {QmlCoapSecureClient::setSecurityMode()} method + is invoked from the QML code, when one of the security modes is selected: + + \snippet quicksecureclient/Main.qml security_modes + + On the C++ side, this method creates a \l QCoapClient and connects to its + \l {QCoapClient::}{finished()} and \l {QCoapClient::}{error()} signals. The + class handles both signals internally, and forwards them to the new + \c finished() signal. + + \snippet quicksecureclient/qmlcoapsecureclient.cpp set_security_mode - There are two overloads for the \c setSecurityConfiguration method. For the PSK - mode we simply set the client identity and the pre-shared key: + \section2 Sending a Request - \quotefromfile quicksecureclient/qmlcoapsecureclient.cpp - \skipto QmlCoapSecureClient::setSecurityConfiguration - \printuntil } + Click the \uicontrol {Send Request} button to set the security configuration + based on the selected security mode and send a \c GET request: - And for X.509 certificates, we read the certificate files and the private key, - and set the security configuration: + \snippet quicksecureclient/Main.qml send_request - \skipto QmlCoapSecureClient::setSecurityConfiguration - \printto QmlCoapSecureClient::disconnect + There are two overloads for the \c setSecurityConfiguration method. + + The overload for the PSK mode simply sets the client identity and the + pre-shared key: + + \snippet quicksecureclient/qmlcoapsecureclient.cpp set_configuration_psk + + And the overload for X.509 certificates reads the certificate files and + the private key and sets the security configuration: + + \snippet quicksecureclient/qmlcoapsecureclient.cpp set_configuration_cert After setting the security configuration, the \c sendGetRequest method sets the request URL and sends a \c GET request: - \quotefromfile quicksecureclient/qmlcoapsecureclient.cpp - \skipto QmlCoapSecureClient::sendGetRequest - \printuntil } + \snippet quicksecureclient/qmlcoapsecureclient.cpp send_get_request When sending the first request, a handshake with the CoAP server is performed. After the handshake is successfully done, all the subsequent messages are encrypted, and changing the security configuration after a successful handshake won't have any effect. If you want to change it, or change the host, you need to disconnect first. - \skipto QmlCoapSecureClient::disconnect - \printuntil + \snippet quicksecureclient/qmlcoapsecureclient.cpp disconnect This will abort the handshake and close the open sockets. - For the authentication using X.509 certificates, we need to specify the certificate - files. The \c FilePicker component is used for this purpose. It combines a text - field and a button for opening a file dialog when the button is pressed: + For the authentication using X.509 certificates, the certificate files need + to be specified. The \c FilePicker component is used for this purpose. It + combines a text field and a button for opening a file dialog when the button + is pressed: - \quotefromfile quicksecureclient/FilePicker.qml - \skipto Item { - \printuntil + \snippet quicksecureclient/FilePicker.qml filepicker - In the \c main.qml file \c FilePicker is instantiated several times for creating - input fields for certificates and the private key: + \c FilePicker is instantiated several times in the \c Main.qml file for + creating input fields for certificates and the private key: - \quotefromfile quicksecureclient/main.qml - \dots - \skipto FilePicker - \printto Button { - \dots + \snippet quicksecureclient/Main.qml certificate_dialogs \section1 Setting Up a Secure CoAP Server @@ -226,4 +231,15 @@ "IPAddress": "172.17.0.2", ... \endcode + + \section2 Terminating a Docker Container + + To terminate a docker container after usage, use the following command: + + \badcode + docker stop <container_id> + \endcode + + The \c {<container_id>} here is the same as retrieved by the \c {docker ps} + command. */ diff --git a/examples/coap/quicksecureclient/FilePicker.qml b/examples/coap/quicksecureclient/FilePicker.qml index cc24464..270a183 100644 --- a/examples/coap/quicksecureclient/FilePicker.qml +++ b/examples/coap/quicksecureclient/FilePicker.qml @@ -7,6 +7,7 @@ import QtQuick.Dialogs import QtQuick.Controls import QtQuick.Layouts +//! [filepicker] Item { id: filePicker @@ -40,3 +41,4 @@ Item { } } } +//! [filepicker] diff --git a/examples/coap/quicksecureclient/Main.qml b/examples/coap/quicksecureclient/Main.qml index 9762f5c..3c3c086 100644 --- a/examples/coap/quicksecureclient/Main.qml +++ b/examples/coap/quicksecureclient/Main.qml @@ -16,6 +16,7 @@ Window { height: 640 title: qsTr("Qt Quick Secure CoAP Client") + //! [client] CoapSecureClient { id: client onFinished: (result) => { @@ -24,6 +25,7 @@ Window { disconnectButton.enabled = true; } } + //! [client] GridLayout { anchors.fill: parent @@ -65,6 +67,7 @@ Window { Label { text: qsTr("Security Mode:") } + //! [security_modes] ButtonGroup { id: securityModeGroup onClicked: { @@ -74,6 +77,7 @@ Window { client.setSecurityMode(QtCoap.SecurityMode.Certificate); } } + //! [security_modes] RowLayout { RadioButton { id: preSharedMode @@ -110,6 +114,7 @@ Window { } } + //! [certificate_dialogs] FilePicker { id: localCertificatePicker dialogText: qsTr("Local Certificate") @@ -133,7 +138,9 @@ Window { Layout.columnSpan: 2 Layout.fillWidth: true } + //! [certificate_dialogs] + //! [send_request] Button { id: requestButton text: qsTr("Send Request") @@ -155,6 +162,7 @@ Window { .arg(resourceField.text); } } + //! [send_request] Button { id: disconnectButton diff --git a/examples/coap/quicksecureclient/qmlcoapsecureclient.cpp b/examples/coap/quicksecureclient/qmlcoapsecureclient.cpp index a5b40eb..5f7dc18 100644 --- a/examples/coap/quicksecureclient/qmlcoapsecureclient.cpp +++ b/examples/coap/quicksecureclient/qmlcoapsecureclient.cpp @@ -33,6 +33,7 @@ static QString errorMessage(QtCoap::Error errorCode) return QmlCoapSecureClient::tr("Request failed with error: %1\n").arg(error); } +//! [set_security_mode] void QmlCoapSecureClient::setSecurityMode(QtCoap::SecurityMode mode) { // Create a new client, if the security mode has changed @@ -61,7 +62,9 @@ void QmlCoapSecureClient::setSecurityMode(QtCoap::SecurityMode mode) }); } } +//! [set_security_mode] +//! [send_get_request] void QmlCoapSecureClient::sendGetRequest(const QString &host, const QString &path, int port) { if (!m_coapClient) @@ -75,7 +78,9 @@ void QmlCoapSecureClient::sendGetRequest(const QString &host, const QString &pat url.setPort(port); m_coapClient->get(url); } +//! [send_get_request] +//! [set_configuration_psk] void QmlCoapSecureClient::setSecurityConfiguration(const QString &preSharedKey, const QString &identity) { @@ -84,7 +89,9 @@ QmlCoapSecureClient::setSecurityConfiguration(const QString &preSharedKey, const configuration.setPreSharedKeyIdentity(identity.toUtf8()); m_configuration = configuration; } +//! [set_configuration_psk] +//! [set_configuration_cert] void QmlCoapSecureClient::setSecurityConfiguration(const QString &localCertificatePath, const QString &caCertificatePath, const QString &privateKeyPath) @@ -116,9 +123,12 @@ void QmlCoapSecureClient::setSecurityConfiguration(const QString &localCertifica } m_configuration = configuration; } +//! [set_configuration_cert] +//! [disconnect] void QmlCoapSecureClient::disconnect() { if (m_coapClient) m_coapClient->disconnect(); } +//! [disconnect] diff --git a/examples/coap/quicksecureclient/qmlcoapsecureclient.h b/examples/coap/quicksecureclient/qmlcoapsecureclient.h index cd237e0..0b5e1c7 100644 --- a/examples/coap/quicksecureclient/qmlcoapsecureclient.h +++ b/examples/coap/quicksecureclient/qmlcoapsecureclient.h @@ -13,6 +13,7 @@ QT_BEGIN_NAMESPACE class QCoapClient; QT_END_NAMESPACE +//! [coap_client] class QmlCoapSecureClient : public QObject { Q_OBJECT @@ -38,12 +39,15 @@ private: QCoapSecurityConfiguration m_configuration; QtCoap::SecurityMode m_securityMode; }; +//! [coap_client] +//! [coap_namespace] namespace QCoapForeignNamespace { Q_NAMESPACE QML_FOREIGN_NAMESPACE(QtCoap) QML_NAMED_ELEMENT(QtCoap) } +//! [coap_namespace] #endif // QMLCOAPSECURECLIENT_H |