Compare commits

...

443 Commits

Author SHA1 Message Date
7e19495fb0 Add esp_tls option to skip server verification 2023-10-24 16:31:07 +02:00
dffabb067f Merge branch 'feature/esp_mqtt_as_managed_component' into 'master'
Moves mqtt build files to esp-mqtt and adds a component file

See merge request espressif/esp-mqtt!149
2022-12-17 01:46:11 +08:00
159b1638b2 Reorganize mqtt build structure
- Integrate build definitions from idf
- Changes CMakeLists to allow import
- Added host test from idf
- Added test code from idf
2022-12-16 08:52:54 +01:00
f27cb47c0f [MQTT] Simplifies MQTT CMakeLists file
- Uses mocks from tools instead of creating them.
- Move host based definition to test code.
2022-12-16 08:38:48 +01:00
ee9b52b7d2 build system: re-add -Wno-format as private flag for some components 2022-12-16 08:38:48 +01:00
01d0f34654 test: Add mqtt5 unit-test 2022-12-16 08:38:48 +01:00
0b98c63247 mqtt: Add mqtt5 Kconfig 2022-12-16 08:38:48 +01:00
94ecca2073 esp_netif/lwip: Fix deps cycles to "lwip -> esp_netif -> phy-drivers"
Fix dependency tree so that lwip doesn't depend on any specific network
interface component.
Network interface drivers shall depend on esp_netif.
esp_netif shall depend on lwip (but not on any specific interface
driver) -- it optionally depends on vfs and esp_eth (need ethernet
header for L2/bridge mode)
2022-12-16 08:38:48 +01:00
1e598b071b [MQTT] - Updates esp_mqtt configuration struct
- Layered config struct
- Fix examples.
2022-12-16 08:38:48 +01:00
d4ee31f627 docs: changes docs supported targets tables 2022-12-16 08:38:48 +01:00
411ea65ec7 [MQTT] - Adds esp-timer as dependency and change version.
- Current time is now from esp_timer.
2022-12-16 08:38:48 +01:00
bc30b9a8e3 mqtt: Update tests to start with valid transport 2022-12-16 08:38:48 +01:00
d372bbf09e mqtt: Fix client_enqueue(len=0), Improve transport memory
* Update submodule: git log --oneline 64f88b4412ea6649dbf207a07370c2617160d044..a21c387d6280260894981c22494017c893d505b9

Detailed description of the changes:
* mqtt_client: Added checks for cleanly-closed connection and timeout
  - See merge request espressif/esp-mqtt!118
  - Added checks for cleanly-closed connection and timeout (espressif/esp-mqtt@e05d873)
* mqtt_client: fix esp_mqtt_client_enqueue for len=0 (GitHub PR)
  - See merge request espressif/esp-mqtt!135
  - mqtt_client: fix esp_mqtt_client_enqueue for len=0 (espressif/esp-mqtt@69b6493)
* Fix implicit malloc/free inclusion
  - See merge request espressif/esp-mqtt!134
  - See commit https://github.com/espressif/esp-mqtt/commit/9299f54
* feat(mqtt): Optimize mqtt transport list and remove unused transport
  - See merge request espressif/esp-mqtt!131
  - See commit https://github.com/espressif/esp-mqtt/commit/647e0ef
* Fix WSS default port selection through menuconfig.
  - See merge request espressif/esp-mqtt!132
  - - Closes https://github.com/espressif/esp-mqtt/issues/223
  - See commit https://github.com/espressif/esp-mqtt/commit/f6caaff
2022-12-16 08:38:48 +01:00
610db7b934 mqtt: Fix and add mqtt host test to CI 2022-12-16 08:38:48 +01:00
62c5545f2d esp-netif: Make dependency on esp-eth optional
* esp-netif to optionally depend on esp-eth (only for l2tap config)
* esp_eth.h now includes the original ethernet header and the
ethernet-netif glue layer
* Updated examples and test to explicitely use esp-eth dependency if
needed
2022-12-16 08:38:48 +01:00
b80d4d468c tools: Increase the minimal supported CMake version to 3.16
This updates the minimal supported version of CMake to 3.16, which in turn enables us to use more CMake features and have a cleaner build system.
This is the version that provides most new features and also the one we use in our latest docker image for CI.
2022-12-16 08:38:48 +01:00
5539c83c0a mqtt: Fix incorrect reads on error; Update ping processing
* Update submodule: git log --oneline 4874bab35659bd2301e65fd849f6559d7380d4f1..64f88b4412ea6649dbf207a07370c2617160d044

Detailed description of the changes:
* Fix documentation of config struct
  - See merge request espressif/esp-mqtt!129
  - See commit https://github.com/espressif/esp-mqtt/commit/e31834c
* Changes the moment we update keepalive_tick.
  - See merge request espressif/esp-mqtt!127
  - See commit https://github.com/espressif/esp-mqtt/commit/2c2e6f3
* MQTT: Fix signature matching for some integer values
  - See merge request espressif/esp-mqtt!128
  - Closes https://github.com/espressif/esp-idf/issues/8482
  - MQTT: Fix signature matching for integer values (espressif/esp-mqtt@6b794e4)
* Make the mqtt submodule logging tags lower case
  - See merge request espressif/esp-mqtt!122
  - See commit https://github.com/espressif/esp-mqtt/commit/fb3184c

Closes https://github.com/espressif/esp-idf/issues/8482
Closes https://github.com/espressif/esp-idf/issues/8550
2022-12-16 08:38:48 +01:00
0a507f1205 build system: remove lwip from common requirements
lwip was added to common requirements list to provide "sys/socket.h"
header to all components without additional requirements specified.

However, lwip pulls in a lot of dependencies on other components.
This commit removes lwip from common requirements to reduce the number
of components in G1-only apps.

To compensate for this removal, the following changes are made:
- newlib (which is a common requirement) has a public dependency on
  lwip if lwip is present in the build. This ensures that sys/socket.h
  is available as long as lwip component is included into the build.
- lwip is now a public requirement of esp-tls since esp_tls.h includes
  sys/socket.h header.
- lwip is now a public requirement o esp_http_client because
  sys/socket.h is included from esp_http_client.h
- lwip is now a private requirement of esp_wifi for "smartconfig_ack"
- lwip is now a private requirement of mqtt for socket functions
- lwip is now a public requirement of tcp_transport because
  esp_transport_tcp.h includes sys/socket.h header.
- mbedtls checks if lwip component is present in the build. If yes,
  net_sockets.c is added to the build, along with the dependency on
  lwip. Previously lwip was a public requirement of mbedtls
  unconditionally.

system/g1_components test app is updated to reflect the changes

Default public dependencies of a component before and after this
change, except common requirements:

- esp_timer (public dependency of freertos)
- bootloader_support (public dependency of esp_hw_support)
- vfs (public dependency of lwip)
- esp_wifi (public dependency of lwip)
- esp_event (public dependency of esp_wifi)
- esp_netif (public dependency of esp_event)
- esp_eth (public dependency of esp_netif)
- esp_phy (public dependency of esp_wifi)

After:

- esp_timer (public dependency of freertos)
- bootloader_support (public dependency of esp_hw_support)

Altogether, the following components have been always added as
public requirements to all other components, and are not added now
([breaking-change]):

- lwip
- vfs
- esp_wifi
- esp_event
- esp_netif
- esp_eth
- esp_phy

Application components now need to explicitly declare dependencies on
these components.
2022-12-16 08:38:48 +01:00
77e41479d7 components: correct printf() placeholder for time_t
Using C99 %jd, https://en.cppreference.com/w/c/chrono/time_t
2022-12-16 08:38:48 +01:00
a88eaebad9 esp-mqtt: fix warnings 2022-12-16 08:38:48 +01:00
8dc8e5ae0b kconfig: Changed default values of bool configs
- Some bool configs were using default values true and false,
  instead of y and n.
2022-12-16 08:38:48 +01:00
933da9efed Remove legacy system event framework. 2022-12-16 08:38:48 +01:00
a840bcf274 esp_hw_support/esp_system: Re-evaluate header inclusions and include directories
This commit updates the visibility of various header files and cleans up
some unnecessary inclusions. Also, this commit removes certain header
include paths which were maintained for backward compatibility.
2022-12-16 08:38:48 +01:00
fcd548daab freertos: Remove legacy hooks
This commit refactors the legacy hooks as follows:

- Removed CONFIG_FREERTOS_LEGACY_HOOKS
- FreeRTOS hooks are now enabled via:
    - CONFIG_FREERTOS_USE_IDLE_HOOK
    - CONFIG_FREERTOS_USE_TICK_HOOK
- Update IDF hooks documentation
2022-12-16 08:38:48 +01:00
23e5c5a02c esp_eth: Update esp32's EMAC API to decouple driver and vendor config 2022-12-16 08:38:48 +01:00
71d9236275 mqtt: Fix sending log data; dup flag after queue
* Fix sending mqtt message longer than Tx buffer size
* Fix enqueue API to send data with correct dup flag
* Update submodule: git log --oneline b86d42c130ac64a916ce6cf299d99f9756692394..985078affa8a2d2b56b87c8e6455252850f895c6

Detailed description of the changes:
* Isolate IDF env for v4.4 and v5.0(master)
  - See merge request espressif/esp-mqtt!111
  - ci: Isolate IDF env for v4.4 and v5.0(master) (espressif/esp-mqtt@4c5a65c)
* Client: Remove usage of legacy FreeRTOS types
  - See merge request espressif/esp-mqtt!120
  - ci: Fix build issues with IDF-4.4 against master (espressif/esp-mqtt@c28a56d)
  - See commit https://github.com/espressif/esp-mqtt/commit/6ef98d6
* mqtt_client: Fix mqtt send long data error
  - See merge request espressif/esp-mqtt!117
  - Closes https://github.com/espressif/esp-mqtt/issues/214
  - See commit https://github.com/espressif/esp-mqtt/commit/372b323
* Client: Fix use esp_mqtt_client_enqueue API to send data, data dup flag will be set 1
  - See merge request espressif/esp-mqtt!116
  - See commit https://github.com/espressif/esp-mqtt/commit/df8dc92
2022-12-16 08:38:48 +01:00
f8cb9f7286 mqtt: Add docs on MQTT_CUSTOM_OUTBOX implentation
Closes https://github.com/espressif/esp-mqtt/issues/217
2022-12-16 08:38:48 +01:00
47ac29b1e2 mqtt: replace nghttp with http_parser references 2022-12-16 08:38:48 +01:00
174c6781de refactor (test_utils)!: separate file for memory check functions
Memory check (leaks and heap tracing) functions for unit tests
now have a separate file now and are renamed for more consistency.

BREAKING CHANGE: renamed memory check function names which may be used
                 in unit tests outside IDF.
2022-12-16 08:38:48 +01:00
1766fd4d5b MQTT: Fix disconnect/reconnect, Adds empty client id, ...
Updated MQTT submodule: git log --oneline 89894bd0c611b1392967fe90bb49682eba858383...b86d42c130ac64a916ce6cf299d99f9756692394
* Added support for client with empty id
* Fixed user requested disconnect to correctly send MQTT disconnection message
* Fixed reconnection request with disabled autoreconnect
* Added qos and dup flags to data events
* Added Support for suback massage payload in mqtt events

Detailed description of the changes (89894bd0c6...b86d42c130):
* Adds the possibility of client with empty id
    - See merge request esp-mqtt!114
    - esp_mqtt commit 09287a1156
    - esp_mqtt commit 1fd50dd2cb
    - Related IDF-4124
* Client: Disconnect/Reconnect improvements
    - See merge request esp-mqtt!113
    - esp_mqtt commit 3f05b1aedc
    - esp_mqtt commit 86e40f8615
    - Related https://github.com/espressif/esp-mqtt/issues/206
    - Related https://github.com/espressif/esp-mqtt/issues/208
* Events: Support qos/dup flags and suback payload in mqtt events (GitHub PR)
    - See merge request esp-mqtt!112
    - esp_mqtt commit de47f1c341
    - esp_mqtt commit e1d5a9402f
    - Related https://github.com/espressif/esp-mqtt/issues/200
    - Related https://github.com/espressif/esp-mqtt/pull/203
2022-12-16 08:38:48 +01:00
4afe71b132 MQTT: Add more tests 2022-12-16 08:38:48 +01:00
74882b18f0 MQTT: Add more unit tests with actual broker 2022-12-16 08:38:48 +01:00
ff8a93585f freertos: Add portTRY_ENTRY_CRITICAL() and deprecate legacy spinlock fucntions
Add TRY_ENTRY_CRITICAL() API to all for timeouts when entering critical sections.
The following port API were added:
- portTRY_ENTER_CRITICAL()
- portTRY_ENTER_CRITICAL_ISR()
- portTRY_ENTER_CRITICAL_SAFE()

Deprecated legacy spinlock API in favor of spinlock.h. The following API were deprecated:
- vPortCPUInitializeMutex()
- vPortCPUAcquireMutex()
- vPortCPUAcquireMutexTimeout()
- vPortCPUReleaseMutex()

Other Changes:
- Added portMUX_INITIALIZE() to replace vPortCPUInitializeMutex()
- The assembly of the critical section functions ends up being about 50 instructions longer,
  thus the spinlock test pass threshold had to be increased to account for the extra runtime.

Closes https://github.com/espressif/esp-idf/issues/5301
2022-12-16 08:38:48 +01:00
b4474ac16d Build & config: Remove leftover files from the unsupported "make" build system 2022-12-16 08:38:48 +01:00
3c764f0fc1 freertos: update freertos folder structure to match upstream
The following changes have been made:
1. All FreeRTOS kernel source files are now placed in the
   freertos/FreeRTOS-Kernel folder to match with the upstream folder structure.
2. All kernel include files are now placed in freertos/FreeRTOS-Kernel/include.
3. All port files are now placed in freertos/FreeRTOS-Kernel/portable.
4. All additions/customizations are placed in freertos/esp_additions.
5. All other miscellaneous files (README, License files etc.) are moved to
   freertos/FreeRTOS-Kernel folder to match with the upstream.
6. Updated esp-cryptoauthlib to latest commit to resolve FreeRTOS
   include dependencies.

Signed-off-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2022-12-16 08:38:48 +01:00
c03353333b MQTT: Fix build if CONFIG_WS_TRANSPORT is not set and client cleanups
Updated MQTT submodule: git log --oneline f10321a53b53a146ee299cfecc320b89c0cf6611...89894bd0c611b1392967fe90bb49682eba858383
* Fix build issue if cert bundle disabled
* Fix build issue if ws transport disabled
* Add config to set retransmission interval

Detailed description of the changes (f10321a53b...89894bd0c6):
* Added config option to configure custom retransmission interval
    - See merge request espressif/esp-mqtt!110
    - esp_mqtt commit 1b009c840b
    - Related https://github.com/espressif/esp-mqtt/pull/199
* Configuration conflicts were verified, logged but not reported to the user.
    - See merge request espressif/esp-mqtt!102
    - esp_mqtt commit 88f4b8ed50
* Fixed build issue if cert bundle disabled
    - See merge request espressif/esp-mqtt!109
    - esp_mqtt commit 4a89bff610
    - esp_mqtt commit 1b71980575
    - esp_mqtt commit 5b3c81ee48
    - Related https://github.com/espressif/esp-mqtt/pull/198
    - Related https://github.com/espressif/esp-idf/issues/7535
* Removes unnecessary outbox_cleanup
    - This function were used on old version to handle QoS 2 messages. It's no longer necessary in current implementation.
    - See merge request espressif/esp-mqtt!108
    - esp_mqtt commit ebef896b00
* Fixed return an error when fail to enqueue
    - The functions that enqueue messages didn't had a return for the handler, with this the error was only logged instead of returned whichmay cause the user to have an ID for a message that was not published.
    - See merge request espressif/esp-mqtt!103
    - esp_mqtt commit 7471177fe7
* CI: Use qemu image based on esp-env:v4.4-1
    - Replaced the temporary qemu image with the official qemu:v4.4-1-20210517 derived from the esp-env:v4.4-1 test environment
    - See merge request espressif/esp-mqtt!107
    - esp_mqtt commit 231b274962

Closes https://github.com/espressif/esp-idf/issues/7535
2022-12-16 08:38:48 +01:00
382caedbbb upgrade freertos version and history 2022-12-16 08:38:48 +01:00
93158d5d18 mqtt: Adds host tests for mqtt client 2022-12-16 08:38:48 +01:00
a8b0f474ec MQTT: Support for certificate bundle; Client clean-up
* Closes https://github.com/espressif/esp-idf/issues/7040
* Merges https://github.com/espressif/esp-idf/pull/7041
* Update submodule: git log --oneline 9fdf7b61385633075d5c3b84803f2dd0578d7869..f10321a53b53a146ee299cfecc320b89c0cf6611

Detailed description of the changes:
* Remove unnecessary parentheses
  - esp-mqtt commit: db13533904
  - esp-mqtt MR: espressif/esp-mqtt!101
* outbox: Cleanup all items when connection closes
  - esp-mqtt commit: 1a94efe8b9
  - esp-mqtt MR: espressif/esp-mqtt!104
* Outbox: Removes unnecessary calls to outbox_set_pending
  - esp-mqtt commit: 36a3990404
  - esp-mqtt MR: espressif/esp-mqtt!105
* MQTT: Makes abort connection function void.
  - esp-mqtt commit: 67553aba45
  - esp-mqtt MR: espressif/esp-mqtt!106
* Client: Removes unused defines
  - esp-mqtt commit: eec6f0e17d
  - esp-mqtt MR: espressif/esp-mqtt!100
  - Closes https://github.com/espressif/esp-mqtt/issues/194
* Config: Added support for certificate bundle
  - esp-mqtt commit: 06157be118
  - esp-mqtt MR: espressif/esp-mqtt!98
  - Closes https://github.com/espressif/esp-mqtt/issues/190
* Config: Adds missing field at config struct (path field)
  - esp-mqtt commit: 5b27d1896e
  - esp-mqtt MR: espressif/esp-mqtt!96
* Client: Add support for partial transport writes
  - esp-mqtt commit: d8c9c7a9e7
  - esp-mqtt MR: espressif/esp-mqtt!99
  - Partially addresses https://github.com/espressif/esp-idf/issues/6940
* Client: Add support for Retain flag in messages posted by events
  - esp-mqtt commit: a00a3134c6
  - esp-mqtt MR: espressif/esp-mqtt!99
  - Closes https://github.com/espressif/esp-mqtt/issues/193
* esp-mqtt: Added nullchecks for public APIs
  - esp-mqtt commit: 2f57985c0b
  - esp-mqtt MR: espressif/esp-mqtt!94
  - Closes https://github.com/espressif/esp-mqtt/issues/185
* esp-mqtt: Reduce the includes used in all files
  - esp-mqtt commit: 87fcce72c9
  - esp-mqtt MR: espressif/esp-mqtt!93
* mqtt_outbox: Use STAILQ_FOREACH for outbox_delete_single_expired
  - esp-mqtt commit: ff8e64839a
  - esp-mqtt MR: espressif/esp-mqtt!97
  - Merges https://github.com/espressif/esp-mqtt/pull/187
* Client: Add optimize for depend on ssl
  - esp-mqtt commit: 8f3cac8c36
  - esp-mqtt MR: espressif/esp-mqtt!95
2022-12-16 08:38:48 +01:00
0fda7d7062 transport: Add CONFI_WS_TRANSPORT for optimize the code size 2022-12-16 08:38:48 +01:00
128be3f402 mqtt: Moved weekend tests to test apps 2022-12-16 08:38:48 +01:00
f2f30baec0 esp-mqtt: Remove __FILE__ macro from error logs 2022-12-16 08:38:48 +01:00
f072c9f753 style: format python files with isort and double-quote-string-fixer 2022-12-16 08:38:48 +01:00
3883bde0b0 ci: Add MQTT publish test to standard test apps 2022-12-16 08:38:48 +01:00
40fdf32793 ci: Extend the MQTT weekend test to check mqtt-enqueue api 2022-12-16 08:38:48 +01:00
2c3363e23a MQTT: Add new config modes (outbox related, incremental id) 2022-12-16 08:38:48 +01:00
6756e62387 MQTT: Update submodule reference to support new config modes
* Queueing publish messages to outbox when the client is not connected (default=off -> messages are queued if disconnected)
* Use of incremental msg-id instead of random id (default=off -> msg-id uses platform_random())
* Posting a new event-id if a queued message gets deleted from the outbox (default=off -> events are not posted)

Detailed description of included `esp-mqtt` changes
(da850b0add1e71b3659bfac5d797cc834dc3e89b...9ea804e0ab5368d5ab53ae2301a5fec9d1f12f1a)
* mqtt: Remove unused mqtt_header_state_t
  - esp-mqtt commit: b7158a4aea
  - esp-mqtt MR: espressif/esp-mqtt!84
  - Merges https://github.com/espressif/esp-mqtt/pull/180
* Cleanup public include dirs
  - esp-mqtt commit: f65d5d05db
  - esp-mqtt MR: espressif/esp-mqtt!85
* Config: Add a new option to use incremental message id
  - esp-mqtt commit: 8bb4a26f46
  - esp-mqtt MR: espressif/esp-mqtt!85
  - Closes https://github.com/espressif/esp-mqtt/issues/176
* Publish: Add new API to enqueue qos>0 messages
  - esp-mqtt commit: dc7fd5c0b1
  - esp-mqtt MR: espressif/esp-mqtt!85
  - Closes https://github.com/espressif/esp-mqtt/issues/155
* Config: Add a new option to disable publishing when disconnected
  - esp-mqtt commit: f44dcb1c26
  - esp-mqtt MR: espressif/esp-mqtt!85
  - Related https://github.com/espressif/esp-mqtt/issues/177
* Events: Add new event to report deleted messages from outbox
  - esp-mqtt commit: 2e35d4d4d5
  - esp-mqtt MR: espressif/esp-mqtt!85
* Publish: Allow for qos=0 messages to be stored using esp_mqtt_client_enqueue()
  - esp-mqtt commit: e2de0f3e3e
  - esp-mqtt MR: espressif/esp-mqtt!85
2022-12-16 08:38:48 +01:00
10bba73d21 MQTT: Update submodule reference: config, error handle, minor fixes
Updates esp-mqtt reference to include fixes below related mainly to:
* configuration update (disable keepalive, network timeout)
* minor fixes (size_t for all sizes, unbalanced lock, api for
  outbox-size)
* extended error handle to include socket's errno

Closes https://github.com/espressif/esp-idf/issues/5906

