From 03c1c70145875f84364435c7e23dd3c3881fcd5f Mon Sep 17 00:00:00 2001 From: gabsuren Date: Fri, 26 May 2023 09:43:18 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20espressi?= =?UTF-8?q?f/esp-mqtt@b2bd8e5f49a472e79759f211c3d1b06ed566ab36=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 34 - .gitignore | 36 - .gitlab-ci.yml | 96 -- .nojekyll | 0 .travis.yml | 65 - CMakeLists.txt | 18 - Kconfig | 180 --- LICENSE | 202 --- README.md | 39 - ci/build_examples.sh | 22 - ci/modify_for_legacy_idf.sh | 33 - ci/publish_connect_mqtt_qemu.yml | 7 - ci/set_idf.sh | 19 - ci/set_mqtt.sh | 16 - host_test/CMakeLists.txt | 17 - host_test/README.md | 30 - host_test/main/CMakeLists.txt | 3 - host_test/main/test_mqtt_client.cpp | 126 -- host_test/mocks/heap/CMakeLists.txt | 4 - host_test/mocks/heap/heap_mock.c | 11 - host_test/mocks/include/sys/queue.h | 71 - host_test/sdkconfig.defaults | 6 - idf_component.yml | 5 - include/mqtt5_client.h | 281 ---- include/mqtt_client.h | 640 -------- include/mqtt_supported_features.h | 68 - index.html | 721 +++++++++ lib/include/mqtt5_client_priv.h | 55 - lib/include/mqtt5_msg.h | 142 -- lib/include/mqtt_client_priv.h | 138 -- lib/include/mqtt_config.h | 117 -- lib/include/mqtt_msg.h | 153 -- lib/include/mqtt_outbox.h | 66 - lib/include/platform.h | 14 - lib/include/platform_esp32_idf.h | 29 - lib/mqtt5_msg.c | 1043 ------------- lib/mqtt_msg.c | 624 -------- lib/mqtt_outbox.c | 238 --- lib/platform_esp32_idf.c | 35 - mqtt5_client.c | 760 ---------- mqtt_client.c | 2186 --------------------------- static-analysis-rules.yml | 9 - 42 files changed, 721 insertions(+), 7638 deletions(-) delete mode 100644 .editorconfig delete mode 100644 .gitignore delete mode 100644 .gitlab-ci.yml create mode 100644 .nojekyll delete mode 100644 .travis.yml delete mode 100644 CMakeLists.txt delete mode 100644 Kconfig delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100755 ci/build_examples.sh delete mode 100755 ci/modify_for_legacy_idf.sh delete mode 100644 ci/publish_connect_mqtt_qemu.yml delete mode 100755 ci/set_idf.sh delete mode 100755 ci/set_mqtt.sh delete mode 100644 host_test/CMakeLists.txt delete mode 100644 host_test/README.md delete mode 100644 host_test/main/CMakeLists.txt delete mode 100644 host_test/main/test_mqtt_client.cpp delete mode 100644 host_test/mocks/heap/CMakeLists.txt delete mode 100644 host_test/mocks/heap/heap_mock.c delete mode 100644 host_test/mocks/include/sys/queue.h delete mode 100644 host_test/sdkconfig.defaults delete mode 100644 idf_component.yml delete mode 100644 include/mqtt5_client.h delete mode 100644 include/mqtt_client.h delete mode 100644 include/mqtt_supported_features.h create mode 100644 index.html delete mode 100644 lib/include/mqtt5_client_priv.h delete mode 100644 lib/include/mqtt5_msg.h delete mode 100644 lib/include/mqtt_client_priv.h delete mode 100644 lib/include/mqtt_config.h delete mode 100644 lib/include/mqtt_msg.h delete mode 100644 lib/include/mqtt_outbox.h delete mode 100644 lib/include/platform.h delete mode 100644 lib/include/platform_esp32_idf.h delete mode 100644 lib/mqtt5_msg.c delete mode 100644 lib/mqtt_msg.c delete mode 100644 lib/mqtt_outbox.c delete mode 100644 lib/platform_esp32_idf.c delete mode 100644 mqtt5_client.c delete mode 100644 mqtt_client.c delete mode 100644 static-analysis-rules.yml diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 15977c6..0000000 --- a/.editorconfig +++ /dev/null @@ -1,34 +0,0 @@ -# EditorConfig helps developers define and maintain consistent -# coding styles between different editors and IDEs -# http://editorconfig.org - -root = true - -[*] -indent_style = space -indent_size = 4 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[{*.md,*.rst}] -trim_trailing_whitespace = false - -[{Makefile,*.mk,*.bat}] -indent_style = tab -indent_size = 2 - -[*/freertos/**] -indent_style = tab -indent_size = 4 - -[{*/freertos/**.S,**/FreeRTOSConfig.h}] -indent_style = space -indent_size = 4 - -[*.pem] -insert_final_newline = false - -[*.py] -max_line_length = 119 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 2c4b72c..0000000 --- a/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# Object files -*.o -*.ko -*.obj -*.elf - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -build -examples/**/build -examples/**/sdkconfig* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index ed90913..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,96 +0,0 @@ -stages: - - build - - deploy - - -variables: - IDF_REPO: ${GITLAB_SSH_SERVER}/idf/esp-idf.git - -.add_gh_key_remote: &add_gh_key_remote | - cit_add_ssh_key "${GH_PUSH_KEY}" - git remote remove github || true - git remote add github ${GH_PUSH_REPO} - -before_script: - # Use CI Tools - - curl -sSL ${CIT_LOADER_URL} | sh - - source citools/import_functions - # Add gitlab ssh key - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64 - - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - - PATH=$CI_PROJECT_DIR/esp-idf/tools:$PATH - - export MQTT_PATH=$CI_PROJECT_DIR - -.build_template: - stage: build - tags: - - build - - internet - script: - # Replace the IDF's default esp-mqtt with this version - - rm -rf $IDF_PATH/components/mqtt/esp-mqtt && cp -r $MQTT_PATH $IDF_PATH/components/mqtt/ - # Build the examples - - $MQTT_PATH/ci/build_examples.sh - -build_idf_v5.0: - extends: .build_template - image: espressif/idf:release-v5.0 - -build_idf_v5.1: - extends: .build_template - image: espressif/idf:release-v5.1 - -build_idf_latest: - extends: .build_template - image: espressif/idf:latest - -build_and_test_qemu: - stage: build - image: ${CI_DOCKER_REGISTRY}/qemu-v5.1:1-20220802 - tags: - - build - - shiny - dependencies: [] - script: - - export IDF_PATH=$CI_PROJECT_DIR/esp-idf - - git clone "${IDF_REPO}" - # switch to IDF and setup the tools - - $MQTT_PATH/ci/set_idf.sh release/v5.1 - - $IDF_PATH/tools/idf_tools.py install-python-env - - cd $IDF_PATH && tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" - # Remove `debug_backend` and Add `paho-mqtt` to the required packages - - sed '/debug_backend/d;/pygobject/d' $IDF_PATH/tools/requirements/requirements.ttfw.txt > requirements.txt - - python -m pip install -r requirements.txt - - python -m pip install paho-mqtt - - $MQTT_PATH/ci/set_mqtt.sh $CI_COMMIT_SHA - # build publish-connect stress test, setup test parameters - - cd tools/test_apps/protocols/mqtt/publish_connect_test && cat sdkconfig.qemu | $IDF_PATH/tools/ci/envsubst.py > sdkconfig.defaults && idf.py build - - export TEST_PATH=`pwd` && export MQTT_PUBLISH_TEST=1 - - export PYTHONPATH="$IDF_PATH/tools:$IDF_PATH/tools/ci/python_packages" - # run test (with environment->qemu) - - cd $IDF_PATH/tools/ci/python_packages/tiny_test_fw/bin - # use more relaxed criteria with QEMU tests - - export MQTT_PUBLISH_MSG_len_0=0 MQTT_PUBLISH_MSG_repeat_0=5 - - export MQTT_PUBLISH_MSG_len_1=2 MQTT_PUBLISH_MSG_repeat_1=50 - - export MQTT_PUBLISH_MSG_len_2=128 MQTT_PUBLISH_MSG_repeat_2=2 - - export MQTT_PUBLISH_MSG_len_3=20 MQTT_PUBLISH_MSG_repeat_3=20 - - python Runner.py $TEST_PATH -c $MQTT_PATH/ci/publish_connect_mqtt_qemu.yml -e $TEST_PATH/env.yml - -push_master_to_github: - stage: deploy - image: ${CI_DOCKER_REGISTRY}/esp32-ci-env - tags: - - build - only: - - master - - idf - when: on_success - variables: - GIT_STRATEGY: clone - script: - - *add_gh_key_remote - - git push github HEAD:${CI_COMMIT_REF_NAME} diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4affec1..0000000 --- a/.travis.yml +++ /dev/null @@ -1,65 +0,0 @@ -sudo: false -language: bash -os: - - linux - -addons: - apt: - packages: - - gperf - - python - - python-serial - -before_install: - # Save path to the git respository - - PROJECT_PATH=$(pwd) - # Have to checkout a temp branch for later in tree reference - - git checkout -b temporary_ref_branch - - CI_COMMIT_SHA=$(git rev-parse HEAD) - # Test building with latest (stable == v3.3 for now) IDF - - LTS_IDF=release/v3.3 - -install: - # Install ESP32 toochain following steps as desribed - # in http://esp-idf.readthedocs.io/en/latest/linux-setup.html - # - # Get required packages - already done above, see addons: apt: packages: - # - sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial - # Prepare directory for the toolchain - - mkdir -p ~/esp - - cd ~/esp - # Download binary toolchain for the ESP32 - - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz - - tar -xzf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz - # Get ESP-IDF from github (non-recursive to save time, later we update submodules for different versions) - - git clone https://github.com/espressif/esp-idf.git - # Set the path to ESP-IDF directory - - export IDF_PATH=~/esp/esp-idf - - python -m pip install --user -r $IDF_PATH/requirements.txt - # Setup build tool: xtensa-esp32-elf and idf.py - - export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin:$IDF_PATH/tools - -script: - # Legacy build with IDF < 3.2 - - cd $IDF_PATH - - git checkout v3.1 && git submodule update --init --recursive - - cd $PROJECT_PATH - - ./ci/modify_for_legacy_idf.sh ${LTS_IDF} || true - - cd $PROJECT_PATH/examples/tcp - - make defconfig - - make -j4 - # Build with v3.3 (LTS) IDF - - cd $IDF_PATH - - git checkout ${LTS_IDF} && git submodule update --init --recursive - - cd $IDF_PATH/components/mqtt/esp-mqtt - - git remote add local $PROJECT_PATH/.git - - git fetch local - - git reset --hard $CI_COMMIT_SHA - - cd $IDF_PATH/examples/protocols/mqtt/tcp - - idf.py build - - cd $IDF_PATH/examples/protocols/mqtt/ssl - - idf.py build - - cd $IDF_PATH/examples/protocols/mqtt/ws - - idf.py build - - cd $IDF_PATH/examples/protocols/mqtt/wss - - idf.py build \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 1fce7fb..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(srcs mqtt_client.c lib/mqtt_msg.c lib/mqtt_outbox.c lib/platform_esp32_idf.c) - -if(CONFIG_MQTT_PROTOCOL_5) - list(APPEND srcs lib/mqtt5_msg.c mqtt5_client.c) -endif() - -list(TRANSFORM srcs PREPEND ${CMAKE_CURRENT_LIST_DIR}/) -idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/include - PRIV_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/lib/include - REQUIRES esp_event tcp_transport - PRIV_REQUIRES esp_timer http_parser esp_hw_support heap - KCONFIG ${CMAKE_CURRENT_LIST_DIR}/Kconfig - ) -target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") - - - diff --git a/Kconfig b/Kconfig deleted file mode 100644 index 9eb6c0b..0000000 --- a/Kconfig +++ /dev/null @@ -1,180 +0,0 @@ -menu "ESP-MQTT Configurations" - - config MQTT_PROTOCOL_311 - bool "Enable MQTT protocol 3.1.1" - default y - help - If not, this library will use MQTT protocol 3.1 - - config MQTT_PROTOCOL_5 - bool "Enable MQTT protocol 5.0" - default n - help - If not, this library will not support MQTT 5.0 - - config MQTT_TRANSPORT_SSL - bool "Enable MQTT over SSL" - default y - help - Enable MQTT transport over SSL with mbedtls - - config MQTT_TRANSPORT_WEBSOCKET - bool "Enable MQTT over Websocket" - default y - depends on WS_TRANSPORT - help - Enable MQTT transport over Websocket. - - config MQTT_TRANSPORT_WEBSOCKET_SECURE - bool "Enable MQTT over Websocket Secure" - default y - depends on MQTT_TRANSPORT_WEBSOCKET - depends on MQTT_TRANSPORT_SSL - help - Enable MQTT transport over Websocket Secure. - - config MQTT_MSG_ID_INCREMENTAL - bool "Use Incremental Message Id" - default n - help - Set this to true for the message id (2.3.1 Packet Identifier) to be generated - as an incremental number rather then a random value (used by default) - - config MQTT_SKIP_PUBLISH_IF_DISCONNECTED - bool "Skip publish if disconnected" - default n - help - Set this to true to avoid publishing (enqueueing messages) if the client is disconnected. - The MQTT client tries to publish all messages by default, even in the disconnected state - (where the qos1 and qos2 packets are stored in the internal outbox to be published later) - The MQTT_SKIP_PUBLISH_IF_DISCONNECTED option allows applications to override this behaviour - and not enqueue publish packets in the disconnected state. - - config MQTT_REPORT_DELETED_MESSAGES - bool "Report deleted messages" - default n - help - Set this to true to post events for all messages which were deleted from the outbox - before being correctly sent and confirmed. - - config MQTT_USE_CUSTOM_CONFIG - bool "MQTT Using custom configurations" - default n - help - Custom MQTT configurations. - - config MQTT_TCP_DEFAULT_PORT - int "Default MQTT over TCP port" - default 1883 - depends on MQTT_USE_CUSTOM_CONFIG - help - Default MQTT over TCP port - - config MQTT_SSL_DEFAULT_PORT - int "Default MQTT over SSL port" - default 8883 - depends on MQTT_USE_CUSTOM_CONFIG - depends on MQTT_TRANSPORT_SSL - help - Default MQTT over SSL port - - config MQTT_WS_DEFAULT_PORT - int "Default MQTT over Websocket port" - default 80 - depends on MQTT_USE_CUSTOM_CONFIG - depends on MQTT_TRANSPORT_WEBSOCKET - help - Default MQTT over Websocket port - - config MQTT_WSS_DEFAULT_PORT - int "Default MQTT over Websocket Secure port" - default 443 - depends on MQTT_USE_CUSTOM_CONFIG - depends on MQTT_TRANSPORT_WEBSOCKET - depends on MQTT_TRANSPORT_WEBSOCKET_SECURE - help - Default MQTT over Websocket Secure port - - config MQTT_BUFFER_SIZE - int "Default MQTT Buffer Size" - default 1024 - depends on MQTT_USE_CUSTOM_CONFIG - help - This buffer size using for both transmit and receive - - config MQTT_TASK_STACK_SIZE - int "MQTT task stack size" - default 6144 - depends on MQTT_USE_CUSTOM_CONFIG - help - MQTT task stack size - - config MQTT_DISABLE_API_LOCKS - bool "Disable API locks" - default n - depends on MQTT_USE_CUSTOM_CONFIG - help - Default config employs API locks to protect internal structures. It is possible to disable - these locks if the user code doesn't access MQTT API from multiple concurrent tasks - - config MQTT_TASK_PRIORITY - int "MQTT task priority" - default 5 - depends on MQTT_USE_CUSTOM_CONFIG - help - MQTT task priority. Higher number denotes higher priority. - - config MQTT_POLL_READ_TIMEOUT_MS - int "MQTT transport poll read timeut" - default 1000 - depends on MQTT_USE_CUSTOM_CONFIG - help - Timeout when polling underlying transport for read. - - config MQTT_EVENT_QUEUE_SIZE - int "Number of queued events." - default 1 - depends on MQTT_USE_CUSTOM_CONFIG - help - A value higher than 1 enables multiple queued events. - - config MQTT_TASK_CORE_SELECTION_ENABLED - bool "Enable MQTT task core selection" - help - This will enable core selection - - choice MQTT_TASK_CORE_SELECTION - depends on MQTT_TASK_CORE_SELECTION_ENABLED - prompt "Core to use ?" - config MQTT_USE_CORE_0 - bool "Core 0" - config MQTT_USE_CORE_1 - bool "Core 1" - endchoice - - config MQTT_OUTBOX_DATA_ON_EXTERNAL_MEMORY - bool "Use external memory for outbox data" - default n - depends on MQTT_USE_CUSTOM_CONFIG - help - Set to true to use external memory for outbox data. - - config MQTT_CUSTOM_OUTBOX - bool "Enable custom outbox implementation" - default n - help - Set to true if a specific implementation of message outbox is needed (e.g. persistent outbox in NVM or - similar). - Note: Implementation of the custom outbox must be added to the mqtt component. These CMake commands - could be used to append the custom implementation to lib-mqtt sources: - idf_component_get_property(mqtt mqtt COMPONENT_LIB) - set_property(TARGET ${mqtt} PROPERTY SOURCES ${PROJECT_DIR}/custom_outbox.c APPEND) - - config MQTT_OUTBOX_EXPIRED_TIMEOUT_MS - int "Outbox message expired timeout[ms]" - default 30000 - depends on MQTT_USE_CUSTOM_CONFIG - help - Messages which stays in the outbox longer than this value before being published will be discarded. - -endmenu diff --git a/LICENSE b/LICENSE deleted file mode 100644 index a623b53..0000000 --- a/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2016 Tuan PM - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md deleted file mode 100644 index 6a6fe3e..0000000 --- a/README.md +++ /dev/null @@ -1,39 +0,0 @@ -[![](https://travis-ci.org/tuanpmt/espmqtt.svg?branch=master)](https://travis-ci.org/tuanpmt/espmqtt) -[![](http://hits.dwyl.io/tuanpmt/espmqtt.svg)](http://hits.dwyl.io/tuanpmt/espmqtt) -[![Twitter Follow](https://img.shields.io/twitter/follow/tuanpmt.svg?style=social&label=Follow)](https://twitter.com/tuanpmt) -![GitHub contributors](https://img.shields.io/github/contributors/tuanpmt/espmqtt.svg) - -# ESP32 MQTT Library - -## Features - -- Based on: https://github.com/tuanpmt/esp_mqtt -- Support MQTT over TCP, SSL with mbedtls, MQTT over Websocket, MQTT over Websocket Secure -- Easy to setup with URI -- Multiple instances (Multiple clients in one application) -- Support subscribing, publishing, authentication, will messages, keep alive pings and all 3 QoS levels (it should be a fully functional client). - -## How to use - -[ESP-MQTT](https://github.com/espressif/esp-mqtt) is a standard [ESP-IDF](https://github.com/espressif/esp-idf) component. -Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf) - -## Documentation - -* Please refer to the standard [ESP-IDF](https://github.com/espressif/esp-idf), documentation for the latest version: https://docs.espressif.com/projects/esp-idf/ - -* Documentation of ESP-MQTT API: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/protocols/mqtt.html - -## License - -- MQTT Package - [Stephen Robinson - contiki-mqtt](https://github.com/esar/contiki-mqtt) -- Others [@tuanpmt](https://twitter.com/tuanpmt) -Apache License - -## Older IDF verisons - -For [ESP-IDF](https://github.com/espressif/esp-idf) versions prior to IDFv3.2, please clone as a component of [ESP-IDF](https://github.com/espressif/esp-idf): -``` -git submodule add https://github.com/espressif/esp-mqtt.git components/espmqtt -``` -and checkout the [ESP-MQTT_FOR_IDF_3.1](https://github.com/espressif/esp-mqtt/tree/ESP-MQTT_FOR_IDF_3.1) tag diff --git a/ci/build_examples.sh b/ci/build_examples.sh deleted file mode 100755 index 9643ea2..0000000 --- a/ci/build_examples.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -# build mqtt examples with make if $1=="make", with cmake otherwise -set -o errexit # Exit if command failed. - -if [ -z $IDF_PATH ] ; then - echo "Mandatory variables undefined" - exit 1; -fi; - -examples="tcp ssl ssl_mutual_auth ws wss" -for i in $examples; do - echo "Building MQTT example $i" - cd $IDF_PATH/examples/protocols/mqtt/$i - if [[ "$1" = "make" ]]; then - make defconfig - make -j 4 - else - rm -rf build sdkconfig - idf.py build - fi; -done diff --git a/ci/modify_for_legacy_idf.sh b/ci/modify_for_legacy_idf.sh deleted file mode 100755 index 8ea7e2b..0000000 --- a/ci/modify_for_legacy_idf.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -if [[ -z $1 ]]; then - LATEST_IDF=master -else - LATEST_IDF=$1 -fi - -# This snipped prepares environment for using esp-mqtt repository separately from idf -- legacy use before IDFv3.2 -# -esp_mqtt_path=`pwd` -mkdir -p ${esp_mqtt_path}/examples -pushd -cd $IDF_PATH -former_commit_id=`git rev-parse HEAD` -git checkout ${LATEST_IDF} - -for example in tcp; do - cp -r $IDF_PATH/examples/protocols/mqtt/${example} ${esp_mqtt_path}/examples - echo 'EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../' > ${esp_mqtt_path}/examples/${example}/Makefile - cat $IDF_PATH/examples/protocols/mqtt/${example}/Makefile >> ${esp_mqtt_path}/examples/${example}/Makefile - echo "CONFIG_MQTT_TRANSPORT_SSL=" >> ${esp_mqtt_path}/examples/${example}/sdkconfig.defaults - echo "CONFIG_MQTT_TRANSPORT_WEBSOCKET=" >> ${esp_mqtt_path}/examples/${example}/sdkconfig.defaults -done - -cp -r $IDF_PATH/components/tcp_transport ${esp_mqtt_path}/.. -rm ${esp_mqtt_path}/../tcp_transport/transport_ssl.c -echo -e "#include \"esp_transport.h\"\nvoid esp_transport_ws_set_path(esp_transport_handle_t t, const char *path) {}" > ${esp_mqtt_path}/../tcp_transport/transport_ws.c - -cp $IDF_PATH/components/mqtt/Kconfig ${esp_mqtt_path} -sed 's/esp-mqtt/\./g' $IDF_PATH/components/mqtt/component.mk > ${esp_mqtt_path}/component.mk -git checkout $former_commit_id -popd \ No newline at end of file diff --git a/ci/publish_connect_mqtt_qemu.yml b/ci/publish_connect_mqtt_qemu.yml deleted file mode 100644 index 1a8cd50..0000000 --- a/ci/publish_connect_mqtt_qemu.yml +++ /dev/null @@ -1,7 +0,0 @@ -CaseConfig: -- name: test_app_protocol_mqtt_publish_connect - overwrite: - dut: - class: ESP32QEMUDUT - package: ttfw_idf - diff --git a/ci/set_idf.sh b/ci/set_idf.sh deleted file mode 100755 index 1bd7ab8..0000000 --- a/ci/set_idf.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -# sets up the IDF repo incl submodules with specified version as $1 -set -o errexit # Exit if command failed. - -if [ -z $IDF_PATH ] || [ -z $MQTT_PATH ] || [ -z $1 ] ; then - echo "Mandatory variables undefined" - exit 1; -fi; - -echo "Checking out IDF version $1" -cd $IDF_PATH -# Cleans out the untracked files in the repo, so the next "git checkout" doesn't fail -git clean -f -git checkout $1 -# Removes the mqtt submodule, so the next submodule update doesn't fail -rm -rf $IDF_PATH/components/mqtt/esp-mqtt -git submodule update --init --recursive - diff --git a/ci/set_mqtt.sh b/ci/set_mqtt.sh deleted file mode 100755 index 8c70b66..0000000 --- a/ci/set_mqtt.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -# sets the mqtt in IDF tree as a submodule with the version specified as $1 -set -o errexit # Exit if command failed. - -if [ -z $IDF_PATH ] || [ -z $MQTT_PATH ] || [ -z $1 ] ; then - echo "Mandatory variables undefined" - exit 1; -fi; - -echo "Checking out MQTT version to $1" -# exchange remotes of mqtt submodules with plain copy -cd $IDF_PATH/components/mqtt/esp-mqtt -rm -rf .git # removes the actual IDF referenced version -cp -r $MQTT_PATH/.git . # replaces with the MQTT_PATH (CI checked tree) -git reset --hard $1 # sets the requested version diff --git a/host_test/CMakeLists.txt b/host_test/CMakeLists.txt deleted file mode 100644 index db98733..0000000 --- a/host_test/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -set(COMPONENTS main) -list(APPEND EXTRA_COMPONENT_DIRS - "mocks/heap/" - "$ENV{IDF_PATH}/tools/mocks/esp_hw_support/" - "$ENV{IDF_PATH}/tools/mocks/freertos/" - "$ENV{IDF_PATH}/tools/mocks/esp_timer/" - "$ENV{IDF_PATH}/tools/mocks/esp_event/" - "$ENV{IDF_PATH}/tools/mocks/lwip/" - "$ENV{IDF_PATH}/tools/mocks/esp-tls/" - "$ENV{IDF_PATH}/tools/mocks/http_parser/" - "$ENV{IDF_PATH}/tools/mocks/tcp_transport/" - ) - -project(host_mqtt_client_test) diff --git a/host_test/README.md b/host_test/README.md deleted file mode 100644 index a62087a..0000000 --- a/host_test/README.md +++ /dev/null @@ -1,30 +0,0 @@ -| Supported Targets | Linux | -| ----------------- | ----- | - -# Description - -This directory contains test code for the mqtt client that runs on host. - -Tests are written using [Catch2](https://github.com/catchorg/Catch2) test framework - -# Build - -Tests build regularly like an idf project. - -``` -idf.py build -``` - -# Run - -The build produces an executable in the build folder. - -Just run: - -``` -./build/host_mqtt_client_test.elf -``` - -The test executable have some options provided by the test framework. - - diff --git a/host_test/main/CMakeLists.txt b/host_test/main/CMakeLists.txt deleted file mode 100644 index 6c4a9c7..0000000 --- a/host_test/main/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -idf_component_register(SRCS "test_mqtt_client.cpp" - INCLUDE_DIRS "$ENV{IDF_PATH}/tools/catch" - REQUIRES cmock mqtt esp_timer esp_hw_support http_parser log) diff --git a/host_test/main/test_mqtt_client.cpp b/host_test/main/test_mqtt_client.cpp deleted file mode 100644 index 37dd34e..0000000 --- a/host_test/main/test_mqtt_client.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#define CATCH_CONFIG_MAIN // This tells the catch header to generate a main -#include "catch.hpp" - -extern "C" { -#include "Mockesp_event.h" -#include "Mockesp_mac.h" -#include "Mockesp_transport.h" -#include "Mockesp_transport_ssl.h" -#include "Mockesp_transport_tcp.h" -#include "Mockesp_transport_ws.h" -#include "Mockevent_groups.h" -#include "Mockhttp_parser.h" -#include "Mockqueue.h" -#include "Mocktask.h" -#include "Mockesp_timer.h" - - /* - * The following functions are not directly called but the generation of them - * from cmock is broken, so we need to define them here. - */ - esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *esp_tls_code, int *esp_tls_flags) - { - return ESP_OK; - } -} - -#include "mqtt_client.h" - -struct ClientInitializedFixture { - esp_mqtt_client_handle_t client; - ClientInitializedFixture() - { - [[maybe_unused]] auto protect = TEST_PROTECT(); - int mtx; - int transport_list; - int transport; - int event_group; - uint8_t mac[] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55}; - esp_timer_get_time_IgnoreAndReturn(0); - xQueueTakeMutexRecursive_IgnoreAndReturn(true); - xQueueGiveMutexRecursive_IgnoreAndReturn(true); - xQueueCreateMutex_ExpectAnyArgsAndReturn( - reinterpret_cast(&mtx)); - xEventGroupCreate_IgnoreAndReturn(reinterpret_cast(&event_group)); - esp_transport_list_init_IgnoreAndReturn(reinterpret_cast(&transport_list)); - esp_transport_tcp_init_IgnoreAndReturn(reinterpret_cast(&transport)); - esp_transport_ssl_init_IgnoreAndReturn(reinterpret_cast(&transport)); - esp_transport_ws_init_IgnoreAndReturn(reinterpret_cast(&transport)); - esp_transport_ws_set_subprotocol_IgnoreAndReturn(ESP_OK); - esp_transport_list_add_IgnoreAndReturn(ESP_OK); - esp_transport_set_default_port_IgnoreAndReturn(ESP_OK); - http_parser_parse_url_IgnoreAndReturn(0); - http_parser_url_init_ExpectAnyArgs(); - esp_event_loop_create_IgnoreAndReturn(ESP_OK); - esp_read_mac_IgnoreAndReturn(ESP_OK); - esp_read_mac_ReturnThruPtr_mac(mac); - esp_transport_list_destroy_IgnoreAndReturn(ESP_OK); - vEventGroupDelete_Ignore(); - vQueueDelete_Ignore(); - - esp_mqtt_client_config_t config{}; - client = esp_mqtt_client_init(&config); - } - ~ClientInitializedFixture() - { - esp_mqtt_client_destroy(client); - } -}; -TEST_CASE_METHOD(ClientInitializedFixture, "Client set uri") -{ - struct http_parser_url ret_uri = { - .field_set = 1, - .port = 0, - .field_data = { { 0, 1} } - }; - SECTION("User set a correct URI") { - http_parser_parse_url_StopIgnore(); - http_parser_parse_url_ExpectAnyArgsAndReturn(0); - http_parser_parse_url_ReturnThruPtr_u(&ret_uri); - auto res = esp_mqtt_client_set_uri(client, " "); - REQUIRE(res == ESP_OK); - } - SECTION("Incorrect URI from user") { - http_parser_parse_url_StopIgnore(); - http_parser_parse_url_ExpectAnyArgsAndReturn(1); - http_parser_parse_url_ReturnThruPtr_u(&ret_uri); - auto res = esp_mqtt_client_set_uri(client, " "); - REQUIRE(res == ESP_FAIL); - } -} -TEST_CASE_METHOD(ClientInitializedFixture, "Client Start") -{ - SECTION("Successful start") { - esp_mqtt_client_config_t config{}; - config.broker.address.uri = "mqtt://1.1.1.1"; - struct http_parser_url ret_uri = { - .field_set = 1 | (1<<1), - .port = 0, - .field_data = { { 0, 4 } /*mqtt*/, { 7, 1 } } // at least *scheme* and *host* - }; - http_parser_parse_url_StopIgnore(); - http_parser_parse_url_ExpectAnyArgsAndReturn(0); - http_parser_parse_url_ReturnThruPtr_u(&ret_uri); - xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdTRUE); - auto res = esp_mqtt_set_config(client, &config); - REQUIRE(res == ESP_OK); - res = esp_mqtt_client_start(client); - REQUIRE(res == ESP_OK); - } - SECTION("Failed on initialization") { - xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdFALSE); - auto res = esp_mqtt_client_start(nullptr); - REQUIRE(res == ESP_ERR_INVALID_ARG); - } - SECTION("Client already started") {} - SECTION("Failed to start task") { - xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdFALSE); - auto res = esp_mqtt_client_start(client); - REQUIRE(res == ESP_FAIL); - } -} diff --git a/host_test/mocks/heap/CMakeLists.txt b/host_test/mocks/heap/CMakeLists.txt deleted file mode 100644 index 0a0c8a6..0000000 --- a/host_test/mocks/heap/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -idf_component_get_property(original_heap_dir heap COMPONENT_OVERRIDEN_DIR) - -idf_component_register(SRCS heap_mock.c - INCLUDE_DIRS "${original_heap_dir}/include") diff --git a/host_test/mocks/heap/heap_mock.c b/host_test/mocks/heap/heap_mock.c deleted file mode 100644 index 6bc3b35..0000000 --- a/host_test/mocks/heap/heap_mock.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "esp_heap_caps.h" -#include -#include - - - -void *heap_caps_calloc(size_t n, size_t size, uint32_t caps) { - (void)caps; - return calloc(n, size); - -} diff --git a/host_test/mocks/include/sys/queue.h b/host_test/mocks/include/sys/queue.h deleted file mode 100644 index 1afffb9..0000000 --- a/host_test/mocks/include/sys/queue.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SPDX-FileCopyrightText: 1991-1993 The Regents of the University of California - * - * SPDX-License-Identifier: BSD-3-Clause - */ -#pragma once - -/* Implementation from BSD headers*/ -#define QMD_SAVELINK(name, link) void **name = (void *)&(link) -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first;/* first element */ \ - struct type **stqh_last;/* addr of last next element */ \ -} - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - STAILQ_NEXT((elm), field) = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_INIT(head) do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_FOREACH(var, head, field) \ - for((var) = STAILQ_FIRST((head)); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = STAILQ_FIRST((head)); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - STAILQ_REMOVE_AFTER(head, curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) diff --git a/host_test/sdkconfig.defaults b/host_test/sdkconfig.defaults deleted file mode 100644 index c126429..0000000 --- a/host_test/sdkconfig.defaults +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG_IDF_TARGET="linux" -CONFIG_COMPILER_CXX_EXCEPTIONS=y -CONFIG_COMPILER_CXX_RTTI=y -CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 -CONFIG_COMPILER_STACK_CHECK_NONE=y -CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n diff --git a/idf_component.yml b/idf_component.yml deleted file mode 100644 index 23cec31..0000000 --- a/idf_component.yml +++ /dev/null @@ -1,5 +0,0 @@ -version: "1.0.0" -description: esp-mqtt -dependencies: - idf: - version: ">=5.0" diff --git a/include/mqtt5_client.h b/include/mqtt5_client.h deleted file mode 100644 index af5277f..0000000 --- a/include/mqtt5_client.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _MQTT5_CLIENT_H_ -#define _MQTT5_CLIENT_H_ - -#include "mqtt_client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct esp_mqtt_client *esp_mqtt5_client_handle_t; - -/** - * MQTT5 protocol error reason code, more details refer to MQTT5 protocol document section 2.4 - */ -enum mqtt5_error_reason_code { - MQTT5_UNSPECIFIED_ERROR = 0x80, - MQTT5_MALFORMED_PACKET = 0x81, - MQTT5_PROTOCOL_ERROR = 0x82, - MQTT5_IMPLEMENT_SPECIFIC_ERROR = 0x83, - MQTT5_UNSUPPORTED_PROTOCOL_VER = 0x84, - MQTT5_INVAILD_CLIENT_ID = 0x85, - MQTT5_BAD_USERNAME_OR_PWD = 0x86, - MQTT5_NOT_AUTHORIZED = 0x87, - MQTT5_SERVER_UNAVAILABLE = 0x88, - MQTT5_SERVER_BUSY = 0x89, - MQTT5_BANNED = 0x8A, - MQTT5_SERVER_SHUTTING_DOWN = 0x8B, - MQTT5_BAD_AUTH_METHOD = 0x8C, - MQTT5_KEEP_ALIVE_TIMEOUT = 0x8D, - MQTT5_SESSION_TAKEN_OVER = 0x8E, - MQTT5_TOPIC_FILTER_INVAILD = 0x8F, - MQTT5_TOPIC_NAME_INVAILD = 0x90, - MQTT5_PACKET_IDENTIFIER_IN_USE = 0x91, - MQTT5_PACKET_IDENTIFIER_NOT_FOUND = 0x92, - MQTT5_RECEIVE_MAXIMUM_EXCEEDED = 0x93, - MQTT5_TOPIC_ALIAS_INVAILD = 0x94, - MQTT5_PACKET_TOO_LARGE = 0x95, - MQTT5_MESSAGE_RATE_TOO_HIGH = 0x96, - MQTT5_QUOTA_EXCEEDED = 0x97, - MQTT5_ADMINISTRATIVE_ACTION = 0x98, - MQTT5_PAYLOAD_FORMAT_INVAILD = 0x99, - MQTT5_RETAIN_NOT_SUPPORT = 0x9A, - MQTT5_QOS_NOT_SUPPORT = 0x9B, - MQTT5_USE_ANOTHER_SERVER = 0x9C, - MQTT5_SERVER_MOVED = 0x9D, - MQTT5_SHARED_SUBSCR_NOT_SUPPORTED = 0x9E, - MQTT5_CONNECTION_RATE_EXCEEDED = 0x9F, - MQTT5_MAXIMUM_CONNECT_TIME = 0xA0, - MQTT5_SUBSCRIBE_IDENTIFIER_NOT_SUPPORT = 0xA1, - MQTT5_WILDCARD_SUBSCRIBE_NOT_SUPPORT = 0xA2, -}; - -/** - * MQTT5 user property handle - */ -typedef struct mqtt5_user_property_list_t *mqtt5_user_property_handle_t; - -/** - * MQTT5 protocol connect properties and will properties configuration, more details refer to MQTT5 protocol document section 3.1.2.11 and 3.3.2.3 - */ -typedef struct { - uint32_t session_expiry_interval; /*!< The interval time of session expiry */ - uint32_t maximum_packet_size; /*!< The maximum packet size that we can receive */ - uint16_t receive_maximum; /*!< The maximum pakcket count that we process concurrently */ - uint16_t topic_alias_maximum; /*!< The maximum topic alias that we support */ - bool request_resp_info; /*!< This value to request Server to return Response information */ - bool request_problem_info; /*!< This value to indicate whether the reason string or user properties are sent in case of failures */ - mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ - uint32_t will_delay_interval; /*!< The time interval that server delays publishing will message */ - uint32_t message_expiry_interval; /*!< The time interval that message expiry */ - bool payload_format_indicator; /*!< This value is to indicator will message payload format */ - const char *content_type; /*!< This value is to indicator will message content type, use a MIME content type string */ - const char *response_topic; /*!< Topic name for a response message */ - const char *correlation_data; /*!< Binary data for receiver to match the response message */ - uint16_t correlation_data_len; /*!< The length of correlation data */ - mqtt5_user_property_handle_t will_user_property; /*!< The handle for will message user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_connection_property_config_t; - -/** - * MQTT5 protocol publish properties configuration, more details refer to MQTT5 protocol document section 3.3.2.3 - */ -typedef struct { - bool payload_format_indicator; /*!< This value is to indicator publish message payload format */ - uint32_t message_expiry_interval; /*!< The time interval that message expiry */ - uint16_t topic_alias; /*!< An interger value to identify the topic instead of using topic name string */ - const char *response_topic; /*!< Topic name for a response message */ - const char *correlation_data; /*!< Binary data for receiver to match the response message */ - uint16_t correlation_data_len; /*!< The length of correlation data */ - const char *content_type; /*!< This value is to indicator publish message content type, use a MIME content type string */ - mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_publish_property_config_t; - -/** - * MQTT5 protocol subscribe properties configuration, more details refer to MQTT5 protocol document section 3.8.2.1 - */ -typedef struct { - uint16_t subscribe_id; /*!< A variable byte represents the identifier of the subscription */ - bool no_local_flag; /*!< Subscription Option to allow that server publish message that client sent */ - bool retain_as_published_flag; /*!< Subscription Option to keep the retain flag as published option */ - uint8_t retain_handle; /*!< Subscription Option to handle retain option */ - bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */ - const char *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */ - mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_subscribe_property_config_t; - -/** - * MQTT5 protocol unsubscribe properties configuration, more details refer to MQTT5 protocol document section 3.10.2.1 - */ -typedef struct { - bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */ - const char *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */ - mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_unsubscribe_property_config_t; - -/** - * MQTT5 protocol disconnect properties configuration, more details refer to MQTT5 protocol document section 3.14.2.2 - */ -typedef struct { - uint32_t session_expiry_interval; /*!< The interval time of session expiry */ - uint8_t disconnect_reason; /*!< The reason that connection disconnet, refer to mqtt5_error_reason_code */ - mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_disconnect_property_config_t; - -/** - * MQTT5 protocol for event properties - */ -typedef struct { - bool payload_format_indicator; /*!< Payload format of the message */ - char *response_topic; /*!< Response topic of the message */ - int response_topic_len; /*!< Response topic length of the message */ - char *correlation_data; /*!< Correlation data of the message */ - uint16_t correlation_data_len; /*!< Correlation data length of the message */ - char *content_type; /*!< Content type of the message */ - int content_type_len; /*!< Content type length of the message */ - uint16_t subscribe_id; /*!< Subscription identifier of the message */ - mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_delete_user_property to free the memory */ -} esp_mqtt5_event_property_t; - -/** - * MQTT5 protocol for user property - */ -typedef struct { - const char *key; /*!< Item key name */ - const char *value; /*!< Item value string */ -} esp_mqtt5_user_property_item_t; - -/** - * @brief Set MQTT5 client connect property configuration - * - * @param client mqtt client handle - * @param connect_property connect property - * - * @return ESP_ERR_NO_MEM if failed to allocate - * ESP_ERR_INVALID_ARG on wrong initialization - * ESP_FAIL on fail - * ESP_OK on success - */ -esp_err_t esp_mqtt5_client_set_connect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_connection_property_config_t *connect_property); - -/** - * @brief Set MQTT5 client publish property configuration - * - * This API will not store the publish property, it is one-time configuration. - * Before call `esp_mqtt_client_publish` to publish data, call this API to set publish property if have - * - * @param client mqtt client handle - * @param property publish property - * - * @return ESP_ERR_INVALID_ARG on wrong initialization - * ESP_FAIL on fail - * ESP_OK on success - */ -esp_err_t esp_mqtt5_client_set_publish_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_publish_property_config_t *property); - -/** - * @brief Set MQTT5 client subscribe property configuration - * - * This API will not store the subscribe property, it is one-time configuration. - * Before call `esp_mqtt_client_subscribe` to subscribe topic, call this API to set subscribe property if have - * - * @param client mqtt client handle - * @param property subscribe property - * - * @return ESP_ERR_INVALID_ARG on wrong initialization - * ESP_FAIL on fail - * ESP_OK on success - */ -esp_err_t esp_mqtt5_client_set_subscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_subscribe_property_config_t *property); - -/** - * @brief Set MQTT5 client unsubscribe property configuration - * - * This API will not store the unsubscribe property, it is one-time configuration. - * Before call `esp_mqtt_client_unsubscribe` to unsubscribe topic, call this API to set unsubscribe property if have - * - * @param client mqtt client handle - * @param property unsubscribe property - * - * @return ESP_ERR_INVALID_ARG on wrong initialization - * ESP_FAIL on fail - * ESP_OK on success - */ -esp_err_t esp_mqtt5_client_set_unsubscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_unsubscribe_property_config_t *property); - -/** - * @brief Set MQTT5 client disconnect property configuration - * - * This API will not store the disconnect property, it is one-time configuration. - * Before call `esp_mqtt_client_disconnect` to disconnect connection, call this API to set disconnect property if have - * - * @param client mqtt client handle - * @param property disconnect property - * - * @return ESP_ERR_NO_MEM if failed to allocate - * ESP_ERR_INVALID_ARG on wrong initialization - * ESP_FAIL on fail - * ESP_OK on success - */ -esp_err_t esp_mqtt5_client_set_disconnect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_disconnect_property_config_t *property); - -/** - * @brief Set MQTT5 client user property configuration - * - * This API will allocate memory for user_property, please DO NOT forget `call esp_mqtt5_client_delete_user_property` - * after you use it. - * Before publish data, subscribe topic, unsubscribe, etc, call this API to set user property if have - * - * @param user_property user_property handle - * @param item array of user property data (eg. {{"var","val"},{"other","2"}}) - * @param item_num number of items in user property data - * - * @return ESP_ERR_NO_MEM if failed to allocate - * ESP_FAIL on fail - * ESP_OK on success - */ -esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_property, esp_mqtt5_user_property_item_t item[], uint8_t item_num); - -/** - * @brief Get MQTT5 client user property - * - * @param user_property user_property handle - * @param item point that store user property data - * @param item_num number of items in user property data - * - * This API can use with `esp_mqtt5_client_get_user_property_count` to get list count of user property. - * And malloc number of count item array memory to store the user property data. - * Please DO NOT forget the item memory, key and value point in item memory when get user property data successfully. - * - * @return ESP_ERR_NO_MEM if failed to allocate - * ESP_FAIL on fail - * ESP_OK on success - */ -esp_err_t esp_mqtt5_client_get_user_property(mqtt5_user_property_handle_t user_property, esp_mqtt5_user_property_item_t *item, uint8_t *item_num); - -/** - * @brief Get MQTT5 client user property list count - * - * @param user_property user_property handle - * @return user property list count - */ -uint8_t esp_mqtt5_client_get_user_property_count(mqtt5_user_property_handle_t user_property); - -/** - * @brief Free the user property list - * - * @param user_property user_property handle - * - * This API will free the memory in user property list and free user_property itself - */ -void esp_mqtt5_client_delete_user_property(mqtt5_user_property_handle_t user_property); -#ifdef __cplusplus -} -#endif //__cplusplus - -#endif diff --git a/include/mqtt_client.h b/include/mqtt_client.h deleted file mode 100644 index f103794..0000000 --- a/include/mqtt_client.h +++ /dev/null @@ -1,640 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ - -#ifndef _MQTT_CLIENT_H_ -#define _MQTT_CLIENT_H_ - -#include -#include -#include -#include "esp_err.h" -#include "esp_event.h" -#ifdef CONFIG_MQTT_PROTOCOL_5 -#include "mqtt5_client.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef ESP_EVENT_DECLARE_BASE -// Define event loop types if macros not available -typedef void *esp_event_loop_handle_t; -typedef void *esp_event_handler_t; -#endif - -typedef struct esp_mqtt_client *esp_mqtt_client_handle_t; - -/** - * @brief *MQTT* event types. - * - * User event handler receives context data in `esp_mqtt_event_t` structure with - * - client - *MQTT* client handle - * - various other data depending on event type - * - */ -typedef enum esp_mqtt_event_id_t { - MQTT_EVENT_ANY = -1, - MQTT_EVENT_ERROR = - 0, /*!< on error event, additional context: connection return code, error - handle from esp_tls (if supported) */ - MQTT_EVENT_CONNECTED, /*!< connected event, additional context: - session_present flag */ - MQTT_EVENT_DISCONNECTED, /*!< disconnected event */ - MQTT_EVENT_SUBSCRIBED, /*!< subscribed event, additional context: - - msg_id message id - - error_handle `error_type` in case subscribing failed - - data pointer to broker response, check for errors. - - data_len length of the data for this - event - */ - MQTT_EVENT_UNSUBSCRIBED, /*!< unsubscribed event, additional context: msg_id */ - MQTT_EVENT_PUBLISHED, /*!< published event, additional context: msg_id */ - MQTT_EVENT_DATA, /*!< data event, additional context: - - msg_id message id - - topic pointer to the received topic - - topic_len length of the topic - - data pointer to the received data - - data_len length of the data for this event - - current_data_offset offset of the current data for - this event - - total_data_len total length of the data received - - retain retain flag of the message - - qos QoS level of the message - - dup dup flag of the message - Note: Multiple MQTT_EVENT_DATA could be fired for one - message, if it is longer than internal buffer. In that - case only first event contains topic pointer and length, - other contain data only with current data length and - current data offset updating. - */ - MQTT_EVENT_BEFORE_CONNECT, /*!< The event occurs before connecting */ - MQTT_EVENT_DELETED, /*!< Notification on delete of one message from the - internal outbox, if the message couldn't have been sent - and acknowledged before expiring defined in - OUTBOX_EXPIRED_TIMEOUT_MS. (events are not posted upon - deletion of successfully acknowledged messages) - - This event id is posted only if - MQTT_REPORT_DELETED_MESSAGES==1 - - Additional context: msg_id (id of the deleted - message). - */ - MQTT_USER_EVENT, /*!< Custom event used to queue tasks into mqtt event handler - All fields from the esp_mqtt_event_t type could be used to pass - an additional context data to the handler. - */ -} esp_mqtt_event_id_t; - -/** - * *MQTT* connection error codes propagated via ERROR event - */ -typedef enum esp_mqtt_connect_return_code_t { - MQTT_CONNECTION_ACCEPTED = 0, /*!< Connection accepted */ - MQTT_CONNECTION_REFUSE_PROTOCOL, /*!< *MQTT* connection refused reason: Wrong - protocol */ - MQTT_CONNECTION_REFUSE_ID_REJECTED, /*!< *MQTT* connection refused reason: ID - rejected */ - MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE, /*!< *MQTT* connection refused - reason: Server unavailable */ - MQTT_CONNECTION_REFUSE_BAD_USERNAME, /*!< *MQTT* connection refused reason: - Wrong user */ - MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED /*!< *MQTT* connection refused reason: - Wrong username or password */ -} esp_mqtt_connect_return_code_t; - -/** - * *MQTT* connection error codes propagated via ERROR event - */ -typedef enum esp_mqtt_error_type_t { - MQTT_ERROR_TYPE_NONE = 0, - MQTT_ERROR_TYPE_TCP_TRANSPORT, - MQTT_ERROR_TYPE_CONNECTION_REFUSED, - MQTT_ERROR_TYPE_SUBSCRIBE_FAILED -} esp_mqtt_error_type_t; - -/** - * MQTT_ERROR_TYPE_TCP_TRANSPORT error type hold all sorts of transport layer - * errors, including ESP-TLS error, but in the past only the errors from - * MQTT_ERROR_TYPE_ESP_TLS layer were reported, so the ESP-TLS error type is - * re-defined here for backward compatibility - */ -#define MQTT_ERROR_TYPE_ESP_TLS MQTT_ERROR_TYPE_TCP_TRANSPORT - -typedef enum esp_mqtt_transport_t { - MQTT_TRANSPORT_UNKNOWN = 0x0, - MQTT_TRANSPORT_OVER_TCP, /*!< *MQTT* over TCP, using scheme: ``MQTT`` */ - MQTT_TRANSPORT_OVER_SSL, /*!< *MQTT* over SSL, using scheme: ``MQTTS`` */ - MQTT_TRANSPORT_OVER_WS, /*!< *MQTT* over Websocket, using scheme:: ``ws`` */ - MQTT_TRANSPORT_OVER_WSS /*!< *MQTT* over Websocket Secure, using scheme: - ``wss`` */ -} esp_mqtt_transport_t; - -/** - * *MQTT* protocol version used for connection - */ -typedef enum esp_mqtt_protocol_ver_t { - MQTT_PROTOCOL_UNDEFINED = 0, - MQTT_PROTOCOL_V_3_1, - MQTT_PROTOCOL_V_3_1_1, - MQTT_PROTOCOL_V_5, -} esp_mqtt_protocol_ver_t; - -/** - * @brief *MQTT* error code structure to be passed as a contextual information - * into ERROR event - * - * Important: This structure extends `esp_tls_last_error` error structure and is - * backward compatible with it (so might be down-casted and treated as - * `esp_tls_last_error` error, but recommended to update applications if used - * this way previously) - * - * Use this structure directly checking error_type first and then appropriate - * error code depending on the source of the error: - * - * | error_type | related member variables | note | - * | MQTT_ERROR_TYPE_TCP_TRANSPORT | esp_tls_last_esp_err, esp_tls_stack_err, - * esp_tls_cert_verify_flags, sock_errno | Error reported from - * tcp_transport/esp-tls | | MQTT_ERROR_TYPE_CONNECTION_REFUSED | - * connect_return_code | Internal error reported from *MQTT* broker on - * connection | - */ -typedef struct esp_mqtt_error_codes { - /* compatible portion of the struct corresponding to struct esp_tls_last_error - */ - esp_err_t esp_tls_last_esp_err; /*!< last esp_err code reported from esp-tls - component */ - int esp_tls_stack_err; /*!< tls specific error code reported from underlying - tls stack */ - int esp_tls_cert_verify_flags; /*!< tls flags reported from underlying tls - stack during certificate verification */ - /* esp-mqtt specific structure extension */ - esp_mqtt_error_type_t - error_type; /*!< error type referring to the source of the error */ - esp_mqtt_connect_return_code_t - connect_return_code; /*!< connection refused error code reported from - *MQTT* broker on connection */ - /* tcp_transport extension */ - int esp_transport_sock_errno; /*!< errno from the underlying socket */ - -} esp_mqtt_error_codes_t; - -/** - * *MQTT* event configuration structure - */ -typedef struct esp_mqtt_event_t { - esp_mqtt_event_id_t event_id; /*!< *MQTT* event type */ - esp_mqtt_client_handle_t client; /*!< *MQTT* client handle for this event */ - char *data; /*!< Data associated with this event */ - int data_len; /*!< Length of the data for this event */ - int total_data_len; /*!< Total length of the data (longer data are supplied - with multiple events) */ - int current_data_offset; /*!< Actual offset for the data associated with this - event */ - char *topic; /*!< Topic associated with this event */ - int topic_len; /*!< Length of the topic for this event associated with this - event */ - int msg_id; /*!< *MQTT* messaged id of message */ - int session_present; /*!< *MQTT* session_present flag for connection event */ - esp_mqtt_error_codes_t - *error_handle; /*!< esp-mqtt error handle including esp-tls errors as well - as internal *MQTT* errors */ - bool retain; /*!< Retained flag of the message associated with this event */ - int qos; /*!< QoS of the messages associated with this event */ - bool dup; /*!< dup flag of the message associated with this event */ - esp_mqtt_protocol_ver_t protocol_ver; /*!< MQTT protocol version used for connection, defaults to value from menuconfig*/ -#ifdef CONFIG_MQTT_PROTOCOL_5 - esp_mqtt5_event_property_t *property; /*!< MQTT 5 property associated with this event */ -#endif - -} esp_mqtt_event_t; - -typedef esp_mqtt_event_t *esp_mqtt_event_handle_t; - -typedef esp_err_t (*mqtt_event_callback_t)(esp_mqtt_event_handle_t event); - -/** - * *MQTT* client configuration structure - * - * - Default values can be set via menuconfig - * - All certificates and key data could be passed in PEM or DER format. PEM format must have a terminating NULL - * character and the related len field set to 0. DER format requires a related len field set to the correct length. - */ -typedef struct esp_mqtt_client_config_t { - /** - * Broker related configuration - */ - struct broker_t { - /** - * Broker address - * - * - uri have precedence over other fields - * - If uri isn't set at least hostname, transport and port should. - */ - struct address_t { - const char *uri; /*!< Complete *MQTT* broker URI */ - const char *hostname; /*!< Hostname, to set ipv4 pass it as string) */ - esp_mqtt_transport_t transport; /*!< Selects transport*/ - const char *path; /*!< Path in the URI*/ - uint32_t port; /*!< *MQTT* server port */ - } address; /*!< Broker address configuration */ - /** - * Broker identity verification - * - * If fields are not set broker's identity isn't verified. it's recommended - * to set the options in this struct for security reasons. - */ - struct verification_t { - bool use_global_ca_store; /*!< Use a global ca_store, look esp-tls - documentation for details. */ - esp_err_t (*crt_bundle_attach)(void *conf); /*!< Pointer to ESP x509 Certificate Bundle attach function for - the usage of certificate bundles. */ - const char *certificate; /*!< Certificate data, default is NULL, not required to verify the server. */ - size_t certificate_len; /*!< Length of the buffer pointed to by certificate. */ - const struct psk_key_hint *psk_hint_key; /*!< Pointer to PSK struct defined in esp_tls.h to enable PSK - authentication (as alternative to certificate verification). - PSK is enabled only if there are no other ways to - verify broker.*/ - bool skip_cert_common_name_check; /*!< Skip any validation of server certificate CN field, this reduces the - security of TLS and makes the *MQTT* client susceptible to MITM attacks */ - const char **alpn_protos; /*!< NULL-terminated list of supported application protocols to be used for ALPN */ - } verification; /*!< Security verification of the broker */ - } broker; /*!< Broker address and security verification */ - /** - * Client related credentials for authentication. - */ - struct credentials_t { - const char *username; /*!< *MQTT* username */ - const char *client_id; /*!< Set *MQTT* client identifier. Ignored if set_null_client_id == true If NULL set - the default client id. Default client id is ``ESP32_%CHIPID%`` where `%CHIPID%` are - last 3 bytes of MAC address in hex format */ - bool set_null_client_id; /*!< Selects a NULL client id */ - /** - * Client authentication - * - * Fields related to client authentication by broker - * - * For mutual authentication using TLS, user could select certificate and key, - * secure element or digital signature peripheral if available. - * - */ - struct authentication_t { - const char *password; /*!< *MQTT* password */ - const char *certificate; /*!< Certificate for ssl mutual authentication, not required if mutual - authentication is not needed. Must be provided with `key`.*/ - size_t certificate_len; /*!< Length of the buffer pointed to by certificate.*/ - const char *key; /*!< Private key for SSL mutual authentication, not required if mutual authentication - is not needed. If it is not NULL, also `certificate` has to be provided.*/ - size_t key_len; /*!< Length of the buffer pointed to by key.*/ - const char *key_password; /*!< Client key decryption password, not PEM nor DER, if provided - `key_password_len` must be correctly set. */ - int key_password_len; /*!< Length of the password pointed to by `key_password` */ - bool use_secure_element; /*!< Enable secure element, available in ESP32-ROOM-32SE, for SSL connection */ - void *ds_data; /*!< Carrier of handle for digital signature parameters, digital signature peripheral is - available in some Espressif devices. */ - } authentication; /*!< Client authentication */ - } credentials; /*!< User credentials for broker */ - /** - * *MQTT* Session related configuration - */ - struct session_t { - /** - * Last Will and Testament message configuration. - */ - struct last_will_t { - const char *topic; /*!< LWT (Last Will and Testament) message topic */ - const char *msg; /*!< LWT message, may be NULL terminated*/ - int msg_len; /*!< LWT message length, if msg isn't NULL terminated must have the correct length */ - int qos; /*!< LWT message QoS */ - int retain; /*!< LWT retained message flag */ - } last_will; /*!< Last will configuration */ - bool disable_clean_session; /*!< *MQTT* clean session, default clean_session is true */ - int keepalive; /*!< *MQTT* keepalive, default is 120 seconds */ - bool disable_keepalive; /*!< Set `disable_keepalive=true` to turn off keep-alive mechanism, keepalive is active - by default. Note: setting the config value `keepalive` to `0` doesn't disable - keepalive feature, but uses a default keepalive period */ - esp_mqtt_protocol_ver_t protocol_ver; /*!< *MQTT* protocol version used for connection.*/ - int message_retransmit_timeout; /*!< timeout for retransmitting of failed packet */ - } session; /*!< *MQTT* session configuration. */ - /** - * Network related configuration - */ - struct network_t { - int reconnect_timeout_ms; /*!< Reconnect to the broker after this value in miliseconds if auto reconnect is not - disabled (defaults to 10s) */ - int timeout_ms; /*!< Abort network operation if it is not completed after this value, in milliseconds - (defaults to 10s). */ - int refresh_connection_after_ms; /*!< Refresh connection after this value (in milliseconds) */ - bool disable_auto_reconnect; /*!< Client will reconnect to server (when errors/disconnect). Set - `disable_auto_reconnect=true` to disable */ - } network; /*!< Network configuration */ - /** - * Client task configuration - */ - struct task_t { - int priority; /*!< *MQTT* task priority*/ - int stack_size; /*!< *MQTT* task stack size*/ - } task; /*!< FreeRTOS task configuration.*/ - /** - * Client buffer size configuration - * - * Client have two buffers for input and output respectivelly. - */ - struct buffer_t { - int size; /*!< size of *MQTT* send/receive buffer*/ - int out_size; /*!< size of *MQTT* output buffer. If not defined, defaults to the size defined by - ``buffer_size`` */ - } buffer; /*!< Buffer size configuration.*/ -} esp_mqtt_client_config_t; - -/** - * Topic definition struct - */ -typedef struct topic_t { - const char *filter; /*!< Topic filter to subscribe */ - int qos; /*!< Max QoS level of the subscription */ -} esp_mqtt_topic_t; - -/** - * @brief Creates *MQTT* client handle based on the configuration - * - * @param config *MQTT* configuration structure - * - * @return mqtt_client_handle if successfully created, NULL on error - */ -esp_mqtt_client_handle_t -esp_mqtt_client_init(const esp_mqtt_client_config_t *config); - -/** - * @brief Sets *MQTT* connection URI. This API is usually used to overrides the - * URI configured in esp_mqtt_client_init - * - * @param client *MQTT* client handle - * @param uri - * - * @return ESP_FAIL if URI parse error, ESP_OK on success - */ -esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, - const char *uri); - -/** - * @brief Starts *MQTT* client with already created client handle - * - * @param client *MQTT* client handle - * - * @return ESP_OK on success - * ESP_ERR_INVALID_ARG on wrong initialization - * ESP_FAIL on other error - */ -esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client); - -/** - * @brief This api is typically used to force reconnection upon a specific event - * - * @param client *MQTT* client handle - * - * @return ESP_OK on success - * ESP_ERR_INVALID_ARG on wrong initialization - * ESP_FAIL if client is in invalid state - */ -esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client); - -/** - * @brief This api is typically used to force disconnection from the broker - * - * @param client *MQTT* client handle - * - * @return ESP_OK on success - * ESP_ERR_INVALID_ARG on wrong initialization - */ -esp_err_t esp_mqtt_client_disconnect(esp_mqtt_client_handle_t client); - -/** - * @brief Stops *MQTT* client tasks - * - * * Notes: - * - Cannot be called from the *MQTT* event handler - * - * @param client *MQTT* client handle - * - * @return ESP_OK on success - * ESP_ERR_INVALID_ARG on wrong initialization - * ESP_FAIL if client is in invalid state - */ -esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client); - - -/** - * @brief Convenience macro to select subscribe function to use. - * - * Notes: - * - Usage of `esp_mqtt_client_subscribe_single` is the same as previous - * esp_mqtt_client_subscribe, refer to it for details. - * - * @param client_handle *MQTT* client handle - * @param topic_type Needs to be char* for single subscription or `esp_mqtt_topic_t` for multiple topics - * @param qos_or_size It's either a qos when subscribing to a single topic or the size of the subscription array when subscribing to multiple topics. - * - * @return message_id of the subscribe message on success - * -1 on failure - */ -#define esp_mqtt_client_subscribe(client_handle, topic_type, qos_or_size) _Generic((topic_type), \ - char *: esp_mqtt_client_subscribe_single, \ - esp_mqtt_topic_t*: esp_mqtt_client_subscribe_multiple \ - )(client_handle, topic_type, qos_or_size) - -/** - * @brief Subscribe the client to defined topic with defined qos - * - * Notes: - * - Client must be connected to send subscribe message - * - This API is could be executed from a user task or - * from a *MQTT* event callback i.e. internal *MQTT* task - * (API is protected by internal mutex, so it might block - * if a longer data receive operation is in progress. - * - `esp_mqtt_client_subscribe` could be used to call this function. - * - * @param client *MQTT* client handle - * @param topic topic filter to subscribe - * @param qos Max qos level of the subscription - * - * @return message_id of the subscribe message on success - * -1 on failure - */ -int esp_mqtt_client_subscribe_single(esp_mqtt_client_handle_t client, - const char *topic, int qos); -/** - * @brief Subscribe the client to a list of defined topics with defined qos - * - * Notes: - * - Client must be connected to send subscribe message - * - This API is could be executed from a user task or - * from a *MQTT* event callback i.e. internal *MQTT* task - * (API is protected by internal mutex, so it might block - * if a longer data receive operation is in progress. - * - `esp_mqtt_client_subscribe` could be used to call this function. - * - * @param client *MQTT* client handle - * @param topic_list List of topics to subscribe - * @param size size of topic_list - * - * @return message_id of the subscribe message on success - * -1 on failure - */ -int esp_mqtt_client_subscribe_multiple(esp_mqtt_client_handle_t client, - const esp_mqtt_topic_t *topic_list, int size); - -/** - * @brief Unsubscribe the client from defined topic - * - * Notes: - * - Client must be connected to send unsubscribe message - * - It is thread safe, please refer to `esp_mqtt_client_subscribe_single` for details - * - * @param client *MQTT* client handle - * @param topic - * - * @return message_id of the subscribe message on success - * -1 on failure - */ -int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, - const char *topic); - -/** - * @brief Client to send a publish message to the broker - * - * Notes: - * - This API might block for several seconds, either due to network timeout - * (10s) or if publishing payloads longer than internal buffer (due to message - * fragmentation) - * - Client doesn't have to be connected for this API to work, enqueueing the - * messages with qos>1 (returning -1 for all the qos=0 messages if - * disconnected). If MQTT_SKIP_PUBLISH_IF_DISCONNECTED is enabled, this API will - * not attempt to publish when the client is not connected and will always - * return -1. - * - It is thread safe, please refer to `esp_mqtt_client_subscribe` for details - * - * @param client *MQTT* client handle - * @param topic topic string - * @param data payload string (set to NULL, sending empty payload message) - * @param len data length, if set to 0, length is calculated from payload - * string - * @param qos QoS of publish message - * @param retain retain flag - * - * @return message_id of the publish message (for QoS 0 message_id will always - * be zero) on success. -1 on failure. - */ -int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, - const char *data, int len, int qos, int retain); - -/** - * @brief Enqueue a message to the outbox, to be sent later. Typically used for - * messages with qos>0, but could be also used for qos=0 messages if store=true. - * - * This API generates and stores the publish message into the internal outbox - * and the actual sending to the network is performed in the mqtt-task context - * (in contrast to the esp_mqtt_client_publish() which sends the publish message - * immediately in the user task's context). Thus, it could be used as a non - * blocking version of esp_mqtt_client_publish(). - * - * @param client *MQTT* client handle - * @param topic topic string - * @param data payload string (set to NULL, sending empty payload message) - * @param len data length, if set to 0, length is calculated from payload - * string - * @param qos QoS of publish message - * @param retain retain flag - * @param store if true, all messages are enqueued; otherwise only QoS 1 and - * QoS 2 are enqueued - * - * @return message_id if queued successfully, -1 otherwise - */ -int esp_mqtt_client_enqueue(esp_mqtt_client_handle_t client, const char *topic, - const char *data, int len, int qos, int retain, - bool store); - -/** - * @brief Destroys the client handle - * - * Notes: - * - Cannot be called from the *MQTT* event handler - * - * @param client *MQTT* client handle - * - * @return ESP_OK - * ESP_ERR_INVALID_ARG on wrong initialization - */ -esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client); - -/** - * @brief Set configuration structure, typically used when updating the config - * (i.e. on "before_connect" event - * - * @param client *MQTT* client handle - * - * @param config *MQTT* configuration structure - * - * @return ESP_ERR_NO_MEM if failed to allocate - * ESP_ERR_INVALID_ARG if conflicts on transport configuration. - * ESP_OK on success - */ -esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, - const esp_mqtt_client_config_t *config); - -/** - * @brief Registers *MQTT* event - * - * @param client *MQTT* client handle - * @param event event type - * @param event_handler handler callback - * @param event_handler_arg handlers context - * - * @return ESP_ERR_NO_MEM if failed to allocate - * ESP_ERR_INVALID_ARG on wrong initialization - * ESP_OK on success - */ -esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client, - esp_mqtt_event_id_t event, - esp_event_handler_t event_handler, - void *event_handler_arg); - -/** - * @brief Unregisters mqtt event - * - * @param client mqtt client handle - * @param event event ID - * @param event_handler handler to unregister - * - * @return ESP_ERR_NO_MEM if failed to allocate - * ESP_ERR_INVALID_ARG on invalid event ID - * ESP_OK on success - */ -esp_err_t esp_mqtt_client_unregister_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler); - -/** - * @brief Get outbox size - * - * @param client *MQTT* client handle - * @return outbox size - * 0 on wrong initialization - */ -int esp_mqtt_client_get_outbox_size(esp_mqtt_client_handle_t client); - -/** - * @brief Dispatch user event to the mqtt internal event loop - * - * @param client *MQTT* client handle - * @param event *MQTT* event handle structure - * @return ESP_OK on success - * ESP_ERR_TIMEOUT if the event couldn't be queued (ref also CONFIG_MQTT_EVENT_QUEUE_SIZE) - */ -esp_err_t esp_mqtt_dispatch_custom_event(esp_mqtt_client_handle_t client, esp_mqtt_event_t *event); - -#ifdef __cplusplus -} -#endif //__cplusplus - -#endif diff --git a/include/mqtt_supported_features.h b/include/mqtt_supported_features.h deleted file mode 100644 index 6e49182..0000000 --- a/include/mqtt_supported_features.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef _MQTT_SUPPORTED_FEATURES_H_ -#define _MQTT_SUPPORTED_FEATURES_H_ - -#if __has_include("esp_idf_version.h") -#include "esp_idf_version.h" -#endif - -/** - * @brief This header defines supported features of IDF which mqtt module - * could use depending on specific version of ESP-IDF. - * In case "esp_idf_version.h" were not found, all additional - * features would be disabled - */ - -#ifdef ESP_IDF_VERSION - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(3, 3, 0) -// Features supported from 3.3 -#define MQTT_SUPPORTED_FEATURE_EVENT_LOOP -#define MQTT_SUPPORTED_FEATURE_SKIP_CRT_CMN_NAME_CHECK -#endif - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) -// Features supported in 4.0 -#define MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL -#define MQTT_SUPPORTED_FEATURE_TRANSPORT_ERR_REPORTING -#endif - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0) -// Features supported in 4.1 -#define MQTT_SUPPORTED_FEATURE_PSK_AUTHENTICATION -#define MQTT_SUPPORTED_FEATURE_DER_CERTIFICATES -#define MQTT_SUPPORTED_FEATURE_ALPN -#define MQTT_SUPPORTED_FEATURE_CLIENT_KEY_PASSWORD -#endif - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) -// Features supported in 4.2 -#define MQTT_SUPPORTED_FEATURE_SECURE_ELEMENT -#endif - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) -// Features supported in 4.3 -#define MQTT_SUPPORTED_FEATURE_DIGITAL_SIGNATURE -#define MQTT_SUPPORTED_FEATURE_TRANSPORT_SOCK_ERRNO_REPORTING -#endif - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) -// Features supported in 4.4 -#define MQTT_SUPPORTED_FEATURE_CERTIFICATE_BUNDLE -#endif - -#endif /* ESP_IDF_VERSION */ -#endif // _MQTT_SUPPORTED_FEATURES_H_ diff --git a/index.html b/index.html new file mode 100644 index 0000000..5cb7194 --- /dev/null +++ b/index.html @@ -0,0 +1,721 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:./
Date:2023-05-26 09:43:15
Coverage: + low: ≥ 0% + medium: ≥ 75.0% + high: ≥ 90.0% +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:222107320.7%
Functions:124626.1%
Branches:10763216.9%
+
+
+ +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileLinesFunctionsBranches
+ lib/include/mqtt_msg.h + + 0.0 + 0.0%0 / 15-%0 / 00.0%0 / 18
+ mqtt_client.c + + 21.0 + 21.0%222 / 105826.1%12 / 4617.4%107 / 614
+
+
+ + + + diff --git a/lib/include/mqtt5_client_priv.h b/lib/include/mqtt5_client_priv.h deleted file mode 100644 index 2337e06..0000000 --- a/lib/include/mqtt5_client_priv.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _MQTT5_CLIENT_PRIV_H_ -#define _MQTT5_CLIENT_PRIV_H_ - -#include "mqtt5_client.h" -#include "mqtt_client_priv.h" -#include "mqtt5_msg.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct mqtt5_topic_alias { - char *topic; - uint16_t topic_len; - uint16_t topic_alias; - STAILQ_ENTRY(mqtt5_topic_alias) next; -} mqtt5_topic_alias_t; -STAILQ_HEAD(mqtt5_topic_alias_list_t, mqtt5_topic_alias); -typedef struct mqtt5_topic_alias_list_t *mqtt5_topic_alias_handle_t; -typedef struct mqtt5_topic_alias *mqtt5_topic_alias_item_t; - -typedef struct { - esp_mqtt5_connection_property_storage_t connect_property_info; - esp_mqtt5_connection_will_property_storage_t will_property_info; - esp_mqtt5_connection_server_resp_property_t server_resp_property_info; - esp_mqtt5_disconnect_property_config_t disconnect_property_info; - const esp_mqtt5_publish_property_config_t *publish_property_info; - const esp_mqtt5_subscribe_property_config_t *subscribe_property_info; - const esp_mqtt5_unsubscribe_property_config_t *unsubscribe_property_info; - mqtt5_topic_alias_handle_t peer_topic_alias; -} mqtt5_config_storage_t; - -void esp_mqtt5_increment_packet_counter(esp_mqtt5_client_handle_t client); -void esp_mqtt5_decrement_packet_counter(esp_mqtt5_client_handle_t client); -void esp_mqtt5_parse_pubcomp(esp_mqtt5_client_handle_t client); -void esp_mqtt5_parse_puback(esp_mqtt5_client_handle_t client); -void esp_mqtt5_parse_unsuback(esp_mqtt5_client_handle_t client); -void esp_mqtt5_parse_suback(esp_mqtt5_client_handle_t client); -esp_err_t esp_mqtt5_parse_connack(esp_mqtt5_client_handle_t client, int *connect_rsp_code); -void esp_mqtt5_client_destory(esp_mqtt5_client_handle_t client); -esp_err_t esp_mqtt5_client_publish_check(esp_mqtt5_client_handle_t client, int qos, int retain); -esp_err_t esp_mqtt5_client_subscribe_check(esp_mqtt5_client_handle_t client, int qos); -esp_err_t esp_mqtt5_create_default_config(esp_mqtt5_client_handle_t client); -esp_err_t esp_mqtt5_get_publish_data(esp_mqtt5_client_handle_t client, uint8_t *msg_buf, size_t msg_read_len, char **msg_topic, size_t *msg_topic_len, char **msg_data, size_t *msg_data_len); -#ifdef __cplusplus -} -#endif //__cplusplus - -#endif \ No newline at end of file diff --git a/lib/include/mqtt5_msg.h b/lib/include/mqtt5_msg.h deleted file mode 100644 index 6c2a036..0000000 --- a/lib/include/mqtt5_msg.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef MQTT5_MSG_H -#define MQTT5_MSG_H -#include -#include -#include "sys/queue.h" -#include "mqtt_config.h" -#include "mqtt_msg.h" -#include "mqtt_client.h" -#ifdef __cplusplus -extern "C" { -#endif - -enum mqtt_properties_type { - MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR = 0x01, - MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL = 0x02, - MQTT5_PROPERTY_CONTENT_TYPE = 0x03, - MQTT5_PROPERTY_RESPONSE_TOPIC = 0x08, - MQTT5_PROPERTY_CORRELATION_DATA = 0x09, - MQTT5_PROPERTY_SUBSCRIBE_IDENTIFIER = 0x0B, - MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL = 0x11, - MQTT5_PROPERTY_ASSIGNED_CLIENT_IDENTIFIER = 0x12, - MQTT5_PROPERTY_SERVER_KEEP_ALIVE = 0x13, - MQTT5_PROPERTY_AUTHENTICATION_METHOD = 0x15, - MQTT5_PROPERTY_AUTHENTICATION_DATA = 0x16, - MQTT5_PROPERTY_REQUEST_PROBLEM_INFO = 0x17, - MQTT5_PROPERTY_WILL_DELAY_INTERVAL = 0x18, - MQTT5_PROPERTY_REQUEST_RESP_INFO = 0x19, - MQTT5_PROPERTY_RESP_INFO = 0x1A, - MQTT5_PROPERTY_SERVER_REFERENCE = 0x1C, - MQTT5_PROPERTY_REASON_STRING = 0x1F, - MQTT5_PROPERTY_RECEIVE_MAXIMUM = 0x21, - MQTT5_PROPERTY_TOPIC_ALIAS_MAXIMIM = 0x22, - MQTT5_PROPERTY_TOPIC_ALIAS = 0x23, - MQTT5_PROPERTY_MAXIMUM_QOS = 0x24, - MQTT5_PROPERTY_RETAIN_AVAILABLE = 0x25, - MQTT5_PROPERTY_USER_PROPERTY = 0x26, - MQTT5_PROPERTY_MAXIMUM_PACKET_SIZE = 0x27, - MQTT5_PROPERTY_WILDCARD_SUBSCR_AVAILABLE = 0x28, - MQTT5_PROPERTY_SUBSCR_IDENTIFIER_AVAILABLE = 0x29, - MQTT5_PROPERTY_SHARED_SUBSCR_AVAILABLE = 0x2A, -}; - -typedef struct mqtt5_user_property { - char *key; - char *value; - STAILQ_ENTRY(mqtt5_user_property) next; -} mqtt5_user_property_t; -STAILQ_HEAD(mqtt5_user_property_list_t, mqtt5_user_property); -typedef struct mqtt5_user_property *mqtt5_user_property_item_t; - -typedef struct { - uint32_t maximum_packet_size; - uint16_t receive_maximum; - uint16_t topic_alias_maximum; - uint8_t max_qos; - bool retain_available; - bool wildcard_subscribe_available; - bool subscribe_identifiers_available; - bool shared_subscribe_available; - char *response_info; -} esp_mqtt5_connection_server_resp_property_t; - -typedef struct { - bool payload_format_indicator; - uint32_t message_expiry_interval; - uint16_t topic_alias; - char *response_topic; - int response_topic_len; - char *correlation_data; - uint16_t correlation_data_len; - char *content_type; - int content_type_len; - uint16_t subscribe_id; -} esp_mqtt5_publish_resp_property_t; - -typedef struct { - uint32_t session_expiry_interval; - uint32_t maximum_packet_size; - uint16_t receive_maximum; - uint16_t topic_alias_maximum; - bool request_resp_info; - bool request_problem_info; - mqtt5_user_property_handle_t user_property; -} esp_mqtt5_connection_property_storage_t; - -typedef struct { - uint32_t will_delay_interval; - uint32_t message_expiry_interval; - bool payload_format_indicator; - char *content_type; - char *response_topic; - char *correlation_data; - uint16_t correlation_data_len; - mqtt5_user_property_handle_t user_property; -} esp_mqtt5_connection_will_property_storage_t; - -#define mqtt5_get_type mqtt_get_type - -#define mqtt5_get_dup mqtt_get_dup - -#define mqtt5_set_dup mqtt_set_dup - -#define mqtt5_get_qos mqtt_get_qos - -#define mqtt5_get_retain mqtt_get_retain - -#define mqtt5_msg_init mqtt_msg_init - -#define mqtt5_get_total_length mqtt_get_total_length - -#define mqtt5_has_valid_msg_hdr mqtt_has_valid_msg_hdr - -#define mqtt5_msg_pingreq mqtt_msg_pingreq - -#define mqtt5_msg_pingresp mqtt_msg_pingresp - -#define mqtt5_get_unsuback_data mqtt5_get_suback_data - -#define mqtt5_get_pubcomp_data mqtt5_get_puback_data - -uint16_t mqtt5_get_id(uint8_t *buffer, size_t length); -char *mqtt5_get_publish_property_payload(uint8_t *buffer, size_t buffer_length, char **msg_topic, size_t *msg_topic_len, esp_mqtt5_publish_resp_property_t *resp_property, uint16_t *property_len, size_t *payload_len, mqtt5_user_property_handle_t *user_property); -char *mqtt5_get_suback_data(uint8_t *buffer, size_t *length, mqtt5_user_property_handle_t *user_property); -char *mqtt5_get_puback_data(uint8_t *buffer, size_t *length, mqtt5_user_property_handle_t *user_property); -mqtt_message_t *mqtt5_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info, esp_mqtt5_connection_property_storage_t *property, esp_mqtt5_connection_will_property_storage_t *will_property); -mqtt_message_t *mqtt5_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id, const esp_mqtt5_publish_property_config_t *property, const char *resp_info); -esp_err_t mqtt5_msg_parse_connack_property(uint8_t *buffer, size_t buffer_len, mqtt_connect_info_t *connection_info, esp_mqtt5_connection_property_storage_t *connection_property, esp_mqtt5_connection_server_resp_property_t *resp_property, int *reason_code, uint8_t *ack_flag, mqtt5_user_property_handle_t *user_property); -int mqtt5_msg_get_reason_code(uint8_t *buffer, size_t length); -mqtt_message_t *mqtt5_msg_subscribe(mqtt_connection_t *connection, const esp_mqtt_topic_t *topic, int size, uint16_t *message_id, const esp_mqtt5_subscribe_property_config_t *property); -mqtt_message_t *mqtt5_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id, const esp_mqtt5_unsubscribe_property_config_t *property); -mqtt_message_t *mqtt5_msg_disconnect(mqtt_connection_t *connection, esp_mqtt5_disconnect_property_config_t *disconnect_property_info); -mqtt_message_t *mqtt5_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id); -mqtt_message_t *mqtt5_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id); -mqtt_message_t *mqtt5_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id); -mqtt_message_t *mqtt5_msg_puback(mqtt_connection_t *connection, uint16_t message_id); - -#ifdef __cplusplus -} -#endif - -#endif /* MQTT5_MSG_H */ - diff --git a/lib/include/mqtt_client_priv.h b/lib/include/mqtt_client_priv.h deleted file mode 100644 index bf09ceb..0000000 --- a/lib/include/mqtt_client_priv.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _MQTT_CLIENT_PRIV_H_ -#define _MQTT_CLIENT_PRIV_H_ - -#include -#include -#include -#include "esp_err.h" -#include "platform.h" - -#include "esp_event.h" -#include "mqtt_client.h" -#include "mqtt_msg.h" -#ifdef MQTT_PROTOCOL_5 -#include "mqtt5_client_priv.h" -#endif -#include "esp_transport.h" -#include "esp_transport_tcp.h" -#include "esp_transport_ssl.h" -#include "esp_transport_ws.h" -#include "esp_log.h" -#include "mqtt_outbox.h" -#include "freertos/event_groups.h" -#include -#include - -#include "mqtt_supported_features.h" - -/* using uri parser */ -#include "http_parser.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef MQTT_DISABLE_API_LOCKS -# define MQTT_API_LOCK(c) -# define MQTT_API_UNLOCK(c) -#else -# define MQTT_API_LOCK(c) xSemaphoreTakeRecursive(c->api_lock, portMAX_DELAY) -# define MQTT_API_UNLOCK(c) xSemaphoreGiveRecursive(c->api_lock) -#endif /* MQTT_USE_API_LOCKS */ - -typedef struct mqtt_state { - uint8_t *in_buffer; - uint8_t *out_buffer; - int in_buffer_length; - int out_buffer_length; - size_t message_length; - size_t in_buffer_read_len; - mqtt_message_t *outbound_message; - mqtt_connection_t mqtt_connection; - uint16_t pending_msg_id; - int pending_msg_type; - int pending_publish_qos; -} mqtt_state_t; - -typedef struct { - mqtt_event_callback_t event_handle; - esp_event_loop_handle_t event_loop_handle; - int task_stack; - int task_prio; - char *uri; - char *host; - char *path; - char *scheme; - int port; - bool auto_reconnect; - int network_timeout_ms; - int refresh_connection_after_ms; - int reconnect_timeout_ms; - char **alpn_protos; - int num_alpn_protos; - char *clientkey_password; - int clientkey_password_len; - bool use_global_ca_store; - esp_err_t ((*crt_bundle_attach)(void *conf)); - const char *cacert_buf; - size_t cacert_bytes; - const char *clientcert_buf; - size_t clientcert_bytes; - const char *clientkey_buf; - size_t clientkey_bytes; - const struct psk_key_hint *psk_hint_key; - bool skip_cert_common_name_check; - bool use_secure_element; - void *ds_data; - int message_retransmit_timeout; -} mqtt_config_storage_t; - -typedef enum { - MQTT_STATE_INIT = 0, - MQTT_STATE_DISCONNECTED, - MQTT_STATE_CONNECTED, - MQTT_STATE_WAIT_RECONNECT, -} mqtt_client_state_t; - -struct esp_mqtt_client { - esp_transport_list_handle_t transport_list; - esp_transport_handle_t transport; - mqtt_config_storage_t *config; - mqtt_state_t mqtt_state; - mqtt_connect_info_t connect_info; - mqtt_client_state_t state; - uint64_t refresh_connection_tick; - int64_t keepalive_tick; - uint64_t reconnect_tick; -#ifdef MQTT_PROTOCOL_5 - mqtt5_config_storage_t *mqtt5_config; - uint16_t send_publish_packet_count; // This is for MQTT v5.0 flow control -#endif - int wait_timeout_ms; - int auto_reconnect; - esp_mqtt_event_t event; - bool run; - bool wait_for_ping_resp; - outbox_handle_t outbox; - EventGroupHandle_t status_bits; - SemaphoreHandle_t api_lock; - TaskHandle_t task_handle; -#if MQTT_EVENT_QUEUE_SIZE > 1 - atomic_int queued_events; -#endif -}; - -bool esp_mqtt_set_if_config(char const *const new_config, char **old_config); -void esp_mqtt_destroy_config(esp_mqtt_client_handle_t client); - -#ifdef __cplusplus -} -#endif //__cplusplus - -#endif diff --git a/lib/include/mqtt_config.h b/lib/include/mqtt_config.h deleted file mode 100644 index 409fb3c..0000000 --- a/lib/include/mqtt_config.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ -#ifndef _MQTT_CONFIG_H_ -#define _MQTT_CONFIG_H_ - -#include "sdkconfig.h" - -#ifdef CONFIG_MQTT_PROTOCOL_311 -#define MQTT_PROTOCOL_311 -#endif - -#ifdef CONFIG_MQTT_PROTOCOL_5 -#define MQTT_PROTOCOL_5 -#endif - -#define MQTT_RECON_DEFAULT_MS (10*1000) - -#ifdef CONFIG_MQTT_POLL_READ_TIMEOUT_MS -#define MQTT_POLL_READ_TIMEOUT_MS CONFIG_MQTT_POLL_READ_TIMEOUT_MS -#else -#define MQTT_POLL_READ_TIMEOUT_MS (1000) -#endif - -#define MQTT_MSG_ID_INCREMENTAL CONFIG_MQTT_MSG_ID_INCREMENTAL - -#define MQTT_SKIP_PUBLISH_IF_DISCONNECTED CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED - -#define MQTT_REPORT_DELETED_MESSAGES CONFIG_MQTT_REPORT_DELETED_MESSAGES - -#if CONFIG_MQTT_BUFFER_SIZE -#define MQTT_BUFFER_SIZE_BYTE CONFIG_MQTT_BUFFER_SIZE -#else -#define MQTT_BUFFER_SIZE_BYTE 1024 -#endif - -#if CONFIG_MQTT_TASK_PRIORITY -#define MQTT_TASK_PRIORITY CONFIG_MQTT_TASK_PRIORITY -#else -#define MQTT_TASK_PRIORITY 5 -#endif - -#if CONFIG_MQTT_TASK_STACK_SIZE -#define MQTT_TASK_STACK CONFIG_MQTT_TASK_STACK_SIZE -#else -#define MQTT_TASK_STACK (6*1024) -#endif - -#define MQTT_KEEPALIVE_TICK (120) -#define MQTT_NETWORK_TIMEOUT_MS (10000) - -#ifdef CONFIG_MQTT_TCP_DEFAULT_PORT -#define MQTT_TCP_DEFAULT_PORT CONFIG_MQTT_TCP_DEFAULT_PORT -#else -#define MQTT_TCP_DEFAULT_PORT 1883 -#endif - -#ifdef CONFIG_MQTT_SSL_DEFAULT_PORT -#define MQTT_SSL_DEFAULT_PORT CONFIG_MQTT_SSL_DEFAULT_PORT -#else -#define MQTT_SSL_DEFAULT_PORT 8883 -#endif - -#ifdef CONFIG_MQTT_WS_DEFAULT_PORT -#define MQTT_WS_DEFAULT_PORT CONFIG_MQTT_WS_DEFAULT_PORT -#else -#define MQTT_WS_DEFAULT_PORT 80 -#endif - -#ifdef CONFIG_MQTT_WSS_DEFAULT_PORT -#define MQTT_WSS_DEFAULT_PORT CONFIG_MQTT_WSS_DEFAULT_PORT -#else -#define MQTT_WSS_DEFAULT_PORT 443 -#endif - -#define MQTT_CORE_SELECTION_ENABLED CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED - -#ifdef CONFIG_MQTT_DISABLE_API_LOCKS -#define MQTT_DISABLE_API_LOCKS CONFIG_MQTT_DISABLE_API_LOCKS -#endif - -#ifdef CONFIG_MQTT_USE_CORE_0 -#define MQTT_TASK_CORE 0 -#else -#ifdef CONFIG_MQTT_USE_CORE_1 -#define MQTT_TASK_CORE 1 -#else -#define MQTT_TASK_CORE 0 -#endif -#endif - -#ifdef CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS -#define OUTBOX_EXPIRED_TIMEOUT_MS CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS -#else -#define OUTBOX_EXPIRED_TIMEOUT_MS (30*1000) -#endif - -#define MQTT_ENABLE_SSL CONFIG_MQTT_TRANSPORT_SSL -#define MQTT_ENABLE_WS CONFIG_MQTT_TRANSPORT_WEBSOCKET -#define MQTT_ENABLE_WSS CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE - -#ifdef CONFIG_MQTT_EVENT_QUEUE_SIZE -#define MQTT_EVENT_QUEUE_SIZE CONFIG_MQTT_EVENT_QUEUE_SIZE -#else -#define MQTT_EVENT_QUEUE_SIZE 1 -#endif - -#ifdef CONFIG_MQTT_OUTBOX_DATA_ON_EXTERNAL_MEMORY -#define MQTT_OUTBOX_MEMORY MALLOC_CAP_SPIRAM -#else -#define MQTT_OUTBOX_MEMORY MALLOC_CAP_DEFAULT -#endif - -#define OUTBOX_MAX_SIZE (4*1024) -#endif diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h deleted file mode 100644 index 60fcf8c..0000000 --- a/lib/include/mqtt_msg.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef MQTT_MSG_H -#define MQTT_MSG_H -#include -#include - -#include "mqtt_config.h" -#include "mqtt_client.h" -#ifdef __cplusplus -extern "C" { -#endif - -/* -* Copyright (c) 2014, Stephen Robinson -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 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. -* 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. -* -* 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. -* -*/ -/* 7 6 5 4 3 2 1 0 */ -/*| --- Message Type---- | DUP Flag | QoS Level | Retain | */ -/* Remaining Length */ - - -enum mqtt_message_type { - MQTT_MSG_TYPE_CONNECT = 1, - MQTT_MSG_TYPE_CONNACK = 2, - MQTT_MSG_TYPE_PUBLISH = 3, - MQTT_MSG_TYPE_PUBACK = 4, - MQTT_MSG_TYPE_PUBREC = 5, - MQTT_MSG_TYPE_PUBREL = 6, - MQTT_MSG_TYPE_PUBCOMP = 7, - MQTT_MSG_TYPE_SUBSCRIBE = 8, - MQTT_MSG_TYPE_SUBACK = 9, - MQTT_MSG_TYPE_UNSUBSCRIBE = 10, - MQTT_MSG_TYPE_UNSUBACK = 11, - MQTT_MSG_TYPE_PINGREQ = 12, - MQTT_MSG_TYPE_PINGRESP = 13, - MQTT_MSG_TYPE_DISCONNECT = 14 -}; - -typedef struct mqtt_message { - uint8_t *data; - size_t length; - size_t fragmented_msg_total_length; /*!< total len of fragmented messages (zero for all other messages) */ - size_t fragmented_msg_data_offset; /*!< data offset of fragmented messages (zero for all other messages) */ -} mqtt_message_t; - -typedef struct mqtt_connection { - mqtt_message_t message; -#if MQTT_MSG_ID_INCREMENTAL - uint16_t last_message_id; /*!< last used id if incremental message id configured */ -#endif - uint8_t *buffer; - size_t buffer_length; - -} mqtt_connection_t; - -typedef struct mqtt_connect_info { - char *client_id; - char *username; - char *password; - char *will_topic; - char *will_message; - int64_t keepalive; /*!< keepalive=0 -> keepalive is disabled */ - int will_length; - int will_qos; - int will_retain; - int clean_session; - esp_mqtt_protocol_ver_t protocol_ver; - -} mqtt_connect_info_t; - - -static inline int mqtt_get_type(const uint8_t *buffer) -{ - return (buffer[0] & 0xf0) >> 4; -} -static inline int mqtt_get_connect_session_present(const uint8_t *buffer) -{ - return buffer[2] & 0x01; -} -static inline int mqtt_get_connect_return_code(const uint8_t *buffer) -{ - return buffer[3]; -} -static inline int mqtt_get_dup(const uint8_t *buffer) -{ - return (buffer[0] & 0x08) >> 3; -} -static inline void mqtt_set_dup(uint8_t *buffer) -{ - buffer[0] |= 0x08; -} -static inline int mqtt_get_qos(const uint8_t *buffer) -{ - return (buffer[0] & 0x06) >> 1; -} -static inline int mqtt_get_retain(const uint8_t *buffer) -{ - return (buffer[0] & 0x01); -} - -void mqtt_msg_init(mqtt_connection_t *connection, uint8_t *buffer, size_t buffer_length); -bool mqtt_header_complete(uint8_t *buffer, size_t buffer_length); -size_t mqtt_get_total_length(const uint8_t *buffer, size_t length, int *fixed_size_len); -char *mqtt_get_publish_topic(uint8_t *buffer, size_t *length); -char *mqtt_get_publish_data(uint8_t *buffer, size_t *length); -char *mqtt_get_suback_data(uint8_t *buffer, size_t *length); -uint16_t mqtt_get_id(uint8_t *buffer, size_t length); -int mqtt_has_valid_msg_hdr(uint8_t *buffer, size_t length); - -mqtt_message_t *mqtt_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info); -mqtt_message_t *mqtt_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id); -mqtt_message_t *mqtt_msg_puback(mqtt_connection_t *connection, uint16_t message_id); -mqtt_message_t *mqtt_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id); -mqtt_message_t *mqtt_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id); -mqtt_message_t *mqtt_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id); -mqtt_message_t *mqtt_msg_subscribe(mqtt_connection_t *connection, const esp_mqtt_topic_t topic_list[], int size, uint16_t *message_id) __attribute__((nonnull)); -mqtt_message_t *mqtt_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id); -mqtt_message_t *mqtt_msg_pingreq(mqtt_connection_t *connection); -mqtt_message_t *mqtt_msg_pingresp(mqtt_connection_t *connection); -mqtt_message_t *mqtt_msg_disconnect(mqtt_connection_t *connection); - - -#ifdef __cplusplus -} -#endif - -#endif /* MQTT_MSG_H */ - diff --git a/lib/include/mqtt_outbox.h b/lib/include/mqtt_outbox.h deleted file mode 100644 index fbeb5a5..0000000 --- a/lib/include/mqtt_outbox.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ -#ifndef _MQTT_OUTOBX_H_ -#define _MQTT_OUTOBX_H_ -#include "platform.h" -#include "esp_err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct outbox_item; - -typedef struct outbox_list_t *outbox_handle_t; -typedef struct outbox_item *outbox_item_handle_t; -typedef struct outbox_message *outbox_message_handle_t; -typedef long long outbox_tick_t; - -typedef struct outbox_message { - uint8_t *data; - int len; - int msg_id; - int msg_qos; - int msg_type; - uint8_t *remaining_data; - int remaining_len; -} outbox_message_t; - -typedef enum pending_state { - QUEUED, - TRANSMITTED, - ACKNOWLEDGED, - CONFIRMED -} pending_state_t; - -outbox_handle_t outbox_init(void); -outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, outbox_tick_t tick); -outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, outbox_tick_t *tick); -outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id); -uint8_t *outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos); -esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type); -esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id); -esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type); -esp_err_t outbox_delete_item(outbox_handle_t outbox, outbox_item_handle_t item); -int outbox_delete_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout); -/** - * @brief Deletes single expired message returning it's message id - * - * @return msg id of the deleted message, -1 if no expired message in the outbox - */ -int outbox_delete_single_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout); - -esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id, pending_state_t pending); -pending_state_t outbox_item_get_pending(outbox_item_handle_t item); -esp_err_t outbox_set_tick(outbox_handle_t outbox, int msg_id, outbox_tick_t tick); -int outbox_get_size(outbox_handle_t outbox); -void outbox_destroy(outbox_handle_t outbox); -void outbox_delete_all_items(outbox_handle_t outbox); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/lib/include/platform.h b/lib/include/platform.h deleted file mode 100644 index b3358b9..0000000 --- a/lib/include/platform.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ -#ifndef _PLATFORM_H__ -#define _PLATFORM_H__ - -//Support ESP32 -#ifdef ESP_PLATFORM -#include "platform_esp32_idf.h" -#endif - -#endif diff --git a/lib/include/platform_esp32_idf.h b/lib/include/platform_esp32_idf.h deleted file mode 100644 index 4569041..0000000 --- a/lib/include/platform_esp32_idf.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ -#ifndef _ESP_PLATFORM_H__ -#define _ESP_PLATFORM_H__ - -#include "freertos/FreeRTOS.h" -#include "freertos/event_groups.h" - -#include -#include - -char *platform_create_id_string(void); -int platform_random(int max); -uint64_t platform_tick_get_ms(void); - -#define ESP_MEM_CHECK(TAG, a, action) if (!(a)) { \ - ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Memory exhausted"); \ - action; \ - } - -#define ESP_OK_CHECK(TAG, a, action) if ((a) != ESP_OK) { \ - ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Failed with non ESP_OK err code"); \ - action; \ - } - -#endif diff --git a/lib/mqtt5_msg.c b/lib/mqtt5_msg.c deleted file mode 100644 index 16a479b..0000000 --- a/lib/mqtt5_msg.c +++ /dev/null @@ -1,1043 +0,0 @@ -#include -#include "mqtt5_msg.h" -#include "mqtt_client.h" -#include "mqtt_config.h" -#include "platform.h" -#include "esp_log.h" - -#define MQTT5_MAX_FIXED_HEADER_SIZE 5 - -static const char *TAG = "mqtt5_msg"; - -#define APPEND_CHECK(a, ret) if(a == -1) { \ - ESP_LOGE(TAG,"%s(%d) fail",__FUNCTION__, __LINE__); \ - return (ret); \ - } -#define MQTT5_SHARED_SUB "$share/%s/%s" -#define MQTT5_CONVERT_ONE_BYTE_TO_FOUR(i, a, b, c, d) i = (a << 24); \ - i |= (b << 16); \ - i |= (c << 8); \ - i |= d; - -#define MQTT5_CONVERT_ONE_BYTE_TO_TWO(i, a, b) i = (a << 8); \ - i |= b; - -#define MQTT5_CONVERT_TWO_BYTE(i, a) i = (a >> 8) & 0xff; \ - i = a & 0xff; - -enum mqtt5_connect_flag { - MQTT5_CONNECT_FLAG_USERNAME = 1 << 7, - MQTT5_CONNECT_FLAG_PASSWORD = 1 << 6, - MQTT5_CONNECT_FLAG_WILL_RETAIN = 1 << 5, - MQTT5_CONNECT_FLAG_WILL = 1 << 2, - MQTT5_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 -}; - -static void generate_variable_len(size_t len, uint8_t *len_bytes, uint8_t *encoded_lens) -{ - uint8_t bytes = 0; - do { - uint8_t i = len % 128; - len /= 128; - if (len > 0) { - i |= 0x80; - } - encoded_lens[bytes ++] = i; - } while (len > 0); - *len_bytes = bytes; -} - -static size_t get_variable_len(uint8_t *buffer, size_t offset, size_t buffer_length, uint8_t *len_bytes) -{ - *len_bytes = 0; - size_t len = 0, i = 0; - for (i = offset; i < buffer_length; i ++) { - len += (buffer[i] & 0x7f) << (7 * (i - offset)); - if ((buffer[i] & 0x80) == 0) { - i ++; - break; - } - } - *len_bytes = i - offset; - return len; -} - -static int update_property_len_value(mqtt_connection_t *connection, size_t property_len, int property_offset) -{ - uint8_t encoded_lens[4] = {0}, len_bytes = 0; - size_t len = property_len, message_offset = property_offset + property_len; - generate_variable_len(len, &len_bytes, encoded_lens); - int offset = len_bytes - 1; - - connection->message.length += offset; - if (connection->message.length > connection->buffer_length) { - return -1; - } - - if (offset > 0) { - for (int i = 0; i < property_len; i ++) { - connection->buffer[message_offset + offset] = connection->buffer[message_offset]; - message_offset --; - } - } - - for (int i = 0; i < len_bytes; i ++) { - connection->buffer[property_offset ++] = encoded_lens[i]; - } - return offset; -} - -static int append_property(mqtt_connection_t *connection, uint8_t property_type, uint8_t len_occupy, const char *data, size_t data_len) -{ - if ((connection->message.length + len_occupy + (data ? data_len : 0) + (property_type ? 1 : 0)) > connection->buffer_length) { - return -1; - } - - size_t origin_message_len = connection->message.length; - if (property_type) { - connection->buffer[connection->message.length ++] = property_type; - } - - if (len_occupy == 0) { - uint8_t encoded_lens[4] = {0}, len_bytes = 0; - generate_variable_len(data_len, &len_bytes, encoded_lens); - for (int j = 0; j < len_bytes; j ++) { - connection->buffer[connection->message.length ++] = encoded_lens[j]; - } - } else { - for (int i = 1; i <= len_occupy; i ++) { - connection->buffer[connection->message.length ++] = (data_len >> (8 * (len_occupy - i))) & 0xff; - } - } - - if (data) { - memcpy(connection->buffer + connection->message.length, data, data_len); - connection->message.length += data_len; - } - - return connection->message.length - origin_message_len; -} - -static uint16_t append_message_id(mqtt_connection_t *connection, uint16_t message_id) -{ - // If message_id is zero then we should assign one, otherwise - // we'll use the one supplied by the caller - while (message_id == 0) { -#if MQTT_MSG_ID_INCREMENTAL - message_id = ++ connection->last_message_id; -#else - message_id = platform_random(65535); -#endif - } - - if (connection->message.length + 2 > connection->buffer_length) { - return 0; - } - - MQTT5_CONVERT_TWO_BYTE(connection->buffer[connection->message.length ++], message_id) - - return message_id; -} - -static int init_message(mqtt_connection_t *connection) -{ - connection->message.length = MQTT5_MAX_FIXED_HEADER_SIZE; - return MQTT5_MAX_FIXED_HEADER_SIZE; -} - -static mqtt_message_t *fail_message(mqtt_connection_t *connection) -{ - connection->message.data = connection->buffer; - connection->message.length = 0; - return &connection->message; -} - -static mqtt_message_t *fini_message(mqtt_connection_t *connection, int type, int dup, int qos, int retain) -{ - int message_length = connection->message.length - MQTT5_MAX_FIXED_HEADER_SIZE; - int total_length = message_length; - uint8_t encoded_lens[4] = {0}, len_bytes = 0; - // Check if we have fragmented message and update total_len - if (connection->message.fragmented_msg_total_length) { - total_length = connection->message.fragmented_msg_total_length - MQTT5_MAX_FIXED_HEADER_SIZE; - } - - // Encode MQTT message length - generate_variable_len(total_length, &len_bytes, encoded_lens); - - // Sanity check for MQTT header - if (len_bytes + 1 > MQTT5_MAX_FIXED_HEADER_SIZE) { - return fail_message(connection); - } - - // Save the header bytes - connection->message.length = message_length + len_bytes + 1; // msg len + encoded_size len + type (1 byte) - int offs = MQTT5_MAX_FIXED_HEADER_SIZE - 1 - len_bytes; - connection->message.data = connection->buffer + offs; - connection->message.fragmented_msg_data_offset -= offs; - // type byte - connection->buffer[offs ++] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); - // length bytes - for (int j = 0; j < len_bytes; j ++) { - connection->buffer[offs ++] = encoded_lens[j]; - } - - return &connection->message; -} - -static esp_err_t mqtt5_msg_set_user_property(mqtt5_user_property_handle_t *user_property, char *key, size_t key_len, char *value, size_t value_len) -{ - if (!*user_property) { - *user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); - ESP_MEM_CHECK(TAG, *user_property, return ESP_FAIL); - STAILQ_INIT(*user_property); - } - - mqtt5_user_property_item_t user_property_item = calloc(1, sizeof(mqtt5_user_property_t)); - ESP_MEM_CHECK(TAG, user_property_item, return ESP_FAIL;); - user_property_item->key = calloc(1, key_len + 1); - ESP_MEM_CHECK(TAG, user_property_item->key, { - free(user_property_item); - return ESP_FAIL; - }); - memcpy(user_property_item->key, key, key_len); - user_property_item->key[key_len] = '\0'; - - user_property_item->value = calloc(1, value_len + 1); - ESP_MEM_CHECK(TAG, user_property_item->value, { - free(user_property_item->key); - free(user_property_item); - return ESP_FAIL; - }); - memcpy(user_property_item->value, value, value_len); - user_property_item->value[value_len] = '\0'; - - STAILQ_INSERT_TAIL(*user_property, user_property_item, next); - return ESP_OK; -} - -static mqtt5_user_property_handle_t mqtt5_msg_get_user_property(uint8_t *buffer, size_t buffer_length) -{ - mqtt5_user_property_handle_t user_porperty = NULL; - uint8_t *property = buffer; - uint16_t property_offset = 0, len = 0; - while (property_offset < buffer_length) { - uint8_t property_id = property[property_offset ++]; - switch (property_id) { - case MQTT5_PROPERTY_REASON_STRING: //only print now - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_REASON_STRING %.*s", len, &property[property_offset]); - property_offset += len; - continue; - case MQTT5_PROPERTY_USER_PROPERTY: { - uint8_t *key = NULL, *value = NULL; - size_t key_len = 0, value_len = 0; - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - key = &property[property_offset]; - key_len = len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY key: %.*s", key_len, (char *)key); - property_offset += len; - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - value = &property[property_offset]; - value_len = len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY value: %.*s", value_len, (char *)value); - property_offset += len; - if (mqtt5_msg_set_user_property(&user_porperty, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { - ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); - goto err; - } - continue; - } - default: - ESP_LOGW(TAG, "Unknow property id 0x%02x", property_id); - goto err; - } - } - return user_porperty; -err: - esp_mqtt5_client_delete_user_property(user_porperty); - return NULL; -} - -uint16_t mqtt5_get_id(uint8_t *buffer, size_t length) -{ - int topiclen = 0; - uint8_t len_bytes = 0; - size_t offset = 1; - size_t totlen = get_variable_len(buffer, offset, length, &len_bytes); - offset += len_bytes; - totlen += offset; - - if (offset + 2 > length) { - return 0; - } - - switch (mqtt5_get_type(buffer)) { - case MQTT_MSG_TYPE_PUBLISH: { - MQTT5_CONVERT_ONE_BYTE_TO_TWO(topiclen, buffer[offset++], buffer[offset++]) - offset += topiclen; - if (offset + 2 > length) { - return 0; - } - if (mqtt_get_qos(buffer) == 0) { - return 0; - } - return (buffer[offset] << 8) | buffer[offset + 1]; - } - case MQTT_MSG_TYPE_PUBACK: - case MQTT_MSG_TYPE_PUBREC: - case MQTT_MSG_TYPE_PUBREL: - case MQTT_MSG_TYPE_PUBCOMP: - case MQTT_MSG_TYPE_SUBACK: - case MQTT_MSG_TYPE_UNSUBACK: - case MQTT_MSG_TYPE_SUBSCRIBE: - case MQTT_MSG_TYPE_UNSUBSCRIBE: { - return (buffer[offset] << 8) | buffer[offset + 1]; - } - default: - return 0; - } -} - -char *mqtt5_get_publish_property_payload(uint8_t *buffer, size_t buffer_length, char **msg_topic, size_t *msg_topic_len, esp_mqtt5_publish_resp_property_t *resp_property, uint16_t *property_len, size_t *payload_len, mqtt5_user_property_handle_t *user_property) -{ - *user_property = NULL; - uint8_t len_bytes = 0; - size_t offset = 1; - size_t totlen = get_variable_len(buffer, offset, buffer_length, &len_bytes); - offset += len_bytes; - totlen += offset; - - size_t topic_len = buffer[offset ++] << 8; - topic_len |= buffer[offset ++] & 0xff; - *msg_topic = (char *)(buffer + offset); - *msg_topic_len = topic_len; - offset += topic_len; - - if (offset >= buffer_length) { - return NULL; - } - - if (mqtt5_get_qos(buffer) > 0) { - if (offset + 2 >= buffer_length) { - return NULL; - } - offset += 2; // skip the message id - } - - *property_len = get_variable_len(buffer, offset, buffer_length, &len_bytes); - offset += len_bytes; - - uint16_t len = 0, property_offset = 0; - uint8_t *property = (buffer + offset); - while (property_offset < *property_len) { - uint8_t property_id = property[property_offset ++]; - switch (property_id) { - case MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR: - resp_property->payload_format_indicator = property[property_offset ++]; - ESP_LOGD(TAG, "MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR %d", resp_property->payload_format_indicator); - continue; - case MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL: - MQTT5_CONVERT_ONE_BYTE_TO_FOUR(resp_property->message_expiry_interval, property[property_offset ++], property[property_offset ++], property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL %d", resp_property->message_expiry_interval); - continue; - case MQTT5_PROPERTY_TOPIC_ALIAS: - MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->topic_alias, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_TOPIC_ALIAS %d", resp_property->topic_alias); - continue; - case MQTT5_PROPERTY_RESPONSE_TOPIC: - MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->response_topic_len, property[property_offset ++], property[property_offset ++]) - resp_property->response_topic = (char *)(property + property_offset); - property_offset += resp_property->response_topic_len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_RESPONSE_TOPIC %.*s", resp_property->response_topic_len, resp_property->response_topic); - continue; - case MQTT5_PROPERTY_CORRELATION_DATA: - MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->correlation_data_len, property[property_offset ++], property[property_offset ++]) - resp_property->correlation_data = (char *)(property + property_offset); - property_offset += resp_property->correlation_data_len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_CORRELATION_DATA length %d", resp_property->correlation_data_len); - continue; - case MQTT5_PROPERTY_SUBSCRIBE_IDENTIFIER: - resp_property->subscribe_id = get_variable_len(property, property_offset, buffer_length, &len_bytes); - property_offset += len_bytes; - ESP_LOGD(TAG, "MQTT5_PROPERTY_SUBSCRIBE_IDENTIFIER %d", resp_property->subscribe_id); - continue; - case MQTT5_PROPERTY_CONTENT_TYPE: - MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->content_type_len, property[property_offset ++], property[property_offset ++]) - resp_property->content_type = (char *)(property + property_offset); - property_offset += resp_property->content_type_len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_CONTENT_TYPE %.*s", resp_property->content_type_len, resp_property->content_type); - continue; - case MQTT5_PROPERTY_USER_PROPERTY: { - uint8_t *key = NULL, *value = NULL; - size_t key_len = 0, value_len = 0; - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - key = &property[property_offset]; - key_len = len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY key: %.*s", key_len, (char *)key); - property_offset += len; - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - value = &property[property_offset]; - value_len = len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY value: %.*s", value_len, (char *)value); - property_offset += len; - if (mqtt5_msg_set_user_property(user_property, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { - esp_mqtt5_client_delete_user_property(*user_property); - *user_property = NULL; - ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); - return NULL; - } - continue; - } - case MQTT5_PROPERTY_REASON_STRING: //only print now - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_REASON_STRING %.*s", len, &property[property_offset]); - property_offset += len; - continue; - default: - ESP_LOGW(TAG, "Unknow publish property id 0x%02x", property_id); - return NULL; - } - } - - offset += property_offset; - if (totlen <= buffer_length) { - *payload_len = totlen - offset; - } else { - *payload_len = buffer_length - offset; - } - return (char *)(buffer + offset); -} - -char *mqtt5_get_suback_data(uint8_t *buffer, size_t *length, mqtt5_user_property_handle_t *user_property) -{ - uint8_t len_bytes = 0; - size_t offset = 1; - size_t totlen = get_variable_len(buffer, offset, *length, &len_bytes); - offset += len_bytes; - totlen += offset; - - if (totlen > *length) { - goto err; - } - offset += 2; // skip the message id - if (offset < totlen) { - size_t property_len = get_variable_len(buffer, offset, totlen, &len_bytes); - offset += len_bytes; - *user_property = mqtt5_msg_get_user_property(buffer + offset, property_len); - offset += property_len; - if (offset < totlen) { - *length = totlen - offset; - return (char *)(buffer + offset); - } - } -err: - *user_property = NULL; - *length = 0; - return NULL; -} - -char *mqtt5_get_puback_data(uint8_t *buffer, size_t *length, mqtt5_user_property_handle_t *user_property) -{ - uint8_t len_bytes = 0; - size_t offset = 1; - size_t totlen = get_variable_len(buffer, offset, *length, &len_bytes); - offset += len_bytes; - totlen += offset; - - offset += 2; // skip the message id - if (offset < totlen) { - *length = 1; - char *data = (char *)(buffer + offset); - offset ++; - if (offset < totlen) { - size_t property_len = get_variable_len(buffer, offset, totlen, &len_bytes); - offset += len_bytes; - *user_property = mqtt5_msg_get_user_property(buffer + offset, property_len); - } - return data; - } else { - *length = 0; - return NULL; - } -} - -mqtt_message_t *mqtt5_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info, esp_mqtt5_connection_property_storage_t *property, esp_mqtt5_connection_will_property_storage_t *will_property) -{ - init_message(connection); - connection->buffer[connection->message.length ++] = 0; // Variable header length MSB - /* Defaults to protocol version 5 values */ - connection->buffer[connection->message.length ++] = 4; // Variable header length LSB - memcpy(&connection->buffer[connection->message.length], "MQTT", 4); // Protocol name - connection->message.length += 4; - connection->buffer[connection->message.length ++] = 5; // Protocol version - - int flags_offset = connection->message.length; - connection->buffer[connection->message.length ++] = 0; // Flags - MQTT5_CONVERT_TWO_BYTE(connection->buffer[connection->message.length ++], info->keepalive) // Keep-alive - - if (info->clean_session) { - connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_CLEAN_SESSION; - } - - //Add properties - int properties_offset = connection->message.length; - connection->message.length ++; - if (property->session_expiry_interval) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL, 4, NULL, property->session_expiry_interval), fail_message(connection)); - } - if (property->maximum_packet_size) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_MAXIMUM_PACKET_SIZE, 4, NULL, property->maximum_packet_size), fail_message(connection)); - } - if (property->receive_maximum) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_RECEIVE_MAXIMUM, 2, NULL, property->receive_maximum), fail_message(connection)); - } - if (property->topic_alias_maximum) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_TOPIC_ALIAS_MAXIMIM, 2, NULL, property->topic_alias_maximum), fail_message(connection)); - } - if (property->request_resp_info) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_REQUEST_RESP_INFO, 1, NULL, 1), fail_message(connection)); - } - if (property->request_problem_info) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_REQUEST_PROBLEM_INFO, 1, NULL, 1), fail_message(connection)); - } - if (property->user_property) { - mqtt5_user_property_item_t item; - STAILQ_FOREACH(item, property->user_property, next) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); - APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); - } - } - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - - if (info->client_id != NULL && info->client_id[0] != '\0') { - APPEND_CHECK(append_property(connection, 0, 2, info->client_id, strlen(info->client_id)), fail_message(connection)); - } else { - APPEND_CHECK(append_property(connection, 0, 2, NULL, 0), fail_message(connection)); - } - - //Add will properties - if (info->will_topic != NULL && info->will_topic[0] != '\0') { - properties_offset = connection->message.length; - connection->message.length ++; - if (will_property->will_delay_interval) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_WILL_DELAY_INTERVAL, 4, NULL, will_property->will_delay_interval), fail_message(connection)); - } - if (will_property->payload_format_indicator) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR, 1, NULL, 1), fail_message(connection)); - } - if (will_property->message_expiry_interval) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL, 4, NULL, will_property->message_expiry_interval), fail_message(connection)); - } - if (will_property->content_type) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_CONTENT_TYPE, 2, will_property->content_type, strlen(will_property->content_type)), fail_message(connection)); - } - if (will_property->response_topic) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_RESPONSE_TOPIC, 2, will_property->response_topic, strlen(will_property->response_topic)), fail_message(connection)); - } - if (will_property->correlation_data && will_property->correlation_data_len) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_CORRELATION_DATA, 2, will_property->correlation_data, will_property->correlation_data_len), fail_message(connection)); - } - if (will_property->user_property) { - mqtt5_user_property_item_t item; - STAILQ_FOREACH(item, will_property->user_property, next) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); - APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); - } - } - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - - APPEND_CHECK(append_property(connection, 0, 2, info->will_topic, strlen(info->will_topic)), fail_message(connection)); - APPEND_CHECK(append_property(connection, 0, 2, info->will_message, info->will_length), fail_message(connection)); - - connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_WILL; - if (info->will_retain) { - connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_WILL_RETAIN; - } - connection->buffer[flags_offset] |= (info->will_qos & 3) << 3; - } - - if (info->username != NULL && info->username[0] != '\0') { - APPEND_CHECK(append_property(connection, 0, 2, info->username, strlen(info->username)), fail_message(connection)); - connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_USERNAME; - } - - if (info->password != NULL && info->password[0] != '\0') { - if (info->username == NULL || info->username[0] == '\0') { - /* In case if password is set without username, we need to set a zero length username. - * (otherwise we violate: MQTT-3.1.2-22: If the User Name Flag is set to 0 then the Password Flag MUST be set to 0.) - */ - APPEND_CHECK(append_property(connection, 0, 2, NULL, 0), fail_message(connection)); - connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_USERNAME; - } - APPEND_CHECK(append_property(connection, 0, 2, info->password, strlen(info->password)), fail_message(connection)); - connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_PASSWORD; - } - - return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); -} - -esp_err_t mqtt5_msg_parse_connack_property(uint8_t *buffer, size_t buffer_len, mqtt_connect_info_t *connection_info, esp_mqtt5_connection_property_storage_t *connection_property, esp_mqtt5_connection_server_resp_property_t *resp_property, int *reason_code, uint8_t *ack_flag, mqtt5_user_property_handle_t *user_property) -{ - *reason_code = 0; - *user_property = NULL; - uint8_t len_bytes = 0; - size_t offset = 1; - size_t totlen = get_variable_len(buffer, offset, buffer_len, &len_bytes); - offset += len_bytes; - totlen += offset; - - if (totlen > buffer_len) { - ESP_LOGE(TAG, "Total length %d is over read len %d", totlen, buffer_len); - return ESP_FAIL; - } - - *ack_flag = buffer[offset ++]; //acknowledge flags - *reason_code = buffer[offset ++]; //reason code - size_t property_len = get_variable_len(buffer, offset, buffer_len, &len_bytes); - offset += len_bytes; - uint16_t property_offset = 0, len = 0; - uint8_t *property = (buffer + offset); - while (property_offset < property_len) { - uint8_t property_id = property[property_offset ++]; - switch (property_id) { - case MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL: - MQTT5_CONVERT_ONE_BYTE_TO_FOUR(connection_property->session_expiry_interval, property[property_offset ++], property[property_offset ++], property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL %d", connection_property->session_expiry_interval); - continue; - case MQTT5_PROPERTY_RECEIVE_MAXIMUM: - MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->receive_maximum, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_RECEIVE_MAXIMUM %d", resp_property->receive_maximum); - continue; - case MQTT5_PROPERTY_MAXIMUM_QOS: - resp_property->max_qos = property[property_offset ++]; - ESP_LOGD(TAG, "MQTT5_PROPERTY_MAXIMUM_QOS %d", resp_property->max_qos); - continue; - case MQTT5_PROPERTY_RETAIN_AVAILABLE: - resp_property->retain_available = property[property_offset ++]; - ESP_LOGD(TAG, "MQTT5_PROPERTY_RETAIN_AVAILABLE %d", resp_property->retain_available); - continue; - case MQTT5_PROPERTY_MAXIMUM_PACKET_SIZE: - MQTT5_CONVERT_ONE_BYTE_TO_FOUR(resp_property->maximum_packet_size, property[property_offset ++], property[property_offset ++], property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_MAXIMUM_PACKET_SIZE %d", resp_property->maximum_packet_size); - continue; - case MQTT5_PROPERTY_ASSIGNED_CLIENT_IDENTIFIER: - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - if (connection_info->client_id) { - free(connection_info->client_id); - } - connection_info->client_id = calloc(1, len + 1); - if (!connection_info->client_id) { - ESP_LOGE(TAG, "Failed to calloc %d data", len); - return ESP_FAIL; - } - memcpy(connection_info->client_id, &property[property_offset], len); - connection_info->client_id[len] = '\0'; - property_offset += len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_ASSIGNED_CLIENT_IDENTIFIER %s", connection_info->client_id); - continue; - case MQTT5_PROPERTY_TOPIC_ALIAS_MAXIMIM: - MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->topic_alias_maximum, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_TOPIC_ALIAS_MAXIMIM %d", resp_property->topic_alias_maximum); - continue; - case MQTT5_PROPERTY_REASON_STRING: //only print now - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_REASON_STRING %.*s", len, &property[property_offset]); - property_offset += len; - continue; - case MQTT5_PROPERTY_USER_PROPERTY: { - uint8_t *key = NULL, *value = NULL; - size_t key_len = 0, value_len = 0; - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - key = &property[property_offset]; - key_len = len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY key: %.*s", key_len, (char *)key); - property_offset += len; - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - value = &property[property_offset]; - value_len = len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY value: %.*s", value_len, (char *)value); - property_offset += len; - if (mqtt5_msg_set_user_property(user_property, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { - esp_mqtt5_client_delete_user_property(*user_property); - *user_property = NULL; - ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); - return ESP_FAIL; - } - continue; - } - case MQTT5_PROPERTY_WILDCARD_SUBSCR_AVAILABLE: - resp_property->wildcard_subscribe_available = property[property_offset++]; - ESP_LOGD(TAG, "MQTT5_PROPERTY_WILDCARD_SUBSCR_AVAILABLE %d", resp_property->wildcard_subscribe_available); - continue; - case MQTT5_PROPERTY_SUBSCR_IDENTIFIER_AVAILABLE: - resp_property->subscribe_identifiers_available = property[property_offset++]; - ESP_LOGD(TAG, "MQTT5_PROPERTY_SUBSCR_IDENTIFIER_AVAILABLE %d", resp_property->subscribe_identifiers_available); - continue; - case MQTT5_PROPERTY_SHARED_SUBSCR_AVAILABLE: - resp_property->shared_subscribe_available = property[property_offset++]; - ESP_LOGD(TAG, "MQTT5_PROPERTY_SHARED_SUBSCR_AVAILABLE %d", resp_property->shared_subscribe_available); - continue; - case MQTT5_PROPERTY_SERVER_KEEP_ALIVE: - MQTT5_CONVERT_ONE_BYTE_TO_TWO(connection_info->keepalive, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_SERVER_KEEP_ALIVE %lld", connection_info->keepalive); - continue; - case MQTT5_PROPERTY_RESP_INFO: - if (resp_property->response_info) { - free(resp_property->response_info); - } - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - resp_property->response_info = calloc(1, len + 1); - if (!resp_property->response_info) { - ESP_LOGE(TAG, "Failed to calloc %d data", len); - return ESP_FAIL; - } - memcpy(resp_property->response_info, &property[property_offset], len); - resp_property->response_info[len] = '\0'; - property_offset += len; - ESP_LOGD(TAG, "MQTT5_PROPERTY_RESP_INFO %s", resp_property->response_info); - continue; - case MQTT5_PROPERTY_SERVER_REFERENCE: //only print now - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_SERVER_REFERENCE %.*s", len, &property[property_offset]); - property_offset += len; - continue; - case MQTT5_PROPERTY_AUTHENTICATION_METHOD: //only print now - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_AUTHENTICATION_METHOD %.*s", len, &property[property_offset]); - property_offset += len; - continue; - case MQTT5_PROPERTY_AUTHENTICATION_DATA: //only print now - MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) - ESP_LOGD(TAG, "MQTT5_PROPERTY_AUTHENTICATION_DATA length %d", len); - property_offset += len; - continue; - default: - ESP_LOGW(TAG, "Unknow connack property id 0x%02x", property_id); - return ESP_FAIL; - } - } - return ESP_OK; -} - -mqtt_message_t *mqtt5_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id, const esp_mqtt5_publish_property_config_t *property, const char *resp_info) -{ - init_message(connection); - - if (topic == NULL || topic[0] == '\0') { - return fail_message(connection); - } - - APPEND_CHECK(append_property(connection, 0, 2, topic, strlen(topic)), fail_message(connection)); - - if (data == NULL && data_length > 0) { - return fail_message(connection); - } - - if (qos > 0) { - if ((*message_id = append_message_id(connection, 0)) == 0) { - return fail_message(connection); - } - } else { - *message_id = 0; - } - - int properties_offset = connection->message.length; - connection->message.length ++; - - if (property) { - if (property->payload_format_indicator) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR, 1, NULL, 1), fail_message(connection)); - } - if (property->message_expiry_interval) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL, 4, NULL, property->message_expiry_interval), fail_message(connection)); - } - if (property->topic_alias) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_TOPIC_ALIAS, 2, NULL, property->topic_alias), fail_message(connection)); - } - if (property->response_topic) { - if (resp_info && strlen(resp_info)) { - uint16_t response_topic_size = strlen(property->response_topic) + strlen(resp_info) + 1; - char *response_topic = calloc(1, response_topic_size); - if (!response_topic) { - ESP_LOGE(TAG, "Failed to calloc %d memory", response_topic_size); - fail_message(connection); - } - snprintf(response_topic, response_topic_size, "%s/%s", property->response_topic, resp_info); - if (append_property(connection, MQTT5_PROPERTY_RESPONSE_TOPIC, 2, response_topic, response_topic_size) == -1) { - ESP_LOGE(TAG, "%s(%d) fail", __FUNCTION__, __LINE__); - free(response_topic); - return fail_message(connection); - } - free(response_topic); - } else { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_RESPONSE_TOPIC, 2, property->response_topic, strlen(property->response_topic)), fail_message(connection)); - } - } - if (property->correlation_data && property->correlation_data_len) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_CORRELATION_DATA, 2, property->correlation_data, property->correlation_data_len), fail_message(connection)); - } - if (property->user_property) { - mqtt5_user_property_item_t item; - STAILQ_FOREACH(item, property->user_property, next) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); - APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); - } - } - if (property->content_type) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_CONTENT_TYPE, 2, property->content_type, strlen(property->content_type)), fail_message(connection)); - } - } - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - - if (connection->message.length + data_length > connection->buffer_length) { - // Not enough size in buffer -> fragment this message - connection->message.fragmented_msg_data_offset = connection->message.length; - memcpy(connection->buffer + connection->message.length, data, connection->buffer_length - connection->message.length); - connection->message.length = connection->buffer_length; - connection->message.fragmented_msg_total_length = data_length + connection->message.fragmented_msg_data_offset; - } else { - if (data != NULL) { - memcpy(connection->buffer + connection->message.length, data, data_length); - connection->message.length += data_length; - } - connection->message.fragmented_msg_total_length = 0; - } - return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); -} - -int mqtt5_msg_get_reason_code(uint8_t *buffer, size_t length) -{ - uint8_t len_bytes = 0; - size_t offset = 1; - size_t totlen = get_variable_len(buffer, offset, length, &len_bytes); - offset += len_bytes; - totlen += offset; - - switch (mqtt5_get_type(buffer)) { - case MQTT_MSG_TYPE_PUBACK: - case MQTT_MSG_TYPE_PUBREC: - case MQTT_MSG_TYPE_PUBREL: - case MQTT_MSG_TYPE_PUBCOMP: - offset += 2; //skip the message id - if (offset >= length) { - return -1; - } - return buffer[offset]; - case MQTT_MSG_TYPE_SUBACK: - case MQTT_MSG_TYPE_UNSUBACK: { - offset += 2; //skip the message id - if (offset >= length) { - return -1; - } - size_t property_len = get_variable_len(buffer, offset, length, &len_bytes); - offset = offset + len_bytes + property_len; - if (offset >= length) { - return -1; - } else { - return buffer[offset]; - } - } - case MQTT_MSG_TYPE_DISCONNECT: - if (offset >= length) { - return -1; - } else { - return buffer[offset]; - } - default: - break; - } - return -1; -} - -mqtt_message_t *mqtt5_msg_subscribe(mqtt_connection_t *connection, const esp_mqtt_topic_t *topic_list, int size, uint16_t *message_id, const esp_mqtt5_subscribe_property_config_t *property) -{ - init_message(connection); - - if ((*message_id = append_message_id(connection, 0)) == 0) { - return fail_message(connection); - } - - int properties_offset = connection->message.length; - connection->message.length ++; - - if (property) { - if (property->subscribe_id) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_SUBSCRIBE_IDENTIFIER, 0, NULL, property->subscribe_id), fail_message(connection)); - } - if (property->user_property) { - mqtt5_user_property_item_t item; - STAILQ_FOREACH(item, property->user_property, next) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); - APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); - } - } - } - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - - for (int topic_number = 0; topic_number < size; ++topic_number) { - if (topic_list[topic_number].filter[0] == '\0') { - return fail_message(connection); - } - if (property && property->is_share_subscribe) { - uint16_t shared_topic_size = strlen(topic_list[topic_number].filter) + strlen(MQTT5_SHARED_SUB) + strlen(property->share_name); - char *shared_topic = calloc(1, shared_topic_size); - if (!shared_topic) { - ESP_LOGE(TAG, "Failed to calloc %d memory", shared_topic_size); - fail_message(connection); - } - snprintf(shared_topic, shared_topic_size, MQTT5_SHARED_SUB, property->share_name, topic_list[topic_number].filter); - if (append_property(connection, 0, 2, shared_topic, strlen(shared_topic)) == -1) { - ESP_LOGE(TAG, "%s(%d) fail", __FUNCTION__, __LINE__); - free(shared_topic); - return fail_message(connection); - } - free(shared_topic); - } else { - APPEND_CHECK(append_property(connection, 0, 2, topic_list[topic_number].filter, strlen(topic_list[topic_number].filter)), fail_message(connection)); - } - - if (connection->message.length + 1 > connection->buffer_length) { - return fail_message(connection); - } - connection->buffer[connection->message.length] = 0; - if (property) { - if (property->retain_handle > 0 && property->retain_handle < 3) { - connection->buffer[connection->message.length] |= (property->retain_handle & 3) << 4; - } - if (property->no_local_flag) { - connection->buffer[connection->message.length] |= (property->no_local_flag << 2); - } - if (property->retain_as_published_flag) { - connection->buffer[connection->message.length] |= (property->retain_as_published_flag << 3); - } - } - connection->buffer[connection->message.length] |= (topic_list[topic_number].qos & 3); - connection->message.length ++; - } - return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); -} - -mqtt_message_t *mqtt5_msg_disconnect(mqtt_connection_t *connection, esp_mqtt5_disconnect_property_config_t *disconnect_property_info) -{ - init_message(connection); - int reason_offset = connection->message.length; - connection->buffer[connection->message.length ++] = 0; - int properties_offset = connection->message.length; - connection->message.length ++; - if (disconnect_property_info) { - if (disconnect_property_info->session_expiry_interval) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL, 4, NULL, disconnect_property_info->session_expiry_interval), fail_message(connection)); - } - if (disconnect_property_info->user_property) { - mqtt5_user_property_item_t item; - STAILQ_FOREACH(item, disconnect_property_info->user_property, next) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); - APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); - } - } - if (disconnect_property_info->disconnect_reason) { - connection->buffer[reason_offset] = disconnect_property_info->disconnect_reason; - } - } - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); -} - -mqtt_message_t *mqtt5_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id, const esp_mqtt5_unsubscribe_property_config_t *property) -{ - init_message(connection); - - if (topic == NULL || topic[0] == '\0') { - return fail_message(connection); - } - - if ((*message_id = append_message_id(connection, 0)) == 0) { - return fail_message(connection); - } - - int properties_offset = connection->message.length; - connection->message.length ++; - if (property) { - if (property->user_property) { - mqtt5_user_property_item_t item; - STAILQ_FOREACH(item, property->user_property, next) { - APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); - APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); - } - } - } - - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - if (property && property->is_share_subscribe) { - uint16_t shared_topic_size = strlen(topic) + strlen(MQTT5_SHARED_SUB) + strlen(property->share_name); - char *shared_topic = calloc(1, shared_topic_size); - if (!shared_topic) { - ESP_LOGE(TAG, "Failed to calloc %d memory", shared_topic_size); - fail_message(connection); - } - snprintf(shared_topic, shared_topic_size, MQTT5_SHARED_SUB, property->share_name, topic); - if (append_property(connection, 0, 2, shared_topic, strlen(shared_topic)) == -1) { - ESP_LOGE(TAG, "%s(%d) fail", __FUNCTION__, __LINE__); - free(shared_topic); - return fail_message(connection); - } - free(shared_topic); - } else { - APPEND_CHECK(append_property(connection, 0, 2, topic, strlen(topic)), fail_message(connection)); - } - - return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); -} - -mqtt_message_t *mqtt5_msg_puback(mqtt_connection_t *connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) { - return fail_message(connection); - } - connection->buffer[connection->message.length ++] = 0; // Regard it is success - int properties_offset = connection->message.length; - connection->message.length ++; - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); -} - -mqtt_message_t *mqtt5_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) { - return fail_message(connection); - } - connection->buffer[connection->message.length ++] = 0; // Regard it is success - int properties_offset = connection->message.length; - connection->message.length ++; - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); -} - -mqtt_message_t *mqtt5_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) { - return fail_message(connection); - } - connection->buffer[connection->message.length ++] = 0; // Regard it is success - int properties_offset = connection->message.length; - connection->message.length ++; - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); -} - -mqtt_message_t *mqtt5_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) { - return fail_message(connection); - } - connection->buffer[connection->message.length ++] = 0; // Regard it is success - int properties_offset = connection->message.length; - connection->message.length ++; - APPEND_CHECK(update_property_len_value(connection, connection->message.length - properties_offset - 1, properties_offset), fail_message(connection)); - return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); -} diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c deleted file mode 100644 index 8b78ae3..0000000 --- a/lib/mqtt_msg.c +++ /dev/null @@ -1,624 +0,0 @@ -/* -* Copyright (c) 2014, Stephen Robinson -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 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. -* 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. -* -* 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. -* -*/ -#include -#include "mqtt_client.h" -#include "mqtt_msg.h" -#include "mqtt_config.h" -#include "platform.h" - -#define MQTT_MAX_FIXED_HEADER_SIZE 5 -#define MQTT_3_1_VARIABLE_HEADER_SIZE 12 -#define MQTT_3_1_1_VARIABLE_HEADER_SIZE 10 - -enum mqtt_connect_flag { - MQTT_CONNECT_FLAG_USERNAME = 1 << 7, - MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, - MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, - MQTT_CONNECT_FLAG_WILL = 1 << 2, - MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 -}; - -static int append_string(mqtt_connection_t *connection, const char *string, int len) -{ - if (connection->message.length + len + 2 > connection->buffer_length) { - return -1; - } - - connection->buffer[connection->message.length++] = len >> 8; - connection->buffer[connection->message.length++] = len & 0xff; - memcpy(connection->buffer + connection->message.length, string, len); - connection->message.length += len; - - return len + 2; -} - -static uint16_t append_message_id(mqtt_connection_t *connection, uint16_t message_id) -{ - // If message_id is zero then we should assign one, otherwise - // we'll use the one supplied by the caller - while (message_id == 0) { -#if MQTT_MSG_ID_INCREMENTAL - message_id = ++connection->last_message_id; -#else - message_id = platform_random(65535); -#endif - } - - if (connection->message.length + 2 > connection->buffer_length) { - return 0; - } - - connection->buffer[connection->message.length++] = message_id >> 8; - connection->buffer[connection->message.length++] = message_id & 0xff; - - return message_id; -} - -static int init_message(mqtt_connection_t *connection) -{ - connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE; - return MQTT_MAX_FIXED_HEADER_SIZE; -} - -static mqtt_message_t *fail_message(mqtt_connection_t *connection) -{ - connection->message.data = connection->buffer; - connection->message.length = 0; - return &connection->message; -} - -static mqtt_message_t *fini_message(mqtt_connection_t *connection, int type, int dup, int qos, int retain) -{ - int message_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; - int total_length = message_length; - int encoded_length = 0; - uint8_t encoded_lens[4] = {0}; - // Check if we have fragmented message and update total_len - if (connection->message.fragmented_msg_total_length) { - total_length = connection->message.fragmented_msg_total_length - MQTT_MAX_FIXED_HEADER_SIZE; - } - - // Encode MQTT message length - int len_bytes = 0; // size of encoded message length - do { - encoded_length = total_length % 128; - total_length /= 128; - if (total_length > 0) { - encoded_length |= 0x80; - } - encoded_lens[len_bytes] = encoded_length; - len_bytes++; - } while (total_length > 0); - - // Sanity check for MQTT header - if (len_bytes + 1 > MQTT_MAX_FIXED_HEADER_SIZE) { - return fail_message(connection); - } - - // Save the header bytes - connection->message.length = message_length + len_bytes + 1; // msg len + encoded_size len + type (1 byte) - int offs = MQTT_MAX_FIXED_HEADER_SIZE - 1 - len_bytes; - connection->message.data = connection->buffer + offs; - connection->message.fragmented_msg_data_offset -= offs; - // type byte - connection->buffer[offs++] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); - // length bytes - for (int j = 0; j < len_bytes; j++) { - connection->buffer[offs++] = encoded_lens[j]; - } - - return &connection->message; -} - -void mqtt_msg_init(mqtt_connection_t *connection, uint8_t *buffer, size_t buffer_length) -{ - memset(connection, 0, sizeof(mqtt_connection_t)); - connection->buffer = buffer; - connection->buffer_length = buffer_length; -} - -size_t mqtt_get_total_length(const uint8_t *buffer, size_t length, int *fixed_size_len) -{ - int i; - size_t totlen = 0; - - for (i = 1; i < length; ++i) { - totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) { - ++i; - break; - } - } - totlen += i; - if (fixed_size_len) { - *fixed_size_len = i; - } - - return totlen; -} - -bool mqtt_header_complete(uint8_t *buffer, size_t buffer_length) -{ - uint16_t i; - uint16_t topiclen; - - for (i = 1; i < MQTT_MAX_FIXED_HEADER_SIZE; ++i) { - if (i >= buffer_length) { - return false; - } - if ((buffer[i] & 0x80) == 0) { - ++i; - break; - } - } - // i is now the length of the fixed header - - if (i + 2 >= buffer_length) { - return false; - } - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; - - i += topiclen; - - if (mqtt_get_qos(buffer) > 0) { - i += 2; - } - // i is now the length of the fixed + variable header - return buffer_length >= i; -} - -char *mqtt_get_publish_topic(uint8_t *buffer, size_t *length) -{ - int i; - int topiclen; - - for (i = 1; i < *length; ++i) { - if ((buffer[i] & 0x80) == 0) { - ++i; - break; - } - } - - if (i + 2 >= *length) { - return NULL; - } - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; - - if (i + topiclen > *length) { - return NULL; - } - - *length = topiclen; - return (char *)(buffer + i); -} - -char *mqtt_get_publish_data(uint8_t *buffer, size_t *length) -{ - int i; - int totlen = 0; - int topiclen; - int blength = *length; - *length = 0; - - for (i = 1; i < blength; ++i) { - totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) { - ++i; - break; - } - } - totlen += i; - - if (i + 2 >= blength) { - return NULL; - } - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; - - if (i + topiclen >= blength) { - return NULL; - } - - i += topiclen; - - if (mqtt_get_qos(buffer) > 0) { - if (i + 2 >= blength) { - return NULL; - } - i += 2; - } - - if (totlen < i) { - return NULL; - } - - if (totlen <= blength) { - *length = totlen - i; - } else { - *length = blength - i; - } - return (char *)(buffer + i); -} - -char *mqtt_get_suback_data(uint8_t *buffer, size_t *length) -{ - // SUBACK payload length = total length - (fixed header (2 bytes) + variable header (2 bytes)) - // This requires the remaining length to be encoded in 1 byte. - if (*length > 4) { - *length -= 4; - return (char *)(buffer + 4); - } - *length = 0; - return NULL; -} - -uint16_t mqtt_get_id(uint8_t *buffer, size_t length) -{ - if (length < 1) { - return 0; - } - - switch (mqtt_get_type(buffer)) { - case MQTT_MSG_TYPE_PUBLISH: { - int i; - int topiclen; - - for (i = 1; i < length; ++i) { - if ((buffer[i] & 0x80) == 0) { - ++i; - break; - } - } - - if (i + 2 >= length) { - return 0; - } - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; - - if (i + topiclen > length) { - return 0; - } - i += topiclen; - - if (mqtt_get_qos(buffer) > 0) { - if (i + 2 > length) { - return 0; - } - //i += 2; - } else { - return 0; - } - - return (buffer[i] << 8) | buffer[i + 1]; - } - case MQTT_MSG_TYPE_PUBACK: - case MQTT_MSG_TYPE_PUBREC: - case MQTT_MSG_TYPE_PUBREL: - case MQTT_MSG_TYPE_PUBCOMP: - case MQTT_MSG_TYPE_SUBACK: - case MQTT_MSG_TYPE_UNSUBACK: - case MQTT_MSG_TYPE_SUBSCRIBE: - case MQTT_MSG_TYPE_UNSUBSCRIBE: { - // This requires the remaining length to be encoded in 1 byte, - // which it should be. - if (length >= 4 && (buffer[1] & 0x80) == 0) { - return (buffer[2] << 8) | buffer[3]; - } else { - return 0; - } - } - - default: - return 0; - } -} - -mqtt_message_t *mqtt_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info) -{ - - init_message(connection); - - int header_len; - if (info->protocol_ver == MQTT_PROTOCOL_V_3_1) { - header_len = MQTT_3_1_VARIABLE_HEADER_SIZE; - } else { - header_len = MQTT_3_1_1_VARIABLE_HEADER_SIZE; - } - - if (connection->message.length + header_len > connection->buffer_length) { - return fail_message(connection); - } - char *variable_header = (char *)(connection->buffer + connection->message.length); - connection->message.length += header_len; - - int header_idx = 0; - variable_header[header_idx++] = 0; // Variable header length MSB - - if (info->protocol_ver == MQTT_PROTOCOL_V_3_1) { - variable_header[header_idx++] = 6; // Variable header length LSB - memcpy(&variable_header[header_idx], "MQIsdp", 6); // Protocol name - header_idx = header_idx + 6; - variable_header[header_idx++] = 3; // Protocol version - } else { - /* Defaults to protocol version 3.1.1 values */ - variable_header[header_idx++] = 4; // Variable header length LSB - memcpy(&variable_header[header_idx], "MQTT", 4); // Protocol name - header_idx = header_idx + 4; - variable_header[header_idx++] = 4; // Protocol version - } - - int flags_offset = header_idx; - variable_header[header_idx++] = 0; // Flags - variable_header[header_idx++] = info->keepalive >> 8; // Keep-alive MSB - variable_header[header_idx] = info->keepalive & 0xff; // Keep-alive LSB - - if (info->clean_session) { - variable_header[flags_offset] |= MQTT_CONNECT_FLAG_CLEAN_SESSION; - } - - if (info->client_id != NULL && info->client_id[0] != '\0') { - if (append_string(connection, info->client_id, strlen(info->client_id)) < 0) { - return fail_message(connection); - } - } else { - if (append_string(connection, "", 0) < 0) { - return fail_message(connection); - } - } - - if (info->will_topic != NULL && info->will_topic[0] != '\0') { - if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) { - return fail_message(connection); - } - - if (append_string(connection, info->will_message, info->will_length) < 0) { - return fail_message(connection); - } - - variable_header[flags_offset] |= MQTT_CONNECT_FLAG_WILL; - if (info->will_retain) { - variable_header[flags_offset] |= MQTT_CONNECT_FLAG_WILL_RETAIN; - } - variable_header[flags_offset] |= (info->will_qos & 3) << 3; - } - - if (info->username != NULL && info->username[0] != '\0') { - if (append_string(connection, info->username, strlen(info->username)) < 0) { - return fail_message(connection); - } - - variable_header[flags_offset] |= MQTT_CONNECT_FLAG_USERNAME; - } - - if (info->password != NULL && info->password[0] != '\0') { - if (info->username == NULL || info->username[0] == '\0') { - /* In case if password is set without username, we need to set a zero length username. - * (otherwise we violate: MQTT-3.1.2-22: If the User Name Flag is set to 0 then the Password Flag MUST be set to 0.) - */ - if (append_string(connection, "", 0) < 0) { - return fail_message(connection); - } - - variable_header[flags_offset] |= MQTT_CONNECT_FLAG_USERNAME; - } - - if (append_string(connection, info->password, strlen(info->password)) < 0) { - return fail_message(connection); - } - - variable_header[flags_offset] |= MQTT_CONNECT_FLAG_PASSWORD; - } - - return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); -} - -mqtt_message_t *mqtt_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id) -{ - init_message(connection); - - if (topic == NULL || topic[0] == '\0') { - return fail_message(connection); - } - - if (append_string(connection, topic, strlen(topic)) < 0) { - return fail_message(connection); - } - - if (data == NULL && data_length > 0) { - return fail_message(connection); - } - - if (qos > 0) { - if ((*message_id = append_message_id(connection, 0)) == 0) { - return fail_message(connection); - } - } else { - *message_id = 0; - } - - if (data != NULL) { - if (connection->message.length + data_length > connection->buffer_length) { - // Not enough size in buffer -> fragment this message - connection->message.fragmented_msg_data_offset = connection->message.length; - memcpy(connection->buffer + connection->message.length, data, connection->buffer_length - connection->message.length); - connection->message.length = connection->buffer_length; - connection->message.fragmented_msg_total_length = data_length + connection->message.fragmented_msg_data_offset; - } else { - memcpy(connection->buffer + connection->message.length, data, data_length); - connection->message.length += data_length; - connection->message.fragmented_msg_total_length = 0; - } - } - return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); -} - -mqtt_message_t *mqtt_msg_puback(mqtt_connection_t *connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) { - return fail_message(connection); - } - return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); -} - -mqtt_message_t *mqtt_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) { - return fail_message(connection); - } - return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); -} - -mqtt_message_t *mqtt_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) { - return fail_message(connection); - } - return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); -} - -mqtt_message_t *mqtt_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) { - return fail_message(connection); - } - return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); -} - -mqtt_message_t *mqtt_msg_subscribe(mqtt_connection_t *connection, const esp_mqtt_topic_t topic_list[], int size, uint16_t *message_id) -{ - init_message(connection); - - if ((*message_id = append_message_id(connection, 0)) == 0) { - return fail_message(connection); - } - - for (int topic_number = 0; topic_number < size; ++topic_number) { - if (topic_list[topic_number].filter[0] == '\0') { - return fail_message(connection); - } - - if (append_string(connection, topic_list[topic_number].filter, strlen(topic_list[topic_number].filter)) < 0) { - return fail_message(connection); - } - - if (connection->message.length + 1 > connection->buffer_length) { - return fail_message(connection); - } - connection->buffer[connection->message.length] = topic_list[topic_number].qos; - connection->message.length ++; - } - - return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); -} - -mqtt_message_t *mqtt_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id) -{ - init_message(connection); - - if (topic == NULL || topic[0] == '\0') { - return fail_message(connection); - } - - if ((*message_id = append_message_id(connection, 0)) == 0) { - return fail_message(connection); - } - - if (append_string(connection, topic, strlen(topic)) < 0) { - return fail_message(connection); - } - - return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); -} - -mqtt_message_t *mqtt_msg_pingreq(mqtt_connection_t *connection) -{ - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); -} - -mqtt_message_t *mqtt_msg_pingresp(mqtt_connection_t *connection) -{ - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); -} - -mqtt_message_t *mqtt_msg_disconnect(mqtt_connection_t *connection) -{ - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); -} - -/* - * check flags: [MQTT-2.2.2-1], [MQTT-2.2.2-2] - * returns 0 if flags are invalid, otherwise returns 1 - */ -int mqtt_has_valid_msg_hdr(uint8_t *buffer, size_t length) -{ - int qos, dup; - - if (length < 1) { - return 0; - } - switch (mqtt_get_type(buffer)) { - case MQTT_MSG_TYPE_CONNECT: - case MQTT_MSG_TYPE_CONNACK: - case MQTT_MSG_TYPE_PUBACK: - case MQTT_MSG_TYPE_PUBREC: - case MQTT_MSG_TYPE_PUBCOMP: - case MQTT_MSG_TYPE_SUBACK: - case MQTT_MSG_TYPE_UNSUBACK: - case MQTT_MSG_TYPE_PINGREQ: - case MQTT_MSG_TYPE_PINGRESP: - case MQTT_MSG_TYPE_DISCONNECT: - return (buffer[0] & 0x0f) == 0; /* all flag bits are 0 */ - case MQTT_MSG_TYPE_PUBREL: - case MQTT_MSG_TYPE_SUBSCRIBE: - case MQTT_MSG_TYPE_UNSUBSCRIBE: - return (buffer[0] & 0x0f) == 0x02; /* only bit 1 is set */ - case MQTT_MSG_TYPE_PUBLISH: - qos = mqtt_get_qos(buffer); - dup = mqtt_get_dup(buffer); - /* - * there is no qos=3 [MQTT-3.3.1-4] - * dup flag must be set to 0 for all qos=0 messages [MQTT-3.3.1-2] - */ - return (qos < 3) && ((qos > 0) || (dup == 0)); - default: - return 0; - } -} diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c deleted file mode 100644 index f60a471..0000000 --- a/lib/mqtt_outbox.c +++ /dev/null @@ -1,238 +0,0 @@ -#include "mqtt_outbox.h" -#include -#include -#include "mqtt_config.h" -#include "sys/queue.h" -#include "esp_heap_caps.h" -#include "esp_log.h" - -#ifndef CONFIG_MQTT_CUSTOM_OUTBOX -static const char *TAG = "outbox"; - -typedef struct outbox_item { - char *buffer; - int len; - int msg_id; - int msg_type; - int msg_qos; - outbox_tick_t tick; - pending_state_t pending; - STAILQ_ENTRY(outbox_item) next; -} outbox_item_t; - -STAILQ_HEAD(outbox_list_t, outbox_item); - - -outbox_handle_t outbox_init(void) -{ - outbox_handle_t outbox = calloc(1, sizeof(struct outbox_list_t)); - ESP_MEM_CHECK(TAG, outbox, return NULL); - STAILQ_INIT(outbox); - return outbox; -} - -outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, outbox_tick_t tick) -{ - outbox_item_handle_t item = heap_caps_calloc(1, sizeof(outbox_item_t), MQTT_OUTBOX_MEMORY); - ESP_MEM_CHECK(TAG, item, return NULL); - item->msg_id = message->msg_id; - item->msg_type = message->msg_type; - item->msg_qos = message->msg_qos; - item->tick = tick; - item->len = message->len + message->remaining_len; - item->pending = QUEUED; - item->buffer = malloc(message->len + message->remaining_len); - ESP_MEM_CHECK(TAG, item->buffer, { - free(item); - return NULL; - }); - memcpy(item->buffer, message->data, message->len); - if (message->remaining_data) { - memcpy(item->buffer + message->len, message->remaining_data, message->remaining_len); - } - STAILQ_INSERT_TAIL(outbox, item, next); - ESP_LOGD(TAG, "ENQUEUE msgid=%d, msg_type=%d, len=%d, size=%d", message->msg_id, message->msg_type, message->len + message->remaining_len, outbox_get_size(outbox)); - return item; -} - -outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id) -{ - outbox_item_handle_t item; - STAILQ_FOREACH(item, outbox, next) { - if (item->msg_id == msg_id) { - return item; - } - } - return NULL; -} - -outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, outbox_tick_t *tick) -{ - outbox_item_handle_t item; - STAILQ_FOREACH(item, outbox, next) { - if (item->pending == pending) { - if (tick) { - *tick = item->tick; - } - return item; - } - } - return NULL; -} - -esp_err_t outbox_delete_item(outbox_handle_t outbox, outbox_item_handle_t item_to_delete) -{ - outbox_item_handle_t item; - STAILQ_FOREACH(item, outbox, next) { - if (item == item_to_delete) { - STAILQ_REMOVE(outbox, item, outbox_item, next); - free(item->buffer); - free(item); - return ESP_OK; - } - } - return ESP_FAIL; -} - -uint8_t *outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos) -{ - if (item) { - *len = item->len; - *msg_id = item->msg_id; - *msg_type = item->msg_type; - *qos = item->msg_qos; - return (uint8_t *)item->buffer; - } - return NULL; -} - -esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type) -{ - outbox_item_handle_t item, tmp; - STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { - if (item->msg_id == msg_id && (0xFF & (item->msg_type)) == msg_type) { - STAILQ_REMOVE(outbox, item, outbox_item, next); - free(item->buffer); - free(item); - ESP_LOGD(TAG, "DELETED msgid=%d, msg_type=%d, remain size=%d", msg_id, msg_type, outbox_get_size(outbox)); - return ESP_OK; - } - - } - return ESP_FAIL; -} -esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id) -{ - outbox_item_handle_t item, tmp; - STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { - if (item->msg_id == msg_id) { - STAILQ_REMOVE(outbox, item, outbox_item, next); - free(item->buffer); - free(item); - } - - } - return ESP_OK; -} -esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id, pending_state_t pending) -{ - outbox_item_handle_t item = outbox_get(outbox, msg_id); - if (item) { - item->pending = pending; - return ESP_OK; - } - return ESP_FAIL; -} - -pending_state_t outbox_item_get_pending(outbox_item_handle_t item) -{ - if (item) { - return item->pending; - } - return QUEUED; -} - -esp_err_t outbox_set_tick(outbox_handle_t outbox, int msg_id, outbox_tick_t tick) -{ - outbox_item_handle_t item = outbox_get(outbox, msg_id); - if (item) { - item->tick = tick; - return ESP_OK; - } - return ESP_FAIL; -} - -esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type) -{ - outbox_item_handle_t item, tmp; - STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { - if (item->msg_type == msg_type) { - STAILQ_REMOVE(outbox, item, outbox_item, next); - free(item->buffer); - free(item); - } - - } - return ESP_OK; -} -int outbox_delete_single_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout) -{ - int msg_id = -1; - outbox_item_handle_t item; - STAILQ_FOREACH(item, outbox, next) { - if (current_tick - item->tick > timeout) { - STAILQ_REMOVE(outbox, item, outbox_item, next); - free(item->buffer); - msg_id = item->msg_id; - free(item); - return msg_id; - } - - } - return msg_id; -} - -int outbox_delete_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout) -{ - int deleted_items = 0; - outbox_item_handle_t item, tmp; - STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { - if (current_tick - item->tick > timeout) { - STAILQ_REMOVE(outbox, item, outbox_item, next); - free(item->buffer); - free(item); - deleted_items ++; - } - - } - return deleted_items; -} - -int outbox_get_size(outbox_handle_t outbox) -{ - int siz = 0; - outbox_item_handle_t item; - STAILQ_FOREACH(item, outbox, next) { - // Suppressing "use after free" warning as this could happen only if queue is in inconsistent state - // which never happens if STAILQ interface used - siz += item->len; // NOLINT(clang-analyzer-unix.Malloc) - } - return siz; -} - -void outbox_delete_all_items(outbox_handle_t outbox) -{ - outbox_item_handle_t item, tmp; - STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { - STAILQ_REMOVE(outbox, item, outbox_item, next); - free(item->buffer); - free(item); - } -} -void outbox_destroy(outbox_handle_t outbox) -{ - outbox_delete_all_items(outbox); - free(outbox); -} - -#endif /* CONFIG_MQTT_CUSTOM_OUTBOX */ diff --git a/lib/platform_esp32_idf.c b/lib/platform_esp32_idf.c deleted file mode 100644 index 86db376..0000000 --- a/lib/platform_esp32_idf.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "platform.h" - -#ifdef ESP_PLATFORM -#include "esp_log.h" -#include "esp_mac.h" -#include "esp_timer.h" -#include "esp_random.h" -#include -#include - -static const char *TAG = "platform"; - -#define MAX_ID_STRING (32) - -char *platform_create_id_string(void) -{ - uint8_t mac[6]; - char *id_string = calloc(1, MAX_ID_STRING); - ESP_MEM_CHECK(TAG, id_string, return NULL); - esp_read_mac(mac, ESP_MAC_WIFI_STA); - sprintf(id_string, "ESP32_%02x%02X%02X", mac[3], mac[4], mac[5]); - return id_string; -} - -int platform_random(int max) -{ - return esp_random() % max; -} - -uint64_t platform_tick_get_ms(void) -{ - return esp_timer_get_time()/(int64_t)1000; -} - -#endif diff --git a/mqtt5_client.c b/mqtt5_client.c deleted file mode 100644 index 82d4f41..0000000 --- a/mqtt5_client.c +++ /dev/null @@ -1,760 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "mqtt_client_priv.h" -#include "esp_log.h" -#include - -static const char *TAG = "mqtt5_client"; - -static void esp_mqtt5_print_error_code(esp_mqtt5_client_handle_t client, int code); -static esp_err_t esp_mqtt5_client_update_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, char *topic, size_t topic_len); -static char *esp_mqtt5_client_get_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, size_t *topic_length); -static void esp_mqtt5_client_delete_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle); -static esp_err_t esp_mqtt5_user_property_copy(mqtt5_user_property_handle_t user_property_new, const mqtt5_user_property_handle_t user_property_old); - -void esp_mqtt5_increment_packet_counter(esp_mqtt5_client_handle_t client) -{ - bool msg_dup = mqtt5_get_dup(client->mqtt_state.outbound_message->data); - if (msg_dup == false) { - client->send_publish_packet_count ++; - ESP_LOGD(TAG, "Sent (%d) qos > 0 publish packet without ack", client->send_publish_packet_count); - } -} - -void esp_mqtt5_decrement_packet_counter(esp_mqtt5_client_handle_t client) -{ - if (client->send_publish_packet_count > 0) { - client->send_publish_packet_count --; - ESP_LOGD(TAG, "Receive (%d) qos > 0 publish packet with ack", client->send_publish_packet_count); - } -} - -void esp_mqtt5_parse_pubcomp(esp_mqtt5_client_handle_t client) -{ - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBCOMP return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); - size_t msg_data_len = client->mqtt_state.in_buffer_read_len; - client->event.data = mqtt5_get_pubcomp_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property); - client->event.data_len = msg_data_len; - client->event.total_data_len = msg_data_len; - client->event.current_data_offset = 0; - } -} - -void esp_mqtt5_parse_puback(esp_mqtt5_client_handle_t client) -{ - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); - size_t msg_data_len = client->mqtt_state.in_buffer_read_len; - client->event.data = mqtt5_get_puback_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property); - client->event.data_len = msg_data_len; - client->event.total_data_len = msg_data_len; - client->event.current_data_offset = 0; - } -} - -void esp_mqtt5_parse_unsuback(esp_mqtt5_client_handle_t client) -{ - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - ESP_LOGI(TAG, "MQTT_MSG_TYPE_UNSUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); - size_t msg_data_len = client->mqtt_state.in_buffer_read_len; - client->event.data = mqtt5_get_unsuback_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property); - client->event.data_len = msg_data_len; - client->event.total_data_len = msg_data_len; - client->event.current_data_offset = 0; - } -} - -void esp_mqtt5_parse_suback(esp_mqtt5_client_handle_t client) -{ - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - ESP_LOGI(TAG, "MQTT_MSG_TYPE_SUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); - } -} - -esp_err_t esp_mqtt5_parse_connack(esp_mqtt5_client_handle_t client, int *connect_rsp_code) -{ - size_t len = client->mqtt_state.in_buffer_read_len; - client->mqtt_state.in_buffer_read_len = 0; - uint8_t ack_flag = 0; - if (mqtt5_msg_parse_connack_property(client->mqtt_state.in_buffer, len, &client->connect_info, &client->mqtt5_config->connect_property_info, &client->mqtt5_config->server_resp_property_info, connect_rsp_code, &ack_flag, &client->event.property->user_property) != ESP_OK) { - ESP_LOGE(TAG, "Failed to parse CONNACK packet"); - return ESP_FAIL; - } - if (*connect_rsp_code == MQTT_CONNECTION_ACCEPTED) { - ESP_LOGD(TAG, "Connected"); - client->event.session_present = ack_flag & 0x01; - return ESP_OK; - } - esp_mqtt5_print_error_code(client, *connect_rsp_code); - return ESP_FAIL; -} - -esp_err_t esp_mqtt5_get_publish_data(esp_mqtt5_client_handle_t client, uint8_t *msg_buf, size_t msg_read_len, char **msg_topic, size_t *msg_topic_len, char **msg_data, size_t *msg_data_len) -{ - // get property - uint16_t property_len = 0; - esp_mqtt5_publish_resp_property_t property = {0}; - *msg_data = mqtt5_get_publish_property_payload(msg_buf, msg_read_len, msg_topic, msg_topic_len, &property, &property_len, msg_data_len, &client->event.property->user_property); - if (*msg_data == NULL) { - ESP_LOGE(TAG, "%s: mqtt5_get_publish_property_payload() failed", __func__); - return ESP_FAIL; - } - - if (property.topic_alias > client->mqtt5_config->connect_property_info.topic_alias_maximum) { - ESP_LOGE(TAG, "%s: Broker response topic alias %d is over the max topic alias %d", __func__, property.topic_alias, client->mqtt5_config->connect_property_info.topic_alias_maximum); - return ESP_FAIL; - } - - if (property.topic_alias) { - if (*msg_topic_len == 0) { - ESP_LOGI(TAG, "Publish topic is empty, use topic alias"); - *msg_topic = esp_mqtt5_client_get_topic_alias(client->mqtt5_config->peer_topic_alias, property.topic_alias, msg_topic_len); - if (!*msg_topic) { - ESP_LOGE(TAG, "%s: esp_mqtt5_client_get_topic_alias() failed", __func__); - return ESP_FAIL; - } - } else { - if (esp_mqtt5_client_update_topic_alias(client->mqtt5_config->peer_topic_alias, property.topic_alias, *msg_topic, *msg_topic_len) != ESP_OK) { - ESP_LOGE(TAG, "%s: esp_mqtt5_client_update_topic_alias() failed", __func__); - return ESP_FAIL; - } - } - } - - client->event.property->payload_format_indicator = property.payload_format_indicator; - client->event.property->response_topic = property.response_topic; - client->event.property->response_topic_len = property.response_topic_len; - client->event.property->correlation_data = property.correlation_data; - client->event.property->correlation_data_len = property.correlation_data_len; - client->event.property->content_type = property.content_type; - client->event.property->content_type_len = property.content_type_len; - client->event.property->subscribe_id = property.subscribe_id; - return ESP_OK; -} - -esp_err_t esp_mqtt5_create_default_config(esp_mqtt5_client_handle_t client) -{ - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - client->event.property = calloc(1, sizeof(esp_mqtt5_event_property_t)); - ESP_MEM_CHECK(TAG, client->event.property, return ESP_FAIL) - client->mqtt5_config = calloc(1, sizeof(mqtt5_config_storage_t)); - ESP_MEM_CHECK(TAG, client->mqtt5_config, return ESP_FAIL) - client->mqtt5_config->server_resp_property_info.max_qos = 2; - client->mqtt5_config->server_resp_property_info.retain_available = true; - client->mqtt5_config->server_resp_property_info.wildcard_subscribe_available = true; - client->mqtt5_config->server_resp_property_info.subscribe_identifiers_available = true; - client->mqtt5_config->server_resp_property_info.shared_subscribe_available = true; - client->mqtt5_config->server_resp_property_info.receive_maximum = 65535; - } - return ESP_OK; -} - -static void esp_mqtt5_print_error_code(esp_mqtt5_client_handle_t client, int code) -{ - switch (code) { - case MQTT5_UNSPECIFIED_ERROR: - ESP_LOGW(TAG, "Unspecified error"); - break; - case MQTT5_MALFORMED_PACKET: - ESP_LOGW(TAG, "Malformed Packet"); - break; - case MQTT5_PROTOCOL_ERROR: - ESP_LOGW(TAG, "Protocol Error"); - break; - case MQTT5_IMPLEMENT_SPECIFIC_ERROR: - ESP_LOGW(TAG, "Implementation specific error"); - break; - case MQTT5_UNSUPPORTED_PROTOCOL_VER: - ESP_LOGW(TAG, "Unsupported Protocol Version"); - break; - case MQTT5_INVAILD_CLIENT_ID: - ESP_LOGW(TAG, "Client Identifier not valid"); - break; - case MQTT5_BAD_USERNAME_OR_PWD: - ESP_LOGW(TAG, "Bad User Name or Password"); - break; - case MQTT5_NOT_AUTHORIZED: - ESP_LOGW(TAG, "Not authorized"); - break; - case MQTT5_SERVER_UNAVAILABLE: - ESP_LOGW(TAG, "Server unavailable"); - break; - case MQTT5_SERVER_BUSY: - ESP_LOGW(TAG, "Server busy"); - break; - case MQTT5_BANNED: - ESP_LOGW(TAG, "Banned"); - break; - case MQTT5_SERVER_SHUTTING_DOWN: - ESP_LOGW(TAG, "Server shutting down"); - break; - case MQTT5_BAD_AUTH_METHOD: - ESP_LOGW(TAG, "Bad authentication method"); - break; - case MQTT5_KEEP_ALIVE_TIMEOUT: - ESP_LOGW(TAG, "Keep Alive timeout"); - break; - case MQTT5_SESSION_TAKEN_OVER: - ESP_LOGW(TAG, "Session taken over"); - break; - case MQTT5_TOPIC_FILTER_INVAILD: - ESP_LOGW(TAG, "Topic Filter invalid"); - break; - case MQTT5_TOPIC_NAME_INVAILD: - ESP_LOGW(TAG, "Topic Name invalid"); - break; - case MQTT5_PACKET_IDENTIFIER_IN_USE: - ESP_LOGW(TAG, "Packet Identifier in use"); - break; - case MQTT5_PACKET_IDENTIFIER_NOT_FOUND: - ESP_LOGW(TAG, "Packet Identifier not found"); - break; - case MQTT5_RECEIVE_MAXIMUM_EXCEEDED: - ESP_LOGW(TAG, "Receive Maximum exceeded"); - break; - case MQTT5_TOPIC_ALIAS_INVAILD: - ESP_LOGW(TAG, "Topic Alias invalid"); - break; - case MQTT5_PACKET_TOO_LARGE: - ESP_LOGW(TAG, "Packet too large"); - break; - case MQTT5_MESSAGE_RATE_TOO_HIGH: - ESP_LOGW(TAG, "Message rate too high"); - break; - case MQTT5_QUOTA_EXCEEDED: - ESP_LOGW(TAG, "Quota exceeded"); - break; - case MQTT5_ADMINISTRATIVE_ACTION: - ESP_LOGW(TAG, "Administrative action"); - break; - case MQTT5_PAYLOAD_FORMAT_INVAILD: - ESP_LOGW(TAG, "Payload format invalid"); - break; - case MQTT5_RETAIN_NOT_SUPPORT: - ESP_LOGW(TAG, "Retain not supported"); - break; - case MQTT5_QOS_NOT_SUPPORT: - ESP_LOGW(TAG, "QoS not supported"); - break; - case MQTT5_USE_ANOTHER_SERVER: - ESP_LOGW(TAG, "Use another server"); - break; - case MQTT5_SERVER_MOVED: - ESP_LOGW(TAG, "Server moved"); - break; - case MQTT5_SHARED_SUBSCR_NOT_SUPPORTED: - ESP_LOGW(TAG, "Shared Subscriptions not supported"); - break; - case MQTT5_CONNECTION_RATE_EXCEEDED: - ESP_LOGW(TAG, "Connection rate exceeded"); - break; - case MQTT5_MAXIMUM_CONNECT_TIME: - ESP_LOGW(TAG, "Maximum connect time"); - break; - case MQTT5_SUBSCRIBE_IDENTIFIER_NOT_SUPPORT: - ESP_LOGW(TAG, "Subscription Identifiers not supported"); - break; - case MQTT5_WILDCARD_SUBSCRIBE_NOT_SUPPORT: - ESP_LOGW(TAG, "Wildcard Subscriptions not supported"); - break; - default: - ESP_LOGW(TAG, "Connection refused, Unknow reason"); - break; - } -} - -esp_err_t esp_mqtt5_client_subscribe_check(esp_mqtt5_client_handle_t client, int qos) -{ - /* Check Server support QoS level */ - if (client->mqtt5_config->server_resp_property_info.max_qos < qos) { - ESP_LOGE(TAG, "Server only support max QoS level %d", client->mqtt5_config->server_resp_property_info.max_qos); - return ESP_FAIL; - } - - return ESP_OK; -} - -esp_err_t esp_mqtt5_client_publish_check(esp_mqtt5_client_handle_t client, int qos, int retain) -{ - /* Check Server support QoS level */ - if (client->mqtt5_config->server_resp_property_info.max_qos < qos) { - ESP_LOGE(TAG, "Server only support max QoS level %d", client->mqtt5_config->server_resp_property_info.max_qos); - return ESP_FAIL; - } - - /* Check Server support RETAIN */ - if (!client->mqtt5_config->server_resp_property_info.retain_available && retain) { - ESP_LOGE(TAG, "Server not support retain"); - return ESP_FAIL; - } - - /* Flow control to check PUBLISH(No PUBACK or PUBCOMP received) packet sent count(Only record QoS1 and QoS2)*/ - if (client->send_publish_packet_count > client->mqtt5_config->server_resp_property_info.receive_maximum) { - ESP_LOGE(TAG, "Client send more than %d QoS1 and QoS2 PUBLISH packet without no ack", client->mqtt5_config->server_resp_property_info.receive_maximum); - return ESP_FAIL; - } - - return ESP_OK; -} - -void esp_mqtt5_client_destory(esp_mqtt5_client_handle_t client) -{ - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - if (client->mqtt5_config) { - free(client->mqtt5_config->will_property_info.content_type); - free(client->mqtt5_config->will_property_info.response_topic); - free(client->mqtt5_config->will_property_info.correlation_data); - free(client->mqtt5_config->server_resp_property_info.response_info); - esp_mqtt5_client_delete_topic_alias(client->mqtt5_config->peer_topic_alias); - esp_mqtt5_client_delete_user_property(client->mqtt5_config->connect_property_info.user_property); - esp_mqtt5_client_delete_user_property(client->mqtt5_config->will_property_info.user_property); - esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property); - free(client->mqtt5_config); - } - free(client->event.property); - } -} - -static void esp_mqtt5_client_delete_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle) -{ - if (topic_alias_handle) { - mqtt5_topic_alias_item_t item, tmp; - STAILQ_FOREACH_SAFE(item, topic_alias_handle, next, tmp) { - STAILQ_REMOVE(topic_alias_handle, item, mqtt5_topic_alias, next); - free(item->topic); - free(item); - } - free(topic_alias_handle); - } -} - -static esp_err_t esp_mqtt5_client_update_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, char *topic, size_t topic_len) -{ - mqtt5_topic_alias_item_t item; - bool found = false; - STAILQ_FOREACH(item, topic_alias_handle, next) { - if (item->topic_alias == topic_alias) { - found = true; - break; - } - } - if (found) { - if ((item->topic_len != topic_len) || strncmp(topic, item->topic, topic_len)) { - free(item->topic); - item->topic = calloc(1, topic_len); - ESP_MEM_CHECK(TAG, item->topic, return ESP_FAIL); - memcpy(item->topic, topic, topic_len); - item->topic_len = topic_len; - } - } else { - item = calloc(1, sizeof(mqtt5_topic_alias_t)); - ESP_MEM_CHECK(TAG, item, return ESP_FAIL); - item->topic_alias = topic_alias; - item->topic_len = topic_len; - item->topic = calloc(1, topic_len); - ESP_MEM_CHECK(TAG, item->topic, { - free(item); - return ESP_FAIL; - }); - memcpy(item->topic, topic, topic_len); - STAILQ_INSERT_TAIL(topic_alias_handle, item, next); - } - return ESP_OK; -} - -static char *esp_mqtt5_client_get_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, size_t *topic_length) -{ - mqtt5_topic_alias_item_t item; - STAILQ_FOREACH(item, topic_alias_handle, next) { - if (item->topic_alias == topic_alias) { - *topic_length = item->topic_len; - return item->topic; - } - } - *topic_length = 0; - return NULL; -} - -static esp_err_t esp_mqtt5_user_property_copy(mqtt5_user_property_handle_t user_property_new, const mqtt5_user_property_handle_t user_property_old) -{ - if (!user_property_new || !user_property_old) { - ESP_LOGE(TAG, "Input is NULL"); - return ESP_FAIL; - } - - mqtt5_user_property_item_t old_item, new_item; - STAILQ_FOREACH(old_item, user_property_old, next) { - new_item = calloc(1, sizeof(mqtt5_user_property_t)); - ESP_MEM_CHECK(TAG, new_item, return ESP_FAIL); - new_item->key = strdup(old_item->key); - ESP_MEM_CHECK(TAG, new_item->key, { - free(new_item); - return ESP_FAIL; - }); - new_item->value = strdup(old_item->value); - ESP_MEM_CHECK(TAG, new_item->value, { - free(new_item->key); - free(new_item); - return ESP_FAIL; - }); - STAILQ_INSERT_TAIL(user_property_new, new_item, next); - } - return ESP_OK; -} - -esp_err_t esp_mqtt5_client_set_publish_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_publish_property_config_t *property) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - MQTT_API_LOCK(client); - - /* Check protocol version */ - if(client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) { - ESP_LOGE(TAG, "MQTT protocol version is not v5"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - /* Check topic alias less than server maximum topic alias */ - if (property->topic_alias > client->mqtt5_config->server_resp_property_info.topic_alias_maximum) { - ESP_LOGE(TAG, "Topic alias %d is bigger than server support %d", property->topic_alias, client->mqtt5_config->server_resp_property_info.topic_alias_maximum); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - client->mqtt5_config->publish_property_info = property; - MQTT_API_UNLOCK(client); - return ESP_OK; -} - -esp_err_t esp_mqtt5_client_set_subscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_subscribe_property_config_t *property) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - if (property->retain_handle > 2) { - ESP_LOGE(TAG, "retain_handle only support 0, 1, 2"); - return -1; - } - MQTT_API_LOCK(client); - - /* Check protocol version */ - if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) { - ESP_LOGE(TAG, "MQTT protocol version is not v5"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - if (property->is_share_subscribe) { - if (property->no_local_flag) { - // MQTT-3.8.3-4 not allow that No Local bit to 1 on a Shared Subscription - ESP_LOGE(TAG, "Protocol error that no local flag set on shared subscription"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - if (!client->mqtt5_config->server_resp_property_info.shared_subscribe_available) { - ESP_LOGE(TAG, "MQTT broker not support shared subscribe"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - if (!property->share_name || !strlen(property->share_name)) { - ESP_LOGE(TAG, "Share name can't be empty for shared subscribe"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - } - client->mqtt5_config->subscribe_property_info = property; - MQTT_API_UNLOCK(client); - return ESP_OK; -} - -esp_err_t esp_mqtt5_client_set_unsubscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_unsubscribe_property_config_t *property) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - MQTT_API_LOCK(client); - - /* Check protocol version */ - if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) { - ESP_LOGE(TAG, "MQTT protocol version is not v5"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - if (property->is_share_subscribe) { - if (!client->mqtt5_config->server_resp_property_info.shared_subscribe_available) { - ESP_LOGE(TAG, "MQTT broker not support shared subscribe"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - if (!property->share_name || !strlen(property->share_name)) { - ESP_LOGE(TAG, "Share name can't be empty for shared subscribe"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - } - client->mqtt5_config->unsubscribe_property_info = property; - MQTT_API_UNLOCK(client); - return ESP_OK; -} - -esp_err_t esp_mqtt5_client_set_disconnect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_disconnect_property_config_t *property) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - MQTT_API_LOCK(client); - - /* Check protocol version */ - if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) { - ESP_LOGE(TAG, "MQTT protocol version is not v5"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - if (property) { - if (property->session_expiry_interval) { - client->mqtt5_config->disconnect_property_info.session_expiry_interval = property->session_expiry_interval; - } - if (property->disconnect_reason) { - client->mqtt5_config->disconnect_property_info.disconnect_reason = property->disconnect_reason; - } - if (property->user_property) { - esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property); - client->mqtt5_config->disconnect_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); - ESP_MEM_CHECK(TAG, client->mqtt5_config->disconnect_property_info.user_property, { - MQTT_API_UNLOCK(client); - return ESP_ERR_NO_MEM; - }); - STAILQ_INIT(client->mqtt5_config->disconnect_property_info.user_property); - if (esp_mqtt5_user_property_copy(client->mqtt5_config->disconnect_property_info.user_property, property->user_property) != ESP_OK) { - ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail"); - free(client->mqtt5_config->disconnect_property_info.user_property); - client->mqtt5_config->disconnect_property_info.user_property = NULL; - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - } - } - - MQTT_API_UNLOCK(client); - return ESP_OK; -} - -esp_err_t esp_mqtt5_client_set_connect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_connection_property_config_t *connect_property) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - MQTT_API_LOCK(client); - - /* Check protocol version */ - if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) { - ESP_LOGE(TAG, "MQTT protocol version is not v5"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - if (connect_property) { - if (connect_property->session_expiry_interval) { - client->mqtt5_config->connect_property_info.session_expiry_interval = connect_property->session_expiry_interval; - } - if (connect_property->maximum_packet_size) { - if (connect_property->maximum_packet_size > client->mqtt_state.in_buffer_length) { - ESP_LOGW(TAG, "Connect maximum_packet_size property is over buffer_size(%d), Please first change it", client->mqtt_state.in_buffer_length); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } else { - client->mqtt5_config->connect_property_info.maximum_packet_size = connect_property->maximum_packet_size; - } - } else { - client->mqtt5_config->connect_property_info.maximum_packet_size = client->mqtt_state.in_buffer_length; - } - if (connect_property->receive_maximum) { - client->mqtt5_config->connect_property_info.receive_maximum = connect_property->receive_maximum; - } - if (connect_property->topic_alias_maximum) { - client->mqtt5_config->connect_property_info.topic_alias_maximum = connect_property->topic_alias_maximum; - if (!client->mqtt5_config->peer_topic_alias) { - client->mqtt5_config->peer_topic_alias = calloc(1, sizeof(struct mqtt5_topic_alias_list_t)); - ESP_MEM_CHECK(TAG, client->mqtt5_config->peer_topic_alias, goto _mqtt_set_config_failed); - STAILQ_INIT(client->mqtt5_config->peer_topic_alias); - } - } - if (connect_property->request_resp_info) { - client->mqtt5_config->connect_property_info.request_resp_info = connect_property->request_resp_info; - } - if (connect_property->request_problem_info) { - client->mqtt5_config->connect_property_info.request_problem_info = connect_property->request_problem_info; - } - if (connect_property->user_property) { - esp_mqtt5_client_delete_user_property(client->mqtt5_config->connect_property_info.user_property); - client->mqtt5_config->connect_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); - ESP_MEM_CHECK(TAG, client->mqtt5_config->connect_property_info.user_property, goto _mqtt_set_config_failed); - STAILQ_INIT(client->mqtt5_config->connect_property_info.user_property); - if (esp_mqtt5_user_property_copy(client->mqtt5_config->connect_property_info.user_property, connect_property->user_property) != ESP_OK) { - ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail"); - goto _mqtt_set_config_failed; - } - } - if (connect_property->payload_format_indicator) { - client->mqtt5_config->will_property_info.payload_format_indicator = connect_property->payload_format_indicator; - } - if (connect_property->will_delay_interval) { - client->mqtt5_config->will_property_info.will_delay_interval = connect_property->will_delay_interval; - } - if (connect_property->message_expiry_interval) { - client->mqtt5_config->will_property_info.message_expiry_interval = connect_property->message_expiry_interval; - } - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(connect_property->content_type, &client->mqtt5_config->will_property_info.content_type), goto _mqtt_set_config_failed); - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(connect_property->response_topic, &client->mqtt5_config->will_property_info.response_topic), goto _mqtt_set_config_failed); - if (connect_property->correlation_data && connect_property->correlation_data_len) { - free(client->mqtt5_config->will_property_info.correlation_data); - client->mqtt5_config->will_property_info.correlation_data = malloc(connect_property->correlation_data_len); - ESP_MEM_CHECK(TAG, client->mqtt5_config->will_property_info.correlation_data, goto _mqtt_set_config_failed); - memcpy(client->mqtt5_config->will_property_info.correlation_data, connect_property->correlation_data, connect_property->correlation_data_len); - client->mqtt5_config->will_property_info.correlation_data_len = connect_property->correlation_data_len; - } - if (connect_property->will_user_property) { - esp_mqtt5_client_delete_user_property(client->mqtt5_config->will_property_info.user_property); - client->mqtt5_config->will_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); - ESP_MEM_CHECK(TAG, client->mqtt5_config->will_property_info.user_property, goto _mqtt_set_config_failed); - STAILQ_INIT(client->mqtt5_config->will_property_info.user_property); - if (esp_mqtt5_user_property_copy(client->mqtt5_config->will_property_info.user_property, connect_property->will_user_property) != ESP_OK) { - ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail"); - goto _mqtt_set_config_failed; - } - } - } - MQTT_API_UNLOCK(client); - return ESP_OK; -_mqtt_set_config_failed: - esp_mqtt_destroy_config(client); - MQTT_API_UNLOCK(client); - return ESP_ERR_NO_MEM; -} - -esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_property, esp_mqtt5_user_property_item_t item[], uint8_t item_num) -{ - if (!item_num || !item) { - ESP_LOGE(TAG, "Input value is NULL"); - return ESP_FAIL; - } - - if (!*user_property) { - *user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); - ESP_MEM_CHECK(TAG, *user_property, return ESP_ERR_NO_MEM); - STAILQ_INIT(*user_property); - } - - for (int i = 0; i < item_num; i ++) { - if (item[i].key && item[i].value) { - mqtt5_user_property_item_t user_property_item = calloc(1, sizeof(mqtt5_user_property_t)); - ESP_MEM_CHECK(TAG, user_property_item, goto err); - size_t key_len = strlen(item[i].key); - size_t value_len = strlen(item[i].value); - - user_property_item->key = calloc(1, key_len + 1); - ESP_MEM_CHECK(TAG, user_property_item->key, { - free(user_property_item); - goto err; - }); - memcpy(user_property_item->key, item[i].key, key_len); - user_property_item->key[key_len] = '\0'; - - user_property_item->value = calloc(1, value_len + 1); - ESP_MEM_CHECK(TAG, user_property_item->value, { - free(user_property_item->key); - free(user_property_item); - goto err; - }); - memcpy(user_property_item->value, item[i].value, value_len); - user_property_item->value[value_len] = '\0'; - - STAILQ_INSERT_TAIL(*user_property, user_property_item, next); - } - } - return ESP_OK; -err: - esp_mqtt5_client_delete_user_property(*user_property); - *user_property = NULL; - return ESP_ERR_NO_MEM; -} - -esp_err_t esp_mqtt5_client_get_user_property(mqtt5_user_property_handle_t user_property, esp_mqtt5_user_property_item_t *item, uint8_t *item_num) -{ - int i = 0, j = 0; - if (user_property && item && *item_num) { - mqtt5_user_property_item_t user_property_item; - uint8_t num = *item_num; - STAILQ_FOREACH(user_property_item, user_property, next) { - if (i < num) { - size_t item_key_len = strlen(user_property_item->key); - size_t item_value_len = strlen(user_property_item->value); - char *key = calloc(1, item_key_len + 1); - ESP_MEM_CHECK(TAG, key, goto err); - memcpy(key, user_property_item->key, item_key_len); - key[item_key_len] = '\0'; - char *value = calloc(1, item_value_len + 1); - ESP_MEM_CHECK(TAG, value, { - free(key); - goto err; - }); - memcpy(value, user_property_item->value, item_value_len); - value[item_value_len] = '\0'; - item[i].key = key; - item[i].value = value; - i ++; - } else { - break; - } - } - *item_num = i; - return ESP_OK; - } else { - ESP_LOGE(TAG, "Input value is NULL or item_num is 0"); - return ESP_FAIL; - } -err: - for (j = 0; j < i; j ++) { - if (item[j].key) { - free((char *)item[j].key); - } - if (item[j].value) { - free((char *)item[j].value); - } - } - return ESP_ERR_NO_MEM; -} - -uint8_t esp_mqtt5_client_get_user_property_count(mqtt5_user_property_handle_t user_property) -{ - uint8_t count = 0; - if (user_property) { - mqtt5_user_property_item_t item; - STAILQ_FOREACH(item, user_property, next) { - count ++; - } - } - return count; -} - -void esp_mqtt5_client_delete_user_property(mqtt5_user_property_handle_t user_property) -{ - if (user_property) { - mqtt5_user_property_item_t item, tmp; - STAILQ_FOREACH_SAFE(item, user_property, next, tmp) { - STAILQ_REMOVE(user_property, item, mqtt5_user_property, next); - free(item->key); - free(item->value); - free(item); - } - } - free(user_property); -} \ No newline at end of file diff --git a/mqtt_client.c b/mqtt_client.c deleted file mode 100644 index c68bd53..0000000 --- a/mqtt_client.c +++ /dev/null @@ -1,2186 +0,0 @@ -#include "mqtt_client.h" -#include "mqtt_client_priv.h" -#include "esp_log.h" -#include -#include "esp_heap_caps.h" - - -_Static_assert(sizeof(uint64_t) == sizeof(outbox_tick_t), "mqtt-client tick type size different from outbox tick type"); -#ifdef ESP_EVENT_ANY_ID -_Static_assert(MQTT_EVENT_ANY == ESP_EVENT_ANY_ID, "mqtt-client event enum does not match the global EVENT_ANY_ID"); -#endif - -static const char *TAG = "mqtt_client"; - -#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP -/** - * @brief Define of MQTT Event base - * - */ -ESP_EVENT_DEFINE_BASE(MQTT_EVENTS); -#endif - -#define MQTT_OVER_TCP_SCHEME "mqtt" -#define MQTT_OVER_SSL_SCHEME "mqtts" -#define MQTT_OVER_WS_SCHEME "ws" -#define MQTT_OVER_WSS_SCHEME "wss" - -const static int STOPPED_BIT = (1 << 0); -const static int RECONNECT_BIT = (1 << 1); -const static int DISCONNECT_BIT = (1 << 2); - -static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client); -static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client); -static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms); -static void esp_mqtt_abort_connection(esp_mqtt_client_handle_t client); -static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client); -static char *create_string(const char *ptr, int len); -static int mqtt_message_receive(esp_mqtt_client_handle_t client, int read_poll_timeout_ms); -static void esp_mqtt_client_dispatch_transport_error(esp_mqtt_client_handle_t client); -static esp_err_t send_disconnect_msg(esp_mqtt_client_handle_t client); - -static int esp_mqtt_handle_transport_read_error(int err, esp_mqtt_client_handle_t client) -{ - if (err == ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN) { - ESP_LOGD(TAG, "%s: transport_read(): EOF", __func__); - return 0; - } - - if (err == ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT) { - ESP_LOGD(TAG, "%s: transport_read(): call timed out before data was ready!", __func__); - return 0; - } - - ESP_LOGE(TAG, "%s: transport_read() error: errno=%d", __func__, errno); - esp_mqtt_client_dispatch_transport_error(client); - return -1; -} - -#if MQTT_ENABLE_SSL -enum esp_mqtt_ssl_cert_key_api { - MQTT_SSL_DATA_API_CA_CERT, - MQTT_SSL_DATA_API_CLIENT_CERT, - MQTT_SSL_DATA_API_CLIENT_KEY, - MQTT_SSL_DATA_API_MAX, -}; - -static esp_err_t esp_mqtt_set_cert_key_data(esp_transport_handle_t ssl, enum esp_mqtt_ssl_cert_key_api what, const char *cert_key_data, int cert_key_len) -{ - char *data = (char *)cert_key_data; - int ssl_transport_api_id = what; - int len = cert_key_len; - - if (!data) { - return ESP_OK; - } - - if (len == 0) { - // if length not specified, expect 0-terminated PEM string - // and the original transport_api_id (by convention after the last api_id in the enum) - ssl_transport_api_id += MQTT_SSL_DATA_API_MAX; - len = strlen(data); - } -#ifndef MQTT_SUPPORTED_FEATURE_DER_CERTIFICATES - else { - ESP_LOGE(TAG, "Explicit cert-/key-len is not available in IDF version %s", IDF_VER); - return ESP_ERR_NOT_SUPPORTED; - } -#endif - - // option to force the cert/key config to null (i.e. skip validation) when existing config updates - if (0 == strcmp(data, "NULL")) { - data = NULL; - len = 0; - } - - switch (ssl_transport_api_id) { -#ifdef MQTT_SUPPORTED_FEATURE_DER_CERTIFICATES - case MQTT_SSL_DATA_API_CA_CERT: - esp_transport_ssl_set_cert_data_der(ssl, data, len); - break; - case MQTT_SSL_DATA_API_CLIENT_CERT: - esp_transport_ssl_set_client_cert_data_der(ssl, data, len); - break; - case MQTT_SSL_DATA_API_CLIENT_KEY: - esp_transport_ssl_set_client_key_data_der(ssl, data, len); - break; -#endif - case MQTT_SSL_DATA_API_CA_CERT + MQTT_SSL_DATA_API_MAX: - esp_transport_ssl_set_cert_data(ssl, data, len); - break; - case MQTT_SSL_DATA_API_CLIENT_CERT + MQTT_SSL_DATA_API_MAX: - esp_transport_ssl_set_client_cert_data(ssl, data, len); - break; - case MQTT_SSL_DATA_API_CLIENT_KEY + MQTT_SSL_DATA_API_MAX: - esp_transport_ssl_set_client_key_data(ssl, data, len); - break; - default: - return ESP_ERR_INVALID_ARG; - } - return ESP_OK; -} - -static esp_err_t esp_mqtt_set_ssl_transport_properties(esp_transport_list_handle_t transport_list, mqtt_config_storage_t *cfg) -{ - esp_transport_handle_t ssl = esp_transport_list_get_transport(transport_list, MQTT_OVER_SSL_SCHEME); - - if (cfg->use_global_ca_store == true) { - esp_transport_ssl_enable_global_ca_store(ssl); - } else if (cfg->crt_bundle_attach != NULL) { -#ifdef MQTT_SUPPORTED_FEATURE_CERTIFICATE_BUNDLE -#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE - esp_transport_ssl_crt_bundle_attach(ssl, cfg->crt_bundle_attach); -#else - ESP_LOGE(TAG, "Certificate bundle is not enabled for mbedTLS in menuconfig"); - goto esp_mqtt_set_transport_failed; -#endif /* CONFIG_MBEDTLS_CERTIFICATE_BUNDLE */ -#else - ESP_LOGE(TAG, "Certificate bundle feature is not available in IDF version %s", IDF_VER); - goto esp_mqtt_set_transport_failed; -#endif /* MQTT_SUPPORTED_FEATURE_CERTIFICATE_BUNDLE */ - } else { - ESP_OK_CHECK(TAG, esp_mqtt_set_cert_key_data(ssl, MQTT_SSL_DATA_API_CA_CERT, cfg->cacert_buf, cfg->cacert_bytes), - goto esp_mqtt_set_transport_failed); - - } - if (cfg->psk_hint_key) { -#if defined(MQTT_SUPPORTED_FEATURE_PSK_AUTHENTICATION) && MQTT_ENABLE_SSL -#ifdef CONFIG_ESP_TLS_PSK_VERIFICATION - esp_transport_ssl_set_psk_key_hint(ssl, cfg->psk_hint_key); -#else - ESP_LOGE(TAG, "PSK authentication configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option"); - goto esp_mqtt_set_transport_failed; -#endif -#else - ESP_LOGE(TAG, "PSK authentication is not available in IDF version %s", IDF_VER); - goto esp_mqtt_set_transport_failed; -#endif - } - - if (cfg->alpn_protos) { -#if defined(MQTT_SUPPORTED_FEATURE_ALPN) && MQTT_ENABLE_SSL -#if defined(CONFIG_MBEDTLS_SSL_ALPN) || defined(CONFIG_WOLFSSL_HAVE_ALPN) - esp_transport_ssl_set_alpn_protocol(ssl, (const char **)cfg->alpn_protos); -#else - ESP_LOGE(TAG, "APLN configured but not enabled in menuconfig: Please enable MBEDTLS_SSL_ALPN or WOLFSSL_HAVE_ALPN option"); - goto esp_mqtt_set_transport_failed; -#endif -#else - ESP_LOGE(TAG, "APLN is not available in IDF version %s", IDF_VER); - goto esp_mqtt_set_transport_failed; -#endif - } - - - if (cfg->skip_cert_common_name_check) { -#if defined(MQTT_SUPPORTED_FEATURE_SKIP_CRT_CMN_NAME_CHECK) && MQTT_ENABLE_SSL - esp_transport_ssl_skip_common_name_check(ssl); -#else - ESP_LOGE(TAG, "Skip certificate common name check is not available in IDF version %s", IDF_VER); - goto esp_mqtt_set_transport_failed; -#endif - } - - if (cfg->use_secure_element) { -#ifdef MQTT_SUPPORTED_FEATURE_SECURE_ELEMENT -#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT - esp_transport_ssl_use_secure_element(ssl); -#else - ESP_LOGE(TAG, "Secure element not enabled for esp-tls in menuconfig"); - goto esp_mqtt_set_transport_failed; -#endif /* CONFIG_ESP_TLS_USE_SECURE_ELEMENT */ -#else - ESP_LOGE(TAG, "Secure element feature is not available in IDF version %s", IDF_VER); - goto esp_mqtt_set_transport_failed; -#endif /* MQTT_SUPPORTED_FEATURE_SECURE_ELEMENT */ - } - - if (cfg->ds_data != NULL) { -#ifdef MQTT_SUPPORTED_FEATURE_DIGITAL_SIGNATURE -#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL - esp_transport_ssl_set_ds_data(ssl, cfg->ds_data); -#else - ESP_LOGE(TAG, "Digital Signature not enabled for esp-tls in menuconfig"); - goto esp_mqtt_set_transport_failed; -#endif /* CONFIG_ESP_TLS_USE_DS_PERIPHERAL */ -#else - ESP_LOGE(TAG, "Digital Signature feature is not available in IDF version %s", IDF_VER); - goto esp_mqtt_set_transport_failed; -#endif - } - ESP_OK_CHECK(TAG, esp_mqtt_set_cert_key_data(ssl, MQTT_SSL_DATA_API_CLIENT_CERT, cfg->clientcert_buf, cfg->clientcert_bytes), - goto esp_mqtt_set_transport_failed); - ESP_OK_CHECK(TAG, esp_mqtt_set_cert_key_data(ssl, MQTT_SSL_DATA_API_CLIENT_KEY, cfg->clientkey_buf, cfg->clientkey_bytes), - goto esp_mqtt_set_transport_failed); - - if (cfg->clientkey_password && cfg->clientkey_password_len) { -#if defined(MQTT_SUPPORTED_FEATURE_CLIENT_KEY_PASSWORD) && MQTT_ENABLE_SSL - esp_transport_ssl_set_client_key_password(ssl, - cfg->clientkey_password, - cfg->clientkey_password_len); -#else - ESP_LOGE(TAG, "Password protected keys are not available in IDF version %s", IDF_VER); - goto esp_mqtt_set_transport_failed; -#endif - } - - - return ESP_OK; - -esp_mqtt_set_transport_failed: - return ESP_FAIL; -} -#endif // MQTT_ENABLE_SSL - -/* Checks if the user supplied config values are internally consistent */ -static esp_err_t esp_mqtt_check_cfg_conflict(const mqtt_config_storage_t *cfg, const esp_mqtt_client_config_t *user_cfg) -{ - if(cfg == NULL || user_cfg == NULL) { - ESP_LOGE(TAG, "Invalid configuration"); - return ESP_ERR_INVALID_ARG; - } - esp_err_t ret = ESP_OK; - - bool ssl_cfg_enabled = cfg->use_global_ca_store || cfg->cacert_buf || cfg->clientcert_buf || cfg->psk_hint_key || cfg->alpn_protos; - bool is_ssl_scheme = false; - if (cfg->scheme) { - is_ssl_scheme = (strncasecmp(cfg->scheme, MQTT_OVER_SSL_SCHEME, sizeof(MQTT_OVER_SSL_SCHEME)) == 0) || (strncasecmp(cfg->scheme, MQTT_OVER_WSS_SCHEME, sizeof(MQTT_OVER_WSS_SCHEME)) == 0); - } - - if (!is_ssl_scheme && ssl_cfg_enabled) { - if (cfg->uri) { - ESP_LOGW(TAG, "SSL related configs set, but the URI scheme specifies a non-SSL scheme, scheme = %s", cfg->scheme); - } else { - ESP_LOGW(TAG, "SSL related configs set, but the transport protocol is a non-SSL scheme, transport = %d", user_cfg->broker.address.transport); - } - ret = ESP_ERR_INVALID_ARG; - } - - if (cfg->uri && user_cfg->broker.address.transport) { - ESP_LOGW(TAG, "Transport config set, but overridden by scheme from URI: transport = %d, uri scheme = %s", user_cfg->broker.address.transport, cfg->scheme); - ret = ESP_ERR_INVALID_ARG; - } - - return ret; -} - -bool esp_mqtt_set_if_config(char const *const new_config, char **old_config) -{ - if (new_config) { - free(*old_config); - *old_config = strdup(new_config); - if (*old_config == NULL) { - return false; - } - } - return true; -} - -static esp_err_t esp_mqtt_client_create_transport(esp_mqtt_client_handle_t client) -{ - esp_err_t ret = ESP_OK; - if (client->transport_list) { - esp_transport_list_destroy(client->transport_list); - client->transport_list = NULL; - } - if (client->config->scheme) { - client->transport_list = esp_transport_list_init(); - ESP_MEM_CHECK(TAG, client->transport_list, return ESP_ERR_NO_MEM); - - if ((strncasecmp(client->config->scheme, MQTT_OVER_TCP_SCHEME, sizeof(MQTT_OVER_TCP_SCHEME)) == 0) || (strncasecmp(client->config->scheme, MQTT_OVER_WS_SCHEME, sizeof(MQTT_OVER_WS_SCHEME)) == 0)) { - esp_transport_handle_t tcp = esp_transport_tcp_init(); - ESP_MEM_CHECK(TAG, tcp, return ESP_ERR_NO_MEM); - esp_transport_set_default_port(tcp, MQTT_TCP_DEFAULT_PORT); - esp_transport_list_add(client->transport_list, tcp, MQTT_OVER_TCP_SCHEME); - if (strncasecmp(client->config->scheme, MQTT_OVER_WS_SCHEME, sizeof(MQTT_OVER_WS_SCHEME)) == 0) { -#if MQTT_ENABLE_WS - esp_transport_handle_t ws = esp_transport_ws_init(tcp); - ESP_MEM_CHECK(TAG, ws, return ESP_ERR_NO_MEM); - esp_transport_set_default_port(ws, MQTT_WS_DEFAULT_PORT); - if (client->config->path) { - esp_transport_ws_set_path(ws, client->config->path); - } -#ifdef MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL - esp_transport_ws_set_subprotocol(ws, MQTT_OVER_TCP_SCHEME); -#endif - esp_transport_list_add(client->transport_list, ws, MQTT_OVER_WS_SCHEME); -#else - ESP_LOGE(TAG, "Please enable MQTT_ENABLE_WS to use %s", client->config->scheme); - ret = ESP_FAIL; -#endif - } - } else if ((strncasecmp(client->config->scheme, MQTT_OVER_SSL_SCHEME, sizeof(MQTT_OVER_SSL_SCHEME)) == 0) || (strncasecmp(client->config->scheme, MQTT_OVER_WSS_SCHEME, sizeof(MQTT_OVER_WSS_SCHEME)) == 0)) { -#if MQTT_ENABLE_SSL - esp_transport_handle_t ssl = esp_transport_ssl_init(); - ESP_MEM_CHECK(TAG, ssl, return ESP_ERR_NO_MEM); - esp_transport_set_default_port(ssl, MQTT_SSL_DEFAULT_PORT); - esp_transport_list_add(client->transport_list, ssl, MQTT_OVER_SSL_SCHEME); - if (strncasecmp(client->config->scheme, MQTT_OVER_WSS_SCHEME, sizeof(MQTT_OVER_WSS_SCHEME)) == 0) { -#if MQTT_ENABLE_WS - esp_transport_handle_t wss = esp_transport_ws_init(ssl); - ESP_MEM_CHECK(TAG, wss, return ESP_ERR_NO_MEM); - esp_transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT); - if (client->config->path) { - esp_transport_ws_set_path(wss, client->config->path); - } -#ifdef MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL - esp_transport_ws_set_subprotocol(wss, MQTT_OVER_TCP_SCHEME); -#endif - esp_transport_list_add(client->transport_list, wss, MQTT_OVER_WSS_SCHEME); -#else - ESP_LOGE(TAG, "Please enable MQTT_ENABLE_WS to use %s", client->config->scheme); - ret = ESP_FAIL; -#endif - } -#else - ESP_LOGE(TAG, "Please enable MQTT_ENABLE_SSL to use %s", client->config->scheme); - ret = ESP_FAIL; -#endif - } else { - ESP_LOGE(TAG, "Not support this mqtt scheme %s", client->config->scheme); - ret = ESP_FAIL; - } - } else { - ESP_LOGE(TAG, "No scheme found"); - ret = ESP_FAIL; - } - return ret; -} - -esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - MQTT_API_LOCK(client); - //Copy user configurations to client context - esp_err_t err = ESP_OK; - if (!client->config) { - client->config = calloc(1, sizeof(mqtt_config_storage_t)); - ESP_MEM_CHECK(TAG, client->config, { - MQTT_API_UNLOCK(client); - return ESP_ERR_NO_MEM; - }); - } - - client->config->message_retransmit_timeout = config->session.message_retransmit_timeout; - if (config->session.message_retransmit_timeout <= 0) { - client->config->message_retransmit_timeout = 1000; - } - - client->config->task_prio = config->task.priority; - if (client->config->task_prio <= 0) { - client->config->task_prio = MQTT_TASK_PRIORITY; - } - - client->config->task_stack = config->task.stack_size; - if (client->config->task_stack <= 0) { - client->config->task_stack = MQTT_TASK_STACK; - } - - if (config->broker.address.port) { - client->config->port = config->broker.address.port; - } - - err = ESP_ERR_NO_MEM; - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->broker.address.hostname, &client->config->host), goto _mqtt_set_config_failed); - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->broker.address.path, &client->config->path), goto _mqtt_set_config_failed); - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->credentials.username, &client->connect_info.username), goto _mqtt_set_config_failed); - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->credentials.authentication.password, &client->connect_info.password), goto _mqtt_set_config_failed); - - if (!config->credentials.set_null_client_id) { - if (config->credentials.client_id) { - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->credentials.client_id, &client->connect_info.client_id), goto _mqtt_set_config_failed); - } else if (client->connect_info.client_id == NULL) { - client->connect_info.client_id = platform_create_id_string(); - } - ESP_MEM_CHECK(TAG, client->connect_info.client_id, goto _mqtt_set_config_failed); - ESP_LOGD(TAG, "MQTT client_id=%s", client->connect_info.client_id); - } - - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->broker.address.uri, &client->config->uri), goto _mqtt_set_config_failed); - ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->session.last_will.topic, &client->connect_info.will_topic), goto _mqtt_set_config_failed); - - if (config->session.last_will.msg_len && config->session.last_will.msg) { - free(client->connect_info.will_message); - client->connect_info.will_message = malloc(config->session.last_will.msg_len); - ESP_MEM_CHECK(TAG, client->connect_info.will_message, goto _mqtt_set_config_failed); - memcpy(client->connect_info.will_message, config->session.last_will.msg, config->session.last_will.msg_len); - client->connect_info.will_length = config->session.last_will.msg_len; - } else if (config->session.last_will.msg) { - free(client->connect_info.will_message); - client->connect_info.will_message = strdup(config->session.last_will.msg); - ESP_MEM_CHECK(TAG, client->connect_info.will_message, goto _mqtt_set_config_failed); - client->connect_info.will_length = strlen(config->session.last_will.msg); - } - if (config->session.last_will.qos) { - client->connect_info.will_qos = config->session.last_will.qos; - } - if (config->session.last_will.retain) { - client->connect_info.will_retain = config->session.last_will.retain; - } - - if (config->session.disable_clean_session == client->connect_info.clean_session) { - client->connect_info.clean_session = !config->session.disable_clean_session; - if (!client->connect_info.clean_session && config->credentials.set_null_client_id) { - ESP_LOGE(TAG, "Clean Session flag must be true if client has a null id"); - } - } - if (config->session.keepalive) { - client->connect_info.keepalive = config->session.keepalive; - } - if (client->connect_info.keepalive == 0) { - client->connect_info.keepalive = MQTT_KEEPALIVE_TICK; - } - if (config->session.disable_keepalive) { - // internal `keepalive` value (in connect_info) is in line with 3.1.2.10 Keep Alive from mqtt spec: - // * keepalive=0: Keep alive mechanism disabled (server not to disconnect the client on its inactivity) - // * period in seconds to send a Control packet if inactive - client->connect_info.keepalive = 0; - } - - if (config->session.protocol_ver) { - client->connect_info.protocol_ver = config->session.protocol_ver; - } - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_UNDEFINED) { -#ifdef MQTT_PROTOCOL_311 - client->connect_info.protocol_ver = MQTT_PROTOCOL_V_3_1_1; -#else - client->connect_info.protocol_ver = MQTT_PROTOCOL_V_3_1; -#endif - } else if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifndef MQTT_PROTOCOL_5 - ESP_LOGE(TAG, "Please first enable MQTT_PROTOCOL_5 feature in menuconfig"); - goto _mqtt_set_config_failed; -#endif - } - - client->config->network_timeout_ms = config->network.timeout_ms; - if (client->config->network_timeout_ms <= 0) { - client->config->network_timeout_ms = MQTT_NETWORK_TIMEOUT_MS; - } - - if (config->network.refresh_connection_after_ms) { - client->config->refresh_connection_after_ms = config->network.refresh_connection_after_ms; - } - - client->config->auto_reconnect = true; - if (config->network.disable_auto_reconnect == client->config->auto_reconnect) { - client->config->auto_reconnect = !config->network.disable_auto_reconnect; - } - - if (config->network.reconnect_timeout_ms) { - client->config->reconnect_timeout_ms = config->network.reconnect_timeout_ms; - } else { - client->config->reconnect_timeout_ms = MQTT_RECON_DEFAULT_MS; - } - - if (config->broker.verification.alpn_protos) { - for (int i = 0; i < client->config->num_alpn_protos; i++) { - free(client->config->alpn_protos[i]); - } - free(client->config->alpn_protos); - client->config->num_alpn_protos = 0; - - const char **p; - - for (p = config->broker.verification.alpn_protos; *p != NULL; p++ ) { - client->config->num_alpn_protos++; - } - // mbedTLS expects the list to be null-terminated - client->config->alpn_protos = calloc(client->config->num_alpn_protos + 1, sizeof(*config->broker.verification.alpn_protos)); - ESP_MEM_CHECK(TAG, client->config->alpn_protos, goto _mqtt_set_config_failed); - - for (int i = 0; i < client->config->num_alpn_protos; i++) { - client->config->alpn_protos[i] = strdup(config->broker.verification.alpn_protos[i]); - ESP_MEM_CHECK(TAG, client->config->alpn_protos[i], goto _mqtt_set_config_failed); - } - } - - // configure ssl related parameters - client->config->use_global_ca_store = config->broker.verification.use_global_ca_store; - client->config->cacert_buf = config->broker.verification.certificate; - client->config->cacert_bytes = config->broker.verification.certificate_len; - client->config->psk_hint_key = config->broker.verification.psk_hint_key; - client->config->crt_bundle_attach = config->broker.verification.crt_bundle_attach; - client->config->clientcert_buf = config->credentials.authentication.certificate; - client->config->clientcert_bytes = config->credentials.authentication.certificate_len; - client->config->clientkey_buf = config->credentials.authentication.key; - client->config->clientkey_bytes = config->credentials.authentication.key_len; - client->config->skip_cert_common_name_check = config->broker.verification.skip_cert_common_name_check; - client->config->use_secure_element = config->credentials.authentication.use_secure_element; - client->config->ds_data = config->credentials.authentication.ds_data; - - if (config->credentials.authentication.key_password && config->credentials.authentication.key_password_len) { - client->config->clientkey_password_len = config->credentials.authentication.key_password_len; - client->config->clientkey_password = malloc(client->config->clientkey_password_len); - ESP_MEM_CHECK(TAG, client->config->clientkey_password, goto _mqtt_set_config_failed); - memcpy(client->config->clientkey_password, config->credentials.authentication.key_password, client->config->clientkey_password_len); - } - - if (config->broker.address.transport) { - free(client->config->scheme); - client->config->scheme = NULL; - if (config->broker.address.transport == MQTT_TRANSPORT_OVER_TCP) { - client->config->scheme = create_string(MQTT_OVER_TCP_SCHEME, strlen(MQTT_OVER_TCP_SCHEME)); - ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_set_config_failed); - } -#if MQTT_ENABLE_WS - else if (config->broker.address.transport == MQTT_TRANSPORT_OVER_WS) { - client->config->scheme = create_string(MQTT_OVER_WS_SCHEME, strlen(MQTT_OVER_WS_SCHEME)); - ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_set_config_failed); - } -#endif -#if MQTT_ENABLE_SSL - else if (config->broker.address.transport == MQTT_TRANSPORT_OVER_SSL) { - client->config->scheme = create_string(MQTT_OVER_SSL_SCHEME, strlen(MQTT_OVER_SSL_SCHEME)); - ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_set_config_failed); - } -#endif -#if MQTT_ENABLE_WSS - else if (config->broker.address.transport == MQTT_TRANSPORT_OVER_WSS) { - client->config->scheme = create_string(MQTT_OVER_WSS_SCHEME, strlen(MQTT_OVER_WSS_SCHEME)); - ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_set_config_failed); - } -#endif - } - - // Set uri at the end of config to override separately configured uri elements - if (config->broker.address.uri) { - if (esp_mqtt_client_set_uri(client, client->config->uri) != ESP_OK) { - err = ESP_FAIL; - goto _mqtt_set_config_failed; - } - } - esp_err_t config_has_conflict = esp_mqtt_check_cfg_conflict(client->config, config); - - MQTT_API_UNLOCK(client); - - return config_has_conflict; -_mqtt_set_config_failed: - esp_mqtt_destroy_config(client); - MQTT_API_UNLOCK(client); - return err; -} - -void esp_mqtt_destroy_config(esp_mqtt_client_handle_t client) -{ - if (client->config == NULL) { - return; - } - free(client->config->host); - free(client->config->uri); - free(client->config->path); - free(client->config->scheme); - for (int i = 0; i < client->config->num_alpn_protos; i++) { - free(client->config->alpn_protos[i]); - } - free(client->config->alpn_protos); - free(client->config->clientkey_password); - free(client->connect_info.will_topic); - free(client->connect_info.will_message); - free(client->connect_info.client_id); - free(client->connect_info.username); - free(client->connect_info.password); -#ifdef MQTT_PROTOCOL_5 - esp_mqtt5_client_destory(client); -#endif - memset(&client->connect_info, 0, sizeof(mqtt_connect_info_t)); -#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP - if (client->config->event_loop_handle) { - esp_event_loop_delete(client->config->event_loop_handle); - } -#endif - memset(client->config, 0, sizeof(mqtt_config_storage_t)); - free(client->config); - client->config = NULL; -} - -static inline bool has_timed_out(uint64_t last_tick, uint64_t timeout) -{ - uint64_t next = last_tick + timeout; - return (int64_t)(next - platform_tick_get_ms()) <= 0; -} - -static esp_err_t process_keepalive(esp_mqtt_client_handle_t client) -{ - if (client->connect_info.keepalive > 0) { - const uint64_t keepalive_ms = client->connect_info.keepalive * 1000; - - if (client->wait_for_ping_resp == true ) { - if (has_timed_out(client->keepalive_tick, keepalive_ms)) { - ESP_LOGE(TAG, "No PING_RESP, disconnected"); - esp_mqtt_abort_connection(client); - client->wait_for_ping_resp = false; - return ESP_FAIL; - } - return ESP_OK; - } - - if (has_timed_out(client->keepalive_tick, keepalive_ms / 2)) { - if (esp_mqtt_client_ping(client) == ESP_FAIL) { - ESP_LOGE(TAG, "Can't send ping, disconnected"); - esp_mqtt_abort_connection(client); - return ESP_FAIL; - } - client->wait_for_ping_resp = true; - return ESP_OK; - } - } - return ESP_OK; -} - -static inline esp_err_t esp_mqtt_write(esp_mqtt_client_handle_t client) -{ - int wlen = 0, widx = 0, len = client->mqtt_state.outbound_message->length; - while (len > 0) { - wlen = esp_transport_write(client->transport, - (char *)client->mqtt_state.outbound_message->data + widx, - len, - client->config->network_timeout_ms); - if (wlen < 0) { - ESP_LOGE(TAG, "Writing failed: errno=%d", errno); - esp_mqtt_client_dispatch_transport_error(client); - return ESP_FAIL; - } - - if (wlen == 0) { - ESP_LOGE(TAG, "Writing didn't complete in specified timeout: errno=%d", errno); - return ESP_ERR_TIMEOUT; - } - widx += wlen; - len -= wlen; - } - return ESP_OK; -} - -static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms) -{ - int read_len, connect_rsp_code = 0; - client->wait_for_ping_resp = false; - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->mqtt_state.outbound_message = mqtt5_msg_connect(&client->mqtt_state.mqtt_connection, - &client->connect_info, &client->mqtt5_config->connect_property_info, &client->mqtt5_config->will_property_info); -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, - &client->connect_info); - } - if (client->mqtt_state.outbound_message->length == 0) { - ESP_LOGE(TAG, "Connect message cannot be created"); - return ESP_FAIL; - } - - client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->mqtt_state.pending_msg_id = mqtt5_get_id(client->mqtt_state.outbound_message->data, - client->mqtt_state.outbound_message->length); -#endif - } else { - client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, - client->mqtt_state.outbound_message->length); - } - ESP_LOGD(TAG, "Sending MQTT CONNECT message, type: %d, id: %04X", - client->mqtt_state.pending_msg_type, - client->mqtt_state.pending_msg_id); - - if (esp_mqtt_write(client) != ESP_OK) { - return ESP_FAIL; - } - - client->mqtt_state.in_buffer_read_len = 0; - client->mqtt_state.message_length = 0; - - /* wait configured network timeout for broker connection response */ - uint64_t connack_recv_started = platform_tick_get_ms(); - do { - read_len = mqtt_message_receive(client, client->config->network_timeout_ms); - } while (read_len == 0 && platform_tick_get_ms() - connack_recv_started < client->config->network_timeout_ms); - - if (read_len <= 0) { - ESP_LOGE(TAG, "%s: mqtt_message_receive() returned %d", __func__, read_len); - return ESP_FAIL; - } - - if (mqtt_get_type(client->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK) { - ESP_LOGE(TAG, "Invalid MSG_TYPE response: %d, read_len: %d", mqtt_get_type(client->mqtt_state.in_buffer), read_len); - return ESP_FAIL; - } - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - if (esp_mqtt5_parse_connack(client, &connect_rsp_code) == ESP_OK) { - client->send_publish_packet_count = 0; - return ESP_OK; - } -#endif - } else { - client->mqtt_state.in_buffer_read_len = 0; - connect_rsp_code = mqtt_get_connect_return_code(client->mqtt_state.in_buffer); - if (connect_rsp_code == MQTT_CONNECTION_ACCEPTED) { - ESP_LOGD(TAG, "Connected"); - return ESP_OK; - } - switch (connect_rsp_code) { - case MQTT_CONNECTION_REFUSE_PROTOCOL: - ESP_LOGW(TAG, "Connection refused, bad protocol"); - break; - case MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE: - ESP_LOGW(TAG, "Connection refused, server unavailable"); - break; - case MQTT_CONNECTION_REFUSE_BAD_USERNAME: - ESP_LOGW(TAG, "Connection refused, bad username or password"); - break; - case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED: - ESP_LOGW(TAG, "Connection refused, not authorized"); - break; - default: - ESP_LOGW(TAG, "Connection refused, Unknow reason"); - break; - } - } - /* propagate event with connection refused error */ - client->event.event_id = MQTT_EVENT_ERROR; - client->event.error_handle->error_type = MQTT_ERROR_TYPE_CONNECTION_REFUSED; - client->event.error_handle->connect_return_code = connect_rsp_code; - client->event.error_handle->esp_tls_stack_err = 0; - client->event.error_handle->esp_tls_last_esp_err = 0; - client->event.error_handle->esp_tls_cert_verify_flags = 0; - esp_mqtt_dispatch_event_with_msgid(client); - - return ESP_FAIL; -} - -static void esp_mqtt_abort_connection(esp_mqtt_client_handle_t client) -{ - MQTT_API_LOCK(client); - esp_transport_close(client->transport); - client->wait_timeout_ms = client->config->reconnect_timeout_ms; - client->reconnect_tick = platform_tick_get_ms(); - client->state = MQTT_STATE_WAIT_RECONNECT; - ESP_LOGD(TAG, "Reconnect after %d ms", client->wait_timeout_ms); - client->event.event_id = MQTT_EVENT_DISCONNECTED; - client->wait_for_ping_resp = false; - esp_mqtt_dispatch_event_with_msgid(client); - MQTT_API_UNLOCK(client); -} - -static bool create_client_data(esp_mqtt_client_handle_t client) -{ - client->event.error_handle = calloc(1, sizeof(esp_mqtt_error_codes_t)); - ESP_MEM_CHECK(TAG, client->event.error_handle, return false) - - client->api_lock = xSemaphoreCreateRecursiveMutex(); - ESP_MEM_CHECK(TAG, client->api_lock, return false); - - return true; -} - -esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config) -{ - esp_mqtt_client_handle_t client = heap_caps_calloc(1, sizeof(struct esp_mqtt_client), -#if MQTT_EVENT_QUEUE_SIZE > 1 - // if supporting multiple queued events, we keep track of them - // using atomic variable, so need to make sure it won't get allocated in PSRAM - MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); -#else - MALLOC_CAP_DEFAULT); -#endif - ESP_MEM_CHECK(TAG, client, return NULL); - if (!create_client_data(client)) { - goto _mqtt_init_failed; - } - - if (esp_mqtt_set_config(client, config) != ESP_OK) { - goto _mqtt_init_failed; - } -#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP - esp_event_loop_args_t no_task_loop = { - .queue_size = MQTT_EVENT_QUEUE_SIZE, - .task_name = NULL, - }; - esp_event_loop_create(&no_task_loop, &client->config->event_loop_handle); -#if MQTT_EVENT_QUEUE_SIZE > 1 - atomic_init(&client->queued_events, 0); -#endif -#endif - - client->keepalive_tick = platform_tick_get_ms(); - client->reconnect_tick = platform_tick_get_ms(); - client->refresh_connection_tick = platform_tick_get_ms(); - client->wait_for_ping_resp = false; - int buffer_size = config->buffer.size; - if (buffer_size <= 0) { - buffer_size = MQTT_BUFFER_SIZE_BYTE; - } - // use separate value for output buffer size if configured - int out_buffer_size = config->buffer.out_size > 0 ? config->buffer.out_size : buffer_size; - - client->mqtt_state.in_buffer = (uint8_t *)malloc(buffer_size); - ESP_MEM_CHECK(TAG, client->mqtt_state.in_buffer, goto _mqtt_init_failed); - client->mqtt_state.in_buffer_length = buffer_size; - client->mqtt_state.out_buffer = (uint8_t *)malloc(out_buffer_size); - ESP_MEM_CHECK(TAG, client->mqtt_state.out_buffer, goto _mqtt_init_failed); - - client->mqtt_state.out_buffer_length = out_buffer_size; - client->outbox = outbox_init(); - ESP_MEM_CHECK(TAG, client->outbox, goto _mqtt_init_failed); - client->status_bits = xEventGroupCreate(); - ESP_MEM_CHECK(TAG, client->status_bits, goto _mqtt_init_failed); - - mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, - client->mqtt_state.out_buffer_length); -#ifdef MQTT_PROTOCOL_5 - if (esp_mqtt5_create_default_config(client) != ESP_OK) { - goto _mqtt_init_failed; - } -#endif - return client; -_mqtt_init_failed: - esp_mqtt_client_destroy(client); - return NULL; -} - -esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client) -{ - if (client == NULL) { - return ESP_ERR_INVALID_ARG; - } - if (client->api_lock) { - esp_mqtt_client_stop(client); - } - esp_mqtt_destroy_config(client); - if (client->transport_list) { - esp_transport_list_destroy(client->transport_list); - } - if (client->outbox) { - outbox_destroy(client->outbox); - } - if (client->status_bits) { - vEventGroupDelete(client->status_bits); - } - free(client->mqtt_state.in_buffer); - free(client->mqtt_state.out_buffer); - if (client->api_lock) { - vSemaphoreDelete(client->api_lock); - } - free(client->event.error_handle); - free(client); - return ESP_OK; -} - -static char *create_string(const char *ptr, int len) -{ - char *ret; - if (len <= 0) { - return NULL; - } - ret = calloc(1, len + 1); - ESP_MEM_CHECK(TAG, ret, return NULL); - memcpy(ret, ptr, len); - return ret; -} - -esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *uri) -{ - struct http_parser_url puri; - http_parser_url_init(&puri); - int parser_status = http_parser_parse_url(uri, strlen(uri), 0, &puri); - if (parser_status != 0) { - ESP_LOGE(TAG, "Error parse uri = %s", uri); - return ESP_FAIL; - } - - // This API could be also executed when client is active (need to protect config fields) - MQTT_API_LOCK(client); - // set uri overrides actual scheme, host, path if configured previously - free(client->config->scheme); - free(client->config->host); - free(client->config->path); - - client->config->scheme = create_string(uri + puri.field_data[UF_SCHEMA].off, puri.field_data[UF_SCHEMA].len); - client->config->host = create_string(uri + puri.field_data[UF_HOST].off, puri.field_data[UF_HOST].len); - client->config->path = NULL; - - if (puri.field_data[UF_PATH].len || puri.field_data[UF_QUERY].len) { - if (puri.field_data[UF_QUERY].len == 0) { - asprintf(&client->config->path, "%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off); - } else if (puri.field_data[UF_PATH].len == 0) { - asprintf(&client->config->path, "/?%.*s", puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off); - } else { - asprintf(&client->config->path, "%.*s?%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off, - puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off); - } - ESP_MEM_CHECK(TAG, client->config->path, { - MQTT_API_UNLOCK(client); - return ESP_ERR_NO_MEM; - }); - } - - if (puri.field_data[UF_PORT].len) { - client->config->port = strtol((const char *)(uri + puri.field_data[UF_PORT].off), NULL, 10); - } - - char *user_info = create_string(uri + puri.field_data[UF_USERINFO].off, puri.field_data[UF_USERINFO].len); - if (user_info) { - char *pass = strchr(user_info, ':'); - if (pass) { - pass[0] = 0; //terminal username - pass ++; - client->connect_info.password = strdup(pass); - } - client->connect_info.username = strdup(user_info); - - free(user_info); - } - - MQTT_API_UNLOCK(client); - return ESP_OK; -} - - -static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client) -{ - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->event.msg_id = mqtt5_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); -#endif - } else { - client->event.msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); - } - return esp_mqtt_dispatch_event(client); -} - -esp_err_t esp_mqtt_dispatch_custom_event(esp_mqtt_client_handle_t client, esp_mqtt_event_t *event) -{ - esp_err_t ret = esp_event_post_to(client->config->event_loop_handle, MQTT_EVENTS, MQTT_USER_EVENT, event, sizeof(*event), 0); -#if MQTT_EVENT_QUEUE_SIZE > 1 - if (ret == ESP_OK) { - atomic_fetch_add(&client->queued_events, 1); - } -#endif - return ret; -} - -static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) -{ - client->event.client = client; - client->event.protocol_ver = client->connect_info.protocol_ver; - esp_err_t ret = ESP_FAIL; - - if (client->config->event_handle) { - ret = client->config->event_handle(&client->event); - } else { -#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP - esp_event_post_to(client->config->event_loop_handle, MQTT_EVENTS, client->event.event_id, &client->event, sizeof(client->event), portMAX_DELAY); - ret = esp_event_loop_run(client->config->event_loop_handle, 0); -#else - return ESP_FAIL; -#endif - } - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - esp_mqtt5_client_delete_user_property(client->event.property->user_property); - client->event.property->user_property = NULL; -#endif - } - return ret; -} - -static esp_err_t deliver_publish(esp_mqtt_client_handle_t client) -{ - uint8_t *msg_buf = client->mqtt_state.in_buffer; - size_t msg_read_len = client->mqtt_state.in_buffer_read_len; - size_t msg_total_len = client->mqtt_state.message_length; - size_t msg_topic_len = msg_read_len, msg_data_len = msg_read_len; - size_t msg_data_offset = 0; - char *msg_topic = NULL, *msg_data = NULL; - - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - if (esp_mqtt5_get_publish_data(client, msg_buf, msg_read_len, &msg_topic, &msg_topic_len, &msg_data, &msg_data_len) != ESP_OK) { - ESP_LOGE(TAG, "%s: esp_mqtt5_get_publish_data() failed", __func__); - return ESP_FAIL; - } -#endif - } else { - // get topic - msg_topic = mqtt_get_publish_topic(msg_buf, &msg_topic_len); - if (msg_topic == NULL) { - ESP_LOGE(TAG, "%s: mqtt_get_publish_topic() failed", __func__); - return ESP_FAIL; - } - ESP_LOGD(TAG, "%s: msg_topic_len=%"PRIu32, __func__, msg_topic_len); - - // get payload - msg_data = mqtt_get_publish_data(msg_buf, &msg_data_len); - if (msg_data_len > 0 && msg_data == NULL) { - ESP_LOGE(TAG, "%s: mqtt_get_publish_data() failed", __func__); - return ESP_FAIL; - } - } - // post data event - client->event.retain = mqtt_get_retain(msg_buf); - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->event.msg_id = mqtt5_get_id(msg_buf, msg_read_len); -#endif - } else { - client->event.msg_id = mqtt_get_id(msg_buf, msg_read_len); - } - client->event.qos = mqtt_get_qos(msg_buf); - client->event.dup = mqtt_get_dup(msg_buf); - client->event.total_data_len = msg_data_len + msg_total_len - msg_read_len; -post_data_event: - ESP_LOGD(TAG, "Get data len= %"PRIu32", topic len=%"PRIu32", total_data: %d offset: %"PRIu32, msg_data_len, msg_topic_len, - client->event.total_data_len, msg_data_offset); - client->event.event_id = MQTT_EVENT_DATA; - client->event.data = msg_data_len > 0 ? msg_data : NULL; - client->event.data_len = msg_data_len; - client->event.current_data_offset = msg_data_offset; - client->event.topic = msg_topic; - client->event.topic_len = msg_topic_len; - esp_mqtt_dispatch_event(client); - - if (msg_read_len < msg_total_len) { - size_t buf_len = client->mqtt_state.in_buffer_length; - - msg_data = (char *)client->mqtt_state.in_buffer; - msg_topic = NULL; - msg_topic_len = 0; - msg_data_offset += msg_data_len; - int ret = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, - msg_total_len - msg_read_len > buf_len ? buf_len : msg_total_len - msg_read_len, - client->config->network_timeout_ms); - if (ret <= 0) { - return esp_mqtt_handle_transport_read_error(ret, client) == 0 ? ESP_OK : ESP_FAIL; - } - - msg_data_len = ret; - msg_read_len += msg_data_len; - goto post_data_event; - } - return ESP_OK; -} - -static esp_err_t deliver_suback(esp_mqtt_client_handle_t client) -{ - uint8_t *msg_buf = client->mqtt_state.in_buffer; - size_t msg_data_len = client->mqtt_state.in_buffer_read_len; - char *msg_data = NULL; - - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - msg_data = mqtt5_get_suback_data(msg_buf, &msg_data_len, &client->event.property->user_property); -#else - // SUBACK Using MQTT5 received but MQTT5 is disabled, This is unlikely to happen. - return ESP_FAIL; -#endif - } else { - msg_data = mqtt_get_suback_data(msg_buf, &msg_data_len); - } - if (msg_data_len <= 0) { - ESP_LOGE(TAG, "Failed to acquire suback data"); - return ESP_FAIL; - } - client->event.error_handle->esp_tls_stack_err = 0; - client->event.error_handle->esp_tls_last_esp_err = 0; - client->event.error_handle->esp_tls_cert_verify_flags = 0; - client->event.error_handle->error_type = MQTT_ERROR_TYPE_NONE; - client->event.error_handle->connect_return_code = MQTT_CONNECTION_ACCEPTED; - // post data event - for (int topic = 0; topic < msg_data_len; ++topic) { - if ((uint8_t)msg_data[topic] == 0x80) { - client->event.error_handle->error_type = MQTT_ERROR_TYPE_SUBSCRIBE_FAILED; - break; - } - } - client->event.data_len = msg_data_len; - client->event.total_data_len = msg_data_len; - client->event.event_id = MQTT_EVENT_SUBSCRIBED; - client->event.data = msg_data; - client->event.current_data_offset = 0; - esp_mqtt_dispatch_event_with_msgid(client); - - return ESP_OK; -} - -// Deletes the initial message in MQTT communication protocol -// Return false when message is not found, making the received counterpart invalid. -static bool remove_initiator_message(esp_mqtt_client_handle_t client, int msg_type, int msg_id) -{ - if (outbox_delete(client->outbox, msg_id, msg_type) == ESP_OK) { - ESP_LOGD(TAG, "Removed pending_id=%d", client->mqtt_state.pending_msg_id); - return true; - } - - ESP_LOGD(TAG, "Failed to remove pending_id=%d", client->mqtt_state.pending_msg_id); - return false; -} - -static outbox_item_handle_t mqtt_enqueue(esp_mqtt_client_handle_t client, uint8_t *remaining_data, int remaining_len) -{ - ESP_LOGD(TAG, "mqtt_enqueue id: %d, type=%d successful", - client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_type); - outbox_message_t msg = { 0 }; - msg.data = client->mqtt_state.outbound_message->data; - msg.len = client->mqtt_state.outbound_message->length; - msg.msg_id = client->mqtt_state.pending_msg_id; - msg.msg_type = client->mqtt_state.pending_msg_type; - msg.msg_qos = client->mqtt_state.pending_publish_qos; - msg.remaining_data = remaining_data; - msg.remaining_len = remaining_len; - //Copy to queue buffer - return outbox_enqueue(client->outbox, &msg, platform_tick_get_ms()); -} - - -/* - * Returns: - * -1 in case of failure - * 0 if no message has been received - * 1 if a message has been received and placed to client->mqtt_state: - * message length: client->mqtt_state.message_length - * message content: client->mqtt_state.in_buffer - */ -static int mqtt_message_receive(esp_mqtt_client_handle_t client, int read_poll_timeout_ms) -{ - int read_len, total_len, fixed_header_len; - uint8_t *buf = client->mqtt_state.in_buffer + client->mqtt_state.in_buffer_read_len; - esp_transport_handle_t t = client->transport; - - client->mqtt_state.message_length = 0; - if (client->mqtt_state.in_buffer_read_len == 0) { - /* - * Read first byte of the mqtt packet fixed header, it contains packet - * type and flags. - */ - read_len = esp_transport_read(t, (char *)buf, 1, read_poll_timeout_ms); - if (read_len <= 0) { - return esp_mqtt_handle_transport_read_error(read_len, client); - } - ESP_LOGD(TAG, "%s: first byte: 0x%x", __func__, *buf); - /* - * Verify the flags and act according to MQTT protocol: close connection - * if the flags are set incorrectly. - */ - if (!mqtt_has_valid_msg_hdr(buf, read_len)) { - ESP_LOGE(TAG, "%s: received a message with an invalid header=0x%x", __func__, *buf); - goto err; - } - buf++; - client->mqtt_state.in_buffer_read_len++; - } - if ((client->mqtt_state.in_buffer_read_len == 1) || - ((client->mqtt_state.in_buffer_read_len < 6) && (*(buf - 1) & 0x80))) { - do { - /* - * Read the "remaining length" part of mqtt packet fixed header. It - * starts at second byte and spans up to 4 bytes, but we accept here - * only up to 2 bytes of remaining length, i.e. messages with - * maximal remaining length value = 16383 (maximal total message - * size of 16386 bytes). - */ - read_len = esp_transport_read(t, (char *)buf, 1, read_poll_timeout_ms); - if (read_len <= 0) { - return esp_mqtt_handle_transport_read_error(read_len, client); - } - ESP_LOGD(TAG, "%s: read \"remaining length\" byte: 0x%x", __func__, *buf); - buf++; - client->mqtt_state.in_buffer_read_len++; - } while ((client->mqtt_state.in_buffer_read_len < 6) && (*(buf - 1) & 0x80)); - } - total_len = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len, &fixed_header_len); - ESP_LOGD(TAG, "%s: total message length: %d (already read: %"PRIu32")", __func__, total_len, client->mqtt_state.in_buffer_read_len); - client->mqtt_state.message_length = total_len; - if (client->mqtt_state.in_buffer_length < total_len) { - if (mqtt_get_type(client->mqtt_state.in_buffer) == MQTT_MSG_TYPE_PUBLISH) { - /* - * In case larger publish messages, we only need to read full topic, data can be split to multiple data event. - * Evaluate and correct total_len to read only publish message header, so data can be read separately - */ - if (client->mqtt_state.in_buffer_read_len < fixed_header_len + 2) { - /* read next 2 bytes - topic length to get minimum portion of publish packet */ - read_len = esp_transport_read(t, (char *)buf, client->mqtt_state.in_buffer_read_len - fixed_header_len + 2, read_poll_timeout_ms); - ESP_LOGD(TAG, "%s: read_len=%d", __func__, read_len); - if (read_len <= 0) { - return esp_mqtt_handle_transport_read_error(read_len, client); - } - client->mqtt_state.in_buffer_read_len += read_len; - buf += read_len; - if (client->mqtt_state.in_buffer_read_len < fixed_header_len + 2) { - ESP_LOGD(TAG, "%s: transport_read(): message reading left in progress :: total message length: %d (already read: %"PRIu32")", - __func__, total_len, client->mqtt_state.in_buffer_read_len); - return 0; - } - } - int topic_len = client->mqtt_state.in_buffer[fixed_header_len] << 8; - topic_len |= client->mqtt_state.in_buffer[fixed_header_len + 1]; - total_len = fixed_header_len + topic_len + (mqtt_get_qos(client->mqtt_state.in_buffer) > 0 ? 2 : 0); - ESP_LOGD(TAG, "%s: total len modified to %d as message longer than input buffer", __func__, total_len); - if (client->mqtt_state.in_buffer_length < total_len) { - ESP_LOGE(TAG, "%s: message is too big, insufficient buffer size", __func__); - goto err; - } else { - total_len = client->mqtt_state.in_buffer_length; - } - /* free to continue with reading */ - } else { - ESP_LOGE(TAG, "%s: message is too big, insufficient buffer size", __func__); - goto err; - } - } - if (client->mqtt_state.in_buffer_read_len < total_len) { - /* read the rest of the mqtt message */ - read_len = esp_transport_read(t, (char *)buf, total_len - client->mqtt_state.in_buffer_read_len, read_poll_timeout_ms); - ESP_LOGD(TAG, "%s: read_len=%d", __func__, read_len); - if (read_len <= 0) { - return esp_mqtt_handle_transport_read_error(read_len, client); - } - client->mqtt_state.in_buffer_read_len += read_len; - if (client->mqtt_state.in_buffer_read_len < total_len) { - ESP_LOGD(TAG, "%s: transport_read(): message reading left in progress :: total message length: %d (already read: %"PRIu32")", - __func__, total_len, client->mqtt_state.in_buffer_read_len); - return 0; - } - } - ESP_LOGD(TAG, "%s: transport_read():%"PRIu32" %"PRIu32, __func__, client->mqtt_state.in_buffer_read_len, client->mqtt_state.message_length); - return 1; -err: - esp_mqtt_client_dispatch_transport_error(client); - return -1; -} - -static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) -{ - uint8_t msg_type = 0, msg_qos = 0; - uint16_t msg_id = 0; - - /* non-blocking receive in order not to block other tasks */ - int recv = mqtt_message_receive(client, 0); - if (recv < 0) { - ESP_LOGE(TAG, "%s: mqtt_message_receive() returned %d", __func__, recv); - return ESP_FAIL; - } - if (recv == 0) { - return ESP_OK; - } - int read_len = client->mqtt_state.message_length; - - // If the message was valid, get the type, quality of service and id of the message - msg_type = mqtt_get_type(client->mqtt_state.in_buffer); - msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer); - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - msg_id = mqtt5_get_id(client->mqtt_state.in_buffer, read_len); -#endif - } else { - msg_id = mqtt_get_id(client->mqtt_state.in_buffer, read_len); - } - - ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); - - switch (msg_type) { - case MQTT_MSG_TYPE_SUBACK: - if (remove_initiator_message(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { -#ifdef MQTT_PROTOCOL_5 - esp_mqtt5_parse_suback(client); -#endif - ESP_LOGD(TAG, "deliver_suback, message_length_read=%"PRIu32", message_length=%"PRIu32, client->mqtt_state.in_buffer_read_len, client->mqtt_state.message_length); - if (deliver_suback(client) != ESP_OK) { - ESP_LOGE(TAG, "Failed to deliver suback message id=%d", msg_id); - return ESP_FAIL; - } - } - break; - case MQTT_MSG_TYPE_UNSUBACK: - if (remove_initiator_message(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { -#ifdef MQTT_PROTOCOL_5 - esp_mqtt5_parse_unsuback(client); -#endif - ESP_LOGD(TAG, "UnSubscribe successful"); - client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PUBLISH: - ESP_LOGD(TAG, "deliver_publish, message_length_read=%"PRIu32", message_length=%"PRIu32, client->mqtt_state.in_buffer_read_len, client->mqtt_state.message_length); - if (deliver_publish(client) != ESP_OK) { - ESP_LOGE(TAG, "Failed to deliver publish message id=%d", msg_id); - return ESP_FAIL; - } - if (msg_qos == 1) { - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->mqtt_state.outbound_message = mqtt5_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); - } - } else if (msg_qos == 2) { - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->mqtt_state.outbound_message = mqtt5_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); - } - } - if (client->mqtt_state.outbound_message->length == 0) { - ESP_LOGE(TAG, "Publish response message PUBACK or PUBREC cannot be created"); - return ESP_FAIL; - } - - if (msg_qos == 1 || msg_qos == 2) { - ESP_LOGD(TAG, "Queue response QoS: %d", msg_qos); - - if (esp_mqtt_write(client) != ESP_OK) { - ESP_LOGE(TAG, "Error write qos msg repsonse, qos = %d", msg_qos); - return ESP_FAIL; - } - } - break; - case MQTT_MSG_TYPE_PUBACK: -#ifdef MQTT_PROTOCOL_5 - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - esp_mqtt5_decrement_packet_counter(client); - } -#endif - if (remove_initiator_message(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); -#ifdef MQTT_PROTOCOL_5 - esp_mqtt5_parse_puback(client); -#endif - client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PUBREC: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBREC return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); - client->mqtt_state.outbound_message = mqtt5_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); - } - if (client->mqtt_state.outbound_message->length == 0) { - ESP_LOGE(TAG, "Publish response message PUBREL cannot be created"); - return ESP_FAIL; - } - - outbox_set_pending(client->outbox, msg_id, ACKNOWLEDGED); - esp_mqtt_write(client); - break; - case MQTT_MSG_TYPE_PUBREL: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBREL return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); - client->mqtt_state.outbound_message = mqtt5_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); - } - if (client->mqtt_state.outbound_message->length == 0) { - ESP_LOGE(TAG, "Publish response message PUBCOMP cannot be created"); - return ESP_FAIL; - } - - esp_mqtt_write(client); - break; - case MQTT_MSG_TYPE_PUBCOMP: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); -#ifdef MQTT_PROTOCOL_5 - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - esp_mqtt5_decrement_packet_counter(client); - } -#endif - if (remove_initiator_message(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { - ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); -#ifdef MQTT_PROTOCOL_5 - esp_mqtt5_parse_pubcomp(client); -#endif - client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PINGRESP: - ESP_LOGD(TAG, "MQTT_MSG_TYPE_PINGRESP"); - client->wait_for_ping_resp = false; - /* It is the responsibility of the Client to ensure that the interval between Control Packets - * being sent does not exceed the Keep Alive value. In the absence of sending any other Control - * Packets, the Client MUST send a PINGREQ Packet [MQTT-3.1.2-23]. - * [MQTT-3.1.2-23] - */ - client->keepalive_tick = platform_tick_get_ms(); - break; - } - - client->mqtt_state.in_buffer_read_len = 0; - return ESP_OK; -} - -static esp_err_t mqtt_resend_queued(esp_mqtt_client_handle_t client, outbox_item_handle_t item) -{ - // decode queued data - client->mqtt_state.outbound_message->data = outbox_item_get_data(item, &client->mqtt_state.outbound_message->length, &client->mqtt_state.pending_msg_id, - &client->mqtt_state.pending_msg_type, &client->mqtt_state.pending_publish_qos); - // set duplicate flag for QoS-1 and QoS-2 messages - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_publish_qos > 0 && (outbox_item_get_pending(item) == TRANSMITTED)) { - mqtt_set_dup(client->mqtt_state.outbound_message->data); - ESP_LOGD(TAG, "Sending Duplicated QoS%d message with id=%d", client->mqtt_state.pending_publish_qos, client->mqtt_state.pending_msg_id); - } - - // try to resend the data - if (esp_mqtt_write(client) != ESP_OK) { - ESP_LOGE(TAG, "Error to resend data "); - esp_mqtt_abort_connection(client); - return ESP_FAIL; - } - - // check if it was QoS-0 publish message - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH) { - if (client->mqtt_state.pending_publish_qos == 0) { - // delete all qos0 publish messages once we process them - if (outbox_delete_item(client->outbox, item) != ESP_OK) { - ESP_LOGE(TAG, "Failed to remove queued qos0 message from the outbox"); - } - } else if (client->mqtt_state.pending_publish_qos > 0) { -#ifdef MQTT_PROTOCOL_5 - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - esp_mqtt5_increment_packet_counter(client); - } -#endif - } - } - return ESP_OK; -} - -static void mqtt_delete_expired_messages(esp_mqtt_client_handle_t client) -{ - // Delete message after OUTBOX_EXPIRED_TIMEOUT_MS milliseconds -#if MQTT_REPORT_DELETED_MESSAGES - // also report the deleted items as MQTT_EVENT_DELETED events if enabled - int msg_id = 0; - while ((msg_id = outbox_delete_single_expired(client->outbox, platform_tick_get_ms(), OUTBOX_EXPIRED_TIMEOUT_MS)) > 0) { - client->event.event_id = MQTT_EVENT_DELETED; - client->event.msg_id = msg_id; - if (esp_mqtt_dispatch_event(client) != ESP_OK) { - ESP_LOGE(TAG, "Failed to post event on deleting message id=%d", msg_id); - } - } -#else - outbox_delete_expired(client->outbox, platform_tick_get_ms(), OUTBOX_EXPIRED_TIMEOUT_MS); -#endif -} - -/** - * @brief When using multiple queued item, we'd like to reduce the poll timeout to proceed with event loop exacution - */ -static inline int max_poll_timeout(esp_mqtt_client_handle_t client, int max_timeout) -{ - return -#if MQTT_EVENT_QUEUE_SIZE > 1 - atomic_load(&client->queued_events) > 0 ? 10 : max_timeout; -#else - max_timeout; -#endif -} - -static inline void run_event_loop(esp_mqtt_client_handle_t client) -{ -#if MQTT_EVENT_QUEUE_SIZE > 1 - if (atomic_load(&client->queued_events) > 0) { - atomic_fetch_sub(&client->queued_events, 1); -#else - { -#endif - esp_err_t ret = esp_event_loop_run(client->config->event_loop_handle, 0); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Error in running event_loop %d", ret); - } - } -} - -static void esp_mqtt_task(void *pv) -{ - esp_mqtt_client_handle_t client = (esp_mqtt_client_handle_t) pv; - uint64_t last_retransmit = 0; - outbox_tick_t msg_tick = 0; - client->run = true; - - //get transport by scheme - client->transport = esp_transport_list_get_transport(client->transport_list, client->config->scheme); - - if (client->transport == NULL) { - ESP_LOGE(TAG, "There are no transports valid, stop mqtt client, config scheme = %s", client->config->scheme); - client->run = false; - } - //default port - if (client->config->port == 0) { - client->config->port = esp_transport_get_default_port(client->transport); - } - - client->state = MQTT_STATE_INIT; - xEventGroupClearBits(client->status_bits, STOPPED_BIT); - while (client->run) { - MQTT_API_LOCK(client); - run_event_loop(client); - switch (client->state) { - case MQTT_STATE_DISCONNECTED: - break; - case MQTT_STATE_INIT: - xEventGroupClearBits(client->status_bits, RECONNECT_BIT | DISCONNECT_BIT); - client->event.event_id = MQTT_EVENT_BEFORE_CONNECT; - esp_mqtt_dispatch_event_with_msgid(client); - - if (client->transport == NULL) { - ESP_LOGE(TAG, "There is no transport"); - client->run = false; - } -#if MQTT_ENABLE_SSL - esp_mqtt_set_ssl_transport_properties(client->transport_list, client->config); -#endif - - if (esp_transport_connect(client->transport, - client->config->host, - client->config->port, - client->config->network_timeout_ms) < 0) { - ESP_LOGE(TAG, "Error transport connect"); - esp_mqtt_client_dispatch_transport_error(client); - esp_mqtt_abort_connection(client); - break; - } - ESP_LOGD(TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port); - if (esp_mqtt_connect(client, client->config->network_timeout_ms) != ESP_OK) { - ESP_LOGE(TAG, "MQTT connect failed"); - esp_mqtt_abort_connection(client); - break; - } - client->event.event_id = MQTT_EVENT_CONNECTED; - if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) { - client->event.session_present = mqtt_get_connect_session_present(client->mqtt_state.in_buffer); - } - client->state = MQTT_STATE_CONNECTED; - esp_mqtt_dispatch_event_with_msgid(client); - client->refresh_connection_tick = platform_tick_get_ms(); - client->keepalive_tick = platform_tick_get_ms(); - - break; - case MQTT_STATE_CONNECTED: - // check for disconnection request - if (xEventGroupWaitBits(client->status_bits, DISCONNECT_BIT, true, true, 0) & DISCONNECT_BIT) { - send_disconnect_msg(client); // ignore error, if clean disconnect fails, just abort the connection - esp_mqtt_abort_connection(client); - break; - } - // receive and process data - if (mqtt_process_receive(client) == ESP_FAIL) { - esp_mqtt_abort_connection(client); - break; - } - - // delete long pending messages - mqtt_delete_expired_messages(client); - - // resend all non-transmitted messages first - outbox_item_handle_t item = outbox_dequeue(client->outbox, QUEUED, NULL); - if (item) { - if (mqtt_resend_queued(client, item) == ESP_OK) { - outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED); - } - // resend other "transmitted" messages after 1s - } else if (has_timed_out(last_retransmit, client->config->message_retransmit_timeout)) { - last_retransmit = platform_tick_get_ms(); - item = outbox_dequeue(client->outbox, TRANSMITTED, &msg_tick); - if (item && (last_retransmit - msg_tick > client->config->message_retransmit_timeout)) { - mqtt_resend_queued(client, item); - } - } - - if (process_keepalive(client) != ESP_OK) { - break; - } - - if (client->config->refresh_connection_after_ms && - has_timed_out(client->refresh_connection_tick, client->config->refresh_connection_after_ms)) { - ESP_LOGD(TAG, "Refreshing the connection..."); - esp_mqtt_abort_connection(client); - client->state = MQTT_STATE_INIT; - } - - break; - case MQTT_STATE_WAIT_RECONNECT: - - if (!client->config->auto_reconnect && xEventGroupGetBits(client->status_bits)&RECONNECT_BIT) { - xEventGroupClearBits(client->status_bits, RECONNECT_BIT); - client->state = MQTT_STATE_INIT; - client->wait_timeout_ms = MQTT_RECON_DEFAULT_MS; - ESP_LOGD(TAG, "Reconnecting per user request..."); - break; - } else if (client->config->auto_reconnect && - platform_tick_get_ms() - client->reconnect_tick > client->wait_timeout_ms) { - client->state = MQTT_STATE_INIT; - client->reconnect_tick = platform_tick_get_ms(); - ESP_LOGD(TAG, "Reconnecting..."); - break; - } - MQTT_API_UNLOCK(client); - xEventGroupWaitBits(client->status_bits, RECONNECT_BIT, false, true, - max_poll_timeout(client, client->wait_timeout_ms / 2 / portTICK_PERIOD_MS)); - // continue the while loop instead of break, as the mutex is unlocked - continue; - default: - ESP_LOGE(TAG, "MQTT client error, client is in an unrecoverable state."); - break; - } - MQTT_API_UNLOCK(client); - if (MQTT_STATE_CONNECTED == client->state) { - if (esp_transport_poll_read(client->transport, max_poll_timeout(client, MQTT_POLL_READ_TIMEOUT_MS)) < 0) { - ESP_LOGE(TAG, "Poll read error: %d, aborting connection", errno); - esp_mqtt_abort_connection(client); - } - } - - } - esp_transport_close(client->transport); - outbox_delete_all_items(client->outbox); - xEventGroupSetBits(client->status_bits, STOPPED_BIT); - client->state = MQTT_STATE_DISCONNECTED; - - vTaskDelete(NULL); -} - -esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - MQTT_API_LOCK(client); - if (client->state != MQTT_STATE_INIT && client->state != MQTT_STATE_DISCONNECTED) { - ESP_LOGE(TAG, "Client has started"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - if (esp_mqtt_client_create_transport(client) != ESP_OK) { - ESP_LOGE(TAG, "Failed to create transport list"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - esp_err_t err = ESP_OK; -#if MQTT_CORE_SELECTION_ENABLED - ESP_LOGD(TAG, "Core selection enabled on %u", MQTT_TASK_CORE); - if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle, MQTT_TASK_CORE) != pdTRUE) { - ESP_LOGE(TAG, "Error create mqtt task"); - err = ESP_FAIL; - } -#else - ESP_LOGD(TAG, "Core selection disabled"); - if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle) != pdTRUE) { - ESP_LOGE(TAG, "Error create mqtt task"); - err = ESP_FAIL; - } -#endif - MQTT_API_UNLOCK(client); - return err; -} - -esp_err_t esp_mqtt_client_disconnect(esp_mqtt_client_handle_t client) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - ESP_LOGI(TAG, "Client asked to disconnect"); - xEventGroupSetBits(client->status_bits, DISCONNECT_BIT); - return ESP_OK; -} - -esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - ESP_LOGI(TAG, "Client force reconnect requested"); - if (client->state != MQTT_STATE_WAIT_RECONNECT) { - ESP_LOGD(TAG, "The client is not waiting for reconnection. Ignore the request"); - return ESP_FAIL; - } - client->wait_timeout_ms = 0; - xEventGroupSetBits(client->status_bits, RECONNECT_BIT); - return ESP_OK; -} - -static esp_err_t send_disconnect_msg(esp_mqtt_client_handle_t client) -{ - // Notify the broker we are disconnecting - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->mqtt_state.outbound_message = mqtt5_msg_disconnect(&client->mqtt_state.mqtt_connection, &client->mqtt5_config->disconnect_property_info); - if (client->mqtt_state.outbound_message->length) { - esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property); - client->mqtt5_config->disconnect_property_info.user_property = NULL; - memset(&client->mqtt5_config->disconnect_property_info, 0, sizeof(esp_mqtt5_disconnect_property_config_t)); - } -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_disconnect(&client->mqtt_state.mqtt_connection); - } - if (client->mqtt_state.outbound_message->length == 0) { - ESP_LOGE(TAG, "Disconnect message cannot be created"); - return ESP_FAIL; - } - if (esp_mqtt_write(client) != ESP_OK) { - ESP_LOGE(TAG, "Error sending disconnect message"); - } - return ESP_OK; -} - -esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return ESP_ERR_INVALID_ARG; - } - MQTT_API_LOCK(client); - if (client->run) { - /* A running client cannot be stopped from the MQTT task/event handler */ - TaskHandle_t running_task = xTaskGetCurrentTaskHandle(); - if (running_task == client->task_handle) { - MQTT_API_UNLOCK(client); - ESP_LOGE(TAG, "Client cannot be stopped from MQTT task"); - return ESP_FAIL; - } - - // Only send the disconnect message if the client is connected - if (client->state == MQTT_STATE_CONNECTED) { - if (send_disconnect_msg(client) != ESP_OK) { - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } - } - - client->run = false; - client->state = MQTT_STATE_DISCONNECTED; - MQTT_API_UNLOCK(client); - xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY); - return ESP_OK; - } else { - ESP_LOGW(TAG, "Client asked to stop, but was not started"); - MQTT_API_UNLOCK(client); - return ESP_FAIL; - } -} - -static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client) -{ - client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); - if (client->mqtt_state.outbound_message->length == 0) { - ESP_LOGE(TAG, "Ping message cannot be created"); - return ESP_FAIL; - } - - if (esp_mqtt_write(client) != ESP_OK) { - ESP_LOGE(TAG, "Error sending ping"); - return ESP_FAIL; - } - ESP_LOGD(TAG, "Sent PING successful"); - return ESP_OK; -} - -int esp_mqtt_client_subscribe_multiple(esp_mqtt_client_handle_t client, - const esp_mqtt_topic_t *topic_list, int size) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return -1; - } - MQTT_API_LOCK(client); - if (client->state != MQTT_STATE_CONNECTED) { - ESP_LOGE(TAG, "Client has not connected"); - MQTT_API_UNLOCK(client); - return -1; - } - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - int max_qos = topic_list[0].qos; - for (int topic_number = 0; topic_number < size; ++topic_number) { - if (topic_list[topic_number].qos > max_qos) { - max_qos = topic_list[topic_number].qos; - } - } - if (esp_mqtt5_client_subscribe_check(client, max_qos) != ESP_OK) { - ESP_LOGI(TAG, "MQTT5 subscribe check fail: QoS %d not accepted by broker ", max_qos); - MQTT_API_UNLOCK(client); - return -1; - } - client->mqtt_state.outbound_message = mqtt5_msg_subscribe(&client->mqtt_state.mqtt_connection, - topic_list, size, - &client->mqtt_state.pending_msg_id, client->mqtt5_config->subscribe_property_info); - if (client->mqtt_state.outbound_message->length) { - client->mqtt5_config->subscribe_property_info = NULL; - } -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection, - topic_list, size, - &client->mqtt_state.pending_msg_id); - } - if (client->mqtt_state.outbound_message->length == 0) { - ESP_LOGE(TAG, "Subscribe message cannot be created"); - MQTT_API_UNLOCK(client); - return -1; - } - - client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); - //move pending msg to outbox (if have) - if (!mqtt_enqueue(client, NULL, 0)) { - MQTT_API_UNLOCK(client); - return -1; - } - outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED);// handle error - - if (esp_mqtt_write(client) != ESP_OK) { - ESP_LOGE(TAG, "Error to send subscribe message, first topic: %s, qos: %d", topic_list[0].filter, topic_list[0].qos); - MQTT_API_UNLOCK(client); - return -1; - } - - ESP_LOGD(TAG, "Sent subscribe, first topic=%s, id: %d", topic_list[0].filter, client->mqtt_state.pending_msg_id); - MQTT_API_UNLOCK(client); - return client->mqtt_state.pending_msg_id; - -} -int esp_mqtt_client_subscribe_single(esp_mqtt_client_handle_t client, const char *topic, int qos) -{ - esp_mqtt_topic_t user_topic = {.filter = topic, .qos = qos}; - return esp_mqtt_client_subscribe_multiple(client, &user_topic, 1); -} - -int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return -1; - } - MQTT_API_LOCK(client); - if (client->state != MQTT_STATE_CONNECTED) { - MQTT_API_UNLOCK(client); - ESP_LOGE(TAG, "Client has not connected"); - return -1; - } - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->mqtt_state.outbound_message = mqtt5_msg_unsubscribe(&client->mqtt_state.mqtt_connection, - topic, - &client->mqtt_state.pending_msg_id, client->mqtt5_config->unsubscribe_property_info); - if (client->mqtt_state.outbound_message->length) { - client->mqtt5_config->unsubscribe_property_info = NULL; - } -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_unsubscribe(&client->mqtt_state.mqtt_connection, - topic, - &client->mqtt_state.pending_msg_id); - } - if (client->mqtt_state.outbound_message->length == 0) { - MQTT_API_UNLOCK(client); - ESP_LOGE(TAG, "Unubscribe message cannot be created"); - return -1; - } - ESP_LOGD(TAG, "unsubscribe, topic\"%s\", id: %d", topic, client->mqtt_state.pending_msg_id); - - client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); - if (!mqtt_enqueue(client, NULL, 0)) { - MQTT_API_UNLOCK(client); - return -1; - } - outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED); //handle error - - if (esp_mqtt_write(client) != ESP_OK) { - ESP_LOGE(TAG, "Error to unsubscribe topic=%s", topic); - MQTT_API_UNLOCK(client); - return -1; - } - - ESP_LOGD(TAG, "Sent Unsubscribe topic=%s, id: %d, successful", topic, client->mqtt_state.pending_msg_id); - MQTT_API_UNLOCK(client); - return client->mqtt_state.pending_msg_id; -} - -static inline int mqtt_client_enqueue_priv(esp_mqtt_client_handle_t client, const char *topic, const char *data, - int len, int qos, int retain, bool store) -{ - uint16_t pending_msg_id = 0; - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { -#ifdef MQTT_PROTOCOL_5 - client->mqtt_state.outbound_message = mqtt5_msg_publish(&client->mqtt_state.mqtt_connection, - topic, data, len, - qos, retain, - &pending_msg_id, client->mqtt5_config->publish_property_info, client->mqtt5_config->server_resp_property_info.response_info); - if (client->mqtt_state.outbound_message->length) { - client->mqtt5_config->publish_property_info = NULL; - } -#endif - } else { - client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, - topic, data, len, - qos, retain, - &pending_msg_id); - } - - if (client->mqtt_state.outbound_message->length == 0) { - ESP_LOGE(TAG, "Publish message cannot be created"); - return -1; - } - /* We have to set as pending all the qos>0 messages */ - //TODO: client->mqtt_state.outbound_message = publish_msg; - if (qos > 0 || store) { - client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); - client->mqtt_state.pending_msg_id = pending_msg_id; - client->mqtt_state.pending_publish_qos = qos; - // by default store as QUEUED (not transmitted yet) only for messages which would fit outbound buffer - if (client->mqtt_state.mqtt_connection.message.fragmented_msg_total_length == 0) { - if (!mqtt_enqueue(client, NULL, 0)) { - return -1; - } - } else { - int first_fragment = client->mqtt_state.outbound_message->length - client->mqtt_state.outbound_message->fragmented_msg_data_offset; - if (!mqtt_enqueue(client, ((uint8_t *)data) + first_fragment, len - first_fragment)) { - return -1; - } - client->mqtt_state.outbound_message->fragmented_msg_total_length = 0; - } - } - return pending_msg_id; -} - -int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return -1; - } - MQTT_API_LOCK(client); -#if MQTT_SKIP_PUBLISH_IF_DISCONNECTED - if (client->state != MQTT_STATE_CONNECTED) { - ESP_LOGI(TAG, "Publishing skipped: client is not connected"); - MQTT_API_UNLOCK(client); - return -1; - } -#endif - -#ifdef MQTT_PROTOCOL_5 - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - if (esp_mqtt5_client_publish_check(client, qos, retain) != ESP_OK) { - ESP_LOGI(TAG, "MQTT5 publish check fail"); - MQTT_API_UNLOCK(client); - return -1; - } - } -#endif - - /* Acceptable publish messages: - data == NULL, len == 0: publish null message - data valid, len == 0: publish all data, payload len is determined from string length - data valid, len > 0: publish data with defined length - */ - if (len <= 0 && data != NULL) { - len = strlen(data); - } - - int pending_msg_id = mqtt_client_enqueue_priv(client, topic, data, len, qos, retain, false); - if (pending_msg_id < 0) { - MQTT_API_UNLOCK(client); - return -1; - } - int ret = 0; - - /* Skip sending if not connected (rely on resending) */ - if (client->state != MQTT_STATE_CONNECTED) { - ESP_LOGD(TAG, "Publish: client is not connected"); - if (qos > 0) { - ret = pending_msg_id; - } - - // delete long pending messages - mqtt_delete_expired_messages(client); - - goto cannot_publish; - } - - /* Provide support for sending fragmented message if it doesn't fit buffer */ - int remaining_len = len; - const char *current_data = data; - bool sending = true; - - while (sending) { - - if (esp_mqtt_write(client) != ESP_OK) { - esp_mqtt_abort_connection(client); - ret = -1; - goto cannot_publish; - } - - int data_sent = client->mqtt_state.outbound_message->length - client->mqtt_state.outbound_message->fragmented_msg_data_offset; - client->mqtt_state.outbound_message->fragmented_msg_data_offset = 0; - client->mqtt_state.outbound_message->fragmented_msg_total_length = 0; - remaining_len -= data_sent; - current_data += data_sent; - - if (remaining_len > 0) { - mqtt_connection_t *connection = &client->mqtt_state.mqtt_connection; - ESP_LOGD(TAG, "Sending fragmented message, remains to send %d bytes of %d", remaining_len, len); - if (remaining_len > connection->buffer_length) { - // Continue with sending - memcpy(connection->buffer, current_data, connection->buffer_length); - connection->message.length = connection->buffer_length; - sending = true; - } else { - memcpy(connection->buffer, current_data, remaining_len); - connection->message.length = remaining_len; - sending = true; - } - connection->message.data = connection->buffer; - client->mqtt_state.outbound_message = &connection->message; - } else { - // Message was sent correctly - sending = false; - } - } - - if (qos > 0) { -#ifdef MQTT_PROTOCOL_5 - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - esp_mqtt5_increment_packet_counter(client); - } -#endif - //Tick is set after transmit to avoid retransmitting too early due slow network speed / big messages - outbox_set_tick(client->outbox, pending_msg_id, platform_tick_get_ms()); - outbox_set_pending(client->outbox, pending_msg_id, TRANSMITTED); - } - MQTT_API_UNLOCK(client); - return pending_msg_id; - -cannot_publish: - // clear out possible fragmented publish if failed or skipped - client->mqtt_state.outbound_message->fragmented_msg_total_length = 0; - if (qos == 0) { - ESP_LOGW(TAG, "Publish: Losing qos0 data when client not connected"); - } - MQTT_API_UNLOCK(client); - - return ret; -} - -int esp_mqtt_client_enqueue(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain, bool store) -{ - if (!client) { - ESP_LOGE(TAG, "Client was not initialized"); - return -1; - } - - /* Acceptable publish messages: - data == NULL, len == 0: publish null message - data valid, len == 0: publish all data, payload len is determined from string length - data valid, len > 0: publish data with defined length - */ - if (len <= 0 && data != NULL) { - len = strlen(data); - } - - MQTT_API_LOCK(client); -#ifdef MQTT_PROTOCOL_5 - if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) { - if (esp_mqtt5_client_publish_check(client, qos, retain) != ESP_OK) { - ESP_LOGI(TAG, "esp_mqtt_client_enqueue check fail"); - MQTT_API_UNLOCK(client); - return -1; - } - } -#endif - int ret = mqtt_client_enqueue_priv(client, topic, data, len, qos, retain, store); - MQTT_API_UNLOCK(client); - if (ret == 0 && store == false) { - // messages with qos=0 are not enqueued if not overridden by store_in_outobx -> indicate as error - return -1; - } - return ret; -} - -esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler, void *event_handler_arg) -{ - if (client == NULL) { - return ESP_ERR_INVALID_ARG; - } -#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP - if (client->config->event_handle) { - ESP_LOGW(TAG, "Registering event loop while event callback is not null, clearing callback"); - client->config->event_handle = NULL; - } - - return esp_event_handler_register_with(client->config->event_loop_handle, MQTT_EVENTS, event, event_handler, event_handler_arg); -#else - ESP_LOGE(TAG, "Registering event handler while event loop not available in IDF version %s", IDF_VER); - return ESP_FAIL; -#endif -} - -esp_err_t esp_mqtt_client_unregister_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler) -{ - if (client == NULL) { - return ESP_ERR_INVALID_ARG; - } -#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP - if (client->config->event_handle) { - ESP_LOGW(TAG, "Unregistering event loop while event callback is not null, clearing callback"); - client->config->event_handle = NULL; - } - - return esp_event_handler_unregister_with(client->config->event_loop_handle, MQTT_EVENTS, event, event_handler); -#else - ESP_LOGE(TAG, "Unregistering event handler while event loop not available in IDF version %s", IDF_VER); - return ESP_FAIL; -#endif -} - -static void esp_mqtt_client_dispatch_transport_error(esp_mqtt_client_handle_t client) -{ - client->event.event_id = MQTT_EVENT_ERROR; - client->event.error_handle->error_type = MQTT_ERROR_TYPE_TCP_TRANSPORT; - client->event.error_handle->connect_return_code = 0; -#ifdef MQTT_SUPPORTED_FEATURE_TRANSPORT_ERR_REPORTING - client->event.error_handle->esp_tls_last_esp_err = esp_tls_get_and_clear_last_error(esp_transport_get_error_handle(client->transport), - &client->event.error_handle->esp_tls_stack_err, - &client->event.error_handle->esp_tls_cert_verify_flags); -#ifdef MQTT_SUPPORTED_FEATURE_TRANSPORT_SOCK_ERRNO_REPORTING - client->event.error_handle->esp_transport_sock_errno = esp_transport_get_errno(client->transport); -#endif -#endif - esp_mqtt_dispatch_event_with_msgid(client); -} - -int esp_mqtt_client_get_outbox_size(esp_mqtt_client_handle_t client) -{ - int outbox_size = 0; - - if (client == NULL) { - return 0; - } - - MQTT_API_LOCK(client); - - if (client->outbox) { - outbox_size = outbox_get_size(client->outbox); - } - - MQTT_API_UNLOCK(client); - - return outbox_size; -} diff --git a/static-analysis-rules.yml b/static-analysis-rules.yml deleted file mode 100644 index bd36de8..0000000 --- a/static-analysis-rules.yml +++ /dev/null @@ -1,9 +0,0 @@ -limits: - "clang-analyzer-core.NullDereference" : 0 - "clang-analyzer-unix.Malloc" : 0 - -ignore: - - "llvm-header-guard" - - "llvm-include-order" - -skip: