mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-03 13:46:33 +02:00
Compare commits
308 Commits
mdns-v1.0.
...
websocket-
Author | SHA1 | Date | |
---|---|---|---|
08f1f0175d | |||
a2050ac041 | |||
6015c19c31 | |||
5df8fdb713 | |||
ef3f0ee688 | |||
996fef7fcf | |||
9f87a8ca77 | |||
3bf0511938 | |||
319fce018e | |||
44bae24c78 | |||
d047ff569c | |||
02be2b76f8 | |||
1c850ddacf | |||
9ae88aab48 | |||
c6db3ea84c | |||
b23eedac3a | |||
1407dfc2e7 | |||
34c6f52f70 | |||
c674b8855d | |||
256389613f | |||
2865255ec0 | |||
7b2470ddd6 | |||
dda2722563 | |||
36db37ea2b | |||
4f013e3522 | |||
231392d0c6 | |||
9fb01ca534 | |||
d464ed7d30 | |||
b94a211e4b | |||
73f2800b59 | |||
e00e056162 | |||
1b134486db | |||
7ba1085e9f | |||
3bdb2067e0 | |||
1d6888445d | |||
d68624ec4f | |||
d4825f5c53 | |||
de1480a072 | |||
b9b4a75000 | |||
cc259aa035 | |||
91134f10ff | |||
fb8a2f0198 | |||
b87bef52e5 | |||
28813148b2 | |||
ae38f27997 | |||
d0c9070715 | |||
a8339e4618 | |||
12cfcb5aed | |||
2cfffb056e | |||
0247926219 | |||
05fff94b91 | |||
8958d5e37c | |||
f71192b876 | |||
f9b47900f2 | |||
0e215b118f | |||
dc8b916561 | |||
a01096f621 | |||
3de4727385 | |||
59053b8c98 | |||
2956477353 | |||
1d9b6f7e90 | |||
6b684ceb0f | |||
5304a6ec0e | |||
c7f20ee98e | |||
7d47ec3b6b | |||
e4c8a5932c | |||
b56b1c577b | |||
4e212c31fe | |||
9a7bd90ad9 | |||
4314c78ca0 | |||
457f8335bb | |||
42565ff5d7 | |||
6e2bb518fd | |||
2180ab17d8 | |||
ac5d43882b | |||
3f0262dfe5 | |||
74787c9aa8 | |||
045009bb82 | |||
79c11e9ecd | |||
c73c797595 | |||
3330b96b10 | |||
1547aa8c03 | |||
1ca139109a | |||
55c1223a1e | |||
0643613eee | |||
55dc56462f | |||
698fb3ae00 | |||
23a537b19b | |||
aee016d6e4 | |||
f1ae14f263 | |||
65c0e0e195 | |||
f71f61ff0a | |||
652314e73d | |||
71a2388acb | |||
ebc36a3519 | |||
5097065a22 | |||
193ac643e4 | |||
945bd17701 | |||
9d45d505d5 | |||
96fcbc0694 | |||
6b4767cba0 | |||
f148c98b13 | |||
06103e4bb4 | |||
c6fc267e5f | |||
52b7f001a2 | |||
cf504ec900 | |||
ab2e08f96c | |||
511ed541b8 | |||
8d0e2aab6b | |||
a02bf05eed | |||
85a2e25093 | |||
a9b5e66d0f | |||
988b3f9905 | |||
53b59332dc | |||
bf84ae940a | |||
a89a0ab7a3 | |||
fe536e476c | |||
afafcb7c24 | |||
55b4775ca8 | |||
1c6c610f20 | |||
9b48b0a5e0 | |||
25ac2d98c6 | |||
ce175df376 | |||
9d9d0db1ee | |||
b704aaa33b | |||
7a21db23ad | |||
fcd6f0bb14 | |||
52d7458b99 | |||
56cb58ced7 | |||
77a7538a02 | |||
c8d0a13f0e | |||
582f5b5ff6 | |||
06dd536d52 | |||
e66b19c414 | |||
0ad6cad8b2 | |||
ffa13e4b90 | |||
0fc1fc6b23 | |||
f1d1d79daf | |||
36d0d32b35 | |||
3bf488eb86 | |||
061885ad23 | |||
ab70791625 | |||
62cb235aa9 | |||
04c711f757 | |||
467fec5c9b | |||
5193ebc6ea | |||
3498e86d8b | |||
07a347f907 | |||
d9c9681094 | |||
7310a7a0bc | |||
accf9244ca | |||
290197c210 | |||
b8d1e58778 | |||
cc4d33d871 | |||
ef0e48a678 | |||
187ef7676e | |||
a8714730fb | |||
d2f519f9e5 | |||
a045c1c885 | |||
543521a220 | |||
85be67e708 | |||
5b1b2cce75 | |||
1029078541 | |||
0015e5411c | |||
65b64e1fc1 | |||
d07237b2ce | |||
3c65fde2a7 | |||
35833d2730 | |||
bbb4b7e686 | |||
64e31dae48 | |||
63ce3a5d59 | |||
5dd138c883 | |||
088f7ac3f8 | |||
e079f8ba98 | |||
ff2b0734ea | |||
330332a0fb | |||
48c157bc46 | |||
98bf3efeb6 | |||
ae8479c77e | |||
444fae9066 | |||
bb4c002841 | |||
656ab21c9b | |||
2099434b3f | |||
8f00fc182a | |||
d74c296182 | |||
c4e85bd099 | |||
85ba60e405 | |||
89e1bd27b3 | |||
341fcb0f40 | |||
469f953b28 | |||
381eb314dc | |||
1ffc20c8e3 | |||
5c245dbdb5 | |||
134a9a9eee | |||
010f98ca80 | |||
6e4e4fab1d | |||
b6852a0588 | |||
415e04a55f | |||
3456781494 | |||
d1129f3d19 | |||
973837dd66 | |||
36de9afe0c | |||
0d5081b841 | |||
85c7282641 | |||
57afa38f49 | |||
238ee96783 | |||
10e6348e09 | |||
a286634359 | |||
4cdfc857ad | |||
371a32d4ae | |||
dc4e54e99a | |||
d66f9dc158 | |||
4980ac85b7 | |||
626eb52d04 | |||
82b1aa9280 | |||
e8145fcede | |||
9c3e24b6cf | |||
b4d85d6aae | |||
0b102f6286 | |||
06e7baf2c2 | |||
3662c149fb | |||
a243d7e878 | |||
ef1bae5cdd | |||
4cefcd3606 | |||
a177b3d024 | |||
b7e73d25a7 | |||
9b403d477f | |||
d723fb7a5a | |||
9905fe4cf6 | |||
055f051f53 | |||
8dc3e5835c | |||
0cf08fb676 | |||
ac7bf465d2 | |||
2cf7518114 | |||
057a5d2db8 | |||
63bff632df | |||
938ddf16b9 | |||
0c84c9750c | |||
952e5df477 | |||
e3c4391246 | |||
98138189c9 | |||
30dae8f7ed | |||
b76d3fbff9 | |||
f605fdd632 | |||
abbc8d9c5a | |||
a0297743dd | |||
3bcc46276a | |||
f0d0698582 | |||
91262baede | |||
cb2375827b | |||
cc0f2b3cf0 | |||
47d57a5b14 | |||
278b7bef3c | |||
a165452ca1 | |||
55f95fb790 | |||
9b76388163 | |||
0d1d73eb35 | |||
88d3eda156 | |||
622a360e97 | |||
4358c3ceab | |||
f00c3be139 | |||
c05558ba28 | |||
c0c1a65598 | |||
dab12309e2 | |||
789670e8c5 | |||
131613c5cc | |||
919091766d | |||
4e4ab0908d | |||
54e3a85983 | |||
98dfb691b6 | |||
ff7d214f9c | |||
ee6dbbfeaa | |||
a14331ad01 | |||
f3754a3683 | |||
c1176ccdcc | |||
df51e60ac0 | |||
9e83b1eb0e | |||
f82cbfde7b | |||
96d13293ab | |||
3b49d1f559 | |||
3e7591e92a | |||
de830e51d4 | |||
21c0878f0e | |||
a96c890f97 | |||
86d107635b | |||
57672d5add | |||
e8ea8786d2 | |||
142200c7ca | |||
6c47cfe30a | |||
0ae8c3ca33 | |||
5472d5c52f | |||
51a50db0fd | |||
e1660a1806 | |||
84f18bddfb | |||
609594a849 | |||
66e6d4cbf8 | |||
4868689111 | |||
f3ff98bb82 | |||
58a0b57e12 | |||
3fd4391c38 | |||
a16aab6979 | |||
1e0aefd72a | |||
ebf122bd36 | |||
5addf9e885 | |||
6dbfc69627 | |||
128c0a2d87 | |||
1f91d248f5 | |||
d56b5d90ea |
140
.flake8
Normal file
140
.flake8
Normal file
@ -0,0 +1,140 @@
|
||||
[flake8]
|
||||
|
||||
select =
|
||||
# Full lists are given in order to suppress all errors from other plugins
|
||||
# Full list of pyflakes error codes:
|
||||
F401, # module imported but unused
|
||||
F402, # import module from line N shadowed by loop variable
|
||||
F403, # 'from module import *' used; unable to detect undefined names
|
||||
F404, # future import(s) name after other statements
|
||||
F405, # name may be undefined, or defined from star imports: module
|
||||
F406, # 'from module import *' only allowed at module level
|
||||
F407, # an undefined __future__ feature name was imported
|
||||
F601, # dictionary key name repeated with different values
|
||||
F602, # dictionary key variable name repeated with different values
|
||||
F621, # too many expressions in an assignment with star-unpacking
|
||||
F622, # two or more starred expressions in an assignment (a, *b, *c = d)
|
||||
F631, # assertion test is a tuple, which are always True
|
||||
F701, # a break statement outside of a while or for loop
|
||||
F702, # a continue statement outside of a while or for loop
|
||||
F703, # a continue statement in a finally block in a loop
|
||||
F704, # a yield or yield from statement outside of a function
|
||||
F705, # a return statement with arguments inside a generator
|
||||
F706, # a return statement outside of a function/method
|
||||
F707, # an except: block as not the last exception handler
|
||||
F721, F722, # doctest syntax error syntax error in forward type annotation
|
||||
F811, # redefinition of unused name from line N
|
||||
F812, # list comprehension redefines name from line N
|
||||
F821, # undefined name name
|
||||
F822, # undefined name name in __all__
|
||||
F823, # local variable name referenced before assignment
|
||||
F831, # duplicate argument name in function definition
|
||||
F841, # local variable name is assigned to but never used
|
||||
F901, # raise NotImplemented should be raise NotImplementedError
|
||||
|
||||
# Full list of pycodestyle violations:
|
||||
E101, # indentation contains mixed spaces and tabs
|
||||
E111, # indentation is not a multiple of four
|
||||
E112, # expected an indented block
|
||||
E113, # unexpected indentation
|
||||
E114, # indentation is not a multiple of four (comment)
|
||||
E115, # expected an indented block (comment)
|
||||
E116, # unexpected indentation (comment)
|
||||
E121, # continuation line under-indented for hanging indent
|
||||
E122, # continuation line missing indentation or outdented
|
||||
E123, # closing bracket does not match indentation of opening bracket's line
|
||||
E124, # closing bracket does not match visual indentation
|
||||
E125, # continuation line with same indent as next logical line
|
||||
E126, # continuation line over-indented for hanging indent
|
||||
E127, # continuation line over-indented for visual indent
|
||||
E128, # continuation line under-indented for visual indent
|
||||
E129, # visually indented line with same indent as next logical line
|
||||
E131, # continuation line unaligned for hanging indent
|
||||
E133, # closing bracket is missing indentation
|
||||
E201, # whitespace after '('
|
||||
E202, # whitespace before ')'
|
||||
E203, # whitespace before ':'
|
||||
E211, # whitespace before '('
|
||||
E221, # multiple spaces before operator
|
||||
E222, # multiple spaces after operator
|
||||
E223, # tab before operator
|
||||
E224, # tab after operator
|
||||
E225, # missing whitespace around operator
|
||||
E226, # missing whitespace around arithmetic operator
|
||||
E227, # missing whitespace around bitwise or shift operator
|
||||
E228, # missing whitespace around modulo operator
|
||||
E231, # missing whitespace after ',', ';', or ':'
|
||||
E241, # multiple spaces after ','
|
||||
E242, # tab after ','
|
||||
E251, # unexpected spaces around keyword / parameter equals
|
||||
E261, # at least two spaces before inline comment
|
||||
E262, # inline comment should start with '# '
|
||||
E265, # block comment should start with '# '
|
||||
E266, # too many leading '#' for block comment
|
||||
E271, # multiple spaces after keyword
|
||||
E272, # multiple spaces before keyword
|
||||
E273, # tab after keyword
|
||||
E274, # tab before keyword
|
||||
E275, # missing whitespace after keyword
|
||||
E301, # expected 1 blank line, found 0
|
||||
E302, # expected 2 blank lines, found 0
|
||||
E303, # too many blank lines
|
||||
E304, # blank lines found after function decorator
|
||||
E305, # expected 2 blank lines after end of function or class
|
||||
E306, # expected 1 blank line before a nested definition
|
||||
E401, # multiple imports on one line
|
||||
E402, # module level import not at top of file
|
||||
E501, # line too long (82 > 79 characters)
|
||||
E502, # the backslash is redundant between brackets
|
||||
E701, # multiple statements on one line (colon)
|
||||
E702, # multiple statements on one line (semicolon)
|
||||
E703, # statement ends with a semicolon
|
||||
E704, # multiple statements on one line (def)
|
||||
E711, # comparison to None should be 'if cond is None:'
|
||||
E712, # comparison to True should be 'if cond is True:' or 'if cond:'
|
||||
E713, # test for membership should be 'not in'
|
||||
E714, # test for object identity should be 'is not'
|
||||
E721, # do not compare types, use 'isinstance()'
|
||||
E722, # do not use bare except, specify exception instead
|
||||
E731, # do not assign a lambda expression, use a def
|
||||
E741, # do not use variables named 'l', 'O', or 'I'
|
||||
E742, # do not define classes named 'l', 'O', or 'I'
|
||||
E743, # do not define functions named 'l', 'O', or 'I'
|
||||
E901, # SyntaxError or IndentationError
|
||||
E902, # IOError
|
||||
W191, # indentation contains tabs
|
||||
W291, # trailing whitespace
|
||||
W292, # no newline at end of file
|
||||
W293, # blank line contains whitespace
|
||||
W391, # blank line at end of file
|
||||
W503, # line break before binary operator
|
||||
W504, # line break after binary operator
|
||||
W505, # doc line too long (82 > 79 characters)
|
||||
W601, # .has_key() is deprecated, use 'in'
|
||||
W602, # deprecated form of raising exception
|
||||
W603, # '<>' is deprecated, use '!='
|
||||
W604, # backticks are deprecated, use 'repr()'
|
||||
W605, # invalid escape sequence 'x'
|
||||
W606, # 'async' and 'await' are reserved keywords starting with Python 3.7
|
||||
|
||||
# Full list of flake8 violations
|
||||
E999, # failed to compile a file into an Abstract Syntax Tree for the plugins that require it
|
||||
|
||||
# Full list of mccabe violations
|
||||
C901 # complexity value provided by the user
|
||||
|
||||
ignore =
|
||||
E221, # multiple spaces before operator
|
||||
E231, # missing whitespace after ',', ';', or ':'
|
||||
E241, # multiple spaces after ','
|
||||
W503, # line break before binary operator
|
||||
W504 # line break after binary operator
|
||||
|
||||
max-line-length = 160
|
||||
|
||||
show_source = True
|
||||
|
||||
statistics = True
|
||||
|
||||
exclude =
|
||||
components/asio/docs/conf_common.py
|
2
.git-blame-ignore-revs
Normal file
2
.git-blame-ignore-revs
Normal file
@ -0,0 +1,2 @@
|
||||
# Formating according pre-commit hooks
|
||||
945bd177011d984b705daee9b895f88212292a42
|
51
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
51
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
name: Installation or build bug report
|
||||
description: Report installation or build bugs
|
||||
labels: ['Type: Bug']
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Answers checklist.
|
||||
description: Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
options:
|
||||
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) and the issue is not addressed there.
|
||||
required: true
|
||||
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
|
||||
required: true
|
||||
- label: I have searched the issue tracker for a similar issue and not found a similar issue.
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: component
|
||||
attributes:
|
||||
label: What component are you using? If you choose Other, provide details in More Information.
|
||||
multiple: false
|
||||
options:
|
||||
- ASIO port
|
||||
- esp_modem
|
||||
- esp_websocket_client
|
||||
- mDNS
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: component_id
|
||||
attributes:
|
||||
label: component version
|
||||
description: Which component version does this issue occur on? (see your `idf_component.yml`)
|
||||
placeholder: ex. 1.0.0
|
||||
- type: input
|
||||
id: idf_version
|
||||
attributes:
|
||||
label: IDF version.
|
||||
description: On which IDF version does this issue occur on? Run `git describe --tags` to find it.
|
||||
placeholder: ex. v3.2-dev-1148-g96cd3b75c
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: more-info
|
||||
attributes:
|
||||
label: More Information.
|
||||
description: Do you have any other information from investigating this?
|
||||
placeholder: ex. I tried on my friend's Windows 10 PC and the command works there.
|
||||
validations:
|
||||
required: false
|
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: esp-protocols documentation
|
||||
url: https://espressif.github.io/esp-protocols/
|
||||
about: Documenation for esp-protocols components.
|
||||
- name: ESP-IDF Programming Guide
|
||||
url: https://docs.espressif.com/projects/esp-idf/en/latest/
|
||||
about: Documentation for configuring and using ESP-IDF.
|
||||
- name: Espressif documentation page
|
||||
url: https://www.espressif.com/en/support/download/documents
|
||||
about: Hardware documentation (datasheets, Technical Reference Manual, etc).
|
||||
- name: Forum
|
||||
url: https://esp32.com
|
||||
about: For questions about using ESP-IDF and/or ESP32 series chips. Please submit all questions starting "How do I..." here.
|
33
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
33
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea or new component for this project.
|
||||
labels: ['Type: Feature Request']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
* We welcome any ideas or feature requests! It’s helpful if you can explain exactly why the feature would be useful.
|
||||
* There are usually some outstanding feature requests in the [existing issues list](https://github.com/espressif/esp-protocols/labels/Type%3A%20Feature%20Request), feel free to add comments to them.
|
||||
- type: textarea
|
||||
id: problem-related
|
||||
attributes:
|
||||
label: Is your feature request related to a problem?
|
||||
description: Please provide a clear and concise description of what the problem is.
|
||||
placeholder: ex. I'm always frustrated when ...
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like.
|
||||
description: Please provide a clear and concise description of what you want to happen.
|
||||
placeholder: ex. When building my application ...
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Describe alternatives you've considered.
|
||||
description: Please provide a clear and concise description of any alternative solutions or features you've considered.
|
||||
placeholder: ex. Choosing other approach wouldn't work, because ...
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context.
|
||||
description: Please add any other context or screenshots about the feature request here.
|
||||
placeholder: ex. This would work only when ...
|
23
.github/ISSUE_TEMPLATE/other-issue.yml
vendored
Normal file
23
.github/ISSUE_TEMPLATE/other-issue.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: General issue report
|
||||
description: File an issue report
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Answers checklist.
|
||||
description: Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
options:
|
||||
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) and the issue is not addressed there.
|
||||
required: true
|
||||
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
|
||||
required: true
|
||||
- label: I have searched the issue tracker for a similar issue and not found a similar issue.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: issue
|
||||
attributes:
|
||||
label: General issue report
|
||||
description: Your issue report goes here.
|
||||
placeholder: ex. How do I...
|
||||
validations:
|
||||
required: true
|
36
.github/workflows/build.yml
vendored
36
.github/workflows/build.yml
vendored
@ -1,36 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4"]
|
||||
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
|
||||
idf_target: ["esp32"]
|
||||
exclude:
|
||||
- idf_ver: "release-v4.1"
|
||||
example: modem_console
|
||||
- idf_ver: "release-v4.1"
|
||||
example: ap_to_pppos
|
||||
- idf_ver: "release-v4.1"
|
||||
example: simple_cmux_client
|
||||
- idf_ver: "release-v4.2"
|
||||
example: simple_cmux_client
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
|
||||
idf.py build
|
76
.github/workflows/build_and_run_example_test.yml
vendored
76
.github/workflows/build_and_run_example_test.yml
vendored
@ -1,76 +0,0 @@
|
||||
name: Build Websockets
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v1
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: components/esp_websocket_client/examples/
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cat sdkconfig.ci >> sdkconfig.defaults
|
||||
idf.py build
|
||||
- name: Merge binaries
|
||||
working-directory: components/esp_websocket_client/examples/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/esp_websocket_client/examples/build/
|
||||
if-no-files-found: error
|
||||
|
||||
run-target:
|
||||
name: Run Example Test on target
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
container:
|
||||
image: python:3.7-buster
|
||||
options: --privileged # Privileged mode has access to serial ports
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/esp_websocket_client/examples/build/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install -r $GITHUB_WORKSPACE/components/esp_websocket_client/examples/requirements.txt
|
||||
- name: Download Example Test to target
|
||||
run: python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/esp_websocket_client/examples/build/flash_image.bin
|
||||
- name: Run Example Test on target
|
||||
working-directory: components/esp_websocket_client/examples
|
||||
run: |
|
||||
cp sdkconfig.ci sdkconfig.defaults
|
||||
pytest --log-cli-level DEBUG --junit-xml=./test_app_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: examples/*.xml
|
@ -1,35 +0,0 @@
|
||||
name: Build mDNS
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32c3"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/examples/
|
||||
cat sdkconfig.ci.eth_def >> sdkconfig.defaults
|
||||
idf.py build
|
||||
rm sdkconfig.defaults
|
||||
cat sdkconfig.ci.eth_custom_netif >> sdkconfig.defaults
|
||||
idf.py build
|
||||
rm sdkconfig.defaults
|
||||
cat sdkconfig.ci.eth_socket >> sdkconfig.defaults
|
||||
idf.py build
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_apps/
|
||||
idf.py build
|
92
.github/workflows/gcov_analyzer.yml
vendored
Normal file
92
.github/workflows/gcov_analyzer.yml
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
name: Code Coverage Analyzer
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
gcovr_analyzer_esp_modem:
|
||||
name: Run gcovr on esp modem host test
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
lwip: lwip-2.1.2
|
||||
lwip_contrib: contrib-2.1.0
|
||||
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
|
||||
COMP_DIR: esp-protocols/components/esp_modem
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: esp-protocols
|
||||
persist-credentials: false
|
||||
- name: Build and Test
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get update && apt-get install -y gcc-8 g++-8 python3-pip
|
||||
apt-get install -y rsync
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export LWIP_PATH=`pwd`/${{ env.lwip }}
|
||||
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
|
||||
. ${IDF_PATH}/export.sh
|
||||
${{ env.COMP_DIR }}/test/host_test/env.sh $lwip $lwip_uri $lwip_contrib
|
||||
cd $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/test/host_test
|
||||
cat sdkconfig.ci.coverage >> sdkconfig.defaults
|
||||
idf.py build
|
||||
./build/host_modem_test.elf
|
||||
- name: Run gcovr
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install gcovr
|
||||
cd $GITHUB_WORKSPACE/${{ env.COMP_DIR }}
|
||||
gcov-8 `find . -name "esp_modem*gcda" -printf '%h\n' | head -n 1`/*
|
||||
gcovr --gcov-ignore-parse-errors -g -k -r . --html index.html -x esp_modem_coverage.xml
|
||||
mkdir docs_gcovr
|
||||
cp $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/index.html docs_gcovr
|
||||
touch docs_gcovr/.nojekyll
|
||||
|
||||
- name: Code Coverage Summary Report
|
||||
uses: irongut/CodeCoverageSummary@v1.3.0
|
||||
with:
|
||||
filename: esp-protocols/**/esp_modem_coverage.xml
|
||||
badge: true
|
||||
fail_below_min: false
|
||||
format: markdown
|
||||
hide_branch_rate: false
|
||||
hide_complexity: false
|
||||
indicators: true
|
||||
output: both
|
||||
thresholds: '60 80'
|
||||
|
||||
- name: Write to Job Summary
|
||||
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: docs_gcovr
|
||||
path: |
|
||||
${{ env.COMP_DIR }}/docs_gcovr
|
||||
if-no-files-found: error
|
||||
|
||||
# show_report_data:
|
||||
# name: Publish-Results
|
||||
# if: github.ref == 'refs/heads/master' || github.repository != 'espressif/esp-protocols'
|
||||
# runs-on: ubuntu-22.04
|
||||
# needs: gcovr_analyzer_esp_modem
|
||||
# steps:
|
||||
# - name: Checkout 🛎️
|
||||
# uses: actions/checkout@v3
|
||||
# with:
|
||||
# persist-credentials: false
|
||||
# - name: Download Artifacts
|
||||
# uses: actions/download-artifact@v1
|
||||
# with:
|
||||
# name: docs_gcovr
|
||||
#
|
||||
# - name: Deploy generated docs
|
||||
# uses: JamesIves/github-pages-deploy-action@v4
|
||||
# with:
|
||||
# branch: gh-pages
|
||||
# folder: 'docs_gcovr'
|
35
.github/workflows/host-test.yml
vendored
35
.github/workflows/host-test.yml
vendored
@ -3,16 +3,15 @@ name: Host test
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
host_test:
|
||||
name: Build and test
|
||||
host_test_esp_modem:
|
||||
name: esp-modem Build and Test on Host
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
lwip: lwip-2.1.2
|
||||
lwip_contrib: contrib-2.1.0
|
||||
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
|
||||
|
||||
|
||||
COMP_DIR: esp-protocols/components/esp_modem
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
@ -26,11 +25,8 @@ jobs:
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
|
||||
export LWIP_PATH=`pwd`/${{ env.lwip }}
|
||||
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
|
||||
wget --no-verbose ${lwip_uri}/${lwip}.zip
|
||||
unzip -oq ${lwip}.zip
|
||||
wget --no-verbose ${lwip_uri}/${lwip_contrib}.zip
|
||||
unzip -oq ${lwip_contrib}.zip
|
||||
. ${IDF_PATH}/export.sh
|
||||
$GITHUB_WORKSPACE/${{ env.COMP_DIR }}/test/host_test/env.sh $lwip $lwip_uri $lwip_contrib
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/linux_modem
|
||||
idf.py build
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/test/host_test
|
||||
@ -42,3 +38,26 @@ jobs:
|
||||
if: always()
|
||||
with:
|
||||
files: esp-protocols/components/esp_modem/test/host_test/junit.xml
|
||||
|
||||
host_test_mdns:
|
||||
name: mdns Build and Test on Host
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:latest
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
|
||||
- name: Build and Test
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update && apt-get install -y dnsutils gcc g++
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/host_test
|
||||
idf.py build
|
||||
./build/mdns_host.elf &
|
||||
dig +short -p 5353 @224.0.0.251 myesp.local > ip.txt
|
||||
cat ip.txt | xargs dig +short -p 5353 @224.0.0.251 -x
|
||||
cat ip.txt
|
||||
|
40
.github/workflows/pre_commit_check.yml
vendored
Normal file
40
.github/workflows/pre_commit_check.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
name: Check pre-commit rules
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
pre_commit_check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch head and base refs
|
||||
# This is necessary for pre-commit to check the changes in the PR branch
|
||||
run: |
|
||||
git fetch origin ${{ github.base_ref }}:base_ref
|
||||
git fetch origin pull/${{ github.event.pull_request.number }}/head:pr_ref
|
||||
- name: Set up Python environment
|
||||
uses: actions/setup-python@master
|
||||
with:
|
||||
python-version: v3.7
|
||||
- name: Install python packages
|
||||
run: |
|
||||
pip install pre-commit
|
||||
pre-commit install-hooks
|
||||
- name: Run pre-commit and check for any changes
|
||||
run: |
|
||||
echo "Commits being checked:"
|
||||
git log --oneline --no-decorate base_ref..pr_ref
|
||||
echo ""
|
||||
if ! pre-commit run --from-ref base_ref --to-ref pr_ref --show-diff-on-failure ; then
|
||||
echo ""
|
||||
echo "::notice::It looks like the commits in this PR have been made without having pre-commit hooks installed."
|
||||
echo "::notice::Please see https://github.com/espressif/esp-protocols/CONTRIBUTING.md for instructions."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
11
.github/workflows/publish-docs-component.yml
vendored
11
.github/workflows/publish-docs-component.yml
vendored
@ -9,6 +9,8 @@ jobs:
|
||||
docs_build:
|
||||
name: Docs-Build-And-Upload
|
||||
runs-on: ubuntu-latest
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
@ -16,6 +18,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: Generate docs
|
||||
run: |
|
||||
@ -39,10 +42,16 @@ jobs:
|
||||
cp -r html_en/. $GITHUB_WORKSPACE/docs/mdns/en
|
||||
cp -r html_zh_CN/. $GITHUB_WORKSPACE/docs/mdns/zh_CN
|
||||
|
||||
cd $GITHUB_WORKSPACE/components/asio/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/asio
|
||||
cp -r html/. $GITHUB_WORKSPACE/docs/asio
|
||||
|
||||
cd $GITHUB_WORKSPACE/docs
|
||||
touch .nojekyll
|
||||
echo '<a href="esp_modem/index.html">esp-modem</a><br>' > index.html
|
||||
echo '<a href="esp_websocket_client/index.html">esp-websocket-client</a><br>' >> index.html
|
||||
echo '<a href="asio/index.html">ASIO</a><br>' >> index.html
|
||||
echo '<a href="mdns/en/index.html">mDNS_en</a><br>' >> index.html
|
||||
echo '<a href="mdns/zh_CN/index.html">mDNS_zh_CN</a><br>' >> index.html
|
||||
|
||||
@ -50,7 +59,7 @@ jobs:
|
||||
- name: Upload components to component service
|
||||
uses: espressif/github-actions/upload_components@master
|
||||
with:
|
||||
directories: "components/esp_modem;components/esp_websocket_client;components/mdns"
|
||||
directories: "components/esp_modem;components/esp_websocket_client;components/mdns;components/asio"
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
||||
|
383
.github/workflows/target-test.yml
vendored
Normal file
383
.github/workflows/target-test.yml
vendored
Normal file
@ -0,0 +1,383 @@
|
||||
name: Build and Run Target tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build_esp_modem:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4", "release-v5.0"]
|
||||
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
|
||||
idf_target: ["esp32"]
|
||||
exclude:
|
||||
- idf_ver: "release-v4.1"
|
||||
example: modem_console
|
||||
- idf_ver: "release-v4.1"
|
||||
example: ap_to_pppos
|
||||
- idf_ver: "release-v4.1"
|
||||
example: simple_cmux_client
|
||||
- idf_ver: "release-v4.2"
|
||||
example: simple_cmux_client
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
|
||||
idf.py build
|
||||
|
||||
build_esp_modem_usb:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.4", "release-v5.0"]
|
||||
example: ["modem_console", "pppos_client"]
|
||||
idf_target: ["esp32s2", "esp32s3"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
working-directory: components/esp_modem/examples/${{ matrix.example }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cat sdkconfig.ci.usb >> sdkconfig.defaults
|
||||
idf.py build
|
||||
|
||||
build_mdns:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32c3"]
|
||||
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{ matrix.test.path }}
|
||||
run: |
|
||||
${IDF_PATH}/install.sh --enable-pytest
|
||||
. ${IDF_PATH}/export.sh
|
||||
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
|
||||
for dir in `ls -d build_*`; do
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: ${{ matrix.idf_target }} == "esp32"
|
||||
with:
|
||||
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ matrix.test.path }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
build_asio:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2"]
|
||||
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/asio/examples
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
test -f sdkconfig.ci && cat sdkconfig.ci >> sdkconfig.defaults || echo "No sdkconfig.ci"
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.example }}
|
||||
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: |
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/bootloader/bootloader.bin
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build//partition_table/partition-table.bin
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/*.bin
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/*.elf
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/flasher_args.json
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/config/sdkconfig.h
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/config/sdkconfig.json
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
build_websocket:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "latest"]
|
||||
idf_target: ["esp32"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/examples
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cat sdkconfig.ci >> sdkconfig.defaults
|
||||
idf.py build
|
||||
- name: Merge binaries
|
||||
working-directory: ${{ env.TEST_DIR }}/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: |
|
||||
${{ env.TEST_DIR }}/build/bootloader/bootloader.bin
|
||||
${{ env.TEST_DIR }}/build/partition_table/partition-table.bin
|
||||
${{ env.TEST_DIR }}/build/*.bin
|
||||
${{ env.TEST_DIR }}/build/*.elf
|
||||
${{ env.TEST_DIR }}/build/flasher_args.json
|
||||
${{ env.TEST_DIR }}/build/config/sdkconfig.h
|
||||
${{ env.TEST_DIR }}/build/config/sdkconfig.json
|
||||
if-no-files-found: error
|
||||
|
||||
build_esp_mqtt_cxx:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "components/esp_mqtt_cxx/examples" }]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{matrix.test.path}}
|
||||
run: |
|
||||
${IDF_PATH}/install.sh --enable-pytest
|
||||
. ${IDF_PATH}/export.sh
|
||||
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
|
||||
|
||||
run-target-websocket:
|
||||
name: Run Websocket Example Test on target
|
||||
needs: build_websocket
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "latest"]
|
||||
idf_target: ["esp32"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/examples
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/build/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Download Example Test to target
|
||||
run: python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/esp_websocket_client/examples/build/flash_image.bin
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/*.xml
|
||||
|
||||
run-target-mdns:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
|
||||
name: Run mDNS target tests
|
||||
needs: build_mdns
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ matrix.test.path }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Run ${{ matrix.test.app }} application on ${{ matrix.idf_target }}
|
||||
working-directory: ${{ matrix.test.path }}
|
||||
run: |
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: ${{ matrix.test.path }}/*.xml
|
||||
|
||||
run-target-asio:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
|
||||
name: Run ASIO Example Test on target
|
||||
needs: build_asio
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/asio/examples
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: ${{ env.TEST_DIR }}/${{ matrix.example }}/build
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Download Example Test to target ${{ matrix.config }}
|
||||
run: |
|
||||
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 ${{ env.TEST_DIR }}/${{ matrix.example }}/build/flash_image.bin
|
||||
- name: Run Example Test ${{ matrix.example }} on target
|
||||
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: ${{ env.TEST_DIR }}/${{ matrix.example }}/*.xml
|
||||
|
||||
build_esp_modem_tests:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32c3"]
|
||||
test: [ { app: pppd, path: test/target }, { app: sim800, path: examples/pppos_client } ]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build esp-modem target tests with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
SDKCONFIG: sdkconfig.ci.${{ matrix.test.app }}
|
||||
shell: bash
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
rm -rf sdkconfig build
|
||||
[ -f ${SDKCONFIG} ] && cp ${SDKCONFIG} sdkconfig.defaults
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
if-no-files-found: error
|
||||
|
||||
run_esp_modem_tests:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32c3"]
|
||||
test: [ { app: pppd, path: test/target }, { app: sim800, path: examples/pppos_client } ]
|
||||
name: Run esp_modem Test on target
|
||||
needs: build_esp_modem_tests
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- BrnoRPI-GH006
|
||||
env:
|
||||
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --target=${{ matrix.idf_target }}
|
94
.github/workflows/test_apps.yml
vendored
Normal file
94
.github/workflows/test_apps.yml
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
name: Build and Run Test apps
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'components/mdns/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'components/mdns/**'
|
||||
|
||||
jobs:
|
||||
build_mdns_app:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32c3"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Setup Build Environment
|
||||
working-directory: components/mdns/tests/test_apps
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: components/mdns/tests/test_apps
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --pytest-apps
|
||||
- name: Merge binaries with IDF-${{ matrix.idf_ver }}
|
||||
working-directory: components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: |
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/bootloader/bootloader.bin
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/partition_table/partition-table.bin
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/*.bin
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/*.elf
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/flasher_args.json
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/config/sdkconfig.h
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/config/sdkconfig.json
|
||||
if-no-files-found: error
|
||||
|
||||
run-target-mdns-app:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
name: Run mDNS Test apps on target
|
||||
needs: build_mdns_app
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/mdns/tests/test_apps/build
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Download Test apps to target
|
||||
run: |
|
||||
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/mdns/tests/test_apps/build/flash_image.bin
|
||||
- name: Run Example Test on target
|
||||
working-directory: components/mdns/tests/test_apps
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{matrix.idf_target}}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: test_apps_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/mdns/tests/test_apps/*.xml
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "components/asio/asio"]
|
||||
path = components/asio/asio
|
||||
url = https://github.com/espressif/asio
|
26
.mypy.ini
Normal file
26
.mypy.ini
Normal file
@ -0,0 +1,26 @@
|
||||
[mypy]
|
||||
|
||||
# Specifies the Python version used to parse and check the target program
|
||||
python_version = 3.9
|
||||
|
||||
# Disallows defining functions without type annotations or with incomplete type annotations
|
||||
# True => enforce type annotation in all function definitions
|
||||
disallow_untyped_defs = True
|
||||
|
||||
# Shows a warning when returning a value with type Any from a function declared with a non- Any return type
|
||||
warn_return_any = True
|
||||
|
||||
# Shows errors for missing return statements on some execution paths
|
||||
warn_no_return = True
|
||||
|
||||
# Suppress error messages about imports that cannot be resolved
|
||||
# True => ignore all import errors
|
||||
ignore_missing_imports = True
|
||||
|
||||
# Disallows defining functions with incomplete type annotations
|
||||
disallow_incomplete_defs = False
|
||||
|
||||
# Directs what to do with imports when the imported module is found as a .py file and not part of the files,
|
||||
# modules and packages provided on the command line.
|
||||
# SKIP -> mypy checks only single file, not included imports
|
||||
follow_imports = skip
|
52
.pre-commit-config.yaml
Normal file
52
.pre-commit-config.yaml
Normal file
@ -0,0 +1,52 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.3.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- id: fix-byte-order-marker
|
||||
- id: check-case-conflict
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- id: mixed-line-ending
|
||||
- id: debug-statements
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 5.0.4
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.981
|
||||
hooks:
|
||||
- id: mypy
|
||||
exclude: >
|
||||
(?x)^(
|
||||
.*.py
|
||||
)$
|
||||
- repo: https://github.com/myint/unify
|
||||
rev: v0.5
|
||||
hooks:
|
||||
- id: unify
|
||||
- repo: https://github.com/pre-commit/mirrors-yapf
|
||||
rev: "v0.32.0"
|
||||
hooks:
|
||||
- id: yapf
|
||||
- repo: https://github.com/pre-commit/mirrors-isort
|
||||
rev: v5.10.1
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/myint/eradicate/
|
||||
rev: v2.1.0
|
||||
hooks:
|
||||
- id: eradicate
|
||||
- repo: https://github.com/espressif/check-copyright/
|
||||
rev: v1.0.1
|
||||
hooks:
|
||||
- id: check-copyright
|
||||
args: ['--ignore', 'ci/check_copyright_ignore.txt', '--config', 'ci/check_copyright_config.yaml']
|
||||
- repo: https://github.com/igrr/astyle_py.git
|
||||
rev: c0013808882a15a0c0c2c1a9b5c903866c53a653
|
||||
hooks:
|
||||
- id: astyle_py
|
||||
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper']
|
13
CONTRIBUTING.md
Normal file
13
CONTRIBUTING.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Information for Contributors
|
||||
|
||||
Contributions in the form of pull requests, issue reports, and feature requests are welcome!
|
||||
|
||||
## Submitting a PR
|
||||
|
||||
- [ ] Fork the [esp-protocols repository on GitHub](https://github.com/espressif/esp-protocols) to start making your changes.
|
||||
|
||||
- [ ] Install pre-commit hooks: `pip install pre-commit && pre-commit install`
|
||||
|
||||
- [ ] Send a pull request (PR) and work with us until it gets merged and published. Contributions may need some modifications, so a few rounds of review and fixing may be necessary.
|
||||
|
||||
For quick merging, the contribution should be short, and concentrated on a single feature or topic. The larger the contribution is, the longer it would take to review it and merge it.
|
@ -19,3 +19,8 @@
|
||||
|
||||
* Brief introduction [README](components/esp_websocket_client/README.md)
|
||||
* Full html [documentation](https://espressif.github.io/esp-protocols/esp_websocket_client/index.html)
|
||||
|
||||
### ASIO port
|
||||
|
||||
* Brief introduction [README](components/asio/README.md)
|
||||
* Full html [documentation](https://espressif.github.io/esp-protocols/asio/index.html)
|
||||
|
64
ci/check_copyright_config.yaml
Normal file
64
ci/check_copyright_config.yaml
Normal file
@ -0,0 +1,64 @@
|
||||
# don't modify this section!
|
||||
DEFAULT:
|
||||
perform_check: yes # should the check be performed?
|
||||
# Sections setting this to 'no' don't need to include any other options as they are ignored
|
||||
# When a file is using a section with the option set to 'no', no checks are performed.
|
||||
|
||||
# what licenses (or license expressions) are allowed for files in this section
|
||||
# when setting this option in a section, you need to list all the allowed licenses
|
||||
allowed_licenses:
|
||||
- Apache-2.0
|
||||
license_for_new_files: Apache-2.0 # license to be used when inserting a new copyright notice
|
||||
new_notice_c: | # notice for new C, CPP, H, HPP and LD files
|
||||
/*
|
||||
* SPDX-FileCopyrightText: {years} Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: {license}
|
||||
*/
|
||||
new_notice_python: | # notice for new python files
|
||||
# SPDX-FileCopyrightText: {years} Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: {license}
|
||||
|
||||
# comment lines matching:
|
||||
# SPDX-FileCopyrightText: year[-year] Espressif Systems
|
||||
# or
|
||||
# SPDX-FileContributor: year[-year] Espressif Systems
|
||||
# are replaced with this template prefixed with the correct comment notation (# or // or *) and SPDX- notation
|
||||
espressif_copyright: '{years} Espressif Systems (Shanghai) CO LTD'
|
||||
|
||||
# this section sets the default license for examples and unit tests of components
|
||||
examples_and_unit_tests:
|
||||
include:
|
||||
- 'components/**/examples/**'
|
||||
- 'components/**/test/**'
|
||||
- 'components/**/tests/**'
|
||||
- 'common_components/**'
|
||||
allowed_licenses:
|
||||
- Apache-2.0
|
||||
- Unlicense
|
||||
- CC0-1.0
|
||||
license_for_new_files: Unlicense OR CC0-1.0
|
||||
|
||||
asio_component:
|
||||
include:
|
||||
- 'components/asio/port/**'
|
||||
allowed_licenses:
|
||||
- Apache-2.0
|
||||
- BSL-1.0
|
||||
|
||||
slim_modem_examples:
|
||||
include:
|
||||
- 'examples/esp_netif/slip_custom_netif/**'
|
||||
allowed_licenses:
|
||||
- Apache-2.0
|
||||
- Unlicense
|
||||
- CC0-1.0
|
||||
|
||||
ignore:
|
||||
perform_check: no
|
||||
include:
|
||||
- 'components/**/docs/**'
|
||||
- 'components/esp_modem/port/linux/**'
|
||||
- 'components/asio/examples/**'
|
||||
- 'components/mdns/**/esp_system_protocols_linux/**'
|
||||
- 'common_components/protocol_examples_common/**'
|
0
ci/check_copyright_ignore.txt
Normal file
0
ci/check_copyright_ignore.txt
Normal file
7
ci/clean_build_artifacts.sh
Executable file
7
ci/clean_build_artifacts.sh
Executable file
@ -0,0 +1,7 @@
|
||||
# Remove everything, but
|
||||
# - elf/bin files in the build dir
|
||||
# - partition-table and bootloader binaries
|
||||
# - flasher args
|
||||
# - sdkconfigs (header and json)
|
||||
# (Ignoring the command failure as it refuses to delete nonempty dirs)
|
||||
find $1 ! -regex ".*/build[^/]*/[^/]+.\(bin\|elf\)" -a ! -regex ".*\(bootloader\|partition-table\).bin" -a ! -name "flasher_args.json" -a ! -regex ".*/build[^/]*/config/sdkconfig.\(h\|json\)" -delete || true
|
8
ci/requirements.txt
Normal file
8
ci/requirements.txt
Normal file
@ -0,0 +1,8 @@
|
||||
pytest-embedded-serial-esp
|
||||
pytest-embedded-idf
|
||||
junit_xml
|
||||
SimpleWebSocketServer
|
||||
dpkt
|
||||
pytest
|
||||
idf_build_apps
|
||||
netifaces
|
@ -1,4 +1,4 @@
|
||||
idf_component_register(SRCS "connect.c" "stdin_out.c" "addr_from_stdin.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES esp_netif driver
|
||||
PRIV_REQUIRES esp_netif driver esp_eth esp_wifi vfs
|
||||
)
|
||||
|
@ -26,7 +26,7 @@ esp_err_t get_addr_from_stdin(int port, int sock_type, int *ip_protocol, int *ad
|
||||
do {
|
||||
fgets(host_ip, HOST_IP_SIZE, stdin);
|
||||
len = strlen(host_ip);
|
||||
} while (len<=1 && host_ip[0] == '\n');
|
||||
} while (len <= 1 && host_ip[0] == '\n');
|
||||
host_ip[len - 1] = '\0';
|
||||
|
||||
struct addrinfo hints, *addr_list, *cur;
|
||||
@ -36,16 +36,16 @@ esp_err_t get_addr_from_stdin(int port, int sock_type, int *ip_protocol, int *ad
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = sock_type;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
if( getaddrinfo( host_ip, NULL, &hints, &addr_list ) != 0 ) {
|
||||
if ( getaddrinfo( host_ip, NULL, &hints, &addr_list ) != 0 ) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
for( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
|
||||
for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
|
||||
memcpy(dest_addr, cur->ai_addr, sizeof(*dest_addr));
|
||||
if (cur->ai_family == AF_INET) {
|
||||
*ip_protocol = IPPROTO_IP;
|
||||
*addr_family = AF_INET;
|
||||
// add port number and return on first IPv4 match
|
||||
((struct sockaddr_in*)dest_addr)->sin_port = htons(port);
|
||||
((struct sockaddr_in *)dest_addr)->sin_port = htons(port);
|
||||
freeaddrinfo( addr_list );
|
||||
return ESP_OK;
|
||||
|
||||
@ -55,8 +55,8 @@ esp_err_t get_addr_from_stdin(int port, int sock_type, int *ip_protocol, int *ad
|
||||
*ip_protocol = IPPROTO_IPV6;
|
||||
*addr_family = AF_INET6;
|
||||
// add port and interface number and return on first IPv6 match
|
||||
((struct sockaddr_in6*)dest_addr)->sin6_port = htons(port);
|
||||
((struct sockaddr_in6*)dest_addr)->sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
|
||||
((struct sockaddr_in6 *)dest_addr)->sin6_port = htons(port);
|
||||
((struct sockaddr_in6 *)dest_addr)->sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
|
||||
freeaddrinfo( addr_list );
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
/*
|
||||
* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@ -396,7 +397,9 @@ static esp_netif_t *eth_start(void)
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
gpio_install_isr_service(0);
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
#endif
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
|
||||
@ -414,9 +417,14 @@ static esp_netif_t *eth_start(void)
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver */
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
#else
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg);
|
||||
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
s_phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
@ -429,9 +437,13 @@ static esp_netif_t *eth_start(void)
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* w5500 ethernet driver is based on spi driver */
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
#else
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg);
|
||||
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
s_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
s_phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
|
@ -1,13 +1,14 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
/* Common utilities for socket address input interface:
|
||||
The API get_addr_from_stdin() is mainly used by socket client examples which read IP address from stdin (if configured).
|
||||
This option is typically used in the CI, but could be enabled in the project configuration.
|
||||
In that case this component is used to receive a string that is evaluated and processed to output
|
||||
socket structures to open a connectio
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
/*
|
||||
* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -15,6 +16,7 @@ extern "C" {
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_eth.h"
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
#define EXAMPLE_INTERFACE get_example_netif()
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* Common functions for protocol examples, to configure stdin and stdout.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
/*
|
||||
* Common functions for protocol examples, to configure stdin and stdout.
|
||||
*/
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
@ -19,7 +20,7 @@ esp_err_t example_configure_stdin_stdout(void)
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
/* Install UART driver for interrupt-driven reads and writes */
|
||||
ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_ESP_CONSOLE_UART_NUM,
|
||||
256, 0, 0, NULL, 0) );
|
||||
256, 0, 0, NULL, 0) );
|
||||
/* Tell VFS to use UART driver */
|
||||
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
|
||||
esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
|
||||
|
45
components/asio/CMakeLists.txt
Normal file
45
components/asio/CMakeLists.txt
Normal file
@ -0,0 +1,45 @@
|
||||
if(NOT CONFIG_LWIP_IPV6 AND NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
# note: the component is still included in the build so it can become visible again in config
|
||||
# without needing to re-run CMake. However no source or header files are built.
|
||||
message(STATUS "IPV6 support is disabled so the asio component will not be built")
|
||||
idf_component_register()
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(asio_sources "asio/asio/src/asio.cpp")
|
||||
|
||||
if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
if(CONFIG_ASIO_USE_ESP_OPENSSL)
|
||||
list(APPEND asio_sources
|
||||
"port/src/asio_ssl_impl.cpp"
|
||||
"port/mbedtls/src/mbedtls_context.cpp"
|
||||
"port/mbedtls/src/mbedtls_engine.cpp")
|
||||
set(asio_priv_includes "port/mbedtls/include")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ASIO_USE_ESP_WOLFSSL)
|
||||
list(APPEND asio_sources
|
||||
"asio/asio/src/asio_ssl.cpp")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${asio_sources}
|
||||
INCLUDE_DIRS "asio/asio/include" "port/include"
|
||||
PRIV_INCLUDE_DIRS ${asio_priv_includes}
|
||||
REQUIRES lwip)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
||||
if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
if(CONFIG_ASIO_USE_ESP_WOLFSSL)
|
||||
idf_component_get_property(wolflib esp-wolfssl COMPONENT_LIB)
|
||||
idf_component_get_property(wolfdir esp-wolfssl COMPONENT_DIR)
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC ${wolflib})
|
||||
target_include_directories(${COMPONENT_LIB} PUBLIC ${wolfdir}/wolfssl/wolfssl)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ASIO_USE_ESP_OPENSSL)
|
||||
idf_component_get_property(mbedtls mbedtls COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC ${mbedtls})
|
||||
endif()
|
||||
endif()
|
36
components/asio/Kconfig
Normal file
36
components/asio/Kconfig
Normal file
@ -0,0 +1,36 @@
|
||||
menu "ESP-ASIO"
|
||||
visible if LWIP_IPV6
|
||||
|
||||
config ASIO_SSL_SUPPORT
|
||||
bool "Enable SSL/TLS support of ASIO"
|
||||
default n
|
||||
help
|
||||
Enable support for basic SSL/TLS features, available for mbedTLS/OpenSSL
|
||||
as well as wolfSSL TLS library.
|
||||
|
||||
choice ASIO_SSL_LIBRARY_CHOICE
|
||||
prompt "Choose SSL/TLS library for ESP-TLS (See help for more Info)"
|
||||
default ASIO_USE_ESP_OPENSSL
|
||||
depends on ASIO_SSL_SUPPORT
|
||||
help
|
||||
The ASIO support multiple backend TLS libraries. Currently the mbedTLS with a thin ESP-OpenSSL
|
||||
port layer (default choice) and WolfSSL are supported.
|
||||
Different TLS libraries may support different features and have different resource
|
||||
usage. Consult the ESP-TLS documentation in ESP-IDF Programming guide for more details.
|
||||
config ASIO_USE_ESP_OPENSSL
|
||||
bool "esp-openssl"
|
||||
config ASIO_USE_ESP_WOLFSSL
|
||||
depends on TLS_STACK_WOLFSSL
|
||||
bool "wolfSSL (License info in wolfSSL directory README)"
|
||||
endchoice
|
||||
|
||||
config ASIO_SSL_BIO_SIZE
|
||||
int "Size of BIO object"
|
||||
default 1024
|
||||
depends on ASIO_SSL_SUPPORT
|
||||
help
|
||||
Size in bytes of SSL-BIO implementation.
|
||||
Reducing the BIO size saves more RAM, but may slow down input output operations due to
|
||||
fragmentation.
|
||||
|
||||
endmenu
|
23
components/asio/LICENSE
Normal file
23
components/asio/LICENSE
Normal file
@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
13
components/asio/README.md
Normal file
13
components/asio/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# ASIO port
|
||||
|
||||
[](https://components.espressif.com/components/espressif/asio)
|
||||
|
||||
Asio is a cross-platform C++ library, see https://think-async.com/Asio/. It provides a consistent asynchronous model using a modern C++ approach.
|
||||
|
||||
## Examples
|
||||
|
||||
Get started with example test :example:`examples <examples/..>`:
|
||||
|
||||
## Documentation
|
||||
|
||||
* View the full [html documentation](https://espressif.github.io/esp-protocols/asio/index.html)
|
1
components/asio/asio
Submodule
1
components/asio/asio
Submodule
Submodule components/asio/asio added at 58384fb6af
73
components/asio/docs/Doxyfile
Executable file
73
components/asio/docs/Doxyfile
Executable file
@ -0,0 +1,73 @@
|
||||
# This is Doxygen configuration file
|
||||
#
|
||||
# Doxygen provides over 260 configuration statements
|
||||
# To make this file easier to follow,
|
||||
# it contains only statements that are non-default
|
||||
#
|
||||
# NOTE:
|
||||
# It is recommended not to change defaults unless specifically required
|
||||
# Test any changes how they affect generated documentation
|
||||
# Make sure that correct warnings are generated to flag issues with documented code
|
||||
#
|
||||
# For the complete list of configuration statements see:
|
||||
# http://doxygen.nl/manual/config.html
|
||||
|
||||
|
||||
PROJECT_NAME = "ESP Protocols Programming Guide"
|
||||
|
||||
## The 'INPUT' statement below is used as input by script 'gen-df-input.py'
|
||||
## to automatically generate API reference list files heder_file.inc
|
||||
## These files are placed in '_inc' directory
|
||||
## and used to include in API reference documentation
|
||||
|
||||
|
||||
## Get warnings for functions that have no documentation for their parameters or return value
|
||||
##
|
||||
WARN_NO_PARAMDOC = YES
|
||||
|
||||
## Enable preprocessing and remove __attribute__(...) expressions from the INPUT files
|
||||
##
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
PREDEFINED = \
|
||||
$(ENV_DOXYGEN_DEFINES) \
|
||||
__DOXYGEN__=1 \
|
||||
__attribute__(x)= \
|
||||
_Static_assert()= \
|
||||
IDF_DEPRECATED(X)= \
|
||||
IRAM_ATTR= \
|
||||
configSUPPORT_DYNAMIC_ALLOCATION=1 \
|
||||
configSUPPORT_STATIC_ALLOCATION=1 \
|
||||
configQUEUE_REGISTRY_SIZE=1 \
|
||||
configUSE_RECURSIVE_MUTEXES=1 \
|
||||
configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS=1 \
|
||||
configNUM_THREAD_LOCAL_STORAGE_POINTERS=1 \
|
||||
configUSE_APPLICATION_TASK_TAG=1 \
|
||||
configTASKLIST_INCLUDE_COREID=1 \
|
||||
"ESP_EVENT_DECLARE_BASE(x)=extern esp_event_base_t x"
|
||||
|
||||
## Do not complain about not having dot
|
||||
##
|
||||
HAVE_DOT = NO
|
||||
|
||||
## Generate XML that is required for Breathe
|
||||
##
|
||||
GENERATE_XML = YES
|
||||
XML_OUTPUT = xml
|
||||
|
||||
GENERATE_HTML = NO
|
||||
HAVE_DOT = NO
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_MAN = YES
|
||||
GENERATE_RTF = NO
|
||||
|
||||
## Skip distracting progress messages
|
||||
##
|
||||
QUIET = YES
|
||||
|
||||
## Enable Section Tags for conditional documentation
|
||||
##
|
||||
ENABLED_SECTIONS += \
|
||||
DOC_EXCLUDE_HEADER_SECTION \ ## To conditionally remove doc sections from IDF source files without affecting documentation in upstream files.
|
||||
DOC_SINGLE_GROUP ## To conditionally remove groups from the documentation and create a 'flat' document without affecting documentation in upstream files.
|
22
components/asio/docs/conf_common.py
Normal file
22
components/asio/docs/conf_common.py
Normal file
@ -0,0 +1,22 @@
|
||||
from esp_docs.conf_docs import * # noqa: F403,F401
|
||||
|
||||
extensions += [
|
||||
'sphinx_copybutton',
|
||||
# Needed as a trigger for running doxygen
|
||||
'esp_docs.esp_extensions.dummy_build_system',
|
||||
'esp_docs.esp_extensions.run_doxygen',
|
||||
]
|
||||
|
||||
# link roles config
|
||||
github_repo = 'espressif/esp-protocols'
|
||||
|
||||
# context used by sphinx_idf_theme
|
||||
html_context['github_user'] = 'espressif'
|
||||
html_context['github_repo'] = 'esp-protocols'
|
||||
|
||||
# Extra options required by sphinx_idf_theme
|
||||
project_slug = 'esp-idf' # >=5.0
|
||||
versions_url = 'https://github.com/espressif/esp-protocols/docs/docs_versions.js'
|
||||
|
||||
idf_targets = ['esp32']
|
||||
languages = ['en', 'zh_CN']
|
24
components/asio/docs/en/conf.py
Normal file
24
components/asio/docs/en/conf.py
Normal file
@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# English Language RTD & Sphinx config file
|
||||
#
|
||||
# Uses ../conf_common.py for most non-language-specific settings.
|
||||
|
||||
# Importing conf_common adds all the non-language-specific
|
||||
# parts to this conf module
|
||||
|
||||
try:
|
||||
from conf_common import * # noqa: F403,F401
|
||||
except ImportError:
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('../'))
|
||||
from conf_common import * # noqa: F403,F401
|
||||
|
||||
# General information about the project.
|
||||
project = u'ESP-Protocols'
|
||||
copyright = u'2016 - 2022, Espressif Systems (Shanghai) Co., Ltd'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
language = 'en'
|
42
components/asio/docs/en/index.rst
Normal file
42
components/asio/docs/en/index.rst
Normal file
@ -0,0 +1,42 @@
|
||||
ASIO port
|
||||
=========
|
||||
|
||||
Overview
|
||||
--------
|
||||
Asio is a cross-platform C++ library, see https://think-async.com/Asio/. It provides a consistent asynchronous model using a modern C++ approach.
|
||||
|
||||
|
||||
ASIO documentation
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
Please refer to the original asio documentation at https://think-async.com/Asio/Documentation.
|
||||
Asio also comes with a number of examples which could be find under Documentation/Examples on that web site.
|
||||
|
||||
Supported features
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
ESP platform port currently supports only network asynchronous socket operations; does not support serial port.
|
||||
SSL/TLS support is disabled by default and could be enabled in component configuration menu by choosing TLS library from
|
||||
|
||||
- mbedTLS with OpenSSL translation layer (default option)
|
||||
- wolfSSL
|
||||
|
||||
SSL support is very basic at this stage and it does include following features:
|
||||
|
||||
- Verification callbacks
|
||||
- DH property files
|
||||
- Certificates/private keys file APIs
|
||||
|
||||
Internal asio settings for ESP include
|
||||
|
||||
- EXCEPTIONS are enabled in ASIO if enabled in menuconfig
|
||||
- TYPEID is enabled in ASIO if enabled in menuconfig
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
ESP examples are based on standard asio :example:`examples <../examples>`:
|
||||
|
||||
- :example:`udp_echo_server <../examples/udp_echo_server>`
|
||||
- :example:`tcp_echo_server <../examples/tcp_echo_server>`
|
||||
- :example:`asio_chat <../examples/asio_chat>`
|
||||
- :example:`ssl_client_server <../examples/ssl_client_server>`
|
||||
|
||||
Please refer to the specific example README.md for details
|
26
components/asio/docs/generate_docs
Executable file
26
components/asio/docs/generate_docs
Executable file
@ -0,0 +1,26 @@
|
||||
build-docs --target esp32 --language en
|
||||
|
||||
cp -rf _build/en/esp32/html .
|
||||
rm -rf _build __pycache__
|
||||
|
||||
# Modifes some version and target fields of index.html
|
||||
echo "<script type="text/javascript">
|
||||
window.onload =(function() {
|
||||
var myAnchor = document.getElementById('version-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'latest';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
var myAnchor = document.getElementById('target-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'all targets';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
})();
|
||||
</script>" >> html/index.html
|
27
components/asio/docs/zh_CN/conf.py
Normal file
27
components/asio/docs/zh_CN/conf.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# English Language RTD & Sphinx config file
|
||||
#
|
||||
# Uses ../conf_common.py for most non-language-specific settings.
|
||||
|
||||
# Importing conf_common adds all the non-language-specific
|
||||
# parts to this conf module
|
||||
try:
|
||||
from conf_common import * # noqa: F403,F401
|
||||
except ImportError:
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
from conf_common import * # noqa: F403,F401
|
||||
|
||||
import datetime
|
||||
|
||||
current_year = datetime.datetime.now().year
|
||||
|
||||
# General information about the project.
|
||||
project = u'ESP-IDF 编程指南'
|
||||
copyright = u'2016 - {} 乐鑫信息科技(上海)股份有限公司'.format(current_year)
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
language = 'zh_CN'
|
1
components/asio/docs/zh_CN/index.rst
Normal file
1
components/asio/docs/zh_CN/index.rst
Normal file
@ -0,0 +1 @@
|
||||
.. include:: ../../../en/api-reference/protocols/asio.rst
|
10
components/asio/examples/asio_chat/CMakeLists.txt
Normal file
10
components/asio/examples/asio_chat/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_chat)
|
65
components/asio/examples/asio_chat/README.md
Normal file
65
components/asio/examples/asio_chat/README.md
Normal file
@ -0,0 +1,65 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
|
||||
|
||||
# Asio chat client and server examples
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
The application aims to demonstrate a simple use of Asio library in different modes.
|
||||
In project settings it could be configured to run either a Asio chat server, a Asio chat client, or both.
|
||||
|
||||
## How to use example
|
||||
|
||||
The example is configured by default as an Asio chat client.
|
||||
|
||||
Note that the example uses string representation of IP addresses and ports.
|
||||
|
||||
You can find the upstream asio chat implementation [here] https://github.com/chriskohlhoff/asio/tree/master/asio/src/examples/cpp11/chat
|
||||
|
||||
### Asio Client
|
||||
|
||||
In the client mode, the example connects to the configured address, sends the message, which was inserted as an input in the terminal, and receives a response.
|
||||
|
||||
### Asio Server
|
||||
|
||||
In the server mode, Asio chat server with a specified port number is created and being polled till a connection request from the client arrives.
|
||||
Chat server echoes a message (received from any client) to all connected clients.
|
||||
|
||||
## Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
Set following parameters under Example Configuration Options:
|
||||
|
||||
* Set `EXAMPLE_CHAT_SERVER` to use the example as an ASIO chat server
|
||||
* Configure `EXAMPLE_CHAT_SERVER_BIND_PORT` to the port number.
|
||||
|
||||
* Set `EXAMPLE_CHAT_CLIENT` to use the example as an ASIO chat client
|
||||
* Configure `EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS` to a string representation of the address to connect the client to.
|
||||
* Configure `EXAMPLE_CHAT_CLIENT_CONNECT_PORT` to the port number.
|
||||
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more d etails.
|
||||
|
||||
## Running the example in server mode
|
||||
|
||||
- Configure the example according "Configure the project" section.
|
||||
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
||||
- Wait for the board to connect to WiFi or Ethernet (note the IP address).
|
||||
- Connect to the server using multiple clients, for example using any option below.
|
||||
- build and run asio chat client on your host machine
|
||||
- run chat_client asio example on ESP platform
|
||||
- since chat messages consists of ASCII size and message, it is possible to
|
||||
netcat `nc IP PORT` and type for example ` 4ABC<CR>` to transmit 'ABC\n'
|
||||
|
||||
## Running the example in client mode
|
||||
|
||||
- Configure the example according "Configure the project" section.
|
||||
- Start chat server either on host machine or as another ESP device running chat_server example.
|
||||
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
||||
- Wait for the board to connect to WiFi or Ethernet.
|
||||
- Receive and send messages to/from other clients on stdin/stdout via serial terminal.
|
||||
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
2
components/asio/examples/asio_chat/main/CMakeLists.txt
Normal file
2
components/asio/examples/asio_chat/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "asio_chat.cpp"
|
||||
INCLUDE_DIRS ".")
|
39
components/asio/examples/asio_chat/main/Kconfig.projbuild
Normal file
39
components/asio/examples/asio_chat/main/Kconfig.projbuild
Normal file
@ -0,0 +1,39 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_CHAT_SERVER
|
||||
bool "Asio example chat server"
|
||||
default n
|
||||
help
|
||||
This example will setup a chat server, binds it to the specified address
|
||||
and starts listening.
|
||||
|
||||
if EXAMPLE_CHAT_SERVER
|
||||
config EXAMPLE_CHAT_SERVER_BIND_PORT
|
||||
string "Asio example server bind port"
|
||||
default "3344"
|
||||
help
|
||||
Server listener's socket would be bound to this port.
|
||||
endif
|
||||
|
||||
config EXAMPLE_CHAT_CLIENT
|
||||
bool "Asio example chat client"
|
||||
default y
|
||||
help
|
||||
This example will setup an asio chat client.
|
||||
and sends the data.
|
||||
|
||||
if EXAMPLE_CHAT_CLIENT
|
||||
config EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS
|
||||
string "Client connection address"
|
||||
default "192.168.0.1"
|
||||
help
|
||||
Client's socket would connect to this address/host.
|
||||
|
||||
config EXAMPLE_CHAT_CLIENT_CONNECT_PORT
|
||||
string "Client connection port"
|
||||
default "3344"
|
||||
help
|
||||
Client's connection port.
|
||||
endif
|
||||
|
||||
endmenu
|
120
components/asio/examples/asio_chat/main/asio_chat.cpp
Normal file
120
components/asio/examples/asio_chat/main/asio_chat.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/* ASIO chat server client example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "server.hpp"
|
||||
#include "client.hpp"
|
||||
#include <thread>
|
||||
#include <pthread.h>
|
||||
|
||||
using asio::ip::tcp;
|
||||
|
||||
static const char *TAG = "asio-chat";
|
||||
|
||||
// This variable is necessary for `python test` execution, it provides synchronisation between server/client(as server should be started before client)
|
||||
std::mutex server_ready;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
|
||||
static void get_string(char *line, size_t size)
|
||||
{
|
||||
int count = 0;
|
||||
while (count < size) {
|
||||
int c = fgetc(stdin);
|
||||
if (c == '\n') {
|
||||
line[count] = '\0';
|
||||
break;
|
||||
} else if (c > 0 && c < 127) {
|
||||
line[count] = c;
|
||||
++count;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void start_client(void)
|
||||
{
|
||||
const std::string port(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_PORT);
|
||||
const std::string name(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS);
|
||||
asio::io_context io_context;
|
||||
char line[128];
|
||||
|
||||
tcp::resolver resolver(io_context);
|
||||
auto endpoints = resolver.resolve(name, port);
|
||||
chat_client c(io_context, endpoints);
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||
std::lock_guard<std::mutex> guard(server_ready);
|
||||
#endif
|
||||
std::thread t([&io_context]() {
|
||||
try {
|
||||
io_context.run();
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE(TAG, "Exception occured during client thread execution %s", e.what());
|
||||
} catch (...) {
|
||||
ESP_LOGE(TAG, "Unknown exception");
|
||||
}
|
||||
});
|
||||
do {
|
||||
ESP_LOGI(TAG, "CLIENT: Waiting for input");
|
||||
get_string(line, sizeof(line));
|
||||
|
||||
chat_message msg;
|
||||
msg.body_length(std::strlen(line));
|
||||
std::memcpy(msg.body(), line, msg.body_length());
|
||||
msg.encode_header();
|
||||
c.write(msg);
|
||||
sleep(1);
|
||||
} while (strcmp(line, "exit") != 0);
|
||||
|
||||
c.close();
|
||||
t.join();
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_CHAT_CLIENT
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
esp_netif_init();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
try {
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||
asio::io_context io_context;
|
||||
chat_server server(io_context, tcp::endpoint(tcp::v4(), std::atoi(CONFIG_EXAMPLE_CHAT_SERVER_BIND_PORT)));
|
||||
std::thread t = std::thread([&io_context]() { // Chat server starting here
|
||||
try {
|
||||
io_context.run();
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE(TAG, "Exception occured during server thread execution %s", e.what());
|
||||
} catch (...) {
|
||||
ESP_LOGE(TAG, "Unknown exception");
|
||||
}
|
||||
});;
|
||||
#endif
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
|
||||
start_client();
|
||||
#endif
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||
t.join();
|
||||
#endif
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE(TAG, "Exception occured during run %s", e.what());
|
||||
} catch (...) {
|
||||
ESP_LOGE(TAG, "Unknown exception");
|
||||
}
|
||||
ESP_ERROR_CHECK(example_disconnect());
|
||||
}
|
90
components/asio/examples/asio_chat/main/chat_message.hpp
Normal file
90
components/asio/examples/asio_chat/main/chat_message.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
//
|
||||
// chat_message.hpp
|
||||
// ~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef CHAT_MESSAGE_HPP
|
||||
#define CHAT_MESSAGE_HPP
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
class chat_message {
|
||||
public:
|
||||
static constexpr std::size_t header_length = 4;
|
||||
static constexpr std::size_t max_body_length = 512;
|
||||
|
||||
chat_message()
|
||||
: body_length_(0)
|
||||
{
|
||||
}
|
||||
|
||||
const char *data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
char *data()
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
std::size_t length() const
|
||||
{
|
||||
return header_length + body_length_;
|
||||
}
|
||||
|
||||
const char *body() const
|
||||
{
|
||||
return data_ + header_length;
|
||||
}
|
||||
|
||||
char *body()
|
||||
{
|
||||
return data_ + header_length;
|
||||
}
|
||||
|
||||
std::size_t body_length() const
|
||||
{
|
||||
return body_length_;
|
||||
}
|
||||
|
||||
void body_length(std::size_t new_length)
|
||||
{
|
||||
body_length_ = new_length;
|
||||
if (body_length_ > max_body_length) {
|
||||
body_length_ = max_body_length;
|
||||
}
|
||||
}
|
||||
|
||||
bool decode_header()
|
||||
{
|
||||
char header[header_length + 1] = "";
|
||||
std::strncat(header, data_, header_length);
|
||||
body_length_ = std::atoi(header);
|
||||
if (body_length_ > max_body_length) {
|
||||
body_length_ = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void encode_header()
|
||||
{
|
||||
char header[header_length + 1] = "";
|
||||
std::sprintf(header, "%4d", static_cast<int>(body_length_));
|
||||
std::memcpy(data_, header, header_length);
|
||||
}
|
||||
|
||||
private:
|
||||
char data_[header_length + max_body_length];
|
||||
std::size_t body_length_;
|
||||
};
|
||||
|
||||
#endif // CHAT_MESSAGE_HPP
|
110
components/asio/examples/asio_chat/main/client.hpp
Normal file
110
components/asio/examples/asio_chat/main/client.hpp
Normal file
@ -0,0 +1,110 @@
|
||||
//
|
||||
// client.hpp
|
||||
// ~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef CHAT_CLIENT_HPP
|
||||
#define CHAT_CLIENT_HPP
|
||||
|
||||
#include <deque>
|
||||
#include "asio.hpp"
|
||||
#include "chat_message.hpp"
|
||||
|
||||
typedef std::deque<chat_message> chat_message_queue;
|
||||
|
||||
class chat_client {
|
||||
public:
|
||||
chat_client(asio::io_context &io_context,
|
||||
const asio::ip::tcp::resolver::results_type &endpoints)
|
||||
: io_context_(io_context),
|
||||
socket_(io_context)
|
||||
{
|
||||
do_connect(endpoints);
|
||||
}
|
||||
|
||||
void write(const chat_message &msg)
|
||||
{
|
||||
asio::post(io_context_,
|
||||
[this, msg]() {
|
||||
bool write_in_progress = !write_msgs_.empty();
|
||||
write_msgs_.push_back(msg);
|
||||
if (!write_in_progress) {
|
||||
do_write();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
asio::post(io_context_, [this]() {
|
||||
socket_.close();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
void do_connect(const asio::ip::tcp::resolver::results_type &endpoints)
|
||||
{
|
||||
asio::async_connect(socket_, endpoints,
|
||||
[this](std::error_code ec, asio::ip::tcp::endpoint) {
|
||||
if (!ec) {
|
||||
do_read_header();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_read_header()
|
||||
{
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.data(), chat_message::header_length),
|
||||
[this](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec && read_msg_.decode_header()) {
|
||||
do_read_body();
|
||||
} else {
|
||||
socket_.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_read_body()
|
||||
{
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
[this](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
do_read_header();
|
||||
} else {
|
||||
socket_.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_write()
|
||||
{
|
||||
asio::async_write(socket_,
|
||||
asio::buffer(write_msgs_.front().data(),
|
||||
write_msgs_.front().length()),
|
||||
[this](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
write_msgs_.pop_front();
|
||||
if (!write_msgs_.empty()) {
|
||||
do_write();
|
||||
}
|
||||
} else {
|
||||
socket_.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_context &io_context_;
|
||||
asio::ip::tcp::socket socket_;
|
||||
chat_message read_msg_;
|
||||
chat_message_queue write_msgs_;
|
||||
};
|
||||
|
||||
#endif // CHAT_CLIENT_HPP
|
185
components/asio/examples/asio_chat/main/server.hpp
Normal file
185
components/asio/examples/asio_chat/main/server.hpp
Normal file
@ -0,0 +1,185 @@
|
||||
//
|
||||
// server.hpp
|
||||
// ~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef CHAT_SERVER_HPP
|
||||
#define CHAT_SERVER_HPP
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
#include "asio.hpp"
|
||||
#include "chat_message.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
typedef std::deque<chat_message> chat_message_queue;
|
||||
|
||||
extern std::mutex server_ready;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
class chat_participant {
|
||||
public:
|
||||
virtual ~chat_participant() {}
|
||||
virtual void deliver(const chat_message &msg) = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<chat_participant> chat_participant_ptr;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class chat_room {
|
||||
public:
|
||||
void join(chat_participant_ptr participant)
|
||||
{
|
||||
participants_.insert(participant);
|
||||
for (auto msg : recent_msgs_) {
|
||||
participant->deliver(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void leave(chat_participant_ptr participant)
|
||||
{
|
||||
participants_.erase(participant);
|
||||
}
|
||||
|
||||
void deliver(const chat_message &msg)
|
||||
{
|
||||
recent_msgs_.push_back(msg);
|
||||
while (recent_msgs_.size() > max_recent_msgs) {
|
||||
recent_msgs_.pop_front();
|
||||
}
|
||||
|
||||
for (auto participant : participants_) {
|
||||
participant->deliver(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<chat_participant_ptr> participants_;
|
||||
enum { max_recent_msgs = 100 };
|
||||
chat_message_queue recent_msgs_;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
class chat_session
|
||||
: public chat_participant,
|
||||
public std::enable_shared_from_this<chat_session> {
|
||||
public:
|
||||
chat_session(asio::ip::tcp::socket socket, chat_room &room)
|
||||
: socket_(std::move(socket)),
|
||||
room_(room)
|
||||
{
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
room_.join(shared_from_this());
|
||||
do_read_header();
|
||||
}
|
||||
|
||||
void deliver(const chat_message &msg)
|
||||
{
|
||||
bool write_in_progress = !write_msgs_.empty();
|
||||
write_msgs_.push_back(msg);
|
||||
if (!write_in_progress) {
|
||||
do_write();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void do_read_header()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.data(), chat_message::header_length),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec && read_msg_.decode_header()) {
|
||||
do_read_body();
|
||||
} else {
|
||||
room_.leave(shared_from_this());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_read_body()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
|
||||
room_.deliver(read_msg_);
|
||||
do_read_header();
|
||||
} else {
|
||||
room_.leave(shared_from_this());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_write()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_write(socket_,
|
||||
asio::buffer(write_msgs_.front().data(),
|
||||
write_msgs_.front().length()),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
write_msgs_.pop_front();
|
||||
if (!write_msgs_.empty()) {
|
||||
do_write();
|
||||
}
|
||||
} else {
|
||||
room_.leave(shared_from_this());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
asio::ip::tcp::socket socket_;
|
||||
chat_room &room_;
|
||||
chat_message read_msg_;
|
||||
chat_message_queue write_msgs_;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class chat_server {
|
||||
public:
|
||||
chat_server(asio::io_context &io_context,
|
||||
const asio::ip::tcp::endpoint &endpoint)
|
||||
: acceptor_(io_context, endpoint)
|
||||
{
|
||||
do_accept();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_accept()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(server_ready);
|
||||
acceptor_.async_accept(
|
||||
[this](std::error_code ec, asio::ip::tcp::socket socket) {
|
||||
if (!ec) {
|
||||
std::make_shared<chat_session>(std::move(socket), room_)->start();
|
||||
}
|
||||
|
||||
do_accept();
|
||||
});
|
||||
}
|
||||
|
||||
asio::ip::tcp::acceptor acceptor_;
|
||||
chat_room room_;
|
||||
};
|
||||
|
||||
#endif // CHAT_SERVER_HPP
|
16
components/asio/examples/asio_chat/pytest_asio_chat_test.py
Normal file
16
components/asio/examples/asio_chat/pytest_asio_chat_test.py
Normal file
@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def test_examples_asio_chat(dut):
|
||||
msg = 'asio-chat: received hi'
|
||||
# start the test and expect the client to receive back it's original data
|
||||
dut.expect(re.compile(b'Waiting for input'), timeout=30)
|
||||
dut.write(msg)
|
||||
dut.write('exit')
|
||||
msg = bytes(msg, encoding='utf8')
|
||||
dut.expect(re.compile(msg), timeout=30)
|
6
components/asio/examples/asio_chat/sdkconfig.ci
Normal file
6
components/asio/examples/asio_chat/sdkconfig.ci
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||
CONFIG_EXAMPLE_CHAT_CLIENT=y
|
||||
CONFIG_EXAMPLE_CHAT_SERVER=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS="localhost"
|
8
components/asio/examples/asio_chat/sdkconfig.defaults
Normal file
8
components/asio/examples/asio_chat/sdkconfig.defaults
Normal file
@ -0,0 +1,8 @@
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
# Leave some room for larger apps without needing to reduce other features
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
10
components/asio/examples/async_request/CMakeLists.txt
Normal file
10
components/asio/examples/async_request/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../ ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(async_http_request)
|
52
components/asio/examples/async_request/README.md
Normal file
52
components/asio/examples/async_request/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# Async request using ASIO
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
The application aims to show how to compose async operations using ASIO to build network protocols and operations.
|
||||
|
||||
# Configure and Building example
|
||||
|
||||
This example doesn't require any configuration, just build it with
|
||||
|
||||
```
|
||||
idf.py build
|
||||
```
|
||||
|
||||
# Async operations composition and automatic lifetime control
|
||||
|
||||
On this example we compose the operation by starting the next step in the chain inside the completion handler of the
|
||||
previous operation. Also we pass the `Connection` class itself as the parameter of its final handler to be owned by
|
||||
the following operation. This is possible due to the control of lifetime by the usage of `std::shared_ptr`.
|
||||
|
||||
The control of lifetime of the class, done by `std::shared_ptr` usage, guarantee that the data will be available for
|
||||
async operations until it's not needed any more. This makes necessary that all of the async operation class must start
|
||||
its lifetime as a `std::shared_ptr` due to the usage of `std::enable_shared_from_this`.
|
||||
|
||||
|
||||
User creates a shared_ptr──┐
|
||||
of AddressResolution and │
|
||||
ask for resolve. │
|
||||
The handler for the ┌▼─────────────────────┐
|
||||
complete operation is sent│ AddressResolution │ In the completion of resolve a connection is created.
|
||||
└─────────────────┬────┘ AddressResolution is automaticly destroyed since it's
|
||||
│ no longer needed
|
||||
┌─▼────────────────────────────────────┐
|
||||
│ Connection │
|
||||
└──────┬───────────────────────────────┘
|
||||
Http::Session is created once we have a Connection. │
|
||||
Connection is passed to Http::Session that holds it │
|
||||
avoiding it's destruction. │
|
||||
┌─▼───────────────────────────────┐
|
||||
│ Http::Session │
|
||||
└────────┬────────────────────────┘
|
||||
After the HTTP request is │
|
||||
sent the completion handler │
|
||||
is called. │
|
||||
└────►Completion Handler()
|
||||
|
||||
|
||||
The previous diagram shows the process and the life span of each of the tasks in this examples. At each stage the
|
||||
object responsible for the last action inject itself to the completion handler of the next stage for reuse.
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "async_http_request.cpp"
|
||||
INCLUDE_DIRS ".")
|
@ -0,0 +1,369 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*
|
||||
* ASIO HTTP request example
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <asio.hpp>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
constexpr auto TAG = "async_request";
|
||||
using asio::ip::tcp;
|
||||
|
||||
namespace {
|
||||
|
||||
void esp_init()
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_log_level_set("async_request", ESP_LOG_DEBUG);
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simple class to add the resolver to a chain of actions
|
||||
*
|
||||
*/
|
||||
class AddressResolution : public std::enable_shared_from_this<AddressResolution> {
|
||||
public:
|
||||
explicit AddressResolution(asio::io_context &context) : ctx(context), resolver(ctx) {}
|
||||
|
||||
/**
|
||||
* @brief Initiator function for the address resolution
|
||||
*
|
||||
* @tparam CompletionToken callable responsible to use the results.
|
||||
*
|
||||
* @param host Host address
|
||||
* @param port Port for the target, must be number due to a limitation on lwip.
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void resolve(const std::string &host, const std::string &port, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
resolver.async_resolve(host, port, [self, completion_handler](const asio::error_code & error, tcp::resolver::results_type results) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Failed to resolve: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
completion_handler(self, results);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_context &ctx;
|
||||
tcp::resolver resolver;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Connection class
|
||||
*
|
||||
* The lowest level dependency on our asynchronous task, Connection provide an interface to TCP sockets.
|
||||
* A similar class could be provided for a TLS connection.
|
||||
*
|
||||
* @note: All read and write operations are written on an explicit strand, even though an implicit strand
|
||||
* occurs in this example since we run the io context in a single task.
|
||||
*
|
||||
*/
|
||||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
explicit Connection(asio::io_context &context) : ctx(context), strand(context), socket(ctx) {}
|
||||
|
||||
/**
|
||||
* @brief Start the connection
|
||||
*
|
||||
* Async operation to start a connection. As the final act of the process the Connection class pass a
|
||||
* std::shared_ptr of itself to the completion_handler.
|
||||
* Since it uses std::shared_ptr as an automatic control of its lifetime this class must be created
|
||||
* through a std::make_shared call.
|
||||
*
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
* @param host host address
|
||||
* @param port port number - due to a limitation on lwip implementation this should be the number not the
|
||||
* service name typically seen in ASIO examples.
|
||||
*
|
||||
* @note The class could be modified to store the completion handler, as a member variable, instead of
|
||||
* pass it along asynchronous calls to allow the process to run again completely.
|
||||
*
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void start(tcp::resolver::results_type results, CompletionToken &&completion_handler)
|
||||
{
|
||||
connect(results, completion_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an async write on the socket
|
||||
*
|
||||
* @tparam data
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
*
|
||||
*/
|
||||
template<class DataType, class CompletionToken>
|
||||
void write_async(const DataType &data, CompletionToken &&completion_handler)
|
||||
{
|
||||
asio::async_write(socket, data, asio::bind_executor(strand, completion_handler));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an async read on the socket
|
||||
*
|
||||
* @tparam data
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
*
|
||||
*/
|
||||
template<class DataBuffer, class CompletionToken>
|
||||
void read_async(DataBuffer &&in_data, CompletionToken &&completion_handler)
|
||||
{
|
||||
asio::async_read(socket, in_data, asio::bind_executor(strand, completion_handler));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<class CompletionToken>
|
||||
void connect(tcp::resolver::results_type results, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_connect(socket, results, [self, completion_handler](const asio::error_code & error, [[maybe_unused]] const tcp::endpoint & endpoint) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Failed to connect: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
completion_handler(self);
|
||||
});
|
||||
}
|
||||
asio::io_context &ctx;
|
||||
asio::io_context::strand strand;
|
||||
tcp::socket socket;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
namespace Http {
|
||||
enum class Method { GET };
|
||||
|
||||
/**
|
||||
* @brief Simple HTTP request class
|
||||
*
|
||||
* The user needs to write the request information direct to header and body fields.
|
||||
*
|
||||
* Only GET verb is provided.
|
||||
*
|
||||
*/
|
||||
class Request {
|
||||
public:
|
||||
Request(Method method, std::string host, std::string port, const std::string &target) : host_data(std::move(host)), port_data(std::move(port))
|
||||
{
|
||||
header_data.append("GET ");
|
||||
header_data.append(target);
|
||||
header_data.append(" HTTP/1.1");
|
||||
header_data.append("\r\n");
|
||||
header_data.append("Host: ");
|
||||
header_data.append(host_data);
|
||||
header_data.append("\r\n");
|
||||
header_data.append("\r\n");
|
||||
};
|
||||
|
||||
void set_header_field(std::string const &field)
|
||||
{
|
||||
header_data.append(field);
|
||||
}
|
||||
|
||||
void append_to_body(std::string const &data)
|
||||
{
|
||||
body_data.append(data);
|
||||
};
|
||||
|
||||
const std::string &host() const
|
||||
{
|
||||
return host_data;
|
||||
}
|
||||
|
||||
const std::string &service_port() const
|
||||
{
|
||||
return port_data;
|
||||
}
|
||||
|
||||
const std::string &header() const
|
||||
{
|
||||
return header_data;
|
||||
}
|
||||
|
||||
const std::string &body() const
|
||||
{
|
||||
return body_data;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string host_data;
|
||||
std::string port_data;
|
||||
std::string header_data;
|
||||
std::string body_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Simple HTTP response class
|
||||
*
|
||||
* The response is built from received data and only parsed to split header and body.
|
||||
*
|
||||
* A copy of the received data is kept.
|
||||
*
|
||||
*/
|
||||
struct Response {
|
||||
/**
|
||||
* @brief Construct a response from a contiguous buffer.
|
||||
*
|
||||
* Simple http parsing.
|
||||
*
|
||||
*/
|
||||
template<class DataIt>
|
||||
explicit Response(DataIt data, size_t size)
|
||||
{
|
||||
raw_response = std::string(data, size);
|
||||
|
||||
auto header_last = raw_response.find("\r\n\r\n");
|
||||
if (header_last != std::string::npos) {
|
||||
header = raw_response.substr(0, header_last);
|
||||
}
|
||||
body = raw_response.substr(header_last + 3);
|
||||
}
|
||||
/**
|
||||
* @brief Print response content.
|
||||
*/
|
||||
void print()
|
||||
{
|
||||
ESP_LOGI(TAG, "Header :\n %s", header.c_str());
|
||||
ESP_LOGI(TAG, "Body : \n %s", body.c_str());
|
||||
}
|
||||
|
||||
std::string raw_response;
|
||||
std::string header;
|
||||
std::string body;
|
||||
};
|
||||
|
||||
/** @brief HTTP Session
|
||||
*
|
||||
* Session class to handle HTTP protocol implementation.
|
||||
*
|
||||
*/
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
public:
|
||||
explicit Session(std::shared_ptr<Connection> connection_in) : connection(std::move(connection_in))
|
||||
{
|
||||
}
|
||||
|
||||
template<class CompletionToken>
|
||||
void send_request(const Request &request, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
send_data = { asio::buffer(request.header()), asio::buffer(request.body()) };
|
||||
connection->write_async(send_data, [self, &completion_handler](std::error_code error, std::size_t bytes_transfered) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Request write error: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Bytes Transfered: %d", bytes_transfered);
|
||||
self->get_response(completion_handler);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
template<class CompletionToken>
|
||||
void get_response(CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
connection->read_async(asio::buffer(receive_buffer), [self, &completion_handler](std::error_code error, std::size_t bytes_received) {
|
||||
if (error and error.value() != asio::error::eof) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Bytes Received: %d", bytes_received);
|
||||
if (bytes_received == 0) {
|
||||
return;
|
||||
}
|
||||
Response response(std::begin(self->receive_buffer), bytes_received);
|
||||
|
||||
completion_handler(self, response);
|
||||
});
|
||||
}
|
||||
/*
|
||||
* For this example we assumed 2048 to be enough for the receive_buffer
|
||||
*/
|
||||
std::array<char, 2048> receive_buffer;
|
||||
/*
|
||||
* The hardcoded 2 below is related to the type we receive the data to send. We gather the parts from Request, header
|
||||
* and body, to send avoiding the copy.
|
||||
*/
|
||||
std::array<asio::const_buffer, 2> send_data;
|
||||
std::shared_ptr<Connection> connection;
|
||||
};
|
||||
|
||||
/** @brief Execute a fully async HTTP request
|
||||
*
|
||||
* @tparam completion_handler
|
||||
* @param ctx io context
|
||||
* @param request
|
||||
*
|
||||
* @note : We build this function as a simpler interface to compose the operations of connecting to
|
||||
* the address and running the HTTP session. The Http::Session class is injected to the completion handler
|
||||
* for further use.
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void request_async(asio::io_context &context, const Request &request, CompletionToken &&completion_handler)
|
||||
{
|
||||
/*
|
||||
* The first step is to resolve the address we want to connect to.
|
||||
* The AddressResolution itself is injected to the completion handler.
|
||||
*
|
||||
* This shared_ptr is destroyed by the end of the scope. Pay attention that this is a non blocking function
|
||||
* the lifetime of the object is extended by the resolve call
|
||||
*/
|
||||
std::make_shared<AddressResolution>(context)->resolve(request.host(), request.service_port(),
|
||||
[&context, &request, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type results) {
|
||||
/* After resolution we create a Connection.
|
||||
* The completion handler gets a shared_ptr<Connection> to receive the connection, once the
|
||||
* connection process is complete.
|
||||
*/
|
||||
std::make_shared<Connection>(context)->start(results,
|
||||
[&request, completion_handler](std::shared_ptr<Connection> connection) {
|
||||
// Now we create a HTTP::Session and inject the necessary connection.
|
||||
std::make_shared<Session>(connection)->send_request(request, completion_handler);
|
||||
});
|
||||
});
|
||||
}
|
||||
}// namespace Http
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
// Basic initialization of ESP system
|
||||
esp_init();
|
||||
|
||||
asio::io_context io_context;
|
||||
Http::Request request(Http::Method::GET, "www.httpbin.org", "80", "/get");
|
||||
Http::request_async(io_context, request, [](std::shared_ptr<Http::Session> session, Http::Response response) {
|
||||
/*
|
||||
* We only print the response here but could reuse session for other requests.
|
||||
*/
|
||||
response.print();
|
||||
});
|
||||
|
||||
// io_context.run will block until all the tasks on the context are done.
|
||||
io_context.run();
|
||||
ESP_LOGI(TAG, "Context run done");
|
||||
|
||||
ESP_ERROR_CHECK(example_disconnect());
|
||||
}
|
10
components/asio/examples/socks4/CMakeLists.txt
Normal file
10
components/asio/examples/socks4/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_sock4)
|
72
components/asio/examples/socks4/README.md
Normal file
72
components/asio/examples/socks4/README.md
Normal file
@ -0,0 +1,72 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 |
|
||||
| ----------------- | ----- | ----- |
|
||||
|
||||
# Async request using ASIO
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
The application aims to show how to connect to a Socks4 proxy using async operations with ASIO. The SOCKS protocol is
|
||||
briefly described by the diagram below.
|
||||
|
||||
┌──────┐ ┌─────┐ ┌──────┐
|
||||
│Client│ │Proxy│ │Target│
|
||||
└──┬───┘ └──┬──┘ └──┬───┘
|
||||
│ │ │
|
||||
│ ╔═╧══════════════╗ │
|
||||
══════════════════════╪════════════════════════╣ Initialization ╠═══╪════════════════════════════════════════════
|
||||
│ ╚═╤══════════════╝ │
|
||||
│ │ │
|
||||
╔══════════════════╗│ │ │
|
||||
║We establish a ░║│ Socket Connection │ │
|
||||
║TCP connection ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ > │
|
||||
║and get a socket ║│ │ │
|
||||
╚══════════════════╝│ │ │
|
||||
│ │ │
|
||||
│ ╔═╧══════════════╗ │
|
||||
══════════════════════╪════════════════════════╣ Socks Protocol ╠═══╪════════════════════════════════════════════
|
||||
│ ╚═╤══════════════╝ │
|
||||
│ │ │
|
||||
│ Client Connection Request│ │
|
||||
│ ─────────────────────────> │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ╔════════════╪═══════╤══════════╪════════════════════════════════╗
|
||||
│ ║ TARGET CONNECTION │ │ ║
|
||||
│ ╟────────────────────┘ │ ╔═══════════════════╗ ║
|
||||
│ ║ │ Socket Connection│ ║Proxy establishes ░║ ║
|
||||
│ ║ │ <─ ─ ─ ─ ─ ─ ─ ─ > ║ TCPconnection ║ ║
|
||||
│ ║ │ │ ║ with target host ║ ║
|
||||
│ ╚════════════╪══════════════════╪══╚═══════════════════╝═════════╝
|
||||
│ │ │
|
||||
│ Response packet │ │
|
||||
│ <───────────────────────── │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ ╔═══════╗ │
|
||||
══════════════════════╪══════════════════════════╪══╣ Usage ╠═══════╪════════════════════════════════════════════
|
||||
│ │ ╚═══════╝ │
|
||||
│ │ │
|
||||
╔═════════════════╗│ │ │
|
||||
║Client uses the ░║│ │ │
|
||||
║ socket opened ║│ │ │
|
||||
║ with proxy ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─>
|
||||
║to communicate ║│ │ │
|
||||
║ ║│ │ │
|
||||
╚═════════════════╝┴───┐ ┌──┴──┐ ┌──┴───┐
|
||||
│Client│ │Proxy│ │Target│
|
||||
└──────┘ └─────┘ └──────┘
|
||||
|
||||
|
||||
# Configure and Building example
|
||||
|
||||
This example requires the proxy address to be configured. You can do this using the menuconfig option.
|
||||
Proxy address and port must be configured in order for this example to work.
|
||||
|
||||
If using Linux ssh can be used as a proxy for testing.
|
||||
|
||||
```
|
||||
ssh -N -v -D 0.0.0.0:1080 localhost
|
||||
```
|
||||
# Async operations composition and automatic lifetime control
|
||||
|
||||
For documentation about the structure of this example look into [async\_request README](../async_request/README.md).
|
2
components/asio/examples/socks4/main/CMakeLists.txt
Normal file
2
components/asio/examples/socks4/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "socks4.cpp"
|
||||
INCLUDE_DIRS ".")
|
16
components/asio/examples/socks4/main/Kconfig.projbuild
Normal file
16
components/asio/examples/socks4/main/Kconfig.projbuild
Normal file
@ -0,0 +1,16 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_PROXY_ADDRESS
|
||||
string "Proxy address"
|
||||
default "myproxy"
|
||||
help
|
||||
Address of the proxy to be used.
|
||||
|
||||
config EXAMPLE_PROXY_SERVICE
|
||||
string "Proxy Service Type"
|
||||
default "myport"
|
||||
help
|
||||
Service type. Due to a limitation of lwip, must
|
||||
be the port number e.g. "1080".
|
||||
|
||||
endmenu
|
393
components/asio/examples/socks4/main/socks4.cpp
Normal file
393
components/asio/examples/socks4/main/socks4.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*
|
||||
*
|
||||
* ASIO Socks4 example
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <asio.hpp>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include "esp_log.h"
|
||||
#include "socks4.hpp"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
constexpr auto TAG = "asio_socks4";
|
||||
using asio::ip::tcp;
|
||||
|
||||
namespace {
|
||||
|
||||
void esp_init()
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_log_level_set("async_request", ESP_LOG_DEBUG);
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simple class to add the resolver to a chain of actions
|
||||
*
|
||||
*/
|
||||
class AddressResolution : public std::enable_shared_from_this<AddressResolution> {
|
||||
public:
|
||||
explicit AddressResolution(asio::io_context &context) : ctx(context), resolver(ctx) {}
|
||||
|
||||
/**
|
||||
* @brief Initiator function for the address resolution
|
||||
*
|
||||
* @tparam CompletionToken callable responsible to use the results.
|
||||
*
|
||||
* @param host Host address
|
||||
* @param port Port for the target, must be number due to a limitation on lwip.
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void resolve(const std::string &host, const std::string &port, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
resolver.async_resolve(host, port, [self, completion_handler](const asio::error_code & error, tcp::resolver::results_type results) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Failed to resolve: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
completion_handler(self, results);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_context &ctx;
|
||||
tcp::resolver resolver;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Connection class
|
||||
*
|
||||
* The lowest level dependency on our asynchronous task, Connection provide an interface to TCP sockets.
|
||||
* A similar class could be provided for a TLS connection.
|
||||
*
|
||||
* @note: All read and write operations are written on an explicit strand, even though an implicit strand
|
||||
* occurs in this example since we run the io context in a single task.
|
||||
*
|
||||
*/
|
||||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
explicit Connection(asio::io_context &context) : ctx(context), strand(context), socket(ctx) {}
|
||||
|
||||
/**
|
||||
* @brief Start the connection
|
||||
*
|
||||
* Async operation to start a connection. As the final act of the process the Connection class pass a
|
||||
* std::shared_ptr of itself to the completion_handler.
|
||||
* Since it uses std::shared_ptr as an automatic control of its lifetime this class must be created
|
||||
* through a std::make_shared call.
|
||||
*
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
* @param host host address
|
||||
* @param port port number - due to a limitation on lwip implementation this should be the number not the
|
||||
* service name typically seen in ASIO examples.
|
||||
*
|
||||
* @note The class could be modified to store the completion handler, as a member variable, instead of
|
||||
* pass it along asynchronous calls to allow the process to run again completely.
|
||||
*
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void start(tcp::resolver::results_type results, CompletionToken &&completion_handler)
|
||||
{
|
||||
connect(results, completion_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an async write on the socket
|
||||
*
|
||||
* @tparam data
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
*
|
||||
*/
|
||||
template<class DataType, class CompletionToken>
|
||||
void write_async(const DataType &data, CompletionToken &&completion_handler)
|
||||
{
|
||||
asio::async_write(socket, data, asio::bind_executor(strand, completion_handler));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an async read on the socket
|
||||
*
|
||||
* @tparam data
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
*
|
||||
*/
|
||||
template<class DataBuffer, class CompletionToken>
|
||||
void read_async(DataBuffer &&in_data, CompletionToken &&completion_handler)
|
||||
{
|
||||
asio::async_read(socket, in_data, asio::bind_executor(strand, completion_handler));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<class CompletionToken>
|
||||
void connect(tcp::resolver::results_type results, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_connect(socket, results, [self, completion_handler](const asio::error_code & error, [[maybe_unused]] const tcp::endpoint & endpoint) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Failed to connect: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
completion_handler(self);
|
||||
});
|
||||
}
|
||||
asio::io_context &ctx;
|
||||
asio::io_context::strand strand;
|
||||
tcp::socket socket;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace Socks {
|
||||
|
||||
struct ConnectionData {
|
||||
ConnectionData(socks4::request::command_type cmd, const asio::ip::tcp::endpoint &endpoint,
|
||||
const std::string &user_id) : request(cmd, endpoint, user_id) {};
|
||||
socks4::request request;
|
||||
socks4::reply reply;
|
||||
};
|
||||
|
||||
template<class CompletionToken>
|
||||
void async_connect(asio::io_context &context, std::string proxy, std::string proxy_port, std::string host, std::string port, CompletionToken &&completion_handler)
|
||||
{
|
||||
/*
|
||||
* The first step is to resolve the address of the proxy we want to connect to.
|
||||
* The AddressResolution itself is injected to the completion handler.
|
||||
*/
|
||||
// Resolve proxy
|
||||
std::make_shared<AddressResolution>(context)->resolve(proxy, proxy_port,
|
||||
[&context, host, port, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type proxy_resolution) {
|
||||
// We also need to resolve the target host address
|
||||
resolver->resolve(host, port, [&context, proxy_resolution, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type host_resolution) {
|
||||
// Make connection with the proxy
|
||||
ESP_LOGI(TAG, "Startig Proxy Connection");
|
||||
std::make_shared<Connection>(context)->start(proxy_resolution,
|
||||
[resolver, host_resolution, completion_handler](std::shared_ptr<Connection> connection) {
|
||||
auto connect_data = std::make_shared<ConnectionData>(socks4::request::connect, *host_resolution, "");
|
||||
ESP_LOGI(TAG, "Sending Request to proxy for host connection.");
|
||||
connection->write_async(connect_data->request.buffers(), [connection, connect_data, completion_handler](std::error_code error, std::size_t bytes_received) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Proxy request write error: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
connection->read_async(connect_data->reply.buffers(), [connection, connect_data, completion_handler](std::error_code error, std::size_t bytes_received) {
|
||||
if (error) {
|
||||
|
||||
ESP_LOGE(TAG, "Proxy response read error: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
if (!connect_data->reply.success()) {
|
||||
ESP_LOGE(TAG, "Proxy error: %#x", connect_data->reply.status());
|
||||
}
|
||||
completion_handler(connection);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
} // namespace Socks
|
||||
|
||||
namespace Http {
|
||||
enum class Method { GET };
|
||||
|
||||
/**
|
||||
* @brief Simple HTTP request class
|
||||
*
|
||||
* The user needs to write the request information direct to header and body fields.
|
||||
*
|
||||
* Only GET verb is provided.
|
||||
*
|
||||
*/
|
||||
class Request {
|
||||
public:
|
||||
Request(Method method, std::string host, std::string port, const std::string &target) : host_data(std::move(host)), port_data(std::move(port))
|
||||
{
|
||||
header_data.append("GET ");
|
||||
header_data.append(target);
|
||||
header_data.append(" HTTP/1.1");
|
||||
header_data.append("\r\n");
|
||||
header_data.append("Host: ");
|
||||
header_data.append(host_data);
|
||||
header_data.append("\r\n");
|
||||
header_data.append("\r\n");
|
||||
};
|
||||
|
||||
void set_header_field(std::string const &field)
|
||||
{
|
||||
header_data.append(field);
|
||||
}
|
||||
|
||||
void append_to_body(std::string const &data)
|
||||
{
|
||||
body_data.append(data);
|
||||
};
|
||||
|
||||
const std::string &host() const
|
||||
{
|
||||
return host_data;
|
||||
}
|
||||
|
||||
const std::string &service_port() const
|
||||
{
|
||||
return port_data;
|
||||
}
|
||||
|
||||
const std::string &header() const
|
||||
{
|
||||
return header_data;
|
||||
}
|
||||
|
||||
const std::string &body() const
|
||||
{
|
||||
return body_data;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string host_data;
|
||||
std::string port_data;
|
||||
std::string header_data;
|
||||
std::string body_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Simple HTTP response class
|
||||
*
|
||||
* The response is built from received data and only parsed to split header and body.
|
||||
*
|
||||
* A copy of the received data is kept.
|
||||
*
|
||||
*/
|
||||
struct Response {
|
||||
/**
|
||||
* @brief Construct a response from a contiguous buffer.
|
||||
*
|
||||
* Simple http parsing.
|
||||
*
|
||||
*/
|
||||
template<class DataIt>
|
||||
explicit Response(DataIt data, size_t size)
|
||||
{
|
||||
raw_response = std::string(data, size);
|
||||
|
||||
auto header_last = raw_response.find("\r\n\r\n");
|
||||
if (header_last != std::string::npos) {
|
||||
header = raw_response.substr(0, header_last);
|
||||
}
|
||||
body = raw_response.substr(header_last + 3);
|
||||
}
|
||||
/**
|
||||
* @brief Print response content.
|
||||
*/
|
||||
void print()
|
||||
{
|
||||
ESP_LOGI(TAG, "Header :\n %s", header.c_str());
|
||||
ESP_LOGI(TAG, "Body : \n %s", body.c_str());
|
||||
}
|
||||
|
||||
std::string raw_response;
|
||||
std::string header;
|
||||
std::string body;
|
||||
};
|
||||
|
||||
/** @brief HTTP Session
|
||||
*
|
||||
* Session class to handle HTTP protocol implementation.
|
||||
*
|
||||
*/
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
public:
|
||||
explicit Session(std::shared_ptr<Connection> connection_in) : connection(std::move(connection_in))
|
||||
{
|
||||
}
|
||||
|
||||
template<class CompletionToken>
|
||||
void send_request(const Request &request, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
send_data = { asio::buffer(request.header()), asio::buffer(request.body()) };
|
||||
connection->write_async(send_data, [self, &completion_handler](std::error_code error, std::size_t bytes_transfered) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Request write error: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Bytes Transfered: %d", bytes_transfered);
|
||||
self->get_response(completion_handler);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
template<class CompletionToken>
|
||||
void get_response(CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
connection->read_async(asio::buffer(receive_buffer), [self, &completion_handler](std::error_code error, std::size_t bytes_received) {
|
||||
if (error and error.value() != asio::error::eof) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Bytes Received: %d", bytes_received);
|
||||
if (bytes_received == 0) {
|
||||
return;
|
||||
}
|
||||
Response response(std::begin(self->receive_buffer), bytes_received);
|
||||
|
||||
completion_handler(self, response);
|
||||
});
|
||||
}
|
||||
/*
|
||||
* For this example we assumed 2048 to be enough for the receive_buffer
|
||||
*/
|
||||
std::array<char, 2048> receive_buffer;
|
||||
/*
|
||||
* The hardcoded 2 below is related to the type we receive the data to send. We gather the parts from Request, header
|
||||
* and body, to send avoiding the copy.
|
||||
*/
|
||||
std::array<asio::const_buffer, 2> send_data;
|
||||
std::shared_ptr<Connection> connection;
|
||||
};
|
||||
}// namespace Http
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
// Basic initialization of ESP system
|
||||
esp_init();
|
||||
|
||||
asio::io_context io_context;
|
||||
Http::Request request(Http::Method::GET, "www.httpbin.org", "80", "/get");
|
||||
Socks::async_connect(io_context, CONFIG_EXAMPLE_PROXY_ADDRESS, CONFIG_EXAMPLE_PROXY_SERVICE, request.host(), request.service_port(),
|
||||
[&request](std::shared_ptr<Connection> connection) {
|
||||
// Now we create a HTTP::Session and inject the necessary connection.
|
||||
std::make_shared<Http::Session>(connection)->send_request(request, [](std::shared_ptr<Http::Session> session, Http::Response response) {
|
||||
response.print();
|
||||
});
|
||||
});
|
||||
// io_context.run will block until all the tasks on the context are done.
|
||||
io_context.run();
|
||||
ESP_LOGI(TAG, "Context run done");
|
||||
|
||||
ESP_ERROR_CHECK(example_disconnect());
|
||||
}
|
136
components/asio/examples/socks4/main/socks4.hpp
Normal file
136
components/asio/examples/socks4/main/socks4.hpp
Normal file
@ -0,0 +1,136 @@
|
||||
//
|
||||
// socks4.hpp
|
||||
// ~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef SOCKS4_HPP
|
||||
#define SOCKS4_HPP
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <asio/buffer.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
|
||||
namespace socks4 {
|
||||
|
||||
const unsigned char version = 0x04;
|
||||
|
||||
class request {
|
||||
public:
|
||||
enum command_type {
|
||||
connect = 0x01,
|
||||
bind = 0x02
|
||||
};
|
||||
|
||||
request(command_type cmd, const asio::ip::tcp::endpoint &endpoint,
|
||||
const std::string &user_id)
|
||||
: version_(version),
|
||||
command_(cmd),
|
||||
user_id_(user_id),
|
||||
null_byte_(0)
|
||||
{
|
||||
// Only IPv4 is supported by the SOCKS 4 protocol.
|
||||
if (endpoint.protocol() != asio::ip::tcp::v4()) {
|
||||
throw asio::system_error(
|
||||
asio::error::address_family_not_supported);
|
||||
}
|
||||
|
||||
// Convert port number to network byte order.
|
||||
unsigned short port = endpoint.port();
|
||||
port_high_byte_ = (port >> 8) & 0xff;
|
||||
port_low_byte_ = port & 0xff;
|
||||
|
||||
// Save IP address in network byte order.
|
||||
address_ = endpoint.address().to_v4().to_bytes();
|
||||
}
|
||||
|
||||
std::array<asio::const_buffer, 7> buffers() const
|
||||
{
|
||||
return {
|
||||
{
|
||||
asio::buffer(&version_, 1),
|
||||
asio::buffer(&command_, 1),
|
||||
asio::buffer(&port_high_byte_, 1),
|
||||
asio::buffer(&port_low_byte_, 1),
|
||||
asio::buffer(address_),
|
||||
asio::buffer(user_id_),
|
||||
asio::buffer(&null_byte_, 1)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char version_;
|
||||
unsigned char command_;
|
||||
unsigned char port_high_byte_;
|
||||
unsigned char port_low_byte_;
|
||||
asio::ip::address_v4::bytes_type address_;
|
||||
std::string user_id_;
|
||||
unsigned char null_byte_;
|
||||
};
|
||||
|
||||
class reply {
|
||||
public:
|
||||
enum status_type {
|
||||
request_granted = 0x5a,
|
||||
request_failed = 0x5b,
|
||||
request_failed_no_identd = 0x5c,
|
||||
request_failed_bad_user_id = 0x5d
|
||||
};
|
||||
|
||||
reply()
|
||||
: null_byte_(0),
|
||||
status_()
|
||||
{
|
||||
}
|
||||
|
||||
std::array<asio::mutable_buffer, 5> buffers()
|
||||
{
|
||||
return {
|
||||
{
|
||||
asio::buffer(&null_byte_, 1),
|
||||
asio::buffer(&status_, 1),
|
||||
asio::buffer(&port_high_byte_, 1),
|
||||
asio::buffer(&port_low_byte_, 1),
|
||||
asio::buffer(address_)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool success() const
|
||||
{
|
||||
return null_byte_ == 0 && status_ == request_granted;
|
||||
}
|
||||
|
||||
unsigned char status() const
|
||||
{
|
||||
return status_;
|
||||
}
|
||||
|
||||
asio::ip::tcp::endpoint endpoint() const
|
||||
{
|
||||
unsigned short port = port_high_byte_;
|
||||
port = (port << 8) & 0xff00;
|
||||
port = port | port_low_byte_;
|
||||
|
||||
asio::ip::address_v4 address(address_);
|
||||
|
||||
return asio::ip::tcp::endpoint(address, port);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char null_byte_;
|
||||
unsigned char status_;
|
||||
unsigned char port_high_byte_;
|
||||
unsigned char port_low_byte_;
|
||||
asio::ip::address_v4::bytes_type address_;
|
||||
};
|
||||
|
||||
} // namespace socks4
|
||||
|
||||
#endif // SOCKS4_HPP
|
3
components/asio/examples/socks4/sdkconfig.defaults
Normal file
3
components/asio/examples/socks4/sdkconfig.defaults
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_RTTI=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
|
11
components/asio/examples/ssl_client_server/CMakeLists.txt
Normal file
11
components/asio/examples/ssl_client_server/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
set(EXCLUDE_COMPONENTS openssl)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_ssl_client_server)
|
88
components/asio/examples/ssl_client_server/README.md
Normal file
88
components/asio/examples/ssl_client_server/README.md
Normal file
@ -0,0 +1,88 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
|
||||
# Asio SSL client/server example
|
||||
|
||||
Simple Asio client and server with SSL/TLS transport
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP platform board. No external connection is required, it is recommended though
|
||||
to connect to internet or a local network via WiFi or Ethernet to easily exercise features of this example.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
* Enable the ASIO client and set server's host name to examine client's functionality.
|
||||
The ASIO client connects to the configured server and sends default payload string "GET / HTTP/1.1"
|
||||
* Enable the ASIO server to examine server's functionality. The ASIO server listens to connection and echos back what was received.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
### Client connecting to public server
|
||||
|
||||
The below output illustrates the client connecting to a public https server.
|
||||
|
||||
```
|
||||
I (1267) example_connect: Waiting for IP(s)
|
||||
I (2587) wifi:new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1
|
||||
I (3367) wifi:state: init -> auth (b0)
|
||||
I (3377) wifi:state: auth -> assoc (0)
|
||||
I (3387) wifi:state: assoc -> run (10)
|
||||
I (3397) wifi:security type: 3, phy: bgn, rssi: -49
|
||||
I (3397) wifi:pm start, type: 1
|
||||
I (3457) wifi:AP's beacon interval = 102400 us, DTIM period = 1
|
||||
I (4747) example_connect: Got IPv6 event: Interface "example_connect: sta" address: fe80:0000:0000:0000:260a:xxxx:xxxx:xxxx, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (5247) esp_netif_handlers: example_connect: sta ip: 192.168.32.69, mask: 255.255.252.0, gw: 192.168.32.3
|
||||
I (5247) example_connect: Got IPv4 event: Interface "example_connect: sta" address: 192.168.32.69
|
||||
I (5257) example_connect: Connected to example_connect: sta
|
||||
I (5257) example_connect: - IPv4 address: 192.168.32.69
|
||||
I (5267) example_connect: - IPv6 address: fe80:0000:0000:0000:260a:xxxx:xxxx:xxxx, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
W (5277) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
W (5297) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
Reply: HTTP/1.1 200 OK
|
||||
D
|
||||
```
|
||||
### Both server and client enabled
|
||||
|
||||
The below output demonstrates the client connecting to the ASIO server via loopback interface, so no WiFi, nor Ethernet connection
|
||||
was established.
|
||||
```
|
||||
I (0) cpu_start: App cpu up.
|
||||
I (495) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (502) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
|
||||
I (508) heap_init: At 3FFB5400 len 0002AC00 (171 KiB): DRAM
|
||||
I (515) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
|
||||
I (521) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
|
||||
I (527) heap_init: At 4008BB80 len 00014480 (81 KiB): IRAM
|
||||
I (534) cpu_start: Pro cpu start user code
|
||||
I (556) spi_flash: detected chip: gd
|
||||
I (556) spi_flash: flash io: dio
|
||||
W (556) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
|
||||
I (566) cpu_start: Starting scheduler on PRO CPU.
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (600) example_connect: Waiting for IP(s)
|
||||
W (600) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
W (1610) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
W (1610) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
Server received: GET / HTTP/1.1
|
||||
|
||||
|
||||
Reply: GET / HTTP/1.1
|
||||
```
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "asio_ssl_main.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
EMBED_TXTFILES ca.crt server.key srv.crt)
|
@ -0,0 +1,36 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_CLIENT
|
||||
bool "Enable TLS client"
|
||||
default y
|
||||
help
|
||||
Choose this option to use ASIO TLS/SSL client functionality
|
||||
|
||||
config EXAMPLE_PORT
|
||||
string "ASIO port number"
|
||||
default "443"
|
||||
help
|
||||
Port number used by ASIO example.
|
||||
|
||||
config EXAMPLE_SERVER
|
||||
bool "Enable TLS server"
|
||||
default n
|
||||
help
|
||||
Choose this option to use ASIO TLS/SSL server functionality
|
||||
|
||||
config EXAMPLE_SERVER_NAME
|
||||
string "ASIO server name or IP"
|
||||
default "www.google.com"
|
||||
depends on EXAMPLE_CLIENT
|
||||
help
|
||||
Asio example server ip for the ASIO client to connect to.
|
||||
|
||||
config EXAMPLE_CLIENT_VERIFY_PEER
|
||||
bool "Client to verify peer"
|
||||
default n
|
||||
depends on EXAMPLE_CLIENT
|
||||
help
|
||||
This option sets client's mode to verify peer, default is
|
||||
verify-none
|
||||
|
||||
endmenu
|
@ -0,0 +1,272 @@
|
||||
//
|
||||
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "asio.hpp"
|
||||
#include "asio/ssl.hpp"
|
||||
#include "asio/buffer.hpp"
|
||||
#include "esp_pthread.h"
|
||||
|
||||
extern const unsigned char server_pem_start[] asm("_binary_srv_crt_start");
|
||||
extern const unsigned char server_pem_end[] asm("_binary_srv_crt_end");
|
||||
|
||||
extern const unsigned char cacert_pem_start[] asm("_binary_ca_crt_start");
|
||||
extern const unsigned char cacert_pem_end[] asm("_binary_ca_crt_end");
|
||||
|
||||
extern const unsigned char prvtkey_pem_start[] asm("_binary_server_key_start");
|
||||
extern const unsigned char prvtkey_pem_end[] asm("_binary_server_key_end");
|
||||
|
||||
static const asio::const_buffer cert_chain(cacert_pem_start, cacert_pem_end - cacert_pem_start);
|
||||
static const asio::const_buffer privkey(prvtkey_pem_start, prvtkey_pem_end - prvtkey_pem_start);
|
||||
static const asio::const_buffer server_cert(server_pem_start, server_pem_end - server_pem_start);
|
||||
|
||||
using asio::ip::tcp;
|
||||
|
||||
static const std::size_t max_length = 1024;
|
||||
|
||||
class Client {
|
||||
public:
|
||||
Client(asio::io_context &io_context,
|
||||
asio::ssl::context &context,
|
||||
const tcp::resolver::results_type &endpoints)
|
||||
: socket_(io_context, context)
|
||||
{
|
||||
|
||||
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
socket_.set_verify_mode(asio::ssl::verify_peer);
|
||||
#else
|
||||
socket_.set_verify_mode(asio::ssl::verify_none);
|
||||
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
|
||||
connect(endpoints);
|
||||
}
|
||||
|
||||
private:
|
||||
void connect(const tcp::resolver::results_type &endpoints)
|
||||
{
|
||||
asio::async_connect(socket_.lowest_layer(), endpoints,
|
||||
[this](const std::error_code & error,
|
||||
const tcp::endpoint & /*endpoint*/) {
|
||||
if (!error) {
|
||||
handshake();
|
||||
} else {
|
||||
std::cout << "Connect failed: " << error.message() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void handshake()
|
||||
{
|
||||
socket_.async_handshake(asio::ssl::stream_base::client,
|
||||
[this](const std::error_code & error) {
|
||||
if (!error) {
|
||||
send_request();
|
||||
} else {
|
||||
std::cout << "Handshake failed: " << error.message() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void send_request()
|
||||
{
|
||||
size_t request_length = std::strlen(request_);
|
||||
|
||||
asio::async_write(socket_,
|
||||
asio::buffer(request_, request_length),
|
||||
[this](const std::error_code & error, std::size_t length) {
|
||||
if (!error) {
|
||||
receive_response(length);
|
||||
} else {
|
||||
std::cout << "Write failed: " << error.message() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void receive_response(std::size_t length)
|
||||
{
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(reply_, length),
|
||||
[this](const std::error_code & error, std::size_t length) {
|
||||
if (!error) {
|
||||
std::cout << "Reply: ";
|
||||
std::cout.write(reply_, length);
|
||||
std::cout << "\n";
|
||||
} else {
|
||||
std::cout << "Read failed: " << error.message() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
asio::ssl::stream<tcp::socket> socket_;
|
||||
char request_[max_length] = "GET / HTTP/1.1\r\n\r\n";
|
||||
char reply_[max_length];
|
||||
};
|
||||
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
public:
|
||||
Session(tcp::socket socket, asio::ssl::context &context)
|
||||
: socket_(std::move(socket), context)
|
||||
{
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
do_handshake();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_handshake()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
socket_.async_handshake(asio::ssl::stream_base::server,
|
||||
[this, self](const std::error_code & error) {
|
||||
if (!error) {
|
||||
do_read();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_read()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
socket_.async_read_some(asio::buffer(data_),
|
||||
[this, self](const std::error_code & ec, std::size_t length) {
|
||||
if (!ec) {
|
||||
std::cout << "Server received: ";
|
||||
std::cout.write(data_, length);
|
||||
std::cout << std::endl;
|
||||
do_write(length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_write(std::size_t length)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_write(socket_, asio::buffer(data_, length),
|
||||
[this, self](const std::error_code & ec,
|
||||
std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
do_read();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
asio::ssl::stream<tcp::socket> socket_;
|
||||
char data_[max_length];
|
||||
};
|
||||
|
||||
class Server {
|
||||
public:
|
||||
Server(asio::io_context &io_context, unsigned short port)
|
||||
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port)),
|
||||
context_(asio::ssl::context::tls_server)
|
||||
{
|
||||
context_.set_options(
|
||||
asio::ssl::context::default_workarounds
|
||||
| asio::ssl::context::no_sslv2);
|
||||
context_.use_certificate_chain(server_cert);
|
||||
context_.use_private_key(privkey, asio::ssl::context::pem);
|
||||
|
||||
do_accept();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_accept()
|
||||
{
|
||||
acceptor_.async_accept(
|
||||
[this](const std::error_code & error, tcp::socket socket) {
|
||||
if (!error) {
|
||||
std::make_shared<Session>(std::move(socket), context_)->start();
|
||||
}
|
||||
|
||||
do_accept();
|
||||
});
|
||||
}
|
||||
|
||||
tcp::acceptor acceptor_;
|
||||
asio::ssl::context context_;
|
||||
};
|
||||
|
||||
void set_thread_config(const char *name, int stack, int prio)
|
||||
{
|
||||
auto cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name = name;
|
||||
cfg.stack_size = stack;
|
||||
cfg.prio = prio;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
}
|
||||
|
||||
void ssl_server_thread()
|
||||
{
|
||||
asio::io_context io_context;
|
||||
|
||||
Server s(io_context, 443);
|
||||
|
||||
io_context.run();
|
||||
}
|
||||
|
||||
void ssl_client_thread()
|
||||
{
|
||||
asio::io_context io_context;
|
||||
|
||||
tcp::resolver resolver(io_context);
|
||||
std::string server_ip = CONFIG_EXAMPLE_SERVER_NAME;
|
||||
std::string server_port = CONFIG_EXAMPLE_PORT;
|
||||
auto endpoints = resolver.resolve(server_ip, server_port);
|
||||
|
||||
asio::ssl::context ctx(asio::ssl::context::tls_client);
|
||||
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
ctx.add_certificate_authority(cert_chain);
|
||||
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
|
||||
Client c(io_context, ctx, endpoints);
|
||||
|
||||
io_context.run();
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
esp_netif_init();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
/* This helper function configures blocking UART I/O */
|
||||
ESP_ERROR_CHECK(example_configure_stdin_stdout());
|
||||
std::vector<std::thread> work_threads;
|
||||
|
||||
#if CONFIG_EXAMPLE_SERVER
|
||||
set_thread_config("Server", 16 * 1024, 5);
|
||||
work_threads.emplace_back(std::thread(ssl_server_thread));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
#endif // CONFIG_EXAMPLE_SERVER
|
||||
|
||||
#if CONFIG_EXAMPLE_CLIENT
|
||||
set_thread_config("Client", 16 * 1024, 5);
|
||||
work_threads.emplace_back(ssl_client_thread);
|
||||
#endif // CONFIG_EXAMPLE_CLIENT
|
||||
|
||||
for (auto &t : work_threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
}
|
22
components/asio/examples/ssl_client_server/main/ca.crt
Normal file
22
components/asio/examples/ssl_client_server/main/ca.crt
Normal file
@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkzCCAnugAwIBAgIUNI5wldYysh6rtCzYmda6H414aRswDQYJKoZIhvcNAQEL
|
||||
BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMB4X
|
||||
DTIwMDEyMTA5MDk0NloXDTI1MDEyMDA5MDk0NlowWTELMAkGA1UEBhMCQVUxEzAR
|
||||
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
|
||||
IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAyadSpRnIQBVbEAsbpkrKrOMlBOMIUmA8AfNyOYPLfv0Oa5lBiMAV
|
||||
3OQDu5tYyFYKwkCUqq65iAm50fPbSH71w1tkja6nZ1yAIM+TvpMlM/WiFGrhY+Tc
|
||||
kAcLcKUJyPxrv/glzoVslbqUgIhuhCSKA8uk1+ILcn3nWzPcbcowLx31+AHeZj8h
|
||||
bIAdj6vjqxMCFStp4IcA+ikmCk75LCN4vkkifdkebb/ZDNYCZZhpCBnCHyFAjPc4
|
||||
7C+FDVGT3/UUeeTy+Mtn+MqUAhB+W0sPDm1n2h59D4Z/MFm0hl6GQCAKeMJPzssU
|
||||
BBsRm6zoyPQ4VTqG0uwfNNbORyIfKONMUwIDAQABo1MwUTAdBgNVHQ4EFgQUGYLV
|
||||
EkgWzxjpltE6texha7zZVxowHwYDVR0jBBgwFoAUGYLVEkgWzxjpltE6texha7zZ
|
||||
VxowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAb2EF4Zg2XWNb
|
||||
eZHnzupCDd9jAhwPqkt7F1OXvxJa/RFUSB9+2izGvikGGhuKY4f0iLuqF+bhExD9
|
||||
sapDcdFO2Suh4J3onbwEvmKvsv56K3xhapYg8WwPofpkVirnkwFjpQXGzrYxPujg
|
||||
BPmSy3psQrhvOr/WH7SefJv2qr4ikaugfE+3enY4PL+C1dSQAuNo1QGgWsZIu0c8
|
||||
TZybNZ13vNVMA+tgj2CM8FR3Etaabwtu3TTcAnO7aoBTix/bLBTuZoczhN8/MhG3
|
||||
GylmDzFI8a6aKxQL3Fi4PsM82hRKWu3gfs39sR1Ci4V22v8uO5EWBPK0QZvDSc1a
|
||||
KwwxI4zA0w==
|
||||
-----END CERTIFICATE-----
|
27
components/asio/examples/ssl_client_server/main/server.key
Normal file
27
components/asio/examples/ssl_client_server/main/server.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAlUCywNhVv4RO2y9h/XGKZ1azzk3jzHpSBzIGO9LoiA8trC/p
|
||||
1ykGaUfYPJllYK4HMhC4fUyE3J7tVL2Eskzl26LNPLbEoaBWZM9NhV3iA1/1EtOu
|
||||
p6umLx+y3sDfvK35YAOUbjdAlBfhnJ4r8h7oTsxl3J5jZ18zgjJnJi2NEFq/yTpO
|
||||
MiwHLWPjy25fDFixfV9UzSvbgt1JaGPmC7c4QkhHzjyp0+ikuvRIw0p9BBNeqBV2
|
||||
da3qBMB5FtodUJTAz6o6OKWbTalLjQi6C1H6z9TnY7IrJBUOy/FWkQH/sEsLdscD
|
||||
hHa1Dz2oT203QjhzyOSfnNF95D/1MdNcMt6l0wIDAQABAoIBAC1JJTOoMFRc48RT
|
||||
myrYQYNbZlEphv3q+2qdfhC2zMFDwbrmCtCy7PQSzYSNkpoEE8DYG/JAvmtmeWJl
|
||||
4pZrCK9ctWM/nWfhC3WpBL97nfEiM20T94F+bn0L5Cz8XqaULv839th+QUTt/hGU
|
||||
WIctY5VNJXcMQ+MAmtNdUbjex1d3iuxiKHUo4nDoZ8digKFNdtdP5B5nlMq5chCL
|
||||
mxNRcsGsx2dDAxbGUapdTVPWHPJKpLOBoSkluDsfd2KZADFU2R1SJpAX9+RYh3HM
|
||||
5FTUdHTUaISxbKkgeDKlEM0lqk2TtGUwCyEj098ewi7Wzsu9w60IplPPUJx5FRG6
|
||||
jp3wzLkCgYEAxKp5T20rf/7ysX7x053I7VCjDXUxAaWOEj1uS3AhOkl0NaZg7Di+
|
||||
y53fWNkcHdkt2n2LqMt/43UgMYq3TVVcq2eunPNF11e1bJw8CjDafwDs4omwwyVn
|
||||
lYhPuB4dK2OAib+vU5Zqpp0kZMoxk2MZVgon8z+s8DW/zmB6aFqAWeUCgYEAwkhC
|
||||
OgmXKMdjOCVy5t2f5UbY8Y9rV3w8eUATuJ47MMwLr4pGYnKoEn9JB4ltWrHv/u5S
|
||||
fOv3tIrrCEvnCoCbOILwCsY5LqTNXgqova8FB6RpMUQCzhDd8LHuvdHv0WMnMzX1
|
||||
3PKuqwh8JS55m4WqZRhzr5BFKG4fHPVs4IcaJVcCgYAzzCaJSdqUKqTnJOUydDNQ
|
||||
ddWMHNqccWs62J0tF0pZHLGT089hSAzQejMyJnSmU+Ykzr4y5e44DUg+ZCelIZ93
|
||||
saYmxlgVwI8THQ8fLADQRIEfpV4996MRmkZM2vmZzOo03Zyi6lIKsga82Rg3lnk8
|
||||
1Q3ynknBNpbfF0AGLhfyFQKBgBYlxJ73HutAJ5hr9HhLBYJOnEaVUehMOlycKGNg
|
||||
bmD2sdJWEgYBChXpurqIORYguLo4EuE4ySkkuPxeIr14wbkkfBbOWBBwKxUwY+IT
|
||||
xKAFZxR9q1AwbgyVTCEJgKw/AGX/HcMNS0omEnjunmBTUYRq0C1QZgHg490aQUor
|
||||
PJjLAoGAevzdTpFlVeuKeYh1oDubGO1LinyXpBv7fPFjl+zu4AVbjojcU6yC4OO6
|
||||
QvqopE6SyAECKy8kAOFcESPsGc9Lta2XUvI203z7pIVlNVEcJ0+90mQh3Mn1U46l
|
||||
sZ49PdRvNwNb5wvkh1UqNsMlGFbRlzMbIk45ou4311kCobowZek=
|
||||
-----END RSA PRIVATE KEY-----
|
18
components/asio/examples/ssl_client_server/main/srv.crt
Normal file
18
components/asio/examples/ssl_client_server/main/srv.crt
Normal file
@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC9DCCAdwCFA1lSIcHwYKdB2UqOrZxZnVgPObTMA0GCSqGSIb3DQEBCwUAMFkx
|
||||
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
|
||||
cm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yMDA2
|
||||
MTIwNjA0MTNaFw0yMjA2MDIwNjA0MTNaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJVAssDYVb+ETtsvYf1ximdW
|
||||
s85N48x6UgcyBjvS6IgPLawv6dcpBmlH2DyZZWCuBzIQuH1MhNye7VS9hLJM5dui
|
||||
zTy2xKGgVmTPTYVd4gNf9RLTrqerpi8fst7A37yt+WADlG43QJQX4ZyeK/Ie6E7M
|
||||
ZdyeY2dfM4IyZyYtjRBav8k6TjIsBy1j48tuXwxYsX1fVM0r24LdSWhj5gu3OEJI
|
||||
R848qdPopLr0SMNKfQQTXqgVdnWt6gTAeRbaHVCUwM+qOjilm02pS40IugtR+s/U
|
||||
52OyKyQVDsvxVpEB/7BLC3bHA4R2tQ89qE9tN0I4c8jkn5zRfeQ/9THTXDLepdMC
|
||||
AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnMYGW+idt37bEE4WPgrRorKWuplR+zHD
|
||||
wJFz53DQzyIZJHmJ2hR5U0jNcHy/nMq7tbdz9LZPrVF4lZJ3TJhnmkOKjMFPCQE8
|
||||
YcmsP3il6eXgtGqg53InOi/uJqEQ9TfM54cbpp6xKbnmpwk4uprISBRQt7u2ZLk2
|
||||
40ED6zgjFPDTYmSjSpb2AN6KUB6PflgVs+4p9ViHNq4U3AlYV/BM0+3G4aMX2wNl
|
||||
ZIpQfOyuaYD5MU50mY+O+gDiiypkpYf6a6S4YJ1sMbavDsP7bW5UMnP0jKYR549q
|
||||
5hF1fdkXq52DfJ9ya2kl3mANFkKssQV+1KCBMxGoeqfakmJfa03xXA==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1400000,
|
|
@ -0,0 +1,7 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
def test_examples_asio_ssl(dut):
|
||||
dut.expect('Reply: GET / HTTP/1.1')
|
6
components/asio/examples/ssl_client_server/sdkconfig.ci
Normal file
6
components/asio/examples/ssl_client_server/sdkconfig.ci
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_EXAMPLE_CLIENT=y
|
||||
CONFIG_EXAMPLE_SERVER=y
|
||||
CONFIG_EXAMPLE_SERVER_NAME="localhost"
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||
CONFIG_EXAMPLE_CLIENT_VERIFY_PEER=y
|
@ -0,0 +1,10 @@
|
||||
CONFIG_ASIO_SSL_SUPPORT=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
# Leave some room for larger apps without needing to reduce other features
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
10
components/asio/examples/tcp_echo_server/CMakeLists.txt
Normal file
10
components/asio/examples/tcp_echo_server/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_tcp_echo_server)
|
22
components/asio/examples/tcp_echo_server/README.md
Normal file
22
components/asio/examples/tcp_echo_server/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
|
||||
# Asio TCP echo server example
|
||||
|
||||
Simple Asio TCP echo server using WiFi STA or Ethernet.
|
||||
|
||||
## Example workflow
|
||||
|
||||
- Wi-Fi or Ethernet connection is established, and IP address is obtained.
|
||||
- Asio TCP server is started on port number defined through the project configuration.
|
||||
- Server receives and echoes back messages transmitted from client.
|
||||
|
||||
## Running the example
|
||||
|
||||
- Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
- Set server port number in menuconfig, "Example configuration".
|
||||
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
||||
- Wait for the board to connect to WiFi or Ethernet (note the IP address).
|
||||
- You can now send a TCP message and check it is repeated, for example using netcat `nc IP PORT`.
|
||||
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "echo_server.cpp"
|
||||
INCLUDE_DIRS ".")
|
@ -0,0 +1,9 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_PORT
|
||||
string "Asio example port number"
|
||||
default "2222"
|
||||
help
|
||||
Port number used by Asio example.
|
||||
|
||||
endmenu
|
105
components/asio/examples/tcp_echo_server/main/echo_server.cpp
Normal file
105
components/asio/examples/tcp_echo_server/main/echo_server.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "asio.hpp"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
using asio::ip::tcp;
|
||||
|
||||
class session
|
||||
: public std::enable_shared_from_this<session> {
|
||||
public:
|
||||
session(tcp::socket socket)
|
||||
: socket_(std::move(socket))
|
||||
{
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
do_read();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_read()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
socket_.async_read_some(asio::buffer(data_, max_length),
|
||||
[this, self](std::error_code ec, std::size_t length) {
|
||||
if (!ec) {
|
||||
data_[length] = 0;
|
||||
std::cout << data_ << std::endl;
|
||||
do_write(length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_write(std::size_t length)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_write(socket_, asio::buffer(data_, length),
|
||||
[this, self](std::error_code ec, std::size_t length) {
|
||||
if (!ec) {
|
||||
do_read();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tcp::socket socket_;
|
||||
enum { max_length = 1024 };
|
||||
char data_[max_length];
|
||||
};
|
||||
|
||||
class server {
|
||||
public:
|
||||
server(asio::io_context &io_context, short port)
|
||||
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
|
||||
{
|
||||
do_accept();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_accept()
|
||||
{
|
||||
acceptor_.async_accept(
|
||||
[this](std::error_code ec, tcp::socket socket) {
|
||||
if (!ec) {
|
||||
std::make_shared<session>(std::move(socket))->start();
|
||||
}
|
||||
|
||||
do_accept();
|
||||
});
|
||||
}
|
||||
|
||||
tcp::acceptor acceptor_;
|
||||
};
|
||||
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
esp_netif_init();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
/* This helper function configures blocking UART I/O */
|
||||
ESP_ERROR_CHECK(example_configure_stdin_stdout());
|
||||
|
||||
asio::io_context io_context;
|
||||
|
||||
server s(io_context, std::atoi(CONFIG_EXAMPLE_PORT));
|
||||
|
||||
std::cout << "ASIO engine is up and running" << std::endl;
|
||||
|
||||
io_context.run();
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import re
|
||||
import socket
|
||||
|
||||
|
||||
def test_examples_protocol_asio_tcp_server(dut):
|
||||
"""
|
||||
steps: |
|
||||
1. join AP
|
||||
2. Start server
|
||||
3. Test connects to server and sends a test message
|
||||
4. Test evaluates received test message from server
|
||||
5. Test evaluates received test message on server stdout
|
||||
"""
|
||||
test_msg = b'echo message from client to server'
|
||||
# 2. get the server IP address
|
||||
data = dut.expect(
|
||||
re.compile(
|
||||
b' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), # noqa: W605
|
||||
timeout=30).group(1).decode()
|
||||
# 3. create tcp client and connect to server
|
||||
dut.expect('ASIO engine is up and running', timeout=1)
|
||||
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
cli.settimeout(30)
|
||||
cli.connect((data, 2222))
|
||||
cli.send(test_msg)
|
||||
data = cli.recv(1024)
|
||||
# 4. check the message received back from the server
|
||||
if (data == test_msg):
|
||||
print('PASS: Received correct message')
|
||||
pass
|
||||
else:
|
||||
print('Failure!')
|
||||
raise ValueError(
|
||||
'Wrong data received from asi tcp server: {} (expected:{})'.format(
|
||||
data, test_msg))
|
||||
# 5. check the client message appears also on server terminal
|
||||
dut.expect(test_msg.decode())
|
2
components/asio/examples/tcp_echo_server/sdkconfig.ci
Normal file
2
components/asio/examples/tcp_echo_server/sdkconfig.ci
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
@ -0,0 +1,7 @@
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
# Leave some room for larger apps without needing to reduce other features
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
10
components/asio/examples/udp_echo_server/CMakeLists.txt
Normal file
10
components/asio/examples/udp_echo_server/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../ ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_udp_echo_server)
|
22
components/asio/examples/udp_echo_server/README.md
Normal file
22
components/asio/examples/udp_echo_server/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
|
||||
# Asio UDP echo server example
|
||||
|
||||
Simple Asio UDP echo server using WiFi STA or Ethernet.
|
||||
|
||||
## Example workflow
|
||||
|
||||
- Wi-Fi or Ethernet connection is established, and IP address is obtained.
|
||||
- Asio UDP server is started on port number defined through the project configuration
|
||||
- Server receives and echoes back messages transmitted from client
|
||||
|
||||
## Running the example
|
||||
|
||||
- Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
- Set server port number in menuconfig, "Example configuration".
|
||||
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
||||
- Wait for the board to connect to WiFi or Ethernet (note the IP address).
|
||||
- You can now send a UDP message and check it is repeated, for example using netcat `nc -u IP PORT`.
|
||||
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "udp_echo_server.cpp"
|
||||
INCLUDE_DIRS ".")
|
@ -0,0 +1,9 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_PORT
|
||||
string "Asio example port number"
|
||||
default "2222"
|
||||
help
|
||||
Port number used by Asio example.
|
||||
|
||||
endmenu
|
@ -0,0 +1,84 @@
|
||||
//
|
||||
// async_udp_echo_server.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "asio.hpp"
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
|
||||
using asio::ip::udp;
|
||||
|
||||
class server {
|
||||
public:
|
||||
server(asio::io_context &io_context, short port)
|
||||
: socket_(io_context, udp::endpoint(udp::v4(), port))
|
||||
{
|
||||
do_receive();
|
||||
}
|
||||
|
||||
void do_receive()
|
||||
{
|
||||
socket_.async_receive_from(
|
||||
asio::buffer(data_, max_length), sender_endpoint_,
|
||||
[this](std::error_code ec, std::size_t bytes_recvd) {
|
||||
if (!ec && bytes_recvd > 0) {
|
||||
data_[bytes_recvd] = 0;
|
||||
std::cout << data_ << std::endl;
|
||||
do_send(bytes_recvd);
|
||||
} else {
|
||||
do_receive();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_send(std::size_t length)
|
||||
{
|
||||
socket_.async_send_to(
|
||||
asio::buffer(data_, length), sender_endpoint_,
|
||||
[this](std::error_code /*ec*/, std::size_t bytes /*bytes_sent*/) {
|
||||
do_receive();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
udp::socket socket_;
|
||||
udp::endpoint sender_endpoint_;
|
||||
enum { max_length = 1024 };
|
||||
char data_[max_length];
|
||||
};
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
esp_netif_init();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
/* This helper function configures blocking UART I/O */
|
||||
ESP_ERROR_CHECK(example_configure_stdin_stdout());
|
||||
|
||||
asio::io_context io_context;
|
||||
|
||||
server s(io_context, std::atoi(CONFIG_EXAMPLE_PORT));
|
||||
|
||||
std::cout << "ASIO engine is up and running" << std::endl;
|
||||
|
||||
io_context.run();
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import re
|
||||
import socket
|
||||
|
||||
|
||||
def test_examples_protocol_asio_udp_server(dut):
|
||||
"""
|
||||
steps: |
|
||||
1. join AP
|
||||
2. Start server
|
||||
3. Test connects to server and sends a test message
|
||||
4. Test evaluates received test message from server
|
||||
5. Test evaluates received test message on server stdout
|
||||
"""
|
||||
test_msg = b'echo message from client to server'
|
||||
data = dut.expect(
|
||||
re.compile(
|
||||
b' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), # noqa: W605
|
||||
timeout=30).group(1).decode()
|
||||
dut.expect('ASIO engine is up and running', timeout=1)
|
||||
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
cli.settimeout(30)
|
||||
cli.connect((data, 2222))
|
||||
cli.send(test_msg)
|
||||
data = cli.recv(1024)
|
||||
# 4. check the message received back from the server
|
||||
if (data == test_msg):
|
||||
print('PASS: Received correct message')
|
||||
pass
|
||||
else:
|
||||
print('Failure!')
|
||||
raise ValueError(
|
||||
'Wrong data received from asio udp server: {} (expected:{})'.
|
||||
format(data, test_msg))
|
||||
# 5. check the client message appears also on server terminal
|
||||
dut.expect(test_msg.decode())
|
2
components/asio/examples/udp_echo_server/sdkconfig.ci
Normal file
2
components/asio/examples/udp_echo_server/sdkconfig.ci
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
@ -0,0 +1,7 @@
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
# Leave some room for larger apps without needing to reduce other features
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
6
components/asio/idf_component.yml
Normal file
6
components/asio/idf_component.yml
Normal file
@ -0,0 +1,6 @@
|
||||
version: "1.14.1~3"
|
||||
description: ASIO
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/asio
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.0"
|
45
components/asio/port/include/esp_asio_config.h
Normal file
45
components/asio/port/include/esp_asio_config.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_ASIO_CONFIG_H_
|
||||
#define _ESP_ASIO_CONFIG_H_
|
||||
|
||||
//
|
||||
// Enabling exceptions only when they are enabled in menuconfig
|
||||
//
|
||||
# include <sdkconfig.h>
|
||||
# ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
# define ASIO_NO_EXCEPTIONS
|
||||
# endif // CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
|
||||
# ifndef CONFIG_COMPILER_RTTI
|
||||
# define ASIO_NO_TYPEID
|
||||
# endif // CONFIG_COMPILER_RTTI
|
||||
|
||||
//
|
||||
// Use system sockets
|
||||
//
|
||||
# include "sys/socket.h"
|
||||
|
||||
//
|
||||
// Specific ASIO feature flags
|
||||
//
|
||||
# define ASIO_DISABLE_SERIAL_PORT
|
||||
# define ASIO_SEPARATE_COMPILATION
|
||||
# define ASIO_STANDALONE
|
||||
# define ASIO_HAS_PTHREADS
|
||||
# define ASIO_DISABLE_CONCEPTS
|
||||
|
||||
# ifdef CONFIG_ASIO_USE_ESP_OPENSSL
|
||||
# define ASIO_USE_ESP_OPENSSL
|
||||
# define OPENSSL_NO_ENGINE
|
||||
# define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
|
||||
# include "openssl_stub.hpp"
|
||||
|
||||
# elif CONFIG_ASIO_USE_ESP_WOLFSSL
|
||||
# define ASIO_USE_WOLFSSL
|
||||
# endif // CONFIG_ASIO_USE_ESP_OPENSSL
|
||||
|
||||
#endif // _ESP_ASIO_CONFIG_H_
|
31
components/asio/port/include/esp_exception.h
Normal file
31
components/asio/port/include/esp_exception.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_EXCEPTION_H_
|
||||
#define _ESP_EXCEPTION_H_
|
||||
|
||||
//
|
||||
// This exception stub is enabled only if exceptions are disabled in menuconfig
|
||||
//
|
||||
#if !defined(CONFIG_COMPILER_CXX_EXCEPTIONS) && defined (ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
//
|
||||
// asio exception stub
|
||||
//
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
template <typename Exception>
|
||||
void throw_exception(const Exception &e)
|
||||
{
|
||||
ESP_LOGE("esp32_asio_exception", "Caught exception: %s!", e.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS==1 && defined (ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#endif // _ESP_EXCEPTION_H_
|
48
components/asio/port/include/openssl_stub.hpp
Normal file
48
components/asio/port/include/openssl_stub.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Supply OpenSSL macros and flags for asio-ssl header files
|
||||
//
|
||||
#define OPENSSL_VERSION_NUMBER 0x10100001L
|
||||
|
||||
#define SSL_R_SHORT_READ 219
|
||||
#define SSL_OP_ALL 0
|
||||
#define SSL_OP_SINGLE_DH_USE 0
|
||||
#define SSL_OP_NO_COMPRESSION 0
|
||||
|
||||
#define SSL_OP_NO_SSLv2 0x01000000L
|
||||
#define SSL_OP_NO_SSLv3 0x02000000L
|
||||
#define SSL_OP_NO_TLSv1 0x04000000L
|
||||
|
||||
#define SSL_VERIFY_NONE 0x00
|
||||
#define SSL_VERIFY_PEER 0x01
|
||||
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
|
||||
#define SSL_VERIFY_CLIENT_ONCE 0x04
|
||||
|
||||
//
|
||||
// Implement asio-ssl layer with these three classes in asio::ssl::mbedtls
|
||||
//
|
||||
namespace asio {
|
||||
namespace ssl {
|
||||
namespace mbedtls {
|
||||
|
||||
class engine;
|
||||
class bio;
|
||||
class shared_ctx;
|
||||
}
|
||||
}
|
||||
} // namespace asio::ssl::mbedtls
|
||||
|
||||
//
|
||||
// Supply OpenSSL types as aliases to mbedtls classes
|
||||
//
|
||||
using X509_STORE_CTX = void;
|
||||
using BIO = asio::ssl::mbedtls::bio;
|
||||
using SSL_CTX = asio::ssl::mbedtls::shared_ctx;
|
||||
using SSL = asio::ssl::mbedtls::engine;
|
115
components/asio/port/mbedtls/include/mbedtls_bio.hpp
Normal file
115
components/asio/port/mbedtls/include/mbedtls_bio.hpp
Normal file
@ -0,0 +1,115 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "asio/ssl/context_base.hpp"
|
||||
#include "asio/ssl/context.hpp"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
namespace asio {
|
||||
namespace ssl {
|
||||
namespace mbedtls {
|
||||
|
||||
class bio {
|
||||
static constexpr int BIO_SIZE = CONFIG_ASIO_SSL_BIO_SIZE;
|
||||
static constexpr int BIO_FLAGS_READ = 1;
|
||||
static constexpr int BIO_FLAGS_WRITE = 2;
|
||||
|
||||
public:
|
||||
int write(const void *buf, int len)
|
||||
{
|
||||
if (buf == nullptr || len <= 0) {
|
||||
// not an error, just empty operation (as in openssl/bio)
|
||||
return 0;
|
||||
}
|
||||
int remaining = size_ - offset_;
|
||||
if (remaining <= 0) {
|
||||
flags_ |= BIO_FLAGS_WRITE;
|
||||
return -1;
|
||||
}
|
||||
int len_to_write = len > remaining ? remaining : len;
|
||||
std::memcpy(&data_[offset_], buf, len_to_write);
|
||||
offset_ += len_to_write;
|
||||
dlen_ = offset_;
|
||||
if (len_to_write == len) {
|
||||
flags_ &= ~BIO_FLAGS_WRITE;
|
||||
}
|
||||
return len_to_write;
|
||||
}
|
||||
|
||||
int read(void *buf, int len)
|
||||
{
|
||||
if (buf == nullptr || len <= 0) {
|
||||
// not an error, just empty operation (as in openssl/bio)
|
||||
return 0;
|
||||
}
|
||||
int remaining = peer_->dlen_ - peer_->roffset_;
|
||||
if (remaining <= 0) {
|
||||
flags_ |= BIO_FLAGS_READ;
|
||||
return -1;
|
||||
}
|
||||
int len_to_read = remaining > len ? len : remaining;
|
||||
std::memcpy(buf, &peer_->data_[peer_->roffset_], len_to_read);
|
||||
peer_->roffset_ += len_to_read;
|
||||
if (len_to_read == len) {
|
||||
flags_ &= ~BIO_FLAGS_READ;
|
||||
}
|
||||
if (peer_->offset_) {
|
||||
// shift data back to the beginning of the buffer
|
||||
std::memmove(&peer_->data_[0], &peer_->data_[peer_->roffset_], peer_->offset_ - peer_->roffset_);
|
||||
peer_->offset_ -= peer_->roffset_;
|
||||
peer_->roffset_ = 0;
|
||||
peer_->dlen_ = peer_->offset_;
|
||||
}
|
||||
return len_to_read;
|
||||
}
|
||||
|
||||
size_t wpending() const
|
||||
{
|
||||
return dlen_ - roffset_;
|
||||
}
|
||||
|
||||
size_t ctrl_pending()
|
||||
{
|
||||
return peer_->dlen_ - peer_->roffset_;
|
||||
}
|
||||
|
||||
bool should_write() const
|
||||
{
|
||||
return flags_ & BIO_FLAGS_WRITE;
|
||||
}
|
||||
|
||||
bool should_read() const
|
||||
{
|
||||
return flags_ & BIO_FLAGS_READ;
|
||||
}
|
||||
|
||||
static std::pair<std::shared_ptr<bio>, std::shared_ptr<bio>> new_pair(const char *error_location)
|
||||
{
|
||||
auto b1 = std::shared_ptr<bio>(new (std::nothrow) bio);
|
||||
auto b2 = std::shared_ptr<bio>(new (std::nothrow) bio);
|
||||
if (b1 == nullptr || b2 == nullptr) {
|
||||
throw_alloc_failure(error_location);
|
||||
} else {
|
||||
b1->peer_ = b2;
|
||||
b2->peer_ = b1;
|
||||
}
|
||||
return std::make_pair(b1, b2);
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<uint8_t, BIO_SIZE> data_ {};
|
||||
size_t size_ {BIO_SIZE};
|
||||
std::shared_ptr<bio> peer_ {nullptr};
|
||||
int dlen_ {0};
|
||||
size_t offset_ {0};
|
||||
size_t roffset_ {0};
|
||||
size_t flags_ {0};
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace asio::ssl::mbedtls
|
105
components/asio/port/mbedtls/include/mbedtls_context.hpp
Normal file
105
components/asio/port/mbedtls/include/mbedtls_context.hpp
Normal file
@ -0,0 +1,105 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "asio/ssl/context_base.hpp"
|
||||
#include "asio/ssl/context.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace error {
|
||||
|
||||
const asio::error_category &get_mbedtls_category();
|
||||
} // namespace error
|
||||
|
||||
namespace ssl {
|
||||
namespace mbedtls {
|
||||
|
||||
void throw_alloc_failure(const char *location);
|
||||
|
||||
const char *error_message(int error_code);
|
||||
|
||||
enum class container {
|
||||
CERT, CA_CERT, PRIVKEY
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline T *create(const char *location, Args &&... args)
|
||||
{
|
||||
T *t = new (std::nothrow) T(std::forward<Args>(args)...);
|
||||
if (t == nullptr) {
|
||||
throw_alloc_failure(location);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
class context {
|
||||
public:
|
||||
explicit context(context_base::method m): method_(m), options_(0) {}
|
||||
|
||||
const unsigned char *data(container c) const
|
||||
{
|
||||
switch (c) {
|
||||
case container::CERT:
|
||||
return static_cast<const unsigned char *>(cert_chain_.data());
|
||||
case container::CA_CERT:
|
||||
return static_cast<const unsigned char *>(ca_cert_.data());
|
||||
case container::PRIVKEY:
|
||||
return static_cast<const unsigned char *>(private_key_.data());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::size_t size(container c) const
|
||||
{
|
||||
switch (c) {
|
||||
case container::CERT:
|
||||
return cert_chain_.size();
|
||||
case container::CA_CERT:
|
||||
return ca_cert_.size();
|
||||
case container::PRIVKEY:
|
||||
return private_key_.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
context_base::method method_;
|
||||
asio::ssl::context::options options_;
|
||||
const_buffer cert_chain_;
|
||||
const_buffer private_key_;
|
||||
const_buffer ca_cert_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Wrapper class around SSL_CTX so we can easily create
|
||||
* a shared pointer to the context without throwing the default exception.
|
||||
* This is useful, as we can use asio::detail::throw_error for allocation errors.
|
||||
*/
|
||||
class shared_ctx {
|
||||
public:
|
||||
static SSL_CTX *create(const char *location, context_base::method m)
|
||||
{
|
||||
auto wrapped = asio::ssl::mbedtls::create<shared_ctx>(location, m);
|
||||
if (wrapped->ctx_ == nullptr) {
|
||||
throw_alloc_failure(location);
|
||||
}
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
std::shared_ptr<mbedtls::context> get() const
|
||||
{
|
||||
return ctx_;
|
||||
}
|
||||
|
||||
explicit shared_ctx(context_base::method m)
|
||||
: ctx_(std::shared_ptr<context>(new (std::nothrow) context(m))) { }
|
||||
|
||||
private:
|
||||
std::shared_ptr<mbedtls::context> ctx_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace asio::ssl::mbedtls
|
297
components/asio/port/mbedtls/include/mbedtls_engine.hpp
Normal file
297
components/asio/port/mbedtls/include/mbedtls_engine.hpp
Normal file
@ -0,0 +1,297 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/esp_debug.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
namespace asio {
|
||||
namespace ssl {
|
||||
namespace mbedtls {
|
||||
|
||||
const char *error_message(int error_code)
|
||||
{
|
||||
static char error_buf[100];
|
||||
mbedtls_strerror(error_code, error_buf, sizeof(error_buf));
|
||||
return error_buf;
|
||||
}
|
||||
|
||||
void throw_alloc_failure(const char *location)
|
||||
{
|
||||
asio::error_code ec( MBEDTLS_ERR_SSL_ALLOC_FAILED, asio::error::get_mbedtls_category());
|
||||
asio::detail::throw_error(ec, location);
|
||||
}
|
||||
|
||||
namespace error_codes {
|
||||
|
||||
bool is_error(int ret)
|
||||
{
|
||||
return ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
}
|
||||
|
||||
static bool want_write(int ret)
|
||||
{
|
||||
return ret == MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
}
|
||||
|
||||
static bool want_read(int ret)
|
||||
{
|
||||
return ret == MBEDTLS_ERR_SSL_WANT_READ;
|
||||
}
|
||||
|
||||
} // namespace error_codes
|
||||
|
||||
enum rw_state {
|
||||
IDLE, READING, WRITING, CLOSED
|
||||
};
|
||||
|
||||
class engine {
|
||||
public:
|
||||
explicit engine(std::shared_ptr<context> ctx): ctx_(std::move(ctx)),
|
||||
bio_(bio::new_pair("mbedtls-engine")), state_(IDLE), verify_mode_(0) {}
|
||||
|
||||
void set_verify_mode(asio::ssl::verify_mode mode)
|
||||
{
|
||||
verify_mode_ = mode;
|
||||
}
|
||||
|
||||
bio *ext_bio() const
|
||||
{
|
||||
return bio_.second.get();
|
||||
}
|
||||
|
||||
rw_state get_state() const
|
||||
{
|
||||
return state_;
|
||||
}
|
||||
|
||||
int shutdown()
|
||||
{
|
||||
int ret = mbedtls_ssl_close_notify(&impl_.ssl_);
|
||||
if (ret) {
|
||||
impl::print_error("mbedtls_ssl_close_notify", ret);
|
||||
}
|
||||
state_ = CLOSED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int connect()
|
||||
{
|
||||
return handshake(true);
|
||||
}
|
||||
|
||||
int accept()
|
||||
{
|
||||
return handshake(false);
|
||||
}
|
||||
|
||||
int write(const void *buffer, int len)
|
||||
{
|
||||
int ret = impl_.write(buffer, len);
|
||||
state_ = ret == len ? IDLE : WRITING;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int read(void *buffer, int len)
|
||||
{
|
||||
int ret = impl_.read(buffer, len);
|
||||
state_ = ret == len ? IDLE : READING;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
int handshake(bool is_client_not_server)
|
||||
{
|
||||
if (impl_.before_handshake()) {
|
||||
impl_.configure(ctx_.get(), is_client_not_server, impl_verify_mode(is_client_not_server));
|
||||
}
|
||||
return do_handshake();
|
||||
}
|
||||
|
||||
static int bio_read(void *ctx, unsigned char *buf, size_t len)
|
||||
{
|
||||
auto bio = static_cast<BIO *>(ctx);
|
||||
int read = bio->read(buf, len);
|
||||
if (read <= 0 && bio->should_read()) {
|
||||
return MBEDTLS_ERR_SSL_WANT_READ;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
static int bio_write(void *ctx, const unsigned char *buf, size_t len)
|
||||
{
|
||||
auto bio = static_cast<BIO *>(ctx);
|
||||
int written = bio->write(buf, len);
|
||||
if (written <= 0 && bio->should_write()) {
|
||||
return MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
int do_handshake()
|
||||
{
|
||||
int ret = 0;
|
||||
mbedtls_ssl_set_bio(&impl_.ssl_, bio_.first.get(), bio_write, bio_read, nullptr);
|
||||
|
||||
while (impl_.ssl_.MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) {
|
||||
ret = mbedtls_ssl_handshake_step(&impl_.ssl_);
|
||||
|
||||
if (ret != 0) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
impl::print_error("mbedtls_ssl_handshake_step", ret);
|
||||
}
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
state_ = READING;
|
||||
} else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
state_ = WRITING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Converts OpenSSL verification mode to mbedtls enum
|
||||
int impl_verify_mode(bool is_client_not_server) const
|
||||
{
|
||||
int mode = MBEDTLS_SSL_VERIFY_UNSET;
|
||||
if (is_client_not_server) {
|
||||
if (verify_mode_ & SSL_VERIFY_PEER) {
|
||||
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
} else if (verify_mode_ == SSL_VERIFY_NONE) {
|
||||
mode = MBEDTLS_SSL_VERIFY_NONE;
|
||||
}
|
||||
} else {
|
||||
if (verify_mode_ & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
|
||||
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
} else if (verify_mode_ & SSL_VERIFY_PEER) {
|
||||
mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
} else if (verify_mode_ == SSL_VERIFY_NONE) {
|
||||
mode = MBEDTLS_SSL_VERIFY_NONE;
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
struct impl {
|
||||
static void print_error(const char *function, int error_code)
|
||||
{
|
||||
constexpr const char *TAG = "mbedtls-engine-impl";
|
||||
ESP_LOGE(TAG, "%s() returned -0x%04X", function, -error_code);
|
||||
ESP_LOGI(TAG, "-0x%04X: %s", -error_code, error_message(error_code));
|
||||
}
|
||||
|
||||
bool before_handshake() const
|
||||
{
|
||||
return ssl_.MBEDTLS_PRIVATE(state) == 0;
|
||||
}
|
||||
|
||||
int write(const void *buffer, int len)
|
||||
{
|
||||
int ret = mbedtls_ssl_write(&ssl_, static_cast<const unsigned char *>(buffer), len);
|
||||
if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
print_error("mbedtls_ssl_write", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int read(void *buffer, int len)
|
||||
{
|
||||
int ret = mbedtls_ssl_read(&ssl_, static_cast<unsigned char *>(buffer), len);
|
||||
if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
print_error("mbedtls_ssl_read", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
impl()
|
||||
{
|
||||
const unsigned char pers[] = "asio ssl";
|
||||
mbedtls_ssl_init(&ssl_);
|
||||
mbedtls_ssl_config_init(&conf_);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg_);
|
||||
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||
mbedtls_esp_enable_debug_log(&conf_, CONFIG_MBEDTLS_DEBUG_LEVEL);
|
||||
#endif
|
||||
mbedtls_entropy_init(&entropy_);
|
||||
mbedtls_ctr_drbg_seed(&ctr_drbg_, mbedtls_entropy_func, &entropy_, pers, sizeof(pers));
|
||||
mbedtls_x509_crt_init(&public_cert_);
|
||||
mbedtls_pk_init(&pk_key_);
|
||||
mbedtls_x509_crt_init(&ca_cert_);
|
||||
}
|
||||
|
||||
bool configure(context *ctx, bool is_client_not_server, int mbedtls_verify_mode)
|
||||
{
|
||||
mbedtls_x509_crt_init(&public_cert_);
|
||||
mbedtls_pk_init(&pk_key_);
|
||||
mbedtls_x509_crt_init(&ca_cert_);
|
||||
int ret = mbedtls_ssl_config_defaults(&conf_, is_client_not_server ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
|
||||
if (ret) {
|
||||
print_error("mbedtls_ssl_config_defaults", ret);
|
||||
return false;
|
||||
}
|
||||
mbedtls_ssl_conf_rng(&conf_, mbedtls_ctr_drbg_random, &ctr_drbg_);
|
||||
mbedtls_ssl_conf_authmode(&conf_, mbedtls_verify_mode);
|
||||
if (ctx->cert_chain_.size() > 0 && ctx->private_key_.size() > 0) {
|
||||
ret = mbedtls_x509_crt_parse(&public_cert_, ctx->data(container::CERT), ctx->size(container::CERT));
|
||||
if (ret < 0) {
|
||||
print_error("mbedtls_x509_crt_parse", ret);
|
||||
return false;
|
||||
}
|
||||
ret = mbedtls_pk_parse_key(&pk_key_, ctx->data(container::PRIVKEY), ctx->size(container::PRIVKEY),
|
||||
nullptr, 0, mbedtls_ctr_drbg_random, &ctr_drbg_);
|
||||
if (ret < 0) {
|
||||
print_error("mbedtls_pk_parse_keyfile", ret);
|
||||
return false;
|
||||
}
|
||||
ret = mbedtls_ssl_conf_own_cert(&conf_, &public_cert_, &pk_key_);
|
||||
if (ret) {
|
||||
print_error("mbedtls_ssl_conf_own_cert", ret);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->ca_cert_.size() > 0) {
|
||||
ret = mbedtls_x509_crt_parse(&ca_cert_, ctx->data(container::CA_CERT), ctx->size(container::CA_CERT));
|
||||
if (ret < 0) {
|
||||
print_error("mbedtls_x509_crt_parse", ret);
|
||||
return false;
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(&conf_, &ca_cert_, nullptr);
|
||||
} else {
|
||||
mbedtls_ssl_conf_ca_chain(&conf_, nullptr, nullptr);
|
||||
}
|
||||
ret = mbedtls_ssl_setup(&ssl_, &conf_);
|
||||
if (ret) {
|
||||
print_error("mbedtls_ssl_setup", ret);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
mbedtls_ssl_context ssl_{};
|
||||
mbedtls_entropy_context entropy_{};
|
||||
mbedtls_ctr_drbg_context ctr_drbg_{};
|
||||
mbedtls_ssl_config conf_{};
|
||||
mbedtls_x509_crt public_cert_{};
|
||||
mbedtls_pk_context pk_key_{};
|
||||
mbedtls_x509_crt ca_cert_{};
|
||||
};
|
||||
|
||||
impl impl_{};
|
||||
std::shared_ptr<context> ctx_;
|
||||
std::pair<std::shared_ptr<bio>, std::shared_ptr<bio>> bio_;
|
||||
enum rw_state state_;
|
||||
asio::ssl::verify_mode verify_mode_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace asio::ssl::mbedtls
|
56
components/asio/port/mbedtls/include/mbedtls_error.hpp
Normal file
56
components/asio/port/mbedtls/include/mbedtls_error.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include "asio/ssl/error.hpp"
|
||||
#include "asio/ssl/detail/openssl_init.hpp"
|
||||
#include "mbedtls_context.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace error {
|
||||
namespace detail {
|
||||
|
||||
class mbedtls_category : public asio::error_category {
|
||||
public:
|
||||
const char *name() const ASIO_ERROR_CATEGORY_NOEXCEPT
|
||||
{
|
||||
return "asio.ssl";
|
||||
}
|
||||
|
||||
std::string message(int value) const
|
||||
{
|
||||
const char *s = asio::ssl::mbedtls::error_message(value);
|
||||
return s ? s : "asio.mbedtls error";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
const asio::error_category &get_mbedtls_category()
|
||||
{
|
||||
static detail::mbedtls_category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
const asio::error_category &get_ssl_category()
|
||||
{
|
||||
return asio::error::get_mbedtls_category();
|
||||
}
|
||||
|
||||
} // namespace error
|
||||
|
||||
namespace ssl {
|
||||
namespace error {
|
||||
|
||||
const asio::error_category &get_stream_category()
|
||||
{
|
||||
return asio::error::get_mbedtls_category();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace asio::ssl::error
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user