Config: Added config value to disable keepalive mechanism
esp-mqtt commit: 8562437c8a
Related https://github.com/espressif/esp-mqtt/issues/179

Added esp_mqtt_client_get_outbox_size API
esp-mqtt commit: 0a1d9d0300
Related https://github.com/espressif/esp-mqtt/pull/178

mqtt_outbox: Removed unused retry_count field from outbox_item_t
esp-mqtt commit: 673086e13a

config: Fixed typo for configuring OUTBOX_EXPIRED_TIMEOUT_MS
esp-mqtt commit: 259baaec96

Fixed missing MQTT_API_UNLOCK in esp_mqtt_client_stop error path
esp-mqtt commit: 845c2a3a1e
Related https://github.com/espressif/esp-mqtt/issues/173
Related https://github.com/espressif/esp-mqtt/pull/174

Extended mqtt error handle to capture transport's socket errno (IDF
v4.3+)
esp-mqtt commit: 23c8e1ecf5

Config: Added configuration value to set network timeout
esp-mqtt commit: a03228ac46
Related https://github.com/espressif/esp-mqtt/pull/166

Used size_t for all lengths to allow for other architectures
esp-mqtt commit: b9db8d9020
2022-12-16 08:38:48 +01:00
b342444746 riscv: Add new arch-level component
Changes come from internal branch commit a6723fc
2022-12-16 08:38:48 +01:00
5facf78673 MQTT: Restore default MQTT_OUTBOX_EXPIRED_TIMEOUT_MS to 30 sec
The OUTBOX_EXPIRED_TIMEOUT_MS was 30*1000 in original esp-mqtt code.
Don't change the default OUTBOX_EXPIRED_TIMEOUT_MS without good reason,
which may has impact on memory usage for existing applications.

Fixes: e931168ed695 ("MQTT: add configurable msg expired timeout")
Signed-off-by: Axel Lin <axel.lin@gmail.com>
2022-12-16 08:38:48 +01:00
6c55757f70 Whitespace: Automated whitespace fixes (large commit)
Apply the pre-commit hook whitespace fixes to all files in the repo.

(Line endings, blank lines at end of file, trailing whitespace)
2022-12-16 08:38:48 +01:00
87d698cbc7 cmock: added cmock as component
* changing dependencies from unity->cmock
* added component.mk and Makefile.projbuild
* ignore test dir in gen_esp_err_to_name.py
* added some brief introduction of CMock in IDF
2022-12-16 08:38:48 +01:00
25b661c8ea MQTT: add configurable msg expired timeout 2022-12-16 08:38:48 +01:00
8b3d3db10b MQTT: Update submodule reference
SSL: add config option for skipping common name check
esp-mqtt commit: 5e8950e681)
Closes https://github.com/espressif/esp-mqtt/issues/158

SSL: add support for tls with secure element (ATECC608A)
esp-mqtt commit: a7ff9afa3f)
Closes https://github.com/espressif/esp-mqtt/issues/156

Websocket: Allow the query part of the uri to be a part of the path
esp-mqtt commit: 40b06deb10)
Closes https://github.com/espressif/esp-mqtt/issues/161

Config: Add check for consistency between config settings
esp-mqtt commit: 8a412c147d)

Add IDF version check for secure element feature
esp-mqtt commit: db4bce01ab)

Fix esp_mqtt_client_stop deadlock
esp-mqtt commit: 5e17dcaeb2)
Closes https://github.com/espressif/esp-mqtt/issues/163

Add dispatch error event for read errors
esp-mqtt commit: d4aaec08ff
Closes https://github.com/espressif/esp-idf/issues/5704

Cleanup expired messages when offline
esp-mqtt commit: bdadd77c6e
Closes https://github.com/espressif/esp-idf/issues/5668

esp_mqtt_client_publish now returns msg id for QoS > 0 when offline
esp-mqtt commit: f7325bfa10

Add support for Digital Signature through ESP-TLS
esp-mqtt commit: 7d8e59de00
2022-12-16 08:38:48 +01:00
691e7bca88 mqtt: clenaup logs and docs
esp_mqtt: Change an error print to use ESP_LOGE instead of ESP_LOGI
Move Sending MQTT connect message log from Info to Debug level
docs: Makes clear that publish API could block
Change the message printed after MQTT connection failure

Closes https://github.com/espressif/esp-idf/issues/5077
(by means of referencing commit 615aeae0c2)
2022-12-16 08:38:48 +01:00
9b79fe3d00 esp_mqtt_abort_connection: Fixed an issue which could result in a race condition and subsequent crash 2022-12-16 08:38:48 +01:00
cb782cae1e mqtt-tests: rename tests to match the actual group 2022-12-16 08:38:48 +01:00
9db10b5b7b mqtt: reenable outbox unit tests for esp32s2 2022-12-16 08:38:48 +01:00
29ce3c5869 esp_mqtt: add option to configure mqtt task priority.
Merges https://github.com/espressif/esp-idf/pull/4947
2022-12-16 08:38:48 +01:00
605352c1c5 MQTT: Reference latest mqtt addressing c++ build and qos1/2 resend
Closes https://github.com/espressif/esp-idf/issues/4787
2022-12-16 08:38:48 +01:00
5ba36d511f ci: disable failed cases for s2 temporarily 2022-12-16 08:38:48 +01:00
650328b021 mqtt: example test to check connection with different ssl parameters 2022-12-16 08:38:48 +01:00
5be3f7b5d4 mqtt: add basic set of unit tests 2022-12-16 08:38:48 +01:00
0178bafba8 mqtt: update submodule to point to latest commit.
Adds bugfixes for:
 - Too early publishing
 - Potential mutex memory leak
 - CI related issues.
 - Wait for entire connack message
 - Event loop not getting cleaned up

Adds support for ALPN, configurable reconnect time, QEMU CI tests and password
protected client key.

MQTT MR: https://gitlab.espressif.cn:6688/espressif/esp-mqtt/merge_requests/46
Closes IDF-1162
Closes https://github.com/espressif/esp-mqtt/issues/137

MQTT MR: https://gitlab.espressif.cn:6688/espressif/esp-mqtt/merge_requests/47
Closes IDF-1126

MQTT MR: https://gitlab.espressif.cn:6688/espressif/esp-mqtt/merge_requests/48
Closes IDFGH-2197
Closes https://github.com/espressif/esp-idf/issues/4349
Closes https://github.com/espressif/esp-mqtt/issues/140

MQTT MR: https://gitlab.espressif.cn:6688/espressif/esp-mqtt/merge_requests/48
Closes IDFGH-2235
Closes https://github.com/espressif/esp-idf/issues/4384

MQTT MR: https://gitlab.espressif.cn:6688/espressif/esp-mqtt/merge_requests/49
Closes https://github.com/espressif/esp-idf/issues/4433
Closes IDFGH-2293

MQTT MR: https://gitlab.espressif.cn:6688/espressif/esp-mqtt/merge_requests/50
Closes FCS-254

MQTT MR: https://gitlab.espressif.cn:6688/espressif/esp-mqtt/merge_requests/53
Closes FCS-267
2022-12-16 08:38:48 +01:00
8a24bebbc0 ci: updated mqtt weekend test for qemu support
Added default sdkconfig for qemu build for the mqtt publish example,
Added environment configuration for running the same test on target
or in qemu
Updated missing example tests per latest ttfw refactoring
2022-12-16 08:38:48 +01:00
62f3dc4705 mqtt: updated to latest version to include latest fixes, support for global CA store, extended error structure to receive mqtt specific errors. updated idf ssl example to use this error struct
https://github.com/espressif/esp-mqtt/issues/135
2022-12-16 08:38:48 +01:00
6cadfe519b MQTT: update default broker URL for examples
The MQTT broker URL used as default in the examples has ceased operation. All examples and documention have been updated to point to the new domain mqtt.eclipse.org.
This also required an update of the python example test scripts to use TLS 1.2
2022-12-16 08:38:48 +01:00
37e511bef1 ci: fix weekend test confguration update per latest refactoring of
grouping tests
2022-12-16 08:38:48 +01:00
b4ba09ce38 esp_wifi: wifi support new event mechanism
1. WiFi support new event mechanism
2. Update examples to use new event mechanism
2022-12-16 08:38:48 +01:00
25f423d69b ci: limit example test to ESP32s 2022-12-16 08:38:48 +01:00
5a50fc0812 esp_tls: enable psk verification mode, added mqtt example using psk authentication 2022-12-16 08:38:48 +01:00
bef4fce9c1 mqtt: referenced esp-mqtt master to close disconnection issues and fix static analysis warnings
closes https://github.com/espressif/esp-idf/issues/3619 including mqtt commit 7223302deb
closes https://github.com/espressif/esp-idf/issues/3215 including mqtt commit caf5007b99
2022-12-16 08:38:48 +01:00
49296d851d esp-tls: extending error handle to contain error descriptors with last mbedtls failure and latest certificate verification result flags, reworked tcp_transport to use this error handle 2022-12-16 08:38:48 +01:00
a903e5e3a9 esp-tls: capturing specific errors to be available in tcp_transport and then in application code 2022-12-16 08:38:48 +01:00
63b3f29ffc components: use new component registration api 2022-12-16 08:38:48 +01:00
332fadfea6 esp_websocket_client: Add websocket client component
Closes https://github.com/espressif/esp-idf/issues/2829
2022-12-16 08:38:48 +01:00
3a2e82ec0f mqtt: added support for esp event loop, updating examples to register and use event loop handler 2022-12-16 08:38:48 +01:00
7f77ad063d mqtt_tests: add weekend test for sending and receiving empty payload messages, update config options per new naming convetions 2022-12-16 08:38:48 +01:00
6809fcb2df tcp_transport: modified ws_read to read payload directly to the read buffer and separately from header bytes
Previous version read all data to the buffer including header which reduced maximum payload read. This version uses a local array to receive header and reads payload bytes to the buffer
2022-12-16 08:38:48 +01:00
6b70e14236 mqtt tests: adding weekend test for mqtt library to exercise publishing/receiving different data and references esp-mqtt commits to pass these tests
testing conditions:
transports (tcp, ssl, ws..)
qos (0, 1, 2)
short repeated messages (packed packets)
oversized messages (fragmented packets)
publish from a different thread

Closes https://github.com/espressif/esp-idf/issues/2870 by means of including commit 815623dfe5 from esp-mqtt
Closes https://github.com/espressif/esp-idf/issues/2975 by means of including commit 752953dc3b from esp-mqtt
Closes https://github.com/espressif/esp-idf/issues/2850 by means of including commits df455d2a5f 17fd713bce from esp-mqtt
2022-12-16 08:38:48 +01:00
e19b9aa2df separate rom from esp32 component to esp_rom
1. separate rom include files and linkscript to esp_rom
2. modefiy "include rom/xxx.h" to "include esp32/rom/xxx.h"
3. Forward compatible
4. update mqtt
2022-12-16 08:38:48 +01:00
9726859fa3 Correct Kconfigs according to the coding style 2022-12-16 08:38:48 +01:00
7437dce403 mqtt: support for BEFORE_CONNECT event in idf
Updated examples to use new event id, idf to use mqtt with fixed retained, oversized messages
2022-12-16 08:38:48 +01:00
60e39865e6 mqtt: ssl mutual authentication example added per PR from github, corrected cmake build, updated per idf style
Merges https://github.com/espressif/esp-idf/pull/2490
2022-12-16 08:38:48 +01:00
14e9df14ff tcp_transport: Remove the ignore warning because we had idf/esp-idf!3359 2022-12-16 08:38:48 +01:00
a31ede754f tcp_transport: transport set handle refactoring, web socket client name updated 2022-12-16 08:38:48 +01:00
229167f48a tcp_transport: renamed possibly generic function names to be esp_ prefixed and not to colide with user namespace 2022-12-16 08:38:48 +01:00
71d6861d6a tcp_transport: renamed transport related header files to esp_ prefixed to avoid collisions
tcp_transport component used public header files such as 'transport.h', etc. which are too generic and might collide with user or user libraries headers
This change closes #2417
2022-12-16 08:38:48 +01:00
78233fe7de doc: Re-add summaries of what children each menu item has
Slightly different to the original version of this, but same goal.
2022-12-16 08:38:48 +01:00
1d49ac3249 mqtt: silence a format warning 2022-12-16 08:38:48 +01:00
20dda12b88 mqtt: list files manually in component cmake file 2022-12-16 08:38:48 +01:00
24b656ca4b MQTT: Moved Kconfig from esp-mqtt submodule to esp-idf to support docs genration in RTD 2022-12-16 08:38:48 +01:00
c5069977a4 MQTT: Integrate esp-mqtt library into idf
added docs and tests for mqtt library, small fixes (removed warnings, option for custom outbox, websocket bug fixed for longer transports). refactored to use common tcp_transport component, support for CMake build system.
Closes #2108
2022-12-16 08:38:48 +01:00
d5a2c0a7c6 Merge branch 'bugfix/subscribe_error_detection' into 'master'
Fix error code verification on SUBSCRIBE error

See merge request espressif/esp-mqtt!155
2022-12-15 18:59:01 +08:00
d1f6ad23b7 Fix error code verification on SUBSCRIBE error
- Return codes other than 0x1, 0x2, 0x3 and 0x80 are reserved and
  forbidden by the specification.
2022-12-05 15:22:48 +01:00
fde00340f1 Merge branch 'bugfix/event_queue_disabled_deafult' into 'master'
Fix the default configuration for event queue

See merge request espressif/esp-mqtt!153
2022-11-23 22:17:25 +08:00
fb42588a03 Fix the default configuration for event queue
- Event queue should be disabled, making it an opt-in feature.
2022-11-23 20:40:31 +08:00
3e0a118e0b Merge branch 'bugfix/missing_header' into 'master'
Adds missing header.

See merge request espressif/esp-mqtt!152
2022-11-04 00:26:54 +08:00
8a6005781d Adds missing header.
- esp_heap_caps is directly needed and wasn't included.
- For target it's indirecly included but for host test it's needed.
2022-11-03 15:26:43 +01:00
e80f3e6a87 Merge branch 'bugfix/stop_in_wait_reconnection' into 'master'
Moves state change when stopping the client

See merge request espressif/esp-mqtt!150
2022-10-26 21:19:00 +08:00
3738fcd196 Moves state change when stopping the client
- In some situations client could be left in a state where it's
  impossible to restart due to a state change while waiting for the
  stop. This guarantee that it's possible to start after calling stop.

Closes https://github.com/espressif/esp-mqtt/issues/239
2022-10-26 14:37:28 +02:00
5f297c0d62 Merge branch 'bugfix/set_error_on_subscribe_failure' into 'master'
Adds error code to MQTT_EVENT_SUBSCRIBED in case of failure

See merge request espressif/esp-mqtt!143
2022-10-21 23:46:02 +08:00
9af5c26045 Adds error code to MQTT_EVENT_SUBSCRIBED in case of failure
- Payload data parsed for error codes. Check only for first filter
  because our subscribe function only handle one topic filter in each
  call.

- Closes https://github.com/espressif/esp-mqtt/issues/233
2022-10-20 13:29:16 +02:00
2b52b50a6b Merge branch 'feature/debug_retry' into 'master'
Adds debug information on sending dup messages

See merge request espressif/esp-mqtt!145
2022-10-04 13:15:50 +08:00
47b3f9b899 Adds debug information on sending dup messages
- To support debug of resending dup messages QoS 1 and 2 a debug
  log was added.
2022-10-03 07:43:01 +00:00
a87fd9c738 Merge branch 'bugfix/ci_qemu' into 'master'
ci: Fix qemu build

See merge request espressif/esp-mqtt!147
2022-09-30 22:44:15 +08:00
68e8c4f829 ci: Fix qemu build 2022-09-30 16:14:36 +02:00
5688a84cbc Merge branch 'bugfix/extend_ci_idf_v5.1' into 'master'
ci: Build and Test QEMU on v5.0

See merge request espressif/esp-mqtt!142
2022-08-19 23:45:43 +08:00
9db9ee7648 ci: Build and Test QEMU on v5.0
* Patch the QEMU build
* Use public containers for build only tests on v5.0 and master
2022-08-18 16:51:16 +02:00
5f3cadb44d Merge branch 'bugfix/user_events' into 'master'
client: Add support for user events

See merge request espressif/esp-mqtt!140
2022-08-16 21:30:58 +08:00
97503cceb3 client: Add support for user events
Also supporting configurable queue size for the internal event loop.

Closes https://github.com/espressif/esp-mqtt/issues/230
2022-07-29 09:08:52 +02:00
9186e5fa00 Merge branch 'feature/unregister_event_api' into 'master'
Adds unregister event API

See merge request espressif/esp-mqtt!139
2022-07-28 21:07:25 +08:00
a9a9fe76bf Adds unregister event API
- Added to enable users to unregister event handler.

 Closes https://github.com/espressif/esp-idf/issues/9194
2022-07-28 10:36:24 +00:00
f14eeb9157 Merge branch 'feature/mqtt_config_struct_review' into 'master'
Restructure the client configuration struct

See merge request espressif/esp-mqtt!130
2022-07-20 18:40:24 +08:00
ae53d799da Restructure the client configuration struct
- Groups configuration fields by context.
- Removes user_context in favor of the event loop.
2022-07-13 08:37:20 -03:00
9a56b2f086 Merge branch 'bugfix/ping_timer_restart' into 'master'
MQTT tick not starting on connect and switch to esp_timer

See merge request espressif/esp-mqtt!138
2022-07-05 20:09:11 +08:00
89e5c6014f fix: MQTT tick not starting on connect and switch to esp_timer
- Tick should be updated on connect
- Dependency of system timer removed to avoid issues when updating via
  SNTP

Closes https://github.com/espressif/esp-mqtt/issues/225
2022-06-23 12:43:58 -03:00
493822dc9d Merge branch 'feature/support_mqtt_5' into 'master'
mqtt: Support MQTT5 protocol

See merge request espressif/esp-mqtt!125
2022-06-14 21:40:57 +08:00
fdf2aeb36f Seperate MQTT5 from MQTT 3.1.1 2022-06-14 09:37:46 +00:00
3d275f42b9 mqtt: Support MQTT5 protocol 2022-06-14 09:37:46 +00:00
0aa0a342a1 Merge branch 'bugfix/mqtt_ssl_build' into 'master'
mqtt_tcp: Fix build issue when `MQTT_ENABLE_SSL` is disabled

See merge request espressif/esp-mqtt!137
2022-06-14 17:31:41 +08:00
7253211a45 mqtt_tcp: Fix build issue when MQTT_SSL is disabled 2022-06-14 13:43:45 +05:30
a21c387d62 Merge branch 'refactor/tcp_transport' into 'master'
mqtt_client: Added checks for cleanly-closed connection and timeout

See merge request espressif/esp-mqtt!118
2022-06-09 15:20:24 +08:00
7a31a555e9 Merge branch 'bugfix/fix_esp_mqtt_client_enqueue' into 'master'
mqtt_client: fix esp_mqtt_client_enqueue for len=0 (GitHub PR)

See merge request espressif/esp-mqtt!135
2022-06-08 19:33:38 +08:00
16952ea66f Merge branch 'bugfix/implicit_malloc_host_test' into 'master'
Fix implicit malloc/free inclusion

See merge request espressif/esp-mqtt!134
2022-06-08 18:52:04 +08:00
e05d873aa2 Added checks for cleanly-closed connection and timeout
- Related MR: https://gitlab.espressif.cn:6688/espressif/esp-idf/-/merge_requests/16394
2022-06-08 16:12:11 +05:30
9299f5400f Fix implicit malloc/free inclusion
This fails when building on host
2022-06-08 05:16:29 +00:00
69b6493423 mqtt_client: fix esp_mqtt_client_enqueue for len=0
Commit 372b323 (mqtt_client: Fix mqtt send long data error, 2021-12-21)
removed the length calculation from esp_mqtt_client_enqueue_priv and
added it to esp_mqtt_client_publish. However, esp_mqtt_client_enqueue
was missed. Currently calls to esp_mqtt_client_enqueue appear to send no
data, fix this by adding the length calculation to esp_mqtt_client_enqueue.
2022-05-30 21:56:33 +01:00
7f765cac2c Merge branch 'feature/optimize_mqtt_transport_list' into 'master'
feat(mqtt): Optimize mqtt transport list and remove unused transport

See merge request espressif/esp-mqtt!131
2022-05-23 22:19:24 +08:00
647e0eff32 feat(mqtt): Optimize mqtt transport list and remove unused transport 2022-05-23 22:19:24 +08:00
684843a309 Merge branch 'bugfix/wrong_wss_port_definition' into 'master'
Fix WSS default port selection through menuconfig.

See merge request espressif/esp-mqtt!132
2022-05-17 15:43:37 +08:00
f6caaff254 Fix WSS default port selection through menuconfig.
Evaluate the correct define to select default port.

 - Closes https://github.com/espressif/esp-mqtt/issues/223
2022-05-17 07:16:07 +00:00
64f88b4412 Merge branch 'bugfix/fix_transport_config_documentation' into 'master'
Fix documentation of config struct

See merge request espressif/esp-mqtt!129
2022-05-03 20:09:10 +08:00
e31834c00f Fix documentation of config struct
- Transport selection enum was incorrectly pointed as having precedence
  over URI.

- Added names to unnamed enums and structs on typedefs.

- Reorganize config struct fields grouping fields with related context.
2022-05-02 13:29:39 -03:00
59b48a4d49 Merge branch 'bugfix/keep_alive_ping_periodic' into 'master'
Changes the moment we update keepalive_tick.

See merge request espressif/esp-mqtt!127
2022-04-19 22:16:19 +08:00
2cdcdcb4fa Merge branch 'bugfix/mqtt_fix_int_sign_mismatch' into 'master'
MQTT: Fix signature matching for some integer values

See merge request espressif/esp-mqtt!128
2022-04-12 19:35:51 +08:00
6b794e4708 MQTT: Fix signature matching for integer values
Closes https://github.com/espressif/esp-idf/issues/8482
2022-04-08 19:56:56 +04:00
2c2e6f38b5 Changes the moment we update keepalive_tick.
In order to keep sending keep alive messages in the scenario were client
publish too often with QoS0 the keepalive is updated when the response
is received.
2022-04-07 09:14:03 -03:00
5878e2e8a6 Merge branch 'module_logging_tag_lower_case' into 'master'
Make the mqtt submodule logging tags lower case

See merge request espressif/esp-mqtt!122
2022-04-04 18:54:43 +08:00
fb3184cc14 Make the mqtt submodule logging tags lower case 2022-04-04 10:33:06 +02:00
4874bab356 Merge branch 'bugfix/unused_var' into 'master'
remove unused variable

See merge request espressif/esp-mqtt!124
2022-03-04 18:59:54 +08:00
f83d2a9111 remove unused variable 2022-03-04 07:42:25 +00:00
d3d816ed24 Merge branch 'bugfix/ci_update_for_passing' into 'master'
ci: update images to pass jobs with current IDF

See merge request espressif/esp-mqtt!126
2022-03-04 15:41:24 +08:00
2e508fa6ef ci: update images to pass jobs with current IDF 2022-03-04 11:36:04 +07:00
08ce9ed83f Merge branch 'test/ci_qemu_master' into 'master'
CI: Fix idf-env for build and test against IDFv5.0

See merge request espressif/esp-mqtt!121
2022-02-07 09:03:12 +00:00
b66b9745f6 reduce sizes and message counts for QEMU publish test 2022-02-03 10:39:27 +01:00
3a5334de6b ci: Test with QEMU against the latest IDF 2022-02-03 10:39:19 +01:00
0eda78e9b7 Merge branch 'feature/include_alternative_for_esp_system' into 'master'
Replaced esp_system.h inclusion with esp_random.h and esp_mac.h

See merge request espressif/esp-mqtt!119
2022-01-28 07:21:01 +00:00
b7b858cd7f ci: Run tests against IDF v5.0 only
* Supported build only test with ci-evn-5.0
* Disable temporarily publish-connect test on QEMU with qemu-v5.0:1-20210826
2022-01-28 08:09:27 +01:00
1a96ea3efa Replaced esp_system.h inclusion with esp_random.h and esp_mac.h
Signed-off-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
2022-01-17 15:33:11 +01:00
985078affa Merge branch 'bugfix/ci_image_update' into 'master'
Isolate IDF env for v4.4 and v5.0(master)

See merge request espressif/esp-mqtt!111
2022-01-17 14:00:56 +00:00
4c5a65c79e ci: Isolate IDF env for v4.4 and v5.0(master) 2022-01-17 13:55:06 +01:00
b021fc8e30 Merge branch 'bugfix/remove_legacy_freertos_types_usage' into 'master'
Client: Remove usage of legacy FreeRTOS types

See merge request espressif/esp-mqtt!120
2022-01-17 11:32:20 +00:00
c28a56ddb0 ci: Fix build issues with IDF-4.4 against master
IDF env docker image (v4.4-1) became incompatible with IDF master (v5.0)
2022-01-17 10:22:27 +01:00
6ef98d6510 Client: Remove usage of legacy FreeRTOS types 2022-01-13 00:34:53 +08:00
026253d802 Merge branch 'bugfix/fix_mqtt_send_long_data_error' into 'master'
mqtt_client: Fix mqtt send long data error

See merge request espressif/esp-mqtt!117
2021-12-22 02:15:33 +00:00
372b323535 mqtt_client: Fix mqtt send long data error
Closes https://github.com/espressif/esp-mqtt/issues/214
2021-12-21 15:31:56 +08:00
383e7e5f0f Merge branch 'bugfix/fix_enqueue_api' into 'master'
Client: Fix use esp_mqtt_client_enqueue API to send data, data dup flag will be set 1

See merge request espressif/esp-mqtt!116
2021-12-06 12:01:07 +00:00
df8dc92870 Client: Fix use esp_mqtt_client_enqueue API to send data, data dup flag will be set 1 2021-11-26 15:52:04 +08:00
b86d42c130 Merge branch 'feature/mqtt_client_with_null_id' into 'master'
Adds the possibilty of client with empty id

See merge request espressif/esp-mqtt!114
2021-11-03 09:58:39 +00:00
08c4d62bf4 CI: Fix standard gitlab key 2021-11-03 09:30:08 +01:00
09287a1156 Removes redundant field on mqtt state
Client connection_info was unnecessarilly repeated. Removed from
mqtt_state and kept on mqtt_client.
2021-11-01 18:17:29 +01:00
1fd50dd2cb Adds a config flag to allow an empty client id
This commit covers a use case where the user can select to send an
empty user id.
2021-11-01 18:17:29 +01:00
36de30e46d Merge branch 'bugfix/send_diconnect_msg' into 'master'
Client: Disconnect/Reconnect improvements

See merge request espressif/esp-mqtt!113
2021-10-21 08:34:15 +00:00
320b058e28 CI: Adjust jobs for testing IDFs, cleanup
Removes CI jobs for static analysis and reports as they are not primarily used
2021-10-21 08:39:59 +02:00
3f05b1aedc Client: Fix reconnect/disconnect if auto_reconnect=off
Closes https://github.com/espressif/esp-mqtt/issues/206
2021-10-06 17:46:32 +02:00
86e40f8615 Send disconnect message if client asked to disconnect
https://github.com/espressif/esp-mqtt/issues/208
2021-10-06 17:46:32 +02:00
5ec3702881 Merge branch 'feature/add_suback_payload_flags_to_events' into 'master'
Events: Support qos/dup flags and suback payload in mqtt events (GitHub PR)

See merge request espressif/esp-mqtt!112
2021-10-04 10:53:17 +00:00
de47f1c341 add payload to MQTT_EVENT_SUBSCRIBE
+ documentation
+ cleanup logging

Closes https://github.com/espressif/esp-mqtt/issues/200
Merges https://github.com/espressif/esp-mqtt/pull/203
2021-10-04 10:38:02 +02:00
e1d5a9402f add qos and dup to MQTT_EVENT_DATA 2021-09-23 18:09:39 +02:00
89894bd0c6 Merge branch 'feature/configurable_retransmit' into 'master'
Add configurable retransmit (GitHub PR)

See merge request espressif/esp-mqtt!110
2021-09-15 18:10:50 +00:00
1d10608409 Merge branch 'feature/set_config_error_reporting' into 'master'
Reports config conflicts error to the user

See merge request espressif/esp-mqtt!102
2021-09-15 16:46:35 +00:00
d7b00da517 Merge branch 'bugfix/mqtt_check_certbundle' into 'master'
Fix build issue if cert bundle disabled (GitHub PR)

See merge request espressif/esp-mqtt!109
2021-09-15 16:46:13 +00:00
1b009c840b Config: Add configurable retransmit timeout
sometime user want to configure retransmit timeout due to network or other requirement

Merges https://github.com/espressif/esp-mqtt/pull/199
2021-09-15 18:43:23 +02:00
88f4b8ed50 Reports config conflicts error to the user
- Configuration conflicts were verified, logged but not reported to the
  user.
2021-09-15 15:09:23 +08:00
5b3c81ee48 Config: Fix build issue if WS/WSS transport disabled
Closes https://github.com/espressif/esp-idf/issues/7535
2021-09-10 09:15:41 +02:00
1b71980575 Config: Add error message if certbunde is not enabled
Merges https://github.com/espressif/esp-mqtt/pull/198
2021-09-07 15:42:11 +02:00
4a89bff610 Check CONFIG_MBEDTLS_CERTIFICATE_BUNDLE is set
Fixes a compilation error where `esp_transport_ssl_crt_bundle_attach` is undefined in this scenario.
2021-08-10 15:02:35 -06:00
026ea95338 Merge branch 'remove_outbox_cleanup_function' into 'master'
Removes unnecessary outbox_cleanup

See merge request espressif/esp-mqtt!108
2021-07-09 16:13:48 +00:00
c11c314f44 Merge branch 'bugfix/report_enqueue_error' into 'master'
Fix: Return an error when fail to enqueue

See merge request espressif/esp-mqtt!103
2021-07-09 16:12:55 +00:00
ebef896b00 Removes unnecessary outbox_cleanup
The states that were cleaned by this function, CONFIRMED, are no longer reachable.
Itens were marked with this status previously in PUBCOMP and PUBREL
receive handlers.
2021-07-01 14:40:45 +01:00
7471177fe7 Fix: Return an error when fail to enqueue
The functions that enqueue messages didn't had a return for the
handler, with this the error was only logged instead of returned which
may cause the user to have an ID for a message that was not published.
2021-07-01 09:29:58 +01:00
e24852a4dc Merge branch 'bugfix/qemu_image_esp_env' into 'master'
CI: Use qemu image based on esp-env:v4.4-1

See merge request espressif/esp-mqtt!107
2021-06-28 08:16:56 +00:00
231b274962 CI: Use qemu image based on esp-env:v4.4-1 2021-06-28 08:15:10 +02:00
f10321a53b Merge branch 'bugfix/remove_unnecessary_parenteses' into 'master'
Remove unnecessary parentheses.

See merge request espressif/esp-mqtt!101
2021-06-24 17:22:30 +00:00
db13533904 Remove unnecessary parentheses.
- Removed extra parentheses on definition of certificate bundle attach.
2021-06-24 18:35:26 +02:00
831d25cb56 Merge branch 'update/qemu_test_IDFv4.3' into 'master'
CI: Update QEMU image and test against IDF v4.4-dev (plus minor fixes)

See merge request espressif/esp-mqtt!104
2021-06-24 16:34:31 +00:00
a7e5accc7e CI: Temporariy update QEMU image with python 3.7.0
This will be removed once we updated QEMU image, based on the new CI
environment docker image.
2021-06-24 16:34:22 +02:00
90f0bf8dd4 Updated docker images to work with latest IDFv4.4 2021-06-24 07:40:43 +02:00
1a94efe8b9 outbox: Cleanup all items when connection closes 2021-06-24 06:31:29 +02:00
c4b7324bd6 Merge branch 'feature/remove_unnecessary_queue_requests' into 'master'
Removes unnecessary calls to outbox_set_pending

See merge request espressif/esp-mqtt!105
2021-06-23 06:46:06 +00:00
a4d5ee0f12 Merge branch 'feature/make_abort_connection_void' into 'master'
MQTT: Makes abort connection function void.

See merge request espressif/esp-mqtt!106
2021-06-23 06:45:15 +00:00
67553aba45 MQTT: Makes abort connection function void.
The function only returned ESP_OK and the call was always ignored.
2021-06-18 17:18:51 +01:00
36a3990404 Removes unnecessary calls to outbox_set_pending
The call of this function is unnecessary for PUBACK and PUBCOMP,
also the item is deleted on the call of is_valid_mqtt_msg and the
function allways fail.
2021-06-18 14:11:21 +01:00
2e15c9a5fe Fix IDF supported features: cert-bundle from v4.4 2021-06-17 12:33:34 +02:00
626dc3645b CI: Add build test for IDF v4.3 2021-06-17 12:33:34 +02:00
c7ae67b7f0 CI: Update QEMU image and test against IDF master(v4.4-dev)
Also using test-apps instead of weekend tests.
2021-06-17 12:33:18 +02:00
afba070093 Merge branch 'bugfix/remove_unused_defines' into 'master'
Removes unused defines.

See merge request espressif/esp-mqtt!100
2021-06-01 05:32:40 +00:00
eec6f0e17d Removes unused defines.
- mqtt_config.h had some defines that were not used. This removes them.

Closes https://github.com/espressif/esp-mqtt/issues/194
2021-05-31 13:29:25 +01:00
78fcf23947 Merge branch 'bugfix/partial_transport_writes' into 'master'
Address partial writes and retain flags

See merge request espressif/esp-mqtt!99
2021-05-26 15:56:08 +00:00
048f12f55f Merge branch 'feature/add_crt_bundle' into 'master'
Added support for certificate bundle

See merge request espressif/esp-mqtt!98
2021-05-26 15:54:21 +00:00
ff8226a464 Merge branch 'bugfix/missing_path_field_in_config' into 'master'
Fix: Adds missing field at config struct.

See merge request espressif/esp-mqtt!96
2021-05-26 15:51:45 +00:00
7db36f9177 Merge branch 'feature/mqtt_ssl_optimize' into 'master'
esp-mqtt: Add configure to separate code for depend on ssl

See merge request espressif/esp-mqtt!95
2021-05-26 15:51:15 +00:00
8f3cac8c36 Client: Add optimize for depend on ssl 2021-05-24 16:14:02 +02:00
d8c9c7a9e7 Add support for partial transport writes
Partially addresses https://github.com/espressif/esp-idf/issues/6940
2021-05-24 10:58:42 +02:00
a00a3134c6 Add support for Retain flag in messages posted by events
Closes https://github.com/espressif/esp-mqtt/issues/193
2021-05-24 10:57:37 +02:00
06157be118 Add crt_bundle function pointer to be accessible from esp_mqtt_client_config_t 2021-05-24 10:32:10 +02:00
e1a90d0161 Merge branch 'bugfix/outbox_del_single_STAILQ_FOREACH' into 'master'
mqtt_outbox: Use STAILQ_FOREACH for outbox_delete_single_expired

See merge request espressif/esp-mqtt!97
2021-05-22 06:01:35 +00:00
5b27d1896e Fix: Adds missing field at config struct.
If an user chooses to config broker by hostname it wasn't possible to
 add the path.
2021-05-14 15:57:42 +01:00
ff8e64839a mqtt_outbox: Use STAILQ_FOREACH for outbox_delete_single_expired
For the delete one entry and return case, no need to use STAILQ_FOREACH_SAFE.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
2021-04-20 11:27:42 +08:00
1db731f985 Merge branch 'feature/mqtt_unit_test_cleanup' into 'master'
Reduce the includes used in files.

See merge request espressif/esp-mqtt!93
2021-04-07 11:37:00 +00:00
87fcce72c9 Reduce the includes used in all files.
- To reduce the dependencies to the minimal the number of includes was
  reduced.
2021-04-07 10:49:49 +01:00
2b20b5117c Merge branch 'bugfix/mqtt_add_null_check' into 'master'
esp-mqtt: Add null checks for public APIs

See merge request espressif/esp-mqtt!94
2021-03-10 17:59:17 +00:00
2f57985c0b esp-mqtt: Added nullchecks for public APIs
Closes IDFGH-4724
Closes https://github.com/espressif/esp-mqtt/issues/185
2021-03-04 18:30:27 +04:00
9fdf7b6138 Merge branch 'bugfix/disable_file_in_logs' into 'master'
platform: Remove __FILE__ macro from error logs

See merge request espressif/esp-mqtt!92
2021-02-23 17:07:26 +00:00
169b6986eb platform: Remove __FILE__ macro from error logs 2021-02-22 18:11:41 +01:00
fd2d04e687 Merge branch 'bugfix/vs_nullcheck_on_malloc' into 'master'
Config: Add missing nullcheck after cfg password allocation

See merge request espressif/esp-mqtt!91
2021-02-11 23:39:32 +08:00
001dc1a95e Config: Add missing nullcheck after cfg password allocation
Partially addresses https://github.com/espressif/esp-idf/issues/6440
2021-02-11 15:54:45 +01:00
a5a60752c0 Merge branch 'bugfix/handle_missing_mqtt_states' into 'master'
Renames states and add missing handler on esp mqtt task

See merge request espressif/esp-mqtt!90
2021-02-02 22:14:09 +08:00
369f4207f8 Renames states and add missing handler on task
- The state transition on esp_mqtt_task was missing 2 states
- MQTT_STATE_ERROR removed
- Added a default case for state transition.
- Renamed MQTT_STATE_WAIT_TIMEOUT -> MQTT_STATE_WAIT_RECONNECT
2021-01-27 17:33:22 +00:00
1a64f3176c Merge branch 'feature/public_mqtt_supported_features' into 'master'
Moves mqtt_supported_features to public includes.

See merge request espressif/esp-mqtt!89
2021-01-21 18:41:31 +08:00
0213382593 mqtt: Moves mqtt_supported_features to public includes.
- To simplify user code to support multiple IDF versions.

Closes https://github.com/espressif/esp-mqtt/issues/184
2021-01-21 09:49:24 +00:00
a74adfa9eb Merge branch 'client_init_refactor' into 'master'
Clean client init

See merge request espressif/esp-mqtt!87
2021-01-21 15:57:52 +08:00
7a38867ce2 Merge branch 'destroy_config_refactor' into 'master'
Makes esp_mqtt_destroy_config void

See merge request espressif/esp-mqtt!86
2021-01-21 15:24:06 +08:00
2530edbdce Merge branch 'bugfix/allow_zero_length_username' into 'master'
mqtt_msg: Set zero length username if password is set without username

See merge request espressif/esp-mqtt!88
2021-01-21 15:22:05 +08:00
e05ed2ce18 mqtt: Clean client init
- Moves check and copy of parameter to a function to reduce repetition
- Removes cfg variable to be explicit about what is being modified.
2021-01-19 11:54:09 +00:00
3efac7b7fa mqtt_msg: Set zero length username if password is set without username
Some cloud server (e.g. exosite) takes empty username with password.

When password is set without username, the current esp-mqtt implementation will
ignore the username and only set password. This violates MQTT-3.1.2-22 [1].
To address this issue, send zero length username if password is set without username.

[1] MQTT-3.1.2-22: If the User Name Flag is set to 0 then the Password Flag MUST be set to 0.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
2021-01-19 08:36:17 +01:00
b834be80a5 mqtt: Makes esp_mqtt_destroy_config void
- Makes the function a nop in case of NULL config.
2021-01-18 11:42:59 +00:00
9ea804e0ab Merge branch 'feature/queue_if_disconnect' into 'master'
esp-mqtt: More configs to queue when disconnected, events on delete, incremental msg-id

See merge request espressif/esp-mqtt!85
2020-12-21 19:42:15 +08:00
e2de0f3e3e Publish: Allow for qos=0 messages to be stored using esp_mqtt_client_enqueue()
The API presents a boolean parameter to control storing the qos=0
messages into the internal outbox
2020-12-15 19:43:33 +01:00
2e35d4d4d5 Events: Add new event to report deleted messages from outbox 2020-12-09 10:14:54 +01:00
f44dcb1c26 Config: Add a new option to disable publishing when disconnected
Related https://github.com/espressif/esp-mqtt/pull/177
2020-12-09 10:14:54 +01:00
dc7fd5c0b1 Publish: Add new API to enqueue qos>0 messages
Closes https://github.com/espressif/esp-mqtt/issues/155
2020-12-09 10:14:54 +01:00
8bb4a26f46 Config: Add a new option to use incremental message id
This option is off by default, so the client still uses
random message id unless CONFIG_MQTT_MSG_ID_INCREMENTAL is set

Closes https://github.com/espressif/esp-mqtt/issues/176
2020-12-09 10:12:57 +01:00
f65d5d05db Cleanup public include dirs 2020-12-06 11:26:03 +01:00
cef3e16c5d Merge branch 'bugfix/unused_mqtt_header_state_t' into 'master'
Remove unused mqtt_header_state_t

See merge request espressif/esp-mqtt!84
2020-12-03 18:48:17 +08:00
b7158a4aea mqtt: Remove unused mqtt_header_state_t
mqtt_header_state_t was added by commit 0450bd0093 ("MQTT Client:  Added support for receiving empty payload"),
but it's no longer used since commit fd564b1f17 ("client receive: refactor receive to read only one message to fragment only payload for longer messages").
Thus remove the unused mqtt_header_state_t.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
2020-11-23 16:24:33 +08:00
da850b0add Merge branch 'feature/support_no_keepalive' into 'master'
mqtt_config: Add config value to disable keepalive mechanism

See merge request espressif/esp-mqtt!83
2020-11-19 22:07:05 +08:00
8562437c8a mqtt_config: Add config value to disable keepalive mechanism
Added a separate config value to allow disable the keepalive mechanism (and keep the existing API the same)
Internally though, the 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

Closes https://github.com/espressif/esp-mqtt/issues/179
2020-11-18 14:41:44 +01:00
e8be6c3aa7 Merge branch 'feature/add_get_outbox_size' into 'master'
Add esp_mqtt_client_get_outbox_size API

See merge request espressif/esp-mqtt!82
2020-11-18 16:45:27 +08:00
65d8a813ea Merge branch 'bugfix/missing_unlock_and_cleanup' into 'master'
Minor fixes and cleanup

See merge request espressif/esp-mqtt!81
2020-11-18 16:44:41 +08:00
36d721e60b Merge branch 'bugfix/mqtt_err_flags_extention' into 'master'
error reporting: extended error event to use errno captured in transports

See merge request espressif/esp-mqtt!80
2020-11-13 05:10:58 +08:00
0a1d9d0300 mqtt: Add esp_mqtt_client_get_outbox_size API
Allow application to get current outbox_size.
Application may try to send many publish request for a long period and then
system can hit OOM when publish QoS>1 with a busy borker.
Reduce OUTBOX_EXPIRED_TIMEOUT_MS does not help too much because the publish
freauency depends on the data received in different environment.
i.e. In some environment, sometimes it's easy to hit OOM before reaching OUTBOX_EXPIRED_TIMEOUT_MS.

To avoid such issue, add esp_mqtt_client_get_outbox_size API, so the application
can stop publishing to avoid OOM when outbox takes too much memory.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
2020-11-11 17:13:32 +08:00
673086e13a mqtt_outbox: Remove unused retry_count field from outbox_item_t
Signed-off-by: Axel Lin <axel.lin@ingics.com>
2020-11-09 16:08:22 +08:00
259baaec96 config: Fix typo for configuring OUTBOX_EXPIRED_TIMEOUT_MS
In esp-idf, it uses CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS rather than
CONFIG_OUTBOX_EXPIRED_TIMEOUT_MS.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
2020-11-09 16:07:10 +08:00
845c2a3a1e mqtt: Fix missing MQTT_API_UNLOCK in esp_mqtt_client_stop error path
Fixes: 5e17dcaeb2 ("MQTT: Fix esp_mqtt_client_stop deadlock")
Signed-off-by: Axel Lin <axel.lin@ingics.com>
2020-11-09 16:06:58 +08:00
23c8e1ecf5 error reporting: extended error event to use errno captured in transports
Also renamed error type MQTT_ERROR_TYPE_ESP_TLS to
MQTT_ERROR_TYPE_TCP_TRANSPORT, as the former was confusing and might
have implied the error occurred in TLS layer.

Applicable IDF version >= v4.3

Closes https://github.com/espressif/esp-idf/issues/5906
2020-11-04 08:01:06 +01:00
d6613e995b Merge branch 'bugfix/size_t_for_all_lengths' into 'master'
Use size_t for all lengths

See merge request espressif/esp-mqtt!79
2020-10-12 18:16:29 +08:00
b9db8d9020 Use size_t for all lengths
Previously, uint32_t and size_t were used interchangeably. These types are
interchangeable on Xtensa gcc (uint32_t == size_t == unsigned int), but not on most
other 32-bit gcc architectures (where uint32_t == unsigned long, size_t ==
unsigned int).
2020-10-09 16:33:12 +11:00
fcd7f0d083 Merge branch 'bugfix/network_timeout' into 'master'
Allow to configure network timeout

See merge request espressif/esp-mqtt!78
2020-09-02 19:38:15 +08:00
a03228ac46 Allow to configure network timeout
Merges https://github.com/espressif/esp-mqtt/pull/166
2020-09-02 08:36:01 +02:00
01594bf118 Merge branch 'feature/mqtt_support_esp_ds' into 'master'
esp-mqtt: Add support for Digital Signature (through ESP-TLS)

See merge request espressif/esp-mqtt!71
2020-08-18 15:22:41 +08:00
7d8e59de00 mqtt: Add support for Digital Signature (through ESP-TLS)
Digital Signature enables hardware accelerated RSA signature
for TLS handshake.The RSA private key(client key) is also stored in
encrypted format and ecryption key is stored in hardware(efuse) which adds
additional level of security for mutual authentication.
* Digital Signature is only supported for ESP32-S2.

Applicable IDF version >= v4.3
2020-08-18 11:55:43 +05:30
ae408d9a69 Merge branch 'feature/outbox_limit' into 'master'
MQTT: Cleanup expired messages when offline

See merge request espressif/esp-mqtt!76
2020-08-18 14:08:57 +08:00
a8ef2a434b Merge branch 'bugfix/read_error_event' into 'master'
MQTT: add dispatch error event for read errors

See merge request espressif/esp-mqtt!75
2020-08-18 14:07:50 +08:00
867773e423 Merge branch 'fix/secure_element_feature' into 'master'
esp-mqtt: i) fix version check for secure_element

See merge request espressif/esp-mqtt!70
2020-08-18 14:04:39 +08:00
ac7209049f Merge branch 'bugfix/stop_from_event' into 'master'
MQTT: Fix esp_mqtt_client_stop deadlock

See merge request espressif/esp-mqtt!74
2020-08-17 22:01:08 +08:00
bdadd77c6e mqtt: deleted expired messages even when offline
As long as the client was disconnect no cleanup were performed,
consuming memory for every message published. Even if they were already
expired and would be discarded when reconnected.

Also moves delete of expired msgs before retransmit is done.
This avoids situtations where a message could be sent even if it was
expired.

Closes https://github.com/espressif/esp-idf/issues/5668
2020-08-10 16:42:32 +08:00
f7325bfa10 mqtt: esp_mqtt_client_publish now returns msd id for QoS>0 when offline 2020-08-10 14:47:05 +08:00
d4aaec08ff MQTT: add dispatch error event for read errors
Closes https://github.com/espressif/esp-idf/issues/5704
2020-08-07 17:54:40 +08:00
5e17dcaeb2 MQTT: Fix esp_mqtt_client_stop deadlock
esp_mqtt_client_stop would lead to a deadlock (with itself) when called
from the event handler.

Updated comments to reflect that some functions should not be called from
the event handler.

Closes https://github.com/espressif/esp-mqtt/issues/163
2020-08-04 19:26:37 +08:00
db4bce01ab mqtt: i)fix version check for secure_element
ii) fix secure_element error return

The feature allows use of secure element for TLS connections, which makes use of hardware security for storage of client private keys(only keys with ECC algorithm)

Applicable IDF versions: >= 4.2
2020-08-03 09:45:27 +05:30
702da6d528 Merge branch 'bugfix/build_test_fix' into 'master'
CI: Fixes build test issues

See merge request espressif/esp-mqtt!72
2020-07-31 19:40:25 +08:00
0bafcc5188 ci: Add IDF v4.2 to build tests
Also fixes build issues when default config carried over IDF releases --
always remove previous `sdkconfig` before a new build
2020-07-30 16:54:00 +02:00
651c2fb4a2 ci: Fix travis build with legacy IDFs 2020-07-24 14:56:12 +02:00
d754293d25 Merge branch 'feature/check_cfg_consistency' into 'master'
Add check for consistency between config settings

See merge request espressif/esp-mqtt!69
2020-07-17 00:05:04 +08:00
8a412c147d Add check for consistency between config settings
Warn user if the MQTT config seems misconfigured, e.g.
user specifies a SSL certificate, but SSL not activated
2020-07-08 12:54:00 +08:00
5b8c04f348 Merge branch 'feature/allow_query_in_uri' into 'master'
Allow the query part of the uri to be a part of the path

See merge request espressif/esp-mqtt!68
2020-06-29 21:16:48 +08:00
40b06deb10 Allow the query part of the uri to be a part of the path
Closes IDFGH-3565
Closes https://github.com/espressif/esp-mqtt/issues/161
2020-06-29 10:33:42 +08:00
109985d3ad Merge branch 'feature/enable_tls_with_secure_element' into 'master'
esp-mqtt: add support for tls with secure element (ATECC608A)

See merge request espressif/esp-mqtt!66
2020-06-25 13:42:41 +08:00
a7ff9afa3f esp-mqtt: add support for tls with secure element (ATECC608A)
Closes https://github.com/espressif/esp-mqtt/issues/156
2020-06-25 10:36:58 +05:30
2f9b337071 Merge branch 'feature/skip_cmn_name_check' into 'master'
SSL: add config option for skipping common name check

See merge request espressif/esp-mqtt!67
2020-06-10 15:13:58 +08:00
5e8950e681 SSL: add config option for skipping common name check
Closes IDFGH-3408
Closes https://github.com/espressif/esp-mqtt/issues/158
2020-06-09 14:23:40 +08:00
6bc94add89 Merge branch 'bugfix/confusing_print' into 'master'
mqtt_print: Change the message printed after MQTT connection failure

See merge request espressif/esp-mqtt!65
2020-04-28 19:04:34 +08:00
20bf9928d4 Merge branch 'bugfix/block_api_docs' into 'master'
docs: Makes clear that publish API could block

See merge request espressif/esp-mqtt!64
2020-04-28 15:22:46 +08:00
fb41520206 mqtt_print: Change the message printed after MQTT connection failure
Since the original message was confusing.
2020-04-24 23:05:47 +05:30
615aeae0c2 docs: Makes clear that publish API could block
Closes https://github.com/espressif/esp-idf/issues/5077
2020-04-24 14:26:37 +02:00
0c3d306589 Merge branch 'bugfix/print_messages' into 'master'
Some changes to debug prints

See merge request espressif/esp-mqtt!63
2020-04-08 01:33:01 +08:00
b02746492a esp_mqtt: Change an error print to use ESP_LOGE instead of ESP_LOGI
And another one changed from LOGI to LOGD
2020-04-06 12:13:18 +05:30
50dc010b97 Merge branch 'bugfix/abort_race_condition' into 'master'
esp_mqtt_abort_connection: Fixed an issue which could result in a race...

See merge request espressif/esp-mqtt!62
2020-04-01 22:39:06 +08:00
dc1a635a97 esp_mqtt_abort_connection: Fixed an issue which could result in a race condition and subsequent crash 2020-03-30 19:59:27 +05:30
0fc904c5d8 Merge branch 'feature/config_mqtt_task_prio' into 'master'
config: option to configure mqtt task priority

See merge request espressif/esp-mqtt!61
2020-03-20 14:50:07 +08:00
d8e2081332 config: option to configure mqtt task priority 2020-03-17 13:34:27 +01:00
9b750651fc Merge branch 'bugfix/add_out_buff_size' into 'master'
config: option to configure output buffer size

See merge request espressif/esp-mqtt!60
2020-03-12 04:31:35 +08:00
61a8f4b63c ci: fix build issue (stale CMake cache) between 4.1 and 4.2 2020-03-10 16:19:51 +01:00
f243225521 config: option to configure output buffer size
Both input and output buffers had the same size, but it is desirable in embedded environment to use asymetric buffers. Added configuration option to defined output buffer size, if not defined output buffer defaults to the same size as the input buffer.

Closes https://github.com/espressif/esp-mqtt/issues/152
2020-03-10 15:26:49 +01:00
8a1e1a5a9f Merge branch 'bugfix/mqtt_cpp_build' into 'master'
Minor fixes: C++ invalid event, Resend for QoS > 0

See merge request espressif/esp-mqtt!59
2020-02-21 16:15:23 +08:00
62d1509961 Resend queued: Set duplicate flag for both qos1 and qos2
Closes https://github.com/espressif/esp-mqtt/issues/151
2020-02-20 16:00:15 +01:00
e2aa29d2ea Client: Fix C++ build failing on incorrect event enum conversion
Closes https://github.com/espressif/esp-idf/issues/4787
2020-02-20 14:44:38 +01:00
d801f03f46 Merge branch 'bugfix/missed_mutex_unlock' into 'master'
Fixed missing mutex unlock if subscribe message fails to be created

See merge request espressif/esp-mqtt!58
2020-02-10 15:43:27 +08:00
a9036b82a4 CI: make the qemu tests use IDF release branch
Building the mqtt against idf release/v4.1 for the qemu tests to avoid potential issues on IDF master with running qemu
2020-02-10 08:01:10 +01:00
3e4f91ae50 Client: unlock if unsubscribe message fails to be created
In a similar way as for the subscribe message
2020-02-10 08:01:10 +01:00
7983357489 Client: unlock if subscribe message fails to be created
Closes https://github.com/espressif/esp-mqtt/issues/150
2020-02-10 08:00:45 +01:00
d5e915296e Merge branch 'bugfix/failed_to_compile_on4.0' into 'master'
fix compilation issue on v-4.0

See merge request espressif/esp-mqtt!57
2020-02-03 23:53:03 +08:00
9e20c7ae3d CI: Add checks to build against different IDF releases 2020-02-03 10:55:42 +01:00
38eab46f14 Fix compilation issue with IDF version 4.0 and lower
Closes https://github.com/espressif/esp-mqtt/issues/149
2020-01-31 21:42:45 +01:00
b963a5cd86 Merge branch 'bugfix/outbox_tick_type' into 'master'
Various fixes in mqtt library

See merge request espressif/esp-mqtt!55
2020-01-31 21:11:27 +08:00
2994c3f273 receive longer (websocket) data with standard tcp_transport reads
closes IDF-1084
2020-01-30 08:32:24 +01:00
420441b677 set separate ssl connection properties before transport connect 2020-01-30 08:31:59 +01:00
bbcf078a2b fix possible double free of client config if init fails 2020-01-29 08:25:05 +01:00
ed90a64551 client: queued oversized messaged even if not connected 2020-01-29 08:25:05 +01:00
f7941e29be mqtt_outbox: fixed outbox_destroy() to correctly delete all queued messages
Closes https://github.com/espressif/esp-idf/issues/4643
Closes IDFGH-2558
Closes https://github.com/espressif/esp-mqtt/issues/148
Closes IDFGH-2599
Closes https://github.com/espressif/esp-mqtt/issues/147
Closes IDFGH-2598
2020-01-29 08:22:52 +01:00
3a47e3abae client locking: used recursive mutex instead to avoid getting the code too complex 2020-01-27 12:26:10 +01:00
9eca3f6db9 mqtt_client: set_config to update ssl-transport configuration
closes https://github.com/espressif/esp-mqtt/issues/146
closes IDFGH-2534
2020-01-25 22:24:00 +01:00
7087193093 mqtt_msg: address const correctness 2020-01-25 21:57:02 +01:00
89a0c1fc95 removed examples from the submodule
Valid and tested examples are always in esp-idf. these examples were for reference and might and have coused some confussion
2020-01-25 21:57:02 +01:00
6e08f6a04f mqtt_outbox: fix to store timestamps in long-long format
closes https://github.com/espressif/esp-mqtt/issues/144
closes IDFGH-2491
2020-01-25 21:57:02 +01:00
8ab095b5bb Merge branch 'feature/protocol_ver_rt_cfg' into 'master'
MQTT: Add runtime selection of mqtt protocol version

See merge request espressif/esp-mqtt!54
2020-01-20 16:41:55 +08:00
616fa257fb Merge branch 'feature/large_buffers' into 'master'
Support larger buffers and messages

See merge request espressif/esp-mqtt!56
2020-01-17 17:15:10 +08:00
7ac0a42831 MQTT: Add runtime selection of mqtt protocol version
Add config option for selecting protocol version at runtime.

This also fixed MQTT protocol version 3.1 which wasnt working with the original implementation

Closes https://github.com/espressif/esp-idf/issues/4448
Closes IDFGH-2311
Closes IDF-1320
2020-01-09 14:49:33 +08:00
ab1e8d7969 Support larger buffers and messages
Use `uint32_t` instead of `uint16_t` for message and buffer lengths.
This is necessary for receiving messages that are larger than 65K.
2020-01-08 15:00:10 -05:00
86fc8b7584 Merge branch 'feature/support_clientkey_password' into 'master'
add support for password protected client-key

See merge request espressif/esp-mqtt!53
2020-01-09 02:57:30 +08:00
2684ed413d add support for password protected client-key 2020-01-08 09:05:18 +01:00
f74fe3d887 Merge branch 'bugfix/jira_workflow' into 'master'
fix sync issues and pull requests to jira

See merge request espressif/esp-mqtt!52
2020-01-06 14:59:05 +08:00
acc91bacf3 fix sync issues and pull requests to jira 2020-01-03 08:11:00 +01:00
057f140228 Merge branch 'bugfix/fix_connect_timeout' into 'master'
waiting for entire connack message with configured network timeout

See merge request espressif/esp-mqtt!50
2019-12-23 15:57:16 +08:00
97f91eda5c wait for the entire connack message with the configured timeout
Configured network timeout was used to receive separate characters
in the message. This change waits for the configured timeout if reading
the mqtt packet was left in progress (mqtt_message_receive() returns 0)

Closes FCS-254
2019-12-23 07:54:59 +01:00
716b8625ba Merge branch 'feature/qemu_tests' into 'master'
ci: added job with publish tests on qemu

See merge request espressif/esp-mqtt!51
2019-12-23 14:52:47 +08:00
b25077a338 ci: add pushlish weekend tests to all pipelines (running on qemu) 2019-12-19 10:58:58 +01:00
99586c2768 Merge branch 'bugfix/event_handler_mem_leak' into 'master'
Fixed bug where the event loop wouldn't get cleaned up during destroy.

See merge request espressif/esp-mqtt!49
2019-12-04 18:50:43 +08:00
17e2f68e43 Fixed bug where the event loop wouldn't get cleaned up during destroy.
The event loop would never get deleted due to the event loop handle being
cleared to 0 before checking if it exists.

Closes https://github.com/espressif/esp-idf/issues/4433
Closes IDFGH-2293
2019-12-04 11:12:17 +08:00
9a5187771a Merge branch 'bugfix/publish_before_connect' into 'master'
Fixed crash due to publishing before successful transport connect.

See merge request espressif/esp-mqtt!48
2019-11-23 03:39:59 +08:00
e8bb0bcf6f ci: fixed ci build with latest idf using up to date compiler 2019-11-22 20:29:13 +01:00
9ca997d2d4 Fix potential memory leak if failing to create mutex
Closes https://github.com/espressif/esp-idf/issues/4384
Closes IDFGH-2235
2019-11-22 20:28:45 +01:00
9655845fdc Fixed crash due to publishing before successful transport connect.
Initialization of the outgoing message buffer is now done during mqtt_init,
which means messages can be queued before the first connection is made.

The client now checks for fail_message after creating a message, and cancels
the current operation if this happens. Updated error handling in client_publish
to be more inline with API documentation.

Closes https://github.com/espressif/esp-idf/issues/4349
Closes https://github.com/espressif/esp-mqtt/issues/140
2019-11-22 20:28:45 +01:00
1cd0885611 Merge branch 'feature/alpn_support' into 'master'
Add support for ALPN

See merge request espressif/esp-mqtt!46
2019-11-20 21:06:48 +08:00
e1ab64f0d8 Add support for ALPN
Closes IDF-1162

Closes https://github.com/espressif/esp-mqtt/issues/137
2019-11-20 17:30:58 +08:00
c1766c0f56 Merge branch 'feature/configurable_recon_time' into 'master'
Add reconnect time as a configurable parameter.

See merge request espressif/esp-mqtt!47
2019-11-20 17:12:45 +08:00
3da472fd37 Add reconnect time as a configurable parameter.
Closes IDF-1126
2019-11-18 14:43:44 +08:00
566b034984 Merge branch 'bugfix/err_event_mqtt_related' into 'master'
ADD: Get the response code from a failing connection.

See merge request espressif/esp-mqtt!41
2019-10-17 19:00:21 +08:00
e3b013e2db Extended error structure to be used in mqtt library and include mqtt
specific errors.
Corrected typos in comments and log messages
2019-10-09 11:22:02 +02:00
67042a1315 ADD: Get the response code from a failing connection.
This commit adds an event information "connect_return_code" that is written
when the client state is MQTT_STATE_INIT, and the connection fails.

This event info can then be written by the user app to find out the reason
of the fail connection.

Merges https://github.com/espressif/esp-mqtt/pull/100
2019-10-09 09:23:53 +02:00
430676cadb Merge branch 'bugfix/early_retransmit' into 'master'
Fix early retransmit

See merge request espressif/esp-mqtt!44
2019-10-03 20:21:56 +08:00
52cdfa9087 Fix early retransmit
The time for retransmitting a message was set before transfer was done. This ment that if the transfer speed is slow or the message is big then it would be possible to trigger a retransmit too early.

Closes https://github.com/espressif/esp-mqtt/issues/131
2019-10-03 14:03:32 +02:00
40302a3d43 Merge branch 'bugfix/pulished_events_not_posted' into 'master'
MQTT: fix MQTT_PUBLISHED_EVENT not always being posted

See merge request espressif/esp-mqtt!43
2019-10-03 19:58:36 +08:00
3e35fc8323 MQTT: fix MQTT_PUBLISHED_EVENT not always being posted
- Some PUBLISHED events would not be posted due to outbox messages being deleted before receiving PUBCOMP.
 - Current pending_message is no longer used to check for acknowledgements, as it doesn't work with multiple or out of order messages.

Closes https://github.com/espressif/esp-mqtt/issues/132
2019-10-03 13:28:51 +02:00
78e2a7050e Merge branch 'bugfix/mqtt_docs_fix' into 'master'
docs: Updated publish message return code to make it clear that message_id is always 0 for QoS 0

See merge request espressif/esp-mqtt!42
2019-10-03 19:25:47 +08:00
d01c77f70b Merge branch 'feature/error_check_for_null_msgs' into 'master'
Error checks for sending null messages

See merge request espressif/esp-mqtt!39
2019-10-03 19:14:36 +08:00
59b228e0ad Merge branch 'bugfix/err_report_on_publish' into 'master'
Fix not dispatching MQTT_EVENT_ERROR

See merge request espressif/esp-mqtt!40
2019-10-03 17:58:15 +08:00
9fbd7d9244 docs: Updated publish message return code to make it clear that message_id is always 0 for QoS 0
Closes https://github.com/espressif/esp-mqtt/issues/127
2019-09-30 08:05:51 +02:00
2e0e93a2d3 Add a check when publishing data to be able to publish a message without data without crashing.
Signed-off-by: Marius Vikhammer <marius.vikhammer@espressif.com>

Merges https://github.com/espressif/esp-mqtt/pull/117
2019-09-24 18:25:55 +08:00
2b04d177c7 Add a check when publishing data to verify that if some data length is set, data pointer cannot be NULL, in which case an error is returned.
Signed-off-by: Marius Vikhammer <marius.vikhammer@espressif.com>
2019-09-24 18:24:52 +08:00
176be08f75 Fix not dispatching MQTT_EVENT_ERROR
If a publish failure ocurred, MQTT_EVENT_ERROR was not delivered to handler set with esp_mqtt_client_register_event
2019-09-14 21:16:31 -03:00
04253b2b07 Merge branch 'featrue/enable_global_ca_store' into 'master'
client: added config option to enable global ca strore

See merge request espressif/esp-mqtt!38
2019-08-30 22:40:14 +08:00
0234f6e538 client: added config option to enable global ca strore
closes https://github.com/espressif/esp-mqtt/issues/125
2019-08-23 14:33:35 +02:00
1134cb234c Merge branch 'feature/support_der_certs' into 'master'
Feature/support der certs

See merge request espressif/esp-mqtt!37
2019-08-23 02:30:58 +08:00
9a56cc7e14 add der-format support for tls-certificates/keys 2019-08-22 15:11:49 +02:00
54c0161481 Merge branch 'feature/mqtt_use_new_event' into 'master'
MQTT uses new event

See merge request espressif/esp-mqtt!34
2019-08-21 17:20:26 +08:00
fb3d2107cd MQTT examples use new event 2019-08-16 16:15:54 +08:00
92aa01deb8 Merge branch 'bugfix/deadlock_when_close' into 'master'
Bugfix/deadlock when close

See merge request espressif/esp-mqtt!36
2019-08-08 18:12:17 +08:00
cbae6343e9 fix deadlock between xEventGroupWaitBits and API lock semaphore
Merges https://github.com/espressif/esp-mqtt/pull/124
Closes https://github.com/espressif/esp-mqtt/issues/122
2019-08-08 11:54:42 +02:00
2fef1a07c5 Merge branch 'feature/psk_auth' into 'master'
psk ssl could be used to authenticate with mqtt broker as an alternative to cerificate verification

See merge request espressif/esp-mqtt!35
2019-07-29 22:38:14 +08:00
117eef2dad psk ssl could be used to authenticate with mqtt broker as an alternative to cerificate verification
Closes https://github.com/espressif/esp-mqtt/issues/95
2019-07-22 14:26:47 +02:00
dc37d3a065 Merge branch 'feature/transport_pass_error_codes' into 'master'
transport pass error codes to user code

See merge request espressif/esp-mqtt!33
2019-07-18 02:33:44 +08:00
0cc4077bd3 modified error type to be a generic handle to capture different types of errors 2019-07-04 09:12:40 +02:00
65bf2255d7 adding error event with error code 2019-07-03 08:49:54 +02:00
e85430def7 Merge branch 'bugfix/mqtt_fix_close_if_never_connected_crash' into 'master'
MQTT Client: Check for connection before sending disconnect message

See merge request idf/esp-mqtt!32
2019-07-03 14:15:47 +08:00
d9faeb47a3 fix resending subscribe messages
subscribe and unsubscribe messages were pushed to queue, but TRANSMIT flag wasn't set, so they were automatically retransmitted
2019-06-27 16:39:42 +02:00
82fa03a508 fixed possible race conditions in public API of mqtt_client
- Modified most of the public API to lock even if checking for connection state
- Updated `esp_mqtt_set_config` locks to be used also from callbacks (in mqtt-task context)
- Moved initialization of event_loop out of esp_mqtt_set_config
2019-06-27 16:36:12 +02:00
7223302deb MQTT Client: Check for connection before sending disconnect message
Closes https://github.com/espressif/esp-idf/issues/3619
Closes https://github.com/espressif/esp-mqtt/issues/120
Merges https://github.com/espressif/esp-mqtt/pull/118

Signed-off-by: David Cermak <cermak@espressif.com>
2019-06-27 16:33:58 +02:00
11f884623b Merge branch 'idf' to 'master'
Integration of ESP-MQTT to IDF

See merge request idf/esp-mqttmake
2019-06-10 14:51:27 +02:00
9b003d3504 Merge branch 'bugfix/ci_update' into 'idf'
mqtt ci update (both Gitlab and GitHub)

See merge request idf/esp-mqtt!31
2019-06-07 13:37:28 +08:00
971bf47e14 outbox: suppress clang-tidy warning of using ptr after free (no possible for STAILQ structure), removed unnecessary print 2019-06-06 17:00:03 +02:00
a4d1ef8d79 ci: employ new static analysis utilities 2019-06-06 17:00:03 +02:00
edd67e1c8c used event loop only if defined in supported features (enabled by macros) for backward compatibily with older IDFs 2019-06-06 17:00:03 +02:00
5afe3e6b24 ci: internal ci step for building with legacy idf to avoid travis failures 2019-06-06 16:59:58 +02:00
94f87b98dd Merge branch 'bugfix/ws_subprotocol_mqtt' into 'idf'
Add mqtt sub protocol for websocket

See merge request idf/esp-mqtt!23
2019-06-04 18:53:06 +08:00
48cd04baf1 defined macros for supported features in esp-idf based on idf version 2019-05-29 14:05:49 +02:00
a6f8716fff Add mqtt sub protocol for websocket 2019-05-24 09:29:31 +02:00
e205913b2c Merge branch 'bugfix/strict_prototypes' into 'idf'
fix warnings when compiling with `-Wstrict-prototypes`

See merge request idf/esp-mqtt!20
2019-05-17 20:49:38 +08:00
2ef78857e9 fix -Wstrict-prototypes issues 2019-05-17 14:36:44 +02:00
b263e44777 Merge branch 'feature/new_event_loop' into 'idf'
support for esp event loop library while keeping backward compatible mode if callback configured

See merge request idf/esp-mqtt!28
2019-05-16 22:44:13 +08:00
eeebd0215c support for esp event loop library while keeping backward compatible mode if callback configured 2019-05-16 16:29:33 +02:00
6f1fc3785a Merge branch 'feature/reliability_improvemnts' into 'idf'
MQTT reliability improvemnts

See merge request idf/esp-mqtt!30
2019-05-16 03:00:07 +08:00
18b6f2c582 Fixed formatting for all files to comply with idf style formats 2019-05-15 13:40:14 +02:00
e442c19f4e Added API documentaton to public headers 2019-05-15 13:40:14 +02:00
1d294f7606 ci: github build esp-mqtt with more stable IDF (latest release version rather then master)
fixed also internal ci: use the same git command for buld and static analysis (reset --hard instead of checkout)
2019-05-15 13:40:14 +02:00
60cdb79a67 mqtt_msg: avoid uncasting const to mqtt topic and data pointers 2019-05-15 13:40:14 +02:00
db71c753aa FIX: mqtt_get_id wrong logic on msg size checks.
This error was preventing the function from returning the right msg ID,
returning always 0.
2019-05-15 13:40:14 +02:00
d159bf4575 support for publishing message with empty data 2019-05-15 13:40:08 +02:00
891646681e client_init: fix crashing client upon wrong parameters, init or deinit
Closes https://github.com/espressif/esp-idf/issues/3191
2019-05-15 13:37:51 +02:00
35fc42d2b9 mqtt_msg: added missing message type for unsubscribe msg type
Closes #109
2019-05-06 11:23:35 +02:00
7d22ab5fe6 pending_msg_count update on delete expired from outbox
Closes #111
2019-05-06 11:23:35 +02:00
fd564b1f17 client receive: refactor receive to read only one message to fragment only payload for longer messages
Closes #113
2019-05-06 11:23:28 +02:00
c4fdd7759c Merge branch 'bugfix/recv_empty_payload' into 'idf'
Added support for receiving empty payload

See merge request idf/esp-mqtt!27
2019-04-28 03:42:29 +08:00
0450bd0093 MQTT Client: Added support for receiving empty payload 2019-04-26 17:07:04 +02:00
55e72e4ded Merge branch 'bugfix/ci_checkout_fix' into 'idf'
ci: fixed incorrect git checkout submodule

See merge request idf/esp-mqtt!24
2019-04-15 00:36:54 +08:00
9d70713b2e ci: fixed incorrect git checkout submodules causing build failures when switching between IDF releases 2019-04-10 14:21:07 +02:00
27780e3c45 Merge branch 'feature/github_issue_sync' into 'master'
github: Add workflow file for syncing to Jira

See merge request idf/esp-mqtt!22
2019-03-29 15:12:35 +08:00
b1aa1d444e Merge branch 'feature/support_for_disconnect_msg' into 'idf'
MQTT Client:  Added disconnect message on client stop

See merge request idf/esp-mqtt!21
2019-03-28 16:56:36 +08:00
caf5007b99 MQTT Client: Added disconnect message on client stop
Closes https://github.com/espressif/esp-mqtt/issues/97 and closes https://github.com/espressif/esp-idf/issues/3215
2019-03-27 17:41:03 +01:00
78a55fac68 github: Add workflow file for syncing to Jira 2019-03-27 18:18:33 +11:00
39118d5182 Merge branch 'feature/update_queue_h' into 'idf'
change rom/queue.h to sys/queue.h

See merge request idf/esp-mqtt!19
2019-03-20 16:23:55 +08:00
ca373e22cb change rom/queue.h to sys/queue.h 2019-03-14 20:26:28 +08:00
5a4d5518b2 Merge branch 'bugfix/set_client_state_on_timeout' into 'idf'
Bugfix: state not correctly set on disconnect -- PR from GitHub

See merge request idf/esp-mqtt!18
2019-02-20 21:15:55 +08:00
57d2774462 fix bug: client->state not set
If auto_reconnect is disabled, client->state won't be setted in MQTT_STATE_WAIT_TIMEOUT statement, which results in an error if esp_mqtt_client_start() is called.
2019-02-20 16:49:46 +08:00
15818b3a50 Merge branch 'feature/resend_qos12_rebased' into 'idf'
Updated MQTT library

See merge request idf/esp-mqtt!17
2019-02-16 03:58:15 +08:00
3300338c85 tabs to spaces corrections 2019-02-13 15:21:32 +01:00
51089629f7 corrected outbox for oversized messge and qos1, added errno to error messages 2019-02-13 15:21:32 +01:00
752953dc3b added mqtt api locks, so methods can be executed from user context
closes #67, closes #90, closes https://github.com/espressif/esp-idf/issues/2975
2019-02-13 15:21:32 +01:00
6a0d1e7bff support for qos1 and qos2 message retrasmission on reconnect 2019-02-13 15:21:32 +01:00
815623dfe5 improvements on runtime configuration of uri
closes https://github.com/espressif/esp-idf/issues/2870
2019-02-13 15:21:32 +01:00
d4b6655618 minor fixes for issues present with fragmented/packed data 2019-02-13 14:59:38 +01:00
6fed019b9d Merge branch 'feature/reconnection_improvements' into 'idf'
Reconnection improvements: Github PR

See merge request idf/esp-mqtt!15
2019-02-13 21:49:03 +08:00
df455d2a5f Add client force reconnect function
esp-mqtt library is unaware of underlying network connectivity states
and current auto reconnect mechanism is built around timed retry
attempts every MQTT_RECONNECT_TIMEOUT_MS.

As application code usually keeps track of network connectity state
export a new function that application can use to request a forced
reconnect attempt as soon as connected to the network.
2019-02-04 08:44:55 +01:00
17fd713bce Avoid further wait period after reconnect timeout occurs
When reconnect timer expires an additional waiting period of half the
timeout period is seen. Skip this extra waiting period when timeout
is detected and perform the connect attempt right away. This change
makes configured reconnect timeout value MQTT_RECONNECT_TIMEOUT_MS
accurate.
2019-02-04 08:44:55 +01:00
f9abda0ddd Merge branch 'feature/simple_ci_support' into 'idf'
Basic ci support with static checker

See merge request idf/esp-mqtt!13
2019-01-30 12:23:00 +08:00
dc801ce8ea ci: added basic support for building + static analysis with IDF master 2019-01-29 16:31:14 +01:00
8163e12b80 Merge branch 'feature/mqtt_support_arbitrary_datalen' into 'idf'
MQTT rework for packed and fragmented messages -- available for testing

See merge request idf/esp-mqtt!12
2019-01-03 18:57:30 +08:00
f08f3b6787 update log levels, logging complete error code, removed unnecessary struct 2019-01-03 09:14:34 +01:00
06fe5cca8e mqtt data events fixed to keep consistent msg_id when fragmented message received
closes #70
2019-01-03 09:14:34 +01:00
e0bbbebc08 mqtt support for sending fragmented messages and full mqtt message length support 2019-01-03 09:14:34 +01:00
cf5b8eda89 added a fix for incomplete header message received (topic or data could not be resolved from msg) 2019-01-03 09:14:34 +01:00
db64b79120 Fix for case where multiple MQTT messages are fitted into a single TCP packet : iterate over the buffer received.
Merges https://github.com/espressif/esp-mqtt/pull/82
Closes #64
Closes #80
2019-01-03 09:14:34 +01:00
1e787461dc Merge branch 'feature/event_before_connect' into 'idf'
Add BEFORE_CONNECt event and refresh the connection option

See merge request idf/esp-mqtt!10
2018-11-09 23:26:35 +08:00
2b49d37f8d Add BEFORE_CONNECt event and refresh the connection option 2018-11-09 23:26:35 +08:00
a7b1cea5b3 Merge branch 'feature/mutual_authentication' into 'idf'
Added mutual authentication from master, minor corrections, doxy comments

See merge request idf/esp-mqtt!9
2018-10-29 17:22:58 +08:00
85f2eddabd commented event fields, added description of supplied user data to user event handler
closes #66
2018-10-25 09:25:41 +02:00
8b45c25fdc corrections per renaming transports to esp_ prefixed 2018-10-16 08:29:47 +02:00
d2bcdd84a1 Add mutual SSL auth config to mqtt_client
picked from master
2018-10-16 08:29:47 +02:00
52cb6980b0 Merge pull request #77 from rbino/session-present
Expose the session_present flag in the CONNACK packet
2018-10-16 08:28:55 +02:00
d8b2c77ec5 Merge pull request #75 from rbino/fix-buffer-length
Fix buffer length during connection read
2018-10-16 08:25:16 +02:00
4db9918220 mqtt_client: add session_present field to mqtt_event
Populate it using the CONNACK packet
2018-10-15 11:31:46 +02:00
8bd8583216 Add mqtt_get_connect_session_present 2018-10-15 11:29:47 +02:00
a9e796025a Fix buffer length during connection read
Use the in_buffer length instead of the out msg length
2018-10-15 11:26:51 +02:00
439a2eb481 Merge pull request #78 from rbino/fix-publish-enqueue
Fix bug in esp_mqtt_client_publish message enqueueing
2018-10-12 08:26:54 +02:00
c2f3b9f4b4 Fix bug in esp_mqtt_client_publish message enqueueing
We have to enqueue first and then assign to outbound/pending variables,
otherwise the previous pending message is lost and the publish message
is present twice
2018-10-10 14:48:32 +02:00
51a5ca026f Merge branch 'feature/announce_move_to_idf' into 'master'
esp-mqtt announce integration to idf

See merge request idf/esp-mqtt!6
2018-10-10 19:36:27 +08:00
ab357e3ae3 Merge branch 'bugfix/client_stop_only_if_started' into 'idf'
client to stop only if started

See merge request idf/esp-mqtt!7
2018-10-09 13:25:38 +08:00
e26764502a mqtt_client_stop stops only if started, fixed tabs->spaces, updated README, removed unused config
closes #62
2018-10-05 16:01:29 +02:00
ddca82d553 Merge branch 'feature/transpost_methods_renamed_no_collision' into 'idf'
transport: renamed transport headers to avoid compilation collisions

See merge request idf/esp-mqtt!5
2018-10-03 14:12:58 +08:00
85ee406d03 tcp_transport: renamed possibly generic function names to be esp_ prefixed and not to colide with user namespace 2018-10-02 14:18:03 +02:00
d344f928ca transport: renamed transport headers to avoid compilation collisions 2018-10-02 14:17:54 +02:00
ba35d2de56 Merge branch 'revert-99093849' into 'idf'
Revert "Merge branch 'feature/idf_transport_API_change' into 'idf'"

See merge request idf/esp-mqtt!4
2018-09-24 14:58:36 +08:00
61f411c1f9 Revert "Merge branch 'feature/idf_transport_API_change' into 'idf'"
This reverts merge request !3
2018-09-24 13:25:04 +08:00
990938491c Merge branch 'feature/idf_transport_API_change' into 'idf'
esp-mqtt: Add support for modified transport_set_func() API from esp-idf/component/tcp_transport

See merge request idf/esp-mqtt!3
2018-09-24 11:54:13 +08:00
cbeaf67fe3 esp-mqtt: Add support for modified transport_set_func() API from esp-idf/component/tcp_transport 2018-09-18 17:49:41 +05:30
bcb38e45f5 deleted Kconfig as this is used as component in esp-idf 2018-09-13 11:33:52 +02:00
abaab2abcc Moved examples with tests to idf, renamed Kconfig to be included from component config in idf,
All these changes are necessary to support new CMake based build system and documentation generation so that this version of esp-mqtt is no longer usable as standalone component, but a standart component of esp-idf
2018-09-11 11:33:10 +02:00
c1ce30f693 Added doxygen tags for API reference documentation 2018-08-21 15:31:10 +02:00
3bbdebcca9 bugfix for longer data on ws transport 2018-08-21 11:55:36 +02:00
0c25441fdd support for custom implementation of msg outbox 2018-08-21 11:55:36 +02:00
fa7ade77b1 IDF integration: Refactored to common tcp transport component, fixed warnings 2018-08-21 11:55:36 +02:00
87 changed files with 6263 additions and 3784 deletions

20
.github/workflows/issue_comment.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Sync issue comments to JIRA
# This workflow will be triggered when new issue comment is created (including PR comments)
on: issue_comment
jobs:
sync_issue_comments_to_jira:
name: Sync Issue Comments to Jira
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Sync issue comments to JIRA
uses: espressif/github-actions/sync_issues_to_jira@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JIRA_PASS: ${{ secrets.JIRA_PASS }}
JIRA_PROJECT: IDFGH
JIRA_COMPONENT: esp-mqtt
JIRA_URL: ${{ secrets.JIRA_URL }}
JIRA_USER: ${{ secrets.JIRA_USER }}

20
.github/workflows/new_issues.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Sync issues to Jira
# This workflow will be triggered when a new issue is opened
on: issues
jobs:
sync_issues_to_jira:
name: Sync issues to Jira
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Sync GitHub issues to Jira project
uses: espressif/github-actions/sync_issues_to_jira@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JIRA_PASS: ${{ secrets.JIRA_PASS }}
JIRA_PROJECT: IDFGH
JIRA_COMPONENT: esp-mqtt
JIRA_URL: ${{ secrets.JIRA_URL }}
JIRA_USER: ${{ secrets.JIRA_USER }}

20
.github/workflows/new_prs.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Sync PRs to JIRA
# This workflow will be triggered when a pull request is opened
on: pull_request
jobs:
sync_prs_to_jira:
name: Sync PRs to Jira
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Sync PRs to Jira project
uses: espressif/github-actions/sync_issues_to_jira@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JIRA_PASS: ${{ secrets.JIRA_PASS }}
JIRA_PROJECT: IDFGH
JIRA_COMPONENT: esp-mqtt
JIRA_URL: ${{ secrets.JIRA_URL }}
JIRA_USER: ${{ secrets.JIRA_USER }}

92
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,92 @@
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_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 master
- $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 $TEST_PATH/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}

View File

@ -13,6 +13,11 @@ addons:
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
@ -24,32 +29,37 @@ install:
- mkdir -p ~/esp
- cd ~/esp
# Download binary toolchain for the ESP32
- wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz
- tar -xzf xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz
# Make xtensa-esp32-elf available for all terminal sessions
- export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin
# Get ESP-IDF from github
- git clone --recursive https://github.com/espressif/esp-idf.git
- cd esp-idf && git checkout --recurse-submodules v3.1
- 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:
# Go back to the git repository
- cd $PROJECT_PATH/examples/mqtt_tcp
# Update configuration so that kconfig doesn't start interactive mode
- make defconfig
# Build project from the git repository
- make -j4
- cd $PROJECT_PATH/examples/mqtt_ssl
- make defconfig
- make -j4
- cd $PROJECT_PATH/examples/mqtt_ws
- make defconfig
- make -j4
- cd $PROJECT_PATH/examples/mqtt_wss
- make defconfig
- make -j4
- cd $PROJECT_PATH/examples/emitter-client
# 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

View File

@ -1,8 +1,18 @@
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "lib/include")
set(COMPONENT_SRCDIRS ". lib")
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")
set(COMPONENT_REQUIRES lwip nghttp mbedtls)
register_component()

238
Kconfig
View File

@ -1,96 +1,166 @@
menu "ESPMQTT Configurations"
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_311
bool "Enable MQTT protocol 3.1.1"
default y
help
If not, this library will use MQTT protocol 3.1
config MQTT_TRANSPORT_SSL
bool "Enable MQTT over SSL"
default y
help
Enable MQTT transport over SSL with mbedtls
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_WEBSOCKET
bool "Enable MQTT over Websocket"
default y
help
Enable MQTT transport over Websocket.
config MQTT_TRANSPORT_SSL
bool "Enable MQTT over SSL"
default y
help
Enable MQTT transport over SSL with mbedtls
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_TRANSPORT_WEBSOCKET
bool "Enable MQTT over Websocket"
default y
depends on WS_TRANSPORT
help
Enable MQTT transport over Websocket.
config MQTT_USE_CUSTOM_CONFIG
bool "MQTT Using custom configurations"
default n
help
Custom MQTT configurations.
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_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_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_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_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_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_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_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_USE_CUSTOM_CONFIG
bool "MQTT Using custom configurations"
default n
help
Custom MQTT configurations.
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_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_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_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.
config MQTT_TASK_CORE_SELECTION_ENABLED
bool "Enable MQTT task core selection"
default false
help
This will enable core selection
choice
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
endmenu

167
README.md
View File

@ -15,166 +15,25 @@
## How to use
From IDFv3.2 [ESP-MQTT]((https://github.com/espressif/esp-mqtt)) is integrated in [ESP-IDF](https://github.com/espressif/esp-idf) as a submodule. Please do not use separately.
For [ESP-IDF](https://github.com/espressif/esp-idf) versions prior to IDFv3.2, please checkout the [ESP-MQTT_FOR_IDF_3.1](https://github.com/espressif/esp-mqtt/tree/ESP-MQTT_FOR_IDF_3.1) tag and follow the instructions below:
Clone this component to [ESP-IDF](https://github.com/espressif/esp-idf) project (as submodule):
```
git submodule add https://github.com/tuanpmt/espmqtt.git components/espmqtt
```
Or run a sample (make sure you have installed the [toolchain](http://esp-idf.readthedocs.io/en/latest/get-started/index.html#setup-toolchain)):
```
git clone https://github.com/tuanpmt/espmqtt.git
cd espmqtt/examples/mqtt_tcp
make menuconfig
make flash monitor
```
[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
### URI
- Curently support `mqtt`, `mqtts`, `ws`, `wss` schemes
- MQTT over TCP samples:
+ `mqtt://iot.eclipse.org`: MQTT over TCP, default port 1883:
+ `mqtt://iot.eclipse.org:1884` MQTT over TCP, port 1884:
+ `mqtt://username:password@iot.eclipse.org:1884` MQTT over TCP, port 1884, with username and password
- MQTT over SSL samples:
+ `mqtts://iot.eclipse.org`: MQTT over SSL, port 8883
+ `mqtts://iot.eclipse.org:8884`: MQTT over SSL, port 8884
- MQTT over Websocket samples:
+ `ws://iot.eclipse.org:80/ws`
- MQTT over Websocket Secure samples:
+ `wss://iot.eclipse.org:443/ws`
- Minimal configurations:
* 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/
```c
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtt://iot.eclipse.org",
.event_handle = mqtt_event_handler,
// .user_context = (void *)your_context
};
```
- If there are any options related to the URI in `esp_mqtt_client_config_t`, the option defined by the URI will be overridden. Sample:
```c
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtt://iot.eclipse.org:1234",
.event_handle = mqtt_event_handler,
.port = 4567,
};
//MQTT client will connect to iot.eclipse.org using port 4567
```
### SSL
- Get Certification from server, example: `iot.eclipse.org` `openssl s_client -showcerts -connect iot.eclipse.org:8883 </dev/null 2>/dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem`
- Check the sample application: `examples/mqtt_ssl`
- Configuration:
```cpp
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtts://iot.eclipse.org:8883",
.event_handle = mqtt_event_handler,
.cert_pem = (const char *)iot_eclipse_org_pem_start,
};
```
### More options for `esp_mqtt_client_config_t`
- `event_handle` for MQTT events
- `host`: MQTT server domain (ipv4 as string)
- `port`: MQTT server port
- `client_id`: default client id is `ESP32_%CHIPID%`
- `username`: MQTT username
- `password`: MQTT password
- `lwt_topic, lwt_msg, lwt_qos, lwt_retain, lwt_msg_len`: are mqtt lwt options, default NULL
- `disable_clean_session`: mqtt clean session, default clean_session is true
- `keepalive`: (value in seconds) mqtt keepalive, default is 120 seconds
- `disable_auto_reconnect`: this mqtt client will reconnect to server (when errors/disconnect). Set `disable_auto_reconnect=true` to disable
- `user_context` pass user context to this option, then can receive that context in `event->user_context`
- `task_prio, task_stack` for MQTT task, default priority is 5, and task_stack = 6144 bytes (or default task stack can be set via `make menucofig`).
- `buffer_size` for MQTT send/receive buffer, default is 1024
- `cert_pem` pointer to CERT file for server verify (with SSL), default is NULL, not required to verify the server
- `client_cert_pem` pointer to CERT file for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key_pem` has to be provided.
- `client_key_pem` pointer to PEM private key file for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert_pem` has to be provided.
- `transport`: override URI transport
+ `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`
### Change settings in `menuconfig`
```
make menuconfig
-> Component config -> ESPMQTT Configuration
```
## Example
Check `examples/mqtt_tcp` and `examples/mqtt_ssl` project. In Short:
```cpp
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
}
return ESP_OK;
}
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtt://iot.eclipse.org",
.event_handle = mqtt_event_handler,
// .user_context = (void *)your_context
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
```
* 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

22
ci/build_examples.sh Executable file
View File

@ -0,0 +1,22 @@
#!/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

33
ci/modify_for_legacy_idf.sh Executable file
View File

@ -0,0 +1,33 @@
#!/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

19
ci/set_idf.sh Executable file
View File

@ -0,0 +1,19 @@
#!/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

16
ci/set_mqtt.sh Executable file
View File

@ -0,0 +1,16 @@
#!/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

View File

@ -1,10 +0,0 @@
#
# Component Makefile
#
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default,
# this will take the sources in this directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#
COMPONENT_SRCDIRS := . lib
COMPONENT_PRIV_INCLUDEDIRS := lib/include

View File

@ -1,19 +0,0 @@
cmake_minimum_required(VERSION 3.5)
get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
set(PROJECT_ROOT "${DEV_ROOT}/")
set(SUBMODULE_ROOT "${DEV_ROOT}/../../../")
set(PROJECT_NAME "mqtt_ssl")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c)
set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}")
set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt")
project(${PROJECT_NAME})

View File

@ -1,13 +0,0 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := emitter_client
EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../
include $(IDF_PATH)/make/project.mk

View File

@ -1,10 +0,0 @@
# ESPMQTT Emitter client
## Before you run this Example
- Register an account from https://emitter.io/
- Login and create channel key, grant access for the channel `/topic/` as the images bellow
- `make menuconfig` provide Wi-Fi information and CHANNEL_KEY to `MQTT Application example`
- `make flash monitor`
![](generate-key-0.png)
![](generate-key-1.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

View File

@ -1,22 +0,0 @@
menu "MQTT Application example"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
config EMITTER_CHANNEL_KEY
string "Emitter channel key"
default ""
help
The Emitter channel key using to pub/sub
endmenu

View File

@ -1,143 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event_loop.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "MQTTS_SAMPLE";
static EventGroupHandle_t wifi_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******");
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Waiting for wifi");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
}
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, CONFIG_EMITTER_CHANNEL_KEY"/topic/", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, CONFIG_EMITTER_CHANNEL_KEY"/topic/", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
}
return ESP_OK;
}
static void mqtt_app_start(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtts://api.emitter.io:443", // for mqtt over ssl
// .uri = "mqtt://api.emitter.io:8080", //for mqtt over tcp
// .uri = "ws://api.emitter.io:8080", //for mqtt over websocket
// .uri = "wss://api.emitter.io:443", //for mqtt over websocket secure
.event_handle = mqtt_event_handler,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
}
void app_main()
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
nvs_flash_init();
wifi_init();
mqtt_app_start();
}

View File

@ -1,19 +0,0 @@
cmake_minimum_required(VERSION 3.5)
get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
set(PROJECT_ROOT "${DEV_ROOT}/")
set(SUBMODULE_ROOT "${DEV_ROOT}/../../../")
set(PROJECT_NAME "mqtt_ssl")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c)
set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}")
set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt")
project(${PROJECT_NAME})

View File

@ -1,13 +0,0 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := mqtt_ssl
EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../
include $(IDF_PATH)/make/project.mk

View File

@ -1,5 +0,0 @@
# ESPMQTT SSL Sample application
Get iot.eclipse.org Certification
`openssl s_client -showcerts -connect iot.eclipse.org:8883 </dev/null 2>/dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem`

View File

@ -1,15 +0,0 @@
menu "MQTT Application sample"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View File

@ -1,149 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event_loop.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "MQTTS_SAMPLE";
static EventGroupHandle_t wifi_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******");
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Waiting for wifi");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
}
extern const uint8_t iot_eclipse_org_pem_start[] asm("_binary_iot_eclipse_org_pem_start");
extern const uint8_t iot_eclipse_org_pem_end[] asm("_binary_iot_eclipse_org_pem_end");
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
}
return ESP_OK;
}
static void mqtt_app_start(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtts://iot.eclipse.org:8883",
.event_handle = mqtt_event_handler,
.cert_pem = (const char *)iot_eclipse_org_pem_start,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
}
void app_main()
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
nvs_flash_init();
wifi_init();
mqtt_app_start();
}

View File

@ -1 +0,0 @@
COMPONENT_EMBED_TXTFILES := iot_eclipse_org.pem

View File

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View File

@ -1,19 +0,0 @@
cmake_minimum_required(VERSION 3.5)
get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
set(PROJECT_ROOT "${DEV_ROOT}/")
set(SUBMODULE_ROOT "${DEV_ROOT}/../../../")
set(PROJECT_NAME "mqtt_ssl_mutual_auth")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c)
set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}")
set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt")
project(${PROJECT_NAME})

View File

@ -1,13 +0,0 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := mqtt_ssl_mutual_auth
EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../
include $(IDF_PATH)/make/project.mk

View File

@ -1,16 +0,0 @@
# ESPMQTT SSL Sample application
Navigate to the main directory
```
cd main
```
Generate a client key and a CSR. When you are generating the CSR, do not use the default values. At a minimum, the CSR must include the Country, Organisation and Common Name fields.
```
openssl genrsa -out client.key
openssl req -out client.csr -key client.key -new
```
Paste the generated CSR in the [Mosquitto test certificate signer](https://test.mosquitto.org/ssl/index.php), click Submit and copy the downloaded `client.crt` in the `main` directory.

View File

@ -1,15 +0,0 @@
menu "MQTT Application sample"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View File

@ -1,152 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event_loop.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "MQTTS_SAMPLE";
static EventGroupHandle_t wifi_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******");
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Waiting for wifi");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
}
extern const uint8_t client_cert_pem_start[] asm("_binary_client_crt_start");
extern const uint8_t client_cert_pem_end[] asm("_binary_client_crt_end");
extern const uint8_t client_key_pem_start[] asm("_binary_client_key_start");
extern const uint8_t client_key_pem_end[] asm("_binary_client_key_end");
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
}
return ESP_OK;
}
static void mqtt_app_start(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtts://test.mosquitto.org:8884",
.event_handle = mqtt_event_handler,
.client_cert_pem = (const char *)client_cert_pem_start,
.client_key_pem = (const char *)client_key_pem_start,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
}
void app_main()
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
nvs_flash_init();
wifi_init();
mqtt_app_start();
}

View File

@ -1 +0,0 @@
COMPONENT_EMBED_TXTFILES := client.crt client.key

View File

@ -1,19 +0,0 @@
cmake_minimum_required(VERSION 3.5)
get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
set(PROJECT_ROOT "${DEV_ROOT}/")
set(SUBMODULE_ROOT "${DEV_ROOT}/../../../")
set(PROJECT_NAME "mqtt_tcp")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c)
set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}")
set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt")
project(${PROJECT_NAME})

View File

@ -1,13 +0,0 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := mqtt_tcp
EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../
include $(IDF_PATH)/make/project.mk

View File

@ -1 +0,0 @@
# ESPMQTT Sample application

View File

@ -1,15 +0,0 @@
menu "MQTT Application sample"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View File

@ -1,143 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event_loop.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "MQTT_SAMPLE";
static EventGroupHandle_t wifi_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
}
return ESP_OK;
}
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******");
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Waiting for wifi");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
}
static void mqtt_app_start(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtt://iot.eclipse.org",
.event_handle = mqtt_event_handler,
// .user_context = (void *)your_context
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
}
void app_main()
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
nvs_flash_init();
wifi_init();
mqtt_app_start();
}

View File

@ -1,19 +0,0 @@
cmake_minimum_required(VERSION 3.5)
get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
set(PROJECT_ROOT "${DEV_ROOT}/")
set(SUBMODULE_ROOT "${DEV_ROOT}/../../../")
set(PROJECT_NAME "mqtt_ws")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c)
set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}")
set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt")
project(${PROJECT_NAME})

View File

@ -1,13 +0,0 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := mqtt_ws
EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../
include $(IDF_PATH)/make/project.mk

View File

@ -1 +0,0 @@
# ESPMQTT MQTT over Websocket

View File

@ -1,15 +0,0 @@
menu "MQTT Application sample"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View File

@ -1,144 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event_loop.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "MQTTWS_SAMPLE";
static EventGroupHandle_t wifi_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
}
return ESP_OK;
}
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******");
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Waiting for wifi");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
}
static void mqtt_app_start(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "ws://iot.eclipse.org:80/ws",
.event_handle = mqtt_event_handler,
// .user_context = (void *)your_context
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
}
void app_main()
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_WS", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
nvs_flash_init();
wifi_init();
mqtt_app_start();
}

View File

@ -1,19 +0,0 @@
cmake_minimum_required(VERSION 3.5)
get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
set(PROJECT_ROOT "${DEV_ROOT}/")
set(SUBMODULE_ROOT "${DEV_ROOT}/../../../")
set(PROJECT_NAME "mqtt_wss")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c)
set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}")
set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt")
project(${PROJECT_NAME})

View File

@ -1,13 +0,0 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := mqtt_wss
EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../
include $(IDF_PATH)/make/project.mk

View File

@ -1,5 +0,0 @@
# ESPMQTT MQTT over WSS Sample application
Get iot.eclipse.org Certification
`openssl s_client -showcerts -connect iot.eclipse.org:8883 </dev/null 2>/dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem`

View File

@ -1,15 +0,0 @@
menu "MQTT Application sample"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View File

@ -1,148 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event_loop.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "MQTTWSS_SAMPLE";
static EventGroupHandle_t wifi_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******");
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Waiting for wifi");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
}
extern const uint8_t iot_eclipse_org_pem_start[] asm("_binary_iot_eclipse_org_pem_start");
extern const uint8_t iot_eclipse_org_pem_end[] asm("_binary_iot_eclipse_org_pem_end");
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
}
return ESP_OK;
}
static void mqtt_app_start(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "wss://iot.eclipse.org:443/ws",
.event_handle = mqtt_event_handler,
.cert_pem = (const char *)iot_eclipse_org_pem_start,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
}
void app_main()
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
nvs_flash_init();
wifi_init();
mqtt_app_start();
}

View File

@ -1 +0,0 @@
COMPONENT_EMBED_TXTFILES := iot_eclipse_org.pem

View File

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

17
host_test/CMakeLists.txt Normal file
View File

@ -0,0 +1,17 @@
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)

30
host_test/README.md Normal file
View File

@ -0,0 +1,30 @@
| 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.

View File

@ -0,0 +1,3 @@
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)

View File

@ -0,0 +1,126 @@
/*
* 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<QueueHandle_t>(&mtx));
xEventGroupCreate_IgnoreAndReturn(reinterpret_cast<EventGroupHandle_t>(&event_group));
esp_transport_list_init_IgnoreAndReturn(reinterpret_cast<esp_transport_list_handle_t>(&transport_list));
esp_transport_tcp_init_IgnoreAndReturn(reinterpret_cast<esp_transport_handle_t>(&transport));
esp_transport_ssl_init_IgnoreAndReturn(reinterpret_cast<esp_transport_handle_t>(&transport));
esp_transport_ws_init_IgnoreAndReturn(reinterpret_cast<esp_transport_handle_t>(&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);
}
}

View File

@ -0,0 +1,4 @@
idf_component_get_property(original_heap_dir heap COMPONENT_OVERRIDEN_DIR)
idf_component_register(SRCS heap_mock.c
INCLUDE_DIRS "${original_heap_dir}/include")

View File

@ -0,0 +1,11 @@
#include "esp_heap_caps.h"
#include <stdint.h>
#include <stdlib.h>
void *heap_caps_calloc(size_t n, size_t size, uint32_t caps) {
(void)caps;
return calloc(n, size);
}

View File

@ -0,0 +1,66 @@
#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)

View File

@ -0,0 +1,6 @@
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

5
idf_component.yml Normal file
View File

@ -0,0 +1,5 @@
version: "1.0.0"
description: esp-mqtt
dependencies:
idf:
version: ">=5.0"

280
include/mqtt5_client.h Normal file
View File

@ -0,0 +1,280 @@
/*
* 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 */
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

612
include/mqtt_client.h Executable file → Normal file
View File

@ -11,86 +11,580 @@
#include <stdbool.h>
#include <string.h>
#include "esp_err.h"
#include "mqtt_config.h"
#include "esp_event.h"
#ifdef CONFIG_MQTT_PROTOCOL_5
#include "mqtt5_client.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct esp_mqtt_client* esp_mqtt_client_handle_t;
#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 enum {
MQTT_EVENT_ERROR = 0,
MQTT_EVENT_CONNECTED,
MQTT_EVENT_DISCONNECTED,
MQTT_EVENT_SUBSCRIBED,
MQTT_EVENT_UNSUBSCRIBED,
MQTT_EVENT_PUBLISHED,
MQTT_EVENT_DATA,
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;
typedef enum {
/**
* *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_TRANSPORT_OVER_SSL,
MQTT_TRANSPORT_OVER_WS,
MQTT_TRANSPORT_OVER_WSS
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;
typedef struct {
esp_mqtt_event_id_t event_id;
esp_mqtt_client_handle_t client;
void *user_context;
char *data;
int data_len;
int total_data_len;
int current_data_offset;
char *topic;
int topic_len;
int msg_id;
/**
* *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_mqtt_event_t *esp_mqtt_event_handle_t;
typedef esp_err_t (* mqtt_event_callback_t)(esp_mqtt_event_handle_t event);
typedef esp_err_t (*mqtt_event_callback_t)(esp_mqtt_event_handle_t event);
typedef struct {
mqtt_event_callback_t event_handle;
const char *host;
const char *uri;
uint32_t port;
const char *client_id;
const char *username;
const char *password;
const char *lwt_topic;
const char *lwt_msg;
int lwt_qos;
int lwt_retain;
int lwt_msg_len;
int disable_clean_session;
int keepalive;
bool disable_auto_reconnect;
void *user_context;
int task_prio;
int task_stack;
int buffer_size;
const char *cert_pem;
const char *client_cert_pem;
const char *client_key_pem;
esp_mqtt_transport_t transport;
/**
* *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 */
bool skip_server_verification; /*!< Skip server verification completely. Should only be used for debugging */
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;
esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config);
esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *uri);
/**
* @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);
esp_err_t esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic, int qos);
esp_err_t esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic);
int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain);
/**
* @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.
*
* @param client *MQTT* client handle
* @param topic
* @param qos // TODO describe parameters
*
* @return message_id of the subscribe message on success
* -1 on failure
*/
int esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client,
const char *topic, int qos);
/**
* @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` 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

View File

@ -0,0 +1,68 @@
// 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_

View File

@ -0,0 +1,54 @@
/*
* 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_flow_control(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

142
lib/include/mqtt5_msg.h Normal file
View File

@ -0,0 +1,142 @@
#ifndef MQTT5_MSG_H
#define MQTT5_MSG_H
#include <stdint.h>
#include <stdbool.h>
#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 char *topic, int qos, 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 */

View File

@ -0,0 +1,140 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <stdatomic.h>
#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 <errno.h>
#include <string.h>
#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;
int pending_msg_count;
} 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 skip_server_verification;
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

View File

@ -8,8 +8,22 @@
#include "sdkconfig.h"
#define MQTT_PROTOCOL_311 CONFIG_MQTT_PROTOCOL_311
#define MQTT_RECONNECT_TIMEOUT_MS (10*1000)
#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)
#define MQTT_POLL_READ_TIMEOUT_MS (1000)
#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
@ -17,13 +31,11 @@
#define MQTT_BUFFER_SIZE_BYTE 1024
#endif
#define MQTT_MAX_HOST_LEN 64
#define MQTT_MAX_CLIENT_LEN 32
#define MQTT_MAX_USERNAME_LEN 32
#define MQTT_MAX_PASSWORD_LEN 65
#define MQTT_MAX_LWT_TOPIC 32
#define MQTT_MAX_LWT_MSG 128
#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
@ -32,7 +44,6 @@
#endif
#define MQTT_KEEPALIVE_TICK (120)
#define MQTT_CMD_QUEUE_SIZE (10)
#define MQTT_NETWORK_TIMEOUT_MS (10000)
#ifdef CONFIG_MQTT_TCP_DEFAULT_PORT
@ -53,7 +64,7 @@
#define MQTT_WS_DEFAULT_PORT 80
#endif
#ifdef MQTT_WSS_DEFAULT_PORT
#ifdef CONFIG_MQTT_WSS_DEFAULT_PORT
#define MQTT_WSS_DEFAULT_PORT CONFIG_MQTT_WSS_DEFAULT_PORT
#else
#define MQTT_WSS_DEFAULT_PORT 443
@ -61,21 +72,35 @@
#define MQTT_CORE_SELECTION_ENABLED CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED
#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
#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
#define OUTBOX_EXPIRED_TIMEOUT_MS (30*1000)
#ifdef CONFIG_MQTT_EVENT_QUEUE_SIZE
#define MQTT_EVENT_QUEUE_SIZE CONFIG_MQTT_EVENT_QUEUE_SIZE
#else
#define MQTT_EVENT_QUEUE_SIZE 1
#endif
#define OUTBOX_MAX_SIZE (4*1024)
#endif

View File

@ -1,6 +1,10 @@
#ifndef MQTT_MSG_H
#define MQTT_MSG_H
#include <stdint.h>
#include <stdbool.h>
#include "mqtt_config.h"
#include "mqtt_client.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -40,8 +44,7 @@ extern "C" {
/* Remaining Length */
enum mqtt_message_type
{
enum mqtt_message_type {
MQTT_MSG_TYPE_CONNECT = 1,
MQTT_MSG_TYPE_CONNACK = 2,
MQTT_MSG_TYPE_PUBLISH = 3,
@ -58,72 +61,88 @@ enum mqtt_message_type
MQTT_MSG_TYPE_DISCONNECT = 14
};
enum mqtt_connect_return_code
{
CONNECTION_ACCEPTED = 0,
CONNECTION_REFUSE_PROTOCOL,
CONNECTION_REFUSE_ID_REJECTED,
CONNECTION_REFUSE_SERVER_UNAVAILABLE,
CONNECTION_REFUSE_BAD_USERNAME,
CONNECTION_REFUSE_NOT_AUTHORIZED
};
typedef struct mqtt_message
{
uint8_t* data;
uint32_t length;
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
{
typedef struct mqtt_connection {
mqtt_message_t message;
uint16_t message_id;
uint8_t* buffer;
uint16_t buffer_length;
#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;
int keepalive;
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(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }
static inline int mqtt_get_connect_return_code(uint8_t* buffer) { return buffer[3]; }
static inline int mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
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, uint16_t buffer_length);
uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length);
const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length);
const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length);
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length);
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 char* topic, int qos, uint16_t* message_id);
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);
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 char *topic, int qos, uint16_t *message_id);
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

View File

@ -6,40 +6,59 @@
#ifndef _MQTT_OUTOBX_H_
#define _MQTT_OUTOBX_H_
#include "platform.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct outbox_item {
char *buffer;
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;
int tick;
int retry_count;
bool pending;
STAILQ_ENTRY(outbox_item) next;
} outbox_item_t;
uint8_t *remaining_data;
int remaining_len;
} outbox_message_t;
STAILQ_HEAD(outbox_list_t, outbox_item);
typedef enum pending_state {
QUEUED,
TRANSMITTED,
ACKNOWLEDGED,
CONFIRMED
} pending_state_t;
typedef struct outbox_list_t * outbox_handle_t;
typedef outbox_item_t *outbox_item_handle_t;
outbox_handle_t outbox_init();
outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, uint8_t *data, int len, int msg_id, int msg_type, int tick);
outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox);
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_expired(outbox_handle_t outbox, int current_tick, int timeout);
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);
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);
esp_err_t outbox_cleanup(outbox_handle_t outbox, int max_size);
void outbox_destroy(outbox_handle_t outbox);
void outbox_delete_all_items(outbox_handle_t outbox);
#ifdef __cplusplus
}

View File

@ -7,29 +7,23 @@
#define _ESP_PLATFORM_H__
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include <stdint.h>
#include <sys/time.h>
#include "rom/queue.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"
char *platform_create_id_string();
char *platform_create_id_string(void);
int platform_random(int max);
long long platform_tick_get_ms();
void ms_to_timeval(int timeout_ms, struct timeval *tv);
uint64_t platform_tick_get_ms(void);
#define ESP_MEM_CHECK(TAG, a, action) if (!(a)) { \
ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \
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

View File

