aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2023-06-19 13:17:32 +0200
committerIvan Solovev <ivan.solovev@qt.io>2023-06-22 10:58:48 +0200
commite7cda476e73576edcbb5cfe5c6b0a9029d6a2f51 (patch)
tree7b597d1eec4cb9a5e239e177722978365b718faf /examples
parent967163e3d8fd31e2da77122023bd97ed0880484b (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.qdoc166
-rw-r--r--examples/coap/quicksecureclient/FilePicker.qml2
-rw-r--r--examples/coap/quicksecureclient/Main.qml8
-rw-r--r--examples/coap/quicksecureclient/qmlcoapsecureclient.cpp10
-rw-r--r--examples/coap/quicksecureclient/qmlcoapsecureclient.h4
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