├── .tag ├── examples ├── examples.pro ├── coap │ ├── quickmulticastclient │ │ ├── qmldir │ │ ├── quickmulticastclient.pro │ │ ├── main.cpp │ │ ├── CMakeLists.txt │ │ ├── qmlcoapmulticastclient.h │ │ └── qmlcoapmulticastclient.cpp │ ├── doc │ │ ├── images │ │ │ ├── quicksecureclient.png │ │ │ ├── simplecoapclient.webp │ │ │ └── quickmulticastclient.webp │ │ ├── examples.qdoc │ │ └── simplecoapclient.qdoc │ ├── quicksecureclient │ │ ├── qmldir │ │ ├── quicksecureclient.pro │ │ ├── main.cpp │ │ ├── CMakeLists.txt │ │ ├── FilePicker.qml │ │ ├── qmlcoapsecureclient.h │ │ ├── qmlcoapsecureclient.cpp │ │ └── Main.qml │ ├── coap.pro │ ├── CMakeLists.txt │ └── simplecoapclient │ │ ├── main.cpp │ │ ├── simplecoapclient.pro │ │ ├── optiondialog.h │ │ ├── CMakeLists.txt │ │ ├── mainwindow.h │ │ ├── optiondialog.cpp │ │ └── optiondialog.ui └── CMakeLists.txt ├── .gitreview ├── dependencies.yaml ├── src ├── CMakeLists.txt └── coap │ ├── doc │ ├── src │ │ ├── qtcoap-module-cpp.qdoc │ │ ├── external-resources.qdoc │ │ └── qtcoap-index.qdoc │ ├── qtcoap.qdocconf │ └── style │ │ └── style.css │ ├── qcoapglobal.h │ ├── qcoapresourcediscoveryreply.h │ ├── qcoapoption_p.h │ ├── qcoapnamespace_p.h │ ├── qcoapresourcediscoveryreply_p.h │ ├── qcoapclient_p.h │ ├── CMakeLists.txt │ ├── qcoapresource_p.h │ ├── qcoapresource.h │ ├── qcoaprequest.h │ ├── qcoaprequest_p.h │ ├── qcoapmessage_p.h │ ├── qcoapreply_p.h │ ├── qcoapinternalreply_p.h │ ├── qcoapinternalmessage_p.h │ ├── qcoapreply.h │ ├── qcoapoption.h │ ├── qcoapmessage.h │ ├── qcoapqudpconnection_p.h │ ├── qcoapnamespace.h │ ├── qcoapsecurityconfiguration.h │ ├── qcoapconnection_p.h │ ├── qcoapclient.h │ ├── qcoapinternalrequest_p.h │ ├── qcoapresourcediscoveryreply.cpp │ ├── qcoapprotocol_p.h │ ├── qcoapresource.cpp │ ├── qcoapinternalmessage.cpp │ └── qcoapinternalreply.cpp ├── .cmake.conf ├── dist ├── REUSE.toml ├── changes-5.14.0 ├── changes-5.15.0 ├── changes-5.14.1 ├── changes-5.15.1 └── changes-5.14.2 ├── tests ├── testserver │ ├── freecoap │ │ └── freecoap.sh │ ├── californium │ │ └── californium.sh │ └── docker-compose.yml ├── CMakeLists.txt └── auto │ ├── cmake │ └── CMakeLists.txt │ ├── CMakeLists.txt │ ├── qcoapmessage │ └── CMakeLists.txt │ ├── qcoapoption │ ├── CMakeLists.txt │ └── tst_qcoapoption.cpp │ ├── qcoapclient │ ├── testdata │ │ ├── ca_cert.pem │ │ ├── local_cert.pem │ │ └── privkey.pem │ └── CMakeLists.txt │ ├── qcoapreply │ ├── CMakeLists.txt │ └── tst_qcoapreply.cpp │ ├── qcoaprequest │ ├── CMakeLists.txt │ └── tst_qcoaprequest.cpp │ ├── qcoapresource │ ├── CMakeLists.txt │ └── tst_qcoapresource.cpp │ ├── qcoapinternalreply │ ├── CMakeLists.txt │ └── tst_qcoapinternalreply.cpp │ ├── qcoapinternalrequest │ └── CMakeLists.txt │ ├── qcoapqudpconnection │ ├── CMakeLists.txt │ └── tst_qcoapqudpconnection.cpp │ └── coapnetworksettings.h ├── LICENSES ├── LicenseRef-Qt-Commercial.txt ├── Qt-GPL-exception-1.0.txt └── BSD-3-Clause.txt ├── coin ├── module_config.yaml └── axivion │ └── ci_config_linux.json ├── CMakeLists.txt ├── REUSE.toml ├── README.md └── licenseRule.json /.tag: -------------------------------------------------------------------------------- 1 | 4326d1f972d9907a05131a30b4f01a8bc71c8a1e 2 | -------------------------------------------------------------------------------- /examples/examples.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS += coap 3 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=codereview.qt-project.org 3 | project=qt/qtcoap 4 | defaultbranch=dev 5 | -------------------------------------------------------------------------------- /dependencies.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | ../qtbase: 3 | ref: c17ae1096e0548041150b692b3458de19df2f534 4 | required: true 5 | -------------------------------------------------------------------------------- /examples/coap/quickmulticastclient/qmldir: -------------------------------------------------------------------------------- 1 | module CoapClientModule 2 | prefer :/qt/qml/CoapClientModule/ 3 | Main 1.0 Main.qml 4 | -------------------------------------------------------------------------------- /examples/coap/doc/images/quicksecureclient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcoap/HEAD/examples/coap/doc/images/quicksecureclient.png -------------------------------------------------------------------------------- /examples/coap/doc/images/simplecoapclient.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcoap/HEAD/examples/coap/doc/images/simplecoapclient.webp -------------------------------------------------------------------------------- /examples/coap/doc/images/quickmulticastclient.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcoap/HEAD/examples/coap/doc/images/quickmulticastclient.webp -------------------------------------------------------------------------------- /examples/coap/quicksecureclient/qmldir: -------------------------------------------------------------------------------- 1 | module CoapSecureClientModule 2 | prefer :/qt/qml/CoapSecureClientModule/ 3 | FilePicker 1.0 FilePicker.qml 4 | Main 1.0 Main.qml 5 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | set(QT_SBOM_DEFAULT_QT_LICENSE_ID_LIBRARIES "QT_COMMERCIAL_OR_GPL3") 5 | 6 | add_subdirectory(coap) 7 | -------------------------------------------------------------------------------- /examples/coap/coap.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | qtHaveModule(widgets): SUBDIRS += simplecoapclient 4 | 5 | qtHaveModule(quick) { 6 | SUBDIRS += \ 7 | quicksecureclient \ 8 | quickmulticastclient 9 | } 10 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | qt_examples_build_begin(EXTERNAL_BUILD) 5 | 6 | add_subdirectory(coap) 7 | 8 | qt_examples_build_end() 9 | -------------------------------------------------------------------------------- /.cmake.conf: -------------------------------------------------------------------------------- 1 | set(QT_REPO_MODULE_VERSION "6.12.0") 2 | set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") 3 | set(QT_EXTRA_INTERNAL_TARGET_DEFINES 4 | "QT_NO_CONTEXTLESS_CONNECT=1" 5 | "QT_NO_FOREACH=1" 6 | "QT_NO_QASCONST=1" 7 | "QT_NO_URL_CAST_FROM_STRING=1" 8 | ) 9 | -------------------------------------------------------------------------------- /dist/REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = ["*"] 5 | precedence = "override" 6 | comment = "Licensed as documentation." 7 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 8 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" 9 | -------------------------------------------------------------------------------- /tests/testserver/freecoap/freecoap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (C) 2019 The Qt Company Ltd. 3 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 4 | 5 | set -ex 6 | 7 | (cd /root/src/FreeCoAP/sample/time_server && ./time_server 0.0.0.0 5685 &) 8 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(QT_BUILD_STANDALONE_TESTS) 5 | # Add qt_find_package calls for extra dependencies that need to be found when building 6 | # the standalone tests here. 7 | endif() 8 | qt_build_tests() 9 | -------------------------------------------------------------------------------- /tests/testserver/californium/californium.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (C) 2019 The Qt Company Ltd. 3 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 4 | 5 | set -ex 6 | 7 | java -jar /root/src/californium/demo-apps/run/cf-plugtest-server-3.8.0.jar & 8 | -------------------------------------------------------------------------------- /examples/coap/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | if(TARGET Qt::Widgets) 5 | qt_internal_add_example(simplecoapclient) 6 | endif() 7 | if(TARGET Qt::Quick) 8 | qt_internal_add_example(quicksecureclient) 9 | qt_internal_add_example(quickmulticastclient) 10 | endif() 11 | -------------------------------------------------------------------------------- /examples/coap/simplecoapclient/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "mainwindow.h" 5 | 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | QApplication a(argc, argv); 11 | MainWindow w; 12 | w.show(); 13 | 14 | return a.exec(); 15 | } 16 | -------------------------------------------------------------------------------- /tests/auto/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | 6 | project(qtcoap_cmake_tests) 7 | 8 | enable_testing() 9 | 10 | find_package(Qt6Core REQUIRED) 11 | 12 | include("${_Qt6CTestMacros}") 13 | 14 | _qt_internal_test_module_includes( 15 | Coap QCoapClient 16 | ) 17 | -------------------------------------------------------------------------------- /examples/coap/doc/examples.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \group qtcoap-examples 6 | \title Qt CoAP Examples 7 | \brief List of Qt CoAP examples. 8 | 9 | The Qt CoAP examples demonstrate the functionality provided by the 10 | \l{Qt CoAP} module. 11 | */ 12 | -------------------------------------------------------------------------------- /src/coap/doc/src/qtcoap-module-cpp.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | 5 | /*! 6 | \module QtCoap 7 | \title Qt CoAP C++ Classes 8 | \ingroup modules 9 | \qtcmakepackage Coap 10 | \qtvariable coap 11 | \brief Provides classes to use CoAP protocol. 12 | 13 | The \l{Qt CoAP} page contains information about how to use the module. 14 | */ 15 | -------------------------------------------------------------------------------- /examples/coap/simplecoapclient/simplecoapclient.pro: -------------------------------------------------------------------------------- 1 | QT += core network coap widgets 2 | 3 | TARGET = simplecoapclient 4 | TEMPLATE = app 5 | 6 | SOURCES += \ 7 | main.cpp \ 8 | mainwindow.cpp \ 9 | optiondialog.cpp 10 | 11 | HEADERS += \ 12 | mainwindow.h \ 13 | optiondialog.h 14 | 15 | FORMS += \ 16 | mainwindow.ui \ 17 | optiondialog.ui 18 | 19 | target.path = $$[QT_INSTALL_EXAMPLES]/coap/simplecoapclient 20 | INSTALLS += target 21 | -------------------------------------------------------------------------------- /LICENSES/LicenseRef-Qt-Commercial.txt: -------------------------------------------------------------------------------- 1 | Licensees holding valid commercial Qt licenses may use this software in 2 | accordance with the the terms contained in a written agreement between 3 | you and The Qt Company. Alternatively, the terms and conditions that were 4 | accepted by the licensee when buying and/or downloading the 5 | software do apply. 6 | 7 | For the latest licensing terms and conditions, see https://www.qt.io/terms-conditions. 8 | For further information use the contact form at https://www.qt.io/contact-us. 9 | -------------------------------------------------------------------------------- /coin/module_config.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | accept_configuration: 3 | condition: property 4 | property: features 5 | not_contains_value: Disable 6 | 7 | instructions: 8 | Build: 9 | - type: EnvironmentVariable 10 | variableName: VERIFY_SOURCE_SBOM 11 | variableValue: "ON" 12 | - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml" 13 | 14 | Test: 15 | - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml" 16 | - !include "{{qt/qtbase}}/coin_module_test_docs.yaml" 17 | -------------------------------------------------------------------------------- /src/coap/qcoapglobal.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPGLOBAL_H 7 | #define QCOAPGLOBAL_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | typedef QByteArray QCoapToken; 16 | typedef quint16 QCoapMessageId; 17 | 18 | QT_END_NAMESPACE 19 | 20 | #endif // QCOAPGLOBAL_H 21 | -------------------------------------------------------------------------------- /examples/coap/quickmulticastclient/quickmulticastclient.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += qml quick coap 4 | 5 | CONFIG += qmltypes 6 | QML_IMPORT_NAME = CoapClientModule 7 | QML_IMPORT_MAJOR_VERSION = 1 8 | 9 | SOURCES += \ 10 | main.cpp \ 11 | qmlcoapmulticastclient.cpp 12 | 13 | HEADERS += \ 14 | qmlcoapmulticastclient.h 15 | 16 | qml_resources.files = \ 17 | qmldir \ 18 | Main.qml 19 | 20 | qml_resources.prefix = /qt/qml/CoapClientModule 21 | 22 | RESOURCES += qml_resources 23 | 24 | target.path = $$[QT_INSTALL_EXAMPLES]/coap/quickmulticastclient 25 | INSTALLS += target 26 | -------------------------------------------------------------------------------- /tests/auto/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "QNX") # QTBUG-121487 5 | add_subdirectory(cmake) 6 | endif() 7 | add_subdirectory(qcoapclient) 8 | add_subdirectory(qcoapmessage) 9 | add_subdirectory(qcoapoption) 10 | add_subdirectory(qcoaprequest) 11 | add_subdirectory(qcoapresource) 12 | if(QT_FEATURE_private_tests) 13 | add_subdirectory(qcoapqudpconnection) 14 | add_subdirectory(qcoapinternalrequest) 15 | add_subdirectory(qcoapinternalreply) 16 | add_subdirectory(qcoapreply) 17 | endif() 18 | -------------------------------------------------------------------------------- /examples/coap/quicksecureclient/quicksecureclient.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += qml quick coap 4 | 5 | CONFIG += qmltypes 6 | QML_IMPORT_NAME = CoapSecureClientModule 7 | QML_IMPORT_MAJOR_VERSION = 1 8 | 9 | HEADERS += \ 10 | qmlcoapsecureclient.h 11 | 12 | SOURCES += \ 13 | main.cpp \ 14 | qmlcoapsecureclient.cpp 15 | 16 | qml_resources.files = \ 17 | qmldir \ 18 | FilePicker.qml \ 19 | Main.qml 20 | 21 | qml_resources.prefix = /qt/qml/CoapSecureClientModule 22 | 23 | RESOURCES += qml_resources 24 | 25 | target.path = $$[QT_INSTALL_EXAMPLES]/coap/quicksecureclient 26 | INSTALLS += target 27 | -------------------------------------------------------------------------------- /examples/coap/quickmulticastclient/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | QGuiApplication app(argc, argv); 10 | 11 | QQmlApplicationEngine engine; 12 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, 13 | &app, []() { QCoreApplication::exit(1); }, 14 | Qt::QueuedConnection); 15 | engine.loadFromModule("CoapClientModule", "Main"); 16 | 17 | return app.exec(); 18 | } 19 | -------------------------------------------------------------------------------- /tests/auto/qcoapmessage/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoapmessage Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoapmessage LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | qt_internal_add_test(qcoapmessage 15 | SOURCES 16 | tst_qcoapmessage.cpp 17 | LIBRARIES 18 | Qt::Coap 19 | Qt::Network 20 | ) 21 | -------------------------------------------------------------------------------- /tests/auto/qcoapoption/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoapoption Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoapoption LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | qt_internal_add_test(qcoapoption 15 | SOURCES 16 | tst_qcoapoption.cpp 17 | LIBRARIES 18 | Qt::Coap 19 | Qt::CoapPrivate 20 | ) 21 | -------------------------------------------------------------------------------- /tests/auto/qcoapclient/testdata/ca_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIBrTCCAVOgAwIBAgIMWBtPBCPy5ZOTqJ69MAoGCCqGSM49BAMCMDgxEzARBgNV 3 | BAMTCmR1bW15L3Jvb3QxETAPBgNVBAsTCFNvZnR3YXJlMQ4wDAYDVQQKEwVEdW1t 4 | eTAeFw0xNjExMDMxNDUxNDhaFw0yNjExMDExNDUxNDhaMDgxEzARBgNVBAMTCmR1 5 | bW15L3Jvb3QxETAPBgNVBAsTCFNvZnR3YXJlMQ4wDAYDVQQKEwVEdW1teTBZMBMG 6 | ByqGSM49AgEGCCqGSM49AwEHA0IABMJ6XvBwMC3sZRyBatX95w+/AieUhN1cNfWI 7 | Uc4HA0IXp+WwDN7QXd7mm1FDV/wQmNx/y2MJ7OQMJUvSozRPpfKjQzBBMA8GA1Ud 8 | EwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4EFgQUsib+R29JtRKp 9 | G6duvLrDjM8PySUwCgYIKoZIzj0EAwIDSAAwRQIgQC6ZVZi6sXnYypt1CKlDSS2Q 10 | W+CV62TyOdE9j9phNfECIQDno7uEc8sXHnwkCcfuZhFVAkEfE8KBPhEF7ZmqJz5c 11 | BQ== 12 | -----END CERTIFICATE----- 13 | -------------------------------------------------------------------------------- /tests/auto/qcoapreply/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoapreply Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoapreply LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | qt_internal_add_test(qcoapreply 15 | SOURCES 16 | tst_qcoapreply.cpp 17 | LIBRARIES 18 | Qt::Coap 19 | Qt::CoapPrivate 20 | Qt::Network 21 | ) 22 | -------------------------------------------------------------------------------- /tests/auto/qcoaprequest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoaprequest Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoaprequest LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | qt_internal_add_test(qcoaprequest 15 | SOURCES 16 | tst_qcoaprequest.cpp 17 | LIBRARIES 18 | Qt::Coap 19 | Qt::CoapPrivate 20 | Qt::Network 21 | ) 22 | -------------------------------------------------------------------------------- /tests/auto/qcoapresource/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoapresource Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoapresource LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | qt_internal_add_test(qcoapresource 15 | SOURCES 16 | tst_qcoapresource.cpp 17 | LIBRARIES 18 | Qt::Coap 19 | Qt::CoapPrivate 20 | Qt::Network 21 | ) 22 | -------------------------------------------------------------------------------- /tests/auto/qcoapinternalreply/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoapinternalreply Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoapinternalreply LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | qt_internal_add_test(qcoapinternalreply 15 | SOURCES 16 | tst_qcoapinternalreply.cpp 17 | LIBRARIES 18 | Qt::Coap 19 | Qt::CoapPrivate 20 | Qt::Network 21 | ) 22 | -------------------------------------------------------------------------------- /tests/auto/qcoapinternalrequest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoapinternalrequest Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoapinternalrequest LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | qt_internal_add_test(qcoapinternalrequest 15 | SOURCES 16 | tst_qcoapinternalrequest.cpp 17 | LIBRARIES 18 | Qt::Coap 19 | Qt::CoapPrivate 20 | Qt::Network 21 | ) 22 | -------------------------------------------------------------------------------- /dist/changes-5.14.0: -------------------------------------------------------------------------------- 1 | Qt 5.14 introduces many new features and improvements as well as bugfixes 2 | over the 5.13.x series. For more details, refer to the online documentation 3 | included in this distribution. The documentation is also available online: 4 | 5 | https://doc.qt.io/qt-5/index.html 6 | 7 | The Qt version 5.14 series is binary compatible with the 5.13.x series. 8 | Applications compiled for 5.13 will continue to run with 5.14. 9 | 10 | Some of the changes listed in this file include issue tracking numbers 11 | corresponding to tasks in the Qt Bug Tracker: 12 | 13 | https://bugreports.qt.io/ 14 | 15 | Each of these identifiers can be entered in the bug tracker to obtain more 16 | information about a particular change. 17 | 18 | - This release contains only minor code improvements. 19 | -------------------------------------------------------------------------------- /dist/changes-5.15.0: -------------------------------------------------------------------------------- 1 | Qt 5.15 introduces many new features and improvements as well as bugfixes 2 | over the 5.14.x series. For more details, refer to the online documentation 3 | included in this distribution. The documentation is also available online: 4 | 5 | https://doc.qt.io/qt-5/index.html 6 | 7 | The Qt version 5.15 series is binary compatible with the 5.14.x series. 8 | Applications compiled for 5.14 will continue to run with 5.15. 9 | 10 | Some of the changes listed in this file include issue tracking numbers 11 | corresponding to tasks in the Qt Bug Tracker: 12 | 13 | https://bugreports.qt.io/ 14 | 15 | Each of these identifiers can be entered in the bug tracker to obtain more 16 | information about a particular change. 17 | 18 | - This release contains only minor code improvements. 19 | -------------------------------------------------------------------------------- /tests/auto/qcoapclient/testdata/local_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB4jCCAYigAwIBAgIMWBtPBCa+RXwaSLCOMAoGCCqGSM49BAMCMDgxEzARBgNV 3 | BAMTCmR1bW15L3Jvb3QxETAPBgNVBAsTCFNvZnR3YXJlMQ4wDAYDVQQKEwVEdW1t 4 | eTAeFw0xNjExMDMxNDUxNDhaFw0yNjExMDExNDUxNDhaMDoxFTATBgNVBAMTDGR1 5 | bW15L2NsaWVudDERMA8GA1UECxMIU29mdHdhcmUxDjAMBgNVBAoTBUR1bW15MFkw 6 | EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcrIeFXrfmAu/fiT49ToNubG6u/w5GAQb 7 | xI0V7vmFCxFSn4ttoPfEUMlUKCTFYc6HbzmFgUjct1KFGBuAfZ13M6N2MHQwDAYD 8 | VR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAjAPBgNVHQ8BAf8EBQMDB4AA 9 | MB0GA1UdDgQWBBSc2q9vjtlLW1IUSzDa9X2qnJYU1DAfBgNVHSMEGDAWgBQEbS8W 10 | F1883YRUvUnCBnkSs/NhmjAKBggqhkjOPQQDAgNIADBFAiEA9fZYVTMn9My9erGO 11 | j5tFYsGj4A7CkWHFRj50KirZN4ECIFLEmt5SbmipqFdkiRBxkjkJEMYC+iLBeMqI 12 | Cgi5tYDF 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /dist/changes-5.14.1: -------------------------------------------------------------------------------- 1 | Qt 5.14.1 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.14.0. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.14 series is binary compatible with the 5.13.x series. 10 | Applications compiled for 5.13 will continue to run with 5.14. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.15.1: -------------------------------------------------------------------------------- 1 | Qt 5.15.1 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.15.0. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.15 series is binary compatible with the 5.14.x series. 10 | Applications compiled for 5.14 will continue to run with 5.15. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.14.2: -------------------------------------------------------------------------------- 1 | Qt 5.14.2 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.14.0 through 5.14.1. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.14 series is binary compatible with the 5.13.x series. 10 | Applications compiled for 5.13 will continue to run with 5.14. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | 6 | include(.cmake.conf) 7 | project(QtCoap 8 | VERSION "${QT_REPO_MODULE_VERSION}" 9 | DESCRIPTION "Qt Coap Libraries" 10 | HOMEPAGE_URL "https://qt.io/" 11 | LANGUAGES CXX 12 | ) 13 | 14 | find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals) 15 | 16 | # This should be called as early as possible, just after find_package(BuildInternals) where it is 17 | # defined. 18 | qt_internal_project_setup() 19 | 20 | find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core Network) 21 | find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Gui Widgets Quick Qml) 22 | 23 | if(NOT QT_FEATURE_udpsocket) 24 | message(NOTICE "UDP socket support is required for QtCoap, skipping module") 25 | return() 26 | endif() 27 | 28 | qt_build_repo() 29 | -------------------------------------------------------------------------------- /examples/coap/simplecoapclient/optiondialog.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef OPTIONDIALOG_H 5 | #define OPTIONDIALOG_H 6 | 7 | #include 8 | #include 9 | 10 | QT_BEGIN_NAMESPACE 11 | namespace Ui { 12 | class OptionDialog; 13 | } 14 | QT_END_NAMESPACE 15 | 16 | class OptionDialog : public QDialog 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit OptionDialog(const QList &options, QWidget *parent = nullptr); 22 | ~OptionDialog(); 23 | 24 | QList options() const; 25 | 26 | private slots: 27 | void on_addButton_clicked(); 28 | void on_clearButton_clicked(); 29 | void on_removeButton_clicked(); 30 | 31 | private: 32 | void fillOptions(); 33 | void applyOptionValues(); 34 | void addTableRow(const QString &name, const QString &value); 35 | 36 | Ui::OptionDialog *ui; 37 | QList m_options; 38 | }; 39 | 40 | #endif // OPTIONDIALOG_H 41 | -------------------------------------------------------------------------------- /LICENSES/Qt-GPL-exception-1.0.txt: -------------------------------------------------------------------------------- 1 | The Qt Company GPL Exception 1.0 2 | 3 | Exception 1: 4 | 5 | As a special exception you may create a larger work which contains the 6 | output of this application and distribute that work under terms of your 7 | choice, so long as the work is not otherwise derived from or based on 8 | this application and so long as the work does not in itself generate 9 | output that contains the output from this application in its original 10 | or modified form. 11 | 12 | Exception 2: 13 | 14 | As a special exception, you have permission to combine this application 15 | with Plugins licensed under the terms of your choice, to produce an 16 | executable, and to copy and distribute the resulting executable under 17 | the terms of your choice. However, the executable must be accompanied 18 | by a prominent notice offering all users of the executable the entire 19 | source code to this application, excluding the source code of the 20 | independent modules, but including any changes you have made to this 21 | application, under the terms of this license. 22 | 23 | -------------------------------------------------------------------------------- /src/coap/qcoapresourcediscoveryreply.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPRESOURCEDISCOVERYREPLY_H 7 | #define QCOAPRESOURCEDISCOVERYREPLY_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QCoapResourceDiscoveryReplyPrivate; 16 | class Q_COAP_EXPORT QCoapResourceDiscoveryReply : public QCoapReply 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | QList resources() const; 22 | 23 | Q_SIGNALS: 24 | void discovered(QCoapResourceDiscoveryReply *reply, QList resources); 25 | 26 | private: 27 | explicit QCoapResourceDiscoveryReply(const QCoapRequest &request, QObject *parent = nullptr); 28 | friend class QCoapClientPrivate; 29 | 30 | Q_DECLARE_PRIVATE(QCoapResourceDiscoveryReply) 31 | }; 32 | 33 | QT_END_NAMESPACE 34 | 35 | #endif // QCOAPRESOURCEDISCOVERYREPLY_H 36 | -------------------------------------------------------------------------------- /src/coap/qcoapoption_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPOPTION_P_H 7 | #define QCOAPOPTION_P_H 8 | 9 | #include 10 | #include 11 | 12 | // 13 | // W A R N I N G 14 | // ------------- 15 | // 16 | // This file is not part of the Qt API. It exists purely as an 17 | // implementation detail. This header file may change from version to 18 | // version without notice, or even be removed. 19 | // 20 | // We mean it. 21 | // 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | class Q_AUTOTEST_EXPORT QCoapOptionPrivate 26 | { 27 | public: 28 | QCoapOptionPrivate() = default; 29 | 30 | void setValue(const QByteArray &opaqueValue); 31 | void setValue(const QString &value); 32 | void setValue(quint32 value); 33 | 34 | QCoapOption::OptionName name = QCoapOption::Invalid; 35 | QByteArray value; 36 | }; 37 | 38 | QT_END_NAMESPACE 39 | 40 | #endif // QCOAPOPTION_P_H 41 | -------------------------------------------------------------------------------- /src/coap/qcoapnamespace_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 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 | #ifndef QCOAPNAMESPACE_P_H 6 | #define QCOAPNAMESPACE_P_H 7 | 8 | #include "qcoapnamespace.h" 9 | #include "private/qglobal_p.h" 10 | #include 11 | 12 | 13 | // 14 | // W A R N I N G 15 | // ------------- 16 | // 17 | // This file is not part of the Qt API. It exists purely as an 18 | // implementation detail. This header file may change from version to 19 | // version without notice, or even be removed. 20 | // 21 | // We mean it. 22 | // 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | Q_DECLARE_LOGGING_CATEGORY(lcCoapExchange) 27 | Q_DECLARE_LOGGING_CATEGORY(lcCoapConnection) 28 | 29 | namespace QtCoap 30 | { 31 | bool Q_AUTOTEST_EXPORT isError(QtCoap::ResponseCode code); 32 | Error Q_AUTOTEST_EXPORT errorForResponseCode(QtCoap::ResponseCode code); 33 | QRandomGenerator Q_AUTOTEST_EXPORT &randomGenerator(); 34 | } 35 | 36 | QT_END_NAMESPACE 37 | 38 | #endif // QCOAPNAMESPACE_P_H 39 | -------------------------------------------------------------------------------- /src/coap/doc/src/external-resources.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \externalpage https://coap.technology/ 6 | \title CoAP 7 | */ 8 | 9 | /*! 10 | \externalpage https://datatracker.ietf.org/doc/html/rfc7252 11 | \title RFC 7252 12 | */ 13 | 14 | /*! 15 | \externalpage https://datatracker.ietf.org/doc/html/rfc7390 16 | \title RFC 7390 17 | */ 18 | 19 | /*! 20 | \externalpage https://datatracker.ietf.org/doc/html/rfc7959 21 | \title RFC 7959 22 | */ 23 | 24 | /*! 25 | \externalpage https://datatracker.ietf.org/doc/html/rfc7641 26 | \title RFC 7641 27 | */ 28 | 29 | /*! 30 | \externalpage https://datatracker.ietf.org/doc/html/rfc7390#section-2.5 31 | \title RFC 7390 - Section 2.5 32 | */ 33 | 34 | /*! 35 | \externalpage https://datatracker.ietf.org/doc/html/rfc7252#section-4.2 36 | \title RFC 7252 - Section 4.2 37 | */ 38 | 39 | /*! 40 | \externalpage https://www.iana.org/assignments/core-parameters/core-parameters.xhtml#content-formats 41 | \title CoAP Content-Formats Registry 42 | */ 43 | -------------------------------------------------------------------------------- /tests/auto/qcoapclient/testdata/privkey.pem: -------------------------------------------------------------------------------- 1 | Public Key Info: 2 | Public Key Algorithm: EC/ECDSA 3 | Key Security Level: High (256 bits) 4 | 5 | curve: SECP256R1 6 | private key: 7 | 00:f7:ea:23:23:78:12:38:e3:8f:e0:2b:05:72:2f:6a 8 | 24:91:a0:54:c6:3d:ed:68:ce:6e:60:8d:0f:fd:9f:39 9 | c6: 10 | 11 | x: 12 | 72:b2:1e:15:7a:df:98:0b:bf:7e:24:f8:f5:3a:0d:b9 13 | b1:ba:bb:fc:39:18:04:1b:c4:8d:15:ee:f9:85:0b:11 14 | 15 | 16 | y: 17 | 52:9f:8b:6d:a0:f7:c4:50:c9:54:28:24:c5:61:ce:87 18 | 6f:39:85:81:48:dc:b7:52:85:18:1b:80:7d:9d:77:33 19 | 20 | 21 | 22 | Public Key ID: 9C:DA:AF:6F:8E:D9:4B:5B:52:14:4B:30:DA:F5:7D:AA:9C:96:14:D4 23 | Public key's random art: 24 | +--[SECP256R1]----+ 25 | | o.=. | 26 | | o = +E. | 27 | | . . + . o| 28 | | . . . . ..| 29 | | S o . | 30 | | o + + | 31 | | . . o B | 32 | | *.= | 33 | | +=B. | 34 | +-----------------+ 35 | 36 | -----BEGIN EC PRIVATE KEY----- 37 | MHgCAQEEIQD36iMjeBI444/gKwVyL2okkaBUxj3taM5uYI0P/Z85xqAKBggqhkjO 38 | PQMBB6FEA0IABHKyHhV635gLv34k+PU6Dbmxurv8ORgEG8SNFe75hQsRUp+LbaD3 39 | xFDJVCgkxWHOh285hYFI3LdShRgbgH2ddzM= 40 | -----END EC PRIVATE KEY----- 41 | -------------------------------------------------------------------------------- /examples/coap/simplecoapclient/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(simplecoapclient LANGUAGES CXX) 6 | 7 | if(NOT DEFINED INSTALL_EXAMPLESDIR) 8 | set(INSTALL_EXAMPLESDIR "examples") 9 | endif() 10 | 11 | set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/coap/simplecoapclient") 12 | 13 | find_package(Qt6 REQUIRED COMPONENTS Coap Core Gui Network Widgets) 14 | 15 | qt_standard_project_setup() 16 | 17 | qt_add_executable(simplecoapclient 18 | main.cpp 19 | mainwindow.cpp mainwindow.h mainwindow.ui 20 | optiondialog.cpp optiondialog.h optiondialog.ui 21 | ) 22 | 23 | set_target_properties(simplecoapclient PROPERTIES 24 | WIN32_EXECUTABLE TRUE 25 | MACOSX_BUNDLE TRUE 26 | ) 27 | 28 | target_link_libraries(simplecoapclient PRIVATE 29 | Qt6::Coap 30 | Qt6::Core 31 | Qt6::Gui 32 | Qt6::Network 33 | Qt6::Widgets 34 | ) 35 | 36 | install(TARGETS simplecoapclient 37 | RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" 38 | BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" 39 | LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" 40 | ) 41 | -------------------------------------------------------------------------------- /coin/axivion/ci_config_linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "BuildSystemIntegration": { 4 | "child_order": [ 5 | "GCCSetup", 6 | "CMake", 7 | "LinkLibraries" 8 | ] 9 | }, 10 | "CMake": { 11 | "_active": true, 12 | "_copy_from": "CMakeIntegration", 13 | "build_environment": {}, 14 | "build_options": "-j4", 15 | "generate_options": "--fresh", 16 | "generator": "Ninja" 17 | }, 18 | "GCCSetup": { 19 | "_active": true, 20 | "_copy_from": "Command", 21 | "build_command": "gccsetup --cc gcc --cxx g++ --config ../../../axivion/" 22 | }, 23 | "LinkLibraries": { 24 | "_active": true, 25 | "_copy_from": "AxivionLinker", 26 | "input_files": [ 27 | "build/lib/lib*.so*.ir" 28 | ], 29 | "ir": "build/$(env:TESTED_MODULE_COIN).ir" 30 | } 31 | }, 32 | "_Format": "1.0", 33 | "_Version": "7.6.2", 34 | "_VersionNum": [ 35 | 7, 36 | 6, 37 | 2, 38 | 12725 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /examples/coap/quicksecureclient/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace Qt::StringLiterals; 10 | 11 | static QStringList availableHosts() 12 | { 13 | QStringList hosts; 14 | 15 | const auto networkInterfaces = QNetworkInterface::allInterfaces(); 16 | for (const auto &interface : networkInterfaces) 17 | for (const auto &address : interface.addressEntries()) 18 | hosts.push_back(address.ip().toString()); 19 | 20 | return hosts; 21 | } 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | QGuiApplication app(argc, argv); 26 | QQmlApplicationEngine engine; 27 | engine.setInitialProperties({{u"hostsModel"_s, availableHosts()}}); 28 | 29 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, 30 | &app, []() { QCoreApplication::exit(1); }, 31 | Qt::QueuedConnection); 32 | engine.loadFromModule("CoapSecureClientModule", "Main"); 33 | 34 | return app.exec(); 35 | } 36 | -------------------------------------------------------------------------------- /tests/auto/qcoapclient/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoapclient Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoapclient LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | set (QT_TESTSERVER_COMPOSE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../../testserver/docker-compose.yml") 15 | 16 | qt_internal_add_test(qcoapclient 17 | EXCEPTIONS 18 | GUI 19 | SOURCES 20 | ../coapnetworksettings.h 21 | tst_qcoapclient.cpp 22 | LIBRARIES 23 | Qt::Coap 24 | Qt::CoapPrivate 25 | Qt::Network 26 | QT_TEST_SERVER_LIST "californium" "freecoap" 27 | ) 28 | 29 | ## Scopes: 30 | ##################################################################### 31 | 32 | qt_internal_extend_target(qcoapclient CONDITION DEFINED ENV{COAP_TEST_SERVER_IP} 33 | DEFINES 34 | COAP_TEST_SERVER_IP="$ENV{COAP_TEST_SERVER_IP}" 35 | ) 36 | -------------------------------------------------------------------------------- /tests/auto/qcoapqudpconnection/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## qcoapqudpconnection Test: 6 | ##################################################################### 7 | 8 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 9 | cmake_minimum_required(VERSION 3.16) 10 | project(qcoapqudpconnection LANGUAGES CXX) 11 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 12 | endif() 13 | 14 | set (QT_TESTSERVER_COMPOSE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../../testserver/docker-compose.yml") 15 | 16 | qt_internal_add_test(qcoapqudpconnection 17 | SOURCES 18 | ../coapnetworksettings.h 19 | tst_qcoapqudpconnection.cpp 20 | LIBRARIES 21 | Qt::Coap 22 | Qt::CoapPrivate 23 | Qt::Network 24 | QT_TEST_SERVER_LIST "californium" 25 | ) 26 | 27 | ## Scopes: 28 | ##################################################################### 29 | 30 | qt_internal_extend_target(qcoapqudpconnection CONDITION DEFINED ENV{COAP_TEST_SERVER_IP} 31 | DEFINES 32 | COAP_TEST_SERVER_IP="$ENV{COAP_TEST_SERVER_IP}" 33 | ) 34 | -------------------------------------------------------------------------------- /examples/coap/quicksecureclient/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(quicksecureclient LANGUAGES CXX) 6 | 7 | if(NOT DEFINED INSTALL_EXAMPLESDIR) 8 | set(INSTALL_EXAMPLESDIR "examples") 9 | endif() 10 | 11 | set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/coap/quicksecureclient") 12 | 13 | find_package(Qt6 REQUIRED COMPONENTS Coap Core Gui Qml Quick) 14 | 15 | qt_standard_project_setup(REQUIRES 6.5) 16 | 17 | qt_add_executable(quicksecureclient 18 | main.cpp 19 | ) 20 | 21 | set_target_properties(quicksecureclient PROPERTIES 22 | WIN32_EXECUTABLE TRUE 23 | MACOSX_BUNDLE TRUE 24 | ) 25 | 26 | target_link_libraries(quicksecureclient PRIVATE 27 | Qt6::Coap 28 | Qt6::Core 29 | Qt6::Gui 30 | Qt6::Qml 31 | Qt6::Quick 32 | ) 33 | 34 | qt_add_qml_module(quicksecureclient 35 | URI CoapSecureClientModule 36 | SOURCES 37 | qmlcoapsecureclient.cpp qmlcoapsecureclient.h 38 | QML_FILES 39 | FilePicker.qml 40 | Main.qml 41 | ) 42 | 43 | install(TARGETS quicksecureclient 44 | RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" 45 | BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" 46 | LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" 47 | ) 48 | -------------------------------------------------------------------------------- /examples/coap/quickmulticastclient/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(quickmulticastclient LANGUAGES CXX) 6 | 7 | if(NOT DEFINED INSTALL_EXAMPLESDIR) 8 | set(INSTALL_EXAMPLESDIR "examples") 9 | endif() 10 | 11 | set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/coap/quickmulticastclient") 12 | 13 | find_package(Qt6 REQUIRED COMPONENTS Coap Core Gui Qml Quick) 14 | 15 | qt_standard_project_setup(REQUIRES 6.5) 16 | 17 | qt_add_executable(quickmulticastclient 18 | main.cpp 19 | ) 20 | 21 | set_target_properties(quickmulticastclient PROPERTIES 22 | WIN32_EXECUTABLE TRUE 23 | MACOSX_BUNDLE TRUE 24 | ) 25 | 26 | target_link_libraries(quickmulticastclient PRIVATE 27 | Qt6::Coap 28 | Qt6::Core 29 | Qt6::Gui 30 | Qt6::Qml 31 | Qt6::Quick 32 | ) 33 | 34 | qt_add_qml_module(quickmulticastclient 35 | URI CoapClientModule 36 | VERSION 1.0 37 | SOURCES 38 | qmlcoapmulticastclient.cpp qmlcoapmulticastclient.h 39 | QML_FILES 40 | Main.qml 41 | ) 42 | 43 | install(TARGETS quickmulticastclient 44 | RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" 45 | BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" 46 | LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" 47 | ) 48 | -------------------------------------------------------------------------------- /examples/coap/quicksecureclient/FilePicker.qml: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | import QtCore 5 | import QtQuick 6 | import QtQuick.Dialogs 7 | import QtQuick.Controls 8 | import QtQuick.Layouts 9 | 10 | //! [filepicker] 11 | Item { 12 | id: filePicker 13 | 14 | property string dialogText 15 | property alias selectedFile: filePathField.text 16 | 17 | height: addFileButton.height 18 | 19 | FileDialog { 20 | id: fileDialog 21 | title: qsTr("Please Choose %1").arg(filePicker.dialogText) 22 | currentFolder: StandardPaths.writableLocation(StandardPaths.HomeLocation) 23 | fileMode: FileDialog.OpenFile 24 | onAccepted: filePathField.text = fileDialog.selectedFile 25 | } 26 | 27 | RowLayout { 28 | anchors.fill: parent 29 | TextField { 30 | id: filePathField 31 | placeholderText: qsTr("<%1>").arg(filePicker.dialogText) 32 | inputMethodHints: Qt.ImhUrlCharactersOnly 33 | selectByMouse: true 34 | Layout.fillWidth: true 35 | } 36 | 37 | Button { 38 | id: addFileButton 39 | text: qsTr("Add %1").arg(filePicker.dialogText) 40 | onClicked: fileDialog.open() 41 | } 42 | } 43 | } 44 | //! [filepicker] 45 | -------------------------------------------------------------------------------- /src/coap/qcoapresourcediscoveryreply_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPRESOURCEDISCOVERYREPLY_P_H 7 | #define QCOAPRESOURCEDISCOVERYREPLY_P_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // 15 | // W A R N I N G 16 | // ------------- 17 | // 18 | // This file is not part of the Qt API. It exists purely as an 19 | // implementation detail. This header file may change from version to 20 | // version without notice, or even be removed. 21 | // 22 | // We mean it. 23 | // 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class Q_AUTOTEST_EXPORT QCoapResourceDiscoveryReplyPrivate : public QCoapReplyPrivate 28 | { 29 | public: 30 | QCoapResourceDiscoveryReplyPrivate(const QCoapRequest &request); 31 | 32 | void _q_setContent(const QHostAddress &sender, const QCoapMessage &, QtCoap::ResponseCode) override; 33 | 34 | static QList resourcesFromCoreLinkList( 35 | const QHostAddress &sender, const QByteArray &data); 36 | 37 | QList resources; 38 | 39 | Q_DECLARE_PUBLIC(QCoapResourceDiscoveryReply) 40 | }; 41 | 42 | QT_END_NAMESPACE 43 | 44 | #endif // QCOAPRESOURCEDISCOVERYREPLY_P_H 45 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) . 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /src/coap/qcoapclient_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPCLIENT_P_H 7 | #define QCOAPCLIENT_P_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // 15 | // W A R N I N G 16 | // ------------- 17 | // 18 | // This file is not part of the Qt API. It exists purely as an 19 | // implementation detail. This header file may change from version to 20 | // version without notice, or even be removed. 21 | // 22 | // We mean it. 23 | // 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class Q_AUTOTEST_EXPORT QCoapClientPrivate : public QObjectPrivate 28 | { 29 | public: 30 | QCoapClientPrivate(QCoapProtocol *protocol, QCoapConnection *connection); 31 | ~QCoapClientPrivate(); 32 | 33 | QCoapProtocol *protocol = nullptr; 34 | QCoapConnection *connection = nullptr; 35 | QThread *workerThread = nullptr; 36 | #if QT_CONFIG(networkinterface) 37 | QNetworkInterface interface; 38 | #endif 39 | 40 | QCoapReply *sendRequest(const QCoapRequest &request); 41 | QCoapResourceDiscoveryReply *sendDiscovery(const QCoapRequest &request); 42 | bool send(QCoapReply *reply); 43 | 44 | void setConnection(QCoapConnection *customConnection); 45 | 46 | Q_DECLARE_PUBLIC(QCoapClient) 47 | }; 48 | 49 | QT_END_NAMESPACE 50 | 51 | #endif // QCOAPCLIENT_P_H 52 | -------------------------------------------------------------------------------- /src/coap/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ##################################################################### 5 | ## Coap Module: 6 | ##################################################################### 7 | 8 | qt_internal_add_module(Coap 9 | SOURCES 10 | qcoapclient.cpp qcoapclient.h qcoapclient_p.h 11 | qcoapconnection.cpp qcoapconnection_p.h 12 | qcoapglobal.h 13 | qcoapinternalmessage.cpp qcoapinternalmessage_p.h 14 | qcoapinternalreply.cpp qcoapinternalreply_p.h 15 | qcoapinternalrequest.cpp qcoapinternalrequest_p.h 16 | qcoapmessage.cpp qcoapmessage.h qcoapmessage_p.h 17 | qcoapnamespace.cpp qcoapnamespace.h qcoapnamespace_p.h 18 | qcoapoption.cpp qcoapoption.h qcoapoption_p.h 19 | qcoapprotocol.cpp qcoapprotocol_p.h 20 | qcoapqudpconnection.cpp qcoapqudpconnection_p.h 21 | qcoapreply.cpp qcoapreply.h qcoapreply_p.h 22 | qcoaprequest.cpp qcoaprequest.h qcoaprequest_p.h 23 | qcoapresource.cpp qcoapresource.h qcoapresource_p.h 24 | qcoapresourcediscoveryreply.cpp qcoapresourcediscoveryreply.h qcoapresourcediscoveryreply_p.h 25 | qcoapsecurityconfiguration.cpp qcoapsecurityconfiguration.h 26 | LIBRARIES 27 | Qt::CorePrivate 28 | Qt::NetworkPrivate 29 | PUBLIC_LIBRARIES 30 | Qt::Core 31 | PRIVATE_MODULE_INTERFACE 32 | Qt::CorePrivate 33 | Qt::NetworkPrivate 34 | ) 35 | qt_internal_add_docs(Coap 36 | doc/qtcoap.qdocconf 37 | ) 38 | -------------------------------------------------------------------------------- /src/coap/qcoapresource_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPRESOURCE_P_H 7 | #define QCOAPRESOURCE_P_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // 15 | // W A R N I N G 16 | // ------------- 17 | // 18 | // This file is not part of the Qt API. It exists purely as an 19 | // implementation detail. This header file may change from version to 20 | // version without notice, or even be removed. 21 | // 22 | // We mean it. 23 | // 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class Q_AUTOTEST_EXPORT QCoapResourcePrivate : public QSharedData 28 | { 29 | public: 30 | QCoapResourcePrivate() {} 31 | QCoapResourcePrivate(const QCoapResourcePrivate &other) 32 | : QSharedData(other), maximumSize(other.maximumSize), contentFormat(other.contentFormat) 33 | , resourceType(other.resourceType), interface(other.interface), host(other.host) 34 | , path(other.path), title(other.title), observable(other.observable) {} 35 | ~QCoapResourcePrivate() {} 36 | 37 | int maximumSize = -1; // sz field 38 | uint contentFormat = 0; // ct field 39 | QString resourceType; // rt field 40 | QString interface; // if field 41 | QHostAddress host; 42 | QString path; 43 | QString title; 44 | bool observable = false; // obs field 45 | }; 46 | 47 | QT_END_NAMESPACE 48 | 49 | #endif // QCOAPRESOURCE_P_H 50 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = ["**/.gitattributes", "**.gitignore", "**.gitreview"] 5 | precedence = "closest" 6 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 7 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 8 | 9 | [[annotations]] 10 | path = [".tag", ".cmake.conf", "**.yaml", "**.yml", "**ci_config_linux.json"] 11 | precedence = "closest" 12 | comment = "build system" 13 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 14 | SPDX-License-Identifier = "BSD-3-Clause" 15 | 16 | [[annotations]] 17 | path = ["examples/**"] 18 | comment = "this must be after the build system table because example and snippets take precedence over build system" 19 | precedence = "closest" 20 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 21 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 22 | 23 | [[annotations]] 24 | path = ["**/README*", "**.qdocconf", "src/coap/doc/style/style.css"] 25 | comment = "documentation" 26 | precedence = "closest" 27 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 28 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" 29 | 30 | [[annotations]] 31 | path = ["**.toml", "licenseRule.json"] 32 | precedence = "override" 33 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 34 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 35 | 36 | [[annotations]] 37 | path = ["**.pem"] 38 | precedence = "override" 39 | comment = "License file. Or such. To be confirmed for .pem files" 40 | SPDX-FileCopyrightText = "None" 41 | SPDX-License-Identifier = "CC0-1.0" 42 | 43 | -------------------------------------------------------------------------------- /examples/coap/simplecoapclient/mainwindow.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef MAINWINDOW_H 5 | #define MAINWINDOW_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | namespace Ui { 14 | class MainWindow; 15 | } 16 | class QCoapClient; 17 | class QCoapResourceDiscoveryReply; 18 | class QCoapMessage; 19 | class QCoapReply; 20 | QT_END_NAMESPACE 21 | 22 | class MainWindow : public QMainWindow 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit MainWindow(QWidget *parent = nullptr); 28 | ~MainWindow(); 29 | 30 | private: 31 | void fillHostSelector(); 32 | void addMessage(const QString &message, bool isError = false); 33 | 34 | private slots: 35 | void onFinished(QCoapReply *reply); 36 | void onError(QCoapReply *reply, QtCoap::Error error); 37 | void onDiscovered(QCoapResourceDiscoveryReply *reply, QList resources); 38 | void onNotified(QCoapReply *reply, const QCoapMessage &message); 39 | 40 | void on_runButton_clicked(); 41 | void on_discoverButton_clicked(); 42 | void on_observeButton_clicked(); 43 | void on_addOptionsButton_clicked(); 44 | void on_contentButton_clicked(); 45 | void on_resourceComboBox_editTextChanged(const QString &text); 46 | void on_methodComboBox_currentIndexChanged(int index); 47 | 48 | private: 49 | Ui::MainWindow *ui; 50 | QCoapClient *m_client; 51 | QList m_options; 52 | QByteArray m_currentData; 53 | }; 54 | 55 | #endif // MAINWINDOW_H 56 | -------------------------------------------------------------------------------- /src/coap/qcoapresource.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPRESOURCE_H 7 | #define QCOAPRESOURCE_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef interface 14 | # undef interface 15 | #endif 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | class QCoapResourcePrivate; 20 | 21 | class Q_COAP_EXPORT QCoapResource 22 | { 23 | public: 24 | QCoapResource(); 25 | QCoapResource(const QCoapResource &other); 26 | ~QCoapResource(); 27 | QCoapResource &operator =(const QCoapResource &other); 28 | 29 | void swap(QCoapResource &other) noexcept; 30 | 31 | QHostAddress host() const; 32 | QString path() const; 33 | QString title() const; 34 | bool observable() const; 35 | QString resourceType() const; 36 | QString interface() const; 37 | int maximumSize() const; 38 | uint contentFormat() const; 39 | 40 | void setHost(const QHostAddress &host); 41 | void setPath(const QString &path); 42 | void setTitle(const QString &title); 43 | void setObservable(bool observable); 44 | void setResourceType(const QString &resourceType); 45 | void setInterface(const QString &interface); 46 | void setMaximumSize(int maximumSize); 47 | void setContentFormat(uint contentFormat); 48 | 49 | private: 50 | QSharedDataPointer d; 51 | }; 52 | 53 | Q_DECLARE_SHARED(QCoapResource) 54 | 55 | QT_END_NAMESPACE 56 | 57 | #endif // QCOAPRESOURCE_H 58 | -------------------------------------------------------------------------------- /src/coap/qcoaprequest.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPREQUEST_H 7 | #define QCOAPREQUEST_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class QCoapInternalRequest; 19 | class QCoapRequestPrivate; 20 | class Q_COAP_EXPORT QCoapRequest : public QCoapMessage 21 | { 22 | public: 23 | explicit QCoapRequest(const QUrl &url = QUrl(), 24 | Type type = Type::NonConfirmable, 25 | const QUrl &proxyUrl = QUrl()); 26 | explicit QCoapRequest(const char* url, Type type = Type::NonConfirmable); 27 | QCoapRequest(const QCoapRequest &other); 28 | ~QCoapRequest(); 29 | 30 | QCoapRequest &operator=(const QCoapRequest &other); 31 | 32 | QUrl url() const; 33 | QUrl proxyUrl() const; 34 | QtCoap::Method method() const; 35 | bool isObserve() const; 36 | void setUrl(const QUrl &url); 37 | void setProxyUrl(const QUrl &proxyUrl); 38 | void enableObserve(); 39 | 40 | private: 41 | // Q_DECLARE_PRIVATE equivalent for shared data pointers 42 | inline QCoapRequestPrivate* d_func(); 43 | const QCoapRequestPrivate* d_func() const 44 | { return reinterpret_cast(d_ptr.constData()); } 45 | 46 | friend class QCoapRequestPrivate; 47 | }; 48 | 49 | QT_END_NAMESPACE 50 | 51 | #endif // QCOAPREQUEST_H 52 | -------------------------------------------------------------------------------- /examples/coap/quicksecureclient/qmlcoapsecureclient.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef QMLCOAPSECURECLIENT_H 5 | #define QMLCOAPSECURECLIENT_H 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | class QCoapClient; 14 | QT_END_NAMESPACE 15 | 16 | //! [coap_client] 17 | class QmlCoapSecureClient : public QObject 18 | { 19 | Q_OBJECT 20 | QML_NAMED_ELEMENT(CoapSecureClient) 21 | 22 | public: 23 | QmlCoapSecureClient(QObject *parent = nullptr); 24 | ~QmlCoapSecureClient() override; 25 | 26 | Q_INVOKABLE void setSecurityMode(QtCoap::SecurityMode mode); 27 | Q_INVOKABLE void sendGetRequest(const QString &host, const QString &path, int port); 28 | Q_INVOKABLE void setSecurityConfiguration(const QString &preSharedKey, const QString &identity); 29 | Q_INVOKABLE void setSecurityConfiguration(const QString &localCertificatePath, 30 | const QString &caCertificatePath, 31 | const QString &privateKeyPath); 32 | Q_INVOKABLE void disconnect(); 33 | 34 | Q_SIGNALS: 35 | void finished(const QString &result); 36 | 37 | private: 38 | QCoapClient *m_coapClient; 39 | QCoapSecurityConfiguration m_configuration; 40 | QtCoap::SecurityMode m_securityMode; 41 | }; 42 | //! [coap_client] 43 | 44 | //! [coap_namespace] 45 | namespace QCoapForeignNamespace 46 | { 47 | Q_NAMESPACE 48 | QML_FOREIGN_NAMESPACE(QtCoap) 49 | QML_NAMED_ELEMENT(QtCoap) 50 | } 51 | //! [coap_namespace] 52 | 53 | #endif // QMLCOAPSECURECLIENT_H 54 | -------------------------------------------------------------------------------- /src/coap/qcoaprequest_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPREQUEST_P_H 7 | #define QCOAPREQUEST_P_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // 14 | // W A R N I N G 15 | // ------------- 16 | // 17 | // This file is not part of the Qt API. It exists purely as an 18 | // implementation detail. This header file may change from version to 19 | // version without notice, or even be removed. 20 | // 21 | // We mean it. 22 | // 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class Q_AUTOTEST_EXPORT QCoapRequestPrivate : public QCoapMessagePrivate 27 | { 28 | public: 29 | QCoapRequestPrivate(const QUrl &url = QUrl(), 30 | QCoapMessage::Type type = QCoapMessage::Type::NonConfirmable, 31 | const QUrl &proxyUrl = QUrl()); 32 | ~QCoapRequestPrivate(); 33 | 34 | QCoapRequestPrivate *clone() const override; 35 | 36 | void setUrl(const QUrl &url); 37 | void adjustUrl(bool secure); 38 | 39 | static QCoapRequest createRequest(const QCoapRequest &other, QtCoap::Method method, 40 | bool isSecure = false); 41 | static QUrl adjustedUrl(const QUrl &url, bool secure); 42 | static bool isUrlValid(const QUrl &url); 43 | 44 | QUrl uri; 45 | QUrl proxyUri; 46 | QtCoap::Method method = QtCoap::Method::Invalid; 47 | 48 | protected: 49 | QCoapRequestPrivate(const QCoapRequestPrivate &other) = default; 50 | }; 51 | 52 | QT_END_NAMESPACE 53 | 54 | #endif // QCOAPREQUEST_P_H 55 | -------------------------------------------------------------------------------- /src/coap/qcoapmessage_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPMESSAGE_P_H 7 | #define QCOAPMESSAGE_P_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // 14 | // W A R N I N G 15 | // ------------- 16 | // 17 | // This file is not part of the Qt API. It exists purely as an 18 | // implementation detail. This header file may change from version to 19 | // version without notice, or even be removed. 20 | // 21 | // We mean it. 22 | // 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class Q_AUTOTEST_EXPORT QCoapMessagePrivate : public QSharedData 27 | { 28 | public: 29 | QCoapMessagePrivate(QCoapMessage::Type type = QCoapMessage::Type::NonConfirmable); 30 | virtual ~QCoapMessagePrivate(); 31 | 32 | virtual QCoapMessagePrivate *clone() const; 33 | 34 | QList::const_iterator findOption(QCoapOption::OptionName name) const; 35 | 36 | quint8 version = 1; 37 | QCoapMessage::Type type = QCoapMessage::Type::NonConfirmable; 38 | quint16 messageId = 0; 39 | QByteArray token; 40 | QList options; 41 | QByteArray payload; 42 | 43 | protected: 44 | QCoapMessagePrivate(const QCoapMessagePrivate &other); 45 | }; 46 | 47 | // don't use the copy constructor when detaching from a QSharedDataPointer, 48 | // use virtual clone() call instead. 49 | template <> 50 | Q_INLINE_TEMPLATE QCoapMessagePrivate *QSharedDataPointer::clone() 51 | { 52 | return d->clone(); 53 | } 54 | 55 | QT_END_NAMESPACE 56 | 57 | #endif // QCOAPMESSAGE_P_H 58 | -------------------------------------------------------------------------------- /src/coap/qcoapreply_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPREPLY_P_H 7 | #define QCOAPREPLY_P_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // 14 | // W A R N I N G 15 | // ------------- 16 | // 17 | // This file is not part of the Qt API. It exists purely as an 18 | // implementation detail. This header file may change from version to 19 | // version without notice, or even be removed. 20 | // 21 | // We mean it. 22 | // 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QHostAddress; 27 | class Q_AUTOTEST_EXPORT QCoapReplyPrivate : public QIODevicePrivate 28 | { 29 | public: 30 | QCoapReplyPrivate(const QCoapRequest &request); 31 | 32 | void _q_setRunning(const QCoapToken &, QCoapMessageId); 33 | virtual void _q_setContent(const QHostAddress &sender, const QCoapMessage &, QtCoap::ResponseCode); 34 | void _q_setNotified(); 35 | void _q_setObserveCancelled(); 36 | void _q_setFinished(QtCoap::Error = QtCoap::Error::Ok); 37 | void _q_setError(QtCoap::ResponseCode code); 38 | void _q_setError(QtCoap::Error); 39 | 40 | static QCoapReply *createCoapReply(const QCoapRequest &request, QObject *parent = nullptr); 41 | 42 | QCoapRequest request; 43 | QCoapMessage message; 44 | QtCoap::ResponseCode responseCode = QtCoap::ResponseCode::InvalidCode; 45 | QtCoap::Error error = QtCoap::Error::Ok; 46 | bool isRunning = false; 47 | bool isFinished = false; 48 | bool isAborted = false; 49 | 50 | Q_DECLARE_PUBLIC(QCoapReply) 51 | }; 52 | 53 | QT_END_NAMESPACE 54 | 55 | #endif // QCOAPREPLY_P_H 56 | -------------------------------------------------------------------------------- /src/coap/doc/qtcoap.qdocconf: -------------------------------------------------------------------------------- 1 | include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) 2 | 3 | project = QtCoap 4 | description = Qt CoAP Reference Documentation 5 | version = $QT_VERSION 6 | 7 | examplesinstallpath = coap 8 | 9 | qhp.projects = QtCoap 10 | 11 | qhp.QtCoap.file = qtcoap.qhp 12 | qhp.QtCoap.namespace = org.qt-project.qtcoap.$QT_VERSION_TAG 13 | qhp.QtCoap.virtualFolder = qtcoap 14 | qhp.QtCoap.indexTitle = Qt CoAP 15 | qhp.QtCoap.indexRoot = 16 | 17 | qhp.QtCoap.subprojects = overview classes examples 18 | 19 | qhp.QtCoap.subprojects.examples.title = Examples 20 | qhp.QtCoap.subprojects.examples.indexTitle = Qt CoAP Examples 21 | qhp.QtCoap.subprojects.examples.selectors = fake:example 22 | qhp.QtCoap.subprojects.examples.sortPages = true 23 | 24 | qhp.QtCoap.subprojects.classes.title = C++ Classes 25 | qhp.QtCoap.subprojects.classes.indexTitle = Qt CoAP C++ Classes 26 | qhp.QtCoap.subprojects.classes.selectors = class fake:headerfile 27 | qhp.QtCoap.subprojects.classes.sortPages = true 28 | 29 | qhp.QtCoap.subprojects.overview.title = Overview 30 | qhp.QtCoap.subprojects.overview.indexTitle = Qt CoAP Overview 31 | qhp.QtCoap.subprojects.overview.selectors = group:none 32 | 33 | headerdirs += .. 34 | sourcedirs += .. 35 | exampledirs = ../../../examples/coap 36 | excludedirs += ../qt4support 37 | 38 | depends += qtcore qtdoc qtnetwork qtqml qmake qtcmake 39 | 40 | #add generic thumbnail images for example documentation that does not have an image. 41 | #manifestmeta.thumbnail.names += "QtCoap/WebSockets MQTT Subscription*" 42 | 43 | navigation.landingpage = "Qt CoAP" 44 | navigation.cppclassespage = "Qt CoAP C++ Classes" 45 | 46 | # Allow zero warnings when testing documentation in CI 47 | warninglimit = 0 48 | -------------------------------------------------------------------------------- /src/coap/qcoapinternalreply_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPINTERNALREPLY_H 7 | #define QCOAPINTERNALREPLY_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // 15 | // W A R N I N G 16 | // ------------- 17 | // 18 | // This file is not part of the Qt API. It exists purely as an 19 | // implementation detail. This header file may change from version to 20 | // version without notice, or even be removed. 21 | // 22 | // We mean it. 23 | // 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QCoapInternalReplyPrivate; 28 | class Q_AUTOTEST_EXPORT QCoapInternalReply : public QCoapInternalMessage 29 | { 30 | Q_OBJECT 31 | public: 32 | explicit QCoapInternalReply(QObject *parent = nullptr); 33 | 34 | static QCoapInternalReply *createFromFrame(const QByteArray &frame, QObject *parent = nullptr); 35 | void appendData(const QByteArray &data); 36 | bool hasMoreBlocksToSend() const; 37 | int nextBlockToSend() const; 38 | 39 | using QCoapInternalMessage::addOption; 40 | void addOption(const QCoapOption &option) override; 41 | void setSenderAddress(const QHostAddress &address); 42 | 43 | QtCoap::ResponseCode responseCode() const; 44 | QHostAddress senderAddress() const; 45 | 46 | private: 47 | Q_DECLARE_PRIVATE(QCoapInternalReply) 48 | }; 49 | 50 | class Q_AUTOTEST_EXPORT QCoapInternalReplyPrivate : public QCoapInternalMessagePrivate 51 | { 52 | public: 53 | QCoapInternalReplyPrivate() = default; 54 | 55 | QtCoap::ResponseCode responseCode = QtCoap::ResponseCode::InvalidCode; 56 | QHostAddress senderAddress; 57 | }; 58 | 59 | QT_END_NAMESPACE 60 | 61 | #endif // QCOAPINTERNALREPLY_H 62 | -------------------------------------------------------------------------------- /tests/testserver/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | 3 | 4 | # The tag of images is used by docker compose file to launch the correct 5 | # docker containers. By default we always launch the "latest" tag. 6 | # 7 | # But in the "docker build" phase, we also tag the images with a unique tag, 8 | # the SHA1 hash of all files used for "docker build" - see sha1tree() in 9 | # provisioning. 10 | # 11 | # So if you want to update the docker image at a specific time, make sure that 12 | # 1. you modify this file to run the specific image's SHA1 tag, instead of 13 | # "latest" 14 | # 2. you build two docker images in provisioning, the currently used one, 15 | # plus the new one that you tag as "latest" 16 | # 3. you switch this file to the "latest" tag when ready 17 | 18 | # You can run `docker images` to list all the tags of available images: 19 | # For example: 20 | # REPOSITORY TAG 21 | # qt-test-server-californium 537fe302f61851d1663f41495230d8e3554a4a13 22 | 23 | services: 24 | californium: 25 | extends: 26 | file: ${SHARED_DATA}/docker-compose-common.yml 27 | service: ${SHARED_SERVICE} 28 | container_name: qt-test-server-californium 29 | hostname: ${HOST_NAME:-californium} 30 | build: 31 | context: . 32 | args: 33 | provisioningImage: qt-test-server-californium:latest 34 | serviceDir: ./californium 35 | ports: 36 | - "5683:5683/udp" 37 | - "5684:5684/udp" 38 | entrypoint: ./startup.sh 39 | command: service/californium.sh 40 | freecoap: 41 | extends: 42 | file: ${SHARED_DATA}/docker-compose-common.yml 43 | service: ${SHARED_SERVICE} 44 | container_name: qt-test-server-freecoap 45 | hostname: ${HOST_NAME:-freecoap} 46 | build: 47 | context: . 48 | args: 49 | provisioningImage: qt-test-server-freecoap:latest 50 | serviceDir: ./freecoap 51 | ports: 52 | - "5685:5685/udp" 53 | entrypoint: ./startup.sh 54 | command: service/freecoap.sh 55 | -------------------------------------------------------------------------------- /src/coap/qcoapinternalmessage_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPINTERNALMESSAGE_P_H 7 | #define QCOAPINTERNALMESSAGE_P_H 8 | 9 | #include 10 | #include 11 | 12 | // 13 | // W A R N I N G 14 | // ------------- 15 | // 16 | // This file is not part of the Qt API. It exists purely as an 17 | // implementation detail. This header file may change from version to 18 | // version without notice, or even be removed. 19 | // 20 | // We mean it. 21 | // 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | class QCoapInternalMessagePrivate; 26 | class Q_AUTOTEST_EXPORT QCoapInternalMessage : public QObject 27 | { 28 | Q_OBJECT 29 | public: 30 | explicit QCoapInternalMessage(QObject *parent = nullptr); 31 | explicit QCoapInternalMessage(const QCoapMessage &message, QObject *parent = nullptr); 32 | virtual ~QCoapInternalMessage() {} 33 | 34 | void addOption(QCoapOption::OptionName name, const QByteArray &value); 35 | void addOption(QCoapOption::OptionName name, quint32 value); 36 | virtual void addOption(const QCoapOption &option); 37 | void removeOption(QCoapOption::OptionName name); 38 | 39 | QCoapMessage *message(); 40 | const QCoapMessage *message() const; 41 | 42 | uint currentBlockNumber() const; 43 | bool hasMoreBlocksToReceive() const; 44 | uint blockSize() const; 45 | 46 | virtual bool isValid() const; 47 | static bool isUrlValid(const QUrl &url); 48 | 49 | protected: 50 | explicit QCoapInternalMessage(QCoapInternalMessagePrivate &dd, QObject *parent = nullptr); 51 | 52 | void setFromDescriptiveBlockOption(const QCoapOption &option); 53 | 54 | Q_DECLARE_PRIVATE(QCoapInternalMessage) 55 | }; 56 | 57 | class Q_AUTOTEST_EXPORT QCoapInternalMessagePrivate : public QObjectPrivate 58 | { 59 | public: 60 | QCoapInternalMessagePrivate() = default; 61 | ~QCoapInternalMessagePrivate(); 62 | 63 | QCoapMessage message; 64 | 65 | uint currentBlockNumber = 0; 66 | bool hasNextBlock = false; 67 | uint blockSize = 0; 68 | }; 69 | 70 | QT_END_NAMESPACE 71 | 72 | #endif // QCOAPINTERNALMESSAGE_P_H 73 | -------------------------------------------------------------------------------- /src/coap/qcoapreply.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPREPLY_H 7 | #define QCOAPREPLY_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QCoapInternalReply; 18 | class QCoapReplyPrivate; 19 | class Q_COAP_EXPORT QCoapReply : public QIODevice 20 | { 21 | Q_OBJECT 22 | public: 23 | ~QCoapReply() override; 24 | 25 | QtCoap::ResponseCode responseCode() const; 26 | QCoapMessage message() const; 27 | QCoapRequest request() const; 28 | QUrl url() const; 29 | QtCoap::Method method() const; 30 | QtCoap::Error errorReceived() const; 31 | bool isRunning() const; 32 | bool isFinished() const; 33 | bool isAborted() const; 34 | bool isSuccessful() const; 35 | void abortRequest(); 36 | 37 | Q_SIGNALS: 38 | void finished(QCoapReply *reply); 39 | void notified(QCoapReply *reply, const QCoapMessage &message); 40 | void error(QCoapReply *reply, QtCoap::Error error); 41 | void aborted(const QCoapToken &token); 42 | 43 | protected: 44 | qint64 readData(char *data, qint64 maxSize) override; 45 | qint64 writeData(const char *data, qint64 maxSize) override; 46 | 47 | Q_DECLARE_PRIVATE(QCoapReply) 48 | Q_PRIVATE_SLOT(d_func(), void _q_setRunning(const QCoapToken &, QCoapMessageId)) 49 | Q_PRIVATE_SLOT(d_func(), void _q_setContent(const QHostAddress &host, const QCoapMessage &, 50 | QtCoap::ResponseCode)) 51 | Q_PRIVATE_SLOT(d_func(), void _q_setNotified()) 52 | Q_PRIVATE_SLOT(d_func(), void _q_setObserveCancelled()) 53 | Q_PRIVATE_SLOT(d_func(), void _q_setFinished(QtCoap::Error)) 54 | Q_PRIVATE_SLOT(d_func(), void _q_setError(QtCoap::ResponseCode)) 55 | Q_PRIVATE_SLOT(d_func(), void _q_setError(QtCoap::Error)) 56 | 57 | private: 58 | explicit QCoapReply(QCoapReplyPrivate &dd, QObject *parent = nullptr); 59 | friend class QCoapResourceDiscoveryReply; 60 | }; 61 | 62 | QT_END_NAMESPACE 63 | 64 | #endif // QCOAPREPLY_H 65 | -------------------------------------------------------------------------------- /examples/coap/quickmulticastclient/qmlcoapmulticastclient.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef QMLCOAPMULTICASTCLIENT_H 5 | #define QMLCOAPMULTICASTCLIENT_H 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | class QCoapResourceDiscoveryReply; 15 | QT_END_NAMESPACE 16 | 17 | //! [coap_resource] 18 | class QmlCoapResource : public QCoapResource 19 | { 20 | Q_GADGET 21 | Q_PROPERTY(QString title READ title) 22 | Q_PROPERTY(QString host READ hostStr) 23 | Q_PROPERTY(QString path READ path) 24 | 25 | QML_ANONYMOUS 26 | public: 27 | QmlCoapResource() : QCoapResource() {} 28 | QmlCoapResource(const QCoapResource &resource) 29 | : QCoapResource(resource) {} 30 | 31 | QString hostStr() const { return host().toString(); } 32 | }; 33 | //! [coap_resource] 34 | Q_DECLARE_METATYPE(QmlCoapResource) 35 | 36 | //! [coap_client] 37 | class QmlCoapMulticastClient : public QCoapClient 38 | { 39 | Q_OBJECT 40 | 41 | Q_PROPERTY(bool isDiscovering READ isDiscovering NOTIFY isDiscoveringChanged) 42 | 43 | QML_NAMED_ELEMENT(CoapMulticastClient) 44 | public: 45 | QmlCoapMulticastClient(QObject *parent = nullptr); 46 | 47 | Q_INVOKABLE void discover(const QString &host, int port, const QString &discoveryPath); 48 | Q_INVOKABLE void discover(QtCoap::MulticastGroup group, int port, const QString &discoveryPath); 49 | Q_INVOKABLE void stopDiscovery(); 50 | 51 | bool isDiscovering() const; 52 | 53 | Q_SIGNALS: 54 | void discovered(const QmlCoapResource &resource); 55 | void finished(int error); 56 | // The bool parameter is not provided, because the signal is only used by 57 | // the QML property system, and it does not use the passed value anyway. 58 | void isDiscoveringChanged(); 59 | 60 | public slots: 61 | void onDiscovered(QCoapResourceDiscoveryReply *reply, const QList &resources); 62 | 63 | private: 64 | QCoapResourceDiscoveryReply *m_reply = nullptr; 65 | }; 66 | //! [coap_client] 67 | 68 | //! [coap_namespace] 69 | namespace QCoapForeignNamespace 70 | { 71 | Q_NAMESPACE 72 | QML_FOREIGN_NAMESPACE(QtCoap) 73 | QML_NAMED_ELEMENT(QtCoap) 74 | } 75 | //! [coap_namespace] 76 | 77 | #endif // QMLCOAPMULTICASTCLIENT_H 78 | -------------------------------------------------------------------------------- /src/coap/qcoapoption.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPOPTION_H 7 | #define QCOAPOPTION_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QCoapOptionPrivate; 16 | class Q_COAP_EXPORT QCoapOption 17 | { 18 | public: 19 | enum OptionName { 20 | Invalid = 0, 21 | IfMatch = 1, 22 | UriHost = 3, 23 | Etag = 4, 24 | IfNoneMatch = 5, 25 | Observe = 6, 26 | UriPort = 7, 27 | LocationPath = 8, 28 | UriPath = 11, 29 | ContentFormat = 12, 30 | MaxAge = 14, 31 | UriQuery = 15, 32 | Accept = 17, 33 | LocationQuery = 20, 34 | Block2 = 23, 35 | Block1 = 27, 36 | Size2 = 28, 37 | ProxyUri = 35, 38 | ProxyScheme = 39, 39 | Size1 = 60 40 | }; 41 | 42 | QCoapOption(OptionName name = Invalid, const QByteArray &opaqueValue = QByteArray()); 43 | QCoapOption(OptionName name, const QString &stringValue); 44 | QCoapOption(OptionName name, quint32 intValue); 45 | QCoapOption(const QCoapOption &other); 46 | QCoapOption(QCoapOption &&other); 47 | ~QCoapOption(); 48 | 49 | QCoapOption &operator=(const QCoapOption &other); 50 | QCoapOption &operator=(QCoapOption &&other) noexcept; 51 | void swap(QCoapOption &other) noexcept; 52 | 53 | QByteArray opaqueValue() const; 54 | quint32 uintValue() const; 55 | QString stringValue() const; 56 | int length() const; 57 | OptionName name() const; 58 | bool isValid() const; 59 | 60 | bool operator==(const QCoapOption &other) const; 61 | bool operator!=(const QCoapOption &other) const; 62 | 63 | private: 64 | QCoapOptionPrivate *d_ptr; 65 | 66 | // Q_DECLARE_PRIVATE equivalent for shared data pointers 67 | inline QCoapOptionPrivate *d_func(); 68 | const QCoapOptionPrivate *d_func() const { return d_ptr; } 69 | }; 70 | 71 | QT_END_NAMESPACE 72 | 73 | Q_DECLARE_METATYPE(QCoapOption::OptionName) 74 | Q_DECLARE_METATYPE(QCoapOption) 75 | 76 | #endif // QCOAPOPTION_H 77 | -------------------------------------------------------------------------------- /src/coap/doc/src/qtcoap-index.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \page qtcoap-index.html 6 | \title Qt CoAP 7 | \brief Provides classes and functions to make CoAP programming simple and 8 | portable. 9 | 10 | Constrained Application Protocol (\l CoAP) is a machine-to-machine (M2M) web 11 | transfer protocol for use with constrained nodes and constrained networks in 12 | the Internet of Things (IoT). It is designed to easily interface with HTTP for 13 | integration with the Web, while meeting specialized requirements such as multicast 14 | support, very low overhead, and simplicity for constrained environments. 15 | 16 | The Qt CoAP module implements the client side of CoAP defined by \l{RFC 7252}. 17 | Generally, CoAP is designed to use datagram-oriented transport such as UDP, so 18 | the current implementation of the transport is based on UDP. However implementing 19 | custom transports based on TCP, WebSocket, and so on, is also possible. 20 | 21 | The Qt CoAP module supports: 22 | 23 | \list 24 | \li Security based on Datagram TLS (DTLS) over UDP 25 | \li Group communication defined by \l{RFC 7390} 26 | \li Blockwise transfers defined by \l{RFC 7959} 27 | \li Resource observation defined by \l{RFC 7641} 28 | \li Resource discovery (multicast and single server) 29 | \endlist 30 | 31 | \include module-use.qdocinc using qt module 32 | 33 | \code 34 | find_package(Qt6 REQUIRED COMPONENTS Coap) 35 | target_link_libraries(mytarget PRIVATE Qt6::Coap) 36 | \endcode 37 | 38 | See also the \l {Build with CMake} overview. 39 | 40 | \include module-use.qdocinc building with qmake 41 | 42 | \code 43 | QT += coap 44 | \endcode 45 | 46 | \section1 Articles and Guides 47 | 48 | \list 49 | \li \l{Qt CoAP Overview}{Overview} 50 | \endlist 51 | 52 | \section1 Examples 53 | 54 | \list 55 | \li \l{Qt CoAP Examples} 56 | \endlist 57 | 58 | \section1 Reference 59 | 60 | \list 61 | \li \l{Qt CoAP C++ Classes}{C++ Classes} 62 | \endlist 63 | 64 | \section1 Licenses and Attributions 65 | 66 | Qt CoAP is available under commercial licenses from \l{The Qt Company}. 67 | In addition, it is available under the 68 | \l{GNU General Public License, version 3}. 69 | 70 | \annotatedlist attributions-qtcoap 71 | */ 72 | -------------------------------------------------------------------------------- /src/coap/qcoapmessage.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPMESSAGE_H 7 | #define QCOAPMESSAGE_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class QCoapMessagePrivate; 19 | class Q_COAP_EXPORT QCoapMessage 20 | { 21 | public: 22 | enum class Type : quint8 { 23 | Confirmable, 24 | NonConfirmable, 25 | Acknowledgment, 26 | Reset 27 | }; 28 | 29 | QCoapMessage(); 30 | QCoapMessage(const QCoapMessage &other); 31 | ~QCoapMessage(); 32 | 33 | void swap(QCoapMessage &other) noexcept; 34 | QCoapMessage &operator=(const QCoapMessage &other); 35 | QCoapMessage &operator=(QCoapMessage &&other) noexcept; 36 | 37 | quint8 version() const; 38 | Type type() const; 39 | QByteArray token() const; 40 | quint8 tokenLength() const; 41 | quint16 messageId() const; 42 | QByteArray payload() const; 43 | void setVersion(quint8 version); 44 | void setType(const Type &type); 45 | void setToken(const QByteArray &token); 46 | void setMessageId(quint16); 47 | void setPayload(const QByteArray &payload); 48 | void setOptions(const QList &options); 49 | 50 | QCoapOption optionAt(int index) const; 51 | QCoapOption option(QCoapOption::OptionName name) const; 52 | bool hasOption(QCoapOption::OptionName name) const; 53 | const QList &options() const; 54 | QList options(QCoapOption::OptionName name) const; 55 | int optionCount() const; 56 | void addOption(QCoapOption::OptionName name, const QByteArray &value = QByteArray()); 57 | void addOption(const QCoapOption &option); 58 | void removeOption(const QCoapOption &option); 59 | void removeOption(QCoapOption::OptionName name); 60 | void clearOptions(); 61 | 62 | protected: 63 | explicit QCoapMessage(QCoapMessagePrivate &dd); 64 | 65 | QSharedDataPointer d_ptr; 66 | 67 | // Q_DECLARE_PRIVATE equivalent for shared data pointers 68 | inline QCoapMessagePrivate *d_func(); 69 | const QCoapMessagePrivate *d_func() const { return d_ptr.constData(); } 70 | }; 71 | 72 | Q_DECLARE_SHARED(QCoapMessage) 73 | 74 | QT_END_NAMESPACE 75 | 76 | Q_DECLARE_METATYPE(QCoapMessage) 77 | Q_DECLARE_METATYPE(QCoapMessage::Type) 78 | 79 | #endif // QCOAPMESSAGE_H 80 | -------------------------------------------------------------------------------- /tests/auto/qcoapoption/tst_qcoapoption.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018 Witekio. 2 | // Copyright (C) 2021 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include 6 | 7 | #include 8 | 9 | class tst_QCoapOption : public QObject 10 | { 11 | Q_OBJECT 12 | 13 | private Q_SLOTS: 14 | void constructAndAssign(); 15 | void constructWithQByteArray(); 16 | void constructWithQString(); 17 | void constructWithInteger(); 18 | void constructWithUtf8Characters(); 19 | }; 20 | 21 | void tst_QCoapOption::constructAndAssign() 22 | { 23 | QCoapOption option1; 24 | QCOMPARE(option1.name(), QCoapOption::Invalid); 25 | QCOMPARE(option1.uintValue(), 0u); 26 | QVERIFY(option1.stringValue().isEmpty()); 27 | QVERIFY(option1.opaqueValue().isEmpty()); 28 | 29 | QCoapOption option2(QCoapOption::Size1, 1); 30 | QCOMPARE(option2.name(), QCoapOption::Size1); 31 | QCOMPARE(option2.uintValue(), 1u); 32 | 33 | // Copy-construction 34 | QCoapOption option3(option2); 35 | QCOMPARE(option3.name(), QCoapOption::Size1); 36 | QCOMPARE(option3.uintValue(), 1u); 37 | 38 | // Move-construction 39 | QCoapOption option4(std::move(option2)); 40 | QCOMPARE(option4.name(), QCoapOption::Size1); 41 | QCOMPARE(option4.uintValue(), 1u); 42 | 43 | // Copy-assignment 44 | option4 = option1; 45 | QCOMPARE(option4.name(), QCoapOption::Invalid); 46 | QCOMPARE(option4.uintValue(), 0u); 47 | 48 | // Move-assignment 49 | option4 = std::move(option3); 50 | QCOMPARE(option4.name(), QCoapOption::Size1); 51 | QCOMPARE(option4.uintValue(), 1u); 52 | 53 | // Assign to a moved-from 54 | option2 = option4; 55 | QCOMPARE(option2.name(), QCoapOption::Size1); 56 | QCOMPARE(option2.uintValue(), 1u); 57 | } 58 | 59 | void tst_QCoapOption::constructWithQByteArray() 60 | { 61 | QByteArray ba = "some data"; 62 | QCoapOption option(QCoapOption::LocationPath, ba); 63 | 64 | QCOMPARE(option.opaqueValue(), ba); 65 | } 66 | 67 | void tst_QCoapOption::constructWithQString() 68 | { 69 | QString str = "some data"; 70 | QCoapOption option(QCoapOption::LocationPath, str); 71 | 72 | QCOMPARE(option.opaqueValue(), str.toUtf8()); 73 | } 74 | 75 | void tst_QCoapOption::constructWithInteger() 76 | { 77 | quint32 value = 64000; 78 | QCoapOption option(QCoapOption::Size1, value); 79 | 80 | QCOMPARE(option.uintValue(), value); 81 | } 82 | 83 | void tst_QCoapOption::constructWithUtf8Characters() 84 | { 85 | QByteArray ba = "\xc3\xa9~\xce\xbb\xe2\x82\xb2"; 86 | QCoapOption option(QCoapOption::LocationPath, ba); 87 | 88 | QCOMPARE(option.opaqueValue(), ba); 89 | } 90 | 91 | QTEST_APPLESS_MAIN(tst_QCoapOption) 92 | 93 | #include "tst_qcoapoption.moc" 94 | -------------------------------------------------------------------------------- /src/coap/doc/style/style.css: -------------------------------------------------------------------------------- 1 | a:link, a:visited { 2 | color: #00732F; 3 | text-decoration: none; 4 | font-weight: bold; 5 | } 6 | 7 | body { 8 | font: normal 400 14px/1.2 Arial; 9 | margin-top: 85px; 10 | } 11 | 12 | h1 { 13 | margin: 0; 14 | } 15 | 16 | h2 { 17 | font: 500 20px/1.2 Arial; 18 | } 19 | 20 | h3.fn, span.fn { 21 | -moz-border-radius: 7px 7px 7px 7px; 22 | -webkit-border-radius: 7px 7px 7px 7px; 23 | border-radius: 7px 7px 7px 7px; 24 | background-color: #F6F6F6; 25 | border-width: 1px; 26 | border-style: solid; 27 | border-color: #E6E6E6; 28 | word-spacing: 3px; 29 | padding: 3px 5px; 30 | } 31 | 32 | table, pre { 33 | -moz-border-radius: 7px 7px 7px 7px; 34 | -webkit-border-radius: 7px 7px 7px 7px; 35 | border-radius: 7px 7px 7px 7px; 36 | background-color: #F6F6F6; 37 | border: 1px solid #E6E6E6; 38 | border-collapse: separate; 39 | font-size: 12px; 40 | line-height: 1.2; 41 | margin-bottom: 25px; 42 | margin-left: 15px; 43 | } 44 | 45 | table td { 46 | padding: 3px 15px 3px 20px; 47 | } 48 | 49 | table tr.even { 50 | background-color: white; 51 | color: #66666E; 52 | } 53 | 54 | table tr.odd { 55 | background-color: #F6F6F6; 56 | color: #66666E; 57 | } 58 | 59 | li { 60 | margin-bottom: 10px; 61 | padding-left: 12px; 62 | } 63 | 64 | .cpp { 65 | display: block; 66 | margin: 10; 67 | overflow: hidden; 68 | overflow-x: hidden; 69 | overflow-y: hidden; 70 | padding: 20px 0 20px 0; 71 | } 72 | 73 | .footer { 74 | margin-top: 50px; 75 | } 76 | 77 | .memItemLeft { 78 | padding-right: 3px; 79 | } 80 | 81 | .memItemRight { 82 | padding: 3px 15px 3px 0; 83 | } 84 | 85 | .qml { 86 | display: block; 87 | margin: 10; 88 | overflow: hidden; 89 | overflow-x: hidden; 90 | overflow-y: hidden; 91 | padding: 20px 0 20px 0; 92 | } 93 | 94 | .qmldefault { 95 | padding-left: 5px; 96 | float: right; 97 | color: red; 98 | } 99 | 100 | .qmlreadonly { 101 | padding-left: 5px; 102 | float: right; 103 | color: #254117; 104 | } 105 | 106 | .rightAlign { 107 | padding: 3px 5px 3px 10px; 108 | text-align: right; 109 | } 110 | 111 | .title { 112 | background-color: white; 113 | color: #44A51C; 114 | font-family: Verdana; 115 | font-size: 35px; 116 | font-weight: normal; 117 | left: 0; 118 | padding-bottom: 5px; 119 | padding-left: 16px; 120 | padding-top: 20px; 121 | position: absolute; 122 | right: 0; 123 | top: 0; 124 | } 125 | 126 | .toc { 127 | float: right; 128 | -moz-border-radius: 7px 7px 7px 7px; 129 | -webkit-border-radius: 7px 7px 7px 7px; 130 | border-radius: 7px 7px 7px 7px; 131 | background-color: #F6F6F6; 132 | border: 1px solid #DDD; 133 | margin: 0 20px 10px 10px; 134 | padding: 20px 15px 20px 20px; 135 | height: auto; 136 | width: 200px; 137 | } 138 | -------------------------------------------------------------------------------- /src/coap/qcoapqudpconnection_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPQUDPCONNECTION_P_H 7 | #define QCOAPQUDPCONNECTION_P_H 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | // 20 | // W A R N I N G 21 | // ------------- 22 | // 23 | // This file is not part of the Qt API. It exists purely as an 24 | // implementation detail. This header file may change from version to 25 | // version without notice, or even be removed. 26 | // 27 | // We mean it. 28 | // 29 | 30 | QT_BEGIN_NAMESPACE 31 | 32 | class QDtls; 33 | class QSslPreSharedKeyAuthenticator; 34 | class QCoapQUdpConnectionPrivate; 35 | class Q_AUTOTEST_EXPORT QCoapQUdpConnection : public QCoapConnection 36 | { 37 | Q_OBJECT 38 | 39 | public: 40 | explicit QCoapQUdpConnection(QtCoap::SecurityMode security = QtCoap::SecurityMode::NoSecurity, 41 | QObject *parent = nullptr); 42 | 43 | ~QCoapQUdpConnection() override = default; 44 | 45 | QUdpSocket *socket() const; 46 | 47 | public Q_SLOTS: 48 | void setSocketOption(QAbstractSocket::SocketOption, const QVariant &value); 49 | 50 | #if QT_CONFIG(dtls) 51 | private Q_SLOTS: 52 | void pskRequired(QSslPreSharedKeyAuthenticator *authenticator); 53 | void handshakeTimeout(); 54 | #endif 55 | 56 | protected: 57 | explicit QCoapQUdpConnection(QCoapQUdpConnectionPrivate &dd, QObject *parent = nullptr); 58 | 59 | void bind(const QString &host, quint16 port) override; 60 | void writeData(const QByteArray &data, const QString &host, quint16 port) override; 61 | void close() override; 62 | 63 | void createSocket(); 64 | 65 | Q_DECLARE_PRIVATE(QCoapQUdpConnection) 66 | }; 67 | 68 | class Q_AUTOTEST_EXPORT QCoapQUdpConnectionPrivate : public QCoapConnectionPrivate 69 | { 70 | public: 71 | QCoapQUdpConnectionPrivate(QtCoap::SecurityMode security = QtCoap::SecurityMode::NoSecurity); 72 | ~QCoapQUdpConnectionPrivate() override; 73 | 74 | virtual bool bind(); 75 | 76 | void bindSocket(); 77 | void writeToSocket(const QByteArray &data, const QString &host, quint16 port); 78 | QUdpSocket* socket() const { return udpSocket; } 79 | void socketReadyRead(); 80 | 81 | void setSecurityConfiguration(const QCoapSecurityConfiguration &configuration); 82 | 83 | bool datagramMatchesNetworkInterface(const QNetworkDatagram &datagram) const; 84 | 85 | #if QT_CONFIG(dtls) 86 | std::optional receiveDatagramDecrypted() const; 87 | void handleEncryptedDatagram(); 88 | 89 | QPointer dtls; 90 | #endif 91 | QPointer udpSocket; 92 | 93 | Q_DECLARE_PUBLIC(QCoapQUdpConnection) 94 | }; 95 | 96 | QT_END_NAMESPACE 97 | 98 | #endif // QCOAPQUDPCONNECTION_P_H 99 | -------------------------------------------------------------------------------- /examples/coap/quickmulticastclient/qmlcoapmulticastclient.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "qmlcoapmulticastclient.h" 5 | 6 | #include 7 | #include 8 | 9 | Q_STATIC_LOGGING_CATEGORY(lcCoapClient, "qt.coap.client") 10 | 11 | //! [ctor] 12 | QmlCoapMulticastClient::QmlCoapMulticastClient(QObject *parent) 13 | : QCoapClient(QtCoap::SecurityMode::NoSecurity, parent) 14 | { 15 | connect(this, &QCoapClient::finished, this, 16 | [this](QCoapReply *reply) { 17 | if (reply) { 18 | emit finished(static_cast(reply->errorReceived())); 19 | reply->deleteLater(); 20 | if (m_reply == reply) { 21 | m_reply = nullptr; 22 | emit isDiscoveringChanged(); 23 | } 24 | } else { 25 | qCWarning(lcCoapClient, "Something went wrong, received a null reply"); 26 | } 27 | }); 28 | 29 | connect(this, &QCoapClient::error, this, 30 | [this](QCoapReply *, QtCoap::Error err) { 31 | emit finished(static_cast(err)); 32 | }); 33 | } 34 | //! [ctor] 35 | 36 | //! [discover_custom] 37 | void QmlCoapMulticastClient::discover(const QString &host, int port, const QString &discoveryPath) 38 | { 39 | QUrl url; 40 | url.setHost(host); 41 | url.setPort(port); 42 | 43 | m_reply = QCoapClient::discover(url, discoveryPath); 44 | if (m_reply) { 45 | connect(m_reply, &QCoapResourceDiscoveryReply::discovered, 46 | this, &QmlCoapMulticastClient::onDiscovered); 47 | emit isDiscoveringChanged(); 48 | } else { 49 | qCWarning(lcCoapClient, "Discovery request failed."); 50 | } 51 | } 52 | //! [discover_custom] 53 | 54 | //! [discover_group] 55 | void QmlCoapMulticastClient::discover(QtCoap::MulticastGroup group, int port, 56 | const QString &discoveryPath) 57 | { 58 | m_reply = QCoapClient::discover(group, port, discoveryPath); 59 | if (m_reply) { 60 | connect(m_reply, &QCoapResourceDiscoveryReply::discovered, 61 | this, &QmlCoapMulticastClient::onDiscovered); 62 | emit isDiscoveringChanged(); 63 | } else { 64 | qCWarning(lcCoapClient, "Discovery request failed."); 65 | } 66 | } 67 | //! [discover_group] 68 | 69 | //! [stop_discovery] 70 | void QmlCoapMulticastClient::stopDiscovery() 71 | { 72 | if (m_reply) 73 | m_reply->abortRequest(); 74 | } 75 | //! [stop_discovery] 76 | 77 | bool QmlCoapMulticastClient::isDiscovering() const 78 | { 79 | return m_reply && !m_reply->isFinished(); 80 | } 81 | 82 | //! [on_discovered] 83 | void QmlCoapMulticastClient::onDiscovered(QCoapResourceDiscoveryReply *reply, 84 | const QList &resources) 85 | { 86 | Q_UNUSED(reply) 87 | for (const auto &resource : resources) 88 | emit discovered(resource); 89 | } 90 | //! [on_discovered] 91 | 92 | #include "moc_qmlcoapmulticastclient.cpp" 93 | -------------------------------------------------------------------------------- /src/coap/qcoapnamespace.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef QCOAPNAMESPACE_H 11 | #define QCOAPNAMESPACE_H 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | #define FOR_EACH_COAP_ERROR(X) \ 16 | X(BadRequest, 0x80) X(Unauthorized, 0x81) X(BadOption, 0x82) X(Forbidden, 0x83) \ 17 | X(NotFound, 0x84) X(MethodNotAllowed, 0x85) X(NotAcceptable, 0x86) \ 18 | X(RequestEntityIncomplete, 0x88) X(PreconditionFailed, 0x8C) X(RequestEntityTooLarge, 0x8D) \ 19 | X(UnsupportedContentFormat, 0x8E) X(InternalServerFault, 0xA0) X(NotImplemented, 0xA1) \ 20 | X(BadGateway, 0xA2) X(ServiceUnavailable, 0xA3) X(GatewayTimeout, 0xA4) \ 21 | X(ProxyingNotSupported, 0xA5) 22 | 23 | namespace QtCoap 24 | { 25 | Q_NAMESPACE_EXPORT(Q_COAP_EXPORT) 26 | 27 | enum class ResponseCode : quint8 { 28 | EmptyMessage = 0x00, 29 | Created = 0x41, // 2.01 30 | Deleted = 0x42, // 2.02 31 | Valid = 0x43, // 2.03 32 | Changed = 0x44, // 2.04 33 | Content = 0x45, // 2.05 34 | Continue = 0x5F, // 2.31 35 | 36 | #define SINGLE_CODE(name, value) name = value, 37 | FOR_EACH_COAP_ERROR(SINGLE_CODE) 38 | #undef SINGLE_CODE 39 | 40 | InvalidCode = 0xFF 41 | }; 42 | Q_ENUM_NS(ResponseCode) 43 | 44 | enum class Error : quint8 { 45 | Ok, 46 | HostNotFound, 47 | AddressInUse, 48 | TimeOut, 49 | 50 | #define SINGLE_ERROR(name, ignored) name, 51 | FOR_EACH_COAP_ERROR(SINGLE_ERROR) 52 | #undef SINGLE_ERROR 53 | 54 | Unknown 55 | }; 56 | Q_ENUM_NS(Error) 57 | 58 | enum class Method : quint8 { 59 | Invalid, 60 | Get, 61 | Post, 62 | Put, 63 | Delete, 64 | #if 0 65 | //! TODO Support other methods included in RFC 8132 66 | //! https://tools.ietf.org/html/rfc8132 67 | Fetch, 68 | Patch, 69 | IPatch, 70 | #endif 71 | Other 72 | }; 73 | Q_ENUM_NS(Method) 74 | 75 | enum Port { 76 | DefaultPort = 5683, 77 | DefaultSecurePort = 5684 78 | }; 79 | Q_ENUM_NS(Port) 80 | 81 | enum class SecurityMode : quint8 { 82 | NoSecurity = 0, 83 | PreSharedKey, 84 | RawPublicKey, 85 | Certificate 86 | }; 87 | Q_ENUM_NS(SecurityMode) 88 | 89 | enum class MulticastGroup : quint8 { 90 | AllCoapNodesIPv4, 91 | AllCoapNodesIPv6LinkLocal, 92 | AllCoapNodesIPv6SiteLocal 93 | }; 94 | Q_ENUM_NS(MulticastGroup) 95 | 96 | Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") 97 | } 98 | 99 | QT_END_NAMESPACE 100 | 101 | Q_DECLARE_METATYPE(QtCoap::ResponseCode) 102 | Q_DECLARE_METATYPE(QtCoap::Error) 103 | Q_DECLARE_METATYPE(QtCoap::Method) 104 | Q_DECLARE_METATYPE(QtCoap::SecurityMode) 105 | Q_DECLARE_METATYPE(QtCoap::MulticastGroup) 106 | 107 | #endif // QCOAPNAMESPACE_H 108 | -------------------------------------------------------------------------------- /src/coap/qcoapsecurityconfiguration.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 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 | #ifndef QCOAPSECURITYCONFIGURATION_H 6 | #define QCOAPSECURITYCONFIGURATION_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | QT_BEGIN_NAMESPACE 15 | 16 | class QCoapPrivateKeyPrivate; 17 | class Q_COAP_EXPORT QCoapPrivateKey 18 | { 19 | public: 20 | QCoapPrivateKey(); 21 | QCoapPrivateKey(const QByteArray &key, QSsl::KeyAlgorithm algorithm, 22 | QSsl::EncodingFormat format = QSsl::Pem, 23 | const QByteArray &passPhrase = QByteArray()); 24 | QCoapPrivateKey(const Qt::HANDLE &handle); 25 | 26 | QCoapPrivateKey(const QCoapPrivateKey& other); 27 | QCoapPrivateKey(QCoapPrivateKey&& other) noexcept; 28 | ~QCoapPrivateKey(); 29 | 30 | QCoapPrivateKey &operator=(QCoapPrivateKey &&other) noexcept 31 | { swap(other); return *this; } 32 | QCoapPrivateKey &operator=(const QCoapPrivateKey &other); 33 | 34 | void swap(QCoapPrivateKey &other) noexcept 35 | { d.swap(other.d); } 36 | 37 | bool isNull() const; 38 | 39 | QByteArray key() const; 40 | Qt::HANDLE handle() const; 41 | QSsl::KeyAlgorithm algorithm() const; 42 | QSsl::EncodingFormat encodingFormat() const; 43 | QByteArray passPhrase() const; 44 | private: 45 | QSharedDataPointer d; 46 | }; 47 | 48 | class QCoapSecurityConfigurationPrivate; 49 | class Q_COAP_EXPORT QCoapSecurityConfiguration 50 | { 51 | public: 52 | QCoapSecurityConfiguration(); 53 | QCoapSecurityConfiguration(const QCoapSecurityConfiguration &other); 54 | ~QCoapSecurityConfiguration(); 55 | 56 | QCoapSecurityConfiguration(QCoapSecurityConfiguration &&other) noexcept; 57 | QCoapSecurityConfiguration &operator=(QCoapSecurityConfiguration &&other) noexcept 58 | { swap(other); return *this; } 59 | QCoapSecurityConfiguration &operator=(const QCoapSecurityConfiguration &other); 60 | 61 | void swap(QCoapSecurityConfiguration &other) noexcept 62 | { d.swap(other.d); } 63 | 64 | void setPreSharedKeyIdentity(const QByteArray &preSharedKeyIdentity); 65 | QByteArray preSharedKeyIdentity() const; 66 | 67 | void setPreSharedKey(const QByteArray &preSharedKey); 68 | QByteArray preSharedKey() const; 69 | 70 | void setDefaultCipherString(const QString &cipherString); 71 | QString defaultCipherString() const; 72 | 73 | void setCaCertificates(const QList &certificates); 74 | QList caCertificates() const; 75 | 76 | void setLocalCertificateChain(const QList &localChain); 77 | QList localCertificateChain() const; 78 | 79 | void setPrivateKey(const QCoapPrivateKey &key); 80 | QCoapPrivateKey privateKey() const; 81 | 82 | private: 83 | QSharedDataPointer d; 84 | }; 85 | 86 | Q_DECLARE_SHARED(QCoapSecurityConfiguration) 87 | 88 | QT_END_NAMESPACE 89 | 90 | Q_DECLARE_METATYPE(QCoapSecurityConfiguration) 91 | 92 | #endif // QCOAPSECURITYCONFIGURATION_H 93 | -------------------------------------------------------------------------------- /src/coap/qcoapconnection_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 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 | #ifndef QCOAPCONNECTION_P_H 6 | #define QCOAPCONNECTION_P_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | // 18 | // W A R N I N G 19 | // ------------- 20 | // 21 | // This file is not part of the Qt API. It exists purely as an 22 | // implementation detail. This header file may change from version to 23 | // version without notice, or even be removed. 24 | // 25 | // We mean it. 26 | // 27 | 28 | QT_BEGIN_NAMESPACE 29 | 30 | class QCoapConnectionPrivate; 31 | class Q_AUTOTEST_EXPORT QCoapConnection : public QObject 32 | { 33 | Q_OBJECT 34 | public: 35 | enum class ConnectionState : quint8 { 36 | Unconnected, 37 | Bound 38 | }; 39 | 40 | explicit QCoapConnection(QtCoap::SecurityMode securityMode = QtCoap::SecurityMode::NoSecurity, 41 | QObject *parent = nullptr); 42 | virtual ~QCoapConnection(); 43 | 44 | bool isSecure() const; 45 | QtCoap::SecurityMode securityMode() const; 46 | ConnectionState state() const; 47 | QCoapSecurityConfiguration securityConfiguration() const; 48 | 49 | Q_INVOKABLE void setSecurityConfiguration(const QCoapSecurityConfiguration &configuration); 50 | Q_INVOKABLE void disconnect(); 51 | 52 | #if QT_CONFIG(networkinterface) 53 | void setUdpNetworkInterface(const QNetworkInterface &iface); 54 | QNetworkInterface udpNetworkInterface() const; 55 | #endif 56 | 57 | Q_SIGNALS: 58 | void error(QAbstractSocket::SocketError error); 59 | void readyRead(const QByteArray &data, const QHostAddress &sender); 60 | void bound(); 61 | void securityConfigurationChanged(); 62 | 63 | private: 64 | void startToSendRequest(); 65 | 66 | protected: 67 | QCoapConnection(QObjectPrivate &dd, QObject *parent = nullptr); 68 | 69 | virtual void bind(const QString &host, quint16 port) = 0; 70 | virtual void writeData(const QByteArray &data, const QString &host, quint16 port) = 0; 71 | virtual void close() = 0; 72 | 73 | private: 74 | friend class QCoapProtocolPrivate; 75 | 76 | Q_DECLARE_PRIVATE(QCoapConnection) 77 | }; 78 | 79 | struct CoapFrame { 80 | QByteArray currentPdu; 81 | QString host; 82 | quint16 port = 0; 83 | 84 | CoapFrame(const QByteArray &pdu, const QString &hostName, quint16 portNumber) 85 | : currentPdu(pdu), host(hostName), port(portNumber) {} 86 | }; 87 | 88 | class Q_AUTOTEST_EXPORT QCoapConnectionPrivate : public QObjectPrivate 89 | { 90 | public: 91 | QCoapConnectionPrivate(QtCoap::SecurityMode security = QtCoap::SecurityMode::NoSecurity); 92 | 93 | ~QCoapConnectionPrivate() override = default; 94 | 95 | void sendRequest(const QByteArray &request, const QString &host, quint16 port); 96 | 97 | QCoapSecurityConfiguration securityConfiguration; 98 | QtCoap::SecurityMode securityMode; 99 | QCoapConnection::ConnectionState state; 100 | QQueue framesToSend; 101 | #if QT_CONFIG(networkinterface) 102 | QNetworkInterface udpNetworkInterface; 103 | #endif 104 | 105 | Q_DECLARE_PUBLIC(QCoapConnection) 106 | }; 107 | 108 | QT_END_NAMESPACE 109 | 110 | #endif // QCOAPCONNECTION_P_H 111 | -------------------------------------------------------------------------------- /src/coap/qcoapclient.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPCLIENT_H 7 | #define QCOAPCLIENT_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class QCoapReply; 19 | class QCoapResourceDiscoveryReply; 20 | class QCoapRequest; 21 | class QCoapProtocol; 22 | class QCoapConnection; 23 | class QCoapSecurityConfiguration; 24 | class QCoapMessage; 25 | class QIODevice; 26 | 27 | class QCoapClientPrivate; 28 | class Q_COAP_EXPORT QCoapClient : public QObject 29 | { 30 | Q_OBJECT 31 | #if QT_CONFIG(networkinterface) 32 | Q_PROPERTY(QNetworkInterface bindInterface READ bindInterface WRITE setBindInterface 33 | NOTIFY bindInterfaceChanged) 34 | #endif 35 | public: 36 | explicit QCoapClient(QtCoap::SecurityMode securityMode = QtCoap::SecurityMode::NoSecurity, 37 | QObject *parent = nullptr); 38 | ~QCoapClient(); 39 | 40 | QCoapReply *get(const QCoapRequest &request); 41 | QCoapReply *get(const QUrl &url); 42 | QCoapReply *put(const QCoapRequest &request, const QByteArray &data = QByteArray()); 43 | QCoapReply *put(const QCoapRequest &request, QIODevice *device); 44 | QCoapReply *put(const QUrl &url, const QByteArray &data = QByteArray()); 45 | QCoapReply *post(const QCoapRequest &request, const QByteArray &data = QByteArray()); 46 | QCoapReply *post(const QCoapRequest &request, QIODevice *device); 47 | QCoapReply *post(const QUrl &url, const QByteArray &data = QByteArray()); 48 | QCoapReply *deleteResource(const QCoapRequest &request); 49 | QCoapReply *deleteResource(const QUrl &url); 50 | QCoapReply *observe(const QCoapRequest &request); 51 | QCoapReply *observe(const QUrl &request); 52 | void cancelObserve(QCoapReply *notifiedReply); 53 | void cancelObserve(const QUrl &url); 54 | void disconnect(); 55 | 56 | QCoapResourceDiscoveryReply *discover( 57 | QtCoap::MulticastGroup group = QtCoap::MulticastGroup::AllCoapNodesIPv4, 58 | int port = QtCoap::DefaultPort, 59 | const QString &discoveryPath = QLatin1String("/.well-known/core")); 60 | QCoapResourceDiscoveryReply *discover( 61 | const QUrl &baseUrl, 62 | const QString &discoveryPath = QLatin1String("/.well-known/core")); 63 | 64 | void setSecurityConfiguration(const QCoapSecurityConfiguration &configuration); 65 | void setBlockSize(quint16 blockSize); 66 | void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value); 67 | void setMaximumServerResponseDelay(uint responseDelay); 68 | void setAckTimeout(uint ackTimeout); 69 | void setAckRandomFactor(double ackRandomFactor); 70 | void setMaximumRetransmitCount(uint maximumRetransmitCount); 71 | void setMinimumTokenSize(int tokenSize); 72 | 73 | #if QT_CONFIG(networkinterface) 74 | void setBindInterface(const QNetworkInterface &iface); 75 | QNetworkInterface bindInterface() const; 76 | #endif 77 | 78 | Q_SIGNALS: 79 | void finished(QCoapReply *reply); 80 | void responseToMulticastReceived(QCoapReply *reply, const QCoapMessage &message, 81 | const QHostAddress &sender); 82 | void error(QCoapReply *reply, QtCoap::Error error); 83 | 84 | #if QT_CONFIG(networkinterface) 85 | void bindInterfaceChanged(const QNetworkInterface &iface); 86 | #endif 87 | 88 | protected: 89 | Q_DECLARE_PRIVATE(QCoapClient) 90 | }; 91 | 92 | QT_END_NAMESPACE 93 | 94 | #endif // QCOAPCLIENT_H 95 | -------------------------------------------------------------------------------- /src/coap/qcoapinternalrequest_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPINTERNALREQUEST_H 7 | #define QCOAPINTERNALREQUEST_H 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | // 20 | // W A R N I N G 21 | // ------------- 22 | // 23 | // This file is not part of the Qt API. It exists purely as an 24 | // implementation detail. This header file may change from version to 25 | // version without notice, or even be removed. 26 | // 27 | // We mean it. 28 | // 29 | 30 | QT_BEGIN_NAMESPACE 31 | 32 | class QCoapRequest; 33 | class QCoapInternalRequestPrivate; 34 | class Q_AUTOTEST_EXPORT QCoapInternalRequest : public QCoapInternalMessage 35 | { 36 | Q_OBJECT 37 | public: 38 | explicit QCoapInternalRequest(QObject *parent = nullptr); 39 | explicit QCoapInternalRequest(const QCoapRequest &request, QObject *parent = nullptr); 40 | 41 | bool isValid() const override; 42 | 43 | void initEmptyMessage(quint16 messageId, QCoapMessage::Type type); 44 | 45 | QByteArray toQByteArray() const; 46 | void setMessageId(quint16); 47 | void setToken(const QCoapToken&); 48 | void setToRequestBlock(uint blockNumber, uint blockSize); 49 | void setToSendBlock(uint blockNumber, uint blockSize); 50 | bool checkBlockNumber(uint blockNumber); 51 | 52 | using QCoapInternalMessage::addOption; 53 | void addOption(const QCoapOption &option) override; 54 | bool addUriOptions(QUrl uri, const QUrl &proxyUri = QUrl()); 55 | 56 | QCoapToken token() const; 57 | QUrl targetUri() const; 58 | QtCoap::Method method() const; 59 | bool isObserve() const; 60 | bool isObserveCancelled() const; 61 | bool isMulticast() const; 62 | QCoapConnection *connection() const; 63 | uint retransmissionCounter() const; 64 | void setMethod(QtCoap::Method method); 65 | void setConnection(QCoapConnection *connection); 66 | void setObserveCancelled(); 67 | 68 | void setTargetUri(QUrl targetUri); 69 | void setTimeout(uint timeout); 70 | void setMaxTransmissionWait(uint timeout); 71 | void setMulticastTimeout(uint responseDelay); 72 | void restartTransmission(); 73 | void startMulticastTransmission(); 74 | void stopTransmission(); 75 | 76 | Q_SIGNALS: 77 | void timeout(QCoapInternalRequest*); 78 | void maxTransmissionSpanReached(QCoapInternalRequest*); 79 | void multicastRequestExpired(QCoapInternalRequest*); 80 | 81 | protected: 82 | QCoapOption uriHostOption(const QUrl &uri) const; 83 | QCoapOption blockOption(QCoapOption::OptionName name, uint blockNumber, uint blockSize) const; 84 | 85 | private: 86 | Q_DECLARE_PRIVATE(QCoapInternalRequest) 87 | }; 88 | 89 | class Q_AUTOTEST_EXPORT QCoapInternalRequestPrivate : public QCoapInternalMessagePrivate 90 | { 91 | public: 92 | QCoapInternalRequestPrivate() = default; 93 | 94 | QUrl targetUri; 95 | QtCoap::Method method = QtCoap::Method::Invalid; 96 | QCoapConnection *connection = nullptr; 97 | QByteArray fullPayload; 98 | 99 | uint timeout = 0; 100 | uint retransmissionCounter = 0; 101 | QTimer *timeoutTimer = nullptr; 102 | QTimer *maxTransmitWaitTimer = nullptr; 103 | QTimer *multicastExpireTimer = nullptr; 104 | 105 | bool observeCancelled = false; 106 | bool transmissionInProgress = false; 107 | 108 | Q_DECLARE_PUBLIC(QCoapInternalRequest) 109 | }; 110 | 111 | QT_END_NAMESPACE 112 | 113 | #endif // QCOAPINTERNALREQUEST_H 114 | -------------------------------------------------------------------------------- /examples/coap/simplecoapclient/optiondialog.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "optiondialog.h" 5 | #include "ui_optiondialog.h" 6 | 7 | OptionDialog::OptionDialog(const QList &options, QWidget *parent) : 8 | QDialog(parent), 9 | ui(new Ui::OptionDialog), 10 | m_options(options) 11 | { 12 | ui->setupUi(this); 13 | connect(ui->tableWidget, &QTableWidget::itemSelectionChanged, this, [this]() { 14 | const auto selection = ui->tableWidget->selectedItems(); 15 | ui->removeButton->setEnabled(!selection.isEmpty()); 16 | }); 17 | 18 | fillOptions(); 19 | applyOptionValues(); 20 | 21 | auto header = ui->tableWidget->horizontalHeader(); 22 | header->setSectionResizeMode(QHeaderView::Stretch); 23 | } 24 | 25 | OptionDialog::~OptionDialog() 26 | { 27 | delete ui; 28 | } 29 | 30 | QList OptionDialog::options() const 31 | { 32 | return m_options; 33 | } 34 | 35 | void OptionDialog::on_addButton_clicked() 36 | { 37 | const auto option = 38 | ui->optionComboBox->currentData(Qt::UserRole).value(); 39 | m_options.push_back(QCoapOption(option, ui->optionValueEdit->text())); 40 | 41 | addTableRow(ui->optionComboBox->currentText(), ui->optionValueEdit->text()); 42 | } 43 | 44 | void OptionDialog::on_removeButton_clicked() 45 | { 46 | const auto idx = ui->tableWidget->currentRow(); 47 | if (idx >= 0 && idx < ui->tableWidget->rowCount()) { 48 | ui->tableWidget->removeRow(idx); 49 | m_options.removeAt(idx); 50 | } 51 | } 52 | 53 | void OptionDialog::on_clearButton_clicked() 54 | { 55 | m_options.clear(); 56 | ui->tableWidget->setRowCount(0); 57 | } 58 | 59 | void OptionDialog::fillOptions() 60 | { 61 | ui->tableWidget->setHorizontalHeaderLabels({tr("Name"), tr("Value")}); 62 | ui->optionComboBox->addItem(tr("None"), QCoapOption::Invalid); 63 | ui->optionComboBox->addItem(tr("Block1"), QCoapOption::Block1); 64 | ui->optionComboBox->addItem(tr("Block2"), QCoapOption::Block2); 65 | ui->optionComboBox->addItem(tr("Content-Format"), QCoapOption::ContentFormat); 66 | ui->optionComboBox->addItem(tr("If-Match"), QCoapOption::IfMatch); 67 | ui->optionComboBox->addItem(tr("If-None-Match"), QCoapOption::IfNoneMatch); 68 | ui->optionComboBox->addItem(tr("Location-Path"), QCoapOption::LocationPath); 69 | ui->optionComboBox->addItem(tr("Location-Query"), QCoapOption::LocationQuery); 70 | ui->optionComboBox->addItem(tr("Max-Age"), QCoapOption::MaxAge); 71 | ui->optionComboBox->addItem(tr("Observe"), QCoapOption::Observe); 72 | ui->optionComboBox->addItem(tr("Proxy-Scheme"), QCoapOption::ProxyScheme); 73 | ui->optionComboBox->addItem(tr("Proxy-Uri"), QCoapOption::ProxyUri); 74 | ui->optionComboBox->addItem(tr("Size1"), QCoapOption::Size1); 75 | ui->optionComboBox->addItem(tr("Size2"), QCoapOption::Size2); 76 | ui->optionComboBox->addItem(tr("Uri-Host"), QCoapOption::UriHost); 77 | ui->optionComboBox->addItem(tr("Uri-Path"), QCoapOption::UriPath); 78 | ui->optionComboBox->addItem(tr("Uri-Port"), QCoapOption::UriPort); 79 | ui->optionComboBox->addItem(tr("Uri-Query"), QCoapOption::UriQuery); 80 | } 81 | 82 | void OptionDialog::applyOptionValues() 83 | { 84 | for (const auto &option : std::as_const(m_options)) { 85 | const int optionIndex = ui->optionComboBox->findData(option.name()); 86 | if (optionIndex != -1) 87 | addTableRow(ui->optionComboBox->itemText(optionIndex), option.stringValue()); 88 | } 89 | } 90 | 91 | void OptionDialog::addTableRow(const QString &name, const QString &value) 92 | { 93 | const auto rowCount = ui->tableWidget->rowCount(); 94 | ui->tableWidget->insertRow(rowCount); 95 | 96 | QTableWidgetItem *optionItem = new QTableWidgetItem(name); 97 | optionItem->setFlags(optionItem->flags() ^ Qt::ItemIsEditable); 98 | ui->tableWidget->setItem(rowCount, 0, optionItem); 99 | 100 | QTableWidgetItem *valueItem = new QTableWidgetItem(value); 101 | valueItem->setFlags(valueItem->flags() ^ Qt::ItemIsEditable); 102 | ui->tableWidget->setItem(rowCount, 1, valueItem); 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | This is the Qt CoAP module repository. CoAP is a protocol for IoT devices, and machine to machine communication. 3 | The full specification can be found in [RFC 7252](https://tools.ietf.org/html/rfc7252). 4 | 5 | ### Supported features 6 | 7 | - CoAP Client 8 | - Send GET/POST/PUT/DELETE requests 9 | - Discover resources (single server) 10 | - Observe resources and cancel the observation 11 | - Blockwise requests and replies 12 | - Confirmable and non-confirmable messages 13 | - Some options can be added to the request 14 | - Replies can be received in a separate or piggybacked message 15 | 16 | ### Unsupported yet 17 | 18 | - CoAP Server 19 | 20 | ## How to use the library 21 | 22 | ### GET/POST/PUT/DELETE requests 23 | ```c++ 24 | QCoapClient* client = new QCoapClient(this); 25 | connect(client, &QCoapClient::finished, this, &MyClass::onFinished); 26 | client->get(QUrl("coap://coap.me/test")); 27 | client->put(QUrl("coap://coap.me/test"), QByteArray("payload")); 28 | ``` 29 | or 30 | ```c++ 31 | QCoapReply* reply = client->get(QCoapRequest("coap://coap.me/test")); 32 | connect(reply, &QCoapReply::finished, this, &MyClass::onFinished); 33 | ``` 34 | The slot connected to the `QCoapReply::finished(QCoapReply *)` signal can use the `QCoapReply` 35 | object like a `QIODevice` object. 36 | 37 | ### OBSERVE requests 38 | Observe requests are used to receive automatic server notifications for a resource. For Observe 39 | requests specifically, you can use the `QCoapReply::notified(QCoapReply *, QCoapMessage)` signal 40 | to handle notifications from the CoAP server. 41 | ```c++ 42 | QCoapRequest request = QCoapRequest("coap://coap.me/obs"); 43 | QCoapReply* reply = client->observe(request); 44 | connect(reply, &QCoapReply::notified, this, &MyClass::onNotified); 45 | ``` 46 | 47 | You can then stop the observation with 48 | ```c++ 49 | client->cancelObserve(reply); 50 | ``` 51 | 52 | The notified signal will provide the `QCoapReply` and most recent message. 53 | 54 | ### DISCOVERY requests 55 | For machine to machine communication, CoAP Discovery requests is used to query the resources 56 | available to an endpoint, or to the complete network. 57 | ```c++ 58 | QCoapResourceDiscoveryReply *reply = client->discover("coap://coap.me/"); 59 | connect(reply, &QCoapReply::discovered, this, &MyClass::onDiscovered); 60 | ``` 61 | 62 | For multicast discovery use one of the groups from the `QtCoap::MulticastGroup` enum, instead of 63 | specifying the discovery path: 64 | 65 | ```c++ 66 | QCoapResourceDiscoveryReply *reply = client->discover(QtCoap::AllCoapNodesIPv6LinkLocal); 67 | ``` 68 | 69 | If no group is specified, `QtCoap::AllCoapNodesIPv4` will be used by default. 70 | 71 | The signal `discovered` can be triggered multiple times, and will provide the list of resources 72 | returned by the server(s). 73 | 74 | ### Using security 75 | 76 | The following example code can be used to secure CoAP communication: 77 | 78 | ```c++ 79 | QCoapClient* client = new QCoapClient(this, QtCoap::PreSharedKey); 80 | QCoapSecurityConfiguration config; 81 | config.setPreSharedKey("secretPSK"); 82 | config.setIdentity("Client_identity"); 83 | client->setSecurityConfiguration(config); 84 | ``` 85 | 86 | To use X.509 certificate-based security use `QtCoap::Certificate` for the security mode. 87 | `QtCoap::RawPublicKey` mode is not supported yet. 88 | 89 | ## Automated tests 90 | Automated tests require a Californium plugtest server. Plugtest is a CoAP server used to test the 91 | main features of the CoAP protocol. The following command starts a plugtest server using Docker. 92 | 93 | ```bash 94 | docker run --name coap-test-server -d --rm -p 5683:5683/udp aleravat/coap-test-server:latest 95 | ``` 96 | 97 | Automated tests require `COAP_TEST_SERVER_IP` environment variable to be set, containing Plugtest 98 | server IP address. This address will be used to connect to the Plugtest server on port 5683. 99 | 100 | The IP address of the docker container can found identified by: 101 | 1. Retrieve the container id with `docker ps` 102 | ``` 103 | $ docker ps 104 | CONTAINER ID IMAGE [...] 105 | 826073e84e7f aleravat/coap-test-server:latest [...] 106 | ``` 107 | 2. Get the IP address with `docker inspect | grep IPAddress` 108 | ``` 109 | $ docker inspect 826073e84e7f | grep IPAddress 110 | [...] 111 | "IPAddress": "172.17.0.3", 112 | [...] 113 | ``` 114 | 3. Set the environment variable in QtCreator, or in a the terminal used `export COAP_TEST_SERVER_IP="172.17.0.3"` 115 | -------------------------------------------------------------------------------- /examples/coap/quicksecureclient/qmlcoapsecureclient.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "qmlcoapsecureclient.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | Q_STATIC_LOGGING_CATEGORY(lcCoapClient, "qt.coap.client") 14 | 15 | QmlCoapSecureClient::QmlCoapSecureClient(QObject *parent) 16 | : QObject(parent) 17 | , m_coapClient(nullptr) 18 | , m_securityMode(QtCoap::SecurityMode::NoSecurity) 19 | { 20 | } 21 | 22 | QmlCoapSecureClient::~QmlCoapSecureClient() 23 | { 24 | if (m_coapClient) { 25 | delete m_coapClient; 26 | m_coapClient = nullptr; 27 | } 28 | } 29 | 30 | static QString errorMessage(QtCoap::Error errorCode) 31 | { 32 | const auto error = QMetaEnum::fromType().valueToKey(static_cast(errorCode)); 33 | return QmlCoapSecureClient::tr("Request failed with error: %1\n").arg(error); 34 | } 35 | 36 | //! [set_security_mode] 37 | void QmlCoapSecureClient::setSecurityMode(QtCoap::SecurityMode mode) 38 | { 39 | // Create a new client, if the security mode has changed 40 | if (m_coapClient && mode != m_securityMode) { 41 | delete m_coapClient; 42 | m_coapClient = nullptr; 43 | } 44 | 45 | if (!m_coapClient) { 46 | m_coapClient = new QCoapClient(mode); 47 | m_securityMode = mode; 48 | 49 | connect(m_coapClient, &QCoapClient::finished, this, 50 | [this](QCoapReply *reply) { 51 | if (!reply) 52 | emit finished(tr("Something went wrong, received a null reply")); 53 | else if (reply->errorReceived() != QtCoap::Error::Ok) 54 | emit finished(errorMessage(reply->errorReceived())); 55 | else 56 | emit finished(reply->message().payload()); 57 | }); 58 | 59 | connect(m_coapClient, &QCoapClient::error, this, 60 | [this](QCoapReply *, QtCoap::Error errorCode) { 61 | emit finished(errorMessage(errorCode)); 62 | }); 63 | } 64 | } 65 | //! [set_security_mode] 66 | 67 | //! [send_get_request] 68 | void QmlCoapSecureClient::sendGetRequest(const QString &host, const QString &path, int port) 69 | { 70 | if (!m_coapClient) 71 | return; 72 | 73 | m_coapClient->setSecurityConfiguration(m_configuration); 74 | 75 | QUrl url; 76 | url.setHost(host); 77 | url.setPath(path); 78 | url.setPort(port); 79 | m_coapClient->get(url); 80 | } 81 | //! [send_get_request] 82 | 83 | //! [set_configuration_psk] 84 | void 85 | QmlCoapSecureClient::setSecurityConfiguration(const QString &preSharedKey, const QString &identity) 86 | { 87 | QCoapSecurityConfiguration configuration; 88 | configuration.setPreSharedKey(preSharedKey.toUtf8()); 89 | configuration.setPreSharedKeyIdentity(identity.toUtf8()); 90 | m_configuration = configuration; 91 | } 92 | //! [set_configuration_psk] 93 | 94 | //! [set_configuration_cert] 95 | void QmlCoapSecureClient::setSecurityConfiguration(const QString &localCertificatePath, 96 | const QString &caCertificatePath, 97 | const QString &privateKeyPath) 98 | { 99 | QCoapSecurityConfiguration configuration; 100 | 101 | const auto localCerts = 102 | QSslCertificate::fromPath(QUrl(localCertificatePath).toLocalFile(), QSsl::Pem, 103 | QSslCertificate::PatternSyntax::FixedString); 104 | if (localCerts.isEmpty()) 105 | qCWarning(lcCoapClient, "The specified local certificate file is not valid."); 106 | else 107 | configuration.setLocalCertificateChain(localCerts.toVector()); 108 | 109 | const auto caCerts = QSslCertificate::fromPath(QUrl(caCertificatePath).toLocalFile(), QSsl::Pem, 110 | QSslCertificate::PatternSyntax::FixedString); 111 | if (caCerts.isEmpty()) 112 | qCWarning(lcCoapClient, "The specified CA certificate file is not valid."); 113 | else 114 | configuration.setCaCertificates(caCerts.toVector()); 115 | 116 | QFile privateKey(QUrl(privateKeyPath).toLocalFile()); 117 | if (privateKey.open(QIODevice::ReadOnly)) { 118 | QCoapPrivateKey key(privateKey.readAll(), QSsl::Ec); 119 | configuration.setPrivateKey(key); 120 | } else { 121 | qCWarning(lcCoapClient) << "Unable to read the specified private key file" 122 | << privateKeyPath; 123 | } 124 | m_configuration = configuration; 125 | } 126 | //! [set_configuration_cert] 127 | 128 | //! [disconnect] 129 | void QmlCoapSecureClient::disconnect() 130 | { 131 | if (m_coapClient) 132 | m_coapClient->disconnect(); 133 | } 134 | //! [disconnect] 135 | -------------------------------------------------------------------------------- /licenseRule.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "comment": ["file_pattern_ending: strings matched against the end of a file name.", 4 | "location keys: regular expression matched against the beginning of", 5 | "the file path (relative to the git submodule root).", 6 | "spdx: list of SPDX-License-Expression's allowed in the matching files.", 7 | "-------------------------------------------------------", 8 | "Files with the following endings are Build System licensed,", 9 | "unless they are examples", 10 | "Files with other endings can also be build system files" 11 | ], 12 | "file_pattern_ending": ["CMakeLists.txt", ".cmake", ".pro", ".pri", ".prf", 13 | "configure", "configure.bat", "cmake.in", "plist.in", "CMakeLists.txt.in", 14 | ".cmake.conf",".tag", "ci_config_linux.json", 15 | ".yaml", ".yml"], 16 | "location": { 17 | "": { 18 | "comment": "Default", 19 | "file type": "build system", 20 | "spdx": ["BSD-3-Clause"] 21 | }, 22 | "(.*)(examples/|snippets/)": { 23 | "comment": "Example takes precedent", 24 | "file type": "examples and snippets", 25 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 26 | } 27 | } 28 | }, 29 | { 30 | "comments": ["Files with the following endings are infrastructure licensed"], 31 | "file_pattern_ending": [".gitattributes", ".gitignore", ".gitmodules", ".gitreview", 32 | "_clang-format", "licenseRule.json", "REUSE.toml"], 33 | "location":{ 34 | "": { 35 | "comment": "Default", 36 | "file type": "infrastructure", 37 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 38 | } 39 | } 40 | }, 41 | { 42 | "comments": ["Files with the following endings are Tool licensed,", 43 | "unless they are examples.", 44 | "Files with other endings can also be tool files."], 45 | "file_pattern_ending": [".sh", ".py", ".pl", ".bat", ".ps1"], 46 | "location":{ 47 | "": { 48 | "comment": "Default", 49 | "file type": "tools and utils", 50 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"] 51 | }, 52 | "(.*)(examples/|snippets/)": { 53 | "comment": "Example takes precedent", 54 | "file type": "examples and snippets", 55 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 56 | } 57 | } 58 | }, 59 | { 60 | "comment": "Files with the following endings are Documentation licensed.", 61 | "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", "qt_attribution.json", 62 | "README.md", ".css"], 63 | "location":{ 64 | "": { 65 | "comment": "", 66 | "file type": "documentation", 67 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 68 | } 69 | } 70 | }, 71 | { 72 | "comment": ["All other files", 73 | "The licensing is defined only by the file location in the Qt module repository.", 74 | "NO key for this case!", 75 | "This needs to be the last entry of the file."], 76 | "location": { 77 | "": { 78 | "comment": "Default", 79 | "file type": "module and plugin", 80 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 81 | }, 82 | "dist/": { 83 | "comment": "Default", 84 | "file type": "documentation", 85 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 86 | }, 87 | "src/": { 88 | "comment": "Default", 89 | "file type": "module and plugin", 90 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 91 | }, 92 | "tests/": { 93 | "comment": "Default", 94 | "file type": "test", 95 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 96 | }, 97 | "(.*)(examples/|snippets/)": { 98 | "comment": "Default", 99 | "file type": "examples and snippets", 100 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 101 | }, 102 | "tests/auto/qcoapclient/testdata/.*pem": { 103 | "comment": "", 104 | "file type": "keys", 105 | "spdx": ["CC0-1.0"] 106 | } 107 | } 108 | } 109 | ] 110 | -------------------------------------------------------------------------------- /examples/coap/simplecoapclient/optiondialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | OptionDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 414 10 | 313 11 | 12 | 13 | 14 | Add Options 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Option 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 0 35 | 0 36 | 37 | 38 | 39 | 40 | 120 41 | 0 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | QAbstractItemView::SingleSelection 55 | 56 | 57 | QAbstractItemView::SelectRows 58 | 59 | 60 | 2 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Qt::Horizontal 70 | 71 | 72 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 0 85 | 0 86 | 87 | 88 | 89 | 90 | 100 91 | 0 92 | 93 | 94 | 95 | Add 96 | 97 | 98 | 99 | 100 | 101 | 102 | false 103 | 104 | 105 | Remove 106 | 107 | 108 | 109 | 110 | 111 | 112 | Clear 113 | 114 | 115 | 116 | 117 | 118 | 119 | Qt::Vertical 120 | 121 | 122 | 123 | 20 124 | 40 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | buttonBox 139 | accepted() 140 | OptionDialog 141 | accept() 142 | 143 | 144 | 152 145 | 289 146 | 147 | 148 | 206 149 | 156 150 | 151 | 152 | 153 | 154 | buttonBox 155 | rejected() 156 | OptionDialog 157 | reject() 158 | 159 | 160 | 152 161 | 289 162 | 163 | 164 | 206 165 | 156 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /src/coap/qcoapresourcediscoveryreply.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:critical reason:data-parser 5 | 6 | #include "qcoapresourcediscoveryreply_p.h" 7 | #include "qcoapinternalreply_p.h" 8 | #include "qcoapnamespace_p.h" 9 | 10 | QT_BEGIN_NAMESPACE 11 | 12 | QCoapResourceDiscoveryReplyPrivate::QCoapResourceDiscoveryReplyPrivate(const QCoapRequest &request) : 13 | QCoapReplyPrivate(request) 14 | { 15 | } 16 | 17 | /*! 18 | \internal 19 | 20 | Updates the QCoapResourceDiscoveryReply object, its message and list of resources 21 | with data of the internal reply \a internalReply. 22 | */ 23 | void QCoapResourceDiscoveryReplyPrivate::_q_setContent(const QHostAddress &sender, 24 | const QCoapMessage &msg, 25 | QtCoap::ResponseCode code) 26 | { 27 | Q_Q(QCoapResourceDiscoveryReply); 28 | 29 | if (q->isFinished()) 30 | return; 31 | 32 | message = msg; 33 | responseCode = code; 34 | 35 | if (QtCoap::isError(responseCode)) { 36 | _q_setError(responseCode); 37 | } else { 38 | auto res = QCoapResourceDiscoveryReplyPrivate::resourcesFromCoreLinkList(sender, 39 | message.payload()); 40 | resources.append(res); 41 | emit q->discovered(q, res); 42 | } 43 | } 44 | 45 | /*! 46 | \class QCoapResourceDiscoveryReply 47 | \inmodule QtCoap 48 | 49 | \brief The QCoapResourceDiscoveryReply class holds the data of a CoAP reply 50 | for a resource discovery request. 51 | 52 | \reentrant 53 | 54 | This class is used for discovery requests. It emits the discovered() 55 | signal if and when resources are discovered. When using a multicast 56 | address for discovery, the discovered() signal will be emitted once 57 | for each response received. 58 | 59 | \note A QCoapResourceDiscoveryReply is a QCoapReply that stores also a list 60 | of QCoapResources. 61 | 62 | \sa QCoapClient, QCoapRequest, QCoapReply, QCoapResource 63 | */ 64 | 65 | /*! 66 | \fn void QCoapResourceDiscoveryReply::discovered(QCoapResourceDiscoveryReply *reply, 67 | QList resources); 68 | 69 | This signal is emitted whenever a CoAP resource is discovered. 70 | 71 | The \a reply parameter contains a pointer to the reply that has just been 72 | received, and \a resources contains a list of resources that were discovered. 73 | 74 | \sa QCoapReply::finished() 75 | */ 76 | 77 | /*! 78 | \internal 79 | 80 | Constructs a new CoAP discovery reply from the \a request and sets \a parent 81 | as its parent. 82 | */ 83 | QCoapResourceDiscoveryReply::QCoapResourceDiscoveryReply(const QCoapRequest &request, QObject *parent) : 84 | QCoapReply(*new QCoapResourceDiscoveryReplyPrivate(request), parent) 85 | { 86 | } 87 | 88 | /*! 89 | Returns the list of resources. 90 | */ 91 | QList QCoapResourceDiscoveryReply::resources() const 92 | { 93 | Q_D(const QCoapResourceDiscoveryReply); 94 | return d->resources; 95 | } 96 | 97 | /*! 98 | \internal 99 | 100 | Decodes the \a data received from the \a sender to a list of QCoapResource 101 | objects. The \a data byte array contains the frame returned by the 102 | discovery request. 103 | */ 104 | QList 105 | QCoapResourceDiscoveryReplyPrivate::resourcesFromCoreLinkList(const QHostAddress &sender, 106 | const QByteArray &data) 107 | { 108 | QList resourceList; 109 | 110 | QLatin1String quote = QLatin1String("\""); 111 | const QList links = data.split(','); 112 | for (const QByteArray &link : links) { 113 | QCoapResource resource; 114 | resource.setHost(sender); 115 | 116 | const QList parameterList = link.split(';'); 117 | for (const QByteArray ¶meter : parameterList) { 118 | QString parameterString = QString::fromUtf8(parameter); 119 | const qsizetype length = parameterString.size(); 120 | if (parameter.startsWith('<')) 121 | resource.setPath(parameterString.mid(1, length - 2)); 122 | else if (parameter.startsWith("title=")) 123 | resource.setTitle(parameterString.mid(6).remove(quote)); 124 | else if (parameter.startsWith("rt=")) 125 | resource.setResourceType(parameterString.mid(3).remove(quote)); 126 | else if (parameter.startsWith("if=")) 127 | resource.setInterface(parameterString.mid(3).remove(quote)); 128 | else if (parameter.startsWith("sz=")) 129 | resource.setMaximumSize(parameterString.mid(3).remove(quote).toInt()); 130 | else if (parameter.startsWith("ct=")) 131 | resource.setContentFormat(parameterString.mid(3).remove(quote).toUInt()); 132 | else if (parameter == "obs") 133 | resource.setObservable(true); 134 | } 135 | 136 | if (!resource.path().isEmpty()) 137 | resourceList.push_back(resource); 138 | } 139 | 140 | return resourceList; 141 | } 142 | 143 | QT_END_NAMESPACE 144 | -------------------------------------------------------------------------------- /examples/coap/doc/simplecoapclient.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \example simplecoapclient 6 | \title Simple CoAP Client 7 | \examplecategory {Connectivity} 8 | \ingroup qtcoap-examples 9 | \brief Creating an application that communicates with a CoAP server. 10 | 11 | \image simplecoapclient.webp 12 | 13 | \e {Simple CoAP Client} demonstrates how to create a minimalistic CoAP client 14 | application to send and receive CoAP messages. 15 | 16 | \include examples-run.qdocinc 17 | 18 | \section1 Setting Up a CoAP Server 19 | 20 | To use the application, you need to specify a CoAP server. You have the following 21 | options: 22 | 23 | \list 24 | \li Use the CoAP test server located at \c {coap://coap.me}. 25 | \li Create a CoAP server using \l {https://github.com/obgm/libcoap} {libcoap}, 26 | \l {https://github.com/keith-cullen/FreeCoAP} {FreeCoAP} or any other CoAP 27 | server implementation. 28 | \li Use the \l {https://github.com/eclipse/californium/} {Californium} plugtest 29 | server, which supports most of the CoAP features. You can build it manually or 30 | use a ready Docker image, which builds and starts the plugtest server. The steps 31 | for using the docker-based server are described below. 32 | 33 | \endlist 34 | 35 | \section2 Using the Docker-based Test Server 36 | 37 | The following command pulls the docker container for the CoAP server from the Docker 38 | Hub and starts it: 39 | 40 | \badcode 41 | docker run --name coap-test-server -d --rm -p 5683:5683/udp -p 5684:5684/udp tqtc/coap-californium-test-server:3.8.0 42 | \endcode 43 | 44 | To find out the IP address of the docker container, first retrieve the container ID 45 | by running \c {docker ps}, which will output something like: 46 | 47 | \badcode 48 | $ docker ps 49 | CONTAINER ID IMAGE 50 | 5e46502df88f tqtc/coap-californium-test-server:3.8.0 51 | \endcode 52 | 53 | Then you can obtain the IP address with the following command: 54 | 55 | \badcode 56 | docker inspect | grep IPAddress 57 | \endcode 58 | 59 | For example: 60 | 61 | \badcode 62 | $ docker inspect 5e46502df88f | grep IPAddress 63 | ... 64 | "IPAddress": "172.17.0.2", 65 | ... 66 | \endcode 67 | 68 | The CoAP test server will be reachable by the retrieved IP address on ports 69 | \e 5683 (non-secure) and \e 5684 (secure). 70 | 71 | To terminate the docker container after usage, use the following command: 72 | 73 | \badcode 74 | docker stop 75 | \endcode 76 | 77 | The \c {} here is the same as retrieved by the \c {docker ps} 78 | command. 79 | 80 | \section1 Creating a Client 81 | 82 | The first step is to create a CoAP client using the QCoapClient class. Then 83 | we need to connect its signals, to get notified when a CoAP reply is received 84 | or a request has failed: 85 | 86 | \quotefromfile simplecoapclient/mainwindow.cpp 87 | \skipto MainWindow::MainWindow 88 | \printuntil onError 89 | \dots 90 | 91 | \section1 Sending Requests 92 | We use the QCoapRequest class to create CoAP requests. This class provides methods 93 | for constructing CoAP frames. 94 | 95 | \skipto on_runButton_clicked 96 | \printuntil addOption 97 | \dots 98 | 99 | In this example, we set the URL, as well as the message type and add options 100 | to the request. It is also possible to set the payload, message ID, token, 101 | and so on, but we are using the default values here. Note that by default, 102 | the message ID and token are generated randomly. 103 | 104 | Based on the selected request method, we send a \c GET, \c PUT, \c POST or 105 | \c DELETE request to the server: 106 | 107 | \skipto switch 108 | \dots 109 | \printuntil } 110 | \dots 111 | 112 | For \c PUT and \c POST requests we also add \c m_currentData as a payload for 113 | the request. 114 | 115 | For browsing the contents of the server and discovering the resources available on 116 | it, a \e discovery request is used: 117 | 118 | \skipto on_discoverButton_clicked 119 | \printuntil { 120 | \dots 121 | \skipto discoverReply 122 | \printuntil onDiscovered 123 | \dots 124 | 125 | \note Instead of QCoapReply class, we use the QCoapResourceDiscoveryReply to keep 126 | the reply for a discovery request. It has the QCoapResourceDiscoveryReply::discovered 127 | signal, which returns the list of QCoapResources that has been discovered. 128 | 129 | If there are \e observable resources on the server (meaning that they have the 130 | resource type \c obs), we can subscribe to updates on that resource by running 131 | an \e observe request: 132 | 133 | \skipto on_observeButton_clicked 134 | \printuntil { 135 | \dots 136 | \skipto observeReply 137 | \printline observeReply 138 | \dots 139 | \skipto onNotified 140 | \printline onNotified 141 | \dots 142 | 143 | The client can unsubscribe from the resource observation by handling the 144 | \c clicked() signal of the \c cancelObserveButton: 145 | 146 | \skipto clicked 147 | \dots 148 | \printuntil }) 149 | 150 | The responses coming from the server are displayed in the UI: 151 | 152 | \quotefromfile simplecoapclient/mainwindow.cpp 153 | \skipto MainWindow::addMessage 154 | \printto on_runButton_clicked 155 | */ 156 | -------------------------------------------------------------------------------- /src/coap/qcoapprotocol_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #ifndef QCOAPPROTOCOL_P_H 7 | #define QCOAPPROTOCOL_P_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | // 19 | // W A R N I N G 20 | // ------------- 21 | // 22 | // This file is not part of the Qt API. It exists purely as an 23 | // implementation detail. This header file may change from version to 24 | // version without notice, or even be removed. 25 | // 26 | // We mean it. 27 | // 28 | 29 | QT_BEGIN_NAMESPACE 30 | 31 | class QCoapInternalRequest; 32 | class QCoapInternalReply; 33 | class QCoapProtocolPrivate; 34 | class QCoapConnection; 35 | class Q_AUTOTEST_EXPORT QCoapProtocol : public QObject 36 | { 37 | Q_OBJECT 38 | public: 39 | explicit QCoapProtocol(QObject *parent = nullptr); 40 | ~QCoapProtocol(); 41 | 42 | uint ackTimeout() const; 43 | double ackRandomFactor() const; 44 | uint maximumRetransmitCount() const; 45 | quint16 blockSize() const; 46 | uint maximumTransmitSpan() const; 47 | uint maximumTransmitWait() const; 48 | uint maximumLatency() const; 49 | 50 | uint minimumTimeout() const; 51 | uint maximumTimeout() const; 52 | 53 | uint nonConfirmLifetime() const; 54 | uint maximumServerResponseDelay() const; 55 | 56 | Q_SIGNALS: 57 | void finished(QCoapReply *reply); 58 | void responseToMulticastReceived(QCoapReply *reply, const QCoapMessage &message, 59 | const QHostAddress &sender); 60 | void error(QCoapReply *reply, QtCoap::Error error); 61 | 62 | public: 63 | Q_INVOKABLE void setAckTimeout(uint ackTimeout); 64 | Q_INVOKABLE void setAckRandomFactor(double ackRandomFactor); 65 | Q_INVOKABLE void setMaximumRetransmitCount(uint maximumRetransmitCount); 66 | Q_INVOKABLE void setBlockSize(quint16 blockSize); 67 | Q_INVOKABLE void setMaximumServerResponseDelay(uint responseDelay); 68 | Q_INVOKABLE void setMinimumTokenSize(int tokenSize); 69 | 70 | private: 71 | Q_INVOKABLE void sendRequest(QPointer reply, QCoapConnection *connection); 72 | Q_INVOKABLE void cancelObserve(QPointer reply) const; 73 | Q_INVOKABLE void cancelObserve(const QUrl &url) const; 74 | 75 | private: 76 | Q_DECLARE_PRIVATE(QCoapProtocol) 77 | 78 | friend class QCoapClient; 79 | friend class QCoapClientPrivate; 80 | }; 81 | 82 | struct CoapExchangeData { 83 | QPointer userReply; 84 | QSharedPointer request; 85 | QList > replies; 86 | }; 87 | 88 | typedef QMap CoapExchangeMap; 89 | 90 | class Q_AUTOTEST_EXPORT QCoapProtocolPrivate : public QObjectPrivate 91 | { 92 | public: 93 | QCoapProtocolPrivate() = default; 94 | 95 | quint16 generateUniqueMessageId() const; 96 | QCoapToken generateUniqueToken() const; 97 | 98 | QCoapInternalReply *decode(const QByteArray &data, const QHostAddress &sender); 99 | 100 | void sendAcknowledgment(QCoapInternalRequest *request) const; 101 | void sendReset(QCoapInternalRequest *request) const; 102 | void sendRequest(QCoapInternalRequest *request, const QString& host = QString()) const; 103 | 104 | void onLastMessageReceived(QCoapInternalRequest *request, const QHostAddress &sender); 105 | void onRequestError(QCoapInternalRequest *request, QCoapInternalReply *reply); 106 | void onRequestError(QCoapInternalRequest *request, QtCoap::Error error, 107 | QCoapInternalReply *reply = nullptr); 108 | 109 | void onRequestTimeout(QCoapInternalRequest *request); 110 | void onRequestMaxTransmissionSpanReached(QCoapInternalRequest *request); 111 | void onMulticastRequestExpired(QCoapInternalRequest *request); 112 | void onFrameReceived(const QByteArray &data, const QHostAddress &sender); 113 | void onConnectionError(QAbstractSocket::SocketError error); 114 | void onRequestAborted(const QCoapToken &token); 115 | 116 | bool isMessageIdRegistered(quint16 id) const; 117 | bool isTokenRegistered(const QCoapToken &token) const; 118 | bool isRequestRegistered(const QCoapInternalRequest *request) const; 119 | 120 | QCoapInternalRequest *requestForToken(const QCoapToken &token) const; 121 | QPointer userReplyForToken(const QCoapToken &token) const; 122 | QList> repliesForToken(const QCoapToken &token) const; 123 | QCoapInternalReply *lastReplyForToken(const QCoapToken &token) const; 124 | QCoapInternalRequest *findRequestByMessageId(quint16 messageId) const; 125 | QCoapInternalRequest *findRequestByUserReply(const QCoapReply *reply) const; 126 | 127 | void registerExchange(const QCoapToken &token, QCoapReply *reply, 128 | QSharedPointer request); 129 | bool addReply(const QCoapToken &token, QSharedPointer reply); 130 | bool forgetExchange(const QCoapToken &token); 131 | bool forgetExchange(const QCoapInternalRequest *request); 132 | bool forgetExchangeReplies(const QCoapToken &token); 133 | 134 | CoapExchangeMap exchangeMap; 135 | quint16 blockSize = 0; 136 | 137 | uint maximumRetransmitCount = 4; 138 | uint ackTimeout = 2000; 139 | uint maximumServerResponseDelay = 250 * 1000; 140 | int minimumTokenSize = 4; 141 | double ackRandomFactor = 1.5; 142 | 143 | Q_DECLARE_PUBLIC(QCoapProtocol) 144 | }; 145 | 146 | QT_END_NAMESPACE 147 | 148 | #endif // QCOAPPROTOCOL_P_H 149 | -------------------------------------------------------------------------------- /tests/auto/qcoapreply/tst_qcoapreply.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | class tst_QCoapReply : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | private Q_SLOTS: 17 | void updateReply_data(); 18 | void updateReply(); 19 | void requestData(); 20 | void abortRequest(); 21 | void readReplyChunked(); 22 | }; 23 | 24 | void tst_QCoapReply::updateReply_data() 25 | { 26 | QTest::addColumn("payload"); 27 | QTest::addColumn("responseCode"); 28 | QTest::addColumn("error"); 29 | 30 | QTest::newRow("success") 31 | << QByteArray("Some data") 32 | << QtCoap::ResponseCode::Content 33 | << QtCoap::Error::Ok; 34 | QTest::newRow("content error") 35 | << QByteArray("Error") 36 | << QtCoap::ResponseCode::BadRequest 37 | << QtCoap::Error::Ok; 38 | QTest::newRow("finished error") 39 | << QByteArray("Error") 40 | << QtCoap::ResponseCode::Content 41 | << QtCoap::Error::BadRequest; 42 | QTest::newRow("content & finished errors") 43 | << QByteArray("2Errors") 44 | << QtCoap::ResponseCode::BadGateway 45 | << QtCoap::Error::BadRequest; 46 | } 47 | 48 | void tst_QCoapReply::updateReply() 49 | { 50 | QFETCH(QByteArray, payload); 51 | QFETCH(QtCoap::ResponseCode, responseCode); 52 | QFETCH(QtCoap::Error, error); 53 | 54 | const QByteArray token = "\xAF\x01\xC2"; 55 | const quint16 id = 645; 56 | 57 | QScopedPointer reply(QCoapReplyPrivate::createCoapReply(QCoapRequest())); 58 | QCoapMessage message; 59 | message.setToken(token); 60 | message.setMessageId(id); 61 | message.setPayload(payload); 62 | 63 | QSignalSpy spyReplyFinished(reply.data(), &QCoapReply::finished); 64 | QSignalSpy spyReplyNotified(reply.data(), &QCoapReply::notified); 65 | QSignalSpy spyReplyError(reply.data(), &QCoapReply::error); 66 | QSignalSpy spyReplyAborted(reply.data(), &QCoapReply::aborted); 67 | 68 | QMetaObject::invokeMethod(reply.data(), "_q_setContent", 69 | Q_ARG(QHostAddress, QHostAddress()), 70 | Q_ARG(QCoapMessage, message), 71 | Q_ARG(QtCoap::ResponseCode, responseCode)); 72 | QMetaObject::invokeMethod(reply.data(), "_q_setFinished", 73 | Q_ARG(QtCoap::Error, error)); 74 | 75 | QCOMPARE(spyReplyFinished.size(), 1); 76 | QCOMPARE(spyReplyNotified.size(), 0); 77 | QCOMPARE(spyReplyAborted.size(), 0); 78 | if (error != QtCoap::Error::Ok || QtCoap::isError(responseCode)) { 79 | QVERIFY(spyReplyError.size() > 0); 80 | QCOMPARE(reply->isSuccessful(), false); 81 | } else { 82 | QCOMPARE(spyReplyError.size(), 0); 83 | QCOMPARE(reply->isSuccessful(), true); 84 | } 85 | 86 | QCOMPARE(reply->readAll(), payload); 87 | QCOMPARE(reply->readAll(), QByteArray()); 88 | QCOMPARE(reply->responseCode(), responseCode); 89 | QCOMPARE(reply->message().token(), token); 90 | QCOMPARE(reply->message().messageId(), id); 91 | } 92 | 93 | void tst_QCoapReply::requestData() 94 | { 95 | QScopedPointer reply(QCoapReplyPrivate::createCoapReply(QCoapRequest())); 96 | QMetaObject::invokeMethod(reply.data(), "_q_setRunning", 97 | Q_ARG(QCoapToken, "token"), 98 | Q_ARG(QCoapMessageId, 543)); 99 | 100 | QCOMPARE(reply->request().token(), QByteArray("token")); 101 | QCOMPARE(reply->request().messageId(), 543); 102 | } 103 | 104 | void tst_QCoapReply::abortRequest() 105 | { 106 | QScopedPointer reply(QCoapReplyPrivate::createCoapReply(QCoapRequest())); 107 | QMetaObject::invokeMethod(reply.data(), "_q_setRunning", 108 | Q_ARG(QCoapToken, "token"), 109 | Q_ARG(QCoapMessageId, 543)); 110 | 111 | QSignalSpy spyAborted(reply.data(), &QCoapReply::aborted); 112 | QSignalSpy spyFinished(reply.data(), &QCoapReply::finished); 113 | reply->abortRequest(); 114 | 115 | QTRY_COMPARE_WITH_TIMEOUT(spyAborted.size(), 1, 1000); 116 | QList arguments = spyAborted.takeFirst(); 117 | QTRY_COMPARE_WITH_TIMEOUT(spyFinished.size(), 1, 1000); 118 | QVERIFY(arguments.at(0).toByteArray() == "token"); 119 | } 120 | 121 | void tst_QCoapReply::readReplyChunked() 122 | { 123 | const QByteArray token = "\xAF\x01\xC2"; 124 | const quint16 id = 645; 125 | const QByteArray payload = "this is some payload"; 126 | 127 | QScopedPointer reply(QCoapReplyPrivate::createCoapReply(QCoapRequest())); 128 | QCoapMessage message; 129 | message.setToken(token); 130 | message.setMessageId(id); 131 | message.setPayload(payload); 132 | 133 | QMetaObject::invokeMethod(reply.data(), "_q_setContent", 134 | Q_ARG(QHostAddress, QHostAddress()), 135 | Q_ARG(QCoapMessage, message), 136 | Q_ARG(QtCoap::ResponseCode, QtCoap::ResponseCode::Content)); 137 | QMetaObject::invokeMethod(reply.data(), "_q_setFinished", 138 | Q_ARG(QtCoap::Error, QtCoap::Error::Ok)); 139 | 140 | QCOMPARE_EQ(reply->pos(), 0); 141 | const qsizetype startBytes = 7; 142 | const QByteArray start = reply->read(startBytes); 143 | QCOMPARE_EQ(start, payload.first(startBytes)); 144 | QCOMPARE_EQ(reply->pos(), startBytes); 145 | 146 | QByteArray last(100, Qt::Uninitialized); 147 | const qint64 read = reply->read(last.data(), last.size()); 148 | QCOMPARE_EQ(read, payload.size() - startBytes); 149 | QCOMPARE_EQ(reply->pos(), payload.size()); 150 | last.resize(read); 151 | QCOMPARE_EQ(start + last, payload); 152 | } 153 | 154 | QTEST_MAIN(tst_QCoapReply) 155 | 156 | #include "tst_qcoapreply.moc" 157 | -------------------------------------------------------------------------------- /src/coap/qcoapresource.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:significant reason:default 5 | 6 | #include "qcoapresource_p.h" 7 | 8 | QT_BEGIN_NAMESPACE 9 | 10 | /*! 11 | \class QCoapResource 12 | \inmodule QtCoap 13 | 14 | \brief The QCoapResource class holds information about a discovered 15 | resource. 16 | 17 | \reentrant 18 | 19 | The QCoapRequest contains data as the path and title of the resource 20 | and other ancillary information. 21 | 22 | \sa QCoapResourceDiscoveryReply 23 | */ 24 | 25 | /*! 26 | Constructs a new QCoapResource. 27 | */ 28 | QCoapResource::QCoapResource() : 29 | d(new QCoapResourcePrivate) 30 | { 31 | } 32 | 33 | /*! 34 | Constructs a new CoAP resource as a copy of \a other, making the two 35 | resources identical. 36 | */ 37 | QCoapResource::QCoapResource(const QCoapResource &other) : 38 | d(other.d) 39 | { 40 | } 41 | 42 | /*! 43 | Destroy the QCoapResource. 44 | */ 45 | QCoapResource::~QCoapResource() 46 | { 47 | } 48 | 49 | /*! 50 | Copies \a other into this resource, making the two resources identical. 51 | Returns a reference to this QCoapResource. 52 | */ 53 | QCoapResource &QCoapResource::operator=(const QCoapResource &other) 54 | { 55 | d = other.d; 56 | return *this; 57 | } 58 | 59 | /*! 60 | Swaps this resource with \a other. This operation is very fast and never fails. 61 | */ 62 | void QCoapResource::swap(QCoapResource &other) noexcept 63 | { 64 | d.swap(other.d); 65 | } 66 | 67 | /*! 68 | Returns the host of the resource. 69 | 70 | \sa setHost() 71 | */ 72 | QHostAddress QCoapResource::host() const 73 | { 74 | return d->host; 75 | } 76 | 77 | /*! 78 | Returns the path of the resource. 79 | 80 | \sa setPath() 81 | */ 82 | QString QCoapResource::path() const 83 | { 84 | return d->path; 85 | } 86 | 87 | /*! 88 | Returns the title of the resource. 89 | 90 | \sa setTitle() 91 | */ 92 | QString QCoapResource::title() const 93 | { 94 | return d->title; 95 | } 96 | 97 | /*! 98 | Returns \c true if the resource is observable 99 | 100 | \sa setObservable() 101 | */ 102 | bool QCoapResource::observable() const 103 | { 104 | return d->observable; 105 | } 106 | 107 | /*! 108 | Returns the type of the resource. 109 | 110 | \sa setResourceType() 111 | */ 112 | QString QCoapResource::resourceType() const 113 | { 114 | return d->resourceType; 115 | } 116 | 117 | /*! 118 | Returns the interface description of the resource. 119 | 120 | The Interface Description 'if' attribute is an opaque string used to 121 | provide a name or URI indicating a specific interface definition used 122 | to interact with the target resource. It is specified in 123 | \l{https://tools.ietf.org/html/rfc6690#section-3.2}{RFC 6690}. 124 | 125 | \sa setInterface() 126 | */ 127 | QString QCoapResource::interface() const 128 | { 129 | return d->interface; 130 | } 131 | 132 | /*! 133 | Returns the maximum size of the resource. 134 | 135 | The maximum size estimate attribute 'sz' gives an indication of the 136 | maximum size of the resource representation returned by performing a 137 | GET on the target URI. It is specified in 138 | \l{https://tools.ietf.org/html/rfc6690#section-3.3}{RFC 6690}. 139 | 140 | \sa setMaximumSize() 141 | */ 142 | int QCoapResource::maximumSize() const 143 | { 144 | return d->maximumSize; 145 | } 146 | 147 | /*! 148 | Returns the Content-Format code of the resource. 149 | 150 | The Content-Format code corresponds to the 'ct' attribute and provides a 151 | hint about the Content-Formats this resource returns. It is specified 152 | in \l{https://tools.ietf.org/html/rfc7252#section-7.2.1}{RFC 7252}. 153 | 154 | \sa setContentFormat() 155 | */ 156 | uint QCoapResource::contentFormat() const 157 | { 158 | return d->contentFormat; 159 | } 160 | 161 | /*! 162 | Sets the host of the resource to \a host. 163 | 164 | \sa host() 165 | */ 166 | void QCoapResource::setHost(const QHostAddress &host) 167 | { 168 | d->host = host; 169 | } 170 | 171 | /*! 172 | Sets the path of the resource to \a path. 173 | 174 | \sa path() 175 | */ 176 | void QCoapResource::setPath(const QString &path) 177 | { 178 | d->path = path; 179 | } 180 | 181 | /*! 182 | Sets the title of the resource to \a title. 183 | 184 | \sa title() 185 | */ 186 | void QCoapResource::setTitle(const QString &title) 187 | { 188 | d->title = title; 189 | } 190 | 191 | /*! 192 | Makes the resource observable if the \a observable 193 | parameter is \c true. 194 | 195 | \sa observable() 196 | */ 197 | void QCoapResource::setObservable(bool observable) 198 | { 199 | d->observable = observable; 200 | } 201 | 202 | /*! 203 | Sets the resource type to \a resourceType. 204 | 205 | \sa resourceType() 206 | */ 207 | void QCoapResource::setResourceType(const QString &resourceType) 208 | { 209 | d->resourceType = resourceType; 210 | } 211 | 212 | /*! 213 | Sets the interface of the resource to \a interface. 214 | 215 | \sa interface() 216 | */ 217 | void QCoapResource::setInterface(const QString &interface) 218 | { 219 | d->interface = interface; 220 | } 221 | 222 | /*! 223 | Sets the maximum size of the resource to \a maximumSize. 224 | 225 | \sa maximumSize() 226 | */ 227 | void QCoapResource::setMaximumSize(int maximumSize) 228 | { 229 | d->maximumSize = maximumSize; 230 | } 231 | 232 | /*! 233 | Sets the content format of the resource to \a contentFormat. The content 234 | format can be one of the content formats defined in \l {CoAP Content-Formats Registry}. 235 | 236 | \note CoAP supports common content formats such as XML, JSON, and so on, but 237 | these are text based and consequently heavy both in payload and in processing. 238 | One of the recommended content formats to use with CoAP is CBOR, which is 239 | designed to be used in such contexts. 240 | 241 | \sa contentFormat(), QCborStreamWriter, QCborStreamReader 242 | */ 243 | void QCoapResource::setContentFormat(uint contentFormat) 244 | { 245 | d->contentFormat = contentFormat; 246 | } 247 | 248 | QT_END_NAMESPACE 249 | -------------------------------------------------------------------------------- /tests/auto/coapnetworksettings.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /*! 12 | \internal 13 | 14 | This namespace provides URL and settings used in QtCoap tests. 15 | 16 | Tests require a Californium plugtest server, accessible with 17 | "coap-plugtest-server" host name. You create such server with Docker and 18 | the following command line: 19 | \code 20 | docker run -d --rm -p 5683:5683/udp aleravat/coap-test-server:latest 21 | \endcode 22 | 23 | For more details, see 24 | \l{https://github.com/Pixep/coap-testserver-docker}{https://github.com/Pixep/coap-testserver-docker}. 25 | */ 26 | namespace QtCoapNetworkSettings 27 | { 28 | 29 | #if defined(COAP_TEST_SERVER_IP) || defined(QT_TEST_SERVER) 30 | #define CHECK_FOR_COAP_SERVER 31 | #else 32 | #define CHECK_FOR_COAP_SERVER \ 33 | QSKIP("CoAP server is not setup, skipping the test..."); \ 34 | return; 35 | #endif 36 | 37 | #if defined(QT_TEST_SERVER) && !defined(COAP_TEST_SERVER_IP) 38 | static QString tryToResolveHostName(const QString &hostName) 39 | { 40 | const auto hostInfo = QHostInfo::fromName(hostName); 41 | if (!hostInfo.addresses().empty()) 42 | return hostInfo.addresses().first().toString(); 43 | 44 | qWarning() << "Could not resolve the hostname"<< hostName; 45 | return hostName; 46 | } 47 | #endif 48 | 49 | static QString getHostAddress(const QString &serverName) 50 | { 51 | #if defined(COAP_TEST_SERVER_IP) 52 | Q_UNUSED(serverName); 53 | return QStringLiteral(COAP_TEST_SERVER_IP); 54 | #elif defined(QT_TEST_SERVER_NAME) 55 | QString hostname = serverName % "." % QString(QT_TEST_SERVER_DOMAIN); 56 | return tryToResolveHostName(hostname); 57 | #elif defined(QT_TEST_SERVER) 58 | Q_UNUSED(serverName); 59 | QString hostname = "qt-test-server." % QString(QT_TEST_SERVER_DOMAIN); 60 | return tryToResolveHostName(hostname); 61 | #else 62 | Q_UNUSED(serverName); 63 | qWarning("This test will fail, " 64 | "please set the COAP_TEST_SERVER_IP variable to specify the CoAP server."); 65 | return ""; 66 | #endif 67 | } 68 | 69 | QString testServerHost() 70 | { 71 | static QString testServerHostAddress = getHostAddress("californium"); 72 | return testServerHostAddress; 73 | } 74 | 75 | QString timeServerUrl() 76 | { 77 | static QString timeServerHostAddress = getHostAddress("freecoap"); 78 | return QStringLiteral("coaps://") + timeServerHostAddress + QStringLiteral(":5685/time"); 79 | } 80 | 81 | QString testServerUrl() 82 | { 83 | return QStringLiteral("coap://") + testServerHost() + QStringLiteral(":") 84 | + QString::number(QtCoap::DefaultPort); 85 | } 86 | 87 | QString testServerResource() 88 | { 89 | return testServerHost() + QStringLiteral("/test"); 90 | } 91 | 92 | QCoapSecurityConfiguration createConfiguration(QtCoap::SecurityMode securityMode) 93 | { 94 | QCoapSecurityConfiguration configuration; 95 | 96 | if (securityMode == QtCoap::SecurityMode::PreSharedKey) { 97 | configuration.setPreSharedKeyIdentity("Client_identity"); 98 | configuration.setPreSharedKey("secretPSK"); 99 | } else if (securityMode == QtCoap::SecurityMode::Certificate) { 100 | const QString directory = QFINDTESTDATA("testdata"); 101 | if (directory.isEmpty()) { 102 | qWarning() << "Found no testdata/, cannot load certificates."; 103 | return configuration; 104 | } 105 | 106 | const auto localCertPath = directory + QDir::separator() +"local_cert.pem"; 107 | const auto localCerts = QSslCertificate::fromPath( 108 | localCertPath, QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); 109 | if (localCerts.isEmpty()) { 110 | qWarning() << "Failed to load local certificates, the" 111 | << localCertPath 112 | << "file was not found or it is not valid."; 113 | } else { 114 | configuration.setLocalCertificateChain(localCerts.toVector()); 115 | } 116 | 117 | const auto caCertPath = directory + QDir::separator() + "ca_cert.pem"; 118 | const auto caCerts = QSslCertificate::fromPath(caCertPath, QSsl::Pem, 119 | QSslCertificate::PatternSyntax::FixedString); 120 | if (caCerts.isEmpty()) { 121 | qWarning() << "Failed to load CA certificates, the" 122 | << caCertPath 123 | << "file was not found or it is not valid."; 124 | } else { 125 | configuration.setCaCertificates(caCerts.toVector()); 126 | } 127 | 128 | const auto privateKeyPath = directory + QDir::separator() + "privkey.pem"; 129 | QFile privateKey(privateKeyPath); 130 | if (privateKey.open(QIODevice::ReadOnly)) { 131 | QCoapPrivateKey key(privateKey.readAll(), QSsl::Ec); 132 | if (key.isNull()) { 133 | qWarning() << "Failed to set a private key, the key" << privateKeyPath 134 | << "is not valid."; 135 | } else { 136 | configuration.setPrivateKey(key); 137 | } 138 | } else { 139 | qWarning() << "Failed to read the private key" << privateKeyPath; 140 | } 141 | } 142 | 143 | return configuration; 144 | } 145 | 146 | bool waitForHost(const QUrl &url, QtCoap::SecurityMode security = QtCoap::SecurityMode::NoSecurity, 147 | quint8 retries = 10) 148 | { 149 | while (retries-- > 0) { 150 | QCoapClient client(security); 151 | if (security != QtCoap::SecurityMode::NoSecurity) 152 | client.setSecurityConfiguration(createConfiguration(security)); 153 | 154 | QSignalSpy spyClientFinished(&client, SIGNAL(finished(QCoapReply*))); 155 | client.get(url); 156 | 157 | spyClientFinished.wait(1000); 158 | 159 | if (spyClientFinished.size() == 1) 160 | return true; 161 | } 162 | return false; 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/coap/qcoapinternalmessage.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:critical reason:network-protocol 5 | 6 | #include "qcoapinternalmessage_p.h" 7 | #include "qcoaprequest_p.h" 8 | #include 9 | 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | Q_LOGGING_CATEGORY(lcCoapExchange, "qt.coap.exchange") 15 | 16 | /*! 17 | \internal 18 | 19 | Destructor of the private class. 20 | */ 21 | QCoapInternalMessagePrivate::~QCoapInternalMessagePrivate() 22 | { 23 | } 24 | 25 | /*! 26 | \internal 27 | 28 | \class QCoapInternalMessage 29 | \brief The QCoapInternalMessage class contains data related to 30 | a received message or a message to send. It contains an instance of 31 | QCoapMessage and other data for the block management. 32 | 33 | \reentrant 34 | 35 | The QCoapInternalMessage class is inherited by QCoapInternalRequest and 36 | QCoapInternalReply that are used internally to manage requests to send 37 | and receive replies. 38 | 39 | \sa QCoapInternalReply, QCoapInternalRequest, QCoapMessage 40 | */ 41 | 42 | /*! 43 | \internal 44 | 45 | Constructs a new QCoapInternalMessage and sets \a parent as the parent 46 | object. 47 | */ 48 | QCoapInternalMessage::QCoapInternalMessage(QObject *parent) : 49 | QObject(*new QCoapInternalMessagePrivate, parent) 50 | { 51 | } 52 | 53 | /*! 54 | \internal 55 | 56 | Constructs a new QCoapInternalMessage with the given \a message and sets 57 | \a parent as the parent object. 58 | */ 59 | QCoapInternalMessage::QCoapInternalMessage(const QCoapMessage &message, QObject *parent) : 60 | QCoapInternalMessage(parent) 61 | { 62 | Q_D(QCoapInternalMessage); 63 | d->message = message; 64 | } 65 | 66 | /*! 67 | \internal 68 | Constructs a new QCoapInternalMessage with \a dd as the d_ptr. 69 | This constructor must be used when subclassing internally 70 | the QCoapInternalMessage class. 71 | */ 72 | QCoapInternalMessage::QCoapInternalMessage(QCoapInternalMessagePrivate &dd, QObject *parent): 73 | QObject(dd, parent) 74 | { 75 | } 76 | 77 | /*! 78 | \internal 79 | Set block information from a descriptive block option. See 80 | \l {https://tools.ietf.org/html/rfc7959#section-2.3}{RFC 7959}. 81 | 82 | \note For block-wise transfer, the size of the block is expressed by a power 83 | of two. See 84 | \l{https://tools.ietf.org/html/rfc7959#section-2.2}{'Structure of a Block Option'} 85 | in RFC 7959 for more information. 86 | */ 87 | void QCoapInternalMessage::setFromDescriptiveBlockOption(const QCoapOption &option) 88 | { 89 | Q_D(QCoapInternalMessage); 90 | 91 | const auto value = option.opaqueValue(); 92 | const quint8 *optionData = reinterpret_cast(value.data()); 93 | const quint8 lastByte = optionData[option.length() - 1]; 94 | quint32 blockNumber = 0; 95 | 96 | for (int i = 0; i < option.length() - 1; ++i) 97 | blockNumber = (blockNumber << 8) | optionData[i]; 98 | 99 | blockNumber = (blockNumber << 4) | (lastByte >> 4); 100 | d->currentBlockNumber = blockNumber; 101 | d->hasNextBlock = ((lastByte & 0x8) == 0x8); 102 | d->blockSize = static_cast(1u << ((lastByte & 0x7) + 4)); 103 | 104 | if (d->blockSize > 1024) 105 | qCWarning(lcCoapExchange, "Received a block size larger than 1024, something may be wrong."); 106 | } 107 | 108 | /*! 109 | \internal 110 | \overload 111 | 112 | Adds the CoAP option with the given \a name and \a value. 113 | */ 114 | void QCoapInternalMessage::addOption(QCoapOption::OptionName name, const QByteArray &value) 115 | { 116 | QCoapOption option(name, value); 117 | addOption(option); 118 | } 119 | 120 | /*! 121 | \internal 122 | \overload 123 | 124 | Adds the CoAP option with the given \a name and \a value. 125 | */ 126 | void QCoapInternalMessage::addOption(QCoapOption::OptionName name, quint32 value) 127 | { 128 | QCoapOption option(name, value); 129 | addOption(option); 130 | } 131 | 132 | /*! 133 | \internal 134 | 135 | Adds the given CoAP \a option. 136 | */ 137 | void QCoapInternalMessage::addOption(const QCoapOption &option) 138 | { 139 | Q_D(QCoapInternalMessage); 140 | d->message.addOption(option); 141 | } 142 | 143 | /*! 144 | \internal 145 | 146 | Removes the option with the given \a name. 147 | */ 148 | void QCoapInternalMessage::removeOption(QCoapOption::OptionName name) 149 | { 150 | Q_D(QCoapInternalMessage); 151 | d->message.removeOption(name); 152 | } 153 | 154 | /*! 155 | \internal 156 | 157 | Returns a pointer to the message. 158 | */ 159 | QCoapMessage *QCoapInternalMessage::message() 160 | { 161 | Q_D(QCoapInternalMessage); 162 | return &(d->message); 163 | } 164 | 165 | /*! 166 | \internal 167 | 168 | Returns a const pointer to the message. 169 | */ 170 | const QCoapMessage *QCoapInternalMessage::message() const 171 | { 172 | Q_D(const QCoapInternalMessage); 173 | return &(d->message); 174 | } 175 | 176 | /*! 177 | \internal 178 | 179 | Returns the block number 180 | */ 181 | uint QCoapInternalMessage::currentBlockNumber() const 182 | { 183 | Q_D(const QCoapInternalMessage); 184 | return d->currentBlockNumber; 185 | } 186 | 187 | /*! 188 | \internal 189 | 190 | Returns \c true if it has a next block, \c false otherwise. 191 | */ 192 | bool QCoapInternalMessage::hasMoreBlocksToReceive() const 193 | { 194 | Q_D(const QCoapInternalMessage); 195 | return d->hasNextBlock; 196 | } 197 | 198 | /*! 199 | \internal 200 | 201 | Returns the size of the block. 202 | */ 203 | uint QCoapInternalMessage::blockSize() const 204 | { 205 | Q_D(const QCoapInternalMessage); 206 | return d->blockSize; 207 | } 208 | 209 | /*! 210 | \internal 211 | 212 | Returns \c true if the message is considered valid. 213 | 214 | \sa isUrlValid() 215 | */ 216 | bool QCoapInternalMessage::isValid() const 217 | { 218 | return true; 219 | } 220 | 221 | /*! 222 | \internal 223 | 224 | Returns \c true if URL is considered valid. 225 | 226 | \sa QCoapRequest::isUrlValid() 227 | */ 228 | bool QCoapInternalMessage::isUrlValid(const QUrl &url) 229 | { 230 | return QCoapRequestPrivate::isUrlValid(url); 231 | } 232 | 233 | QT_END_NAMESPACE 234 | -------------------------------------------------------------------------------- /tests/auto/qcoapqudpconnection/tst_qcoapqudpconnection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "../coapnetworksettings.h" 19 | 20 | using namespace QtCoapNetworkSettings; 21 | 22 | class tst_QCoapQUdpConnection : public QObject 23 | { 24 | Q_OBJECT 25 | 26 | private Q_SLOTS: 27 | void initTestCase(); 28 | void ctor(); 29 | void connectToHost(); 30 | void reconnect(); 31 | void sendRequest_data(); 32 | void sendRequest(); 33 | }; 34 | 35 | class QCoapQUdpConnectionForTest : public QCoapQUdpConnection 36 | { 37 | Q_OBJECT 38 | public: 39 | QCoapQUdpConnectionForTest(QObject *parent = nullptr) : 40 | QCoapQUdpConnection(QtCoap::SecurityMode::NoSecurity, parent) 41 | {} 42 | 43 | void bindSocketForTest() { d_func()->bindSocket(); } 44 | void sendRequest(const QByteArray &request, const QString &host, quint16 port) 45 | { 46 | d_func()->sendRequest(request, host, port); 47 | } 48 | }; 49 | 50 | void tst_QCoapQUdpConnection::initTestCase() 51 | { 52 | #if defined(COAP_TEST_SERVER_IP) || defined(QT_TEST_SERVER) 53 | QVERIFY2(waitForHost(QUrl{testServerHost()}), "Failed to connect to Californium plugtest server."); 54 | #endif 55 | } 56 | 57 | void tst_QCoapQUdpConnection::ctor() 58 | { 59 | QCoapQUdpConnection connection; 60 | QVERIFY(connection.socket()); 61 | } 62 | 63 | void tst_QCoapQUdpConnection::connectToHost() 64 | { 65 | QCoapQUdpConnectionForTest connection; 66 | 67 | QUdpSocket *socket = qobject_cast(connection.socket()); 68 | QSignalSpy spyConnectionBound(&connection, SIGNAL(bound())); 69 | QSignalSpy spySocketStateChanged(socket , SIGNAL(stateChanged(QAbstractSocket::SocketState))); 70 | 71 | QCOMPARE(connection.state(), QCoapQUdpConnection::ConnectionState::Unconnected); 72 | 73 | // This will trigger connection.bind() 74 | connection.sendRequest(QByteArray(), QString(), 0); 75 | 76 | QTRY_COMPARE(spySocketStateChanged.size(), 1); 77 | QTRY_COMPARE(spyConnectionBound.size(), 1); 78 | QCOMPARE(connection.state(), QCoapQUdpConnection::ConnectionState::Bound); 79 | } 80 | 81 | void tst_QCoapQUdpConnection::reconnect() 82 | { 83 | QCoapQUdpConnectionForTest connection; 84 | 85 | // This will trigger connection.bind() 86 | QSignalSpy connectionBoundSpy(&connection, SIGNAL(bound())); 87 | connection.sendRequest(QByteArray(), QString(), 0); 88 | QTRY_COMPARE(connectionBoundSpy.size(), 1); 89 | QCOMPARE(connection.state(), QCoapQUdpConnection::ConnectionState::Bound); 90 | 91 | connection.disconnect(); 92 | QCOMPARE(connection.state(), QCoapQUdpConnection::ConnectionState::Unconnected); 93 | 94 | // Make sure that we are able to connect again 95 | connection.sendRequest(QByteArray(), QString(), 0); 96 | QTRY_COMPARE(connectionBoundSpy.size(), 2); 97 | QCOMPARE(connection.state(), QCoapQUdpConnection::ConnectionState::Bound); 98 | } 99 | 100 | void tst_QCoapQUdpConnection::sendRequest_data() 101 | { 102 | QTest::addColumn("protocol"); 103 | QTest::addColumn("host"); 104 | QTest::addColumn("path"); 105 | QTest::addColumn("port"); 106 | QTest::addColumn("method"); 107 | QTest::addColumn("dataHexaHeader"); 108 | QTest::addColumn("dataHexaPayload"); 109 | 110 | QTest::newRow("simple_get_request") 111 | << "coap://" 112 | << testServerHost() 113 | << "/test" 114 | << quint16(QtCoap::DefaultPort) 115 | << QtCoap::Method::Get 116 | << "5445" 117 | << "61626364c0211eff547970653a203120284e4f4e290a436f64653a2031202847" 118 | "4554290a4d49443a2032343830360a546f6b656e3a203631363236333634"; 119 | 120 | QTest::newRow("simple_put_request") 121 | << "coap://" 122 | << testServerHost() 123 | << "/test" 124 | << quint16(QtCoap::DefaultPort) 125 | << QtCoap::Method::Put 126 | << "5444" 127 | << "61626364"; 128 | 129 | QTest::newRow("simple_post_request") 130 | << "coap://" 131 | << testServerHost() 132 | << "/test" 133 | << quint16(QtCoap::DefaultPort) 134 | << QtCoap::Method::Post 135 | << "5441" 136 | << "61626364896c6f636174696f6e31096c6f636174696f6e32096c6f636174696f" 137 | "6e33"; 138 | 139 | QTest::newRow("simple_delete_request") 140 | << "coap://" 141 | << testServerHost() 142 | << "/test" 143 | << quint16(QtCoap::DefaultPort) 144 | << QtCoap::Method::Delete 145 | << "5442" 146 | << "61626364"; 147 | } 148 | 149 | void tst_QCoapQUdpConnection::sendRequest() 150 | { 151 | CHECK_FOR_COAP_SERVER; 152 | 153 | QFETCH(QString, protocol); 154 | QFETCH(QString, host); 155 | QFETCH(QString, path); 156 | QFETCH(quint16, port); 157 | QFETCH(QtCoap::Method, method); 158 | QFETCH(QString, dataHexaHeader); 159 | QFETCH(QString, dataHexaPayload); 160 | 161 | QCoapQUdpConnectionForTest connection; 162 | 163 | QSignalSpy spySocketReadyRead(connection.socket(), &QUdpSocket::readyRead); 164 | QSignalSpy spyConnectionReadyRead(&connection, &QCoapQUdpConnection::readyRead); 165 | 166 | QCoapRequest request = 167 | QCoapRequestPrivate::createRequest(QCoapRequest(QUrl{protocol + host + path}), method); 168 | request.setMessageId(24806); 169 | request.setToken(QByteArray("abcd")); 170 | QVERIFY(connection.socket() != nullptr); 171 | QCoapInternalRequest internalRequest(request); 172 | connection.sendRequest(internalRequest.toQByteArray(), host, port); 173 | 174 | QTRY_COMPARE(spySocketReadyRead.size(), 1); 175 | QTRY_COMPARE(spyConnectionReadyRead.size(), 1); 176 | 177 | QByteArray data = spyConnectionReadyRead.first().first().value(); 178 | QVERIFY(QString(data.toHex()).startsWith(dataHexaHeader)); 179 | QVERIFY(QString(data.toHex()).endsWith(dataHexaPayload)); 180 | } 181 | 182 | QTEST_MAIN(tst_QCoapQUdpConnection) 183 | 184 | #include "tst_qcoapqudpconnection.moc" 185 | -------------------------------------------------------------------------------- /examples/coap/quicksecureclient/Main.qml: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | import QtQuick 5 | import QtQuick.Layouts 6 | import QtQuick.Controls 7 | import QtQuick.Window 8 | 9 | Window { 10 | id: root 11 | 12 | required property var hostsModel 13 | 14 | visible: true 15 | width: 480 16 | height: 640 17 | title: qsTr("Qt Quick Secure CoAP Client") 18 | 19 | //! [client] 20 | CoapSecureClient { 21 | id: client 22 | onFinished: (result) => { 23 | outputView.text = result; 24 | statusLabel.text = ""; 25 | disconnectButton.enabled = true; 26 | } 27 | } 28 | //! [client] 29 | 30 | GridLayout { 31 | anchors.fill: parent 32 | anchors.margins: 10 33 | columns: 2 34 | 35 | Label { 36 | text: qsTr("Host:") 37 | } 38 | ComboBox { 39 | id: hostComboBox 40 | editable: true 41 | model: root.hostsModel 42 | Layout.fillWidth: true 43 | } 44 | 45 | Label { 46 | text: qsTr("Port:") 47 | } 48 | TextField { 49 | id: portField 50 | text: "5684" 51 | placeholderText: qsTr("") 52 | inputMethodHints: Qt.ImhDigitsOnly 53 | Layout.preferredWidth: 80 54 | } 55 | 56 | Label { 57 | text: qsTr("Resource:") 58 | } 59 | TextField { 60 | id: resourceField 61 | placeholderText: qsTr("") 62 | inputMethodHints: Qt.ImhUrlCharactersOnly 63 | selectByMouse: true 64 | Layout.fillWidth: true 65 | } 66 | 67 | Label { 68 | text: qsTr("Security Mode:") 69 | } 70 | //! [security_modes] 71 | ButtonGroup { 72 | id: securityModeGroup 73 | onClicked: { 74 | if ((securityModeGroup.checkedButton as RadioButton) === preSharedMode) 75 | client.setSecurityMode(QtCoap.SecurityMode.PreSharedKey); 76 | else 77 | client.setSecurityMode(QtCoap.SecurityMode.Certificate); 78 | } 79 | } 80 | //! [security_modes] 81 | RowLayout { 82 | RadioButton { 83 | id: preSharedMode 84 | text: qsTr("Pre-shared Key") 85 | ButtonGroup.group: securityModeGroup 86 | } 87 | RadioButton { 88 | id: certificateMode 89 | text: qsTr("X.509 Certificate") 90 | ButtonGroup.group: securityModeGroup 91 | } 92 | } 93 | 94 | RowLayout { 95 | enabled: (securityModeGroup.checkedButton as RadioButton) === preSharedMode 96 | Layout.columnSpan: 2 97 | 98 | Label { 99 | text: qsTr("Key") 100 | } 101 | TextField { 102 | id: pskField 103 | placeholderText: qsTr("") 104 | Layout.fillWidth: true 105 | } 106 | 107 | Label { 108 | text: qsTr("Identity") 109 | } 110 | TextField { 111 | id: identityField 112 | placeholderText: qsTr("") 113 | Layout.fillWidth: true 114 | } 115 | } 116 | 117 | //! [certificate_dialogs] 118 | FilePicker { 119 | id: localCertificatePicker 120 | dialogText: qsTr("Local Certificate") 121 | enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode 122 | Layout.columnSpan: 2 123 | Layout.fillWidth: true 124 | } 125 | 126 | FilePicker { 127 | id: caCertificatePicker 128 | dialogText: qsTr("CA Certificate") 129 | enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode 130 | Layout.columnSpan: 2 131 | Layout.fillWidth: true 132 | } 133 | 134 | FilePicker { 135 | id: privateKeyPicker 136 | dialogText: qsTr("Private Key") 137 | enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode 138 | Layout.columnSpan: 2 139 | Layout.fillWidth: true 140 | } 141 | //! [certificate_dialogs] 142 | 143 | //! [send_request] 144 | Button { 145 | id: requestButton 146 | text: qsTr("Send Request") 147 | enabled: securityModeGroup.checkState !== Qt.Unchecked 148 | 149 | onClicked: { 150 | outputView.text = ""; 151 | if ((securityModeGroup.checkedButton as RadioButton) === preSharedMode) 152 | client.setSecurityConfiguration(pskField.text, identityField.text); 153 | else 154 | client.setSecurityConfiguration(localCertificatePicker.selectedFile, 155 | caCertificatePicker.selectedFile, 156 | privateKeyPicker.selectedFile); 157 | 158 | client.sendGetRequest(hostComboBox.editText, resourceField.text, 159 | parseInt(portField.text)); 160 | 161 | statusLabel.text = qsTr("Sending request to %1%2...").arg(hostComboBox.editText) 162 | .arg(resourceField.text); 163 | } 164 | } 165 | //! [send_request] 166 | 167 | Button { 168 | id: disconnectButton 169 | text: qsTr("Disconnect") 170 | enabled: false 171 | 172 | onClicked: { 173 | client.disconnect(); 174 | statusLabel.text = qsTr("Disconnected."); 175 | outputView.text = ""; 176 | disconnectButton.enabled = false; 177 | } 178 | } 179 | 180 | TextArea { 181 | id: outputView 182 | placeholderText: qsTr("") 183 | background: Rectangle { 184 | border.color: "gray" 185 | } 186 | Layout.columnSpan: 2 187 | Layout.fillHeight: true 188 | Layout.fillWidth: true 189 | } 190 | Label { 191 | id: statusLabel 192 | Layout.columnSpan: 2 193 | Layout.fillWidth: true 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /tests/auto/qcoaprequest/tst_qcoaprequest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class tst_QCoapRequest : public QObject 14 | { 15 | Q_OBJECT 16 | 17 | private Q_SLOTS: 18 | void ctor_data(); 19 | void ctor(); 20 | void adjustUrl_data(); 21 | void adjustUrl(); 22 | void setUrl_data(); 23 | void setUrl(); 24 | void enableObserve(); 25 | void copyAndDetach(); 26 | }; 27 | 28 | void tst_QCoapRequest::ctor_data() 29 | { 30 | QTest::addColumn("url"); 31 | 32 | QTest::newRow("empty") << QUrl(); 33 | QTest::newRow("coap") << QUrl("coap://vs0.inf.ethz.ch:5683/test"); 34 | } 35 | 36 | void tst_QCoapRequest::ctor() 37 | { 38 | QFETCH(QUrl, url); 39 | 40 | QCoapRequest request(url); 41 | QCOMPARE(request.url(), url); 42 | } 43 | 44 | void tst_QCoapRequest::adjustUrl_data() 45 | { 46 | QTest::addColumn("inputUrl"); 47 | QTest::addColumn("expectedUrl"); 48 | QTest::addColumn("secure"); 49 | 50 | QTest::newRow("empty") << QUrl() << QUrl() << false; 51 | QTest::newRow("empty_secure") << QUrl() << QUrl() << true; 52 | QTest::newRow("scheme_and_port_known") << QUrl("coap://10.11.12.13:1234/test") 53 | << QUrl("coap://10.11.12.13:1234/test") << false; 54 | QTest::newRow("scheme_and_port_known_secure") << QUrl("coaps://10.11.12.13:1234/test") 55 | << QUrl("coaps://10.11.12.13:1234/test") << true; 56 | QTest::newRow("no_port") << QUrl("coap://vs0.inf.ethz.ch/test") 57 | << QUrl("coap://vs0.inf.ethz.ch:5683/test") << false; 58 | QTest::newRow("no_port_secure") << QUrl("coaps://vs0.inf.ethz.ch/test") 59 | << QUrl("coaps://vs0.inf.ethz.ch:5684/test") << true; 60 | QTest::newRow("no_scheme_no_port") << QUrl("vs0.inf.ethz.ch/test") 61 | << QUrl("coap://vs0.inf.ethz.ch:5683/test") << false; 62 | QTest::newRow("no_scheme_no_port_secure") << QUrl("vs0.inf.ethz.ch/test") 63 | << QUrl("coaps://vs0.inf.ethz.ch:5684/test") << true; 64 | 65 | QUrl ipv6Host; 66 | ipv6Host.setHost("::1"); 67 | ipv6Host.setPath("/path"); 68 | QTest::newRow("no_scheme_no_port_ipv6") << ipv6Host << QUrl("coap://[::1]:5683/path") 69 | << false; 70 | QTest::newRow("no_scheme_no_port_ipv6_secure") << ipv6Host << QUrl("coaps://[::1]:5684/path") 71 | << true; 72 | } 73 | 74 | void tst_QCoapRequest::adjustUrl() 75 | { 76 | #ifdef QT_BUILD_INTERNAL 77 | QFETCH(QUrl, inputUrl); 78 | QFETCH(QUrl, expectedUrl); 79 | QFETCH(bool, secure); 80 | 81 | // createRequest() will adjust the url 82 | QCoapRequest request = QCoapRequestPrivate::createRequest(QCoapRequest(inputUrl), 83 | QtCoap::Method::Get, secure); 84 | QCOMPARE(request.url(), expectedUrl); 85 | #else 86 | QSKIP("Not an internal build, skipping this test"); 87 | #endif 88 | } 89 | 90 | void tst_QCoapRequest::setUrl_data() 91 | { 92 | QTest::addColumn("inputUrl"); 93 | QTest::addColumn("expectedUrl"); 94 | 95 | QTest::newRow("empty") << QUrl() << QUrl(); 96 | QTest::newRow("coap") << QUrl("coap://10.11.12.13:5683/test") 97 | << QUrl("coap://10.11.12.13:5683/test"); 98 | QTest::newRow("coaps") << QUrl("coaps://10.11.12.13:5683/test") 99 | << QUrl("coaps://10.11.12.13:5683/test"); 100 | QTest::newRow("other_port") << QUrl("coap://10.11.12.13:8888/test") 101 | << QUrl("coap://10.11.12.13:8888/test"); 102 | QTest::newRow("no_port") << QUrl("coap://vs0.inf.ethz.ch/test") 103 | << QUrl("coap://vs0.inf.ethz.ch:5683/test"); 104 | QTest::newRow("no_port_scure") << QUrl("coaps://vs0.inf.ethz.ch/test") 105 | << QUrl("coaps://vs0.inf.ethz.ch:5684/test"); 106 | QTest::newRow("no_scheme_no_port") << QUrl("vs0.inf.ethz.ch/test") 107 | << QUrl("vs0.inf.ethz.ch/test"); 108 | QTest::newRow("incorrect_scheme") << QUrl("http://vs0.inf.ethz.ch:5683/test") << QUrl(); 109 | QTest::newRow("invalid") << QUrl("-coap://vs0.inf.ethz.ch:5683/test") << QUrl(); 110 | } 111 | 112 | void tst_QCoapRequest::setUrl() 113 | { 114 | QFETCH(QUrl, inputUrl); 115 | QFETCH(QUrl, expectedUrl); 116 | 117 | QCoapRequest request; 118 | request.setUrl(inputUrl); 119 | QCOMPARE(request.url(), expectedUrl); 120 | } 121 | 122 | void tst_QCoapRequest::enableObserve() 123 | { 124 | QCoapRequest request; 125 | 126 | QCOMPARE(request.isObserve(), false); 127 | request.enableObserve(); 128 | 129 | QCOMPARE(request.isObserve(), true); 130 | } 131 | 132 | void tst_QCoapRequest::copyAndDetach() 133 | { 134 | #ifdef QT_BUILD_INTERNAL 135 | QCoapRequest a = QCoapRequestPrivate::createRequest(QCoapRequest(), QtCoap::Method::Delete); 136 | a.setMessageId(3); 137 | a.setPayload("payload"); 138 | a.setToken("token"); 139 | a.setType(QCoapMessage::Type::Acknowledgment); 140 | a.setVersion(5); 141 | QUrl testUrl("coap://url:500/resource"); 142 | a.setUrl(testUrl); 143 | QUrl testProxyUrl("test://proxyurl"); 144 | a.setProxyUrl(testProxyUrl); 145 | 146 | // Test the QCoapMessage copy 147 | QCoapMessage b(a); 148 | QVERIFY2(b.messageId() == 3, "Message not copied correctly"); 149 | QVERIFY2(b.payload() == "payload", "Message not copied correctly"); 150 | QVERIFY2(b.token() == "token", "Message not copied correctly"); 151 | QVERIFY2(b.type() == QCoapMessage::Type::Acknowledgment, "Message not copied correctly"); 152 | QVERIFY2(b.version() == 5, "Message not copied correctly"); 153 | 154 | // Test the QCoapRequest copy 155 | QCoapRequest c(a); 156 | QVERIFY2(c.method() == QtCoap::Method::Delete, "Request not copied correctly"); 157 | QVERIFY2(c.url() == testUrl, "Request not copied correctly"); 158 | QVERIFY2(c.proxyUrl() == testProxyUrl, "Request not copied correctly"); 159 | 160 | // Detach 161 | c.setMessageId(9); 162 | QCOMPARE(c.messageId(), 9); 163 | QCOMPARE(a.messageId(), 3); 164 | #else 165 | QSKIP("Not an internal build, skipping this test"); 166 | #endif 167 | } 168 | 169 | QTEST_APPLESS_MAIN(tst_QCoapRequest) 170 | 171 | #include "tst_qcoaprequest.moc" 172 | -------------------------------------------------------------------------------- /src/coap/qcoapinternalreply.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | // Qt-Security score:critical reason:network-protocol 5 | 6 | #include "qcoapinternalreply_p.h" 7 | #include 8 | 9 | QT_BEGIN_NAMESPACE 10 | 11 | /*! 12 | \internal 13 | 14 | \class QCoapInternalReply 15 | \brief The QCoapInternalReply class contains data related to 16 | a received message. 17 | 18 | It is a subclass of QCoapInternalMessage. 19 | 20 | \reentrant 21 | 22 | \sa QCoapInternalMessage, QCoapInternalRequest 23 | */ 24 | 25 | /*! 26 | \internal 27 | Constructs a new QCoapInternalReply with \a parent as the parent object. 28 | */ 29 | QCoapInternalReply::QCoapInternalReply(QObject *parent) : 30 | QCoapInternalMessage(*new QCoapInternalReplyPrivate, parent) 31 | { 32 | } 33 | 34 | /*! 35 | \internal 36 | Creates a QCoapInternalReply from the CoAP \a reply frame. 37 | 38 | For more details, refer to section 39 | \l{https://tools.ietf.org/html/rfc7252#section-3}{'Message format' of RFC 7252}. 40 | */ 41 | //! 0 1 2 3 42 | //! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 43 | //! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 44 | //! |Ver| T | TKL | Code | Message ID | 45 | //! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 46 | //! | Token (if any, TKL bytes) ... 47 | //! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 48 | //! | Options (if any) ... 49 | //! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 50 | //! |1 1 1 1 1 1 1 1| Payload (if any) ... 51 | //! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 52 | QCoapInternalReply *QCoapInternalReply::createFromFrame(const QByteArray &reply, QObject *parent) 53 | { 54 | QCoapInternalReply *internalReply = new QCoapInternalReply(parent); 55 | QCoapInternalReplyPrivate *d = internalReply->d_func(); 56 | 57 | const quint8 *pduData = reinterpret_cast(reply.data()); 58 | 59 | // Parse Header and Token 60 | d->message.setVersion((pduData[0] >> 6) & 0x03); 61 | d->message.setType(QCoapMessage::Type((pduData[0] >> 4) & 0x03)); 62 | quint8 tokenLength = (pduData[0]) & 0x0F; 63 | d->responseCode = static_cast(pduData[1]); 64 | d->message.setMessageId(static_cast((static_cast(pduData[2]) << 8) 65 | | static_cast(pduData[3]))); 66 | d->message.setToken(reply.mid(4, tokenLength)); 67 | 68 | // Parse Options 69 | int i = 4 + tokenLength; 70 | quint16 lastOptionNumber = 0; 71 | while (i != reply.size() && pduData[i] != 0xFF) { 72 | quint16 optionDelta = ((pduData[i] >> 4) & 0x0F); 73 | quint16 optionLength = (pduData[i] & 0x0F); 74 | 75 | // Delta value > 12 : special values 76 | if (optionDelta == 13) { 77 | ++i; 78 | optionDelta = pduData[i] + 13; 79 | } else if (optionDelta == 14) { 80 | ++i; 81 | optionDelta = pduData[i] + 269; 82 | } 83 | 84 | // Delta length > 12 : special values 85 | if (optionLength == 13) { 86 | ++i; 87 | optionLength = pduData[i] + 13; 88 | } else if (optionLength == 14) { 89 | ++i; 90 | optionLength = pduData[i] + 269; 91 | } 92 | 93 | quint16 optionNumber = lastOptionNumber + optionDelta; 94 | internalReply->addOption(QCoapOption::OptionName(optionNumber), 95 | reply.mid(i + 1, optionLength)); 96 | lastOptionNumber = optionNumber; 97 | i += 1 + optionLength; 98 | } 99 | 100 | // Parse Payload 101 | if (i < reply.size() && pduData[i] == 0xFF) { 102 | // -1 because of 0xFF at the beginning 103 | QByteArray currentPayload = reply.mid(i + 1); 104 | d->message.setPayload(d->message.payload().append(currentPayload)); 105 | } 106 | 107 | return internalReply; 108 | } 109 | 110 | /*! 111 | \internal 112 | Appends the given \a data byte array to the current payload. 113 | */ 114 | void QCoapInternalReply::appendData(const QByteArray &data) 115 | { 116 | Q_D(QCoapInternalReply); 117 | d->message.setPayload(d->message.payload().append(data)); 118 | } 119 | 120 | /*! 121 | \internal 122 | Adds the given CoAP \a option and sets block parameters if needed. 123 | */ 124 | void QCoapInternalReply::addOption(const QCoapOption &option) 125 | { 126 | if (option.name() == QCoapOption::Block2) 127 | setFromDescriptiveBlockOption(option); 128 | 129 | QCoapInternalMessage::addOption(option); 130 | } 131 | 132 | /*! 133 | \internal 134 | Sets the sender address. 135 | */ 136 | void QCoapInternalReply::setSenderAddress(const QHostAddress &address) 137 | { 138 | Q_D(QCoapInternalReply); 139 | d->senderAddress = address; 140 | } 141 | 142 | /*! 143 | \internal 144 | Returns the number of the next block, if there is another block to come, 145 | otherwise -1. 146 | For more details, refer to the 147 | \l{https://tools.ietf.org/html/rfc7959#section-2.2}{RFC 7959}. 148 | */ 149 | int QCoapInternalReply::nextBlockToSend() const 150 | { 151 | Q_D(const QCoapInternalReply); 152 | 153 | QCoapOption option = d->message.option(QCoapOption::Block1); 154 | if (!option.isValid()) 155 | return -1; 156 | 157 | const auto value = option.opaqueValue(); 158 | const quint8 *optionData = reinterpret_cast(value.data()); 159 | const quint8 lastByte = optionData[option.length() - 1]; 160 | 161 | // M field 162 | bool hasNextBlock = ((lastByte & 0x8) == 0x8); 163 | if (!hasNextBlock) 164 | return -1; 165 | 166 | // NUM field 167 | quint32 blockNumber = 0; 168 | for (int i = 0; i < option.length() - 1; ++i) 169 | blockNumber = (blockNumber << 8) | optionData[i]; 170 | blockNumber = (blockNumber << 4) | (lastByte >> 4); 171 | return static_cast(blockNumber) + 1; 172 | } 173 | 174 | /*! 175 | \internal 176 | Returns \c true if the client has one or more blocks to send. 177 | */ 178 | bool QCoapInternalReply::hasMoreBlocksToSend() const 179 | { 180 | return nextBlockToSend() >= 0; 181 | } 182 | 183 | /*! 184 | \internal 185 | Returns the response code of the reply. 186 | */ 187 | QtCoap::ResponseCode QCoapInternalReply::responseCode() const 188 | { 189 | Q_D(const QCoapInternalReply); 190 | return d->responseCode; 191 | } 192 | 193 | /*! 194 | \internal 195 | Returns the host address from which the reply was received. 196 | */ 197 | QHostAddress QCoapInternalReply::senderAddress() const 198 | { 199 | Q_D(const QCoapInternalReply); 200 | return d->senderAddress; 201 | } 202 | 203 | QT_END_NAMESPACE 204 | -------------------------------------------------------------------------------- /tests/auto/qcoapinternalreply/tst_qcoapinternalreply.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | class tst_QCoapInternalReply : public QObject 12 | { 13 | Q_OBJECT 14 | 15 | private Q_SLOTS: 16 | void parseReplyPdu_data(); 17 | void parseReplyPdu(); 18 | void updateReply_data(); 19 | void updateReply(); 20 | }; 21 | 22 | void tst_QCoapInternalReply::parseReplyPdu_data() 23 | { 24 | QTest::addColumn("responseCode"); 25 | QTest::addColumn("type"); 26 | QTest::addColumn("messageId"); 27 | QTest::addColumn("token"); 28 | QTest::addColumn("tokenLength"); 29 | QTest::addColumn>("optionsNames"); 30 | QTest::addColumn>("optionsLengths"); 31 | QTest::addColumn>("optionsValues"); 32 | QTest::addColumn("payload"); 33 | QTest::addColumn("pduHexa"); 34 | 35 | QList optionsNamesReply({QCoapOption::ContentFormat, 36 | QCoapOption::MaxAge}); 37 | QList optionsLengthsReply({0, 1}); 38 | QList optionsValuesReply({"", QByteArray::fromHex("1e")}); 39 | 40 | QList bigOptionNameReply({QCoapOption::Size1}); 41 | QList bigOptionLengthReply({26}); 42 | QList bigOptionValueReply({QByteArray("abcdefghijklmnopqrstuvwxyz")}); 43 | 44 | QTest::newRow("reply_with_options_and_payload") 45 | << QtCoap::ResponseCode::Content 46 | << QCoapMessage::Type::NonConfirmable 47 | << quint16(64463) 48 | << QByteArray("4647f09b") 49 | << quint8(4) 50 | << optionsNamesReply 51 | << optionsLengthsReply 52 | << optionsValuesReply 53 | << "Type: 1 (NON)\nCode: 1 (GET)\nMID: 56400\nToken: 4647f09b" 54 | << "5445fbcf4647f09bc0211eff547970653a203120284e4f4e290a436f64653a20" 55 | "312028474554290a4d49443a2035363430300a546f6b656e3a20343634376630" 56 | "3962"; 57 | 58 | QTest::newRow("reply_with_payload") 59 | << QtCoap::ResponseCode::Content 60 | << QCoapMessage::Type::NonConfirmable 61 | << quint16(64463) 62 | << QByteArray("4647f09b") 63 | << quint8(4) 64 | << QList() 65 | << QList() 66 | << QList() 67 | << "Type: 1 (NON)\nCode: 1 (GET)\nMID: 56400\nToken: 4647f09b" 68 | << "5445fbcf4647f09bff547970653a203120284e4f4e290a436f64653a20312028" 69 | "474554290a4d49443a2035363430300a546f6b656e3a203436343766303962"; 70 | 71 | QTest::newRow("reply_with_options") 72 | << QtCoap::ResponseCode::Content 73 | << QCoapMessage::Type::NonConfirmable 74 | << quint16(64463) 75 | << QByteArray("4647f09b") 76 | << quint8(4) 77 | << optionsNamesReply 78 | << optionsLengthsReply 79 | << optionsValuesReply 80 | << "" 81 | << "5445fbcf4647f09bc0211e"; 82 | 83 | QTest::newRow("reply_only") 84 | << QtCoap::ResponseCode::Content 85 | << QCoapMessage::Type::NonConfirmable 86 | << quint16(64463) 87 | << QByteArray("4647f09b") 88 | << quint8(4) 89 | << QList() 90 | << QList() 91 | << QList() 92 | << "" 93 | << "5445fbcf4647f09b"; 94 | 95 | QTest::newRow("reply_with_big_option") 96 | << QtCoap::ResponseCode::Content 97 | << QCoapMessage::Type::NonConfirmable 98 | << quint16(64463) 99 | << QByteArray("4647f09b") 100 | << quint8(4) 101 | << bigOptionNameReply 102 | << bigOptionLengthReply 103 | << bigOptionValueReply 104 | << "" 105 | << "5445fbcf4647f09bdd2f0d6162636465666768696a6b6c6d6e6f707172737475" 106 | "767778797a"; 107 | } 108 | 109 | void tst_QCoapInternalReply::parseReplyPdu() 110 | { 111 | QFETCH(QtCoap::ResponseCode, responseCode); 112 | QFETCH(QCoapMessage::Type, type); 113 | QFETCH(quint16, messageId); 114 | QFETCH(QByteArray, token); 115 | QFETCH(quint8, tokenLength); 116 | QFETCH(QList, optionsNames); 117 | QFETCH(QList, optionsLengths); 118 | QFETCH(QList, optionsValues); 119 | QFETCH(QString, payload); 120 | QFETCH(QString, pduHexa); 121 | 122 | QScopedPointer 123 | reply(QCoapInternalReply::createFromFrame(QByteArray::fromHex(pduHexa.toUtf8()))); 124 | 125 | QCOMPARE(reply->message()->type(), type); 126 | QCOMPARE(reply->message()->tokenLength(), tokenLength); 127 | QCOMPARE(reply->responseCode(), responseCode); 128 | QCOMPARE(reply->message()->messageId(), messageId); 129 | QCOMPARE(reply->message()->token().toHex(), token); 130 | QCOMPARE(reply->message()->optionCount(), optionsNames.size()); 131 | for (int i = 0; i < reply->message()->optionCount(); ++i) { 132 | QCoapOption option = reply->message()->optionAt(i); 133 | QCOMPARE(option.name(), optionsNames.at(i)); 134 | QCOMPARE(option.length(), optionsLengths.at(i)); 135 | QCOMPARE(option.opaqueValue(), optionsValues.at(i)); 136 | } 137 | QCOMPARE(reply->message()->payload(), payload.toUtf8()); 138 | } 139 | 140 | void tst_QCoapInternalReply::updateReply_data() 141 | { 142 | QTest::addColumn("data"); 143 | 144 | QTest::newRow("success") << QByteArray("Data for the updating test"); 145 | } 146 | 147 | void tst_QCoapInternalReply::updateReply() 148 | { 149 | QFETCH(QByteArray, data); 150 | 151 | QScopedPointer reply(QCoapReplyPrivate::createCoapReply(QCoapRequest())); 152 | QCoapInternalReply internalReply; 153 | internalReply.message()->setPayload(data); 154 | QSignalSpy spyReplyFinished(reply.data(), &QCoapReply::finished); 155 | 156 | QMetaObject::invokeMethod(reply.data(), "_q_setContent", 157 | Q_ARG(QHostAddress, internalReply.senderAddress()), 158 | Q_ARG(QCoapMessage, *internalReply.message()), 159 | Q_ARG(QtCoap::ResponseCode, internalReply.responseCode())); 160 | QMetaObject::invokeMethod(reply.data(), "_q_setFinished", Q_ARG(QtCoap::Error, QtCoap::Error::Ok)); 161 | 162 | QTRY_COMPARE_WITH_TIMEOUT(spyReplyFinished.size(), 1, 1000); 163 | QCOMPARE(reply->readAll(), data); 164 | } 165 | 166 | QTEST_MAIN(tst_QCoapInternalReply) 167 | 168 | #include "tst_qcoapinternalreply.moc" 169 | -------------------------------------------------------------------------------- /tests/auto/qcoapresource/tst_qcoapresource.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Witekio. 2 | // Copyright (C) 2018 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | class tst_QCoapResource : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | private Q_SLOTS: 17 | void parseCoreLink_data(); 18 | void parseCoreLink(); 19 | }; 20 | 21 | void tst_QCoapResource::parseCoreLink_data() 22 | { 23 | QTest::addColumn("resourceNumber"); 24 | QTest::addColumn("senderAddress"); 25 | QTest::addColumn>("pathList"); 26 | QTest::addColumn>("titleList"); 27 | QTest::addColumn>("resourceTypeList"); 28 | QTest::addColumn>("contentFormatList"); 29 | QTest::addColumn>("interfaceList"); 30 | QTest::addColumn>("maximumSizeList"); 31 | QTest::addColumn>("observableList"); 32 | QTest::addColumn("coreLinkList"); 33 | 34 | QList pathList; 35 | pathList << "/obs" << "/separate" << "/seg1" << "/seg1/seg2" << "/large-separate" 36 | << "/.well-known/core" << "/multi-format" << "/path" 37 | << "/path/sub1" << "/link1" << "/validate" << "/test" 38 | << "/query" << "/large-post" << "/obs-non" << "/shutdown"; 39 | 40 | QList titleList; 41 | titleList << "Observable resource which changes every 5 seconds" 42 | << "Resource which cannot be served immediately and which cannot be acknowledged in a piggy-backed way" 43 | << "Long path resource" 44 | << "Long path resource" 45 | << "Large resource" 46 | << "" 47 | << "Resource that exists in different content formats (text/plain utf8 and application/xml)" 48 | << "Hierarchical link description entry" 49 | << "Hierarchical link description sub-resource" 50 | << "Link test resource" 51 | << "Resource which varies" 52 | << "Default test resource" 53 | << "Resource accepting query parameters" 54 | << "Handle PostOperation with two-way blockwise transfer" 55 | << "Observable resource which changes every 5 seconds" 56 | << ""; 57 | 58 | QList resourceTypeList; 59 | resourceTypeList << "observe" << "" << "" << "" << "block" << "" << "" << "" << "" 60 | << "Type1 Type2" << "" << "" << "" << "block" << "observe" << ""; 61 | 62 | QList contentFormatList; 63 | contentFormatList << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 40 << 0 << 0 << 0 << 0 64 | << 0 << 0 << 0 << 0; 65 | 66 | QList interfaceList; 67 | interfaceList << "" << "" << "" << "" << "" << "" << "" << "" << "" << "If1" 68 | << "" << "" << "" << "" << "" << ""; 69 | 70 | QList maximumSizeList; 71 | maximumSizeList << -1 << -1 << -1 << -1 << 1280 << -1 << -1 << -1 << -1 << -1 72 | << -1 << -1 << -1 << -1 << -1 << -1; 73 | 74 | QList observableList; 75 | observableList << true << false << false << false << false << false << false 76 | << false << false << false << false << false << false << false 77 | << true << false; 78 | 79 | QByteArray coreLinks; 80 | // Resources are separated by a comma 81 | coreLinks.append(";obs;rt=\"observe\";title=\"Observable resource which changes every" 82 | " 5 seconds\",;title=\"Resource which cannot be served immediately" 83 | " and which cannot be acknowledged in a piggy-backed way\",;title=\"" 84 | "Long path resource\",;title=\"Long path resource\"," 85 | ";rt=\"block\";sz=1280;title=\"Large resource\"," 86 | ",;ct=\"0 41\";title=\"Resource that exists" 87 | " in different content formats (text/plain utf8 and application/xml)\"," 88 | ";ct=40;title=\"Hierarchical link description entry\",;" 89 | "title=\"Hierarchical link description sub-resource\",;if=\"If1\";" 90 | "rt=\"Type1 Type2\";title=\"Link test resource\",;title=\"Resource" 91 | " which varies\",;title=\"Default test resource\",;" 92 | "title=\"Resource accepting query parameters\",;rt=\"block\";" 93 | "title=\"Handle PostOperation with two-way blockwise transfer\",;" 94 | "obs;rt=\"observe\";title=\"Observable resource which changes every 5 " 95 | "seconds\","); 96 | 97 | QTest::newRow("parse") << 16 98 | << QString("10.20.30.40") 99 | << pathList 100 | << titleList 101 | << resourceTypeList 102 | << contentFormatList 103 | << interfaceList 104 | << maximumSizeList 105 | << observableList 106 | << coreLinks; 107 | } 108 | 109 | void tst_QCoapResource::parseCoreLink() 110 | { 111 | #ifdef QT_BUILD_INTERNAL 112 | QFETCH(int, resourceNumber); 113 | QFETCH(QString, senderAddress); 114 | QFETCH(QList, pathList); 115 | QFETCH(QList, titleList); 116 | QFETCH(QList, resourceTypeList); 117 | QFETCH(QList, contentFormatList); 118 | QFETCH(QList, interfaceList); 119 | QFETCH(QList, maximumSizeList); 120 | QFETCH(QList, observableList); 121 | QFETCH(QByteArray, coreLinkList); 122 | 123 | const auto resourceList = 124 | QCoapResourceDiscoveryReplyPrivate::resourcesFromCoreLinkList( 125 | QHostAddress(senderAddress), coreLinkList); 126 | 127 | QCOMPARE(resourceList.size(), resourceNumber); 128 | 129 | int resourceIndex = 0; 130 | for (const auto &resource : resourceList) { 131 | QCOMPARE(resource.host(), QHostAddress(senderAddress)); 132 | QCOMPARE(resource.path(), pathList[resourceIndex]); 133 | QCOMPARE(resource.title(), titleList[resourceIndex]); 134 | QCOMPARE(resource.resourceType(), resourceTypeList[resourceIndex]); 135 | QCOMPARE(resource.contentFormat(), contentFormatList[resourceIndex]); 136 | QCOMPARE(resource.interface(), interfaceList[resourceIndex]); 137 | QCOMPARE(resource.maximumSize(), maximumSizeList[resourceIndex]); 138 | QCOMPARE(resource.observable(), observableList[resourceIndex]); 139 | ++resourceIndex; 140 | } 141 | #else 142 | QSKIP("Not an internal build, skipping this test"); 143 | #endif 144 | } 145 | 146 | QTEST_APPLESS_MAIN(tst_QCoapResource) 147 | 148 | #include "tst_qcoapresource.moc" 149 | --------------------------------------------------------------------------------