@ -1,242 +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 <tuanpm at live dot com>
*/
#ifndef _TRANSPORT_H_
#define _TRANSPORT_H_
#include <esp_err.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct transport_list_t* transport_list_handle_t;
typedef struct transport_item_t* transport_handle_t;
typedef int (*connect_func)(transport_handle_t t, const char *host, int port, int timeout_ms);
typedef int (*io_func)(transport_handle_t t, const char *buffer, int len, int timeout_ms);
typedef int (*io_read_func)(transport_handle_t t, char *buffer, int len, int timeout_ms);
typedef int (*trans_func)(transport_handle_t t);
typedef int (*poll_func)(transport_handle_t t, int timeout_ms);
/**
* @brief Create transport list
*
* @return A handle can hold all transports
*/
transport_list_handle_t transport_list_init();
/**
* @brief Cleanup and free all transports, include itself,
* this function will invoke transport_destroy of every transport have added this the list
*
* @param[in] list The list
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t transport_list_destroy(transport_list_handle_t list);
/**
* @brief Add a transport to the list, and define a scheme to indentify this transport in the list
*
* @param[in] list The list
* @param[in] t The Transport
* @param[in] scheme The scheme
*
* @return
* - ESP_OK
*/
esp_err_t transport_list_add(transport_list_handle_t list, transport_handle_t t, const char *scheme);
/**
* @brief This function will remove all transport from the list,
* invoke transport_destroy of every transport have added this the list
*
* @param[in] list The list
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG
*/
esp_err_t transport_list_clean(transport_list_handle_t list);
/**
* @brief Get the transport by scheme, which has been defined when calling function `transport_list_add`
*
* @param[in] list The list
* @param[in] tag The tag
*
* @return The transport handle
*/
transport_handle_t transport_list_get_transport(transport_list_handle_t list, const char *scheme);
/**
* @brief Initialize a transport handle object
*
* @return The transport handle
*/
transport_handle_t transport_init();
/**
* @brief Cleanup and free memory the transport
*
* @param[in] t The transport handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t transport_destroy(transport_handle_t t);
/**
* @brief Get default port number used by this transport
*
* @param[in] t The transport handle
*
* @return the port number
*/
int transport_get_default_port(transport_handle_t t);
/**
* @brief Set default port number that can be used by this transport
*
* @param[in] t The transport handle
* @param[in] port The port number
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t transport_set_default_port(transport_handle_t t, int port);
/**
* @brief Transport connection function, to make a connection to server
*
* @param t The transport handle
* @param[in] host Hostname
* @param[in] port Port
* @param[in] timeout_ms The timeout milliseconds
*
* @return
* - socket for will use by this transport
* - (-1) if there are any errors, should check errno
*/
int transport_connect(transport_handle_t t, const char *host, int port, int timeout_ms);
/**
* @brief Transport read function
*
* @param t The transport handle
* @param buffer The buffer
* @param[in] len The length
* @param[in] timeout_ms The timeout milliseconds
*
* @return
* - Number of bytes was read
* - (-1) if there are any errors, should check errno
*/
int transport_read(transport_handle_t t, char *buffer, int len, int timeout_ms);
/**
* @brief Poll the transport until readable or timeout
*
* @param[in] t The transport handle
* @param[in] timeout_ms The timeout milliseconds
*
* @return
* - 0 Timeout
* - (-1) If there are any errors, should check errno
* - other The transport can read
*/
int transport_poll_read(transport_handle_t t, int timeout_ms);
/**
* @brief Transport write function
*
* @param t The transport handle
* @param buffer The buffer
* @param[in] len The length
* @param[in] timeout_ms The timeout milliseconds
*
* @return
* - Number of bytes was written
* - (-1) if there are any errors, should check errno
*/
int transport_write(transport_handle_t t, const char *buffer, int len, int timeout_ms);
/**
* @brief Poll the transport until writeable or timeout
*
* @param[in] t The transport handle
* @param[in] timeout_ms The timeout milliseconds
*
* @return
* - 0 Timeout
* - (-1) If there are any errors, should check errno
* - other The transport can write
*/
int transport_poll_write(transport_handle_t t, int timeout_ms);
/**
* @brief Transport close
*
* @param t The transport handle
*
* @return
* - 0 if ok
* - (-1) if there are any errors, should check errno
*/
int transport_close(transport_handle_t t);
/**
* @brief Get user data context of this transport
*
* @param[in] t The transport handle
*
* @return The user data context
*/
void *transport_get_context_data(transport_handle_t t);
/**
* @brief Set the user context data for this transport
*
* @param[in] t The transport handle
* @param data The user data context
*
* @return
* - ESP_OK
*/
esp_err_t transport_set_context_data(transport_handle_t t, void *data);
/**
* @brief Set transport functions for the transport handle
*
* @param[in] t The transport handle
* @param[in] _connect The connect function pointer
* @param[in] _read The read function pointer
* @param[in] _write The write function pointer
* @param[in] _close The close function pointer
* @param[in] _poll_read The poll read function pointer
* @param[in] _poll_write The poll write function pointer
* @param[in] _destroy The destroy function pointer
*
* @return
* - ESP_OK
*/
esp_err_t transport_set_func(transport_handle_t t,
connect_func _connect,
io_read_func _read,
io_func _write,
trans_func _close,
poll_func _poll_read,
poll_func _poll_write,
trans_func _destroy);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,41 +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 <tuanpm at live dot com>
*/
#ifndef _TRANSPORT_SSL_H_
#define _TRANSPORT_SSL_H_
#include "transport.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Create new SSL transport, the transport handle must be release transport_destroy callback
*
* @return the allocated transport_handle_t, or NULL if the handle can not be allocated
*/
transport_handle_t transport_ssl_init();
/**
* @brief Set SSL certificate data (as PEM format).
* Note that, this function stores the pointer to data, rather than making a copy.
* So we need to make sure to keep the data lifetime before cleanup the connection
*
* @param t ssl transport
* @param[in] data The pem data
* @param[in] len The length
*/
void transport_ssl_set_cert_data(transport_handle_t t, const char *data, int len);
void transport_ssl_set_client_cert_data(transport_handle_t t, const char *data, int len);
void transport_ssl_set_client_key_data(transport_handle_t t, const char *data, int len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,27 +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 <tuanpm at live dot com>
*/
#ifndef _TRANSPORT_TCP_H_
#define _TRANSPORT_TCP_H_
#include "transport.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Create TCP transport, the transport handle must be release transport_destroy callback
*
* @return the allocated transport_handle_t, or NULL if the handle can not be allocated
*/
transport_handle_t transport_tcp_init();
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,46 +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 <tuanpm at live dot com>
*/
#ifndef _TRANSPORT_WS_H_
#define _TRANSPORT_WS_H_
#include "transport.h"
#ifdef __cplusplus
extern "C" {
#endif
#define WS_FIN 0x80
#define WS_OPCODE_TEXT 0x01
#define WS_OPCODE_BINARY 0x02
#define WS_OPCODE_CLOSE 0x08
#define WS_OPCODE_PING 0x09
#define WS_OPCODE_PONG 0x0a
// Second byte
#define WS_MASK 0x80
#define WS_SIZE16 126
#define WS_SIZE64 127
#define MAX_WEBSOCKET_HEADER_SIZE 10
#define WS_RESPONSE_OK 101
/**
* @brief Create TCP transport
*
* @return
* - transport
* - NULL
*/
transport_handle_t transport_ws_init(transport_handle_t parent_handle);
void transport_ws_set_path(transport_handle_t t, const char *path);
#ifdef __cplusplus
}
#endif
#endif

1040
lib/mqtt5_msg.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -28,16 +28,16 @@
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdint.h>
#include <string.h>
#include "mqtt_msg.h"
#include "mqtt_config.h"
#include "platform.h"
#define MQTT_MAX_FIXED_HEADER_SIZE 3
#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
{
enum mqtt_connect_flag {
MQTT_CONNECT_FLAG_USERNAME = 1 << 7,
MQTT_CONNECT_FLAG_PASSWORD = 1 << 6,
MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5,
@ -45,25 +45,11 @@ enum mqtt_connect_flag
MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1
};
struct __attribute((__packed__)) mqtt_connect_variable_header
static int append_string(mqtt_connection_t *connection, const char *string, int len)
{
uint8_t lengthMsb;
uint8_t lengthLsb;
#if defined(MQTT_PROTOCOL_311)
uint8_t magic[4];
#else
uint8_t magic[6];
#endif
uint8_t version;
uint8_t flags;
uint8_t keepaliveMsb;
uint8_t keepaliveLsb;
};
static int append_string(mqtt_connection_t* connection, const char* string, int len)
{
if (connection->message.length + len + 2 > connection->buffer_length)
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;
@ -73,16 +59,21 @@ static int append_string(mqtt_connection_t* connection, const char* string, int
return len + 2;
}
static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t message_id)
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)
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;
@ -90,98 +81,147 @@ static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t messag
return message_id;
}
static int init_message(mqtt_connection_t* connection)
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)
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)
static mqtt_message_t *fini_message(mqtt_connection_t *connection, int type, int dup, int qos, int retain)
{
int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE;
if (remaining_length > 127)
{
connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
connection->buffer[1] = 0x80 | (remaining_length % 128);
connection->buffer[2] = remaining_length / 128;
connection->message.length = remaining_length + 3;
connection->message.data = connection->buffer;
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;
}
else
{
connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
connection->buffer[2] = remaining_length;
connection->message.length = remaining_length + 2;
connection->message.data = connection->buffer + 1;
// 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, uint16_t buffer_length)
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;
}
uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length)
size_t mqtt_get_total_length(const uint8_t *buffer, size_t length, int *fixed_size_len)
{
int i;
uint32_t totlen = 0;
size_t totlen = 0;
for (i = 1; i < length; ++i)
{
for (i = 1; i < length; ++i) {
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
if ((buffer[i] & 0x80) == 0)
{
if ((buffer[i] & 0x80) == 0) {
++i;
break;
}
}
totlen += i;
if (fixed_size_len) {
*fixed_size_len = i;
}
return totlen;
}
const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length)
bool mqtt_header_complete(uint8_t *buffer, size_t buffer_length)
{
int i;
int totlen = 0;
int topiclen;
uint16_t i;
uint16_t topiclen;
for (i = 1; i < *length; ++i)
{
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
if ((buffer[i] & 0x80) == 0)
{
for (i = 1; i < MQTT_MAX_FIXED_HEADER_SIZE; ++i) {
if (i >= buffer_length) {
return false;
}
if ((buffer[i] & 0x80) == 0) {
++i;
break;
}
}
totlen += i;
// i is now the length of the fixed header
if (i + 2 >= *length)
return NULL;
if (i + 2 >= buffer_length) {
return false;
}
topiclen = buffer[i++] << 8;
topiclen |= buffer[i++];
if (i + topiclen > *length)
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 (const char*)(buffer + i);
}
return (char *)(buffer + i);
}
const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length)
char *mqtt_get_publish_data(uint8_t *buffer, size_t *length)
{
int i;
int totlen = 0;
@ -189,284 +229,392 @@ const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length)
int blength = *length;
*length = 0;
for (i = 1; i < blength; ++i)
{
for (i = 1; i < blength; ++i) {
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
if ((buffer[i] & 0x80) == 0)
{
if ((buffer[i] & 0x80) == 0) {
++i;
break;
}
}
totlen += i;
if (i + 2 >= blength)
if (i + 2 >= blength) {
return NULL;
}
topiclen = buffer[i++] << 8;
topiclen |= buffer[i++];
if (i + topiclen >= blength)
if (i + topiclen >= blength) {
return NULL;
}
i += topiclen;
if (mqtt_get_qos(buffer) > 0)
{
if (i + 2 >= blength)
if (mqtt_get_qos(buffer) > 0) {
if (i + 2 >= blength) {
return NULL;
}
i += 2;
}
if (totlen < i)
if (totlen < i) {
return NULL;
}
if (totlen <= blength)
if (totlen <= blength) {
*length = totlen - i;
else
} else {
*length = blength - i;
return (const char*)(buffer + i);
}
return (char *)(buffer + i);
}
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length)
char *mqtt_get_suback_data(uint8_t *buffer, size_t *length)
{
if (length < 1)
// 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;
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:
{
// 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;
for (i = 1; i < length; ++i) {
if ((buffer[i] & 0x80) == 0) {
++i;
break;
}
}
default:
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)
mqtt_message_t *mqtt_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info)
{
struct mqtt_connect_variable_header* variable_header;
init_message(connection);
if (connection->message.length + sizeof(*variable_header) > connection->buffer_length)
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);
variable_header = (void*)(connection->buffer + connection->message.length);
connection->message.length += sizeof(*variable_header);
variable_header->lengthMsb = 0;
#if defined(CONFIG_MQTT_PROTOCOL_311)
variable_header->lengthLsb = 4;
memcpy(variable_header->magic, "MQTT", 4);
variable_header->version = 4;
#else
variable_header->lengthLsb = 6;
memcpy(variable_header->magic, "MQIsdp", 6);
variable_header->version = 3;
#endif
variable_header->flags = 0;
variable_header->keepaliveMsb = info->keepalive >> 8;
variable_header->keepaliveLsb = info->keepalive & 0xff;
if (info->clean_session)
variable_header->flags |= 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
return fail_message(connection);
char *variable_header = (char *)(connection->buffer + connection->message.length);
connection->message.length += header_len;
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);
int header_idx = 0;
variable_header[header_idx++] = 0; // Variable header length MSB
if (append_string(connection, info->will_message, info->will_length) < 0)
return fail_message(connection);
variable_header->flags |= MQTT_CONNECT_FLAG_WILL;
if (info->will_retain)
variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;
variable_header->flags |= (info->will_qos & 3) << 3;
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
}
if (info->username != NULL && info->username[0] != '\0')
{
if (append_string(connection, info->username, strlen(info->username)) < 0)
return fail_message(connection);
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
variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;
if (info->clean_session) {
variable_header[flags_offset] |= MQTT_CONNECT_FLAG_CLEAN_SESSION;
}
if (info->password != NULL && info->password[0] != '\0')
{
if (append_string(connection, info->password, strlen(info->password)) < 0)
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);
}
}
variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;
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)
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')
if (topic == NULL || topic[0] == '\0') {
return fail_message(connection);
if (append_string(connection, topic, strlen(topic)) < 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 (connection->message.length + data_length > connection->buffer_length)
if (append_string(connection, topic, strlen(topic)) < 0) {
return fail_message(connection);
memcpy(connection->buffer + connection->message.length, data, data_length);
connection->message.length += data_length;
}
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 (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);
}
mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id)
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)
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)
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)
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)
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)
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)
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)
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 char* topic, int qos, uint16_t* message_id)
mqtt_message_t *mqtt_msg_subscribe(mqtt_connection_t *connection, const char *topic, int qos, uint16_t *message_id)
{
init_message(connection);
if (topic == NULL || topic[0] == '\0')
if (topic == NULL || topic[0] == '\0') {
return fail_message(connection);
}
if ((*message_id = append_message_id(connection, 0)) == 0)
if ((*message_id = append_message_id(connection, 0)) == 0) {
return fail_message(connection);
}
if (append_string(connection, topic, strlen(topic)) < 0)
if (append_string(connection, topic, strlen(topic)) < 0) {
return fail_message(connection);
}
if (connection->message.length + 1 > connection->buffer_length)
if (connection->message.length + 1 > connection->buffer_length) {
return fail_message(connection);
}
connection->buffer[connection->message.length++] = qos;
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)
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')
if (topic == NULL || topic[0] == '\0') {
return fail_message(connection);
}
if ((*message_id = append_message_id(connection, 0)) == 0)
if ((*message_id = append_message_id(connection, 0)) == 0) {
return fail_message(connection);
}
if (append_string(connection, topic, strlen(topic)) < 0)
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)
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)
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)
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;
}
}

View File

@ -1,12 +1,27 @@
#include "mqtt_outbox.h"
#include <stdlib.h>
#include <string.h>
#include "rom/queue.h"
#include "sys/queue.h"
#include "esp_log.h"
static const char *TAG = "OUTBOX";
#ifndef CONFIG_MQTT_CUSTOM_OUTBOX
static const char *TAG = "outbox";
outbox_handle_t outbox_init()
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);
@ -14,22 +29,27 @@ outbox_handle_t outbox_init()
return outbox;
}
outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, uint8_t *data, int len, int msg_id, int msg_type, int tick)
outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, outbox_tick_t tick)
{
outbox_item_handle_t item = calloc(1, sizeof(outbox_item_t));
ESP_MEM_CHECK(TAG, item, return NULL);
item->msg_id = msg_id;
item->msg_type = msg_type;
item->msg_id = message->msg_id;
item->msg_type = message->msg_type;
item->msg_qos = message->msg_qos;
item->tick = tick;
item->len = len;
item->buffer = malloc(len);
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, data, len);
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", msg_id, msg_type, len, outbox_get_size(outbox));
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;
}
@ -44,21 +64,51 @@ outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id)
return NULL;
}
outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox)
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) {
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 && item->msg_type == msg_type) {
if (item->msg_id == msg_id && (0xFF & (item->msg_type)) == msg_type) {
STAILQ_REMOVE(outbox, item, outbox_item, next);
free(item->buffer);
free(item);
@ -82,11 +132,29 @@ esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id)
}
return ESP_OK;
}
esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id)
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 = true;
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;
@ -105,19 +173,37 @@ esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type)
}
return ESP_OK;
}
esp_err_t outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout)
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 ESP_OK;
return deleted_items;
}
int outbox_get_size(outbox_handle_t outbox)
@ -125,27 +211,26 @@ int outbox_get_size(outbox_handle_t outbox)
int siz = 0;
outbox_item_handle_t item;
STAILQ_FOREACH(item, outbox, next) {
siz += item->len;
// 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;
}
esp_err_t outbox_cleanup(outbox_handle_t outbox, int max_size)
void outbox_delete_all_items(outbox_handle_t outbox)
{
while(outbox_get_size(outbox) > max_size) {
outbox_item_handle_t item = outbox_dequeue(outbox);
if (item == NULL) {
return ESP_FAIL;
}
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);
}
return ESP_OK;
}
void outbox_destroy(outbox_handle_t outbox)
{
outbox_cleanup(outbox, 0);
outbox_delete_all_items(outbox);
free(outbox);
}
#endif /* CONFIG_MQTT_CUSTOM_OUTBOX */

View File

