forked from espressif/esp-mqtt
Compare commits
489 Commits
feature/we
...
fix/jira_s
Author | SHA1 | Date | |
---|---|---|---|
490bde044f | |||
0e4cec9497 | |||
94defb867e | |||
14b11ad07e | |||
da6d38a17e | |||
5729048683 | |||
72833c7f8a | |||
0b315a01b1 | |||
2c71f9e69b | |||
6bcd906b8a | |||
d71dcf372a | |||
9c1826d152 | |||
5cce2c4f35 | |||
9f2db7b4b6 | |||
36f0faa80d | |||
7089fac9c0 | |||
65a4fdaff5 | |||
1011e63cbe | |||
5a156f56b4 | |||
32102558d3 | |||
5adbe11aaf | |||
2fa945d0b8 | |||
86d21e4902 | |||
e9b865eb9d | |||
acab02f2c5 | |||
ed76036744 | |||
c96f6f804c | |||
dffabb067f | |||
159b1638b2 | |||
f27cb47c0f | |||
ee9b52b7d2 | |||
01d0f34654 | |||
0b98c63247 | |||
94ecca2073 | |||
1e598b071b | |||
d4ee31f627 | |||
411ea65ec7 | |||
bc30b9a8e3 | |||
d372bbf09e | |||
610db7b934 | |||
62c5545f2d | |||
b80d4d468c | |||
5539c83c0a | |||
0a507f1205 | |||
77e41479d7 | |||
a88eaebad9 | |||
8dc8e5ae0b | |||
933da9efed | |||
a840bcf274 | |||
fcd548daab | |||
23e5c5a02c | |||
71d9236275 | |||
f8cb9f7286 | |||
47ac29b1e2 | |||
174c6781de | |||
1766fd4d5b | |||
4afe71b132 | |||
74882b18f0 | |||
ff8a93585f | |||
b4474ac16d | |||
3c764f0fc1 | |||
c03353333b | |||
382caedbbb | |||
93158d5d18 | |||
a8b0f474ec | |||
0fda7d7062 | |||
128be3f402 | |||
f2f30baec0 | |||
f072c9f753 | |||
3883bde0b0 | |||
40fdf32793 | |||
2c3363e23a | |||
6756e62387 | |||
10bba73d21 | |||
b342444746 | |||
5facf78673 | |||
6c55757f70 | |||
87d698cbc7 | |||
25b661c8ea | |||
8b3d3db10b | |||
691e7bca88 | |||
9b79fe3d00 | |||
cb782cae1e | |||
9db10b5b7b | |||
29ce3c5869 | |||
605352c1c5 | |||
5ba36d511f | |||
650328b021 | |||
5be3f7b5d4 | |||
0178bafba8 | |||
8a24bebbc0 | |||
62f3dc4705 | |||
6cadfe519b | |||
37e511bef1 | |||
b4ba09ce38 | |||
25f423d69b | |||
5a50fc0812 | |||
bef4fce9c1 | |||
49296d851d | |||
a903e5e3a9 | |||
63b3f29ffc | |||
332fadfea6 | |||
3a2e82ec0f | |||
7f77ad063d | |||
6809fcb2df | |||
6b70e14236 | |||
e19b9aa2df | |||
9726859fa3 | |||
7437dce403 | |||
60e39865e6 | |||
14e9df14ff | |||
a31ede754f | |||
229167f48a | |||
71d6861d6a | |||
78233fe7de | |||
1d49ac3249 | |||
20dda12b88 | |||
24b656ca4b | |||
c5069977a4 | |||
f80772b8d7 | |||
d5a2c0a7c6 | |||
d1f6ad23b7 | |||
fde00340f1 | |||
fb42588a03 | |||
3e0a118e0b | |||
8a6005781d | |||
e80f3e6a87 | |||
3738fcd196 | |||
5f297c0d62 | |||
9af5c26045 | |||
2b52b50a6b | |||
47b3f9b899 | |||
a87fd9c738 | |||
68e8c4f829 | |||
5688a84cbc | |||
9db9ee7648 | |||
5f3cadb44d | |||
97503cceb3 | |||
9186e5fa00 | |||
a9a9fe76bf | |||
f14eeb9157 | |||
ae53d799da | |||
9a56b2f086 | |||
89e5c6014f | |||
493822dc9d | |||
fdf2aeb36f | |||
3d275f42b9 | |||
0aa0a342a1 | |||
7253211a45 | |||
a21c387d62 | |||
7a31a555e9 | |||
16952ea66f | |||
e05d873aa2 | |||
9299f5400f | |||
69b6493423 | |||
7f765cac2c | |||
647e0eff32 | |||
684843a309 | |||
f6caaff254 | |||
64f88b4412 | |||
e31834c00f | |||
59b48a4d49 | |||
2cdcdcb4fa | |||
6b794e4708 | |||
2c2e6f38b5 | |||
5878e2e8a6 | |||
fb3184cc14 | |||
4874bab356 | |||
f83d2a9111 | |||
d3d816ed24 | |||
2e508fa6ef | |||
08ce9ed83f | |||
b66b9745f6 | |||
3a5334de6b | |||
0eda78e9b7 | |||
b7b858cd7f | |||
1a96ea3efa | |||
985078affa | |||
4c5a65c79e | |||
b021fc8e30 | |||
c28a56ddb0 | |||
6ef98d6510 | |||
026253d802 | |||
372b323535 | |||
383e7e5f0f | |||
df8dc92870 | |||
b86d42c130 | |||
08c4d62bf4 | |||
09287a1156 | |||
1fd50dd2cb | |||
36de30e46d | |||
320b058e28 | |||
3f05b1aedc | |||
86e40f8615 | |||
5ec3702881 | |||
de47f1c341 | |||
e1d5a9402f | |||
89894bd0c6 | |||
1d10608409 | |||
d7b00da517 | |||
1b009c840b | |||
88f4b8ed50 | |||
5b3c81ee48 | |||
1b71980575 | |||
4a89bff610 | |||
026ea95338 | |||
c11c314f44 | |||
ebef896b00 | |||
7471177fe7 | |||
e24852a4dc | |||
231b274962 | |||
f10321a53b | |||
db13533904 | |||
831d25cb56 | |||
a7e5accc7e | |||
90f0bf8dd4 | |||
1a94efe8b9 | |||
c4b7324bd6 | |||
a4d5ee0f12 | |||
67553aba45 | |||
36a3990404 | |||
2e15c9a5fe | |||
626dc3645b | |||
c7ae67b7f0 | |||
afba070093 | |||
eec6f0e17d | |||
78fcf23947 | |||
048f12f55f | |||
ff8226a464 | |||
7db36f9177 | |||
8f3cac8c36 | |||
d8c9c7a9e7 | |||
a00a3134c6 | |||
06157be118 | |||
e1a90d0161 | |||
5b27d1896e | |||
ff8e64839a | |||
1db731f985 | |||
87fcce72c9 | |||
2b20b5117c | |||
2f57985c0b | |||
9fdf7b6138 | |||
169b6986eb | |||
fd2d04e687 | |||
001dc1a95e | |||
a5a60752c0 | |||
369f4207f8 | |||
1a64f3176c | |||
0213382593 | |||
a74adfa9eb | |||
7a38867ce2 | |||
2530edbdce | |||
e05ed2ce18 | |||
3efac7b7fa | |||
b834be80a5 | |||
9ea804e0ab | |||
e2de0f3e3e | |||
2e35d4d4d5 | |||
f44dcb1c26 | |||
dc7fd5c0b1 | |||
8bb4a26f46 | |||
f65d5d05db | |||
cef3e16c5d | |||
b7158a4aea | |||
da850b0add | |||
8562437c8a | |||
e8be6c3aa7 | |||
65d8a813ea | |||
36d721e60b | |||
0a1d9d0300 | |||
673086e13a | |||
259baaec96 | |||
845c2a3a1e | |||
23c8e1ecf5 | |||
d6613e995b | |||
b9db8d9020 | |||
fcd7f0d083 | |||
a03228ac46 | |||
01594bf118 | |||
7d8e59de00 | |||
ae408d9a69 | |||
a8ef2a434b | |||
867773e423 | |||
ac7209049f | |||
bdadd77c6e | |||
f7325bfa10 | |||
d4aaec08ff | |||
5e17dcaeb2 | |||
db4bce01ab | |||
702da6d528 | |||
0bafcc5188 | |||
651c2fb4a2 | |||
d754293d25 | |||
8a412c147d | |||
5b8c04f348 | |||
40b06deb10 | |||
109985d3ad | |||
a7ff9afa3f | |||
2f9b337071 | |||
5e8950e681 | |||
6bc94add89 | |||
20bf9928d4 | |||
fb41520206 | |||
615aeae0c2 | |||
0c3d306589 | |||
b02746492a | |||
50dc010b97 | |||
dc1a635a97 | |||
0fc904c5d8 | |||
d8e2081332 | |||
9b750651fc | |||
61a8f4b63c | |||
f243225521 | |||
8a1e1a5a9f | |||
62d1509961 | |||
e2aa29d2ea | |||
d801f03f46 | |||
a9036b82a4 | |||
3e4f91ae50 | |||
7983357489 | |||
d5e915296e | |||
9e20c7ae3d | |||
38eab46f14 | |||
b963a5cd86 | |||
2994c3f273 | |||
420441b677 | |||
bbcf078a2b | |||
ed90a64551 | |||
f7941e29be | |||
3a47e3abae | |||
9eca3f6db9 | |||
7087193093 | |||
89a0c1fc95 | |||
6e08f6a04f | |||
8ab095b5bb | |||
616fa257fb | |||
7ac0a42831 | |||
ab1e8d7969 | |||
86fc8b7584 | |||
2684ed413d | |||
f74fe3d887 | |||
acc91bacf3 | |||
057f140228 | |||
97f91eda5c | |||
716b8625ba | |||
b25077a338 | |||
99586c2768 | |||
17e2f68e43 | |||
9a5187771a | |||
e8bb0bcf6f | |||
9ca997d2d4 | |||
9655845fdc | |||
1cd0885611 | |||
e1ab64f0d8 | |||
c1766c0f56 | |||
3da472fd37 | |||
566b034984 | |||
e3b013e2db | |||
67042a1315 | |||
430676cadb | |||
52cdfa9087 | |||
40302a3d43 | |||
3e35fc8323 | |||
78e2a7050e | |||
d01c77f70b | |||
59b228e0ad | |||
9fbd7d9244 | |||
2e0e93a2d3 | |||
2b04d177c7 | |||
176be08f75 | |||
04253b2b07 | |||
0234f6e538 | |||
1134cb234c | |||
9a56cc7e14 | |||
54c0161481 | |||
fb3d2107cd | |||
92aa01deb8 | |||
cbae6343e9 | |||
2fef1a07c5 | |||
117eef2dad | |||
dc37d3a065 | |||
0cc4077bd3 | |||
65bf2255d7 | |||
e85430def7 | |||
d9faeb47a3 | |||
82fa03a508 | |||
7223302deb | |||
11f884623b | |||
9b003d3504 | |||
971bf47e14 | |||
a4d1ef8d79 | |||
edd67e1c8c | |||
5afe3e6b24 | |||
94f87b98dd | |||
48cd04baf1 | |||
a6f8716fff | |||
e205913b2c | |||
2ef78857e9 | |||
b263e44777 | |||
eeebd0215c | |||
6f1fc3785a | |||
18b6f2c582 | |||
e442c19f4e | |||
1d294f7606 | |||
60cdb79a67 | |||
db71c753aa | |||
d159bf4575 | |||
891646681e | |||
35fc42d2b9 | |||
7d22ab5fe6 | |||
fd564b1f17 | |||
c4fdd7759c | |||
0450bd0093 | |||
55e72e4ded | |||
9d70713b2e | |||
27780e3c45 | |||
b1aa1d444e | |||
caf5007b99 | |||
78a55fac68 | |||
39118d5182 | |||
ca373e22cb | |||
5a4d5518b2 | |||
57d2774462 | |||
15818b3a50 | |||
3300338c85 | |||
51089629f7 | |||
752953dc3b | |||
6a0d1e7bff | |||
815623dfe5 | |||
d4b6655618 | |||
6fed019b9d | |||
df455d2a5f | |||
17fd713bce | |||
f9abda0ddd | |||
dc801ce8ea | |||
8163e12b80 | |||
f08f3b6787 | |||
06fe5cca8e | |||
e0bbbebc08 | |||
cf5b8eda89 | |||
db64b79120 | |||
1e787461dc | |||
2b49d37f8d | |||
a7b1cea5b3 | |||
85f2eddabd | |||
8b45c25fdc | |||
d2bcdd84a1 | |||
52cb6980b0 | |||
d8b2c77ec5 | |||
4db9918220 | |||
8bd8583216 | |||
a9e796025a | |||
439a2eb481 | |||
c2f3b9f4b4 | |||
51a5ca026f | |||
ab357e3ae3 | |||
e26764502a | |||
5fd5523b9b | |||
ddca82d553 | |||
85ee406d03 | |||
d344f928ca | |||
ba35d2de56 | |||
61f411c1f9 | |||
990938491c | |||
cbeaf67fe3 | |||
99004f2a48 | |||
bcb38e45f5 | |||
abaab2abcc | |||
c1ce30f693 | |||
3bbdebcca9 | |||
0c25441fdd | |||
fa7ade77b1 | |||
4e4b5dd06f | |||
8e8cf28bca | |||
b930438e3d | |||
9e2f69cc17 | |||
cd7d321842 | |||
4c19674b16 | |||
da573b482b | |||
c26f1dc607 | |||
87ef46a9b4 | |||
b2916ccaf9 | |||
677db77415 | |||
f3f223e031 | |||
75d3c65cb6 | |||
4bc37bb8db | |||
c837f9cc5f | |||
55f04a8e61 | |||
5c46be5ada |
20
.github/workflows/issue_comment.yml
vendored
Normal file
20
.github/workflows/issue_comment.yml
vendored
Normal 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
20
.github/workflows/new_issues.yml
vendored
Normal 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 }}
|
29
.github/workflows/new_prs.yml
vendored
Normal file
29
.github/workflows/new_prs.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
name: Sync remain PRs to Jira
|
||||
|
||||
# This workflow will be triggered every hour, to sync remaining PRs (i.e. PRs with zero comment) to Jira project
|
||||
# Note that, PRs can also get synced when new PR comment is created
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 * * * *"
|
||||
|
||||
# Limit to single concurrent run for workflows which can create Jira issues.
|
||||
# Same concurrency group is used in issue_comment.yml
|
||||
concurrency: jira_issues
|
||||
|
||||
jobs:
|
||||
sync_prs_to_jira:
|
||||
name: Sync PRs to Jira
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Sync PRs to Jira project
|
||||
uses: espressif/github-actions/sync_issues_to_jira@master
|
||||
with:
|
||||
cron_job: true
|
||||
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 }}
|
96
.gitlab-ci.yml
Normal file
96
.gitlab-ci.yml
Normal file
@ -0,0 +1,96 @@
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
|
||||
variables:
|
||||
IDF_REPO: ${GITLAB_SSH_SERVER}/idf/esp-idf.git
|
||||
|
||||
.add_gh_key_remote: &add_gh_key_remote |
|
||||
cit_add_ssh_key "${GH_PUSH_KEY}"
|
||||
git remote remove github || true
|
||||
git remote add github ${GH_PUSH_REPO}
|
||||
|
||||
before_script:
|
||||
# Use CI Tools
|
||||
- curl -sSL ${CIT_LOADER_URL} | sh
|
||||
- source citools/import_functions
|
||||
# Add gitlab ssh key
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
- echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64
|
||||
- base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa
|
||||
- chmod 600 ~/.ssh/id_rsa
|
||||
- echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||
- PATH=$CI_PROJECT_DIR/esp-idf/tools:$PATH
|
||||
- export MQTT_PATH=$CI_PROJECT_DIR
|
||||
|
||||
.build_template:
|
||||
stage: build
|
||||
tags:
|
||||
- build
|
||||
- internet
|
||||
script:
|
||||
# Replace the IDF's default esp-mqtt with this version
|
||||
- rm -rf $IDF_PATH/components/mqtt/esp-mqtt && cp -r $MQTT_PATH $IDF_PATH/components/mqtt/
|
||||
# Build the examples
|
||||
- $MQTT_PATH/ci/build_examples.sh
|
||||
|
||||
build_idf_v5.0:
|
||||
extends: .build_template
|
||||
image: espressif/idf:release-v5.0
|
||||
|
||||
build_idf_v5.1:
|
||||
extends: .build_template
|
||||
image: espressif/idf:release-v5.1
|
||||
|
||||
build_idf_latest:
|
||||
extends: .build_template
|
||||
image: espressif/idf:latest
|
||||
|
||||
build_and_test_qemu:
|
||||
stage: build
|
||||
image: ${CI_DOCKER_REGISTRY}/qemu-v5.1:1-20220802
|
||||
tags:
|
||||
- build
|
||||
- shiny
|
||||
dependencies: []
|
||||
script:
|
||||
- export IDF_PATH=$CI_PROJECT_DIR/esp-idf
|
||||
- git clone "${IDF_REPO}"
|
||||
# switch to IDF and setup the tools
|
||||
- $MQTT_PATH/ci/set_idf.sh release/v5.1
|
||||
- $IDF_PATH/tools/idf_tools.py install-python-env
|
||||
- cd $IDF_PATH && tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)"
|
||||
# Remove `debug_backend` and Add `paho-mqtt` to the required packages
|
||||
- sed '/debug_backend/d;/pygobject/d' $IDF_PATH/tools/requirements/requirements.ttfw.txt > requirements.txt
|
||||
- python -m pip install -r requirements.txt
|
||||
- python -m pip install paho-mqtt
|
||||
- $MQTT_PATH/ci/set_mqtt.sh $CI_COMMIT_SHA
|
||||
# build publish-connect stress test, setup test parameters
|
||||
- cd tools/test_apps/protocols/mqtt/publish_connect_test && cat sdkconfig.qemu | $IDF_PATH/tools/ci/envsubst.py > sdkconfig.defaults && idf.py build
|
||||
- export TEST_PATH=`pwd` && export MQTT_PUBLISH_TEST=1
|
||||
- export PYTHONPATH="$IDF_PATH/tools:$IDF_PATH/tools/ci/python_packages"
|
||||
# run test (with environment->qemu)
|
||||
- cd $IDF_PATH/tools/ci/python_packages/tiny_test_fw/bin
|
||||
# use more relaxed criteria with QEMU tests
|
||||
- export MQTT_PUBLISH_MSG_len_0=0 MQTT_PUBLISH_MSG_repeat_0=5
|
||||
- export MQTT_PUBLISH_MSG_len_1=2 MQTT_PUBLISH_MSG_repeat_1=50
|
||||
- export MQTT_PUBLISH_MSG_len_2=128 MQTT_PUBLISH_MSG_repeat_2=2
|
||||
- export MQTT_PUBLISH_MSG_len_3=20 MQTT_PUBLISH_MSG_repeat_3=20
|
||||
- python Runner.py $TEST_PATH -c $MQTT_PATH/ci/publish_connect_mqtt_qemu.yml -e $TEST_PATH/env.yml
|
||||
|
||||
push_master_to_github:
|
||||
stage: deploy
|
||||
image: ${CI_DOCKER_REGISTRY}/esp32-ci-env
|
||||
tags:
|
||||
- build
|
||||
only:
|
||||
- master
|
||||
- idf
|
||||
when: on_success
|
||||
variables:
|
||||
GIT_STRATEGY: clone
|
||||
script:
|
||||
- *add_gh_key_remote
|
||||
- git push github HEAD:${CI_COMMIT_REF_NAME}
|
52
.travis.yml
52
.travis.yml
@ -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,28 +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
|
||||
- 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
|
||||
# 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
|
18
CMakeLists.txt
Normal file
18
CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
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")
|
||||
|
||||
|
||||
|
229
Kconfig
229
Kconfig
@ -1,73 +1,180 @@
|
||||
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_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_POLL_READ_TIMEOUT_MS
|
||||
int "MQTT transport poll read timeut"
|
||||
default 1000
|
||||
depends on MQTT_USE_CUSTOM_CONFIG
|
||||
help
|
||||
Timeout when polling underlying transport for read.
|
||||
|
||||
config MQTT_EVENT_QUEUE_SIZE
|
||||
int "Number of queued events."
|
||||
default 1
|
||||
depends on MQTT_USE_CUSTOM_CONFIG
|
||||
help
|
||||
A value higher than 1 enables multiple queued events.
|
||||
|
||||
config MQTT_TASK_CORE_SELECTION_ENABLED
|
||||
bool "Enable MQTT task core selection"
|
||||
help
|
||||
This will enable core selection
|
||||
|
||||
choice MQTT_TASK_CORE_SELECTION
|
||||
depends on MQTT_TASK_CORE_SELECTION_ENABLED
|
||||
prompt "Core to use ?"
|
||||
config MQTT_USE_CORE_0
|
||||
bool "Core 0"
|
||||
config MQTT_USE_CORE_1
|
||||
bool "Core 1"
|
||||
endchoice
|
||||
|
||||
config MQTT_OUTBOX_DATA_ON_EXTERNAL_MEMORY
|
||||
bool "Use external memory for outbox data"
|
||||
default n
|
||||
depends on MQTT_USE_CUSTOM_CONFIG
|
||||
help
|
||||
Set to true to use external memory for outbox data.
|
||||
|
||||
config MQTT_CUSTOM_OUTBOX
|
||||
bool "Enable custom outbox implementation"
|
||||
default n
|
||||
help
|
||||
Set to true if a specific implementation of message outbox is needed (e.g. persistent outbox in NVM or
|
||||
similar).
|
||||
Note: Implementation of the custom outbox must be added to the mqtt component. These CMake commands
|
||||
could be used to append the custom implementation to lib-mqtt sources:
|
||||
idf_component_get_property(mqtt mqtt COMPONENT_LIB)
|
||||
set_property(TARGET ${mqtt} PROPERTY SOURCES ${PROJECT_DIR}/custom_outbox.c APPEND)
|
||||
|
||||
config MQTT_OUTBOX_EXPIRED_TIMEOUT_MS
|
||||
int "Outbox message expired timeout[ms]"
|
||||
default 30000
|
||||
depends on MQTT_USE_CUSTOM_CONFIG
|
||||
help
|
||||
Messages which stays in the outbox longer than this value before being published will be discarded.
|
||||
|
||||
endmenu
|
||||
|
164
README.md
164
README.md
@ -15,161 +15,25 @@
|
||||
|
||||
## How to use
|
||||
|
||||
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
|
||||
- `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
|
||||
|
||||
[@tuanpmt](https://twitter.com/tuanpmt)
|
||||
- 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
22
ci/build_examples.sh
Executable 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
33
ci/modify_for_legacy_idf.sh
Executable 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
|
7
ci/publish_connect_mqtt_qemu.yml
Normal file
7
ci/publish_connect_mqtt_qemu.yml
Normal file
@ -0,0 +1,7 @@
|
||||
CaseConfig:
|
||||
- name: test_app_protocol_mqtt_publish_connect
|
||||
overwrite:
|
||||
dut:
|
||||
class: ESP32QEMUDUT
|
||||
package: ttfw_idf
|
||||
|
19
ci/set_idf.sh
Executable file
19
ci/set_idf.sh
Executable 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
16
ci/set_mqtt.sh
Executable 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
|
10
component.mk
10
component.mk
@ -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
|
@ -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
|
||||
|
@ -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`
|
@ -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
|
@ -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();
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
COMPONENT_EMBED_TXTFILES := iot_eclipse_org.pem
|
@ -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-----
|
@ -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
|
||||
|
@ -1 +0,0 @@
|
||||
# ESPMQTT Sample application
|
@ -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
|
@ -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();
|
||||
}
|
@ -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
|
||||
|
@ -1 +0,0 @@
|
||||
# ESPMQTT MQTT over Websocket
|
@ -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
|
@ -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();
|
||||
}
|
@ -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
|
||||
|
@ -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`
|
@ -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
|
@ -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();
|
||||
}
|
@ -1 +0,0 @@
|
||||
COMPONENT_EMBED_TXTFILES := iot_eclipse_org.pem
|
@ -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
17
host_test/CMakeLists.txt
Normal 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
30
host_test/README.md
Normal 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.
|
||||
|
||||
|
3
host_test/main/CMakeLists.txt
Normal file
3
host_test/main/CMakeLists.txt
Normal 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)
|
126
host_test/main/test_mqtt_client.cpp
Normal file
126
host_test/main/test_mqtt_client.cpp
Normal 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);
|
||||
}
|
||||
}
|
4
host_test/mocks/heap/CMakeLists.txt
Normal file
4
host_test/mocks/heap/CMakeLists.txt
Normal 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")
|
11
host_test/mocks/heap/heap_mock.c
Normal file
11
host_test/mocks/heap/heap_mock.c
Normal 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);
|
||||
|
||||
}
|
71
host_test/mocks/include/sys/queue.h
Normal file
71
host_test/mocks/include/sys/queue.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 1991-1993 The Regents of the University of California
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/* Implementation from BSD headers*/
|
||||
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
|
||||
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
|
||||
#define STAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *stqh_first;/* first element */ \
|
||||
struct type **stqh_last;/* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
STAILQ_NEXT((elm), field) = NULL; \
|
||||
*(head)->stqh_last = (elm); \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INIT(head) do { \
|
||||
STAILQ_FIRST((head)) = NULL; \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for((var) = STAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = STAILQ_NEXT((var), field))
|
||||
|
||||
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = STAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
|
||||
if ((STAILQ_NEXT(elm, field) = \
|
||||
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||
if ((STAILQ_FIRST((head)) = \
|
||||
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
|
||||
if (STAILQ_FIRST((head)) == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = STAILQ_FIRST((head)); \
|
||||
while (STAILQ_NEXT(curelm, field) != (elm)) \
|
||||
curelm = STAILQ_NEXT(curelm, field); \
|
||||
STAILQ_REMOVE_AFTER(head, curelm, field); \
|
||||
} \
|
||||
TRASHIT(*oldnext); \
|
||||
} while (0)
|
6
host_test/sdkconfig.defaults
Normal file
6
host_test/sdkconfig.defaults
Normal 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
5
idf_component.yml
Normal file
@ -0,0 +1,5 @@
|
||||
version: "1.0.0"
|
||||
description: esp-mqtt
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.0"
|
281
include/mqtt5_client.h
Normal file
281
include/mqtt5_client.h
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _MQTT5_CLIENT_H_
|
||||
#define _MQTT5_CLIENT_H_
|
||||
|
||||
#include "mqtt_client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct esp_mqtt_client *esp_mqtt5_client_handle_t;
|
||||
|
||||
/**
|
||||
* MQTT5 protocol error reason code, more details refer to MQTT5 protocol document section 2.4
|
||||
*/
|
||||
enum mqtt5_error_reason_code {
|
||||
MQTT5_UNSPECIFIED_ERROR = 0x80,
|
||||
MQTT5_MALFORMED_PACKET = 0x81,
|
||||
MQTT5_PROTOCOL_ERROR = 0x82,
|
||||
MQTT5_IMPLEMENT_SPECIFIC_ERROR = 0x83,
|
||||
MQTT5_UNSUPPORTED_PROTOCOL_VER = 0x84,
|
||||
MQTT5_INVAILD_CLIENT_ID = 0x85,
|
||||
MQTT5_BAD_USERNAME_OR_PWD = 0x86,
|
||||
MQTT5_NOT_AUTHORIZED = 0x87,
|
||||
MQTT5_SERVER_UNAVAILABLE = 0x88,
|
||||
MQTT5_SERVER_BUSY = 0x89,
|
||||
MQTT5_BANNED = 0x8A,
|
||||
MQTT5_SERVER_SHUTTING_DOWN = 0x8B,
|
||||
MQTT5_BAD_AUTH_METHOD = 0x8C,
|
||||
MQTT5_KEEP_ALIVE_TIMEOUT = 0x8D,
|
||||
MQTT5_SESSION_TAKEN_OVER = 0x8E,
|
||||
MQTT5_TOPIC_FILTER_INVAILD = 0x8F,
|
||||
MQTT5_TOPIC_NAME_INVAILD = 0x90,
|
||||
MQTT5_PACKET_IDENTIFIER_IN_USE = 0x91,
|
||||
MQTT5_PACKET_IDENTIFIER_NOT_FOUND = 0x92,
|
||||
MQTT5_RECEIVE_MAXIMUM_EXCEEDED = 0x93,
|
||||
MQTT5_TOPIC_ALIAS_INVAILD = 0x94,
|
||||
MQTT5_PACKET_TOO_LARGE = 0x95,
|
||||
MQTT5_MESSAGE_RATE_TOO_HIGH = 0x96,
|
||||
MQTT5_QUOTA_EXCEEDED = 0x97,
|
||||
MQTT5_ADMINISTRATIVE_ACTION = 0x98,
|
||||
MQTT5_PAYLOAD_FORMAT_INVAILD = 0x99,
|
||||
MQTT5_RETAIN_NOT_SUPPORT = 0x9A,
|
||||
MQTT5_QOS_NOT_SUPPORT = 0x9B,
|
||||
MQTT5_USE_ANOTHER_SERVER = 0x9C,
|
||||
MQTT5_SERVER_MOVED = 0x9D,
|
||||
MQTT5_SHARED_SUBSCR_NOT_SUPPORTED = 0x9E,
|
||||
MQTT5_CONNECTION_RATE_EXCEEDED = 0x9F,
|
||||
MQTT5_MAXIMUM_CONNECT_TIME = 0xA0,
|
||||
MQTT5_SUBSCRIBE_IDENTIFIER_NOT_SUPPORT = 0xA1,
|
||||
MQTT5_WILDCARD_SUBSCRIBE_NOT_SUPPORT = 0xA2,
|
||||
};
|
||||
|
||||
/**
|
||||
* MQTT5 user property handle
|
||||
*/
|
||||
typedef struct mqtt5_user_property_list_t *mqtt5_user_property_handle_t;
|
||||
|
||||
/**
|
||||
* MQTT5 protocol connect properties and will properties configuration, more details refer to MQTT5 protocol document section 3.1.2.11 and 3.3.2.3
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t session_expiry_interval; /*!< The interval time of session expiry */
|
||||
uint32_t maximum_packet_size; /*!< The maximum packet size that we can receive */
|
||||
uint16_t receive_maximum; /*!< The maximum pakcket count that we process concurrently */
|
||||
uint16_t topic_alias_maximum; /*!< The maximum topic alias that we support */
|
||||
bool request_resp_info; /*!< This value to request Server to return Response information */
|
||||
bool request_problem_info; /*!< This value to indicate whether the reason string or user properties are sent in case of failures */
|
||||
mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */
|
||||
uint32_t will_delay_interval; /*!< The time interval that server delays publishing will message */
|
||||
uint32_t message_expiry_interval; /*!< The time interval that message expiry */
|
||||
bool payload_format_indicator; /*!< This value is to indicator will message payload format */
|
||||
const char *content_type; /*!< This value is to indicator will message content type, use a MIME content type string */
|
||||
const char *response_topic; /*!< Topic name for a response message */
|
||||
const char *correlation_data; /*!< Binary data for receiver to match the response message */
|
||||
uint16_t correlation_data_len; /*!< The length of correlation data */
|
||||
mqtt5_user_property_handle_t will_user_property; /*!< The handle for will message user property, call function esp_mqtt5_client_set_user_property to set it */
|
||||
} esp_mqtt5_connection_property_config_t;
|
||||
|
||||
/**
|
||||
* MQTT5 protocol publish properties configuration, more details refer to MQTT5 protocol document section 3.3.2.3
|
||||
*/
|
||||
typedef struct {
|
||||
bool payload_format_indicator; /*!< This value is to indicator publish message payload format */
|
||||
uint32_t message_expiry_interval; /*!< The time interval that message expiry */
|
||||
uint16_t topic_alias; /*!< An interger value to identify the topic instead of using topic name string */
|
||||
const char *response_topic; /*!< Topic name for a response message */
|
||||
const char *correlation_data; /*!< Binary data for receiver to match the response message */
|
||||
uint16_t correlation_data_len; /*!< The length of correlation data */
|
||||
const char *content_type; /*!< This value is to indicator publish message content type, use a MIME content type string */
|
||||
mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */
|
||||
} esp_mqtt5_publish_property_config_t;
|
||||
|
||||
/**
|
||||
* MQTT5 protocol subscribe properties configuration, more details refer to MQTT5 protocol document section 3.8.2.1
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t subscribe_id; /*!< A variable byte represents the identifier of the subscription */
|
||||
bool no_local_flag; /*!< Subscription Option to allow that server publish message that client sent */
|
||||
bool retain_as_published_flag; /*!< Subscription Option to keep the retain flag as published option */
|
||||
uint8_t retain_handle; /*!< Subscription Option to handle retain option */
|
||||
bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */
|
||||
const char *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */
|
||||
mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */
|
||||
} esp_mqtt5_subscribe_property_config_t;
|
||||
|
||||
/**
|
||||
* MQTT5 protocol unsubscribe properties configuration, more details refer to MQTT5 protocol document section 3.10.2.1
|
||||
*/
|
||||
typedef struct {
|
||||
bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */
|
||||
const char *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */
|
||||
mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */
|
||||
} esp_mqtt5_unsubscribe_property_config_t;
|
||||
|
||||
/**
|
||||
* MQTT5 protocol disconnect properties configuration, more details refer to MQTT5 protocol document section 3.14.2.2
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t session_expiry_interval; /*!< The interval time of session expiry */
|
||||
uint8_t disconnect_reason; /*!< The reason that connection disconnet, refer to mqtt5_error_reason_code */
|
||||
mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */
|
||||
} esp_mqtt5_disconnect_property_config_t;
|
||||
|
||||
/**
|
||||
* MQTT5 protocol for event properties
|
||||
*/
|
||||
typedef struct {
|
||||
bool payload_format_indicator; /*!< Payload format of the message */
|
||||
char *response_topic; /*!< Response topic of the message */
|
||||
int response_topic_len; /*!< Response topic length of the message */
|
||||
char *correlation_data; /*!< Correlation data of the message */
|
||||
uint16_t correlation_data_len; /*!< Correlation data length of the message */
|
||||
char *content_type; /*!< Content type of the message */
|
||||
int content_type_len; /*!< Content type length of the message */
|
||||
uint16_t subscribe_id; /*!< Subscription identifier of the message */
|
||||
mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_delete_user_property to free the memory */
|
||||
} esp_mqtt5_event_property_t;
|
||||
|
||||
/**
|
||||
* MQTT5 protocol for user property
|
||||
*/
|
||||
typedef struct {
|
||||
const char *key; /*!< Item key name */
|
||||
const char *value; /*!< Item value string */
|
||||
} esp_mqtt5_user_property_item_t;
|
||||
|
||||
/**
|
||||
* @brief Set MQTT5 client connect property configuration
|
||||
*
|
||||
* @param client mqtt client handle
|
||||
* @param connect_property connect property
|
||||
*
|
||||
* @return ESP_ERR_NO_MEM if failed to allocate
|
||||
* ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_FAIL on fail
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt5_client_set_connect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_connection_property_config_t *connect_property);
|
||||
|
||||
/**
|
||||
* @brief Set MQTT5 client publish property configuration
|
||||
*
|
||||
* This API will not store the publish property, it is one-time configuration.
|
||||
* Before call `esp_mqtt_client_publish` to publish data, call this API to set publish property if have
|
||||
*
|
||||
* @param client mqtt client handle
|
||||
* @param property publish property
|
||||
*
|
||||
* @return ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_FAIL on fail
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt5_client_set_publish_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_publish_property_config_t *property);
|
||||
|
||||
/**
|
||||
* @brief Set MQTT5 client subscribe property configuration
|
||||
*
|
||||
* This API will not store the subscribe property, it is one-time configuration.
|
||||
* Before call `esp_mqtt_client_subscribe` to subscribe topic, call this API to set subscribe property if have
|
||||
*
|
||||
* @param client mqtt client handle
|
||||
* @param property subscribe property
|
||||
*
|
||||
* @return ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_FAIL on fail
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt5_client_set_subscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_subscribe_property_config_t *property);
|
||||
|
||||
/**
|
||||
* @brief Set MQTT5 client unsubscribe property configuration
|
||||
*
|
||||
* This API will not store the unsubscribe property, it is one-time configuration.
|
||||
* Before call `esp_mqtt_client_unsubscribe` to unsubscribe topic, call this API to set unsubscribe property if have
|
||||
*
|
||||
* @param client mqtt client handle
|
||||
* @param property unsubscribe property
|
||||
*
|
||||
* @return ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_FAIL on fail
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt5_client_set_unsubscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_unsubscribe_property_config_t *property);
|
||||
|
||||
/**
|
||||
* @brief Set MQTT5 client disconnect property configuration
|
||||
*
|
||||
* This API will not store the disconnect property, it is one-time configuration.
|
||||
* Before call `esp_mqtt_client_disconnect` to disconnect connection, call this API to set disconnect property if have
|
||||
*
|
||||
* @param client mqtt client handle
|
||||
* @param property disconnect property
|
||||
*
|
||||
* @return ESP_ERR_NO_MEM if failed to allocate
|
||||
* ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_FAIL on fail
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt5_client_set_disconnect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_disconnect_property_config_t *property);
|
||||
|
||||
/**
|
||||
* @brief Set MQTT5 client user property configuration
|
||||
*
|
||||
* This API will allocate memory for user_property, please DO NOT forget `call esp_mqtt5_client_delete_user_property`
|
||||
* after you use it.
|
||||
* Before publish data, subscribe topic, unsubscribe, etc, call this API to set user property if have
|
||||
*
|
||||
* @param user_property user_property handle
|
||||
* @param item array of user property data (eg. {{"var","val"},{"other","2"}})
|
||||
* @param item_num number of items in user property data
|
||||
*
|
||||
* @return ESP_ERR_NO_MEM if failed to allocate
|
||||
* ESP_FAIL on fail
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_property, esp_mqtt5_user_property_item_t item[], uint8_t item_num);
|
||||
|
||||
/**
|
||||
* @brief Get MQTT5 client user property
|
||||
*
|
||||
* @param user_property user_property handle
|
||||
* @param item point that store user property data
|
||||
* @param item_num number of items in user property data
|
||||
*
|
||||
* This API can use with `esp_mqtt5_client_get_user_property_count` to get list count of user property.
|
||||
* And malloc number of count item array memory to store the user property data.
|
||||
* Please DO NOT forget the item memory, key and value point in item memory when get user property data successfully.
|
||||
*
|
||||
* @return ESP_ERR_NO_MEM if failed to allocate
|
||||
* ESP_FAIL on fail
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt5_client_get_user_property(mqtt5_user_property_handle_t user_property, esp_mqtt5_user_property_item_t *item, uint8_t *item_num);
|
||||
|
||||
/**
|
||||
* @brief Get MQTT5 client user property list count
|
||||
*
|
||||
* @param user_property user_property handle
|
||||
* @return user property list count
|
||||
*/
|
||||
uint8_t esp_mqtt5_client_get_user_property_count(mqtt5_user_property_handle_t user_property);
|
||||
|
||||
/**
|
||||
* @brief Free the user property list
|
||||
*
|
||||
* @param user_property user_property handle
|
||||
*
|
||||
* This API will free the memory in user property list and free user_property itself
|
||||
*/
|
||||
void esp_mqtt5_client_delete_user_property(mqtt5_user_property_handle_t user_property);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
|
||||
#endif
|
665
include/mqtt_client.h
Executable file → Normal file
665
include/mqtt_client.h
Executable file → Normal file
@ -10,78 +10,631 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_event.h"
|
||||
#ifdef CONFIG_MQTT_PROTOCOL_5
|
||||
#include "mqtt5_client.h"
|
||||
#endif
|
||||
|
||||
#include "mqtt_config.h"
|
||||
#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;
|
||||
char host[MQTT_MAX_HOST_LEN];
|
||||
char uri[MQTT_MAX_HOST_LEN];
|
||||
uint32_t port;
|
||||
char client_id[MQTT_MAX_CLIENT_LEN];
|
||||
char username[MQTT_MAX_USERNAME_LEN];
|
||||
char password[MQTT_MAX_PASSWORD_LEN];
|
||||
char lwt_topic[MQTT_MAX_LWT_TOPIC];
|
||||
char lwt_msg[MQTT_MAX_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;
|
||||
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 */
|
||||
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);
|
||||
/**
|
||||
* Topic definition struct
|
||||
*/
|
||||
typedef struct topic_t {
|
||||
const char *filter; /*!< Topic filter to subscribe */
|
||||
int qos; /*!< Max QoS level of the subscription */
|
||||
} esp_mqtt_topic_t;
|
||||
|
||||
/**
|
||||
* @brief Creates *MQTT* client handle based on the configuration
|
||||
*
|
||||
* @param config *MQTT* configuration structure
|
||||
*
|
||||
* @return mqtt_client_handle if successfully created, NULL on error
|
||||
*/
|
||||
esp_mqtt_client_handle_t
|
||||
esp_mqtt_client_init(const esp_mqtt_client_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Sets *MQTT* connection URI. This API is usually used to overrides the
|
||||
* URI configured in esp_mqtt_client_init
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @param uri
|
||||
*
|
||||
* @return ESP_FAIL if URI parse error, ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client,
|
||||
const char *uri);
|
||||
|
||||
/**
|
||||
* @brief Starts *MQTT* client with already created client handle
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_FAIL on other error
|
||||
*/
|
||||
esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client);
|
||||
|
||||
/**
|
||||
* @brief This api is typically used to force reconnection upon a specific event
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_FAIL if client is in invalid state
|
||||
*/
|
||||
esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client);
|
||||
|
||||
/**
|
||||
* @brief This api is typically used to force disconnection from the broker
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* ESP_ERR_INVALID_ARG on wrong initialization
|
||||
*/
|
||||
esp_err_t esp_mqtt_client_disconnect(esp_mqtt_client_handle_t client);
|
||||
|
||||
/**
|
||||
* @brief Stops *MQTT* client tasks
|
||||
*
|
||||
* * Notes:
|
||||
* - Cannot be called from the *MQTT* event handler
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_FAIL if client is in invalid state
|
||||
*/
|
||||
esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client);
|
||||
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 Convenience macro to select subscribe function to use.
|
||||
*
|
||||
* Notes:
|
||||
* - Usage of `esp_mqtt_client_subscribe_single` is the same as previous
|
||||
* esp_mqtt_client_subscribe, refer to it for details.
|
||||
*
|
||||
* @param client_handle *MQTT* client handle
|
||||
* @param topic_type Needs to be char* for single subscription or `esp_mqtt_topic_t` for multiple topics
|
||||
* @param qos_or_size It's either a qos when subscribing to a single topic or the size of the subscription array when subscribing to multiple topics.
|
||||
*
|
||||
* @return message_id of the subscribe message on success
|
||||
* -1 on failure
|
||||
*/
|
||||
#define esp_mqtt_client_subscribe(client_handle, topic_type, qos_or_size) _Generic((topic_type), \
|
||||
char *: esp_mqtt_client_subscribe_single, \
|
||||
esp_mqtt_topic_t*: esp_mqtt_client_subscribe_multiple \
|
||||
)(client_handle, topic_type, qos_or_size)
|
||||
|
||||
/**
|
||||
* @brief Subscribe the client to defined topic with defined qos
|
||||
*
|
||||
* Notes:
|
||||
* - Client must be connected to send subscribe message
|
||||
* - This API is could be executed from a user task or
|
||||
* from a *MQTT* event callback i.e. internal *MQTT* task
|
||||
* (API is protected by internal mutex, so it might block
|
||||
* if a longer data receive operation is in progress.
|
||||
* - `esp_mqtt_client_subscribe` could be used to call this function.
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @param topic topic filter to subscribe
|
||||
* @param qos Max qos level of the subscription
|
||||
*
|
||||
* @return message_id of the subscribe message on success
|
||||
* -1 on failure
|
||||
*/
|
||||
int esp_mqtt_client_subscribe_single(esp_mqtt_client_handle_t client,
|
||||
const char *topic, int qos);
|
||||
/**
|
||||
* @brief Subscribe the client to a list of defined topics with defined qos
|
||||
*
|
||||
* Notes:
|
||||
* - Client must be connected to send subscribe message
|
||||
* - This API is could be executed from a user task or
|
||||
* from a *MQTT* event callback i.e. internal *MQTT* task
|
||||
* (API is protected by internal mutex, so it might block
|
||||
* if a longer data receive operation is in progress.
|
||||
* - `esp_mqtt_client_subscribe` could be used to call this function.
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @param topic_list List of topics to subscribe
|
||||
* @param size size of topic_list
|
||||
*
|
||||
* @return message_id of the subscribe message on success
|
||||
* -1 on failure
|
||||
*/
|
||||
int esp_mqtt_client_subscribe_multiple(esp_mqtt_client_handle_t client,
|
||||
const esp_mqtt_topic_t *topic_list, int size);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe the client from defined topic
|
||||
*
|
||||
* Notes:
|
||||
* - Client must be connected to send unsubscribe message
|
||||
* - It is thread safe, please refer to `esp_mqtt_client_subscribe_single` for details
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @param topic
|
||||
*
|
||||
* @return message_id of the subscribe message on success
|
||||
* -1 on failure
|
||||
*/
|
||||
int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client,
|
||||
const char *topic);
|
||||
|
||||
/**
|
||||
* @brief Client to send a publish message to the broker
|
||||
*
|
||||
* Notes:
|
||||
* - This API might block for several seconds, either due to network timeout
|
||||
* (10s) or if publishing payloads longer than internal buffer (due to message
|
||||
* fragmentation)
|
||||
* - Client doesn't have to be connected for this API to work, enqueueing the
|
||||
* messages with qos>1 (returning -1 for all the qos=0 messages if
|
||||
* disconnected). If MQTT_SKIP_PUBLISH_IF_DISCONNECTED is enabled, this API will
|
||||
* not attempt to publish when the client is not connected and will always
|
||||
* return -1.
|
||||
* - It is thread safe, please refer to `esp_mqtt_client_subscribe` for details
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @param topic topic string
|
||||
* @param data payload string (set to NULL, sending empty payload message)
|
||||
* @param len data length, if set to 0, length is calculated from payload
|
||||
* string
|
||||
* @param qos QoS of publish message
|
||||
* @param retain retain flag
|
||||
*
|
||||
* @return message_id of the publish message (for QoS 0 message_id will always
|
||||
* be zero) on success. -1 on failure.
|
||||
*/
|
||||
int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic,
|
||||
const char *data, int len, int qos, int retain);
|
||||
|
||||
/**
|
||||
* @brief Enqueue a message to the outbox, to be sent later. Typically used for
|
||||
* messages with qos>0, but could be also used for qos=0 messages if store=true.
|
||||
*
|
||||
* This API generates and stores the publish message into the internal outbox
|
||||
* and the actual sending to the network is performed in the mqtt-task context
|
||||
* (in contrast to the esp_mqtt_client_publish() which sends the publish message
|
||||
* immediately in the user task's context). Thus, it could be used as a non
|
||||
* blocking version of esp_mqtt_client_publish().
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @param topic topic string
|
||||
* @param data payload string (set to NULL, sending empty payload message)
|
||||
* @param len data length, if set to 0, length is calculated from payload
|
||||
* string
|
||||
* @param qos QoS of publish message
|
||||
* @param retain retain flag
|
||||
* @param store if true, all messages are enqueued; otherwise only QoS 1 and
|
||||
* QoS 2 are enqueued
|
||||
*
|
||||
* @return message_id if queued successfully, -1 otherwise
|
||||
*/
|
||||
int esp_mqtt_client_enqueue(esp_mqtt_client_handle_t client, const char *topic,
|
||||
const char *data, int len, int qos, int retain,
|
||||
bool store);
|
||||
|
||||
/**
|
||||
* @brief Destroys the client handle
|
||||
*
|
||||
* Notes:
|
||||
* - Cannot be called from the *MQTT* event handler
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
*
|
||||
* @return ESP_OK
|
||||
* ESP_ERR_INVALID_ARG on wrong initialization
|
||||
*/
|
||||
esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client);
|
||||
|
||||
/**
|
||||
* @brief Set configuration structure, typically used when updating the config
|
||||
* (i.e. on "before_connect" event
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
*
|
||||
* @param config *MQTT* configuration structure
|
||||
*
|
||||
* @return ESP_ERR_NO_MEM if failed to allocate
|
||||
* ESP_ERR_INVALID_ARG if conflicts on transport configuration.
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client,
|
||||
const esp_mqtt_client_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Registers *MQTT* event
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @param event event type
|
||||
* @param event_handler handler callback
|
||||
* @param event_handler_arg handlers context
|
||||
*
|
||||
* @return ESP_ERR_NO_MEM if failed to allocate
|
||||
* ESP_ERR_INVALID_ARG on wrong initialization
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client,
|
||||
esp_mqtt_event_id_t event,
|
||||
esp_event_handler_t event_handler,
|
||||
void *event_handler_arg);
|
||||
|
||||
/**
|
||||
* @brief Unregisters mqtt event
|
||||
*
|
||||
* @param client mqtt client handle
|
||||
* @param event event ID
|
||||
* @param event_handler handler to unregister
|
||||
*
|
||||
* @return ESP_ERR_NO_MEM if failed to allocate
|
||||
* ESP_ERR_INVALID_ARG on invalid event ID
|
||||
* ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_mqtt_client_unregister_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler);
|
||||
|
||||
/**
|
||||
* @brief Get outbox size
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @return outbox size
|
||||
* 0 on wrong initialization
|
||||
*/
|
||||
int esp_mqtt_client_get_outbox_size(esp_mqtt_client_handle_t client);
|
||||
|
||||
/**
|
||||
* @brief Dispatch user event to the mqtt internal event loop
|
||||
*
|
||||
* @param client *MQTT* client handle
|
||||
* @param event *MQTT* event handle structure
|
||||
* @return ESP_OK on success
|
||||
* ESP_ERR_TIMEOUT if the event couldn't be queued (ref also CONFIG_MQTT_EVENT_QUEUE_SIZE)
|
||||
*/
|
||||
esp_err_t esp_mqtt_dispatch_custom_event(esp_mqtt_client_handle_t client, esp_mqtt_event_t *event);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
|
||||
#endif
|
||||
|
@ -1,68 +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 _MQTT_CONFIG_H_
|
||||
#define _MQTT_CONFIG_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define MQTT_PROTOCOL_311 CONFIG_MQTT_PROTOCOL_311
|
||||
#define MQTT_RECONNECT_TIMEOUT_MS (10*1000)
|
||||
|
||||
#if CONFIG_MQTT_BUFFER_SIZE
|
||||
#define MQTT_BUFFER_SIZE_BYTE CONFIG_MQTT_BUFFER_SIZE
|
||||
#else
|
||||
#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
|
||||
#define MQTT_TASK_PRIORITY 5
|
||||
|
||||
#if CONFIG_MQTT_TASK_STACK_SIZE
|
||||
#define MQTT_TASK_STACK CONFIG_MQTT_TASK_STACK_SIZE
|
||||
#else
|
||||
#define MQTT_TASK_STACK (6*1024)
|
||||
#endif
|
||||
|
||||
#define MQTT_KEEPALIVE_TICK (120)
|
||||
#define MQTT_CMD_QUEUE_SIZE (10)
|
||||
#define MQTT_NETWORK_TIMEOUT_MS (10000)
|
||||
|
||||
#ifdef CONFIG_MQTT_TCP_DEFAULT_PORT
|
||||
#define MQTT_TCP_DEFAULT_PORT CONFIG_MQTT_TCP_DEFAULT_PORT
|
||||
#else
|
||||
#define MQTT_TCP_DEFAULT_PORT 1883
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_SSL_DEFAULT_PORT
|
||||
#define MQTT_SSL_DEFAULT_PORT CONFIG_MQTT_SSL_DEFAULT_PORT
|
||||
#else
|
||||
#define MQTT_SSL_DEFAULT_PORT 8883
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_WS_DEFAULT_PORT
|
||||
#define MQTT_WS_DEFAULT_PORT CONFIG_MQTT_WS_DEFAULT_PORT
|
||||
#else
|
||||
#define MQTT_WS_DEFAULT_PORT 80
|
||||
#endif
|
||||
|
||||
#ifdef MQTT_WSS_DEFAULT_PORT
|
||||
#define MQTT_WSS_DEFAULT_PORT CONFIG_MQTT_WSS_DEFAULT_PORT
|
||||
#else
|
||||
#define MQTT_WSS_DEFAULT_PORT 443
|
||||
#endif
|
||||
|
||||
#define MQTT_ENABLE_SSL CONFIG_MQTT_TRANSPORT_SSL
|
||||
#define MQTT_ENABLE_WS CONFIG_MQTT_TRANSPORT_WS
|
||||
#define MQTT_ENABLE_WSS CONFIG_MQTT_TRANSPORT_WSS
|
||||
|
||||
#define OUTBOX_EXPIRED_TIMEOUT_MS (30*1000)
|
||||
#define OUTBOX_MAX_SIZE (4*1024)
|
||||
#endif
|
68
include/mqtt_supported_features.h
Normal file
68
include/mqtt_supported_features.h
Normal 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_
|
55
lib/include/mqtt5_client_priv.h
Normal file
55
lib/include/mqtt5_client_priv.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _MQTT5_CLIENT_PRIV_H_
|
||||
#define _MQTT5_CLIENT_PRIV_H_
|
||||
|
||||
#include "mqtt5_client.h"
|
||||
#include "mqtt_client_priv.h"
|
||||
#include "mqtt5_msg.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct mqtt5_topic_alias {
|
||||
char *topic;
|
||||
uint16_t topic_len;
|
||||
uint16_t topic_alias;
|
||||
STAILQ_ENTRY(mqtt5_topic_alias) next;
|
||||
} mqtt5_topic_alias_t;
|
||||
STAILQ_HEAD(mqtt5_topic_alias_list_t, mqtt5_topic_alias);
|
||||
typedef struct mqtt5_topic_alias_list_t *mqtt5_topic_alias_handle_t;
|
||||
typedef struct mqtt5_topic_alias *mqtt5_topic_alias_item_t;
|
||||
|
||||
typedef struct {
|
||||
esp_mqtt5_connection_property_storage_t connect_property_info;
|
||||
esp_mqtt5_connection_will_property_storage_t will_property_info;
|
||||
esp_mqtt5_connection_server_resp_property_t server_resp_property_info;
|
||||
esp_mqtt5_disconnect_property_config_t disconnect_property_info;
|
||||
const esp_mqtt5_publish_property_config_t *publish_property_info;
|
||||
const esp_mqtt5_subscribe_property_config_t *subscribe_property_info;
|
||||
const esp_mqtt5_unsubscribe_property_config_t *unsubscribe_property_info;
|
||||
mqtt5_topic_alias_handle_t peer_topic_alias;
|
||||
} mqtt5_config_storage_t;
|
||||
|
||||
void esp_mqtt5_increment_packet_counter(esp_mqtt5_client_handle_t client);
|
||||
void esp_mqtt5_decrement_packet_counter(esp_mqtt5_client_handle_t client);
|
||||
void esp_mqtt5_parse_pubcomp(esp_mqtt5_client_handle_t client);
|
||||
void esp_mqtt5_parse_puback(esp_mqtt5_client_handle_t client);
|
||||
void esp_mqtt5_parse_unsuback(esp_mqtt5_client_handle_t client);
|
||||
void esp_mqtt5_parse_suback(esp_mqtt5_client_handle_t client);
|
||||
esp_err_t esp_mqtt5_parse_connack(esp_mqtt5_client_handle_t client, int *connect_rsp_code);
|
||||
void esp_mqtt5_client_destory(esp_mqtt5_client_handle_t client);
|
||||
esp_err_t esp_mqtt5_client_publish_check(esp_mqtt5_client_handle_t client, int qos, int retain);
|
||||
esp_err_t esp_mqtt5_client_subscribe_check(esp_mqtt5_client_handle_t client, int qos);
|
||||
esp_err_t esp_mqtt5_create_default_config(esp_mqtt5_client_handle_t client);
|
||||
esp_err_t esp_mqtt5_get_publish_data(esp_mqtt5_client_handle_t client, uint8_t *msg_buf, size_t msg_read_len, char **msg_topic, size_t *msg_topic_len, char **msg_data, size_t *msg_data_len);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
|
||||
#endif
|
142
lib/include/mqtt5_msg.h
Normal file
142
lib/include/mqtt5_msg.h
Normal 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 esp_mqtt_topic_t *topic, int size, uint16_t *message_id, const esp_mqtt5_subscribe_property_config_t *property);
|
||||
mqtt_message_t *mqtt5_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id, const esp_mqtt5_unsubscribe_property_config_t *property);
|
||||
mqtt_message_t *mqtt5_msg_disconnect(mqtt_connection_t *connection, esp_mqtt5_disconnect_property_config_t *disconnect_property_info);
|
||||
mqtt_message_t *mqtt5_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id);
|
||||
mqtt_message_t *mqtt5_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id);
|
||||
mqtt_message_t *mqtt5_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id);
|
||||
mqtt_message_t *mqtt5_msg_puback(mqtt_connection_t *connection, uint16_t message_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MQTT5_MSG_H */
|
||||
|
138
lib/include/mqtt_client_priv.h
Normal file
138
lib/include/mqtt_client_priv.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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;
|
||||
} mqtt_state_t;
|
||||
|
||||
typedef struct {
|
||||
mqtt_event_callback_t event_handle;
|
||||
esp_event_loop_handle_t event_loop_handle;
|
||||
int task_stack;
|
||||
int task_prio;
|
||||
char *uri;
|
||||
char *host;
|
||||
char *path;
|
||||
char *scheme;
|
||||
int port;
|
||||
bool auto_reconnect;
|
||||
int network_timeout_ms;
|
||||
int refresh_connection_after_ms;
|
||||
int reconnect_timeout_ms;
|
||||
char **alpn_protos;
|
||||
int num_alpn_protos;
|
||||
char *clientkey_password;
|
||||
int clientkey_password_len;
|
||||
bool use_global_ca_store;
|
||||
esp_err_t ((*crt_bundle_attach)(void *conf));
|
||||
const char *cacert_buf;
|
||||
size_t cacert_bytes;
|
||||
const char *clientcert_buf;
|
||||
size_t clientcert_bytes;
|
||||
const char *clientkey_buf;
|
||||
size_t clientkey_bytes;
|
||||
const struct psk_key_hint *psk_hint_key;
|
||||
bool skip_cert_common_name_check;
|
||||
bool use_secure_element;
|
||||
void *ds_data;
|
||||
int message_retransmit_timeout;
|
||||
} mqtt_config_storage_t;
|
||||
|
||||
typedef enum {
|
||||
MQTT_STATE_INIT = 0,
|
||||
MQTT_STATE_DISCONNECTED,
|
||||
MQTT_STATE_CONNECTED,
|
||||
MQTT_STATE_WAIT_RECONNECT,
|
||||
} mqtt_client_state_t;
|
||||
|
||||
struct esp_mqtt_client {
|
||||
esp_transport_list_handle_t transport_list;
|
||||
esp_transport_handle_t transport;
|
||||
mqtt_config_storage_t *config;
|
||||
mqtt_state_t mqtt_state;
|
||||
mqtt_connect_info_t connect_info;
|
||||
mqtt_client_state_t state;
|
||||
uint64_t refresh_connection_tick;
|
||||
int64_t keepalive_tick;
|
||||
uint64_t reconnect_tick;
|
||||
#ifdef MQTT_PROTOCOL_5
|
||||
mqtt5_config_storage_t *mqtt5_config;
|
||||
uint16_t send_publish_packet_count; // This is for MQTT v5.0 flow control
|
||||
#endif
|
||||
int wait_timeout_ms;
|
||||
int auto_reconnect;
|
||||
esp_mqtt_event_t event;
|
||||
bool run;
|
||||
bool wait_for_ping_resp;
|
||||
outbox_handle_t outbox;
|
||||
EventGroupHandle_t status_bits;
|
||||
SemaphoreHandle_t api_lock;
|
||||
TaskHandle_t task_handle;
|
||||
#if MQTT_EVENT_QUEUE_SIZE > 1
|
||||
atomic_int queued_events;
|
||||
#endif
|
||||
};
|
||||
|
||||
bool esp_mqtt_set_if_config(char const *const new_config, char **old_config);
|
||||
void esp_mqtt_destroy_config(esp_mqtt_client_handle_t client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
|
||||
#endif
|
117
lib/include/mqtt_config.h
Normal file
117
lib/include/mqtt_config.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 _MQTT_CONFIG_H_
|
||||
#define _MQTT_CONFIG_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_MQTT_PROTOCOL_311
|
||||
#define MQTT_PROTOCOL_311
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_PROTOCOL_5
|
||||
#define MQTT_PROTOCOL_5
|
||||
#endif
|
||||
|
||||
#define MQTT_RECON_DEFAULT_MS (10*1000)
|
||||
|
||||
#ifdef CONFIG_MQTT_POLL_READ_TIMEOUT_MS
|
||||
#define MQTT_POLL_READ_TIMEOUT_MS CONFIG_MQTT_POLL_READ_TIMEOUT_MS
|
||||
#else
|
||||
#define MQTT_POLL_READ_TIMEOUT_MS (1000)
|
||||
#endif
|
||||
|
||||
#define MQTT_MSG_ID_INCREMENTAL CONFIG_MQTT_MSG_ID_INCREMENTAL
|
||||
|
||||
#define MQTT_SKIP_PUBLISH_IF_DISCONNECTED CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED
|
||||
|
||||
#define MQTT_REPORT_DELETED_MESSAGES CONFIG_MQTT_REPORT_DELETED_MESSAGES
|
||||
|
||||
#if CONFIG_MQTT_BUFFER_SIZE
|
||||
#define MQTT_BUFFER_SIZE_BYTE CONFIG_MQTT_BUFFER_SIZE
|
||||
#else
|
||||
#define MQTT_BUFFER_SIZE_BYTE 1024
|
||||
#endif
|
||||
|
||||
#if CONFIG_MQTT_TASK_PRIORITY
|
||||
#define MQTT_TASK_PRIORITY CONFIG_MQTT_TASK_PRIORITY
|
||||
#else
|
||||
#define MQTT_TASK_PRIORITY 5
|
||||
#endif
|
||||
|
||||
#if CONFIG_MQTT_TASK_STACK_SIZE
|
||||
#define MQTT_TASK_STACK CONFIG_MQTT_TASK_STACK_SIZE
|
||||
#else
|
||||
#define MQTT_TASK_STACK (6*1024)
|
||||
#endif
|
||||
|
||||
#define MQTT_KEEPALIVE_TICK (120)
|
||||
#define MQTT_NETWORK_TIMEOUT_MS (10000)
|
||||
|
||||
#ifdef CONFIG_MQTT_TCP_DEFAULT_PORT
|
||||
#define MQTT_TCP_DEFAULT_PORT CONFIG_MQTT_TCP_DEFAULT_PORT
|
||||
#else
|
||||
#define MQTT_TCP_DEFAULT_PORT 1883
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_SSL_DEFAULT_PORT
|
||||
#define MQTT_SSL_DEFAULT_PORT CONFIG_MQTT_SSL_DEFAULT_PORT
|
||||
#else
|
||||
#define MQTT_SSL_DEFAULT_PORT 8883
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_WS_DEFAULT_PORT
|
||||
#define MQTT_WS_DEFAULT_PORT CONFIG_MQTT_WS_DEFAULT_PORT
|
||||
#else
|
||||
#define MQTT_WS_DEFAULT_PORT 80
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_WSS_DEFAULT_PORT
|
||||
#define MQTT_WSS_DEFAULT_PORT CONFIG_MQTT_WSS_DEFAULT_PORT
|
||||
#else
|
||||
#define MQTT_WSS_DEFAULT_PORT 443
|
||||
#endif
|
||||
|
||||
#define MQTT_CORE_SELECTION_ENABLED CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED
|
||||
|
||||
#ifdef CONFIG_MQTT_DISABLE_API_LOCKS
|
||||
#define MQTT_DISABLE_API_LOCKS CONFIG_MQTT_DISABLE_API_LOCKS
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_USE_CORE_0
|
||||
#define MQTT_TASK_CORE 0
|
||||
#else
|
||||
#ifdef CONFIG_MQTT_USE_CORE_1
|
||||
#define MQTT_TASK_CORE 1
|
||||
#else
|
||||
#define MQTT_TASK_CORE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS
|
||||
#define OUTBOX_EXPIRED_TIMEOUT_MS CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS
|
||||
#else
|
||||
#define OUTBOX_EXPIRED_TIMEOUT_MS (30*1000)
|
||||
#endif
|
||||
|
||||
#define MQTT_ENABLE_SSL CONFIG_MQTT_TRANSPORT_SSL
|
||||
#define MQTT_ENABLE_WS CONFIG_MQTT_TRANSPORT_WEBSOCKET
|
||||
#define MQTT_ENABLE_WSS CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE
|
||||
|
||||
#ifdef CONFIG_MQTT_EVENT_QUEUE_SIZE
|
||||
#define MQTT_EVENT_QUEUE_SIZE CONFIG_MQTT_EVENT_QUEUE_SIZE
|
||||
#else
|
||||
#define MQTT_EVENT_QUEUE_SIZE 1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_OUTBOX_DATA_ON_EXTERNAL_MEMORY
|
||||
#define MQTT_OUTBOX_MEMORY MALLOC_CAP_SPIRAM
|
||||
#else
|
||||
#define MQTT_OUTBOX_MEMORY MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
#define OUTBOX_MAX_SIZE (4*1024)
|
||||
#endif
|
@ -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;
|
||||
uint16_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);
|
||||
int mqtt_get_total_length(uint8_t* buffer, uint16_t length);
|
||||
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
|
||||
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_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 esp_mqtt_topic_t topic_list[], int size, uint16_t *message_id) __attribute__((nonnull));
|
||||
mqtt_message_t *mqtt_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id);
|
||||
mqtt_message_t *mqtt_msg_pingreq(mqtt_connection_t *connection);
|
||||
mqtt_message_t *mqtt_msg_pingresp(mqtt_connection_t *connection);
|
||||
mqtt_message_t *mqtt_msg_disconnect(mqtt_connection_t *connection);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -7,25 +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"
|
||||
|
||||
#define mem_assert(x) assert(x)
|
||||
|
||||
char *platform_create_id_string();
|
||||
char *platform_create_id_string(void);
|
||||
int platform_random(int max);
|
||||
long long platform_tick_get_ms();
|
||||
uint64_t platform_tick_get_ms(void);
|
||||
|
||||
#define ESP_MEM_CHECK(TAG, a, action) if (!(a)) { \
|
||||
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Memory exhausted"); \
|
||||
action; \
|
||||
}
|
||||
|
||||
#define ESP_OK_CHECK(TAG, a, action) if ((a) != ESP_OK) { \
|
||||
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Failed with non ESP_OK err code"); \
|
||||
action; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,102 +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 "platform.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, 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);
|
||||
|
||||
transport_list_handle_t transport_list_init();
|
||||
esp_err_t transport_list_destroy(transport_list_handle_t head);
|
||||
esp_err_t transport_list_add(transport_list_handle_t head, transport_handle_t t, const char *scheme);
|
||||
esp_err_t transport_list_clean(transport_list_handle_t head);
|
||||
transport_handle_t transport_list_get_transport(transport_list_handle_t head, const char *tag);
|
||||
|
||||
transport_handle_t transport_init();
|
||||
int transport_destroy(transport_handle_t t);
|
||||
int transport_get_default_port(transport_handle_t t);
|
||||
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 Transport to use
|
||||
* @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
|
||||
*/
|
||||
int transport_connect(transport_handle_t t, const char *host, int port, int timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Transport read function
|
||||
*
|
||||
* @param t Transport to use
|
||||
* @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
|
||||
*/
|
||||
int transport_read(transport_handle_t t, char *buffer, int len, int timeout_ms);
|
||||
int transport_poll_read(transport_handle_t t, int timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Transport write function
|
||||
*
|
||||
* @param t transport
|
||||
* @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
|
||||
*/
|
||||
int transport_write(transport_handle_t t, char *buffer, int len, int timeout_ms);
|
||||
int transport_poll_write(transport_handle_t t, int timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Transport close
|
||||
*
|
||||
* @param t transport
|
||||
*
|
||||
* @return
|
||||
* - 0 if ok
|
||||
* - (-1) if there are any errors
|
||||
*/
|
||||
int transport_close(transport_handle_t t);
|
||||
void *transport_get_data(transport_handle_t t);
|
||||
esp_err_t transport_set_data(transport_handle_t t, void *data);
|
||||
esp_err_t transport_set_func(transport_handle_t t,
|
||||
connect_func _connect,
|
||||
io_func _read,
|
||||
io_func _write,
|
||||
trans_func _close,
|
||||
poll_func _poll_read,
|
||||
poll_func _poll_write,
|
||||
trans_func _destroy);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -1,38 +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
|
||||
*
|
||||
* @return
|
||||
* - transport
|
||||
* - NULL
|
||||
*/
|
||||
transport_handle_t transport_ssl_init();
|
||||
|
||||
/**
|
||||
* @brief Set SSL certification data (as PEM format)
|
||||
*
|
||||
* @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);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* This file is subject to the terms and conditions defined in
|
||||
* file 'LICENSE', which is part of this source code package.
|
||||
* Tuan PM <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
|
||||
*
|
||||
* @return
|
||||
* - transport
|
||||
* - NULL
|
||||
*/
|
||||
transport_handle_t transport_tcp_init();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -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
|
1043
lib/mqtt5_msg.c
Normal file
1043
lib/mqtt5_msg.c
Normal file
File diff suppressed because it is too large
Load Diff
590
lib/mqtt_msg.c
590
lib/mqtt_msg.c
@ -28,16 +28,17 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "mqtt_client.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 +46,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 +60,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 +82,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;
|
||||
}
|
||||
|
||||
int 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;
|
||||
int 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, uint16_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)
|
||||
return NULL;
|
||||
i += topiclen;
|
||||
|
||||
*length = topiclen;
|
||||
return (const char*)(buffer + i);
|
||||
if (mqtt_get_qos(buffer) > 0) {
|
||||
i += 2;
|
||||
}
|
||||
// i is now the length of the fixed + variable header
|
||||
return buffer_length >= i;
|
||||
}
|
||||
|
||||
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
|
||||
char *mqtt_get_publish_topic(uint8_t *buffer, size_t *length)
|
||||
{
|
||||
int i;
|
||||
int topiclen;
|
||||
|
||||
for (i = 1; i < *length; ++i) {
|
||||
if ((buffer[i] & 0x80) == 0) {
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 2 >= *length) {
|
||||
return NULL;
|
||||
}
|
||||
topiclen = buffer[i++] << 8;
|
||||
topiclen |= buffer[i++];
|
||||
|
||||
if (i + topiclen > *length) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*length = topiclen;
|
||||
return (char *)(buffer + i);
|
||||
}
|
||||
|
||||
char *mqtt_get_publish_data(uint8_t *buffer, size_t *length)
|
||||
{
|
||||
int i;
|
||||
int totlen = 0;
|
||||
@ -189,284 +230,395 @@ const char* mqtt_get_publish_data(uint8_t* buffer, uint16_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 (data != NULL) {
|
||||
if (connection->message.length + data_length > connection->buffer_length) {
|
||||
// Not enough size in buffer -> fragment this message
|
||||
connection->message.fragmented_msg_data_offset = connection->message.length;
|
||||
memcpy(connection->buffer + connection->message.length, data, connection->buffer_length - connection->message.length);
|
||||
connection->message.length = connection->buffer_length;
|
||||
connection->message.fragmented_msg_total_length = data_length + connection->message.fragmented_msg_data_offset;
|
||||
} else {
|
||||
memcpy(connection->buffer + connection->message.length, data, data_length);
|
||||
connection->message.length += data_length;
|
||||
connection->message.fragmented_msg_total_length = 0;
|
||||
}
|
||||
}
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);
|
||||
}
|
||||
|
||||
mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id)
|
||||
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 esp_mqtt_topic_t topic_list[], int size, uint16_t *message_id)
|
||||
{
|
||||
init_message(connection);
|
||||
|
||||
if (topic == NULL || topic[0] == '\0')
|
||||
if ((*message_id = append_message_id(connection, 0)) == 0) {
|
||||
return fail_message(connection);
|
||||
}
|
||||
|
||||
if ((*message_id = append_message_id(connection, 0)) == 0)
|
||||
return fail_message(connection);
|
||||
for (int topic_number = 0; topic_number < size; ++topic_number) {
|
||||
if (topic_list[topic_number].filter[0] == '\0') {
|
||||
return fail_message(connection);
|
||||
}
|
||||
|
||||
if (append_string(connection, topic, strlen(topic)) < 0)
|
||||
return fail_message(connection);
|
||||
if (append_string(connection, topic_list[topic_number].filter, strlen(topic_list[topic_number].filter)) < 0) {
|
||||
return fail_message(connection);
|
||||
}
|
||||
|
||||
if (connection->message.length + 1 > connection->buffer_length)
|
||||
return fail_message(connection);
|
||||
connection->buffer[connection->message.length++] = qos;
|
||||
if (connection->message.length + 1 > connection->buffer_length) {
|
||||
return fail_message(connection);
|
||||
}
|
||||
connection->buffer[connection->message.length] = topic_list[topic_number].qos;
|
||||
connection->message.length ++;
|
||||
}
|
||||
|
||||
return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,57 @@
|
||||
#include "mqtt_outbox.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "rom/queue.h"
|
||||
#include "mqtt_config.h"
|
||||
#include "sys/queue.h"
|
||||
#include "esp_heap_caps.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));
|
||||
mem_assert(outbox);
|
||||
ESP_MEM_CHECK(TAG, outbox, return NULL);
|
||||
STAILQ_INIT(outbox);
|
||||
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));
|
||||
mem_assert(item);
|
||||
item->msg_id = msg_id;
|
||||
item->msg_type = msg_type;
|
||||
outbox_item_handle_t item = heap_caps_calloc(1, sizeof(outbox_item_t), MQTT_OUTBOX_MEMORY);
|
||||
ESP_MEM_CHECK(TAG, item, return NULL);
|
||||
item->msg_id = message->msg_id;
|
||||
item->msg_type = message->msg_type;
|
||||
item->msg_qos = message->msg_qos;
|
||||
item->tick = tick;
|
||||
item->len = len;
|
||||
item->buffer = malloc(len);
|
||||
mem_assert(item->buffer);
|
||||
memcpy(item->buffer, data, 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, 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;
|
||||
}
|
||||
|
||||
@ -41,21 +66,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);
|
||||
@ -79,11 +134,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;
|
||||
@ -102,19 +175,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)
|
||||
@ -122,27 +213,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 */
|
||||
|
@ -1,14 +1,22 @@
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_system.h"
|
||||
#include <sys/time.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_mac.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_random.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
char *platform_create_id_string()
|
||||
static const char *TAG = "platform";
|
||||
|
||||
#define MAX_ID_STRING (32)
|
||||
|
||||
char *platform_create_id_string(void)
|
||||
{
|
||||
uint8_t mac[6];
|
||||
char *id_string = calloc(1, 32);
|
||||
mem_assert(id_string);
|
||||
char *id_string = calloc(1, MAX_ID_STRING);
|
||||
ESP_MEM_CHECK(TAG, id_string, return NULL);
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
sprintf(id_string, "ESP32_%02x%02X%02X", mac[3], mac[4], mac[5]);
|
||||
return id_string;
|
||||
@ -16,15 +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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
214
lib/transport.c
214
lib/transport.c
@ -1,214 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "transport.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 *tag; /*!< Tag name */
|
||||
void *context; /*!< Context data */
|
||||
void *data; /*!< Additional transport data */
|
||||
connect_func _connect; /*!< Connect function of this transport */
|
||||
io_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 head = calloc(1, sizeof(struct transport_list_t));
|
||||
assert(head);
|
||||
STAILQ_INIT(head);
|
||||
return head;
|
||||
}
|
||||
|
||||
esp_err_t transport_list_add(transport_list_handle_t head, transport_handle_t t, const char *scheme)
|
||||
{
|
||||
if (head == NULL || t == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
t->tag = calloc(1, strlen(scheme) + 1);
|
||||
assert(t->tag);
|
||||
strcpy(t->tag, scheme);
|
||||
STAILQ_INSERT_TAIL(head, t, next);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
transport_handle_t transport_list_get_transport(transport_list_handle_t head, const char *tag)
|
||||
{
|
||||
if (!head) {
|
||||
return NULL;
|
||||
}
|
||||
if (tag == NULL) {
|
||||
return STAILQ_FIRST(head);
|
||||
}
|
||||
transport_handle_t item;
|
||||
STAILQ_FOREACH(item, head, next) {
|
||||
if (strcasecmp(item->tag, tag) == 0) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t transport_list_destroy(transport_list_handle_t head)
|
||||
{
|
||||
transport_list_clean(head);
|
||||
free(head);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t transport_list_clean(transport_list_handle_t head)
|
||||
{
|
||||
transport_handle_t item = STAILQ_FIRST(head);
|
||||
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(head);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
transport_handle_t transport_init()
|
||||
{
|
||||
transport_handle_t t = calloc(1, sizeof(struct transport_item_t));
|
||||
assert(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
int transport_destroy(transport_handle_t t)
|
||||
{
|
||||
if (t->tag) {
|
||||
free(t->tag);
|
||||
}
|
||||
free(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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, 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_data(transport_handle_t t)
|
||||
{
|
||||
if (t) {
|
||||
return t->data;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t transport_set_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_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;
|
||||
}
|
||||
|
@ -1,250 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.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 = "TRANSPORT_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_ssl_config conf;
|
||||
mbedtls_net_context client_fd;
|
||||
void *cert_pem_data;
|
||||
int cert_pem_len;
|
||||
bool ssl_initialized;
|
||||
bool verify_server;
|
||||
} transport_ssl_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_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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
tv.tv_sec = 10; //default timeout is 10 seconds
|
||||
|
||||
if (timeout_ms) {
|
||||
tv.tv_sec = timeout_ms;
|
||||
}
|
||||
tv.tv_usec = 0;
|
||||
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);
|
||||
|
||||
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) {
|
||||
return -1;
|
||||
}
|
||||
// bzero(buf, sizeof(buf));
|
||||
// mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
|
||||
// ESP_LOGW(TAG, "verification info: %s", buf);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Certificate verified.");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl->ctx));
|
||||
exit:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ssl_poll_read(transport_handle_t t, int timeout_ms)
|
||||
{
|
||||
transport_ssl_t *ssl = transport_get_data(t);
|
||||
fd_set readset;
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(ssl->client_fd.fd, &readset);
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec = timeout_ms / 1000;
|
||||
timeout.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
|
||||
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_data(t);
|
||||
fd_set writeset;
|
||||
FD_ZERO(&writeset);
|
||||
FD_SET(ssl->client_fd.fd, &writeset);
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec = timeout_ms / 1000;
|
||||
timeout.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
return select(ssl->client_fd.fd + 1, NULL, &writeset, NULL, &timeout);
|
||||
}
|
||||
|
||||
static int ssl_write(transport_handle_t t, char *buffer, int len, int timeout_ms)
|
||||
{
|
||||
int poll, ret;
|
||||
transport_ssl_t *ssl = transport_get_data(t);
|
||||
|
||||
if ((poll = transport_poll_write(t, timeout_ms)) <= 0) {
|
||||
return poll;
|
||||
}
|
||||
ret = mbedtls_ssl_write(&ssl->ctx, (const unsigned char *) buffer, len);
|
||||
//TODO: Debug here
|
||||
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_data(t);
|
||||
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_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);
|
||||
}
|
||||
mbedtls_ctr_drbg_free(&ssl->ctr_drbg);
|
||||
mbedtls_entropy_free(&ssl->entropy);
|
||||
mbedtls_ssl_free(&ssl->ctx);
|
||||
ssl->ssl_initialized = false;
|
||||
ssl->verify_server = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int ssl_destroy(transport_handle_t t)
|
||||
{
|
||||
transport_ssl_t *ssl = transport_get_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_data(t);
|
||||
if (t) {
|
||||
if (t && ssl) {
|
||||
ssl->cert_pem_data = (void *)data;
|
||||
ssl->cert_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));
|
||||
assert(ssl);
|
||||
mbedtls_net_init(&ssl->client_fd);
|
||||
transport_set_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;
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "transport.h"
|
||||
|
||||
static const char *TAG = "TRANSPORT_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_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);
|
||||
|
||||
tv.tv_sec = 10; //default timeout is 10 seconds
|
||||
|
||||
if (timeout_ms) {
|
||||
tv.tv_sec = timeout_ms;
|
||||
}
|
||||
tv.tv_usec = 0;
|
||||
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, char *buffer, int len, int timeout_ms)
|
||||
{
|
||||
int poll;
|
||||
transport_tcp_t *tcp = transport_get_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_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_data(t);
|
||||
fd_set readset;
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(tcp->sock, &readset);
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = timeout_ms / 1000;
|
||||
timeout.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
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_data(t);
|
||||
fd_set writeset;
|
||||
FD_ZERO(&writeset);
|
||||
FD_SET(tcp->sock, &writeset);
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = timeout_ms / 1000;
|
||||
timeout.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
return select(tcp->sock + 1, NULL, &writeset, NULL, &timeout);
|
||||
}
|
||||
|
||||
static int tcp_close(transport_handle_t t)
|
||||
{
|
||||
transport_tcp_t *tcp = transport_get_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_data(t);
|
||||
free(tcp);
|
||||
transport_close(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
transport_handle_t transport_tcp_init()
|
||||
{
|
||||
transport_handle_t t = transport_init();
|
||||
transport_tcp_t *tcp = calloc(1, sizeof(transport_tcp_t));
|
||||
assert(tcp);
|
||||
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_data(t, tcp);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
@ -1,247 +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_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, char *buffer, int len, int timeout_ms)
|
||||
{
|
||||
transport_ws_t *ws = transport_get_data(t);
|
||||
char ws_header[MAX_WEBSOCKET_HEADER_SIZE];
|
||||
char *mask;
|
||||
int header_len = 0, i;
|
||||
|
||||
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_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_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_data(t);
|
||||
return transport_poll_write(ws->parent, timeout_ms);;
|
||||
}
|
||||
|
||||
static int ws_close(transport_handle_t t)
|
||||
{
|
||||
transport_ws_t *ws = transport_get_data(t);
|
||||
return transport_close(ws->parent);
|
||||
}
|
||||
|
||||
static esp_err_t ws_destroy(transport_handle_t t)
|
||||
{
|
||||
transport_ws_t *ws = transport_get_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_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));
|
||||
assert(ws);
|
||||
ws->parent = parent_handle;
|
||||
ws->buffer = malloc(DEFAULT_WS_BUFFER);
|
||||
mem_assert(ws->buffer);
|
||||
ws->path = calloc(1, 2);
|
||||
ws->path[0] = '/';
|
||||
|
||||
mem_assert(ws->buffer);
|
||||
transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy);
|
||||
transport_set_data(t, ws);
|
||||
return t;
|
||||
}
|
||||
|
760
mqtt5_client.c
Normal file
760
mqtt5_client.c
Normal file
@ -0,0 +1,760 @@
|
||||
/*
|
||||
* 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_increment_packet_counter(esp_mqtt5_client_handle_t client)
|
||||
{
|
||||
bool msg_dup = mqtt5_get_dup(client->mqtt_state.outbound_message->data);
|
||||
if (msg_dup == false) {
|
||||
client->send_publish_packet_count ++;
|
||||
ESP_LOGD(TAG, "Sent (%d) qos > 0 publish packet without ack", client->send_publish_packet_count);
|
||||
}
|
||||
}
|
||||
|
||||
void esp_mqtt5_decrement_packet_counter(esp_mqtt5_client_handle_t client)
|
||||
{
|
||||
if (client->send_publish_packet_count > 0) {
|
||||
client->send_publish_packet_count --;
|
||||
ESP_LOGD(TAG, "Receive (%d) qos > 0 publish packet with ack", client->send_publish_packet_count);
|
||||
}
|
||||
}
|
||||
|
||||
void esp_mqtt5_parse_pubcomp(esp_mqtt5_client_handle_t client)
|
||||
{
|
||||
if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBCOMP return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len));
|
||||
size_t msg_data_len = client->mqtt_state.in_buffer_read_len;
|
||||
client->event.data = mqtt5_get_pubcomp_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property);
|
||||
client->event.data_len = msg_data_len;
|
||||
client->event.total_data_len = msg_data_len;
|
||||
client->event.current_data_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_mqtt5_parse_puback(esp_mqtt5_client_handle_t client)
|
||||
{
|
||||
if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len));
|
||||
size_t msg_data_len = client->mqtt_state.in_buffer_read_len;
|
||||
client->event.data = mqtt5_get_puback_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property);
|
||||
client->event.data_len = msg_data_len;
|
||||
client->event.total_data_len = msg_data_len;
|
||||
client->event.current_data_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_mqtt5_parse_unsuback(esp_mqtt5_client_handle_t client)
|
||||
{
|
||||
if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGI(TAG, "MQTT_MSG_TYPE_UNSUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len));
|
||||
size_t msg_data_len = client->mqtt_state.in_buffer_read_len;
|
||||
client->event.data = mqtt5_get_unsuback_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property);
|
||||
client->event.data_len = msg_data_len;
|
||||
client->event.total_data_len = msg_data_len;
|
||||
client->event.current_data_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_mqtt5_parse_suback(esp_mqtt5_client_handle_t client)
|
||||
{
|
||||
if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGI(TAG, "MQTT_MSG_TYPE_SUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len));
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_parse_connack(esp_mqtt5_client_handle_t client, int *connect_rsp_code)
|
||||
{
|
||||
size_t len = client->mqtt_state.in_buffer_read_len;
|
||||
client->mqtt_state.in_buffer_read_len = 0;
|
||||
uint8_t ack_flag = 0;
|
||||
if (mqtt5_msg_parse_connack_property(client->mqtt_state.in_buffer, len, &client->connect_info, &client->mqtt5_config->connect_property_info, &client->mqtt5_config->server_resp_property_info, connect_rsp_code, &ack_flag, &client->event.property->user_property) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to parse CONNACK packet");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (*connect_rsp_code == MQTT_CONNECTION_ACCEPTED) {
|
||||
ESP_LOGD(TAG, "Connected");
|
||||
client->event.session_present = ack_flag & 0x01;
|
||||
return ESP_OK;
|
||||
}
|
||||
esp_mqtt5_print_error_code(client, *connect_rsp_code);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_get_publish_data(esp_mqtt5_client_handle_t client, uint8_t *msg_buf, size_t msg_read_len, char **msg_topic, size_t *msg_topic_len, char **msg_data, size_t *msg_data_len)
|
||||
{
|
||||
// get property
|
||||
uint16_t property_len = 0;
|
||||
esp_mqtt5_publish_resp_property_t property = {0};
|
||||
*msg_data = mqtt5_get_publish_property_payload(msg_buf, msg_read_len, msg_topic, msg_topic_len, &property, &property_len, msg_data_len, &client->event.property->user_property);
|
||||
if (*msg_data == NULL) {
|
||||
ESP_LOGE(TAG, "%s: mqtt5_get_publish_property_payload() failed", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (property.topic_alias > client->mqtt5_config->connect_property_info.topic_alias_maximum) {
|
||||
ESP_LOGE(TAG, "%s: Broker response topic alias %d is over the max topic alias %d", __func__, property.topic_alias, client->mqtt5_config->connect_property_info.topic_alias_maximum);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (property.topic_alias) {
|
||||
if (*msg_topic_len == 0) {
|
||||
ESP_LOGI(TAG, "Publish topic is empty, use topic alias");
|
||||
*msg_topic = esp_mqtt5_client_get_topic_alias(client->mqtt5_config->peer_topic_alias, property.topic_alias, msg_topic_len);
|
||||
if (!*msg_topic) {
|
||||
ESP_LOGE(TAG, "%s: esp_mqtt5_client_get_topic_alias() failed", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else {
|
||||
if (esp_mqtt5_client_update_topic_alias(client->mqtt5_config->peer_topic_alias, property.topic_alias, *msg_topic, *msg_topic_len) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: esp_mqtt5_client_update_topic_alias() failed", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client->event.property->payload_format_indicator = property.payload_format_indicator;
|
||||
client->event.property->response_topic = property.response_topic;
|
||||
client->event.property->response_topic_len = property.response_topic_len;
|
||||
client->event.property->correlation_data = property.correlation_data;
|
||||
client->event.property->correlation_data_len = property.correlation_data_len;
|
||||
client->event.property->content_type = property.content_type;
|
||||
client->event.property->content_type_len = property.content_type_len;
|
||||
client->event.property->subscribe_id = property.subscribe_id;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_create_default_config(esp_mqtt5_client_handle_t client)
|
||||
{
|
||||
if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) {
|
||||
client->event.property = calloc(1, sizeof(esp_mqtt5_event_property_t));
|
||||
ESP_MEM_CHECK(TAG, client->event.property, return ESP_FAIL)
|
||||
client->mqtt5_config = calloc(1, sizeof(mqtt5_config_storage_t));
|
||||
ESP_MEM_CHECK(TAG, client->mqtt5_config, return ESP_FAIL)
|
||||
client->mqtt5_config->server_resp_property_info.max_qos = 2;
|
||||
client->mqtt5_config->server_resp_property_info.retain_available = true;
|
||||
client->mqtt5_config->server_resp_property_info.wildcard_subscribe_available = true;
|
||||
client->mqtt5_config->server_resp_property_info.subscribe_identifiers_available = true;
|
||||
client->mqtt5_config->server_resp_property_info.shared_subscribe_available = true;
|
||||
client->mqtt5_config->server_resp_property_info.receive_maximum = 65535;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void esp_mqtt5_print_error_code(esp_mqtt5_client_handle_t client, int code)
|
||||
{
|
||||
switch (code) {
|
||||
case MQTT5_UNSPECIFIED_ERROR:
|
||||
ESP_LOGW(TAG, "Unspecified error");
|
||||
break;
|
||||
case MQTT5_MALFORMED_PACKET:
|
||||
ESP_LOGW(TAG, "Malformed Packet");
|
||||
break;
|
||||
case MQTT5_PROTOCOL_ERROR:
|
||||
ESP_LOGW(TAG, "Protocol Error");
|
||||
break;
|
||||
case MQTT5_IMPLEMENT_SPECIFIC_ERROR:
|
||||
ESP_LOGW(TAG, "Implementation specific error");
|
||||
break;
|
||||
case MQTT5_UNSUPPORTED_PROTOCOL_VER:
|
||||
ESP_LOGW(TAG, "Unsupported Protocol Version");
|
||||
break;
|
||||
case MQTT5_INVAILD_CLIENT_ID:
|
||||
ESP_LOGW(TAG, "Client Identifier not valid");
|
||||
break;
|
||||
case MQTT5_BAD_USERNAME_OR_PWD:
|
||||
ESP_LOGW(TAG, "Bad User Name or Password");
|
||||
break;
|
||||
case MQTT5_NOT_AUTHORIZED:
|
||||
ESP_LOGW(TAG, "Not authorized");
|
||||
break;
|
||||
case MQTT5_SERVER_UNAVAILABLE:
|
||||
ESP_LOGW(TAG, "Server unavailable");
|
||||
break;
|
||||
case MQTT5_SERVER_BUSY:
|
||||
ESP_LOGW(TAG, "Server busy");
|
||||
break;
|
||||
case MQTT5_BANNED:
|
||||
ESP_LOGW(TAG, "Banned");
|
||||
break;
|
||||
case MQTT5_SERVER_SHUTTING_DOWN:
|
||||
ESP_LOGW(TAG, "Server shutting down");
|
||||
break;
|
||||
case MQTT5_BAD_AUTH_METHOD:
|
||||
ESP_LOGW(TAG, "Bad authentication method");
|
||||
break;
|
||||
case MQTT5_KEEP_ALIVE_TIMEOUT:
|
||||
ESP_LOGW(TAG, "Keep Alive timeout");
|
||||
break;
|
||||
case MQTT5_SESSION_TAKEN_OVER:
|
||||
ESP_LOGW(TAG, "Session taken over");
|
||||
break;
|
||||
case MQTT5_TOPIC_FILTER_INVAILD:
|
||||
ESP_LOGW(TAG, "Topic Filter invalid");
|
||||
break;
|
||||
case MQTT5_TOPIC_NAME_INVAILD:
|
||||
ESP_LOGW(TAG, "Topic Name invalid");
|
||||
break;
|
||||
case MQTT5_PACKET_IDENTIFIER_IN_USE:
|
||||
ESP_LOGW(TAG, "Packet Identifier in use");
|
||||
break;
|
||||
case MQTT5_PACKET_IDENTIFIER_NOT_FOUND:
|
||||
ESP_LOGW(TAG, "Packet Identifier not found");
|
||||
break;
|
||||
case MQTT5_RECEIVE_MAXIMUM_EXCEEDED:
|
||||
ESP_LOGW(TAG, "Receive Maximum exceeded");
|
||||
break;
|
||||
case MQTT5_TOPIC_ALIAS_INVAILD:
|
||||
ESP_LOGW(TAG, "Topic Alias invalid");
|
||||
break;
|
||||
case MQTT5_PACKET_TOO_LARGE:
|
||||
ESP_LOGW(TAG, "Packet too large");
|
||||
break;
|
||||
case MQTT5_MESSAGE_RATE_TOO_HIGH:
|
||||
ESP_LOGW(TAG, "Message rate too high");
|
||||
break;
|
||||
case MQTT5_QUOTA_EXCEEDED:
|
||||
ESP_LOGW(TAG, "Quota exceeded");
|
||||
break;
|
||||
case MQTT5_ADMINISTRATIVE_ACTION:
|
||||
ESP_LOGW(TAG, "Administrative action");
|
||||
break;
|
||||
case MQTT5_PAYLOAD_FORMAT_INVAILD:
|
||||
ESP_LOGW(TAG, "Payload format invalid");
|
||||
break;
|
||||
case MQTT5_RETAIN_NOT_SUPPORT:
|
||||
ESP_LOGW(TAG, "Retain not supported");
|
||||
break;
|
||||
case MQTT5_QOS_NOT_SUPPORT:
|
||||
ESP_LOGW(TAG, "QoS not supported");
|
||||
break;
|
||||
case MQTT5_USE_ANOTHER_SERVER:
|
||||
ESP_LOGW(TAG, "Use another server");
|
||||
break;
|
||||
case MQTT5_SERVER_MOVED:
|
||||
ESP_LOGW(TAG, "Server moved");
|
||||
break;
|
||||
case MQTT5_SHARED_SUBSCR_NOT_SUPPORTED:
|
||||
ESP_LOGW(TAG, "Shared Subscriptions not supported");
|
||||
break;
|
||||
case MQTT5_CONNECTION_RATE_EXCEEDED:
|
||||
ESP_LOGW(TAG, "Connection rate exceeded");
|
||||
break;
|
||||
case MQTT5_MAXIMUM_CONNECT_TIME:
|
||||
ESP_LOGW(TAG, "Maximum connect time");
|
||||
break;
|
||||
case MQTT5_SUBSCRIBE_IDENTIFIER_NOT_SUPPORT:
|
||||
ESP_LOGW(TAG, "Subscription Identifiers not supported");
|
||||
break;
|
||||
case MQTT5_WILDCARD_SUBSCRIBE_NOT_SUPPORT:
|
||||
ESP_LOGW(TAG, "Wildcard Subscriptions not supported");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Connection refused, Unknow reason");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_subscribe_check(esp_mqtt5_client_handle_t client, int qos)
|
||||
{
|
||||
/* Check Server support QoS level */
|
||||
if (client->mqtt5_config->server_resp_property_info.max_qos < qos) {
|
||||
ESP_LOGE(TAG, "Server only support max QoS level %d", client->mqtt5_config->server_resp_property_info.max_qos);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_publish_check(esp_mqtt5_client_handle_t client, int qos, int retain)
|
||||
{
|
||||
/* Check Server support QoS level */
|
||||
if (client->mqtt5_config->server_resp_property_info.max_qos < qos) {
|
||||
ESP_LOGE(TAG, "Server only support max QoS level %d", client->mqtt5_config->server_resp_property_info.max_qos);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Check Server support RETAIN */
|
||||
if (!client->mqtt5_config->server_resp_property_info.retain_available && retain) {
|
||||
ESP_LOGE(TAG, "Server not support retain");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Flow control to check PUBLISH(No PUBACK or PUBCOMP received) packet sent count(Only record QoS1 and QoS2)*/
|
||||
if (client->send_publish_packet_count > client->mqtt5_config->server_resp_property_info.receive_maximum) {
|
||||
ESP_LOGE(TAG, "Client send more than %d QoS1 and QoS2 PUBLISH packet without no ack", client->mqtt5_config->server_resp_property_info.receive_maximum);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_mqtt5_client_destory(esp_mqtt5_client_handle_t client)
|
||||
{
|
||||
if (client->connect_info.protocol_ver == MQTT_PROTOCOL_V_5) {
|
||||
if (client->mqtt5_config) {
|
||||
free(client->mqtt5_config->will_property_info.content_type);
|
||||
free(client->mqtt5_config->will_property_info.response_topic);
|
||||
free(client->mqtt5_config->will_property_info.correlation_data);
|
||||
free(client->mqtt5_config->server_resp_property_info.response_info);
|
||||
esp_mqtt5_client_delete_topic_alias(client->mqtt5_config->peer_topic_alias);
|
||||
esp_mqtt5_client_delete_user_property(client->mqtt5_config->connect_property_info.user_property);
|
||||
esp_mqtt5_client_delete_user_property(client->mqtt5_config->will_property_info.user_property);
|
||||
esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property);
|
||||
free(client->mqtt5_config);
|
||||
}
|
||||
free(client->event.property);
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_mqtt5_client_delete_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle)
|
||||
{
|
||||
if (topic_alias_handle) {
|
||||
mqtt5_topic_alias_item_t item, tmp;
|
||||
STAILQ_FOREACH_SAFE(item, topic_alias_handle, next, tmp) {
|
||||
STAILQ_REMOVE(topic_alias_handle, item, mqtt5_topic_alias, next);
|
||||
free(item->topic);
|
||||
free(item);
|
||||
}
|
||||
free(topic_alias_handle);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t esp_mqtt5_client_update_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, char *topic, size_t topic_len)
|
||||
{
|
||||
mqtt5_topic_alias_item_t item;
|
||||
bool found = false;
|
||||
STAILQ_FOREACH(item, topic_alias_handle, next) {
|
||||
if (item->topic_alias == topic_alias) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if ((item->topic_len != topic_len) || strncmp(topic, item->topic, topic_len)) {
|
||||
free(item->topic);
|
||||
item->topic = calloc(1, topic_len);
|
||||
ESP_MEM_CHECK(TAG, item->topic, return ESP_FAIL);
|
||||
memcpy(item->topic, topic, topic_len);
|
||||
item->topic_len = topic_len;
|
||||
}
|
||||
} else {
|
||||
item = calloc(1, sizeof(mqtt5_topic_alias_t));
|
||||
ESP_MEM_CHECK(TAG, item, return ESP_FAIL);
|
||||
item->topic_alias = topic_alias;
|
||||
item->topic_len = topic_len;
|
||||
item->topic = calloc(1, topic_len);
|
||||
ESP_MEM_CHECK(TAG, item->topic, {
|
||||
free(item);
|
||||
return ESP_FAIL;
|
||||
});
|
||||
memcpy(item->topic, topic, topic_len);
|
||||
STAILQ_INSERT_TAIL(topic_alias_handle, item, next);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static char *esp_mqtt5_client_get_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, size_t *topic_length)
|
||||
{
|
||||
mqtt5_topic_alias_item_t item;
|
||||
STAILQ_FOREACH(item, topic_alias_handle, next) {
|
||||
if (item->topic_alias == topic_alias) {
|
||||
*topic_length = item->topic_len;
|
||||
return item->topic;
|
||||
}
|
||||
}
|
||||
*topic_length = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static esp_err_t esp_mqtt5_user_property_copy(mqtt5_user_property_handle_t user_property_new, const mqtt5_user_property_handle_t user_property_old)
|
||||
{
|
||||
if (!user_property_new || !user_property_old) {
|
||||
ESP_LOGE(TAG, "Input is NULL");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
mqtt5_user_property_item_t old_item, new_item;
|
||||
STAILQ_FOREACH(old_item, user_property_old, next) {
|
||||
new_item = calloc(1, sizeof(mqtt5_user_property_t));
|
||||
ESP_MEM_CHECK(TAG, new_item, return ESP_FAIL);
|
||||
new_item->key = strdup(old_item->key);
|
||||
ESP_MEM_CHECK(TAG, new_item->key, {
|
||||
free(new_item);
|
||||
return ESP_FAIL;
|
||||
});
|
||||
new_item->value = strdup(old_item->value);
|
||||
ESP_MEM_CHECK(TAG, new_item->value, {
|
||||
free(new_item->key);
|
||||
free(new_item);
|
||||
return ESP_FAIL;
|
||||
});
|
||||
STAILQ_INSERT_TAIL(user_property_new, new_item, next);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_set_publish_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_publish_property_config_t *property)
|
||||
{
|
||||
if (!client) {
|
||||
ESP_LOGE(TAG, "Client was not initialized");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MQTT_API_LOCK(client);
|
||||
|
||||
/* Check protocol version */
|
||||
if(client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGE(TAG, "MQTT protocol version is not v5");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
/* Check topic alias less than server maximum topic alias */
|
||||
if (property->topic_alias > client->mqtt5_config->server_resp_property_info.topic_alias_maximum) {
|
||||
ESP_LOGE(TAG, "Topic alias %d is bigger than server support %d", property->topic_alias, client->mqtt5_config->server_resp_property_info.topic_alias_maximum);
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
client->mqtt5_config->publish_property_info = property;
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_set_subscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_subscribe_property_config_t *property)
|
||||
{
|
||||
if (!client) {
|
||||
ESP_LOGE(TAG, "Client was not initialized");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (property->retain_handle > 2) {
|
||||
ESP_LOGE(TAG, "retain_handle only support 0, 1, 2");
|
||||
return -1;
|
||||
}
|
||||
MQTT_API_LOCK(client);
|
||||
|
||||
/* Check protocol version */
|
||||
if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGE(TAG, "MQTT protocol version is not v5");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (property->is_share_subscribe) {
|
||||
if (property->no_local_flag) {
|
||||
// MQTT-3.8.3-4 not allow that No Local bit to 1 on a Shared Subscription
|
||||
ESP_LOGE(TAG, "Protocol error that no local flag set on shared subscription");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (!client->mqtt5_config->server_resp_property_info.shared_subscribe_available) {
|
||||
ESP_LOGE(TAG, "MQTT broker not support shared subscribe");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (!property->share_name || !strlen(property->share_name)) {
|
||||
ESP_LOGE(TAG, "Share name can't be empty for shared subscribe");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
client->mqtt5_config->subscribe_property_info = property;
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_set_unsubscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_unsubscribe_property_config_t *property)
|
||||
{
|
||||
if (!client) {
|
||||
ESP_LOGE(TAG, "Client was not initialized");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MQTT_API_LOCK(client);
|
||||
|
||||
/* Check protocol version */
|
||||
if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGE(TAG, "MQTT protocol version is not v5");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (property->is_share_subscribe) {
|
||||
if (!client->mqtt5_config->server_resp_property_info.shared_subscribe_available) {
|
||||
ESP_LOGE(TAG, "MQTT broker not support shared subscribe");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (!property->share_name || !strlen(property->share_name)) {
|
||||
ESP_LOGE(TAG, "Share name can't be empty for shared subscribe");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
client->mqtt5_config->unsubscribe_property_info = property;
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_set_disconnect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_disconnect_property_config_t *property)
|
||||
{
|
||||
if (!client) {
|
||||
ESP_LOGE(TAG, "Client was not initialized");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MQTT_API_LOCK(client);
|
||||
|
||||
/* Check protocol version */
|
||||
if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGE(TAG, "MQTT protocol version is not v5");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (property) {
|
||||
if (property->session_expiry_interval) {
|
||||
client->mqtt5_config->disconnect_property_info.session_expiry_interval = property->session_expiry_interval;
|
||||
}
|
||||
if (property->disconnect_reason) {
|
||||
client->mqtt5_config->disconnect_property_info.disconnect_reason = property->disconnect_reason;
|
||||
}
|
||||
if (property->user_property) {
|
||||
esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property);
|
||||
client->mqtt5_config->disconnect_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t));
|
||||
ESP_MEM_CHECK(TAG, client->mqtt5_config->disconnect_property_info.user_property, {
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_ERR_NO_MEM;
|
||||
});
|
||||
STAILQ_INIT(client->mqtt5_config->disconnect_property_info.user_property);
|
||||
if (esp_mqtt5_user_property_copy(client->mqtt5_config->disconnect_property_info.user_property, property->user_property) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail");
|
||||
free(client->mqtt5_config->disconnect_property_info.user_property);
|
||||
client->mqtt5_config->disconnect_property_info.user_property = NULL;
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_set_connect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_connection_property_config_t *connect_property)
|
||||
{
|
||||
if (!client) {
|
||||
ESP_LOGE(TAG, "Client was not initialized");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MQTT_API_LOCK(client);
|
||||
|
||||
/* Check protocol version */
|
||||
if (client->connect_info.protocol_ver != MQTT_PROTOCOL_V_5) {
|
||||
ESP_LOGE(TAG, "MQTT protocol version is not v5");
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (connect_property) {
|
||||
if (connect_property->session_expiry_interval) {
|
||||
client->mqtt5_config->connect_property_info.session_expiry_interval = connect_property->session_expiry_interval;
|
||||
}
|
||||
if (connect_property->maximum_packet_size) {
|
||||
if (connect_property->maximum_packet_size > client->mqtt_state.in_buffer_length) {
|
||||
ESP_LOGW(TAG, "Connect maximum_packet_size property is over buffer_size(%d), Please first change it", client->mqtt_state.in_buffer_length);
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
client->mqtt5_config->connect_property_info.maximum_packet_size = connect_property->maximum_packet_size;
|
||||
}
|
||||
} else {
|
||||
client->mqtt5_config->connect_property_info.maximum_packet_size = client->mqtt_state.in_buffer_length;
|
||||
}
|
||||
if (connect_property->receive_maximum) {
|
||||
client->mqtt5_config->connect_property_info.receive_maximum = connect_property->receive_maximum;
|
||||
}
|
||||
if (connect_property->topic_alias_maximum) {
|
||||
client->mqtt5_config->connect_property_info.topic_alias_maximum = connect_property->topic_alias_maximum;
|
||||
if (!client->mqtt5_config->peer_topic_alias) {
|
||||
client->mqtt5_config->peer_topic_alias = calloc(1, sizeof(struct mqtt5_topic_alias_list_t));
|
||||
ESP_MEM_CHECK(TAG, client->mqtt5_config->peer_topic_alias, goto _mqtt_set_config_failed);
|
||||
STAILQ_INIT(client->mqtt5_config->peer_topic_alias);
|
||||
}
|
||||
}
|
||||
if (connect_property->request_resp_info) {
|
||||
client->mqtt5_config->connect_property_info.request_resp_info = connect_property->request_resp_info;
|
||||
}
|
||||
if (connect_property->request_problem_info) {
|
||||
client->mqtt5_config->connect_property_info.request_problem_info = connect_property->request_problem_info;
|
||||
}
|
||||
if (connect_property->user_property) {
|
||||
esp_mqtt5_client_delete_user_property(client->mqtt5_config->connect_property_info.user_property);
|
||||
client->mqtt5_config->connect_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t));
|
||||
ESP_MEM_CHECK(TAG, client->mqtt5_config->connect_property_info.user_property, goto _mqtt_set_config_failed);
|
||||
STAILQ_INIT(client->mqtt5_config->connect_property_info.user_property);
|
||||
if (esp_mqtt5_user_property_copy(client->mqtt5_config->connect_property_info.user_property, connect_property->user_property) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail");
|
||||
goto _mqtt_set_config_failed;
|
||||
}
|
||||
}
|
||||
if (connect_property->payload_format_indicator) {
|
||||
client->mqtt5_config->will_property_info.payload_format_indicator = connect_property->payload_format_indicator;
|
||||
}
|
||||
if (connect_property->will_delay_interval) {
|
||||
client->mqtt5_config->will_property_info.will_delay_interval = connect_property->will_delay_interval;
|
||||
}
|
||||
if (connect_property->message_expiry_interval) {
|
||||
client->mqtt5_config->will_property_info.message_expiry_interval = connect_property->message_expiry_interval;
|
||||
}
|
||||
ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(connect_property->content_type, &client->mqtt5_config->will_property_info.content_type), goto _mqtt_set_config_failed);
|
||||
ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(connect_property->response_topic, &client->mqtt5_config->will_property_info.response_topic), goto _mqtt_set_config_failed);
|
||||
if (connect_property->correlation_data && connect_property->correlation_data_len) {
|
||||
free(client->mqtt5_config->will_property_info.correlation_data);
|
||||
client->mqtt5_config->will_property_info.correlation_data = malloc(connect_property->correlation_data_len);
|
||||
ESP_MEM_CHECK(TAG, client->mqtt5_config->will_property_info.correlation_data, goto _mqtt_set_config_failed);
|
||||
memcpy(client->mqtt5_config->will_property_info.correlation_data, connect_property->correlation_data, connect_property->correlation_data_len);
|
||||
client->mqtt5_config->will_property_info.correlation_data_len = connect_property->correlation_data_len;
|
||||
}
|
||||
if (connect_property->will_user_property) {
|
||||
esp_mqtt5_client_delete_user_property(client->mqtt5_config->will_property_info.user_property);
|
||||
client->mqtt5_config->will_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t));
|
||||
ESP_MEM_CHECK(TAG, client->mqtt5_config->will_property_info.user_property, goto _mqtt_set_config_failed);
|
||||
STAILQ_INIT(client->mqtt5_config->will_property_info.user_property);
|
||||
if (esp_mqtt5_user_property_copy(client->mqtt5_config->will_property_info.user_property, connect_property->will_user_property) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail");
|
||||
goto _mqtt_set_config_failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_OK;
|
||||
_mqtt_set_config_failed:
|
||||
esp_mqtt_destroy_config(client);
|
||||
MQTT_API_UNLOCK(client);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_property, esp_mqtt5_user_property_item_t item[], uint8_t item_num)
|
||||
{
|
||||
if (!item_num || !item) {
|
||||
ESP_LOGE(TAG, "Input value is NULL");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (!*user_property) {
|
||||
*user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t));
|
||||
ESP_MEM_CHECK(TAG, *user_property, return ESP_ERR_NO_MEM);
|
||||
STAILQ_INIT(*user_property);
|
||||
}
|
||||
|
||||
for (int i = 0; i < item_num; i ++) {
|
||||
if (item[i].key && item[i].value) {
|
||||
mqtt5_user_property_item_t user_property_item = calloc(1, sizeof(mqtt5_user_property_t));
|
||||
ESP_MEM_CHECK(TAG, user_property_item, goto err);
|
||||
size_t key_len = strlen(item[i].key);
|
||||
size_t value_len = strlen(item[i].value);
|
||||
|
||||
user_property_item->key = calloc(1, key_len + 1);
|
||||
ESP_MEM_CHECK(TAG, user_property_item->key, {
|
||||
free(user_property_item);
|
||||
goto err;
|
||||
});
|
||||
memcpy(user_property_item->key, item[i].key, key_len);
|
||||
user_property_item->key[key_len] = '\0';
|
||||
|
||||
user_property_item->value = calloc(1, value_len + 1);
|
||||
ESP_MEM_CHECK(TAG, user_property_item->value, {
|
||||
free(user_property_item->key);
|
||||
free(user_property_item);
|
||||
goto err;
|
||||
});
|
||||
memcpy(user_property_item->value, item[i].value, value_len);
|
||||
user_property_item->value[value_len] = '\0';
|
||||
|
||||
STAILQ_INSERT_TAIL(*user_property, user_property_item, next);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
esp_mqtt5_client_delete_user_property(*user_property);
|
||||
*user_property = NULL;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt5_client_get_user_property(mqtt5_user_property_handle_t user_property, esp_mqtt5_user_property_item_t *item, uint8_t *item_num)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
if (user_property && item && *item_num) {
|
||||
mqtt5_user_property_item_t user_property_item;
|
||||
uint8_t num = *item_num;
|
||||
STAILQ_FOREACH(user_property_item, user_property, next) {
|
||||
if (i < num) {
|
||||
size_t item_key_len = strlen(user_property_item->key);
|
||||
size_t item_value_len = strlen(user_property_item->value);
|
||||
char *key = calloc(1, item_key_len + 1);
|
||||
ESP_MEM_CHECK(TAG, key, goto err);
|
||||
memcpy(key, user_property_item->key, item_key_len);
|
||||
key[item_key_len] = '\0';
|
||||
char *value = calloc(1, item_value_len + 1);
|
||||
ESP_MEM_CHECK(TAG, value, {
|
||||
free(key);
|
||||
goto err;
|
||||
});
|
||||
memcpy(value, user_property_item->value, item_value_len);
|
||||
value[item_value_len] = '\0';
|
||||
item[i].key = key;
|
||||
item[i].value = value;
|
||||
i ++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*item_num = i;
|
||||
return ESP_OK;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Input value is NULL or item_num is 0");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
err:
|
||||
for (j = 0; j < i; j ++) {
|
||||
if (item[j].key) {
|
||||
free((char *)item[j].key);
|
||||
}
|
||||
if (item[j].value) {
|
||||
free((char *)item[j].value);
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
uint8_t esp_mqtt5_client_get_user_property_count(mqtt5_user_property_handle_t user_property)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
if (user_property) {
|
||||
mqtt5_user_property_item_t item;
|
||||
STAILQ_FOREACH(item, user_property, next) {
|
||||
count ++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void esp_mqtt5_client_delete_user_property(mqtt5_user_property_handle_t user_property)
|
||||
{
|
||||
if (user_property) {
|
||||
mqtt5_user_property_item_t item, tmp;
|
||||
STAILQ_FOREACH_SAFE(item, user_property, next, tmp) {
|
||||
STAILQ_REMOVE(user_property, item, mqtt5_user_property, next);
|
||||
free(item->key);
|
||||
free(item->value);
|
||||
free(item);
|
||||
}
|
||||
}
|
||||
free(user_property);
|
||||
}
|
2454
mqtt_client.c
2454
mqtt_client.c
File diff suppressed because it is too large
Load Diff
9
static-analysis-rules.yml
Normal file
9
static-analysis-rules.yml
Normal file
@ -0,0 +1,9 @@
|
||||
limits:
|
||||
"clang-analyzer-core.NullDereference" : 0
|
||||
"clang-analyzer-unix.Malloc" : 0
|
||||
|
||||
ignore:
|
||||
- "llvm-header-guard"
|
||||
- "llvm-include-order"
|
||||
|
||||
skip:
|
Reference in New Issue
Block a user