@ -1,15 +1,18 @@
#include "platform.h"
#ifdef ESP_PLATFORM
#include "esp_system.h"
#include "esp_log.h"
#include <sys/time.h>
#include "esp_mac.h"
#include "esp_timer.h"
#include "esp_random.h"
#include <stdlib.h>
#include <stdint.h>
static const char *TAG = "PLATFORM";
static const char *TAG = "platform";
#define MAX_ID_STRING (32)
char *platform_create_id_string()
char *platform_create_id_string(void)
{
uint8_t mac[6];
char *id_string = calloc(1, MAX_ID_STRING);
@ -21,21 +24,12 @@ char *platform_create_id_string()
int platform_random(int max)
{
return esp_random()%max;
return esp_random() % max;
}
long long platform_tick_get_ms()
uint64_t platform_tick_get_ms(void)
{
struct timeval te;
gettimeofday(&te, NULL); // get current time
long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // calculate milliseconds
// printf("milliseconds: %lld\n", milliseconds);
return milliseconds;
return esp_timer_get_time()/(int64_t)1000;
}
void ms_to_timeval(int timeout_ms, struct timeval *tv)
{
tv->tv_sec = timeout_ms / 1000;
tv->tv_usec = (timeout_ms - (tv->tv_sec * 1000)) * 1000;
}
#endif

View File

@ -1,218 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "rom/queue.h"
#include "esp_log.h"
#include "transport.h"
#include "platform.h"
static const char *TAG = "TRANSPORT";
/**
* Transport layer structure, which will provide functions, basic properties for transport types
*/
struct transport_item_t {
int port;
int socket; /*!< Socket to use in this transport */
char *scheme; /*!< Tag name */
void *context; /*!< Context data */
void *data; /*!< Additional transport data */
connect_func _connect; /*!< Connect function of this transport */
io_read_func _read; /*!< Read */
io_func _write; /*!< Write */
trans_func _close; /*!< Close */
poll_func _poll_read; /*!< Poll and read */
poll_func _poll_write; /*!< Poll and write */
trans_func _destroy; /*!< Destroy and free transport */
STAILQ_ENTRY(transport_item_t) next;
};
/**
* This list will hold all transport available
*/
STAILQ_HEAD(transport_list_t, transport_item_t);
transport_list_handle_t transport_list_init()
{
transport_list_handle_t list = calloc(1, sizeof(struct transport_list_t));
ESP_MEM_CHECK(TAG, list, return NULL);
STAILQ_INIT(list);
return list;
}
esp_err_t transport_list_add(transport_list_handle_t list, transport_handle_t t, const char *scheme)
{
if (list == NULL || t == NULL) {
return ESP_ERR_INVALID_ARG;
}
t->scheme = calloc(1, strlen(scheme) + 1);
ESP_MEM_CHECK(TAG, t->scheme, return ESP_ERR_NO_MEM);
strcpy(t->scheme, scheme);
STAILQ_INSERT_TAIL(list, t, next);
return ESP_OK;
}
transport_handle_t transport_list_get_transport(transport_list_handle_t list, const char *scheme)
{
if (!list) {
return NULL;
}
if (scheme == NULL) {
return STAILQ_FIRST(list);
}
transport_handle_t item;
STAILQ_FOREACH(item, list, next) {
if (strcasecmp(item->scheme, scheme) == 0) {
return item;
}
}
return NULL;
}
esp_err_t transport_list_destroy(transport_list_handle_t list)
{
transport_list_clean(list);
free(list);
return ESP_OK;
}
esp_err_t transport_list_clean(transport_list_handle_t list)
{
transport_handle_t item = STAILQ_FIRST(list);
transport_handle_t tmp;
while (item != NULL) {
tmp = STAILQ_NEXT(item, next);
if (item->_destroy) {
item->_destroy(item);
}
transport_destroy(item);
item = tmp;
}
STAILQ_INIT(list);
return ESP_OK;
}
transport_handle_t transport_init()
{
transport_handle_t t = calloc(1, sizeof(struct transport_item_t));
ESP_MEM_CHECK(TAG, t, return NULL);
return t;
}
esp_err_t transport_destroy(transport_handle_t t)
{
if (t->scheme) {
free(t->scheme);
}
free(t);
return ESP_OK;
}
int transport_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
{
int ret = -1;
if (t && t->_connect) {
return t->_connect(t, host, port, timeout_ms);
}
return ret;
}
int transport_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
{
if (t && t->_read) {
return t->_read(t, buffer, len, timeout_ms);
}
return -1;
}
int transport_write(transport_handle_t t, const char *buffer, int len, int timeout_ms)
{
if (t && t->_write) {
return t->_write(t, buffer, len, timeout_ms);
}
return -1;
}
int transport_poll_read(transport_handle_t t, int timeout_ms)
{
if (t && t->_poll_read) {
return t->_poll_read(t, timeout_ms);
}
return -1;
}
int transport_poll_write(transport_handle_t t, int timeout_ms)
{
if (t && t->_poll_write) {
return t->_poll_write(t, timeout_ms);
}
return -1;
}
int transport_close(transport_handle_t t)
{
if (t && t->_close) {
return t->_close(t);
}
return 0;
}
void *transport_get_context_data(transport_handle_t t)
{
if (t) {
return t->data;
}
return NULL;
}
esp_err_t transport_set_context_data(transport_handle_t t, void *data)
{
if (t) {
t->data = data;
return ESP_OK;
}
return ESP_FAIL;
}
esp_err_t transport_set_func(transport_handle_t t,
connect_func _connect,
io_read_func _read,
io_func _write,
trans_func _close,
poll_func _poll_read,
poll_func _poll_write,
trans_func _destroy)
{
if (t == NULL) {
return ESP_FAIL;
}
t->_connect = _connect;
t->_read = _read;
t->_write = _write;
t->_close = _close;
t->_poll_read = _poll_read;
t->_poll_write = _poll_write;
t->_destroy = _destroy;
return ESP_OK;
}
int transport_get_default_port(transport_handle_t t)
{
if (t == NULL) {
return -1;
}
return t->port;
}
esp_err_t transport_set_default_port(transport_handle_t t, int port)
{
if (t == NULL) {
return ESP_FAIL;
}
t->port = port;
return ESP_OK;
}

View File

@ -1,310 +0,0 @@
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/esp_debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
#include "esp_log.h"
#include "esp_system.h"
#include "platform.h"
#include "transport.h"
#include "transport_ssl.h"
static const char *TAG = "TRANS_SSL";
/**
* mbedtls specific transport data
*/
typedef struct {
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ctx;
mbedtls_x509_crt cacert;
mbedtls_x509_crt client_cert;
mbedtls_pk_context client_key;
mbedtls_ssl_config conf;
mbedtls_net_context client_fd;
void *cert_pem_data;
int cert_pem_len;
void *client_cert_pem_data;
int client_cert_pem_len;
void *client_key_pem_data;
int client_key_pem_len;
bool mutual_authentication;
bool ssl_initialized;
bool verify_server;
} transport_ssl_t;
static int ssl_close(transport_handle_t t);
static int ssl_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
{
int ret = -1, flags;
struct timeval tv;
transport_ssl_t *ssl = transport_get_context_data(t);
if (!ssl) {
return -1;
}
ssl->ssl_initialized = true;
mbedtls_ssl_init(&ssl->ctx);
mbedtls_ctr_drbg_init(&ssl->ctr_drbg);
mbedtls_ssl_config_init(&ssl->conf);
mbedtls_entropy_init(&ssl->entropy);
if ((ret = mbedtls_ssl_config_defaults(&ssl->conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
goto exit;
}
if ((ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, &ssl->entropy, NULL, 0)) != 0) {
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
goto exit;
}
if (ssl->cert_pem_data) {
mbedtls_x509_crt_init(&ssl->cacert);
ssl->verify_server = true;
if ((ret = mbedtls_x509_crt_parse(&ssl->cacert, ssl->cert_pem_data, ssl->cert_pem_len + 1)) < 0) {
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\nDATA=%s,len=%d", -ret, (char*)ssl->cert_pem_data, ssl->cert_pem_len);
goto exit;
}
mbedtls_ssl_conf_ca_chain(&ssl->conf, &ssl->cacert, NULL);
mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
if ((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
goto exit;
}
} else {
mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_NONE);
}
if (ssl->client_cert_pem_data && ssl->client_key_pem_data) {
mbedtls_x509_crt_init(&ssl->client_cert);
mbedtls_pk_init(&ssl->client_key);
ssl->mutual_authentication = true;
if ((ret = mbedtls_x509_crt_parse(&ssl->client_cert, ssl->client_cert_pem_data, ssl->client_cert_pem_len + 1)) < 0) {
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\nDATA=%s,len=%d", -ret, (char*)ssl->client_cert_pem_data, ssl->client_cert_pem_len);
goto exit;
}
if ((ret = mbedtls_pk_parse_key(&ssl->client_key, ssl->client_key_pem_data, ssl->client_key_pem_len + 1, NULL, 0)) < 0) {
ESP_LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%x\n\nDATA=%s,len=%d", -ret, (char*)ssl->client_key_pem_data, ssl->client_key_pem_len);
goto exit;
}
if ((ret = mbedtls_ssl_conf_own_cert(&ssl->conf, &ssl->client_cert, &ssl->client_key)) < 0) {
ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%x\n", -ret);
goto exit;
}
} else if (ssl->client_cert_pem_data || ssl->client_key_pem_data) {
ESP_LOGE(TAG, "You have to provide both client_cert_pem and client_key_pem for mutual authentication");
goto exit;
}
mbedtls_ssl_conf_rng(&ssl->conf, mbedtls_ctr_drbg_random, &ssl->ctr_drbg);
#ifdef CONFIG_MBEDTLS_DEBUG
mbedtls_esp_enable_debug_log(&ssl->conf, 4);
#endif
if ((ret = mbedtls_ssl_setup(&ssl->ctx, &ssl->conf)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
goto exit;
}
mbedtls_net_init(&ssl->client_fd);
ms_to_timeval(timeout_ms, &tv);
setsockopt(ssl->client_fd.fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
ESP_LOGD(TAG, "Connect to %s:%d", host, port);
char port_str[8] = {0};
sprintf(port_str, "%d", port);
if ((ret = mbedtls_net_connect(&ssl->client_fd, host, port_str, MBEDTLS_NET_PROTO_TCP)) != 0) {
ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
goto exit;
}
mbedtls_ssl_set_bio(&ssl->ctx, &ssl->client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
if((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) {
ESP_LOGE(TAG, " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
goto exit;
}
ESP_LOGD(TAG, "Performing the SSL/TLS handshake...");
while ((ret = mbedtls_ssl_handshake(&ssl->ctx)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
goto exit;
}
}
ESP_LOGD(TAG, "Verifying peer X.509 certificate...");
if ((flags = mbedtls_ssl_get_verify_result(&ssl->ctx)) != 0) {
/* In real life, we probably want to close connection if ret != 0 */
ESP_LOGW(TAG, "Failed to verify peer certificate!");
if (ssl->cert_pem_data) {
goto exit;
}
} else {
ESP_LOGD(TAG, "Certificate verified.");
}
ESP_LOGD(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl->ctx));
return ret;
exit:
ssl_close(t);
return ret;
}
static int ssl_poll_read(transport_handle_t t, int timeout_ms)
{
transport_ssl_t *ssl = transport_get_context_data(t);
fd_set readset;
FD_ZERO(&readset);
FD_SET(ssl->client_fd.fd, &readset);
struct timeval timeout;
ms_to_timeval(timeout_ms, &timeout);
return select(ssl->client_fd.fd + 1, &readset, NULL, NULL, &timeout);
}
static int ssl_poll_write(transport_handle_t t, int timeout_ms)
{
transport_ssl_t *ssl = transport_get_context_data(t);
fd_set writeset;
FD_ZERO(&writeset);
FD_SET(ssl->client_fd.fd, &writeset);
struct timeval timeout;
ms_to_timeval(timeout_ms, &timeout);
return select(ssl->client_fd.fd + 1, NULL, &writeset, NULL, &timeout);
}
static int ssl_write(transport_handle_t t, const char *buffer, int len, int timeout_ms)
{
int poll, ret;
transport_ssl_t *ssl = transport_get_context_data(t);
if ((poll = transport_poll_write(t, timeout_ms)) <= 0) {
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->client_fd.fd, timeout_ms);
return poll;
}
ret = mbedtls_ssl_write(&ssl->ctx, (const unsigned char *) buffer, len);
if (ret <= 0) {
ESP_LOGE(TAG, "mbedtls_ssl_write error, errno=%s", strerror(errno));
}
return ret;
}
static int ssl_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
{
int poll = -1, ret;
transport_ssl_t *ssl = transport_get_context_data(t);
if (mbedtls_ssl_get_bytes_avail(&ssl->ctx) <= 0) {
if ((poll = transport_poll_read(t, timeout_ms)) <= 0) {
return poll;
}
}
ret = mbedtls_ssl_read(&ssl->ctx, (unsigned char *)buffer, len);
if (ret == 0) {
return -1;
}
return ret;
}
static int ssl_close(transport_handle_t t)
{
int ret = -1;
transport_ssl_t *ssl = transport_get_context_data(t);
if (ssl->ssl_initialized) {
ESP_LOGD(TAG, "Cleanup mbedtls");
mbedtls_ssl_close_notify(&ssl->ctx);
mbedtls_ssl_session_reset(&ssl->ctx);
mbedtls_net_free(&ssl->client_fd);
mbedtls_ssl_config_free(&ssl->conf);
if (ssl->verify_server) {
mbedtls_x509_crt_free(&ssl->cacert);
}
if (ssl->mutual_authentication) {
mbedtls_x509_crt_free(&ssl->client_cert);
mbedtls_pk_free(&ssl->client_key);
}
mbedtls_ctr_drbg_free(&ssl->ctr_drbg);
mbedtls_entropy_free(&ssl->entropy);
mbedtls_ssl_free(&ssl->ctx);
ssl->mutual_authentication = false;
ssl->ssl_initialized = false;
ssl->verify_server = false;
}
return ret;
}
static int ssl_destroy(transport_handle_t t)
{
transport_ssl_t *ssl = transport_get_context_data(t);
transport_close(t);
free(ssl);
return 0;
}
void transport_ssl_set_cert_data(transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = transport_get_context_data(t);
if (t && ssl) {
ssl->cert_pem_data = (void *)data;
ssl->cert_pem_len = len;
}
}
void transport_ssl_set_client_cert_data(transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = transport_get_context_data(t);
if (t && ssl) {
ssl->client_cert_pem_data = (void *)data;
ssl->client_cert_pem_len = len;
}
}
void transport_ssl_set_client_key_data(transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = transport_get_context_data(t);
if (t && ssl) {
ssl->client_key_pem_data = (void *)data;
ssl->client_key_pem_len = len;
}
}
transport_handle_t transport_ssl_init()
{
transport_handle_t t = transport_init();
transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t));
ESP_MEM_CHECK(TAG, ssl, return NULL);
mbedtls_net_init(&ssl->client_fd);
transport_set_context_data(t, ssl);
transport_set_func(t, ssl_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy);
return t;
}

View File

@ -1,152 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_err.h"
#include "platform.h"
#include "transport.h"
static const char *TAG = "TRANS_TCP";
typedef struct {
int sock;
} transport_tcp_t;
static int resolve_dns(const char *host, struct sockaddr_in *ip) {
struct hostent *he;
struct in_addr **addr_list;
he = gethostbyname(host);
if (he == NULL) {
return ESP_FAIL;
}
addr_list = (struct in_addr **)he->h_addr_list;
if (addr_list[0] == NULL) {
return ESP_FAIL;
}
ip->sin_family = AF_INET;
memcpy(&ip->sin_addr, addr_list[0], sizeof(ip->sin_addr));
return ESP_OK;
}
static int tcp_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
{
struct sockaddr_in remote_ip;
struct timeval tv;
transport_tcp_t *tcp = transport_get_context_data(t);
bzero(&remote_ip, sizeof(struct sockaddr_in));
//if stream_host is not ip address, resolve it AF_INET,servername,&serveraddr.sin_addr
if (inet_pton(AF_INET, host, &remote_ip.sin_addr) != 1) {
if (resolve_dns(host, &remote_ip) < 0) {
return -1;
}
}
tcp->sock = socket(PF_INET, SOCK_STREAM, 0);
if (tcp->sock < 0) {
ESP_LOGE(TAG, "Error create socket");
return -1;
}
remote_ip.sin_family = AF_INET;
remote_ip.sin_port = htons(port);
ms_to_timeval(timeout_ms, &tv);
setsockopt(tcp->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
ESP_LOGD(TAG, "[sock=%d],connecting to server IP:%s,Port:%d...",
tcp->sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port);
if (connect(tcp->sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 0) {
close(tcp->sock);
tcp->sock = -1;
return -1;
}
return tcp->sock;
}
static int tcp_write(transport_handle_t t, const char *buffer, int len, int timeout_ms)
{
int poll;
transport_tcp_t *tcp = transport_get_context_data(t);
if ((poll = transport_poll_write(t, timeout_ms)) <= 0) {
return poll;
}
return write(tcp->sock, buffer, len);
}
static int tcp_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
{
transport_tcp_t *tcp = transport_get_context_data(t);
int poll = -1;
if ((poll = transport_poll_read(t, timeout_ms)) <= 0) {
return poll;
}
int read_len = read(tcp->sock, buffer, len);
if (read_len == 0) {
return -1;
}
return read_len;
}
static int tcp_poll_read(transport_handle_t t, int timeout_ms)
{
transport_tcp_t *tcp = transport_get_context_data(t);
fd_set readset;
FD_ZERO(&readset);
FD_SET(tcp->sock, &readset);
struct timeval timeout;
ms_to_timeval(timeout_ms, &timeout);
return select(tcp->sock + 1, &readset, NULL, NULL, &timeout);
}
static int tcp_poll_write(transport_handle_t t, int timeout_ms)
{
transport_tcp_t *tcp = transport_get_context_data(t);
fd_set writeset;
FD_ZERO(&writeset);
FD_SET(tcp->sock, &writeset);
struct timeval timeout;
ms_to_timeval(timeout_ms, &timeout);
return select(tcp->sock + 1, NULL, &writeset, NULL, &timeout);
}
static int tcp_close(transport_handle_t t)
{
transport_tcp_t *tcp = transport_get_context_data(t);
int ret = -1;
if (tcp->sock >= 0) {
ret = close(tcp->sock);
tcp->sock = -1;
}
return ret;
}
static esp_err_t tcp_destroy(transport_handle_t t)
{
transport_tcp_t *tcp = transport_get_context_data(t);
transport_close(t);
free(tcp);
return 0;
}
transport_handle_t transport_tcp_init()
{
transport_handle_t t = transport_init();
transport_tcp_t *tcp = calloc(1, sizeof(transport_tcp_t));
ESP_MEM_CHECK(TAG, tcp, return NULL);
tcp->sock = -1;
transport_set_func(t, tcp_connect, tcp_read, tcp_write, tcp_close, tcp_poll_read, tcp_poll_write, tcp_destroy);
transport_set_context_data(t, tcp);
return t;
}

View File

@ -1,251 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "platform.h"
#include "transport.h"
#include "transport_tcp.h"
#include "transport_ws.h"
#include "mbedtls/base64.h"
#include "mbedtls/sha1.h"
static const char *TAG = "TRANSPORT_WS";
#define DEFAULT_WS_BUFFER (1024)
typedef struct {
char *path;
char *buffer;
transport_handle_t parent;
} transport_ws_t;
static char *trimwhitespace(const char *str)
{
char *end;
// Trim leading space
while (isspace((unsigned char)*str)) str++;
if (*str == 0) {
return (char *)str;
}
// Trim trailing space
end = (char *)(str + strlen(str) - 1);
while (end > str && isspace((unsigned char)*end)) end--;
// Write new null terminator
*(end + 1) = 0;
return (char *)str;
}
static char *get_http_header(const char *buffer, const char *key)
{
char *found = strstr(buffer, key);
if (found) {
found += strlen(key);
char *found_end = strstr(found, "\r\n");
if (found_end) {
found_end[0] = 0;//terminal string
return trimwhitespace(found);
}
}
return NULL;
}
static int ws_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
{
transport_ws_t *ws = transport_get_context_data(t);
if (transport_connect(ws->parent, host, port, timeout_ms) < 0) {
ESP_LOGE(TAG, "Error connect to ther server");
}
unsigned char random_key[16] = { 0 }, client_key[32] = {0};
int i;
for (i = 0; i < sizeof(random_key); i++) {
random_key[i] = rand() & 0xFF;
}
size_t outlen = 0;
mbedtls_base64_encode(client_key, 32, &outlen, random_key, 16);
int len = snprintf(ws->buffer, DEFAULT_WS_BUFFER,
"GET %s HTTP/1.1\r\n"
"Connection: Upgrade\r\n"
"Host: %s:%d\r\n"
"Upgrade: websocket\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Protocol: mqtt\r\n"
"Sec-WebSocket-Key: %s\r\n"
"User-Agent: ESP32 MQTT Client\r\n\r\n",
ws->path,
host, port,
client_key);
ESP_LOGD(TAG, "Write upgrate request\r\n%s", ws->buffer);
if (transport_write(ws->parent, ws->buffer, len, timeout_ms) <= 0) {
ESP_LOGE(TAG, "Error write Upgrade header %s", ws->buffer);
return -1;
}
if ((len = transport_read(ws->parent, ws->buffer, DEFAULT_WS_BUFFER, timeout_ms)) <= 0) {
ESP_LOGE(TAG, "Error read response for Upgrade header %s", ws->buffer);
return -1;
}
char *server_key = get_http_header(ws->buffer, "Sec-WebSocket-Accept:");
if (server_key == NULL) {
ESP_LOGE(TAG, "Sec-WebSocket-Accept not found");
return -1;
}
unsigned char client_key_b64[64], valid_client_key[20], accept_key[32] = {0};
int key_len = sprintf((char*)client_key_b64, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", (char*)client_key);
mbedtls_sha1(client_key_b64, (size_t)key_len, valid_client_key);
mbedtls_base64_encode(accept_key, 32, &outlen, valid_client_key, 20);
accept_key[outlen] = 0;
ESP_LOGD(TAG, "server key=%s, send_key=%s, accept_key=%s", (char *)server_key, (char*)client_key, accept_key);
if (strcmp((char*)accept_key, (char*)server_key) != 0) {
ESP_LOGE(TAG, "Invalid websocket key");
return -1;
}
return 0;
}
static int ws_write(transport_handle_t t, const char *buff, int len, int timeout_ms)
{
transport_ws_t *ws = transport_get_context_data(t);
char ws_header[MAX_WEBSOCKET_HEADER_SIZE];
char *mask;
int header_len = 0, i;
char *buffer = (char *)buff;
int poll_write;
if ((poll_write = transport_poll_write(ws->parent, timeout_ms)) <= 0) {
return poll_write;
}
ws_header[header_len++] = WS_OPCODE_BINARY | WS_FIN;
// NOTE: no support for > 16-bit sized messages
if (len > 125) {
ws_header[header_len++] = WS_SIZE16 | WS_MASK;
ws_header[header_len++] = (uint8_t)(len >> 8);
ws_header[header_len++] = (uint8_t)(len & 0xFF);
} else {
ws_header[header_len++] = (uint8_t)(len | WS_MASK);
}
mask = &ws_header[header_len];
ws_header[header_len++] = rand() & 0xFF;
ws_header[header_len++] = rand() & 0xFF;
ws_header[header_len++] = rand() & 0xFF;
ws_header[header_len++] = rand() & 0xFF;
for (i = 0; i < len; ++i) {
buffer[i] = (buffer[i] ^ mask[i % 4]);
}
if (transport_write(ws->parent, ws_header, header_len, timeout_ms) != header_len) {
ESP_LOGE(TAG, "Error write header");
return -1;
}
return transport_write(ws->parent, buffer, len, timeout_ms);
}
static int ws_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
{
transport_ws_t *ws = transport_get_context_data(t);
int payload_len;
char *data_ptr = buffer, opcode, mask, *mask_key = NULL;
int rlen;
int poll_read;
if ((poll_read = transport_poll_read(ws->parent, timeout_ms)) <= 0) {
return poll_read;
}
if ((rlen = transport_read(ws->parent, buffer, len, timeout_ms)) <= 0) {
ESP_LOGE(TAG, "Error read data");
return rlen;
}
opcode = (*data_ptr & 0x0F);
data_ptr ++;
mask = ((*data_ptr >> 7) & 0x01);
payload_len = (*data_ptr & 0x7F);
data_ptr++;
ESP_LOGD(TAG, "Opcode: %d, mask: %d, len: %d\r\n", opcode, mask, payload_len);
if (payload_len == 126) {
// headerLen += 2;
payload_len = data_ptr[0] << 8 | data_ptr[1];
data_ptr += 2;
} else if (payload_len == 127) {
// headerLen += 8;
if (data_ptr[0] != 0 || data_ptr[1] != 0 || data_ptr[2] != 0 || data_ptr[3] != 0) {
// really too big!
payload_len = 0xFFFFFFFF;
} else {
payload_len = data_ptr[4] << 24 | data_ptr[5] << 16 | data_ptr[6] << 8 | data_ptr[7];
}
data_ptr += 8;
}
if (mask) {
mask_key = data_ptr;
data_ptr += 4;
for (int i = 0; i < payload_len; i++) {
buffer[i] = (data_ptr[i] ^ mask_key[i % 4]);
}
} else {
memmove(buffer, data_ptr, payload_len);
}
return payload_len;
}
static int ws_poll_read(transport_handle_t t, int timeout_ms)
{
transport_ws_t *ws = transport_get_context_data(t);
return transport_poll_read(ws->parent, timeout_ms);
}
static int ws_poll_write(transport_handle_t t, int timeout_ms)
{
transport_ws_t *ws = transport_get_context_data(t);
return transport_poll_write(ws->parent, timeout_ms);;
}
static int ws_close(transport_handle_t t)
{
transport_ws_t *ws = transport_get_context_data(t);
return transport_close(ws->parent);
}
static esp_err_t ws_destroy(transport_handle_t t)
{
transport_ws_t *ws = transport_get_context_data(t);
free(ws->buffer);
free(ws->path);
free(ws);
return 0;
}
void transport_ws_set_path(transport_handle_t t, const char *path)
{
transport_ws_t *ws = transport_get_context_data(t);
ws->path = realloc(ws->path, strlen(path) + 1);
strcpy(ws->path, path);
}
transport_handle_t transport_ws_init(transport_handle_t parent_handle)
{
transport_handle_t t = transport_init();
transport_ws_t *ws = calloc(1, sizeof(transport_ws_t));
ESP_MEM_CHECK(TAG, ws, return NULL);
ws->parent = parent_handle;
ws->path = strdup("/");
ESP_MEM_CHECK(TAG, ws->path, return NULL);
ws->buffer = malloc(DEFAULT_WS_BUFFER);
ESP_MEM_CHECK(TAG, ws->buffer, {
free(ws->path);
free(ws);
return NULL;
});
transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy);
transport_set_context_data(t, ws);
return t;
}

757
mqtt5_client.c Normal file
View File

@ -0,0 +1,757 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "mqtt_client_priv.h"
#include "esp_log.h"
#include <string.h>
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_flow_control(esp_mqtt5_client_handle_t client)
{
if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) {
int msg_type = mqtt5_get_type(client->mqtt_state.outbound_message->data);
if (msg_type == MQTT_MSG_TYPE_PUBLISH) {
int msg_qos = mqtt5_get_qos(client->mqtt_state.outbound_message->data);
if (msg_qos > 0) {
client->send_publish_packet_count ++;
ESP_LOGD(TAG, "Sent (%d) qos > 0 publish packet without 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;
client->send_publish_packet_count --;
}
}
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_len == 0 || *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;
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);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
limits:
"clang-analyzer-core.NullDereference" : 0
"clang-analyzer-unix.Malloc" : 0
ignore:
- "llvm-header-guard"
- "llvm-include-order"
skip: