mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1c2ffe1a0 | ||
|
|
9210a762de | ||
|
|
1620110f50 | ||
|
|
0d882f1b43 | ||
|
|
1bb85799ce | ||
|
|
12207edd55 | ||
|
|
bb37f72a63 | ||
|
|
b852e0f8c3 | ||
|
|
25dc078af7 | ||
|
|
06f525713f | ||
|
|
05ade0ba3c | ||
|
|
ec91eaf0f3 | ||
|
|
8392b9407a | ||
|
|
60fe567845 | ||
|
|
02e83c77a4 | ||
|
|
538a1a9bfa | ||
|
|
862fbd0abc | ||
|
|
2121be1abe | ||
|
|
0c794f19d2 | ||
|
|
44ef3b43d2 | ||
|
|
d27e7b3e7e | ||
|
|
f0d1800c6b | ||
|
|
81b61d335f | ||
|
|
70f14336f1 | ||
|
|
19ea5aba43 | ||
|
|
2a7fa4cb68 | ||
|
|
3d094ec921 | ||
|
|
abe19d2367 | ||
|
|
2b408e85e9 | ||
|
|
27897d5514 | ||
|
|
dfcfdfd0f7 | ||
|
|
ec032181c6 | ||
|
|
1cc6a48eea | ||
|
|
17b4054ea5 | ||
|
|
0ec11128f7 | ||
|
|
ed0423f79d | ||
|
|
ba69eb248c | ||
|
|
eefec28b50 | ||
|
|
564c352d0c | ||
|
|
d20eb8b280 | ||
|
|
cc617d537d | ||
|
|
205d4c6832 | ||
|
|
18cea946f1 | ||
|
|
0884338b2a | ||
|
|
ba768693ed | ||
|
|
3170261876 | ||
|
|
2d7e8aa712 | ||
|
|
c083f204fc | ||
|
|
e83e13d8c6 | ||
|
|
70d268d95f | ||
|
|
71f5556de7 | ||
|
|
8c64266f95 | ||
|
|
124b4e93c7 | ||
|
|
e01eeed303 | ||
|
|
4b3cfb4bc0 | ||
|
|
e5dfbec36d | ||
|
|
be1587a933 | ||
|
|
3e87f18a29 | ||
|
|
2214cf66a4 | ||
|
|
7b886ccbde | ||
|
|
b69b288d6c | ||
|
|
37fe251d31 | ||
|
|
5ec7ec141a | ||
|
|
e31079e107 | ||
|
|
1701fb0d03 | ||
|
|
f2ce01641e | ||
|
|
b5e4eef966 | ||
|
|
b93822fc50 | ||
|
|
715f98c546 | ||
|
|
b1878dc9d0 | ||
|
|
fe8cf7d9d6 | ||
|
|
5fa6b0a6ef | ||
|
|
d3ab638e5d | ||
|
|
44e773af54 | ||
|
|
ece3f43f34 | ||
|
|
edd1350864 | ||
|
|
8e0ef3ca5c | ||
|
|
b74913ded5 | ||
|
|
42abbb7e55 | ||
|
|
a4869febf6 | ||
|
|
b10355a536 | ||
|
|
e86d4da129 | ||
|
|
46ad050cea | ||
|
|
2a7cf8d5a7 | ||
|
|
07fd086230 | ||
|
|
f040d094ea | ||
|
|
f101d1422a | ||
|
|
6631c5db87 | ||
|
|
c429a0dc56 | ||
|
|
3f59974639 | ||
|
|
c10a88b64b | ||
|
|
d5e5b3397d | ||
|
|
ab83acf2d1 | ||
|
|
1db25117b0 | ||
|
|
bd1271dd41 | ||
|
|
5dddbb3fce | ||
|
|
a28decbef4 | ||
|
|
73d9c125c0 | ||
|
|
667abfb5e1 | ||
|
|
8c65c2f9af | ||
|
|
f36205e65f | ||
|
|
e2c0b2b477 | ||
|
|
29254ce84b | ||
|
|
1a0716ae4d | ||
|
|
e46ee68a95 | ||
|
|
db496fd7dd | ||
|
|
0a3e129527 | ||
|
|
12491777bb | ||
|
|
ad4b87e24a | ||
|
|
7ffc51d38e | ||
|
|
c9243c3f47 | ||
|
|
0d6c424e62 | ||
|
|
dc9395c904 | ||
|
|
2bb750070a | ||
|
|
17b0b65cab | ||
|
|
b5b63e731c | ||
|
|
7e376bb860 | ||
|
|
b313d697ff | ||
|
|
1cadd2b2aa | ||
|
|
f40b377fff | ||
|
|
43509c1781 | ||
|
|
209d1dd426 | ||
|
|
1f9e1a38b5 | ||
|
|
69936ac9f6 | ||
|
|
6de419d14c | ||
|
|
1200f50e2e | ||
|
|
73bec74380 | ||
|
|
f70647e28e | ||
|
|
effa61f9b2 | ||
|
|
b8bde63554 | ||
|
|
409d3d388a | ||
|
|
2c4bf4cea4 | ||
|
|
1b9c3a0fb0 | ||
|
|
71cc0cfd80 | ||
|
|
63da5aa403 | ||
|
|
cb13900c32 | ||
|
|
926a0e2cf2 | ||
|
|
2bfcfeb359 | ||
|
|
16d8e3b4f9 | ||
|
|
682fe2c9a0 | ||
|
|
bdd309b10b | ||
|
|
21fbf9cdc5 | ||
|
|
9ed98cecff | ||
|
|
ab4e229f57 | ||
|
|
7feab86700 | ||
|
|
6bc0af5dd0 | ||
|
|
6cb685b700 | ||
|
|
5c582c35d8 | ||
|
|
10ab9ae1ea | ||
|
|
756d127cab | ||
|
|
a49eb47a91 | ||
|
|
e15056a9e4 | ||
|
|
66d4069644 | ||
|
|
9aae863956 | ||
|
|
878ec8a86c | ||
|
|
8fccfca17b | ||
|
|
69925c774d | ||
|
|
c1298973e1 | ||
|
|
bedda34515 | ||
|
|
767b0ab90b | ||
|
|
b0109c3319 | ||
|
|
a42271a088 | ||
|
|
154e471256 | ||
|
|
bfc411acaf | ||
|
|
2acbb0ad62 | ||
|
|
60ce504489 | ||
|
|
22b8eda0df | ||
|
|
80ed81583e | ||
|
|
ce0c3a0fe7 | ||
|
|
492c6385da | ||
|
|
5b023cb85b | ||
|
|
4717a15c17 | ||
|
|
d6e7f8ee83 | ||
|
|
17ff656a7d | ||
|
|
4e8965cce5 | ||
|
|
b3d27a3c43 | ||
|
|
66dcca9392 | ||
|
|
0f1a3cf84b | ||
|
|
a4b7025396 | ||
|
|
9c148fd47e | ||
|
|
293d8c22e1 | ||
|
|
5f2ff680d5 | ||
|
|
8eaca9437e | ||
|
|
6e72bf4b5f | ||
|
|
710e7b2004 | ||
|
|
666a3b68e9 | ||
|
|
02e97adbef | ||
|
|
236724ea29 | ||
|
|
b503915ca5 | ||
|
|
156db0bc5e | ||
|
|
11b6bd7d9c | ||
|
|
7ca952faa6 | ||
|
|
4fc40f0ffb | ||
|
|
cac4b3e254 | ||
|
|
0d5cb5cbcc | ||
|
|
a35901121b | ||
|
|
e0740fc2ca | ||
|
|
7d22b5fe18 | ||
|
|
d2e66ac58d | ||
|
|
34cc8da87e | ||
|
|
1957ba8ffe | ||
|
|
72758812f5 | ||
|
|
ab5a0c43de | ||
|
|
c8291e4ae9 | ||
|
|
84e9ea76db | ||
|
|
b8994f8bc3 | ||
|
|
b53d8439e5 | ||
|
|
337e8abf2f | ||
|
|
f0bc1c031f | ||
|
|
19d2b93ec7 | ||
|
|
e0304f2b8f | ||
|
|
f7a86f8cf1 | ||
|
|
340f0dbf89 | ||
|
|
d90b62d911 | ||
|
|
d84aff6420 | ||
|
|
b3b73f4751 | ||
|
|
3c7b2dcd6d | ||
|
|
49470f9bd2 | ||
|
|
f7cf4f60ef | ||
|
|
7e0d06689e | ||
|
|
b843957bd2 | ||
|
|
1a0167eb6d | ||
|
|
6ea3b98941 | ||
|
|
4b0b93d4f3 | ||
|
|
64abf061bf | ||
|
|
05d5c68982 | ||
|
|
235dafe646 | ||
|
|
0cc40b0c70 | ||
|
|
07a0d1265b | ||
|
|
967d746574 | ||
|
|
bd12cb1b87 | ||
|
|
a21ca5d40b | ||
|
|
2d399107fb | ||
|
|
03bfa3806b | ||
|
|
6536ae9bcc | ||
|
|
e8fc817a0c | ||
|
|
e621ade392 | ||
|
|
3273c20ca9 | ||
|
|
a6b2124fd5 | ||
|
|
5a1ff125d7 | ||
|
|
ad58a48144 | ||
|
|
a205fd7877 | ||
|
|
776360ca93 | ||
|
|
af7602497d | ||
|
|
0f83c2a6e5 | ||
|
|
0d58748e63 | ||
|
|
01902bb8b9 | ||
|
|
e28e9aa1d7 | ||
|
|
587e79dc05 | ||
|
|
acd65f2340 | ||
|
|
d55fb80746 | ||
|
|
4536694f20 | ||
|
|
2c5a6d4df6 | ||
|
|
4c8e219643 | ||
|
|
daeca8128b | ||
|
|
fe6d357858 | ||
|
|
a99cc3dbaf | ||
|
|
3c4c04199a | ||
|
|
8ca692100f | ||
|
|
0b9f28b8e3 | ||
|
|
1dff394b63 | ||
|
|
f4c35d1036 | ||
|
|
81c166ad74 | ||
|
|
1f56776050 | ||
|
|
b3a0e7b884 | ||
|
|
8594507b5b | ||
|
|
fa811ce12b | ||
|
|
c1ef477ff3 | ||
|
|
4be3a96987 | ||
|
|
387f875aa1 | ||
|
|
cc069e7e5d | ||
|
|
df994df611 | ||
|
|
8f77fd3940 | ||
|
|
7530062e4b | ||
|
|
0e63510708 | ||
|
|
26260a1d88 | ||
|
|
9e82844f10 | ||
|
|
0568b5a75b | ||
|
|
3baabebb34 | ||
|
|
bf4dd15317 | ||
|
|
b0f2f9621a | ||
|
|
04d6d05e9e | ||
|
|
7339c7dfe7 | ||
|
|
c1152f5eeb | ||
|
|
024922d566 | ||
|
|
6f64c8c0de | ||
|
|
2a5ac3c2e5 | ||
|
|
7b0120f0c2 | ||
|
|
7ee1f14a6d | ||
|
|
3aaf7d0da7 | ||
|
|
434f3f8415 |
No files matched your search
@@ -17,7 +17,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: make -C test ${{ matrix.target }} ARGS="-max_total_time=7200"
|
- run: make -C test ${{ matrix.target }} ARGS="-max_total_time=14400"
|
||||||
|
|
||||||
# as we're not getting access to test units causing a problem, convert from the log:
|
# as we're not getting access to test units causing a problem, convert from the log:
|
||||||
# base64 -d > dataofdeath
|
# base64 -d > dataofdeath
|
||||||
|
|||||||
+74
-155
@@ -1,4 +1,4 @@
|
|||||||
name: Full build and test
|
name: Full build
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 22 * * *' # run at 10 PM UTC
|
- cron: '0 22 * * *' # run at 10 PM UTC
|
||||||
@@ -29,15 +29,28 @@ jobs:
|
|||||||
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0"
|
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0"
|
||||||
- ssl: WOLFSSL
|
- ssl: WOLFSSL
|
||||||
select: "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0"
|
select: "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0"
|
||||||
|
include:
|
||||||
|
- ssl: BUILTIN
|
||||||
|
cc: gcc
|
||||||
|
target: test
|
||||||
|
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=1 -DMG_ENABLE_CHACHA20=0"
|
||||||
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
||||||
env:
|
env:
|
||||||
CC: ${{ matrix.cc }}
|
CC: ${{ matrix.cc }}
|
||||||
SSL: ${{ matrix.ssl }}
|
SSL: ${{ matrix.ssl }}
|
||||||
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST
|
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && test/setup_mqtt_server.sh && make -C test ${{ matrix.target }}
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && test/setup_mqtt_server.sh && make -C test ${{ matrix.target }} > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/linux_${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
|
||||||
mip:
|
mip:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -54,11 +67,20 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CC: ${{ matrix.cc }}
|
CC: ${{ matrix.cc }}
|
||||||
SSL: ${{ matrix.ssl }}
|
SSL: ${{ matrix.ssl }}
|
||||||
TFLAGS: -DMQTT_LOCALHOST
|
TFLAGS: -DMQTT_LOCALHOST -DNO_ABORT
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} IPV6=0
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; export IPV6=0; else export IPV6=1 ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_$(date +"%Y%m%d").json"
|
||||||
|
|
||||||
mip89:
|
mip89:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -70,7 +92,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: make -C test ${{ matrix.target }}
|
- run: make -C test ${{ matrix.target }} IPV6=1
|
||||||
s390:
|
s390:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -128,32 +150,37 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
# Mongoose does not work with WolfSSL version in MacOS
|
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
|
||||||
ssl: ["", BUILTIN, MBEDTLS, OPENSSL] # , WOLFSSL]
|
|
||||||
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
|
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
|
||||||
include:
|
|
||||||
- ssl: MBEDTLS
|
|
||||||
env:
|
|
||||||
# MbedTLS version in MacOS refuses to validate a certificate without a hostname, causing MQTT tests to fail when using MQTT_LOCALHOST
|
|
||||||
tflags: -DNO_MQTT_TESTS
|
|
||||||
exclude:
|
exclude:
|
||||||
- ssl: MBEDTLS
|
- ssl: MBEDTLS
|
||||||
select: -DMG_ENABLE_POLL=0
|
select: -DMG_ENABLE_POLL=0
|
||||||
|
- ssl: MBEDTLS # see issue#2694
|
||||||
|
select: -DMG_ENABLE_POLL=1
|
||||||
- ssl: OPENSSL
|
- ssl: OPENSSL
|
||||||
select: -DMG_ENABLE_POLL=0
|
select: -DMG_ENABLE_POLL=0
|
||||||
#- ssl: WOLFSSL
|
- ssl: WOLFSSL
|
||||||
# select: -DMG_ENABLE_POLL=0
|
select: -DMG_ENABLE_POLL=0
|
||||||
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
||||||
env:
|
env:
|
||||||
SSL: ${{ matrix.ssl }}
|
SSL: ${{ matrix.ssl }}
|
||||||
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST ${{ matrix.env.tflags }} -Wno-sign-conversion # Workaround for MbedTLS 3.5.0
|
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST ${{ matrix.env.tflags }} -DNO_ABORT -Wno-sign-conversion -Wno-undef # Workarounds for MbedTLS
|
||||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: brew install mbedtls wolfssl mosquitto # jq openssl already pre-installed
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: brew install mbedtls wolfssl mosquitto gawk # jq openssl already pre-installed
|
||||||
- run: /opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
|
- run: /opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
|
||||||
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*)
|
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/macos_test_cc_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -169,11 +196,20 @@ jobs:
|
|||||||
name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
||||||
env:
|
env:
|
||||||
SSL: ${{ matrix.ssl }}
|
SSL: ${{ matrix.ssl }}
|
||||||
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST
|
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: ./test/setup_mqtt_server.sh && make -C test ${{ matrix.target }}
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: ./test/setup_mqtt_server.sh && make -C test ${{ matrix.target }} > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/windows_${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
|
||||||
|
|
||||||
arm:
|
arm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -204,9 +240,18 @@ jobs:
|
|||||||
name: tutorials ${{ matrix.ssl }}
|
name: tutorials ${{ matrix.ssl }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
- run: sudo apt -y install libpcap-dev
|
- run: sudo apt -y install libpcap-dev
|
||||||
- run: make -C test tutorials CFLAGS_EXTRA="${{ matrix.ssl }}"
|
- run: make -C test tutorials CFLAGS_EXTRA="${{ matrix.ssl }}" > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/tutorials_${{ matrix.ssl }}_$(date +"%Y%m%d").json"
|
||||||
- run: make -C test clean_tutorials
|
- run: make -C test clean_tutorials
|
||||||
|
|
||||||
tutorials_win:
|
tutorials_win:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -284,6 +329,7 @@ jobs:
|
|||||||
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
|
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
|
||||||
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
|
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
|
||||||
- path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin
|
- path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin
|
||||||
|
- path: pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin
|
||||||
- path: stm32/nucleo-f429zi-make-baremetal-builtin
|
- path: stm32/nucleo-f429zi-make-baremetal-builtin
|
||||||
- path: stm32/nucleo-f429zi-make-freertos-builtin
|
- path: stm32/nucleo-f429zi-make-freertos-builtin
|
||||||
- path: stm32/nucleo-f746zg-make-baremetal-builtin
|
- path: stm32/nucleo-f746zg-make-baremetal-builtin
|
||||||
@@ -454,137 +500,10 @@ jobs:
|
|||||||
- run: sudo pip install yq
|
- run: sudo pip install yq
|
||||||
- run: cd test/cube && make
|
- run: cd test/cube && make
|
||||||
|
|
||||||
test_f7:
|
# xpresso_examples:
|
||||||
runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
steps:
|
# steps:
|
||||||
- uses: actions/checkout@v4
|
# - uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
# with: { fetch-depth: 2 }
|
||||||
- name: baremetal
|
# - run: sudo pip install yq
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
# - run: cd test/xpresso && make
|
||||||
- run: make -C tutorials/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- name: Cube
|
|
||||||
run: echo # nothing specific to install or do
|
|
||||||
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
|
||||||
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
|
||||||
- run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
|
||||||
|
|
||||||
test_f4:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 2 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- name: Cube
|
|
||||||
run: echo # nothing specific to install or do
|
|
||||||
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
|
||||||
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
|
||||||
- run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
|
||||||
|
|
||||||
test_h743:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 3 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
# - name: Cube
|
|
||||||
# run: echo # nothing specific to install or do
|
|
||||||
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
|
|
||||||
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
|
|
||||||
|
|
||||||
test_h723:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 3 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
test_h5:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 3 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
test_rt1020:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 3 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
test_rt1060:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 3 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
test_rt1170:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 3 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
test_ra6m4:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 3 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
# - run: make -C tutorials/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
test_tm4c:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 2 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
test_same54:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 2 }
|
|
||||||
- name: baremetal
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/http/device-dashboard/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
- run: make -C tutorials/mqtt/mqtt-client/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
test_pico_w5500:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 2 }
|
|
||||||
- name: SDK
|
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C tutorials/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
|
||||||
|
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
name: Full test
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 23 * * *' # run at 11 PM UTC
|
||||||
|
# Allow manual runs
|
||||||
|
workflow_dispatch:
|
||||||
|
env:
|
||||||
|
IPV6: 0
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
test_f7:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- name: Cube
|
||||||
|
run: sudo pip install yq
|
||||||
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
||||||
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
||||||
|
- run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
||||||
|
|
||||||
|
test_f4:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- name: Cube
|
||||||
|
run: sudo pip install yq
|
||||||
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
||||||
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
||||||
|
- run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
||||||
|
|
||||||
|
test_h743:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 3 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
# - name: Cube
|
||||||
|
# run: echo # nothing specific to install or do
|
||||||
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
|
||||||
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
|
||||||
|
|
||||||
|
test_h723:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 3 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
|
test_h5:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 3 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
|
test_rt1020:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 3 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
|
test_rt1060:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 3 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
|
test_rt1170:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 3 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
|
test_ra6m4:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 3 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
# - run: make -C tutorials/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
|
test_tm4c:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
|
test_same54:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- name: baremetal
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/http/device-dashboard/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
- run: make -C tutorials/mqtt/mqtt-client/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
|
test_pico_w5500:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- name: SDK
|
||||||
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
name: On demand ad hoc test
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
env:
|
||||||
|
IPV6: 0
|
||||||
|
jobs:
|
||||||
|
macos:
|
||||||
|
runs-on: macos-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
ssl: [MBEDTLS, WOLFSSL]
|
||||||
|
select: [-DMG_ENABLE_POLL=1]
|
||||||
|
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
||||||
|
env:
|
||||||
|
SSL: ${{ matrix.ssl }}
|
||||||
|
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT -Wno-sign-conversion -Wno-undef # Workarounds for MbedTLS
|
||||||
|
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: brew install mbedtls wolfssl mosquitto gawk # jq openssl already pre-installed
|
||||||
|
- run: /opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
|
||||||
|
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/macos_test_cc_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
|
||||||
@@ -170,6 +170,7 @@ jobs:
|
|||||||
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
|
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
|
||||||
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
|
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
|
||||||
- path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin
|
- path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin
|
||||||
|
- path: pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin
|
||||||
- path: stm32/nucleo-f429zi-make-baremetal-builtin
|
- path: stm32/nucleo-f429zi-make-baremetal-builtin
|
||||||
- path: stm32/nucleo-f429zi-make-freertos-builtin
|
- path: stm32/nucleo-f429zi-make-freertos-builtin
|
||||||
- path: stm32/nucleo-f746zg-make-baremetal-builtin
|
- path: stm32/nucleo-f746zg-make-baremetal-builtin
|
||||||
@@ -347,6 +348,22 @@ jobs:
|
|||||||
- if: ${{ env.GO == 1 }}
|
- if: ${{ env.GO == 1 }}
|
||||||
run: cd test/cube && make
|
run: cd test/cube && make
|
||||||
|
|
||||||
|
# xpresso_examples:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# env:
|
||||||
|
# GO: 0
|
||||||
|
# steps:
|
||||||
|
# - uses: actions/checkout@v4
|
||||||
|
# with: { fetch-depth: 2 }
|
||||||
|
# - run: |
|
||||||
|
# if ./test/match_changed_files.sh '^src|tutorials/stm32/nucleo-*-cube-*'; then
|
||||||
|
# echo GO=1 >> $GITHUB_ENV
|
||||||
|
# sudo pip install yq
|
||||||
|
# fi
|
||||||
|
# - if: ${{ env.GO == 1 }}
|
||||||
|
# run: cd test/xpresso && make
|
||||||
|
|
||||||
|
|
||||||
# test_f7:
|
# test_f7:
|
||||||
# runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
# env:
|
# env:
|
||||||
|
|||||||
@@ -10,17 +10,18 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
revno: ["--mr v3.7-branch", "--mr v4.2.0"] # LTS, latest stable
|
revno: ["--mr v3.7-branch", "--mr v4.2.0", "--mr v4.3.0"] # LTS, latest stable
|
||||||
name: Zephyr ${{ matrix.revno }}
|
name: Zephyr ${{ matrix.revno }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: test/setup_ga_docker_filesystem.sh
|
- run: test/setup_ga_docker_filesystem.sh
|
||||||
- run: make -C tutorials/zephyr init REPO=zephyrprojectrtos/ci REVNO="${{ matrix.revno }}"
|
- run: make -C tutorials/zephyr init REPO=zephyrprojectrtos/ci:v0.28.8 REVNO="${{ matrix.revno }}"
|
||||||
- run: make -C tutorials/zephyr minify REVNO="${{ matrix.revno }}"
|
- run: make -C tutorials/zephyr minify REVNO="${{ matrix.revno }}"
|
||||||
- run: make -C tutorials/zephyr update
|
- run: make -C tutorials/zephyr update
|
||||||
- run: make -C tutorials/zephyr/device-dashboard build
|
- run: make -C tutorials/zephyr/device-dashboard build REPO=zephyrprojectrtos/ci:v0.28.8
|
||||||
- run: make -C tutorials/zephyr/http-client build
|
- run: make -C tutorials/zephyr/http-client build REPO=zephyrprojectrtos/ci:v0.28.8
|
||||||
- run: make -C tutorials/zephyr/http-server build
|
- run: make -C tutorials/zephyr/http-server build REPO=zephyrprojectrtos/ci:v0.28.8
|
||||||
- run: make -C tutorials/zephyr/mqtt-aws-client build
|
- run: make -C tutorials/zephyr/mqtt-aws-client build REPO=zephyrprojectrtos/ci:v0.28.8
|
||||||
- run: make -C tutorials/zephyr/websocket-server build
|
- run: make -C tutorials/zephyr/websocket-server build REPO=zephyrprojectrtos/ci:v0.28.8
|
||||||
|
# Latest CI image does not work with pre 4.4, they changed some SDK paths
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
Copyright (c) 2004-2013 Sergey Lyubka
|
Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
Copyright (c) 2013-2025 Cesanta Software Limited
|
Copyright (c) 2013-2026 Cesanta Software Limited
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
This software is dual-licensed: you can redistribute it and/or modify
|
This software is dual-licensed: you can redistribute it and/or modify
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
[](https://codecov.io/gh/cesanta/mongoose)
|
[](https://codecov.io/gh/cesanta/mongoose)
|
||||||
[](https://issues.oss-fuzz.com/issues?sort=-opened&can=1&q=proj:mongoose)
|
[](https://issues.oss-fuzz.com/issues?sort=-opened&can=1&q=proj:mongoose)
|
||||||
|
|
||||||
Mongoose is a network library for C/C++. It provides event-driven non-blocking
|
<img src="https://mongoose.ws/images/logo.svg" width="48" height="48" align="left" style="float:left;" /> Mongoose is a network library for C/C++. It provides event-driven non-blocking
|
||||||
APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocols. It is designed
|
APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocols. It is designed
|
||||||
for connecting devices and bringing them online. On the market since 2004, used
|
for connecting devices and bringing them online. On the market since 2004, used
|
||||||
by vast number of open source and commercial products - it even runs on the
|
by vast number of open source and commercial products - it even runs on the
|
||||||
@@ -198,6 +198,10 @@ We take security seriously:
|
|||||||
have specific security requirements and run independent security audits,
|
have specific security requirements and run independent security audits,
|
||||||
of which we get notified and in case of any issue, act similar to (3).
|
of which we get notified and in case of any issue, act similar to (3).
|
||||||
|
|
||||||
|
## How to report security vulnerabilities
|
||||||
|
|
||||||
|
Please send an email to support@cesanta.com, with the full information.
|
||||||
|
Do NOT create a github issue.
|
||||||
|
|
||||||
## Articles
|
## Articles
|
||||||
|
|
||||||
@@ -209,6 +213,14 @@ Technical guides and deep dives into embedded web servers, WebUI integration and
|
|||||||
- [STM32 WebSocket Guide](https://mongoose.ws/articles/stm32-websocket-guide/)
|
- [STM32 WebSocket Guide](https://mongoose.ws/articles/stm32-websocket-guide/)
|
||||||
- [Web File Manager on STM32, ESP32 and Embedded Linux](https://mongoose.ws/articles/building-a-web-file-manager-on-stm32-esp32-embedded-linux/)
|
- [Web File Manager on STM32, ESP32 and Embedded Linux](https://mongoose.ws/articles/building-a-web-file-manager-on-stm32-esp32-embedded-linux/)
|
||||||
- [Web dashboard on Zephyr RTOS](https://mongoose.ws/articles/web-dashboard-on-zephyr-rtos/)
|
- [Web dashboard on Zephyr RTOS](https://mongoose.ws/articles/web-dashboard-on-zephyr-rtos/)
|
||||||
|
- [Limiting TCP/IP RAM usage on STM32](https://mongoose.ws/articles/limiting-tcpip-ram-usage-on-stm32/)
|
||||||
|
- [STM32 Ethernet explained](https://mongoose.ws/articles/stm32-ethernet-explained/)
|
||||||
|
- [MQTT on a Microcontroller](https://mongoose.ws/articles/mqtt-on-a-microcontroller/)
|
||||||
|
- [STM32 OTA Firmware Update](https://mongoose.ws/articles/stm32-ota-firmware-update/)
|
||||||
|
- [RP2350 OTA Firmware Update](https://mongoose.ws/articles/rp2350-ota-firmware-update/)
|
||||||
|
- [STM32 Ethernet and caches](https://mongoose.ws/articles/stm32-ethernet-and-cache/)
|
||||||
|
- [NXP RW612 OTA Firmware Update](https://mongoose.ws/articles/rw612-ota-firmware-update/)
|
||||||
|
- [lwIP vs Mongoose - TCP/IP Stack Integration Benchmark](https://mongoose.ws/articles/lwip-vs-mongoose-tcpip-stack-integration/)
|
||||||
|
|
||||||
|
|
||||||
## Contributions
|
## Contributions
|
||||||
|
|||||||
+5062
-1536
File diff suppressed because it is too large.
Load diff
+420
-103
@@ -20,7 +20,7 @@
|
|||||||
#ifndef MONGOOSE_H
|
#ifndef MONGOOSE_H
|
||||||
#define MONGOOSE_H
|
#define MONGOOSE_H
|
||||||
|
|
||||||
#define MG_VERSION "7.19"
|
#define MG_VERSION "7.21"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -159,11 +159,14 @@ extern "C" {
|
|||||||
#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
|
#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && !defined(MG_ENABLE_DRIVER_STM32H)
|
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && \
|
||||||
|
!defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_STM32N)
|
||||||
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
|
||||||
#define MG_ENABLE_DRIVER_STM32F 1
|
#define MG_ENABLE_DRIVER_STM32F 1
|
||||||
#elif defined(STM32H5) || defined(STM32H7)
|
#elif defined(STM32H5) || defined(STM32H7)
|
||||||
#define MG_ENABLE_DRIVER_STM32H 1
|
#define MG_ENABLE_DRIVER_STM32H 1
|
||||||
|
#elif defined(STM32N6)
|
||||||
|
#define MG_ENABLE_DRIVER_STM32N 1
|
||||||
#else
|
#else
|
||||||
#error Select a driver in mongoose_config.h
|
#error Select a driver in mongoose_config.h
|
||||||
#endif
|
#endif
|
||||||
@@ -173,7 +176,8 @@ extern "C" {
|
|||||||
#define MG_TLS MG_TLS_BUILTIN
|
#define MG_TLS MG_TLS_BUILTIN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
|
#if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || \
|
||||||
|
defined(STM32F4) || defined(STM32F7)
|
||||||
#define MG_OTA MG_OTA_STM32F
|
#define MG_OTA MG_OTA_STM32F
|
||||||
#elif !defined(MG_OTA) && defined(STM32H5)
|
#elif !defined(MG_OTA) && defined(STM32H5)
|
||||||
#define MG_OTA MG_OTA_STM32H5
|
#define MG_OTA MG_OTA_STM32H5
|
||||||
@@ -285,6 +289,7 @@ extern "C" {
|
|||||||
#define mode_t size_t
|
#define mode_t size_t
|
||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
|
||||||
#elif defined(__CCRH__)
|
#elif defined(__CCRH__)
|
||||||
#else
|
#else
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -650,7 +655,10 @@ typedef enum { false = 0, true = 1 } bool;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef unsigned long nfds_t;
|
#if defined(MG_ENABLE_POLL) && MG_ENABLE_POLL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP)
|
||||||
|
typedef unsigned long nfds_t; // see #3388
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#if MG_ENABLE_WINSOCK
|
#if MG_ENABLE_WINSOCK
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
@@ -721,13 +729,15 @@ typedef int socklen_t;
|
|||||||
#if MG_ARCH == MG_ARCH_ZEPHYR
|
#if MG_ARCH == MG_ARCH_ZEPHYR
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/net/socket.h>
|
||||||
|
// #include <zephyr/posix/dirent.h>
|
||||||
|
#include <zephyr/posix/fcntl.h>
|
||||||
|
#include <zephyr/posix/sys/select.h>
|
||||||
|
#include <zephyr/random/random.h>
|
||||||
#include <zephyr/version.h>
|
#include <zephyr/version.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <zephyr/net/socket.h>
|
|
||||||
#include <zephyr/posix/fcntl.h>
|
|
||||||
#include <zephyr/posix/sys/select.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -1056,10 +1066,34 @@ struct timeval {
|
|||||||
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
|
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_GLOBAL
|
||||||
|
#define MG_TCPIP_GLOBAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_IPV6_LINKLOCAL
|
||||||
|
#define MG_TCPIP_IPV6_LINKLOCAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_PREFIX_LEN
|
||||||
|
#define MG_TCPIP_PREFIX_LEN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_GW6
|
||||||
|
#define MG_TCPIP_GW6 MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MG_SET_MAC_ADDRESS
|
#ifndef MG_SET_MAC_ADDRESS
|
||||||
#define MG_SET_MAC_ADDRESS(mac)
|
#define MG_SET_MAC_ADDRESS(mac)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_DHCPNAME_SIZE
|
||||||
|
#define MG_TCPIP_DHCPNAME_SIZE 18 // struct mg_tcpip_if :: dhcp_name size
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MG_SET_WIFI_CONFIG
|
#ifndef MG_SET_WIFI_CONFIG
|
||||||
#define MG_SET_WIFI_CONFIG(data)
|
#define MG_SET_WIFI_CONFIG(data)
|
||||||
#endif
|
#endif
|
||||||
@@ -1206,7 +1240,6 @@ size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap);
|
|||||||
size_t mg_snprintf(char *, size_t, const char *fmt, ...);
|
size_t mg_snprintf(char *, size_t, const char *fmt, ...);
|
||||||
char *mg_vmprintf(const char *fmt, va_list *ap);
|
char *mg_vmprintf(const char *fmt, va_list *ap);
|
||||||
char *mg_mprintf(const char *fmt, ...);
|
char *mg_mprintf(const char *fmt, ...);
|
||||||
size_t mg_queue_vprintf(struct mg_queue *, const char *fmt, va_list *);
|
|
||||||
size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
|
size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
|
||||||
|
|
||||||
// %M print helper functions
|
// %M print helper functions
|
||||||
@@ -1218,10 +1251,12 @@ size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap);
|
|||||||
size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap);
|
size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap);
|
||||||
size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap);
|
size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap);
|
||||||
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap);
|
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap);
|
||||||
|
size_t mg_print_l2addr(void (*out)(char, void *), void *arg, va_list *ap);
|
||||||
|
|
||||||
// Various output functions
|
// Various output functions
|
||||||
void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf *
|
void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf *
|
||||||
void mg_pfn_stdout(char c, void *param); // param: ignored
|
void mg_pfn_iobuf_noresize(char ch, void *param); // param: struct mg_iobuf *
|
||||||
|
void mg_pfn_stdout(char c, void *param); // param: ignored
|
||||||
|
|
||||||
// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
|
// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
|
||||||
#define MG_ESC(str) mg_print_esc, 0, (str)
|
#define MG_ESC(str) mg_print_esc, 0, (str)
|
||||||
@@ -1243,12 +1278,18 @@ void mg_log_set_fn(mg_pfn_t fn, void *param);
|
|||||||
#define mg_log_set(level_) mg_log_level = (level_)
|
#define mg_log_set(level_) mg_log_level = (level_)
|
||||||
|
|
||||||
#if MG_ENABLE_LOG
|
#if MG_ENABLE_LOG
|
||||||
#define MG_LOG(level, args) \
|
#if !defined(_MSC_VER) && \
|
||||||
do { \
|
(!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
|
||||||
if ((level) <= mg_log_level) { \
|
#define MG___FUNC__ ""
|
||||||
mg_log_prefix((level), __FILE__, __LINE__, __func__); \
|
#else
|
||||||
mg_log args; \
|
#define MG___FUNC__ __func__ // introduced in C99
|
||||||
} \
|
#endif
|
||||||
|
#define MG_LOG(level, args) \
|
||||||
|
do { \
|
||||||
|
if ((level) <= mg_log_level) { \
|
||||||
|
mg_log_prefix((level), __FILE__, __LINE__, MG___FUNC__); \
|
||||||
|
mg_log args; \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define MG_LOG(level, args) \
|
#define MG_LOG(level, args) \
|
||||||
@@ -1364,6 +1405,16 @@ void mg_delayms(unsigned int ms);
|
|||||||
|
|
||||||
#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
|
#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
|
||||||
|
|
||||||
|
#define MG_IPV6(a, b, c, d, e, f, g ,h) \
|
||||||
|
{ (uint8_t)((a)>>8),(uint8_t)(a), \
|
||||||
|
(uint8_t)((b)>>8),(uint8_t)(b), \
|
||||||
|
(uint8_t)((c)>>8),(uint8_t)(c), \
|
||||||
|
(uint8_t)((d)>>8),(uint8_t)(d), \
|
||||||
|
(uint8_t)((e)>>8),(uint8_t)(e), \
|
||||||
|
(uint8_t)((f)>>8),(uint8_t)(f), \
|
||||||
|
(uint8_t)((g)>>8),(uint8_t)(g), \
|
||||||
|
(uint8_t)((h)>>8),(uint8_t)(h) }
|
||||||
|
|
||||||
// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
|
// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
|
||||||
#define MG_U8P(ADDR) ((uint8_t *) (ADDR))
|
#define MG_U8P(ADDR) ((uint8_t *) (ADDR))
|
||||||
#define MG_IPADDR_PARTS(ADDR) \
|
#define MG_IPADDR_PARTS(ADDR) \
|
||||||
@@ -1378,6 +1429,14 @@ void mg_delayms(unsigned int ms);
|
|||||||
((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
|
((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
|
||||||
((uint32_t) MG_U8P(p)[1] << 16U) | \
|
((uint32_t) MG_U8P(p)[1] << 16U) | \
|
||||||
((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
|
((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
|
||||||
|
#define MG_LOAD_BE64(p) \
|
||||||
|
((uint64_t) (((uint64_t) MG_U8P(p)[0] << 56U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[1] << 48U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[2] << 40U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[3] << 32U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[4] << 24U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[5] << 16U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[6] << 8U) | MG_U8P(p)[7]))
|
||||||
#define MG_STORE_BE16(p, n) \
|
#define MG_STORE_BE16(p, n) \
|
||||||
do { \
|
do { \
|
||||||
MG_U8P(p)[0] = ((n) >> 8U) & 255; \
|
MG_U8P(p)[0] = ((n) >> 8U) & 255; \
|
||||||
@@ -1396,11 +1455,24 @@ void mg_delayms(unsigned int ms);
|
|||||||
MG_U8P(p)[2] = ((n) >> 8U) & 255; \
|
MG_U8P(p)[2] = ((n) >> 8U) & 255; \
|
||||||
MG_U8P(p)[3] = (n) &255; \
|
MG_U8P(p)[3] = (n) &255; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
#define MG_STORE_BE64(p, n) \
|
||||||
|
do { \
|
||||||
|
MG_U8P(p)[0] = ((n) >> 56U) & 255; \
|
||||||
|
MG_U8P(p)[1] = ((n) >> 48U) & 255; \
|
||||||
|
MG_U8P(p)[2] = ((n) >> 40U) & 255; \
|
||||||
|
MG_U8P(p)[3] = ((n) >> 32U) & 255; \
|
||||||
|
MG_U8P(p)[4] = ((n) >> 24U) & 255; \
|
||||||
|
MG_U8P(p)[5] = ((n) >> 16U) & 255; \
|
||||||
|
MG_U8P(p)[6] = ((n) >> 8U) & 255; \
|
||||||
|
MG_U8P(p)[7] = (n) &255; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
uint16_t mg_ntohs(uint16_t net);
|
uint16_t mg_ntohs(uint16_t net);
|
||||||
uint32_t mg_ntohl(uint32_t net);
|
uint32_t mg_ntohl(uint32_t net);
|
||||||
|
uint64_t mg_ntohll(uint64_t net);
|
||||||
#define mg_htons(x) mg_ntohs(x)
|
#define mg_htons(x) mg_ntohs(x)
|
||||||
#define mg_htonl(x) mg_ntohl(x)
|
#define mg_htonl(x) mg_ntohl(x)
|
||||||
|
#define mg_htonll(x) mg_ntohll(x)
|
||||||
|
|
||||||
#define MG_REG(x) ((volatile uint32_t *) (x))[0]
|
#define MG_REG(x) ((volatile uint32_t *) (x))[0]
|
||||||
#define MG_BIT(x) (((uint32_t) 1U) << (x))
|
#define MG_BIT(x) (((uint32_t) 1U) << (x))
|
||||||
@@ -1484,8 +1556,8 @@ struct mg_iobuf {
|
|||||||
size_t align; // Alignment during allocation
|
size_t align; // Alignment during allocation
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
|
bool mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
|
||||||
int mg_iobuf_resize(struct mg_iobuf *, size_t);
|
bool mg_iobuf_resize(struct mg_iobuf *, size_t);
|
||||||
void mg_iobuf_free(struct mg_iobuf *);
|
void mg_iobuf_free(struct mg_iobuf *);
|
||||||
size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
|
size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
|
||||||
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
|
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
|
||||||
@@ -1586,6 +1658,8 @@ enum {
|
|||||||
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
||||||
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
|
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
|
||||||
MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data
|
MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data
|
||||||
|
MG_EV_MDNS_REQ, // mDNS request struct mg_mdns_req *
|
||||||
|
MG_EV_MDNS_RESP, // mDNS response struct mg_mdns_resp *
|
||||||
MG_EV_USER // Starting ID for user events
|
MG_EV_USER // Starting ID for user events
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1604,7 +1678,11 @@ struct mg_dns {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mg_addr {
|
struct mg_addr {
|
||||||
uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order
|
union { // Holds IPv4 or IPv6 address, in network byte order
|
||||||
|
uint8_t ip[16];
|
||||||
|
uint32_t ip4;
|
||||||
|
uint64_t ip6[2];
|
||||||
|
} addr;
|
||||||
uint16_t port; // TCP or UDP port in network byte order
|
uint16_t port; // TCP or UDP port in network byte order
|
||||||
uint8_t scope_id; // IPv6 scope ID
|
uint8_t scope_id; // IPv6 scope ID
|
||||||
bool is_ip6; // True when address is IPv6 address
|
bool is_ip6; // True when address is IPv6 address
|
||||||
@@ -1698,6 +1776,7 @@ struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
|
|||||||
struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
|
struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data,
|
mg_event_handler_t fn, void *fn_data,
|
||||||
mg_event_handler_t pfn, void *pfn_data);
|
mg_event_handler_t pfn, void *pfn_data);
|
||||||
|
void mg_multicast_restore(struct mg_connection *c, uint8_t *from);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1740,7 +1819,6 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
|
|||||||
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
|
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
|
||||||
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
|
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
|
||||||
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
|
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
|
||||||
void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm);
|
|
||||||
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data);
|
mg_event_handler_t fn, void *fn_data);
|
||||||
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
||||||
@@ -1803,6 +1881,7 @@ void mg_tls_handshake(struct mg_connection *);
|
|||||||
// Private
|
// Private
|
||||||
void mg_tls_ctx_init(struct mg_mgr *);
|
void mg_tls_ctx_init(struct mg_mgr *);
|
||||||
void mg_tls_ctx_free(struct mg_mgr *);
|
void mg_tls_ctx_free(struct mg_mgr *);
|
||||||
|
#define MG_IS_DER(buf) (((uint8_t *) (buf))[0] == 0x30) // DER begins with 0x30
|
||||||
|
|
||||||
// Low-level IO primives used by TLS layer
|
// Low-level IO primives used by TLS layer
|
||||||
enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
|
enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
|
||||||
@@ -1882,7 +1961,9 @@ int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
|
|||||||
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||||
size_t input_length, const unsigned char *key,
|
size_t input_length, const unsigned char *key,
|
||||||
const size_t key_len, const unsigned char *iv,
|
const size_t key_len, const unsigned char *iv,
|
||||||
const size_t iv_len);
|
const size_t iv_len, unsigned char *aead,
|
||||||
|
size_t aead_len, const unsigned char *tag,
|
||||||
|
const size_t tag_len);
|
||||||
|
|
||||||
#endif /* TLS_AES128_H */
|
#endif /* TLS_AES128_H */
|
||||||
|
|
||||||
@@ -2648,6 +2729,7 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
|
|||||||
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
||||||
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
||||||
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
||||||
|
const uint8_t *restrict ad, size_t ad_size,
|
||||||
const uint8_t *restrict cipher_text, size_t cipher_text_size);
|
const uint8_t *restrict cipher_text, size_t cipher_text_size);
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
@@ -2659,7 +2741,13 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
|||||||
|
|
||||||
|
|
||||||
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
|
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
|
||||||
|
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
|
||||||
|
const uint8_t *dP, size_t dP_len,
|
||||||
|
const uint8_t *dQ, size_t dQ_len,
|
||||||
|
const uint8_t *p, size_t p_len,
|
||||||
|
const uint8_t *q, size_t q_len,
|
||||||
|
const uint8_t *qInv, size_t qInv_len,
|
||||||
|
uint8_t *signature, size_t sig_len);
|
||||||
#endif // TLS_RSA_H
|
#endif // TLS_RSA_H
|
||||||
|
|
||||||
|
|
||||||
@@ -2851,6 +2939,7 @@ struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
|
|||||||
void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
||||||
uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
||||||
void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts);
|
void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts);
|
||||||
|
void mg_mqtt_unsub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
||||||
int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
|
int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
|
||||||
void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
|
void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
|
||||||
uint32_t len);
|
uint32_t len);
|
||||||
@@ -2864,6 +2953,12 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *, struct mg_mqtt_prop *,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define MG_DNS_RTYPE_A 1
|
||||||
|
#define MG_DNS_RTYPE_PTR 12
|
||||||
|
#define MG_DNS_RTYPE_TXT 16
|
||||||
|
#define MG_DNS_RTYPE_AAAA 28
|
||||||
|
#define MG_DNS_RTYPE_SRV 33
|
||||||
|
|
||||||
// Mongoose sends DNS queries that contain only one question:
|
// Mongoose sends DNS queries that contain only one question:
|
||||||
// either A (IPv4) or AAAA (IPv6) address lookup.
|
// either A (IPv4) or AAAA (IPv6) address lookup.
|
||||||
// Therefore, we expect zero or one answer.
|
// Therefore, we expect zero or one answer.
|
||||||
@@ -2892,13 +2987,42 @@ struct mg_dns_rr {
|
|||||||
uint16_t alen; // Address length
|
uint16_t alen; // Address length
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DNS-SD response record
|
||||||
|
struct mg_dnssd_record {
|
||||||
|
struct mg_str srvcproto; // service.proto, service name
|
||||||
|
struct mg_str txt; // TXT record contents
|
||||||
|
uint16_t port; // SRV record port
|
||||||
|
};
|
||||||
|
|
||||||
|
// mDNS request and response data structs passed to event handlers
|
||||||
|
struct mg_mdns_req {
|
||||||
|
struct mg_dns_rr *rr;
|
||||||
|
struct mg_dnssd_record *r;
|
||||||
|
struct mg_str reqname; // requested name in RR
|
||||||
|
struct mg_str respname; // actual name to use in response
|
||||||
|
struct mg_addr *addr; // actual address to use in response
|
||||||
|
bool is_listing;
|
||||||
|
bool is_resp;
|
||||||
|
bool is_unicast;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mg_mdns_resp {
|
||||||
|
struct mg_dns_rr *rr;
|
||||||
|
// TODO(scaprile )struct mg_str srvcproto; struct mg_str txt; uint16_t port; ?
|
||||||
|
struct mg_str name;
|
||||||
|
struct mg_addr addr;
|
||||||
|
// TODO(scaprile); bool has_A; bool has_PTR; bool has_SRV; bool has_TXT; ?
|
||||||
|
};
|
||||||
|
|
||||||
void mg_resolve(struct mg_connection *, const char *url);
|
void mg_resolve(struct mg_connection *, const char *url);
|
||||||
void mg_resolve_cancel(struct mg_connection *);
|
void mg_resolve_cancel(struct mg_connection *);
|
||||||
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
|
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
|
||||||
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
|
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
|
||||||
bool is_question, struct mg_dns_rr *);
|
bool is_question, struct mg_dns_rr *);
|
||||||
|
|
||||||
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name);
|
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn,
|
||||||
|
void *fn_data);
|
||||||
|
bool mg_mdns_query(struct mg_connection *, const char *, unsigned int);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -2975,8 +3099,8 @@ void mg_rpc_list(struct mg_rpc_req *r);
|
|||||||
#define MG_OTA_RT1060 302 // IMXRT1060
|
#define MG_OTA_RT1060 302 // IMXRT1060
|
||||||
#define MG_OTA_RT1064 303 // IMXRT1064
|
#define MG_OTA_RT1064 303 // IMXRT1064
|
||||||
#define MG_OTA_RT1170 304 // IMXRT1170
|
#define MG_OTA_RT1170 304 // IMXRT1170
|
||||||
#define MG_OTA_MCXN 310 // MCXN947
|
#define MG_OTA_MCXN 310 // MCXN947
|
||||||
#define MG_OTA_FRDM 320 // FRDM-RW612
|
#define MG_OTA_RW612 320 // FRDM-RW612
|
||||||
#define MG_OTA_FLASH 900 // OTA via an internal flash
|
#define MG_OTA_FLASH 900 // OTA via an internal flash
|
||||||
#define MG_OTA_ESP32 910 // ESP32 OTA implementation
|
#define MG_OTA_ESP32 910 // ESP32 OTA implementation
|
||||||
#define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash
|
#define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash
|
||||||
@@ -3023,34 +3147,104 @@ bool mg_ota_flash_end(struct mg_flash *flash);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct mg_wifi_scan_bss_data {
|
struct mg_wifi_data {
|
||||||
struct mg_str SSID;
|
char *ssid, *pass; // STA mode, SSID to connect to
|
||||||
char *BSSID;
|
char *apssid, *appass; // AP mode, our SSID
|
||||||
int16_t RSSI;
|
uint32_t apip, apmask; // AP mode, our IP address and mask
|
||||||
uint8_t security;
|
uint8_t security; // STA mode, TBD
|
||||||
#define MG_WIFI_SECURITY_OPEN 0
|
uint8_t apsecurity; // AP mode, TBD
|
||||||
#define MG_WIFI_SECURITY_WEP MG_BIT(0)
|
uint8_t apchannel; // AP mode, channel to use
|
||||||
#define MG_WIFI_SECURITY_WPA MG_BIT(1)
|
bool apmode; // start in AP mode; 'false' -> connect to 'ssid' != NULL
|
||||||
#define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
|
|
||||||
#define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
|
|
||||||
uint8_t channel;
|
|
||||||
unsigned band :2;
|
|
||||||
#define MG_WIFI_BAND_2G 0
|
|
||||||
#define MG_WIFI_BAND_5G 1
|
|
||||||
unsigned has_n :1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mg_wifi_scan_bss_data {
|
||||||
|
struct mg_str SSID;
|
||||||
|
char *BSSID;
|
||||||
|
int16_t RSSI;
|
||||||
|
uint8_t security;
|
||||||
|
#define MG_WIFI_SECURITY_OPEN 0
|
||||||
|
#define MG_WIFI_SECURITY_WEP MG_BIT(0)
|
||||||
|
#define MG_WIFI_SECURITY_WPA MG_BIT(1)
|
||||||
|
#define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
|
||||||
|
#define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
|
||||||
|
#define MG_WIFI_SECURITY_WPA_ENTERPRISE MG_BIT(4)
|
||||||
|
#define MG_WIFI_SECURITY_WPA2_ENTERPRISE MG_BIT(5)
|
||||||
|
#define MG_WIFI_SECURITY_WPA3_ENTERPRISE MG_BIT(6)
|
||||||
|
uint8_t channel;
|
||||||
|
unsigned band : 2;
|
||||||
|
#define MG_WIFI_BAND_2G 0
|
||||||
|
#define MG_WIFI_BAND_5G 1
|
||||||
|
unsigned has_n : 1;
|
||||||
|
unsigned has_ac : 1;
|
||||||
|
unsigned has_ax : 1;
|
||||||
|
};
|
||||||
|
|
||||||
bool mg_wifi_scan(void);
|
bool mg_wifi_scan(void);
|
||||||
bool mg_wifi_connect(char *ssid, char *pass);
|
bool mg_wifi_connect(struct mg_wifi_data *);
|
||||||
bool mg_wifi_disconnect(void);
|
bool mg_wifi_disconnect(void);
|
||||||
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel);
|
bool mg_wifi_ap_start(struct mg_wifi_data *);
|
||||||
bool mg_wifi_ap_stop(void);
|
bool mg_wifi_ap_stop(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
|
||||||
|
// no config defaults to 0 => Ethernet
|
||||||
|
enum mg_l2type { MG_TCPIP_L2_ETH = 0, MG_TCPIP_L2_PPP }; // MG_TCPIP_L2_PPPoE
|
||||||
|
|
||||||
|
#if defined(__DCC__)
|
||||||
|
#pragma pack(1)
|
||||||
|
#else
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct mg_l2addr {
|
||||||
|
union {
|
||||||
|
uint8_t mac[6];
|
||||||
|
} addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__DCC__)
|
||||||
|
#pragma pack(0)
|
||||||
|
#else
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
TODO(): ?
|
||||||
|
struct eth_opts {
|
||||||
|
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
|
||||||
|
bool enable_mac_check; // Do a MAC check on RX frames
|
||||||
|
};
|
||||||
|
struct mg_l2opts {
|
||||||
|
union {
|
||||||
|
struct eth_opts eth;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum mg_l2proto {
|
||||||
|
MG_TCPIP_L2PROTO_IPV4 = 0,
|
||||||
|
MG_TCPIP_L2PROTO_IPV6,
|
||||||
|
MG_TCPIP_L2PROTO_ARP,
|
||||||
|
MG_TCPIP_L2PROTO_PPPoE_DISC,
|
||||||
|
MG_TCPIP_L2PROTO_PPPoE_SESS
|
||||||
|
};
|
||||||
|
enum mg_l2addrtype {
|
||||||
|
MG_TCPIP_L2ADDR_BCAST,
|
||||||
|
MG_TCPIP_L2ADDR_MCAST,
|
||||||
|
MG_TCPIP_L2ADDR_MCAST6
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if MG_ENABLE_TCPIP
|
#if MG_ENABLE_TCPIP
|
||||||
@@ -3068,45 +3262,58 @@ typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev,
|
|||||||
void *ev_data);
|
void *ev_data);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
|
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
|
||||||
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
|
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
|
||||||
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
|
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
|
||||||
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
|
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
|
||||||
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
|
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
|
||||||
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct mg_wifi_scan_bss_data *
|
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct
|
||||||
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
|
// mg_wifi_scan_bss_data *
|
||||||
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and chip specific
|
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
|
||||||
MG_TCPIP_EV_DRIVER, // Driver event driver specific
|
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and
|
||||||
MG_TCPIP_EV_USER // Starting ID for user events
|
// chip specific
|
||||||
|
MG_TCPIP_EV_DRIVER, // Driver event driver specific
|
||||||
|
MG_TCPIP_EV_ST6_CHG, // state6 change uint8_t *
|
||||||
|
// (&ifp->state6)
|
||||||
|
MG_TCPIP_EV_USER // Starting ID for user events
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Network interface
|
// Network interface
|
||||||
struct mg_tcpip_if {
|
struct mg_tcpip_if {
|
||||||
uint8_t mac[6]; // MAC address. Must be set to a valid MAC
|
uint8_t mac[sizeof(struct mg_l2addr)]; // hw address. Set to a valid addr
|
||||||
uint32_t ip, mask, gw; // IP address, mask, default gateway
|
uint32_t ip, mask, gw; // IP address, mask, default gateway
|
||||||
struct mg_str tx; // Output (TX) buffer
|
struct mg_str tx; // Output (TX) buffer
|
||||||
bool enable_dhcp_client; // Enable DCHP client
|
bool enable_dhcp_client; // Enable DCHP client
|
||||||
bool enable_dhcp_server; // Enable DCHP server
|
bool enable_dhcp_server; // Enable DCHP server
|
||||||
bool enable_get_gateway; // DCHP server sets client as gateway
|
bool enable_get_gateway; // DCHP server sets client as gateway
|
||||||
bool enable_req_dns; // DCHP client requests DNS server
|
bool enable_req_dns; // DCHP client requests DNS server
|
||||||
bool enable_req_sntp; // DCHP client requests SNTP server
|
bool enable_req_sntp; // DCHP client requests SNTP server
|
||||||
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
|
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
|
||||||
bool enable_mac_check; // Do a MAC check on RX frames
|
bool enable_mac_check; // Do a MAC check on RX frames
|
||||||
bool update_mac_hash_table; // Signal drivers to update MAC controller
|
bool update_mac_hash_table; // Signal drivers to update MAC controller
|
||||||
struct mg_tcpip_driver *driver; // Low level driver
|
struct mg_tcpip_driver *driver; // Low level driver
|
||||||
void *driver_data; // Driver-specific data
|
void *driver_data; // Driver-specific data
|
||||||
|
mg_tcpip_event_handler_t pfn; // Driver-specific event handler function
|
||||||
mg_tcpip_event_handler_t fn; // User-specified event handler function
|
mg_tcpip_event_handler_t fn; // User-specified event handler function
|
||||||
struct mg_mgr *mgr; // Mongoose event manager
|
struct mg_mgr *mgr; // Mongoose event manager
|
||||||
struct mg_queue recv_queue; // Receive queue
|
struct mg_queue recv_queue; // Receive queue
|
||||||
char dhcp_name[12]; // Name reported to DHCP, "mip" if unset
|
char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Name for DHCP, "mip" if unset
|
||||||
uint16_t mtu; // Interface MTU
|
uint16_t mtu; // Interface link payload
|
||||||
#define MG_TCPIP_MTU_DEFAULT 1500
|
uint16_t framesize; // Interface frame max length
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses,
|
||||||
|
uint8_t prefix[8]; // prefix,
|
||||||
|
uint8_t prefix_len; // prefix length,
|
||||||
|
uint64_t gw6[2]; // default gateway.
|
||||||
|
bool enable_slaac; // Enable IPv6 address autoconfiguration
|
||||||
|
bool enable_dhcp6_client; // Enable DCHPv6 client TODO()
|
||||||
|
#endif
|
||||||
|
|
||||||
// Internal state, user can use it but should not change it
|
// Internal state, user can use it but should not change it
|
||||||
uint8_t gwmac[6]; // Router's MAC
|
uint8_t gwmac[sizeof(struct mg_l2addr)]; // Router's hw address
|
||||||
char *dns4_url; // DNS server URL
|
enum mg_l2type l2type; // Ethernet, PPP, etc.
|
||||||
uint64_t now; // Current time
|
char *dns4_url; // DNS server URL
|
||||||
|
uint64_t now; // Current time
|
||||||
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
|
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
|
||||||
uint64_t lease_expire; // Lease expiration time, in ms
|
uint64_t lease_expire; // Lease expiration time, in ms
|
||||||
uint16_t eport; // Next ephemeral port
|
uint16_t eport; // Next ephemeral port
|
||||||
@@ -3114,12 +3321,18 @@ struct mg_tcpip_if {
|
|||||||
volatile uint32_t nrecv; // Number of received frames
|
volatile uint32_t nrecv; // Number of received frames
|
||||||
volatile uint32_t nsent; // Number of transmitted frames
|
volatile uint32_t nsent; // Number of transmitted frames
|
||||||
volatile uint32_t nerr; // Number of driver errors
|
volatile uint32_t nerr; // Number of driver errors
|
||||||
uint8_t state; // Current state
|
uint8_t state; // Current link and IPv4 state
|
||||||
#define MG_TCPIP_STATE_DOWN 0 // Interface is down
|
#define MG_TCPIP_STATE_DOWN 0 // Interface is down
|
||||||
#define MG_TCPIP_STATE_UP 1 // Interface is up
|
#define MG_TCPIP_STATE_UP 1 // Interface is up
|
||||||
#define MG_TCPIP_STATE_REQ 2 // Interface is up, DHCP REQUESTING state
|
#define MG_TCPIP_STATE_REQ 2 // Interface is up, DHCP REQUESTING state
|
||||||
#define MG_TCPIP_STATE_IP 3 // Interface is up and has an IP assigned
|
#define MG_TCPIP_STATE_IP 3 // Interface is up and has an IP assigned
|
||||||
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work
|
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work
|
||||||
|
bool gw_ready; // We've got a hw address for the router
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
uint8_t gw6mac[sizeof(struct mg_l2addr)]; // IPV6 Router's hw address
|
||||||
|
uint8_t state6; // Current IPv6 state
|
||||||
|
bool gw6_ready; // We've got a hw address for the IPv6 router
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
|
void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
|
||||||
@@ -3143,6 +3356,8 @@ extern struct mg_tcpip_driver mg_tcpip_driver_ppp;
|
|||||||
extern struct mg_tcpip_driver mg_tcpip_driver_pico_w;
|
extern struct mg_tcpip_driver mg_tcpip_driver_pico_w;
|
||||||
extern struct mg_tcpip_driver mg_tcpip_driver_rw612;
|
extern struct mg_tcpip_driver mg_tcpip_driver_rw612;
|
||||||
extern struct mg_tcpip_driver mg_tcpip_driver_cyw;
|
extern struct mg_tcpip_driver mg_tcpip_driver_cyw;
|
||||||
|
extern struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi;
|
||||||
|
extern struct mg_tcpip_driver mg_tcpip_driver_st67w6;
|
||||||
|
|
||||||
// Drivers that require SPI, can use this SPI abstraction
|
// Drivers that require SPI, can use this SPI abstraction
|
||||||
struct mg_tcpip_spi {
|
struct mg_tcpip_spi {
|
||||||
@@ -3152,6 +3367,42 @@ struct mg_tcpip_spi {
|
|||||||
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
|
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Alignment and memory section requirements
|
||||||
|
#ifndef MG_8BYTE_ALIGNED
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U))))
|
||||||
|
#else
|
||||||
|
#define MG_8BYTE_ALIGNED
|
||||||
|
#endif // compiler
|
||||||
|
#endif // 8BYTE_ALIGNED
|
||||||
|
|
||||||
|
#ifndef MG_16BYTE_ALIGNED
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define MG_16BYTE_ALIGNED __attribute__((aligned((16U))))
|
||||||
|
#else
|
||||||
|
#define MG_16BYTE_ALIGNED
|
||||||
|
#endif // compiler
|
||||||
|
#endif // 16BYTE_ALIGNED
|
||||||
|
|
||||||
|
#ifndef MG_32BYTE_ALIGNED
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define MG_32BYTE_ALIGNED __attribute__((aligned((32U))))
|
||||||
|
#else
|
||||||
|
#define MG_32BYTE_ALIGNED
|
||||||
|
#endif // compiler
|
||||||
|
#endif // 32BYTE_ALIGNED
|
||||||
|
|
||||||
|
#ifndef MG_64BYTE_ALIGNED
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define MG_64BYTE_ALIGNED __attribute__((aligned((64U))))
|
||||||
|
#else
|
||||||
|
#define MG_64BYTE_ALIGNED
|
||||||
|
#endif // compiler
|
||||||
|
#endif // 64BYTE_ALIGNED
|
||||||
|
|
||||||
|
#ifndef MG_ETH_RAM
|
||||||
|
#define MG_ETH_RAM
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -3186,43 +3437,35 @@ struct mg_tcpip_driver_cyw_firmware {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mg_tcpip_driver_cyw_data {
|
struct mg_tcpip_driver_cyw_data {
|
||||||
|
struct mg_wifi_data wifi;
|
||||||
void *bus;
|
void *bus;
|
||||||
struct mg_tcpip_driver_cyw_firmware *fw;
|
struct mg_tcpip_driver_cyw_firmware *fw;
|
||||||
char *ssid;
|
bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
|
||||||
char *pass;
|
|
||||||
char *apssid;
|
|
||||||
char *appass;
|
|
||||||
uint8_t security; // TBD
|
|
||||||
uint8_t apsecurity; // TBD
|
|
||||||
uint8_t apchannel;
|
|
||||||
bool apmode; // start in AP mode; 'false' starts connection to 'ssid' if not NULL
|
|
||||||
bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
do { \
|
||||||
do { \
|
static struct mg_tcpip_driver_cyw_data driver_data_; \
|
||||||
static struct mg_tcpip_driver_cyw_data driver_data_; \
|
static struct mg_tcpip_if mif_; \
|
||||||
static struct mg_tcpip_if mif_; \
|
MG_SET_WIFI_CONFIG(&driver_data_); \
|
||||||
MG_SET_WIFI_CONFIG(&driver_data_); \
|
mif_.ip = MG_TCPIP_IP; \
|
||||||
mif_.ip = MG_TCPIP_IP; \
|
mif_.mask = MG_TCPIP_MASK; \
|
||||||
mif_.mask = MG_TCPIP_MASK; \
|
mif_.gw = MG_TCPIP_GW; \
|
||||||
mif_.gw = MG_TCPIP_GW; \
|
mif_.driver = &mg_tcpip_driver_cyw; \
|
||||||
mif_.driver = &mg_tcpip_driver_pico_w; \
|
mif_.driver_data = &driver_data_; \
|
||||||
mif_.driver_data = &driver_data_; \
|
mif_.recv_queue.size = 8192; \
|
||||||
mif_.recv_queue.size = 8192; \
|
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
|
||||||
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
|
mg_tcpip_init(mgr, &mif_); \
|
||||||
mg_tcpip_init(mgr, &mif_); \
|
|
||||||
MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
|
MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if MG_ENABLE_TCPIP && \
|
#if MG_ENABLE_TCPIP && \
|
||||||
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
|
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
|
||||||
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11)
|
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
|
||||||
|
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
|
||||||
|
|
||||||
struct mg_tcpip_driver_imxrt_data {
|
struct mg_tcpip_driver_imxrt_data {
|
||||||
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
|
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
|
||||||
@@ -3268,6 +3511,34 @@ struct mg_tcpip_driver_imxrt_data {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && \
|
||||||
|
defined(MG_ENABLE_DRIVER_NXP_WIFI) && MG_ENABLE_DRIVER_NXP_WIFI
|
||||||
|
|
||||||
|
|
||||||
|
struct mg_tcpip_driver_nxp_wifi_data {
|
||||||
|
struct mg_wifi_data wifi;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
|
do { \
|
||||||
|
static struct mg_tcpip_driver_nxp_wifi_data driver_data_; \
|
||||||
|
static struct mg_tcpip_if mif_; \
|
||||||
|
MG_SET_WIFI_CONFIG(&driver_data_); \
|
||||||
|
mif_.ip = MG_TCPIP_IP; \
|
||||||
|
mif_.mask = MG_TCPIP_MASK; \
|
||||||
|
mif_.gw = MG_TCPIP_GW; \
|
||||||
|
mif_.driver = &mg_tcpip_driver_nxp_wifi; \
|
||||||
|
mif_.driver_data = &driver_data_; \
|
||||||
|
mif_.recv_queue.size = 8192; \
|
||||||
|
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
|
||||||
|
mg_tcpip_init(mgr, &mif_); \
|
||||||
|
MG_INFO(("Driver: nxp wifi, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct mg_phy {
|
struct mg_phy {
|
||||||
@@ -3298,14 +3569,7 @@ bool mg_phy_up(struct mg_phy *, uint8_t addr, bool *full_duplex,
|
|||||||
#include "pico/unique_id.h" // keep this include
|
#include "pico/unique_id.h" // keep this include
|
||||||
|
|
||||||
struct mg_tcpip_driver_pico_w_data {
|
struct mg_tcpip_driver_pico_w_data {
|
||||||
char *ssid;
|
struct mg_wifi_data wifi;
|
||||||
char *pass;
|
|
||||||
char *apssid;
|
|
||||||
char *appass;
|
|
||||||
uint8_t security; // TBD
|
|
||||||
uint8_t apsecurity; // TBD
|
|
||||||
uint8_t apchannel;
|
|
||||||
bool apmode; // start in AP mode; 'false' starts connection to 'ssid' if not NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
@@ -3501,6 +3765,43 @@ bool mg_sdio_transfer(struct mg_tcpip_sdio *sdio, bool write, unsigned int f,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_ST67W6) && \
|
||||||
|
MG_ENABLE_DRIVER_ST67W6
|
||||||
|
|
||||||
|
struct mg_tcpip_spi_ {
|
||||||
|
void *spi; // Opaque SPI bus descriptor
|
||||||
|
void (*begin)(void *); // SPI begin: slave select low
|
||||||
|
void (*end)(void *); // SPI end: slave select high
|
||||||
|
void (*txn)(void *, uint8_t *, uint8_t *,
|
||||||
|
size_t len); // SPI transaction: write-read len bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mg_tcpip_driver_st67w6_data {
|
||||||
|
struct mg_wifi_data wifi;
|
||||||
|
void *spi;
|
||||||
|
bool (*is_ready)(void); // return state of module RDY pin
|
||||||
|
struct mg_queue send_queue; // decouple tx calls from module polls
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
|
do { \
|
||||||
|
static struct mg_tcpip_driver_st67w6_data driver_data_; \
|
||||||
|
static struct mg_tcpip_if mif_; \
|
||||||
|
MG_SET_WIFI_CONFIG(&driver_data_); \
|
||||||
|
mif_.ip = MG_TCPIP_IP; \
|
||||||
|
mif_.mask = MG_TCPIP_MASK; \
|
||||||
|
mif_.gw = MG_TCPIP_GW; \
|
||||||
|
mif_.driver = &mg_tcpip_driver_st67w6; \
|
||||||
|
mif_.driver_data = &driver_data_; \
|
||||||
|
mif_.recv_queue.size = 8192; \
|
||||||
|
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
|
||||||
|
mg_tcpip_init(mgr, &mif_); \
|
||||||
|
MG_INFO(("Driver: st67w6, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \
|
||||||
MG_ENABLE_DRIVER_STM32F
|
MG_ENABLE_DRIVER_STM32F
|
||||||
|
|
||||||
@@ -3562,7 +3863,10 @@ struct mg_tcpip_driver_stm32f_data {
|
|||||||
#if !defined(MG_ENABLE_DRIVER_MCXN)
|
#if !defined(MG_ENABLE_DRIVER_MCXN)
|
||||||
#define MG_ENABLE_DRIVER_MCXN 0
|
#define MG_ENABLE_DRIVER_MCXN 0
|
||||||
#endif
|
#endif
|
||||||
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN
|
#if !defined(MG_ENABLE_DRIVER_STM32N)
|
||||||
|
#define MG_ENABLE_DRIVER_STM32N 0
|
||||||
|
#endif
|
||||||
|
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || MG_ENABLE_DRIVER_STM32N
|
||||||
|
|
||||||
struct mg_tcpip_driver_stm32h_data {
|
struct mg_tcpip_driver_stm32h_data {
|
||||||
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
|
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
|
||||||
@@ -3601,6 +3905,18 @@ struct mg_tcpip_driver_stm32h_data {
|
|||||||
#define MG_ENABLE_ETH_IRQ()
|
#define MG_ENABLE_ETH_IRQ()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
#define MG_IPV6_INIT(mif) \
|
||||||
|
do { \
|
||||||
|
memcpy(mif.ip6ll, (uint8_t[16]) MG_TCPIP_IPV6_LINKLOCAL, 16); \
|
||||||
|
memcpy(mif.ip6, (uint8_t[16]) MG_TCPIP_GLOBAL, 16); \
|
||||||
|
memcpy(mif.gw6, (uint8_t[16]) MG_TCPIP_GW6, 16); \
|
||||||
|
mif.prefix_len = MG_TCPIP_PREFIX_LEN; \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define MG_IPV6_INIT(mif)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
do { \
|
do { \
|
||||||
static struct mg_tcpip_driver_stm32h_data driver_data_; \
|
static struct mg_tcpip_driver_stm32h_data driver_data_; \
|
||||||
@@ -3614,6 +3930,7 @@ struct mg_tcpip_driver_stm32h_data {
|
|||||||
mif_.driver = &mg_tcpip_driver_stm32h; \
|
mif_.driver = &mg_tcpip_driver_stm32h; \
|
||||||
mif_.driver_data = &driver_data_; \
|
mif_.driver_data = &driver_data_; \
|
||||||
MG_SET_MAC_ADDRESS(mif_.mac); \
|
MG_SET_MAC_ADDRESS(mif_.mac); \
|
||||||
|
MG_IPV6_INIT(mif_); \
|
||||||
mg_tcpip_init(mgr, &mif_); \
|
mg_tcpip_init(mgr, &mif_); \
|
||||||
MG_ENABLE_ETH_IRQ(); \
|
MG_ENABLE_ETH_IRQ(); \
|
||||||
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
|
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||||
|
|||||||
+6
-2
@@ -35,11 +35,14 @@
|
|||||||
#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
|
#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && !defined(MG_ENABLE_DRIVER_STM32H)
|
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && \
|
||||||
|
!defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_STM32N)
|
||||||
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
|
||||||
#define MG_ENABLE_DRIVER_STM32F 1
|
#define MG_ENABLE_DRIVER_STM32F 1
|
||||||
#elif defined(STM32H5) || defined(STM32H7)
|
#elif defined(STM32H5) || defined(STM32H7)
|
||||||
#define MG_ENABLE_DRIVER_STM32H 1
|
#define MG_ENABLE_DRIVER_STM32H 1
|
||||||
|
#elif defined(STM32N6)
|
||||||
|
#define MG_ENABLE_DRIVER_STM32N 1
|
||||||
#else
|
#else
|
||||||
#error Select a driver in mongoose_config.h
|
#error Select a driver in mongoose_config.h
|
||||||
#endif
|
#endif
|
||||||
@@ -49,7 +52,8 @@
|
|||||||
#define MG_TLS MG_TLS_BUILTIN
|
#define MG_TLS MG_TLS_BUILTIN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
|
#if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || \
|
||||||
|
defined(STM32F4) || defined(STM32F7)
|
||||||
#define MG_OTA MG_OTA_STM32F
|
#define MG_OTA MG_OTA_STM32F
|
||||||
#elif !defined(MG_OTA) && defined(STM32H5)
|
#elif !defined(MG_OTA) && defined(STM32H5)
|
||||||
#define MG_OTA MG_OTA_STM32H5
|
#define MG_OTA MG_OTA_STM32H5
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#define mode_t size_t
|
#define mode_t size_t
|
||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
|
||||||
#elif defined(__CCRH__)
|
#elif defined(__CCRH__)
|
||||||
#else
|
#else
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|||||||
+4
-1
@@ -110,7 +110,10 @@ typedef enum { false = 0, true = 1 } bool;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef unsigned long nfds_t;
|
#if defined(MG_ENABLE_POLL) && MG_ENABLE_POLL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP)
|
||||||
|
typedef unsigned long nfds_t; // see #3388
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#if MG_ENABLE_WINSOCK
|
#if MG_ENABLE_WINSOCK
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
|||||||
+5
-3
@@ -3,13 +3,15 @@
|
|||||||
#if MG_ARCH == MG_ARCH_ZEPHYR
|
#if MG_ARCH == MG_ARCH_ZEPHYR
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/net/socket.h>
|
||||||
|
// #include <zephyr/posix/dirent.h>
|
||||||
|
#include <zephyr/posix/fcntl.h>
|
||||||
|
#include <zephyr/posix/sys/select.h>
|
||||||
|
#include <zephyr/random/random.h>
|
||||||
#include <zephyr/version.h>
|
#include <zephyr/version.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <zephyr/net/socket.h>
|
|
||||||
#include <zephyr/posix/fcntl.h>
|
|
||||||
#include <zephyr/posix/sys/select.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|||||||
@@ -175,10 +175,34 @@
|
|||||||
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
|
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_GLOBAL
|
||||||
|
#define MG_TCPIP_GLOBAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_IPV6_LINKLOCAL
|
||||||
|
#define MG_TCPIP_IPV6_LINKLOCAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_PREFIX_LEN
|
||||||
|
#define MG_TCPIP_PREFIX_LEN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_GW6
|
||||||
|
#define MG_TCPIP_GW6 MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MG_SET_MAC_ADDRESS
|
#ifndef MG_SET_MAC_ADDRESS
|
||||||
#define MG_SET_MAC_ADDRESS(mac)
|
#define MG_SET_MAC_ADDRESS(mac)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_TCPIP_DHCPNAME_SIZE
|
||||||
|
#define MG_TCPIP_DHCPNAME_SIZE 18 // struct mg_tcpip_if :: dhcp_name size
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MG_SET_WIFI_CONFIG
|
#ifndef MG_SET_WIFI_CONFIG
|
||||||
#define MG_SET_WIFI_CONFIG(data)
|
#define MG_SET_WIFI_CONFIG(data)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs,
|
|||||||
if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
|
if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
|
||||||
// MG_INFO(("--> [%s]", to));
|
// MG_INFO(("--> [%s]", to));
|
||||||
}
|
}
|
||||||
if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term
|
if (tolen > 0) to[tolen - 1] = '\0'; // Make sure it is nul-term
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,14 +134,15 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
|
|||||||
mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
|
mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
|
||||||
ofs += n;
|
ofs += n;
|
||||||
|
|
||||||
if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) {
|
if (rr.alen == 4 && rr.atype == MG_DNS_RTYPE_A && rr.aclass == 1) {
|
||||||
dm->addr.is_ip6 = false;
|
dm->addr.is_ip6 = false;
|
||||||
memcpy(&dm->addr.ip, &buf[ofs - 4], 4);
|
memcpy(&dm->addr.addr.ip, &buf[ofs - 4], 4);
|
||||||
dm->resolved = true;
|
dm->resolved = true;
|
||||||
break; // Return success
|
break; // Return success
|
||||||
} else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) {
|
} else if (rr.alen == 16 && rr.atype == MG_DNS_RTYPE_AAAA &&
|
||||||
|
rr.aclass == 1) {
|
||||||
dm->addr.is_ip6 = true;
|
dm->addr.is_ip6 = true;
|
||||||
memcpy(&dm->addr.ip, &buf[ofs - 16], 16);
|
memcpy(&dm->addr.addr.ip, &buf[ofs - 16], 16);
|
||||||
dm->resolved = true;
|
dm->resolved = true;
|
||||||
break; // Return success
|
break; // Return success
|
||||||
}
|
}
|
||||||
@@ -255,8 +256,12 @@ static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
|
|||||||
mg_error(c, "resolve OOM");
|
mg_error(c, "resolve OOM");
|
||||||
} else {
|
} else {
|
||||||
struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
|
struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
|
||||||
d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1;
|
uint16_t id;
|
||||||
d->next = (struct dns_data *) c->mgr->active_dns_requests;
|
mg_random(&id, sizeof(uint16_t));
|
||||||
|
// TODO(): traverse reqs and check id != reqs->txnid; repeat otherwise
|
||||||
|
if (reqs != NULL) id = (uint16_t) (reqs->txnid + 1); // no collision
|
||||||
|
d->txnid = id;
|
||||||
|
d->next = reqs;
|
||||||
c->mgr->active_dns_requests = d;
|
c->mgr->active_dns_requests = d;
|
||||||
d->expire = mg_millis() + (uint64_t) ms;
|
d->expire = mg_millis() + (uint64_t) ms;
|
||||||
d->c = c;
|
d->c = c;
|
||||||
@@ -282,6 +287,7 @@ void mg_resolve(struct mg_connection *c, const char *url) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Response header length is 10 bytes
|
||||||
static const uint8_t mdns_answer[] = {
|
static const uint8_t mdns_answer[] = {
|
||||||
0, 1, // 2 bytes - record type, A
|
0, 1, // 2 bytes - record type, A
|
||||||
0, 1, // 2 bytes - address class, INET
|
0, 1, // 2 bytes - address class, INET
|
||||||
@@ -289,65 +295,334 @@ static const uint8_t mdns_answer[] = {
|
|||||||
0, 4 // 2 bytes - address length
|
0, 4 // 2 bytes - address length
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A name length is name->len + '.local' + 2 = name->len + 8
|
||||||
|
static uint8_t *build_name(struct mg_str *name, uint8_t *p) {
|
||||||
|
*p++ = (uint8_t) name->len; // label 1
|
||||||
|
memcpy(p, name->buf, name->len), p += name->len;
|
||||||
|
*p++ = 5; // label 2
|
||||||
|
memcpy(p, "local", 5), p += 5;
|
||||||
|
*p++ = 0; // no more labels
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_getlocaddr(struct mg_connection *, struct mg_addr *, struct mg_addr *);
|
||||||
|
|
||||||
|
// An A record length is 10 + 4 = 14 bytes
|
||||||
|
static uint8_t *build_a_record(struct mg_connection *c, uint8_t *p,
|
||||||
|
struct mg_addr *addr) {
|
||||||
|
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
|
||||||
|
if (addr != NULL && !addr->is_ip6) {
|
||||||
|
memcpy(p, &addr->addr.ip4, 4), p += 4;
|
||||||
|
} else {
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
memcpy(p, &c->mgr->ifp->ip, 4), p += 4;
|
||||||
|
#else
|
||||||
|
struct mg_addr loc, to;
|
||||||
|
memset(&loc, 0, sizeof(loc));
|
||||||
|
to.is_ip6 = false;
|
||||||
|
to.port = mg_htons(5353);
|
||||||
|
to.addr.ip4 = MG_IPV4(224, 0, 0, 51);
|
||||||
|
mg_getlocaddr(c, &to, &loc);
|
||||||
|
memcpy(p, &loc.addr.ip4, 4), p += 4;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A srv name length is r->srvcproto.len + '.local' + 2 = r->srvcproto.len + 8
|
||||||
|
static uint8_t *build_srv_name(uint8_t *p, struct mg_dnssd_record *r) {
|
||||||
|
*p++ = (uint8_t) r->srvcproto.len - 5; // label 1, up to '._tcp'
|
||||||
|
memcpy(p, r->srvcproto.buf, r->srvcproto.len), p += r->srvcproto.len;
|
||||||
|
p[-5] = 4; // label 2, '_tcp', overwrite '.'
|
||||||
|
*p++ = 5; // label 3
|
||||||
|
memcpy(p, "local", 5), p += 5;
|
||||||
|
*p++ = 0; // no more labels
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO(): for listing
|
||||||
|
static uint8_t *build_mysrv_name(struct mg_str *name, uint8_t *p,
|
||||||
|
struct mg_dnssd_record *r) {
|
||||||
|
*p++ = name->len; // label 1
|
||||||
|
memcpy(p, name->buf, name->len), p += name->len;
|
||||||
|
return build_srv_name(p, r);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// A PTR record length is 10 + name->len + 3 = name->len + 13
|
||||||
|
static uint8_t *build_ptr_record(struct mg_str *name, uint8_t *p, uint16_t o) {
|
||||||
|
uint16_t offset = mg_htons(o);
|
||||||
|
memcpy(p, mdns_answer, sizeof(mdns_answer));
|
||||||
|
p[1] = MG_DNS_RTYPE_PTR; // overwrite record type
|
||||||
|
p += sizeof(mdns_answer);
|
||||||
|
p[-1] = (uint8_t) name->len +
|
||||||
|
3; // overwrite response length, label length + label + offset
|
||||||
|
*p++ = (uint8_t) name->len; // response: label 1
|
||||||
|
memcpy(p, name->buf, name->len), p += name->len; // copy label
|
||||||
|
memcpy(p, &offset, 2);
|
||||||
|
*p |= 0xC0, p += 2;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An SRV record length is 10 + name->len + 9 = name->len + 19
|
||||||
|
static uint8_t *build_srv_record(struct mg_str *name, uint8_t *p,
|
||||||
|
struct mg_dnssd_record *r, uint16_t o) {
|
||||||
|
uint16_t port = mg_htons(r->port);
|
||||||
|
uint16_t offset = mg_htons(o);
|
||||||
|
memcpy(p, mdns_answer, sizeof(mdns_answer));
|
||||||
|
p[1] = MG_DNS_RTYPE_SRV; // overwrite record type
|
||||||
|
p += sizeof(mdns_answer);
|
||||||
|
p[-1] = (uint8_t) name->len + 9; // overwrite response length (4+2+1+2)
|
||||||
|
*p++ = 0; // priority
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 0; // weight
|
||||||
|
*p++ = 0;
|
||||||
|
memcpy(p, &port, 2), p += 2; // port
|
||||||
|
*p++ = (uint8_t) name->len; // label 1
|
||||||
|
memcpy(p, name->buf, name->len), p += name->len;
|
||||||
|
memcpy(p, &offset, 2);
|
||||||
|
*p |= 0xC0, p += 2;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A TXT record length is r->txt.len (txt contents) + 10
|
||||||
|
static uint8_t *build_txt_record(uint8_t *p, struct mg_dnssd_record *r) {
|
||||||
|
uint16_t len = mg_htons((uint16_t) r->txt.len);
|
||||||
|
memcpy(p, mdns_answer, sizeof(mdns_answer));
|
||||||
|
p[1] = MG_DNS_RTYPE_TXT; // overwrite record type
|
||||||
|
p += sizeof(mdns_answer);
|
||||||
|
memcpy(p - 2, &len, 2); // overwrite response length
|
||||||
|
memcpy(p, r->txt.buf, r->txt.len), p += r->txt.len; // copy record verbatim
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each additional record has a 2-byte field pointing to the name label
|
||||||
|
|
||||||
|
// RFC-6762 16: case-insensitivity --> RFC-1034, 1035
|
||||||
|
|
||||||
|
static void handle_mdns_query(struct mg_connection *c) {
|
||||||
|
struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf;
|
||||||
|
struct mg_dns_rr rr;
|
||||||
|
size_t n;
|
||||||
|
// Parse first question, offset 12 is header size
|
||||||
|
n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
|
||||||
|
MG_VERBOSE(("mDNS request parsed, result=%d", (int) n));
|
||||||
|
if (n > 0) {
|
||||||
|
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
|
||||||
|
uint8_t buf[sizeof(struct mg_dns_header) + 256 + sizeof(mdns_answer) + 4];
|
||||||
|
struct mg_dns_header *h = (struct mg_dns_header *) buf;
|
||||||
|
uint8_t *p = &buf[sizeof(*h)];
|
||||||
|
char name[256];
|
||||||
|
uint8_t name_len;
|
||||||
|
// uint16_t q = mg_ntohs(qh->num_questions);
|
||||||
|
struct mg_str defname = mg_str((const char *) c->fn_data);
|
||||||
|
struct mg_str *respname;
|
||||||
|
struct mg_mdns_req req;
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
req.is_unicast = (rr.aclass & MG_BIT(15)) != 0; // QU
|
||||||
|
rr.aclass &= (uint16_t) ~MG_BIT(15); // remove "QU" (unicast response)
|
||||||
|
qh->num_questions = mg_htons(1); // parser sanity
|
||||||
|
mg_dns_parse_name(c->recv.buf, c->recv.len, 12, name, sizeof(name));
|
||||||
|
name_len = (uint8_t) strlen(name); // verify it ends in .local
|
||||||
|
if (name_len <= 6 || strcmp(".local", &name[name_len - 6]) != 0 ||
|
||||||
|
(rr.aclass != 1 && rr.aclass != 0xff))
|
||||||
|
return;
|
||||||
|
name[name_len -= 6] = '\0'; // remove .local
|
||||||
|
MG_VERBOSE(("RR %u %u %s", (unsigned int) rr.atype,
|
||||||
|
(unsigned int) rr.aclass, name));
|
||||||
|
if (rr.atype == MG_DNS_RTYPE_A) {
|
||||||
|
// TODO(): ensure c->fn_data ends in \0
|
||||||
|
// if we have a name to match, go; otherwise users will match and fill
|
||||||
|
// req.r.name and set req.is_resp
|
||||||
|
if (c->fn_data != NULL && mg_casecmp((char *) c->fn_data, name) != 0)
|
||||||
|
return;
|
||||||
|
req.is_resp = (c->fn_data != NULL);
|
||||||
|
req.reqname = mg_str_n(name, name_len);
|
||||||
|
} else // users have to match the request to something in their db, then
|
||||||
|
// fill req.r and set req.is_resp
|
||||||
|
if (rr.atype == MG_DNS_RTYPE_PTR) {
|
||||||
|
if (strcmp("_services._dns-sd._udp", name) == 0) req.is_listing = true;
|
||||||
|
MG_DEBUG(
|
||||||
|
("PTR request for %s", req.is_listing ? "services listing" : name));
|
||||||
|
req.reqname = mg_str_n(name, name_len);
|
||||||
|
} else if (rr.atype == MG_DNS_RTYPE_SRV || rr.atype == MG_DNS_RTYPE_TXT) {
|
||||||
|
MG_DEBUG(("%s request for %s",
|
||||||
|
rr.atype == MG_DNS_RTYPE_SRV ? "SRV" : "TXT", name));
|
||||||
|
// if possible, check it starts with our name, users will check it ends
|
||||||
|
// in a service name they handle
|
||||||
|
if (c->fn_data != NULL) {
|
||||||
|
if (mg_strcasecmp(defname, mg_str_n(name, defname.len)) != 0 ||
|
||||||
|
name[defname.len] != '.')
|
||||||
|
return;
|
||||||
|
req.reqname =
|
||||||
|
mg_str_n(name + defname.len + 1, name_len - defname.len - 1);
|
||||||
|
MG_DEBUG(
|
||||||
|
("That's us, handing %.*s", req.reqname.len, req.reqname.buf));
|
||||||
|
} else {
|
||||||
|
req.reqname = mg_str_n(name, name_len);
|
||||||
|
}
|
||||||
|
} else { // unhandled record
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
req.rr = &rr;
|
||||||
|
mg_call(c, MG_EV_MDNS_REQ, &req);
|
||||||
|
if (!req.is_resp) return;
|
||||||
|
respname = req.respname.buf != NULL ? &req.respname : &defname;
|
||||||
|
|
||||||
|
memset(h, 0, sizeof(*h)); // clear header
|
||||||
|
h->txnid = req.is_unicast ? qh->txnid : 0; // RFC-6762 18.1
|
||||||
|
h->num_answers = mg_htons(1); // RFC-6762 6: 0 questions, 1 Answer
|
||||||
|
h->flags = mg_htons(0x8400); // Authoritative response
|
||||||
|
if (req.is_listing) {
|
||||||
|
// TODO(): RFC-6762 6: each responder SHOULD delay its response by a
|
||||||
|
// random amount of time selected with uniform random distribution in the
|
||||||
|
// range 20-120 ms.
|
||||||
|
// TODO():
|
||||||
|
return;
|
||||||
|
} else if (rr.atype == MG_DNS_RTYPE_PTR) { // serve PTR + SRV + TXT + A
|
||||||
|
// TODO(): RFC-6762 6: each responder SHOULD delay its response by a
|
||||||
|
// random amount of time selected with uniform random distribution in the
|
||||||
|
// range 20-120 ms. Response to PTR is local_name._myservice._tcp.local
|
||||||
|
uint8_t *o = p, *aux;
|
||||||
|
uint16_t offset;
|
||||||
|
if (respname->buf == NULL || respname->len == 0) return;
|
||||||
|
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 13 + 2 +
|
||||||
|
respname->len + 19 + 2 + req.r->txt.len + 10 + 2 + 14) >
|
||||||
|
sizeof(buf)) // srv name + PTR + 2 + SRV + 2 + TXT + 2 + A
|
||||||
|
return;
|
||||||
|
h->num_other_prs = mg_htons(3); // 3 additional records
|
||||||
|
p = build_srv_name(p, req.r);
|
||||||
|
aux = build_ptr_record(respname, p, (uint16_t) (o - buf));
|
||||||
|
o = p + sizeof(mdns_answer); // point to PTR response (full srvc name)
|
||||||
|
offset = mg_htons((uint16_t) (o - buf));
|
||||||
|
o = p - 7; // point to '.local' label (\x05local\x00)
|
||||||
|
p = aux;
|
||||||
|
memcpy(p, &offset, 2); // point to full srvc name, in record
|
||||||
|
*p |= 0xC0, p += 2;
|
||||||
|
aux = p;
|
||||||
|
p = build_srv_record(respname, p, req.r, (uint16_t) (o - buf));
|
||||||
|
o = aux + sizeof(mdns_answer) + 6; // point to target in SRV
|
||||||
|
memcpy(p, &offset, 2); // point to full srvc name, in record
|
||||||
|
*p |= 0xC0, p += 2;
|
||||||
|
p = build_txt_record(p, req.r);
|
||||||
|
offset = mg_htons((uint16_t) (o - buf));
|
||||||
|
memcpy(p, &offset, 2); // point to target name, in record
|
||||||
|
*p |= 0xC0, p += 2;
|
||||||
|
p = build_a_record(c, p, req.addr);
|
||||||
|
} else if (rr.atype == MG_DNS_RTYPE_TXT) {
|
||||||
|
if ((sizeof(*h) + req.r->srvcproto.len + 8 + req.r->txt.len + 10) >
|
||||||
|
sizeof(buf)) // srv name + TXT
|
||||||
|
return;
|
||||||
|
p = build_srv_name(p, req.r);
|
||||||
|
p = build_txt_record(p, req.r);
|
||||||
|
} else if (rr.atype == MG_DNS_RTYPE_SRV) { // serve SRV + A
|
||||||
|
uint8_t *o, *aux;
|
||||||
|
uint16_t offset;
|
||||||
|
if (respname->buf == NULL || respname->len == 0) return;
|
||||||
|
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 19 + 2 +
|
||||||
|
14) > sizeof(buf)) // srv name + SRV + 2 + A
|
||||||
|
return;
|
||||||
|
h->num_other_prs = mg_htons(1); // 1 additional record
|
||||||
|
p = build_srv_name(p, req.r);
|
||||||
|
o = p - 7; // point to '.local' label (\x05local\x00)
|
||||||
|
aux = p;
|
||||||
|
p = build_srv_record(respname, p, req.r, (uint16_t) (o - buf));
|
||||||
|
o = aux + sizeof(mdns_answer) + 6; // point to target in SRV
|
||||||
|
offset = mg_htons((uint16_t) (o - buf));
|
||||||
|
memcpy(p, &offset, 2); // point to target name, in record
|
||||||
|
*p |= 0xC0, p += 2;
|
||||||
|
p = build_a_record(c, p, req.addr);
|
||||||
|
} else { // A requested
|
||||||
|
// RFC-6762 6: 0 Auth, 0 Additional RRs
|
||||||
|
if (respname->buf == NULL || respname->len == 0) return;
|
||||||
|
if ((sizeof(*h) + respname->len + 8 + 14) > sizeof(buf)) // name + A
|
||||||
|
return;
|
||||||
|
p = build_name(respname, p);
|
||||||
|
p = build_a_record(c, p, req.addr);
|
||||||
|
}
|
||||||
|
if (!req.is_unicast) mg_multicast_restore(c, (uint8_t *) &c->loc);
|
||||||
|
mg_send(c, buf, (size_t) (p - buf)); // And send it!
|
||||||
|
MG_DEBUG(("%M > %M", mg_print_ip_port, &c->loc, mg_print_ip_port, &c->rem));
|
||||||
|
MG_DEBUG(("mDNS %s response sent", req.is_unicast ? "unicast" : "mcast"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_mdns_response(struct mg_connection *c) {
|
||||||
|
struct mg_dns_header *rh = (struct mg_dns_header *) c->recv.buf;
|
||||||
|
struct mg_dns_rr rr;
|
||||||
|
size_t n;
|
||||||
|
// Parse first response, offset 12 is header size
|
||||||
|
n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, false, &rr);
|
||||||
|
MG_VERBOSE(("mDNS response parsed, result=%d", (int) n));
|
||||||
|
if (n > 0) {
|
||||||
|
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
|
||||||
|
char name[256];
|
||||||
|
uint8_t name_len;
|
||||||
|
struct mg_mdns_resp resp;
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
if (rh->num_answers > mg_htons(1)) MG_DEBUG(("ignoring > 1 answers"));
|
||||||
|
mg_dns_parse_name(c->recv.buf, c->recv.len, 12, name, sizeof(name));
|
||||||
|
name_len = (uint8_t) strlen(name); // verify it ends in .local
|
||||||
|
MG_VERBOSE(("RR %u %u %s", (unsigned int) rr.atype,
|
||||||
|
(unsigned int) rr.aclass, name));
|
||||||
|
if (rr.alen == 4 && rr.atype == MG_DNS_RTYPE_A &&
|
||||||
|
(rr.aclass & 0x7FFF) == 1) {
|
||||||
|
resp.addr.is_ip6 = false;
|
||||||
|
memcpy(resp.addr.addr.ip, (char *) (rh + 1) + n - 4, 4);
|
||||||
|
MG_DEBUG(("A response from %.*s = %M", name_len, name, mg_print_ip,
|
||||||
|
&resp.addr));
|
||||||
|
// } else if (rr.alen == 16 && rr.atype == MG_DNS_RTYPE_AAAA &&
|
||||||
|
// (rr.aclass & 0x7FFF) == 1) {
|
||||||
|
// resp.addr.is_ip6 = true;
|
||||||
|
// memcpy(resp.addr.addr.ip, (char *)(rh + 1) + n - 16], 16);
|
||||||
|
// MG_DEBUG(("AAAA response from %.*s = %M", name_len, name,
|
||||||
|
// mg_print_ip, &resp.addr));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resp.name = mg_str_n(name, name_len);
|
||||||
|
resp.rr = &rr;
|
||||||
|
mg_call(c, MG_EV_MDNS_RESP, &resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_mdns_record(struct mg_connection *c) {
|
||||||
|
struct mg_dns_header *h = (struct mg_dns_header *) c->recv.buf;
|
||||||
|
if (c->recv.len <= 12) return;
|
||||||
|
if ((h->flags & mg_htons(0xF800)) == 0) {
|
||||||
|
// flags -> !resp, opcode=0 => query; ignore other opcodes
|
||||||
|
handle_mdns_query(c);
|
||||||
|
} else if ((h->flags & mg_htons(0xF800)) == mg_htons(0x8000)) {
|
||||||
|
// flags -> resp, opcode=0 => response; ignore other opcodes
|
||||||
|
handle_mdns_response(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
|
static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
if (ev == MG_EV_READ) {
|
if (ev == MG_EV_READ) {
|
||||||
struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf;
|
handle_mdns_record(c);
|
||||||
if (c->recv.len > 12 && (qh->flags & mg_htons(0xF800)) == 0) {
|
|
||||||
// flags -> !resp, opcode=0 => query; ignore other opcodes and responses
|
|
||||||
struct mg_dns_rr rr; // Parse first question, offset 12 is header size
|
|
||||||
size_t n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
|
|
||||||
MG_VERBOSE(("mDNS request parsed, result=%d", (int) n));
|
|
||||||
if (n > 0) {
|
|
||||||
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
|
|
||||||
// buf and h declared here to ease future expansion to DNS-SD
|
|
||||||
uint8_t buf[sizeof(struct mg_dns_header) + 256 + sizeof(mdns_answer) + 4];
|
|
||||||
struct mg_dns_header *h = (struct mg_dns_header *) buf;
|
|
||||||
char local_name[63 + 7]; // name label + '.' + local label + '\0'
|
|
||||||
uint8_t name_len = (uint8_t) strlen((char *)c->fn_data);
|
|
||||||
struct mg_dns_message dm;
|
|
||||||
bool unicast = (rr.aclass & MG_BIT(15)) != 0; // QU
|
|
||||||
// uint16_t q = mg_ntohs(qh->num_questions);
|
|
||||||
rr.aclass &= (uint16_t) ~MG_BIT(15); // remove "QU" (unicast response)
|
|
||||||
qh->num_questions = mg_htons(1); // parser sanity
|
|
||||||
mg_dns_parse(c->recv.buf, c->recv.len, &dm);
|
|
||||||
if (name_len > (sizeof(local_name) - 7)) // leave room for .local\0
|
|
||||||
name_len = sizeof(local_name) - 7;
|
|
||||||
memcpy(local_name, c->fn_data, name_len);
|
|
||||||
strcpy(local_name + name_len, ".local"); // ensure proper name.local\0
|
|
||||||
if (strcmp(local_name, dm.name) == 0) {
|
|
||||||
uint8_t *p = &buf[sizeof(*h)];
|
|
||||||
memset(h, 0, sizeof(*h)); // clear header
|
|
||||||
h->txnid = unicast ? qh->txnid : 0; // RFC-6762 18.1
|
|
||||||
// RFC-6762 6: 0 questions, 1 Answer, 0 Auth, 0 Additional RRs
|
|
||||||
h->num_answers = mg_htons(1); // only one answer
|
|
||||||
h->flags = mg_htons(0x8400); // Authoritative response
|
|
||||||
*p++ = name_len; // label 1
|
|
||||||
memcpy(p, c->fn_data, name_len), p += name_len;
|
|
||||||
*p++ = 5; // label 2
|
|
||||||
memcpy(p, "local", 5), p += 5;
|
|
||||||
*p++ = 0; // no more labels
|
|
||||||
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
|
|
||||||
#if MG_ENABLE_TCPIP
|
|
||||||
memcpy(p, &c->mgr->ifp->ip, 4), p += 4;
|
|
||||||
#else
|
|
||||||
memcpy(p, c->data, 4), p += 4;
|
|
||||||
#endif
|
|
||||||
if (!unicast) memcpy(&c->rem, &c->loc, sizeof(c->rem));
|
|
||||||
mg_send(c, buf, (size_t)(p - buf)); // And send it!
|
|
||||||
MG_DEBUG(("mDNS %c response sent", unicast ? 'U' : 'M'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mg_iobuf_del(&c->recv, 0, c->recv.len);
|
mg_iobuf_del(&c->recv, 0, c->recv.len);
|
||||||
}
|
}
|
||||||
(void) ev_data;
|
(void) ev_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_multicast_add(struct mg_connection *c, char *ip);
|
void mg_multicast_add(struct mg_connection *c, char *ip);
|
||||||
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name) {
|
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn,
|
||||||
|
void *fn_data) {
|
||||||
struct mg_connection *c =
|
struct mg_connection *c =
|
||||||
mg_listen(mgr, "udp://224.0.0.251:5353", mdns_cb, name);
|
mg_listen(mgr, "udp://224.0.0.251:5353", fn, fn_data);
|
||||||
if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251");
|
if (c == NULL) return NULL;
|
||||||
|
c->pfn = mdns_cb, c->pfn_data = fn_data;
|
||||||
|
mg_multicast_add(c, (char *) "224.0.0.251");
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mg_mdns_query(struct mg_connection *c, const char *name,
|
||||||
|
unsigned int rtype) {
|
||||||
|
struct mg_str name_;
|
||||||
|
name_.buf = (char *) name, name_.len = strlen(name);
|
||||||
|
mg_multicast_restore(c, (uint8_t *) &c->loc);
|
||||||
|
(void) rtype;
|
||||||
|
return mg_dns_send(c, &name_, 0, false);
|
||||||
|
}
|
||||||
@@ -3,6 +3,12 @@
|
|||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
|
#define MG_DNS_RTYPE_A 1
|
||||||
|
#define MG_DNS_RTYPE_PTR 12
|
||||||
|
#define MG_DNS_RTYPE_TXT 16
|
||||||
|
#define MG_DNS_RTYPE_AAAA 28
|
||||||
|
#define MG_DNS_RTYPE_SRV 33
|
||||||
|
|
||||||
// Mongoose sends DNS queries that contain only one question:
|
// Mongoose sends DNS queries that contain only one question:
|
||||||
// either A (IPv4) or AAAA (IPv6) address lookup.
|
// either A (IPv4) or AAAA (IPv6) address lookup.
|
||||||
// Therefore, we expect zero or one answer.
|
// Therefore, we expect zero or one answer.
|
||||||
@@ -31,10 +37,39 @@ struct mg_dns_rr {
|
|||||||
uint16_t alen; // Address length
|
uint16_t alen; // Address length
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DNS-SD response record
|
||||||
|
struct mg_dnssd_record {
|
||||||
|
struct mg_str srvcproto; // service.proto, service name
|
||||||
|
struct mg_str txt; // TXT record contents
|
||||||
|
uint16_t port; // SRV record port
|
||||||
|
};
|
||||||
|
|
||||||
|
// mDNS request and response data structs passed to event handlers
|
||||||
|
struct mg_mdns_req {
|
||||||
|
struct mg_dns_rr *rr;
|
||||||
|
struct mg_dnssd_record *r;
|
||||||
|
struct mg_str reqname; // requested name in RR
|
||||||
|
struct mg_str respname; // actual name to use in response
|
||||||
|
struct mg_addr *addr; // actual address to use in response
|
||||||
|
bool is_listing;
|
||||||
|
bool is_resp;
|
||||||
|
bool is_unicast;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mg_mdns_resp {
|
||||||
|
struct mg_dns_rr *rr;
|
||||||
|
// TODO(scaprile )struct mg_str srvcproto; struct mg_str txt; uint16_t port; ?
|
||||||
|
struct mg_str name;
|
||||||
|
struct mg_addr addr;
|
||||||
|
// TODO(scaprile); bool has_A; bool has_PTR; bool has_SRV; bool has_TXT; ?
|
||||||
|
};
|
||||||
|
|
||||||
void mg_resolve(struct mg_connection *, const char *url);
|
void mg_resolve(struct mg_connection *, const char *url);
|
||||||
void mg_resolve_cancel(struct mg_connection *);
|
void mg_resolve_cancel(struct mg_connection *);
|
||||||
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
|
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
|
||||||
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
|
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
|
||||||
bool is_question, struct mg_dns_rr *);
|
bool is_question, struct mg_dns_rr *);
|
||||||
|
|
||||||
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name);
|
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn,
|
||||||
|
void *fn_data);
|
||||||
|
bool mg_mdns_query(struct mg_connection *, const char *, unsigned int);
|
||||||
+46
-26
@@ -13,28 +13,42 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct mg_tcpip_if *s_ifp;
|
static struct mg_tcpip_if *s_ifp;
|
||||||
|
static uint32_t s_ip, s_mask;
|
||||||
static bool s_link, s_auth, s_join;
|
static bool s_link, s_auth, s_join;
|
||||||
|
|
||||||
|
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
|
||||||
|
struct mg_wifi_data *wifi = &((struct mg_tcpip_driver_cyw_data *) ifp->driver_data)->wifi;
|
||||||
|
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
|
||||||
|
MG_DEBUG(("Access Point started"));
|
||||||
|
s_ip = ifp->ip, ifp->ip = wifi->apip;
|
||||||
|
s_mask = ifp->mask, ifp->mask = wifi->apmask;
|
||||||
|
ifp->enable_dhcp_client = false;
|
||||||
|
ifp->enable_dhcp_server = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool cyw_init(uint8_t *mac);
|
static bool cyw_init(uint8_t *mac);
|
||||||
static void cyw_poll(void);
|
static void cyw_poll(void);
|
||||||
|
|
||||||
static bool mg_tcpip_driver_cyw_init(struct mg_tcpip_if *ifp) {
|
static bool mg_tcpip_driver_cyw_init(struct mg_tcpip_if *ifp) {
|
||||||
struct mg_tcpip_driver_cyw_data *d =
|
struct mg_tcpip_driver_cyw_data *d =
|
||||||
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
|
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
|
||||||
|
struct mg_wifi_data *wifi = &d->wifi;
|
||||||
if (MG_BIG_ENDIAN) {
|
if (MG_BIG_ENDIAN) {
|
||||||
MG_ERROR(("Big-endian host"));
|
MG_ERROR(("Big-endian host"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
s_ifp = ifp;
|
s_ifp = ifp;
|
||||||
|
s_ip = ifp->ip;
|
||||||
|
s_mask = ifp->mask;
|
||||||
s_link = s_auth = s_join = false;
|
s_link = s_auth = s_join = false;
|
||||||
|
ifp->pfn = wifi_cb;
|
||||||
if (!cyw_init(ifp->mac)) return false;
|
if (!cyw_init(ifp->mac)) return false;
|
||||||
|
|
||||||
if (d->apmode) {
|
if (wifi->apmode) {
|
||||||
MG_DEBUG(("Starting AP '%s' (%u)", d->apssid, d->apchannel));
|
return mg_wifi_ap_start(wifi);
|
||||||
return mg_wifi_ap_start(d->apssid, d->appass, d->apchannel);
|
} else if (wifi->ssid != NULL && wifi->pass != NULL) {
|
||||||
} else if (d->ssid != NULL && d->pass != NULL) {
|
return mg_wifi_connect(wifi);
|
||||||
MG_DEBUG(("Connecting to '%s'", d->ssid));
|
|
||||||
return mg_wifi_connect(d->ssid, d->pass);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -44,7 +58,7 @@ size_t mg_tcpip_driver_cyw_output(const void *buf, size_t len,
|
|||||||
struct mg_tcpip_if *ifp) {
|
struct mg_tcpip_if *ifp) {
|
||||||
struct mg_tcpip_driver_cyw_data *d =
|
struct mg_tcpip_driver_cyw_data *d =
|
||||||
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
|
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
|
||||||
return mg_cyw_tx(d->apmode ? 1 : 0, (void *) buf, len) >= len ? len : 0;
|
return mg_cyw_tx(d->wifi.apmode ? 1 : 0, (void *) buf, len) >= len ? len : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mg_tcpip_driver_cyw_poll(struct mg_tcpip_if *ifp, bool s1) {
|
static bool mg_tcpip_driver_cyw_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||||
@@ -52,7 +66,7 @@ static bool mg_tcpip_driver_cyw_poll(struct mg_tcpip_if *ifp, bool s1) {
|
|||||||
if (!s1) return false;
|
if (!s1) return false;
|
||||||
struct mg_tcpip_driver_cyw_data *d =
|
struct mg_tcpip_driver_cyw_data *d =
|
||||||
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
|
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
|
||||||
return d->apmode ? s_link : s_link && s_auth && s_join;
|
return d->wifi.apmode ? s_link : s_link && s_auth && s_join;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mg_tcpip_driver mg_tcpip_driver_cyw = {mg_tcpip_driver_cyw_init,
|
struct mg_tcpip_driver mg_tcpip_driver_cyw = {mg_tcpip_driver_cyw_init,
|
||||||
@@ -279,7 +293,7 @@ static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len) {
|
|||||||
uint32_t status = mg_ntohl(msg->event.status);
|
uint32_t status = mg_ntohl(msg->event.status);
|
||||||
uint32_t reason = mg_ntohl(msg->event.reason);
|
uint32_t reason = mg_ntohl(msg->event.reason);
|
||||||
uint16_t flags = mg_ntohs(msg->event.flags);
|
uint16_t flags = mg_ntohs(msg->event.flags);
|
||||||
MG_DEBUG(("BCM event %lu %lu %lu %p", event_type, status, reason, flags));
|
MG_VERBOSE(("BCM evt %lu %lu %lu %p", event_type, status, reason, flags));
|
||||||
if (event_type == 16 && status == 0) { // Link
|
if (event_type == 16 && status == 0) { // Link
|
||||||
s_link = flags & 1;
|
s_link = flags & 1;
|
||||||
} else if (event_type == 46 && s_link) { // PSK sup with link up
|
} else if (event_type == 46 && s_link) { // PSK sup with link up
|
||||||
@@ -345,7 +359,7 @@ static bool cyw_wifi_connect(char *ssid, char *pass) {
|
|||||||
uint32_t data[64/4 + 1]; // max pass length: 64 for WPA, 128 for WPA3 SAE
|
uint32_t data[64/4 + 1]; // max pass length: 64 for WPA, 128 for WPA3 SAE
|
||||||
uint16_t *da = (uint16_t *) data;
|
uint16_t *da = (uint16_t *) data;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
val = 4; // security type: 0 for none, 2 for WPA, 4 for WPA2/WPA3, 6 for mixed WPA/WPA2
|
val = 4; // security type: 0 for none, 2 for WPA, 4 for WPA2/WPA3, 6 for mixed WPA/WPA2
|
||||||
// sup_wpa[1] = 0 if not using security
|
// sup_wpa[1] = 0 if not using security
|
||||||
if (!(cyw_ioctl_set(134 /* SET_WSEC */, (uint8_t *)&val, sizeof(val))
|
if (!(cyw_ioctl_set(134 /* SET_WSEC */, (uint8_t *)&val, sizeof(val))
|
||||||
@@ -387,7 +401,7 @@ static bool cyw_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
|
|||||||
uint32_t data[64/4 + 2]; // max pass length: 64 for WPA, 128 for WPA3 SAE
|
uint32_t data[64/4 + 2]; // max pass length: 64 for WPA, 128 for WPA3 SAE
|
||||||
uint16_t *da = (uint16_t *) data;
|
uint16_t *da = (uint16_t *) data;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
// CHIP DEPENDENCY
|
// CHIP DEPENDENCY
|
||||||
// RPi set the AMPDU parameter for AP (window size = 2) *****************
|
// RPi set the AMPDU parameter for AP (window size = 2) *****************
|
||||||
// val = 2 ; cyw_ioctl_iovar_set_(0, "ampdu_ba_wsize", (uint8_t *)&val, sizeof(val));
|
// val = 2 ; cyw_ioctl_iovar_set_(0, "ampdu_ba_wsize", (uint8_t *)&val, sizeof(val));
|
||||||
@@ -416,10 +430,10 @@ static bool cyw_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
|
|||||||
da[1] = 1; // indicates wireless security key, skip for WPA3 SAE
|
da[1] = 1; // indicates wireless security key, skip for WPA3 SAE
|
||||||
memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE
|
memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE
|
||||||
if (!cyw_ioctl_set_(1, 268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA
|
if (!cyw_ioctl_set_(1, 268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA
|
||||||
/* for WPA3 SAE:
|
/* for WPA3 SAE:
|
||||||
memcpy((uint8_t *)data + sizeof(uint16_t), pass, len);
|
memcpy((uint8_t *)data + sizeof(uint16_t), pass, len);
|
||||||
cyw_ioctl_iovar_set_(1, "sae_password", data, sizeof(data)); */
|
cyw_ioctl_iovar_set_(1, "sae_password", data, sizeof(data)); */
|
||||||
/* for WPA3 or mixed WPA2/WPA3:
|
/* for WPA3 or mixed WPA2/WPA3:
|
||||||
val = 5 ; cyw_ioctl_iovar_set_(1, "sae_max_pwe_loop", (uint8_t *)&val, sizeof(val)); // Some chipsets do not support this */
|
val = 5 ; cyw_ioctl_iovar_set_(1, "sae_max_pwe_loop", (uint8_t *)&val, sizeof(val)); // Some chipsets do not support this */
|
||||||
// resume if not using auth
|
// resume if not using auth
|
||||||
|
|
||||||
@@ -565,7 +579,7 @@ static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, si
|
|||||||
bss.band = band & CYW_BSS_BAND2G ? MG_WIFI_BAND_2G : MG_WIFI_BAND_5G;
|
bss.band = band & CYW_BSS_BAND2G ? MG_WIFI_BAND_2G : MG_WIFI_BAND_5G;
|
||||||
bss.security = (sbss->capability & MG_BIT(4) /* CAP_PRIVACY */) ? MG_WIFI_SECURITY_WEP : MG_WIFI_SECURITY_OPEN;
|
bss.security = (sbss->capability & MG_BIT(4) /* CAP_PRIVACY */) ? MG_WIFI_SECURITY_WEP : MG_WIFI_SECURITY_OPEN;
|
||||||
{ // travel IEs (Information Elements) in search of security definitions
|
{ // travel IEs (Information Elements) in search of security definitions
|
||||||
const uint8_t wot1[4] = {0x00, 0x50, 0xf2, 0x01}; // WPA_OUI_TYPE1
|
const uint8_t wot1[4] = {0x00, 0x50, 0xf2, 0x01}; // WPA_OUI_TYPE1
|
||||||
uint8_t *ie = (uint8_t *)sbss + sbss->ie_offset;
|
uint8_t *ie = (uint8_t *)sbss + sbss->ie_offset;
|
||||||
int bytes = (int) sbss->ie_length;
|
int bytes = (int) sbss->ie_length;
|
||||||
while (bytes > 0 && ie[1] + 2 < bytes) { // ie[0] -> type, ie[1] -> bytes from ie[2]
|
while (bytes > 0 && ie[1] + 2 < bytes) { // ie[0] -> type, ie[1] -> bytes from ie[2]
|
||||||
@@ -576,11 +590,11 @@ static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, si
|
|||||||
bytes -= ie[1] + 2;
|
bytes -= ie[1] + 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf, bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI, bss.security));
|
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf, bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI, bss.security));
|
||||||
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
|
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
|
||||||
} else {
|
} else {
|
||||||
MG_ERROR(("scan error"));
|
MG_ERROR(("scan error"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -602,7 +616,7 @@ static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump((void *) cdc, len);
|
if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump((void *) cdc, len);
|
||||||
MG_DEBUG(("IOCTL result: %02x %02x %02x %02x ...", r[0], r[1], r[2], r[3]));
|
MG_VERBOSE(("IOCTL result: %02x %02x %02x %02x ..", r[0], r[1], r[2], r[3]));
|
||||||
s_ioctl_resp = r;
|
s_ioctl_resp = r;
|
||||||
}
|
}
|
||||||
// NOTE(): alt no loop handler dispatching IOCTL response to current handler:
|
// NOTE(): alt no loop handler dispatching IOCTL response to current handler:
|
||||||
@@ -772,7 +786,7 @@ static bool cyw_init(uint8_t *mac) {
|
|||||||
// CHIP DEPENDENCY
|
// CHIP DEPENDENCY
|
||||||
val = 8 ; cyw_ioctl_iovar_set("ampdu_ba_wsize", (uint8_t *)&val, sizeof(val));
|
val = 8 ; cyw_ioctl_iovar_set("ampdu_ba_wsize", (uint8_t *)&val, sizeof(val));
|
||||||
val = 4 ; cyw_ioctl_iovar_set("ampdu_mpdu", (uint8_t *)&val, sizeof(val));
|
val = 4 ; cyw_ioctl_iovar_set("ampdu_mpdu", (uint8_t *)&val, sizeof(val));
|
||||||
val = 0 /* 8K */; cyw_ioctl_iovar_set("ampdu_rx_factor", (uint8_t *)&val, sizeof(val));
|
val = 0 /* 8K */; cyw_ioctl_iovar_set("ampdu_rx_factor", (uint8_t *)&val, sizeof(val));
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
struct cyw_country c;
|
struct cyw_country c;
|
||||||
@@ -990,7 +1004,7 @@ static bool cyw_load_fwll(void *fwdata, size_t fwlen, void *nvramdata, size_t nv
|
|||||||
cyw_load_data(CYW_CHIP_ATCMRAM_BASE, fwdata, fwlen);
|
cyw_load_data(CYW_CHIP_ATCMRAM_BASE, fwdata, fwlen);
|
||||||
mg_delayms(5); // TODO(scaprile): CHECK IF THIS IS ACTUALLY NEEDED
|
mg_delayms(5); // TODO(scaprile): CHECK IF THIS IS ACTUALLY NEEDED
|
||||||
// Load NVRAM and place 'length ~length' at the end; end of chip RAM
|
// Load NVRAM and place 'length ~length' at the end; end of chip RAM
|
||||||
{
|
{
|
||||||
const uint32_t start = CYW_CHIP_RAM_SIZE - 4 - nvramlen;
|
const uint32_t start = CYW_CHIP_RAM_SIZE - 4 - nvramlen;
|
||||||
cyw_load_data(start, nvramdata, nvramlen); // nvramlen must be a multiple of 4
|
cyw_load_data(start, nvramdata, nvramlen); // nvramlen must be a multiple of 4
|
||||||
// RAM_SIZE is a multiple of WINSZ, so the place for len ~len will be at the end of the window
|
// RAM_SIZE is a multiple of WINSZ, so the place for len ~len will be at the end of the window
|
||||||
@@ -1035,7 +1049,7 @@ static size_t cyw_spi_poll(uint8_t *response) {
|
|||||||
cyw_spi_write(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_INT, &val, sizeof(val));
|
cyw_spi_write(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_INT, &val, sizeof(val));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
cyw_spi_read(CYW_SPID_FUNC_WLAN, 0, response, len);
|
cyw_spi_read(CYW_SPID_FUNC_WLAN, 0, response, (uint16_t)len);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1098,7 +1112,7 @@ static bool cyw_spi_init() {
|
|||||||
cyw_set_backplane_window(CYW_CHIP_CHIPCOMMON); // set backplane window to start of CHIPCOMMON area
|
cyw_set_backplane_window(CYW_CHIP_CHIPCOMMON); // set backplane window to start of CHIPCOMMON area
|
||||||
cyw_spi_read(CYW_SPID_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2);
|
cyw_spi_read(CYW_SPID_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2);
|
||||||
if (val == 43430) val = 4343;
|
if (val == 43430) val = 4343;
|
||||||
MG_INFO(("WLAN chip is CYW%u%c", val), val == 4343 ? 'W' : ' '));
|
MG_INFO(("WLAN chip is CYW%u%c", val, val == 4343 ? 'W' : ' '));
|
||||||
|
|
||||||
// Load firmware (code and NVRAM)
|
// Load firmware (code and NVRAM)
|
||||||
if (!cyw_load_firmware(d->fw)) return false;
|
if (!cyw_load_firmware(d->fw)) return false;
|
||||||
@@ -1281,7 +1295,7 @@ static bool cyw_sdio_init() {
|
|||||||
struct mg_tcpip_sdio *s = (struct mg_tcpip_sdio *) d->bus;
|
struct mg_tcpip_sdio *s = (struct mg_tcpip_sdio *) d->bus;
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
if (!mg_sdio_init(s)) return false;
|
if (!mg_sdio_init(s)) return false;
|
||||||
// no block transfers on F0. if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_BUS, 32)) return false;
|
// no block transfers on F0. if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_BUS, 32)) return false;
|
||||||
if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_CHIP, 64)) return false;
|
if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_CHIP, 64)) return false;
|
||||||
if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_WLAN, 64)) return false;
|
if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_WLAN, 64)) return false;
|
||||||
// TODO(scaprile): we don't handle SDIO interrupts, study CCCR INTEN and SDIO support (SDIO 6.3, 8)
|
// TODO(scaprile): we don't handle SDIO interrupts, study CCCR INTEN and SDIO support (SDIO 6.3, 8)
|
||||||
@@ -1376,16 +1390,22 @@ bool mg_wifi_scan(void) {
|
|||||||
return cyw_wifi_scan();
|
return cyw_wifi_scan();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_wifi_connect(char *ssid, char *pass) {
|
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
|
||||||
return cyw_wifi_connect(ssid, pass);
|
s_ifp->ip = s_ip;
|
||||||
|
s_ifp->mask = s_mask;
|
||||||
|
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
|
||||||
|
s_ifp->enable_dhcp_server = false;
|
||||||
|
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
|
||||||
|
return cyw_wifi_connect(wifi->ssid, wifi->pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_wifi_disconnect(void) {
|
bool mg_wifi_disconnect(void) {
|
||||||
return cyw_wifi_disconnect();
|
return cyw_wifi_disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
|
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
|
||||||
return cyw_wifi_ap_start(ssid, pass, channel);
|
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
|
||||||
|
return cyw_wifi_ap_start(wifi->apssid, wifi->appass, wifi->apchannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_wifi_ap_stop(void) {
|
bool mg_wifi_ap_stop(void) {
|
||||||
|
|||||||
+15
-24
@@ -22,35 +22,26 @@ struct mg_tcpip_driver_cyw_firmware {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mg_tcpip_driver_cyw_data {
|
struct mg_tcpip_driver_cyw_data {
|
||||||
|
struct mg_wifi_data wifi;
|
||||||
void *bus;
|
void *bus;
|
||||||
struct mg_tcpip_driver_cyw_firmware *fw;
|
struct mg_tcpip_driver_cyw_firmware *fw;
|
||||||
char *ssid;
|
bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
|
||||||
char *pass;
|
|
||||||
char *apssid;
|
|
||||||
char *appass;
|
|
||||||
uint8_t security; // TBD
|
|
||||||
uint8_t apsecurity; // TBD
|
|
||||||
uint8_t apchannel;
|
|
||||||
bool apmode; // start in AP mode; 'false' starts connection to 'ssid' if not NULL
|
|
||||||
bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
do { \
|
||||||
do { \
|
static struct mg_tcpip_driver_cyw_data driver_data_; \
|
||||||
static struct mg_tcpip_driver_cyw_data driver_data_; \
|
static struct mg_tcpip_if mif_; \
|
||||||
static struct mg_tcpip_if mif_; \
|
MG_SET_WIFI_CONFIG(&driver_data_); \
|
||||||
MG_SET_WIFI_CONFIG(&driver_data_); \
|
mif_.ip = MG_TCPIP_IP; \
|
||||||
mif_.ip = MG_TCPIP_IP; \
|
mif_.mask = MG_TCPIP_MASK; \
|
||||||
mif_.mask = MG_TCPIP_MASK; \
|
mif_.gw = MG_TCPIP_GW; \
|
||||||
mif_.gw = MG_TCPIP_GW; \
|
mif_.driver = &mg_tcpip_driver_cyw; \
|
||||||
mif_.driver = &mg_tcpip_driver_pico_w; \
|
mif_.driver_data = &driver_data_; \
|
||||||
mif_.driver_data = &driver_data_; \
|
mif_.recv_queue.size = 8192; \
|
||||||
mif_.recv_queue.size = 8192; \
|
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
|
||||||
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
|
mg_tcpip_init(mgr, &mif_); \
|
||||||
mg_tcpip_init(mgr, &mif_); \
|
|
||||||
MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
|
MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+16
-10
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#if MG_ENABLE_TCPIP && \
|
#if MG_ENABLE_TCPIP && \
|
||||||
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
|
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
|
||||||
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11)
|
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
|
||||||
|
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
|
||||||
struct imxrt_enet {
|
struct imxrt_enet {
|
||||||
volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3],
|
volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3],
|
||||||
ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR,
|
ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR,
|
||||||
@@ -31,9 +32,12 @@ struct imxrt_enet {
|
|||||||
#if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11
|
#if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11
|
||||||
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U)
|
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U)
|
||||||
#define ETH_DESC_CNT 5 // Descriptors count
|
#define ETH_DESC_CNT 5 // Descriptors count
|
||||||
#else
|
#elif defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10
|
||||||
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x402D8000U)
|
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x402D8000U)
|
||||||
#define ETH_DESC_CNT 4 // Descriptors count
|
#define ETH_DESC_CNT 4 // Descriptors count
|
||||||
|
#else // MG_ENABLE_DRIVER_MCXE
|
||||||
|
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x40079000U)
|
||||||
|
#define ETH_DESC_CNT 4 // Descriptor count
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned
|
#define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned
|
||||||
@@ -44,15 +48,12 @@ struct enet_desc {
|
|||||||
uint32_t *buffer; // Data ptr
|
uint32_t *buffer; // Data ptr
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
|
|
||||||
#define MG_64BYTE_ALIGNED __attribute__((aligned((64U))))
|
|
||||||
|
|
||||||
// Descriptors: in non-cached area (TODO(scaprile)), (37.5.1.22.2 37.5.1.23.2)
|
// Descriptors: in non-cached area (TODO(scaprile)), (37.5.1.22.2 37.5.1.23.2)
|
||||||
// Buffers: 64-byte aligned (37.3.14)
|
// Buffers: 64-byte aligned (37.3.14)
|
||||||
static volatile struct enet_desc s_rxdesc[ETH_DESC_CNT] MG_64BYTE_ALIGNED;
|
static volatile struct enet_desc s_rxdesc[ETH_DESC_CNT] MG_ETH_RAM MG_64BYTE_ALIGNED;
|
||||||
static volatile struct enet_desc s_txdesc[ETH_DESC_CNT] MG_64BYTE_ALIGNED;
|
static volatile struct enet_desc s_txdesc[ETH_DESC_CNT] MG_ETH_RAM MG_64BYTE_ALIGNED;
|
||||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED;
|
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_64BYTE_ALIGNED;
|
||||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED;
|
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_64BYTE_ALIGNED;
|
||||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||||
|
|
||||||
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
|
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
|
||||||
@@ -189,9 +190,14 @@ static bool mg_tcpip_driver_imxrt_poll(struct mg_tcpip_if *ifp, bool s1) {
|
|||||||
return up;
|
return up;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ENET_IRQHandler(void);
|
|
||||||
static uint32_t s_rxno;
|
static uint32_t s_rxno;
|
||||||
|
#if !defined(MG_ENABLE_DRIVER_MCXE)
|
||||||
|
void ENET_IRQHandler(void);
|
||||||
void ENET_IRQHandler(void) {
|
void ENET_IRQHandler(void) {
|
||||||
|
#else
|
||||||
|
void ENET_Receive_IRQHandler(void);
|
||||||
|
void ENET_Receive_IRQHandler(void) {
|
||||||
|
#endif
|
||||||
ENET->EIR = MG_BIT(25); // Ack IRQ
|
ENET->EIR = MG_BIT(25); // Ack IRQ
|
||||||
// Frame received, loop
|
// Frame received, loop
|
||||||
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
|
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
|
||||||
|
|||||||
+2
-1
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#if MG_ENABLE_TCPIP && \
|
#if MG_ENABLE_TCPIP && \
|
||||||
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
|
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
|
||||||
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11)
|
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
|
||||||
|
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
|
||||||
|
|
||||||
struct mg_tcpip_driver_imxrt_data {
|
struct mg_tcpip_driver_imxrt_data {
|
||||||
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
|
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_NXP_WIFI) && \
|
||||||
|
MG_ENABLE_DRIVER_NXP_WIFI
|
||||||
|
|
||||||
|
#include "drivers/nxp_wifi.h"
|
||||||
|
|
||||||
|
bool __attribute__((weak)) netif_init(struct mg_tcpip_if *ifp) {
|
||||||
|
(void) ifp;
|
||||||
|
MG_ERROR(("Please link wifi/port/net contents"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t __attribute__((weak))
|
||||||
|
netif_tx(const void *bfr, size_t len, struct mg_tcpip_if *ifp) {
|
||||||
|
(void) bfr;
|
||||||
|
(void) len;
|
||||||
|
netif_init(ifp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool __attribute__((weak)) netif_connect(struct mg_wifi_data *wifi) {
|
||||||
|
(void) wifi;
|
||||||
|
return netif_init(NULL);
|
||||||
|
}
|
||||||
|
bool __attribute__((weak))
|
||||||
|
netif_poll(struct mg_tcpip_if *ifp, bool s1, mg_tcpip_event_handler_t evcb) {
|
||||||
|
(void) ifp;
|
||||||
|
(void) s1;
|
||||||
|
(void) evcb;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mg_tcpip_if *s_ifp;
|
||||||
|
static uint32_t s_ip, s_mask;
|
||||||
|
|
||||||
|
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
|
||||||
|
struct mg_wifi_data *wifi =
|
||||||
|
&((struct mg_tcpip_driver_nxp_wifi_data *) ifp->driver_data)->wifi;
|
||||||
|
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG &&
|
||||||
|
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
|
||||||
|
MG_DEBUG(("Access Point started"));
|
||||||
|
s_ip = ifp->ip, ifp->ip = wifi->apip;
|
||||||
|
s_mask = ifp->mask, ifp->mask = wifi->apmask;
|
||||||
|
ifp->enable_dhcp_client = false;
|
||||||
|
ifp->enable_dhcp_server = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nxp_wifi_init(struct mg_tcpip_if *ifp) {
|
||||||
|
struct mg_wifi_data *wifi =
|
||||||
|
&((struct mg_tcpip_driver_nxp_wifi_data *) ifp->driver_data)->wifi;
|
||||||
|
s_ifp = ifp;
|
||||||
|
s_ip = ifp->ip;
|
||||||
|
s_mask = ifp->mask;
|
||||||
|
ifp->pfn = wifi_cb;
|
||||||
|
if (!netif_init(ifp)) return false;
|
||||||
|
if (wifi->apmode) {
|
||||||
|
return mg_wifi_ap_start(wifi);
|
||||||
|
} else if (wifi->ssid != NULL && wifi->pass != NULL) {
|
||||||
|
return mg_wifi_connect(wifi);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nxp_wifi_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||||
|
return netif_poll(ifp, s1, mg_tcpip_call);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi = {nxp_wifi_init, netif_tx,
|
||||||
|
NULL, nxp_wifi_poll};
|
||||||
|
|
||||||
|
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
|
||||||
|
s_ifp->ip = s_ip;
|
||||||
|
s_ifp->mask = s_mask;
|
||||||
|
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
|
||||||
|
s_ifp->enable_dhcp_server = false;
|
||||||
|
return netif_connect(wifi);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __attribute__((weak)) mg_wifi_scan(void) {
|
||||||
|
return netif_init(NULL);
|
||||||
|
}
|
||||||
|
bool __attribute__((weak)) mg_wifi_disconnect(void) {
|
||||||
|
return netif_init(NULL);
|
||||||
|
}
|
||||||
|
bool __attribute__((weak)) mg_wifi_ap_start(struct mg_wifi_data *wifi) {
|
||||||
|
(void) wifi;
|
||||||
|
return netif_init(NULL);
|
||||||
|
}
|
||||||
|
bool __attribute__((weak)) mg_wifi_ap_stop(void) {
|
||||||
|
return netif_init(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && \
|
||||||
|
defined(MG_ENABLE_DRIVER_NXP_WIFI) && MG_ENABLE_DRIVER_NXP_WIFI
|
||||||
|
|
||||||
|
|
||||||
|
struct mg_tcpip_driver_nxp_wifi_data {
|
||||||
|
struct mg_wifi_data wifi;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
|
do { \
|
||||||
|
static struct mg_tcpip_driver_nxp_wifi_data driver_data_; \
|
||||||
|
static struct mg_tcpip_if mif_; \
|
||||||
|
MG_SET_WIFI_CONFIG(&driver_data_); \
|
||||||
|
mif_.ip = MG_TCPIP_IP; \
|
||||||
|
mif_.mask = MG_TCPIP_MASK; \
|
||||||
|
mif_.gw = MG_TCPIP_GW; \
|
||||||
|
mif_.driver = &mg_tcpip_driver_nxp_wifi; \
|
||||||
|
mif_.driver_data = &driver_data_; \
|
||||||
|
mif_.recv_queue.size = 8192; \
|
||||||
|
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
|
||||||
|
mg_tcpip_init(mgr, &mif_); \
|
||||||
|
MG_INFO(("Driver: nxp wifi, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
+37
-14
@@ -1,13 +1,15 @@
|
|||||||
#include "phy.h"
|
#include "phy.h"
|
||||||
|
|
||||||
enum { // ID1 ID2
|
enum { // ID1 ID2
|
||||||
MG_PHY_KSZ8x = 0x22, // 0022 1561 - KSZ8081RNB
|
MG_PHY_KSZ8x = 0x22, // 0022 156x - KSZ8081RNB, KSZ8091RNB
|
||||||
MG_PHY_DP83x = 0x2000,
|
MG_PHY_DP83x = 0x2000,
|
||||||
MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I
|
MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I
|
||||||
MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I
|
MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I
|
||||||
MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I
|
MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I
|
||||||
MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720
|
MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720
|
||||||
MG_PHY_RTL8201 = 0x1C, // 001c c816 - RTL8201,
|
MG_PHY_RTL82x = 0x1c,
|
||||||
|
MG_PHY_RTL8201 = 0xc816, // 001c c816 - RTL8201F
|
||||||
|
MG_PHY_RTL8211 = 0xc916, // 001c c916 - RTL8211F
|
||||||
MG_PHY_ICS1894x = 0x15,
|
MG_PHY_ICS1894x = 0x15,
|
||||||
MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894
|
MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894
|
||||||
};
|
};
|
||||||
@@ -24,8 +26,9 @@ enum {
|
|||||||
MG_PHY_KSZ8x_REG_PC1R = 30,
|
MG_PHY_KSZ8x_REG_PC1R = 30,
|
||||||
MG_PHY_KSZ8x_REG_PC2R = 31,
|
MG_PHY_KSZ8x_REG_PC2R = 31,
|
||||||
MG_PHY_LAN87x_REG_SCSR = 31,
|
MG_PHY_LAN87x_REG_SCSR = 31,
|
||||||
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
|
MG_PHY_RTL82x_REG_PAGESEL = 31,
|
||||||
MG_PHY_RTL8201_REG_PAGESEL = 31,
|
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
|
||||||
|
MG_PHY_RTL8211_REG_PHYSR = 26, // in page a43
|
||||||
MG_PHY_ICS189432_REG_POLL = 17
|
MG_PHY_ICS189432_REG_POLL = 17
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,14 +49,20 @@ static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
|
|||||||
return "KSZ8x";
|
return "KSZ8x";
|
||||||
case MG_PHY_LAN87x:
|
case MG_PHY_LAN87x:
|
||||||
return "LAN87x";
|
return "LAN87x";
|
||||||
case MG_PHY_RTL8201:
|
case MG_PHY_RTL82x:
|
||||||
return "RTL8201";
|
switch (id2) {
|
||||||
|
case MG_PHY_RTL8201:
|
||||||
|
return "RTL8201";
|
||||||
|
case MG_PHY_RTL8211:
|
||||||
|
return "RTL8211";
|
||||||
|
default:
|
||||||
|
return "RTL82x";
|
||||||
|
}
|
||||||
case MG_PHY_ICS1894x:
|
case MG_PHY_ICS1894x:
|
||||||
return "ICS1894x";
|
return "ICS1894x";
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
(void) id2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
|
void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
|
||||||
@@ -91,13 +100,15 @@ void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
|
|||||||
(uint16_t) (MG_BIT(15) | MG_BIT(8) | MG_BIT(7)));
|
(uint16_t) (MG_BIT(15) | MG_BIT(8) | MG_BIT(7)));
|
||||||
} else if (id1 == MG_PHY_LAN87x) {
|
} else if (id1 == MG_PHY_LAN87x) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
} else if (id1 == MG_PHY_RTL8201) {
|
} else if (id1 == MG_PHY_RTL82x && id2 == MG_PHY_RTL8201) {
|
||||||
// assume PHY has been hardware strapped properly
|
// assume PHY has been hardware strapped properly
|
||||||
#if 0
|
#if 0
|
||||||
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 7); // Select page 7
|
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 7); // Select page 7
|
||||||
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_RMSR, 0x1ffa);
|
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_RMSR, 0x1ffa);
|
||||||
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 0); // Select page 0
|
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0); // Select page 0
|
||||||
#endif
|
#endif
|
||||||
|
} else if (id1 == MG_PHY_RTL82x && id2 == MG_PHY_RTL8211) {
|
||||||
|
// assume PHY has been hardware strapped properly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,10 +148,22 @@ bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex,
|
|||||||
uint16_t scsr = phy->read_reg(phy_addr, MG_PHY_LAN87x_REG_SCSR);
|
uint16_t scsr = phy->read_reg(phy_addr, MG_PHY_LAN87x_REG_SCSR);
|
||||||
*full_duplex = scsr & MG_BIT(4);
|
*full_duplex = scsr & MG_BIT(4);
|
||||||
*speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
|
*speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
|
||||||
} else if (id1 == MG_PHY_RTL8201) {
|
} else if (id1 == MG_PHY_RTL82x) {
|
||||||
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR);
|
uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
|
||||||
*full_duplex = bcr & MG_BIT(8);
|
if (id2 == MG_PHY_RTL8211) {
|
||||||
*speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
|
uint16_t physr;
|
||||||
|
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0xa43);
|
||||||
|
physr = phy->read_reg(phy_addr, MG_PHY_RTL8211_REG_PHYSR);
|
||||||
|
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0);
|
||||||
|
*full_duplex = physr & MG_BIT(3);
|
||||||
|
*speed = (physr & MG_BIT(5)) ? MG_PHY_SPEED_1000M
|
||||||
|
: (physr & MG_BIT(4)) ? MG_PHY_SPEED_100M
|
||||||
|
: MG_PHY_SPEED_10M;
|
||||||
|
} else {
|
||||||
|
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR);
|
||||||
|
*full_duplex = bcr & MG_BIT(8);
|
||||||
|
*speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
|
||||||
|
}
|
||||||
} else if (id1 == MG_PHY_ICS1894x) {
|
} else if (id1 == MG_PHY_ICS1894x) {
|
||||||
uint16_t poll_reg = phy->read_reg(phy_addr, MG_PHY_ICS189432_REG_POLL);
|
uint16_t poll_reg = phy->read_reg(phy_addr, MG_PHY_ICS189432_REG_POLL);
|
||||||
*full_duplex = poll_reg & MG_BIT(14);
|
*full_duplex = poll_reg & MG_BIT(14);
|
||||||
|
|||||||
+45
-21
@@ -6,23 +6,41 @@
|
|||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
static struct mg_tcpip_if *s_ifp;
|
static struct mg_tcpip_if *s_ifp;
|
||||||
|
static uint32_t s_ip, s_mask;
|
||||||
|
static bool s_aplink = false, s_scanning = false;
|
||||||
|
static bool s_stalink = false, s_connecting = false;
|
||||||
|
|
||||||
|
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
|
||||||
|
struct mg_wifi_data *wifi =
|
||||||
|
&((struct mg_tcpip_driver_pico_w_data *) ifp->driver_data)->wifi;
|
||||||
|
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG &&
|
||||||
|
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
|
||||||
|
MG_DEBUG(("Access Point started"));
|
||||||
|
s_ip = ifp->ip, ifp->ip = wifi->apip;
|
||||||
|
s_mask = ifp->mask, ifp->mask = wifi->apmask;
|
||||||
|
ifp->enable_dhcp_client = false;
|
||||||
|
ifp->enable_dhcp_server = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool mg_tcpip_driver_pico_w_init(struct mg_tcpip_if *ifp) {
|
static bool mg_tcpip_driver_pico_w_init(struct mg_tcpip_if *ifp) {
|
||||||
struct mg_tcpip_driver_pico_w_data *d =
|
struct mg_tcpip_driver_pico_w_data *d =
|
||||||
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
||||||
|
struct mg_wifi_data *wifi = &d->wifi;
|
||||||
s_ifp = ifp;
|
s_ifp = ifp;
|
||||||
|
s_ip = ifp->ip;
|
||||||
|
s_mask = ifp->mask;
|
||||||
|
ifp->pfn = wifi_cb;
|
||||||
if (cyw43_arch_init() != 0)
|
if (cyw43_arch_init() != 0)
|
||||||
return false; // initialize async_context and WiFi chip
|
return false; // initialize async_context and WiFi chip
|
||||||
if (d->apmode && d->apssid != NULL) {
|
if (wifi->apmode && wifi->apssid != NULL) {
|
||||||
MG_DEBUG(("Starting AP '%s' (%u)", d->apssid, d->apchannel));
|
if (!mg_wifi_ap_start(wifi)) return false;
|
||||||
if (!mg_wifi_ap_start(d->apssid, d->appass, d->apchannel)) return false;
|
|
||||||
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); // same MAC
|
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); // same MAC
|
||||||
} else {
|
} else {
|
||||||
cyw43_arch_enable_sta_mode();
|
cyw43_arch_enable_sta_mode();
|
||||||
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac);
|
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac);
|
||||||
if (d->ssid != NULL) {
|
if (wifi->ssid != NULL) {
|
||||||
MG_DEBUG(("Connecting to '%s'", d->ssid));
|
return mg_wifi_connect(wifi);
|
||||||
return mg_wifi_connect(d->ssid, d->pass);
|
|
||||||
} else {
|
} else {
|
||||||
cyw43_arch_disable_sta_mode();
|
cyw43_arch_disable_sta_mode();
|
||||||
}
|
}
|
||||||
@@ -35,35 +53,33 @@ static size_t mg_tcpip_driver_pico_w_tx(const void *buf, size_t len,
|
|||||||
struct mg_tcpip_driver_pico_w_data *d =
|
struct mg_tcpip_driver_pico_w_data *d =
|
||||||
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
||||||
return cyw43_send_ethernet(&cyw43_state,
|
return cyw43_send_ethernet(&cyw43_state,
|
||||||
d->apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len, buf,
|
d->wifi.apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len,
|
||||||
false) == 0
|
buf, false) == 0
|
||||||
? len
|
? len
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool s_aplink = false, s_scanning = false;
|
|
||||||
static bool s_stalink = false, s_connecting = false;
|
|
||||||
|
|
||||||
static bool mg_tcpip_driver_pico_w_poll(struct mg_tcpip_if *ifp, bool s1) {
|
static bool mg_tcpip_driver_pico_w_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||||
cyw43_arch_poll(); // not necessary, except when IRQs are disabled (OTA)
|
cyw43_arch_poll(); // not necessary, except when IRQs are disabled (OTA)
|
||||||
if (s_scanning && !cyw43_wifi_scan_active(&cyw43_state)) {
|
if (s_scanning && !cyw43_wifi_scan_active(&cyw43_state)) {
|
||||||
MG_VERBOSE(("scan complete"));
|
MG_VERBOSE(("scan complete"));
|
||||||
s_scanning = 0;
|
s_scanning = 0;
|
||||||
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
|
mg_tcpip_call(ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
|
||||||
}
|
}
|
||||||
if (ifp->update_mac_hash_table) {
|
if (ifp->update_mac_hash_table) {
|
||||||
// first call to _poll() is after _init(), so this is safe
|
// first call to _poll() is after _init(), so this is safe
|
||||||
cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *)mcast_addr, true);
|
cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *) mcast_addr,
|
||||||
|
true);
|
||||||
ifp->update_mac_hash_table = false;
|
ifp->update_mac_hash_table = false;
|
||||||
}
|
}
|
||||||
if (!s1) return false;
|
if (!s1) return false;
|
||||||
struct mg_tcpip_driver_pico_w_data *d =
|
struct mg_tcpip_driver_pico_w_data *d =
|
||||||
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
|
||||||
if (d->apmode) return s_aplink;
|
if (d->wifi.apmode) return s_aplink;
|
||||||
int sdkstate = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
|
int sdkstate = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
|
||||||
MG_VERBOSE(("conn: %c state: %d", s_connecting ? '1' : '0', sdkstate));
|
MG_VERBOSE(("conn: %c state: %d", s_connecting ? '1' : '0', sdkstate));
|
||||||
if (sdkstate < 0 && s_connecting) {
|
if (sdkstate < 0 && s_connecting) {
|
||||||
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, &sdkstate);
|
mg_tcpip_call(ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, &sdkstate);
|
||||||
s_connecting = false;
|
s_connecting = false;
|
||||||
}
|
}
|
||||||
return s_stalink;
|
return s_stalink;
|
||||||
@@ -94,7 +110,7 @@ void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
|
|||||||
}
|
}
|
||||||
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
|
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
|
||||||
if (itf == CYW43_ITF_AP) {
|
if (itf == CYW43_ITF_AP) {
|
||||||
s_aplink = false;
|
s_aplink = false;
|
||||||
} else {
|
} else {
|
||||||
s_stalink = false;
|
s_stalink = false;
|
||||||
// SDK calls this before we check status, don't clear s_connecting here
|
// SDK calls this before we check status, don't clear s_connecting here
|
||||||
@@ -134,9 +150,15 @@ bool mg_wifi_scan(void) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_wifi_connect(char *ssid, char *pass) {
|
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
|
||||||
|
s_ifp->ip = s_ip;
|
||||||
|
s_ifp->mask = s_mask;
|
||||||
|
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
|
||||||
|
s_ifp->enable_dhcp_server = false;
|
||||||
cyw43_arch_enable_sta_mode();
|
cyw43_arch_enable_sta_mode();
|
||||||
int res = cyw43_arch_wifi_connect_async(ssid, pass, CYW43_AUTH_WPA2_AES_PSK);
|
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
|
||||||
|
int res = cyw43_arch_wifi_connect_async(wifi->ssid, wifi->pass,
|
||||||
|
CYW43_AUTH_WPA2_AES_PSK);
|
||||||
MG_VERBOSE(("res: %d", res));
|
MG_VERBOSE(("res: %d", res));
|
||||||
if (res == 0) s_connecting = true;
|
if (res == 0) s_connecting = true;
|
||||||
return (res == 0);
|
return (res == 0);
|
||||||
@@ -148,9 +170,11 @@ bool mg_wifi_disconnect(void) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
|
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
|
||||||
cyw43_wifi_ap_set_channel(&cyw43_state, channel);
|
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
|
||||||
cyw43_arch_enable_ap_mode(ssid, pass, CYW43_AUTH_WPA2_AES_PSK);
|
cyw43_wifi_ap_set_channel(&cyw43_state, wifi->apchannel);
|
||||||
|
cyw43_arch_enable_ap_mode(wifi->apssid, wifi->appass,
|
||||||
|
CYW43_AUTH_WPA2_AES_PSK);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,7 @@
|
|||||||
#include "pico/unique_id.h" // keep this include
|
#include "pico/unique_id.h" // keep this include
|
||||||
|
|
||||||
struct mg_tcpip_driver_pico_w_data {
|
struct mg_tcpip_driver_pico_w_data {
|
||||||
char *ssid;
|
struct mg_wifi_data wifi;
|
||||||
char *pass;
|
|
||||||
char *apssid;
|
|
||||||
char *appass;
|
|
||||||
uint8_t security; // TBD
|
|
||||||
uint8_t apsecurity; // TBD
|
|
||||||
uint8_t apchannel;
|
|
||||||
bool apmode; // start in AP mode; 'false' starts connection to 'ssid' if not NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
|
|||||||
+5
-9
@@ -38,16 +38,12 @@ struct ra_edmac {
|
|||||||
#define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32
|
#define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32
|
||||||
#define ETH_DESC_CNT 4 // Descriptors count
|
#define ETH_DESC_CNT 4 // Descriptors count
|
||||||
|
|
||||||
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
|
|
||||||
#define MG_16BYTE_ALIGNED __attribute__((aligned((16U))))
|
|
||||||
#define MG_32BYTE_ALIGNED __attribute__((aligned((32U))))
|
|
||||||
|
|
||||||
// Descriptors: 16-byte aligned
|
// Descriptors: 16-byte aligned
|
||||||
// Buffers: 32-byte aligned (27.3.1)
|
// Buffers: 32-byte aligned (27.3.1)
|
||||||
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][4] MG_16BYTE_ALIGNED;
|
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][4] MG_ETH_RAM MG_16BYTE_ALIGNED;
|
||||||
static volatile uint32_t s_txdesc[ETH_DESC_CNT][4] MG_16BYTE_ALIGNED;
|
static volatile uint32_t s_txdesc[ETH_DESC_CNT][4] MG_ETH_RAM MG_16BYTE_ALIGNED;
|
||||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED;
|
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_32BYTE_ALIGNED;
|
||||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED;
|
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_32BYTE_ALIGNED;
|
||||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||||
|
|
||||||
// fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent
|
// fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent
|
||||||
@@ -164,7 +160,7 @@ static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
|
|||||||
|
|
||||||
MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin));
|
MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin));
|
||||||
struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
|
struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
|
||||||
mg_phy_init(&phy, d->phy_addr, 0); // MAC clocks PHY
|
mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC);
|
||||||
|
|
||||||
// Select RMII mode,
|
// Select RMII mode,
|
||||||
ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC
|
ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC
|
||||||
|
|||||||
+5
-5
@@ -26,17 +26,17 @@ struct ENET_Type {
|
|||||||
CHANNEL_TCSR[4], CHANNEL_TCCR[4];
|
CHANNEL_TCSR[4], CHANNEL_TCCR[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#undef ENET
|
||||||
#define ENET ((struct ENET_Type *) 0x40138000)
|
#define ENET ((struct ENET_Type *) 0x40138000)
|
||||||
|
|
||||||
#define ETH_PKT_SIZE 1536 // Max frame size
|
#define ETH_PKT_SIZE 1536 // Max frame size
|
||||||
#define ETH_DESC_CNT 4 // Descriptors count
|
#define ETH_DESC_CNT 4 // Descriptors count
|
||||||
#define ETH_DS 2 // Descriptor size (words)
|
#define ETH_DS 2 // Descriptor size (words)
|
||||||
|
|
||||||
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U))))
|
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED;
|
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED;
|
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||||
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
|
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||||
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
|
|
||||||
static uint8_t s_txno; // Current TX descriptor
|
static uint8_t s_txno; // Current TX descriptor
|
||||||
static uint8_t s_rxno; // Current RX descriptor
|
static uint8_t s_rxno; // Current RX descriptor
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,525 @@
|
|||||||
|
#include "st67w6.h"
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_ST67W6) && \
|
||||||
|
MG_ENABLE_DRIVER_ST67W6
|
||||||
|
|
||||||
|
static struct mg_tcpip_if *s_ifp;
|
||||||
|
static uint32_t s_ip, s_mask;
|
||||||
|
static bool s_link = false, s_connecting = false;
|
||||||
|
|
||||||
|
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
|
||||||
|
struct mg_wifi_data *wifi =
|
||||||
|
&((struct mg_tcpip_driver_st67w6_data *) ifp->driver_data)->wifi;
|
||||||
|
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG &&
|
||||||
|
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
|
||||||
|
MG_DEBUG(("Access Point started"));
|
||||||
|
s_ip = ifp->ip, ifp->ip = wifi->apip;
|
||||||
|
s_mask = ifp->mask, ifp->mask = wifi->apmask;
|
||||||
|
ifp->enable_dhcp_client = false;
|
||||||
|
ifp->enable_dhcp_server = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool st67w6_init(uint8_t *mac);
|
||||||
|
static void st67w6_poll(bool is_at);
|
||||||
|
|
||||||
|
static bool mg_tcpip_driver_st67w6_init(struct mg_tcpip_if *ifp) {
|
||||||
|
struct mg_tcpip_driver_st67w6_data *d =
|
||||||
|
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
|
||||||
|
struct mg_wifi_data *wifi = &d->wifi;
|
||||||
|
if (MG_BIG_ENDIAN) {
|
||||||
|
MG_ERROR(("Big-endian host"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (d->is_ready == NULL) return false;
|
||||||
|
s_ifp = ifp;
|
||||||
|
s_ip = ifp->ip;
|
||||||
|
s_mask = ifp->mask;
|
||||||
|
s_link = false;
|
||||||
|
ifp->pfn = wifi_cb;
|
||||||
|
if (!st67w6_init(ifp->mac)) return false;
|
||||||
|
|
||||||
|
if (d->send_queue.size == 0) d->send_queue.size = 8192;
|
||||||
|
d->send_queue.buf = (char *) mg_calloc(1, d->send_queue.size);
|
||||||
|
if (d->send_queue.buf == NULL) {
|
||||||
|
MG_ERROR(("OOM"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wifi->apmode) {
|
||||||
|
return mg_wifi_ap_start(wifi);
|
||||||
|
} else if (wifi->ssid != NULL && wifi->pass != NULL) {
|
||||||
|
return mg_wifi_connect(wifi);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decouple; module access depends on it being RDY. See st67w6_poll()
|
||||||
|
size_t mg_tcpip_driver_st67w6_output(const void *buf, size_t len,
|
||||||
|
struct mg_tcpip_if *ifp) {
|
||||||
|
struct mg_tcpip_driver_st67w6_data *d =
|
||||||
|
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
|
||||||
|
char *p;
|
||||||
|
if (mg_queue_book(&d->send_queue, &p, len) < len) return 0;
|
||||||
|
memcpy(p, buf, len);
|
||||||
|
mg_queue_add(&d->send_queue, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_tcpip_driver_st67w6_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||||
|
struct mg_tcpip_driver_st67w6_data *d =
|
||||||
|
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
|
||||||
|
if (d->is_ready == NULL) return false;
|
||||||
|
st67w6_poll(false);
|
||||||
|
if (!s1) return false;
|
||||||
|
return s_link;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_tcpip_driver mg_tcpip_driver_st67w6 = {
|
||||||
|
mg_tcpip_driver_st67w6_init, mg_tcpip_driver_st67w6_output, NULL,
|
||||||
|
mg_tcpip_driver_st67w6_poll};
|
||||||
|
|
||||||
|
// AT | STA | AP | HCI | OT
|
||||||
|
// --------------------------
|
||||||
|
// framing <-- includes rx stall indication
|
||||||
|
// --------------------------
|
||||||
|
// SPI <-- padded to 32-bit
|
||||||
|
//
|
||||||
|
// Transactions take place when the module signals RDY, 'tx' and 'write'
|
||||||
|
// functions actually just write to memory
|
||||||
|
// - AT: handles configuration and events (unsolicited +foo:). Responses may
|
||||||
|
// come as:
|
||||||
|
// - 1 frame: just OK or ERROR
|
||||||
|
// - 2 frames: 1 text line each, a response and OK
|
||||||
|
// - 3 frames: 2 text lines: 1 frame with text and no CR/LF, 1 frame with
|
||||||
|
// binary and CR/LF, 1 text line with OK
|
||||||
|
// - STA and AP contain plain Ethernet frames to/from the STA and AP networks,
|
||||||
|
// respectively
|
||||||
|
// - HCI: BLE stuff
|
||||||
|
// - OT: ?
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
// little endian
|
||||||
|
|
||||||
|
struct spi_hdr {
|
||||||
|
uint16_t magic;
|
||||||
|
uint16_t len;
|
||||||
|
uint8_t vflags; // version :2, rx_stall :1, flags :5
|
||||||
|
uint8_t type;
|
||||||
|
uint16_t reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ST67W6_SPI_TYPE_AT 0
|
||||||
|
#define ST67W6_SPI_TYPE_STA 1
|
||||||
|
#define ST67W6_SPI_TYPE_AP 2
|
||||||
|
#define ST67W6_SPI_TYPE_HCI 3
|
||||||
|
#define ST67W6_SPI_TYPE_OT 4
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
static uint32_t txdata[2048 / 4], rxdata[2048 / 4];
|
||||||
|
static uint8_t at_resp[300];
|
||||||
|
|
||||||
|
static bool s_at_ok, s_at_err;
|
||||||
|
static size_t s_at_resp_len;
|
||||||
|
static void st67w6_handle_wifi_evnt(char *, size_t len);
|
||||||
|
static void st67w6_handle_scan_result(char *, size_t len);
|
||||||
|
|
||||||
|
static size_t st67w6_spi_poll(uint8_t *write, uint8_t *read);
|
||||||
|
static void st67w6_write(unsigned int f, void *data, uint16_t len);
|
||||||
|
static void st67w6_update_hash_table(void);
|
||||||
|
|
||||||
|
// High-level comm stuff
|
||||||
|
|
||||||
|
static void st67w6_poll(bool is_at) {
|
||||||
|
struct mg_tcpip_driver_st67w6_data *d =
|
||||||
|
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
|
||||||
|
struct spi_hdr *h = (struct spi_hdr *) rxdata;
|
||||||
|
unsigned int type;
|
||||||
|
uint8_t *txsource = (uint8_t *) txdata;
|
||||||
|
if (s_ifp->update_mac_hash_table) {
|
||||||
|
// first call to _poll() is after _init(), so this is safe
|
||||||
|
st67w6_update_hash_table();
|
||||||
|
s_ifp->update_mac_hash_table = false;
|
||||||
|
}
|
||||||
|
if (!is_at) { // send outstanding WLAN frames in the queue
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
|
// NOTE(): have traffic-dependent queues or queue traffic type with data
|
||||||
|
if ((len = mg_queue_next(&d->send_queue, &buf)) > 0) {
|
||||||
|
st67w6_write(d->wifi.apmode ? ST67W6_SPI_TYPE_AP : ST67W6_SPI_TYPE_STA,
|
||||||
|
buf, (uint16_t) len);
|
||||||
|
mg_queue_del(&d->send_queue, len);
|
||||||
|
} else { // nothing to send
|
||||||
|
txsource = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (st67w6_spi_poll(txsource, (uint8_t *) rxdata) == 0) return;
|
||||||
|
if (h->len == 0) return;
|
||||||
|
type = h->type;
|
||||||
|
if (type == ST67W6_SPI_TYPE_AT) {
|
||||||
|
char *p = (char *) (h + 1);
|
||||||
|
size_t len = h->len;
|
||||||
|
if (len > 7 && strncmp(p, "+CWLAP:", 7) == 0) { // scan result
|
||||||
|
st67w6_handle_scan_result(p + 7, len - 7);
|
||||||
|
} else if (len > 4 && strncmp(p, "+CW:", 4) == 0) {
|
||||||
|
st67w6_handle_wifi_evnt(p + 4, len - 4);
|
||||||
|
} else {
|
||||||
|
MG_VERBOSE(("AT partial: %.*s", (int) len, p));
|
||||||
|
if (s_at_resp_len + len >= sizeof(at_resp))
|
||||||
|
s_at_resp_len = 0; // truncate response, error will be caught later
|
||||||
|
memcpy(at_resp + s_at_resp_len, p, len);
|
||||||
|
s_at_resp_len += len;
|
||||||
|
if (mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
|
||||||
|
mg_str_n("*ERROR*", 7), NULL)) {
|
||||||
|
s_at_err = true;
|
||||||
|
} else if (mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
|
||||||
|
mg_str_n("*OK*", 4), NULL)) {
|
||||||
|
s_at_ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == ST67W6_SPI_TYPE_STA || type == ST67W6_SPI_TYPE_AP) {
|
||||||
|
// WLAN frame reception
|
||||||
|
mg_tcpip_qwrite(h + 1, h->len, s_ifp);
|
||||||
|
} // else silently discard
|
||||||
|
}
|
||||||
|
|
||||||
|
// WLAN event handling
|
||||||
|
|
||||||
|
// - Do not call any AT functions here, otherwise revise st67w6_at_wait()
|
||||||
|
// - The module likes to send ERROR along with other events
|
||||||
|
static void st67w6_handle_wifi_evnt(char *p, size_t len) {
|
||||||
|
struct mg_str data[2];
|
||||||
|
MG_VERBOSE(("event: %.*s", (int) len, p));
|
||||||
|
if (len > 9 && strncmp(p, "CONNECTED", 9) == 0) {
|
||||||
|
s_link = true;
|
||||||
|
s_connecting = false;
|
||||||
|
} else if (len > 12 && strncmp(p, "DISCONNECTED", 12) == 0) {
|
||||||
|
s_link = false;
|
||||||
|
s_connecting = false; // should not be needed
|
||||||
|
} else if (s_connecting && len > 6 &&
|
||||||
|
mg_match(mg_str_n(p, len), mg_str_n("ERROR,*\r\n*", 10), data)) {
|
||||||
|
size_t reason = 0;
|
||||||
|
bool ok = mg_to_size_t(data[0], &reason);
|
||||||
|
s_connecting = false;
|
||||||
|
MG_ERROR(("CONNECT FAILED"));
|
||||||
|
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, ok ? &reason : NULL);
|
||||||
|
} else if (len > 9 && strncmp(p, "SCAN_DONE", 9) == 0) {
|
||||||
|
MG_VERBOSE(("scan complete"));
|
||||||
|
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
|
||||||
|
} // else silently discard: CONNECTING; STA_CONNECTED,"MAC";
|
||||||
|
// STA_DISCONNECTED,"MAC"; DIST_STA_IP,"MAC","IP"
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool st67w6_at_cmd(char *cmd, size_t len);
|
||||||
|
|
||||||
|
// Wi-Fi network stuff
|
||||||
|
|
||||||
|
static bool st67w6_wifi_connect(char *ssid, char *pass) {
|
||||||
|
char cmd[90]; // ssid + pass + AT
|
||||||
|
size_t cmd_len;
|
||||||
|
if (!st67w6_at_cmd("AT+CWMODE=1,0\r\n", 15)) return false;
|
||||||
|
cmd_len = mg_snprintf(cmd, sizeof(cmd), "AT+CWJAP=\"%s\",\"%s\",,0\r\n", ssid,
|
||||||
|
pass); // takes >700ms
|
||||||
|
if (!st67w6_at_cmd(cmd, cmd_len)) return false;
|
||||||
|
st67w6_at_cmd("AT+CWRECONNCFG=0,0\r\n", 20); // disregard error, connecting
|
||||||
|
s_connecting = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool st67w6_wifi_disconnect(void) {
|
||||||
|
s_connecting = false;
|
||||||
|
if (!st67w6_at_cmd("AT+CWQAP=0\r\n", 12)) return false; // takes >800ms
|
||||||
|
return st67w6_at_cmd("AT+CWMODE=0,0\r\n", 15); // takes >550ms
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool st67w6_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
|
||||||
|
char cmd[90]; // ssid + pass + AT
|
||||||
|
size_t cmd_len;
|
||||||
|
if (!st67w6_at_cmd("AT+CWMODE=2,0\r\n", 15)) return false; // takes >800ms
|
||||||
|
cmd_len = mg_snprintf(
|
||||||
|
cmd, sizeof(cmd), "AT+CWSAP=\"%s\",\"%s\",%u,3,2,0\r\n", ssid, pass,
|
||||||
|
channel); // 3: WPA2_PSK; 2: max stations // takes >350ms
|
||||||
|
s_link = true;
|
||||||
|
return st67w6_at_cmd(cmd, cmd_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool st67w6_wifi_ap_stop(void) {
|
||||||
|
s_link = false;
|
||||||
|
return st67w6_at_cmd("AT+CWMODE=0,0\r\n", 15); // takes >550ms
|
||||||
|
}
|
||||||
|
|
||||||
|
// WLAN scan handling
|
||||||
|
|
||||||
|
// +CWLAP:(security,"SSID",RSSI,"BSSID",channel,cipher,proto,wps)\r\n
|
||||||
|
// security: OPEN, WEP, WPA, WPA2, WPA-WPA2, WPA-EAP, WPA3-SAE, WPA2-WPA3-SAE
|
||||||
|
// cipher: NONE, WEP, AES/CCMP, TKIP, TKIP and AES/CCMP
|
||||||
|
// proto: 4-bit bitmap AX,N,G,B; all set from right to left
|
||||||
|
|
||||||
|
static bool st67w6_wifi_scan(void) {
|
||||||
|
return st67w6_at_cmd("AT+CWLAPOPT=1,1695,-100,255,50\r\n", 32) &&
|
||||||
|
st67w6_at_cmd("AT+CWLAP=0,,,0\r\n", 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void st67w6_handle_scan_result(char *data, size_t len) {
|
||||||
|
struct mg_wifi_scan_bss_data bss;
|
||||||
|
struct mg_str fields[2];
|
||||||
|
char mac[6];
|
||||||
|
uint8_t val;
|
||||||
|
unsigned int i;
|
||||||
|
MG_VERBOSE(("scan result event: %.*s", (int) len, data));
|
||||||
|
++data, --len; // skip '('
|
||||||
|
if (!mg_span(mg_str_n(data, len), &fields[0], &fields[1], ',') ||
|
||||||
|
!mg_str_to_num(fields[0], 10, &val, 1))
|
||||||
|
return;
|
||||||
|
bss.security =
|
||||||
|
(val == 0) ? MG_WIFI_SECURITY_OPEN : (uint8_t) MG_WIFI_SECURITY_WEP;
|
||||||
|
if (val == 2 || val == 4) bss.security |= MG_WIFI_SECURITY_WPA;
|
||||||
|
if (val == 3 || val == 4 || val == 7) bss.security |= MG_WIFI_SECURITY_WPA2;
|
||||||
|
if (val == 6 || val == 7) bss.security |= MG_WIFI_SECURITY_WPA3;
|
||||||
|
if (val == 5) bss.security |= MG_WIFI_SECURITY_WPA_ENTERPRISE;
|
||||||
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
|
||||||
|
bss.SSID.buf = fields[0].buf + 1, bss.SSID.len = fields[0].len - 2;
|
||||||
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
|
||||||
|
while (fields[0].buf[0] == ' ') ++fields[0].buf, --fields[0].len;
|
||||||
|
if (fields[0].buf[0] != '-') return; // positive RSSI would be great
|
||||||
|
++fields[0].buf, --fields[0].len;
|
||||||
|
if (!mg_str_to_num(fields[0], 10, &val, 1)) return;
|
||||||
|
bss.RSSI = (int8_t) - (int8_t) val;
|
||||||
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
|
||||||
|
if (fields[0].len < 19) return;
|
||||||
|
++fields[0].buf, --fields[0].len; // skip '"'
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
struct mg_str str;
|
||||||
|
str.buf = fields[0].buf + 3 * i;
|
||||||
|
str.len = 2;
|
||||||
|
if (!mg_str_to_num(str, 16, &mac[i], 1)) return;
|
||||||
|
}
|
||||||
|
bss.BSSID = mac;
|
||||||
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
|
||||||
|
!mg_str_to_num(fields[0], 10, &bss.channel, 1))
|
||||||
|
return;
|
||||||
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
|
||||||
|
!mg_str_to_num(fields[0], 10, &val, 1))
|
||||||
|
return;
|
||||||
|
// ignore cypher
|
||||||
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
|
||||||
|
!mg_str_to_num(fields[0], 10, &val, 1))
|
||||||
|
return;
|
||||||
|
bss.has_n = (val & 4) != 0;
|
||||||
|
bss.has_ax = (val & 8) != 0;
|
||||||
|
bss.band = MG_WIFI_BAND_2G; // NOT INFORMED with default options, no docs
|
||||||
|
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf,
|
||||||
|
bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI,
|
||||||
|
bss.security));
|
||||||
|
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AT stuff
|
||||||
|
|
||||||
|
static inline bool delayms(unsigned int ms) {
|
||||||
|
mg_delayms(ms);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send AT command, wait for a response or timeout, meanwhile delivering
|
||||||
|
// received frames and events
|
||||||
|
|
||||||
|
static bool st67w6_at_cmd(char *cmd, size_t len) {
|
||||||
|
bool is_at = true;
|
||||||
|
unsigned int times = 1000;
|
||||||
|
s_at_resp_len = 0;
|
||||||
|
st67w6_write(ST67W6_SPI_TYPE_AT, cmd, (uint16_t) len);
|
||||||
|
s_at_ok = false, s_at_err = false;
|
||||||
|
do { // AT response processing does not call any other AT function
|
||||||
|
st67w6_poll(is_at); // otherwise we can't allow them to pile up here
|
||||||
|
is_at = false; // avoid repeating, allow queued WLAN frames to be sent
|
||||||
|
// network frames will be pushed to the queue so that is safe
|
||||||
|
} while (!s_at_ok && !s_at_err && times-- > 0 && delayms(1));
|
||||||
|
MG_VERBOSE(("AT response:\n%.*s", s_at_resp_len, at_resp));
|
||||||
|
MG_VERBOSE(("ok: %c, err: %c, times: %d", s_at_ok ? '1' : '0',
|
||||||
|
s_at_err ? '1' : '0', (int) times));
|
||||||
|
return s_at_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool st67w6_spi_init(void);
|
||||||
|
bool mg_to_size_t(struct mg_str str, size_t *val);
|
||||||
|
|
||||||
|
static bool st67w6_init(uint8_t *mac) {
|
||||||
|
// struct mg_tcpip_driver_st67w6_data *d = (struct
|
||||||
|
// mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
|
||||||
|
struct mg_str data[3];
|
||||||
|
size_t val;
|
||||||
|
bool is_b = false;
|
||||||
|
if (!st67w6_spi_init()) return false;
|
||||||
|
if (!st67w6_at_cmd("AT\r\n", 4)) return false;
|
||||||
|
if (!st67w6_at_cmd("AT+CWNETMODE?\r\n", 15) ||
|
||||||
|
!mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
|
||||||
|
mg_str_n("*:*\r\n*", 6), data) ||
|
||||||
|
!mg_to_size_t(data[1], &val))
|
||||||
|
return false;
|
||||||
|
if (val != 0) {
|
||||||
|
MG_ERROR(("Wrong firmware, T02 is needed"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// set clock, who cares ???
|
||||||
|
if (!st67w6_at_cmd("AT+GET_CLOCK\r\n", 14)) return false;
|
||||||
|
MG_DEBUG(("%.*s", s_at_resp_len, at_resp)); // TODO(scaprile): --> VERBOSE
|
||||||
|
// BT-ENABLED DEPENDENCY
|
||||||
|
|
||||||
|
// MODULE DEPENDENCY
|
||||||
|
if (!st67w6_at_cmd("AT+EFUSE-R=24,\"0x100\"\r\n", 23) ||
|
||||||
|
!mg_match(mg_str_n((char *) at_resp, s_at_resp_len), mg_str_n("*,*", 3),
|
||||||
|
data))
|
||||||
|
return false;
|
||||||
|
if (data[1].buf[0] == 'C' && data[1].buf[1] == '6') is_b = true;
|
||||||
|
MG_DEBUG(("WLAN module is %sB type", is_b ? "" : "not")); // --> VERBOSE
|
||||||
|
if (is_b) {
|
||||||
|
// Disable the antenna diversity pin
|
||||||
|
if (!st67w6_at_cmd("AT+IORST=0\r\n", 12)) return false;
|
||||||
|
// Apparently they intend to disable some antenna ...
|
||||||
|
if (!st67w6_at_cmd("AT+CWANTENABLE?\r\n", 17)) return false;
|
||||||
|
MG_DEBUG(("%.*s", s_at_resp_len, at_resp)); // --> VERBOSE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not set wake-up pin (AT+SLWKIO)
|
||||||
|
// Disable power save mode
|
||||||
|
// NOTE(scaprile): (no response if in hibernate mode, though I guess we
|
||||||
|
// wouldn't have reached this point in that case either)
|
||||||
|
if (!st67w6_at_cmd("AT+PWR=0\r\n", 12)) return false;
|
||||||
|
// set Wi-Fi
|
||||||
|
// set country code
|
||||||
|
if (!st67w6_at_cmd("AT+CWCOUNTRY=0,\"00\"\r\n", 21)) return false;
|
||||||
|
#if 0
|
||||||
|
// set DTIM
|
||||||
|
if (!st67w6_at_cmd("AT+SLWKDTIM=1\r\n", 15)) return false;
|
||||||
|
#endif
|
||||||
|
// Read only default MAC, ignore set bit count (data[6] & 0x3F). Custom MACs
|
||||||
|
// reside at @0x64 and 0x70
|
||||||
|
if (st67w6_at_cmd("AT+EFUSE-R=7,\"0x014\"\r\n", 22) &&
|
||||||
|
mg_match(mg_str_n((char *) at_resp, s_at_resp_len), mg_str_n("*,*", 3),
|
||||||
|
data)) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 6; i++) mac[i] = data[1].buf[5 - i];
|
||||||
|
MG_DEBUG(("MAC: %M", mg_print_mac, mac));
|
||||||
|
} else {
|
||||||
|
MG_ERROR(("read MAC failed"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void st67w6_update_hash_table(void) {
|
||||||
|
// TODO(): read database, rebuild hash table
|
||||||
|
// uint32_t val = 0;
|
||||||
|
// val = 1;
|
||||||
|
// st67w6_at_iovar_set2_(0, "mcast_list", (uint8_t *) &val, sizeof(val),
|
||||||
|
// (uint8_t *) mcast_addr, sizeof(mcast_addr)); mg_delayms(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPI specifics
|
||||||
|
|
||||||
|
#define ST67W6_SPI_MAGIC 0x55AA
|
||||||
|
// #define ST67W6_SPI_VERSION(x), IS_STALL, FLAGS(x), ...
|
||||||
|
|
||||||
|
static const uint8_t idlehdr[sizeof(struct spi_hdr)] = {0xaa, 0x55, 0, 0,
|
||||||
|
0, 0, 0, 0};
|
||||||
|
|
||||||
|
static void st67w6_write(unsigned int f, void *data, uint16_t len) {
|
||||||
|
struct spi_hdr *h = (struct spi_hdr *) txdata;
|
||||||
|
h->magic = ST67W6_SPI_MAGIC;
|
||||||
|
h->type = (uint8_t) f;
|
||||||
|
h->vflags = 0;
|
||||||
|
h->len = len;
|
||||||
|
h->reserved = 0;
|
||||||
|
memmove(h + 1, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t st67w6_spi_poll(uint8_t *write, uint8_t *read) {
|
||||||
|
struct mg_tcpip_driver_st67w6_data *d =
|
||||||
|
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
|
||||||
|
struct spi_hdr *th, *rh = (struct spi_hdr *) read;
|
||||||
|
struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->spi;
|
||||||
|
size_t padded;
|
||||||
|
unsigned int times;
|
||||||
|
|
||||||
|
th = (write != NULL) ? (struct spi_hdr *) write : (struct spi_hdr *) idlehdr;
|
||||||
|
s->begin(s->spi);
|
||||||
|
times = 50;
|
||||||
|
while (times--) {
|
||||||
|
if (d->is_ready()) break;
|
||||||
|
if (times == 0) {
|
||||||
|
MG_ERROR(("RDY TIMEOUT"));
|
||||||
|
s->end(s->spi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
mg_delayms(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
padded = (th->len + 3) & ~3;
|
||||||
|
s->txn(s->spi, (uint8_t *) th, (uint8_t *) rh, sizeof(*th) + padded);
|
||||||
|
if (rh->magic == ST67W6_SPI_MAGIC && rh->len > padded) {
|
||||||
|
size_t remaining_padded = (rh->len - padded + 3) & ~3;
|
||||||
|
if (remaining_padded > (2048 - sizeof(*rh) - padded))
|
||||||
|
remaining_padded = 2048 - sizeof(*rh) - padded;
|
||||||
|
s->txn(s->spi, NULL, read + sizeof(*rh) + padded, remaining_padded);
|
||||||
|
}
|
||||||
|
times = 50;
|
||||||
|
while (times--) {
|
||||||
|
if (!d->is_ready()) break;
|
||||||
|
if (times == 0) {
|
||||||
|
MG_ERROR(("!RDY TIMEOUT"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mg_delayms(1);
|
||||||
|
}
|
||||||
|
s->end(s->spi);
|
||||||
|
return (size_t) rh->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool st67w6_spi_init(void) {
|
||||||
|
struct mg_tcpip_driver_st67w6_data *d =
|
||||||
|
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
|
||||||
|
size_t len;
|
||||||
|
unsigned int times = 1000;
|
||||||
|
while (times--) {
|
||||||
|
if (d->is_ready()) break;
|
||||||
|
if (times == 0) return false;
|
||||||
|
mg_delayms(1);
|
||||||
|
}
|
||||||
|
if (((len = st67w6_spi_poll(NULL, (uint8_t *) rxdata)) == 0) ||
|
||||||
|
!mg_match(mg_str_n(((char *) rxdata) + sizeof(struct spi_hdr), len),
|
||||||
|
mg_str_n("*ready*", 7), NULL))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mongoose Wi-Fi API functions
|
||||||
|
|
||||||
|
bool mg_wifi_scan(void) {
|
||||||
|
return st67w6_wifi_scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
|
||||||
|
s_ifp->ip = s_ip;
|
||||||
|
s_ifp->mask = s_mask;
|
||||||
|
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
|
||||||
|
s_ifp->enable_dhcp_server = false;
|
||||||
|
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
|
||||||
|
return st67w6_wifi_connect(wifi->ssid, wifi->pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_wifi_disconnect(void) {
|
||||||
|
return st67w6_wifi_disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
|
||||||
|
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
|
||||||
|
return st67w6_wifi_ap_start(wifi->apssid, wifi->appass, wifi->apchannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_wifi_ap_stop(void) {
|
||||||
|
return st67w6_wifi_ap_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_ST67W6) && \
|
||||||
|
MG_ENABLE_DRIVER_ST67W6
|
||||||
|
|
||||||
|
struct mg_tcpip_spi_ {
|
||||||
|
void *spi; // Opaque SPI bus descriptor
|
||||||
|
void (*begin)(void *); // SPI begin: slave select low
|
||||||
|
void (*end)(void *); // SPI end: slave select high
|
||||||
|
void (*txn)(void *, uint8_t *, uint8_t *,
|
||||||
|
size_t len); // SPI transaction: write-read len bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mg_tcpip_driver_st67w6_data {
|
||||||
|
struct mg_wifi_data wifi;
|
||||||
|
void *spi;
|
||||||
|
bool (*is_ready)(void); // return state of module RDY pin
|
||||||
|
struct mg_queue send_queue; // decouple tx calls from module polls
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
|
do { \
|
||||||
|
static struct mg_tcpip_driver_st67w6_data driver_data_; \
|
||||||
|
static struct mg_tcpip_if mif_; \
|
||||||
|
MG_SET_WIFI_CONFIG(&driver_data_); \
|
||||||
|
mif_.ip = MG_TCPIP_IP; \
|
||||||
|
mif_.mask = MG_TCPIP_MASK; \
|
||||||
|
mif_.gw = MG_TCPIP_GW; \
|
||||||
|
mif_.driver = &mg_tcpip_driver_st67w6; \
|
||||||
|
mif_.driver_data = &driver_data_; \
|
||||||
|
mif_.recv_queue.size = 8192; \
|
||||||
|
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
|
||||||
|
mg_tcpip_init(mgr, &mif_); \
|
||||||
|
MG_INFO(("Driver: st67w6, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -22,10 +22,10 @@ struct stm32f_eth {
|
|||||||
#define ETH_DESC_CNT 4 // Descriptors count
|
#define ETH_DESC_CNT 4 // Descriptors count
|
||||||
#define ETH_DS 4 // Descriptor size (words)
|
#define ETH_DS 4 // Descriptor size (words)
|
||||||
|
|
||||||
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
|
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM; // RX descriptors
|
||||||
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
|
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM; // TX descriptors
|
||||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
|
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM; // RX ethernet buffers
|
||||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
|
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM; // TX ethernet buffers
|
||||||
static uint8_t s_txno; // Current TX descriptor
|
static uint8_t s_txno; // Current TX descriptor
|
||||||
static uint8_t s_rxno; // Current RX descriptor
|
static uint8_t s_rxno; // Current RX descriptor
|
||||||
|
|
||||||
|
|||||||
+123
-23
@@ -1,9 +1,28 @@
|
|||||||
#include "net_builtin.h"
|
#include "net_builtin.h"
|
||||||
|
|
||||||
#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN)
|
#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \
|
||||||
|
MG_ENABLE_DRIVER_STM32N)
|
||||||
// STM32H: vendor modded single-queue Synopsys v4.2
|
// STM32H: vendor modded single-queue Synopsys v4.2
|
||||||
|
// STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI
|
||||||
// MCXNx4x: dual-queue Synopsys v5.2 with no hash table option
|
// MCXNx4x: dual-queue Synopsys v5.2 with no hash table option
|
||||||
// RT1170 ENET_QOS: quad-queue Synopsys v5.1
|
// RT1170: ENET_QOS: quad-queue Synopsys v5.1
|
||||||
|
#if MG_ENABLE_DRIVER_STM32H
|
||||||
|
#define SYNOPSYS_ENET_V5 0
|
||||||
|
#define SYNOPSYS_ENET_SINGLEQ 1
|
||||||
|
#define SYNOPSYS_ENET_NOHASHTABLE 0
|
||||||
|
#define SYNOPSYS_ENET_GbE 0
|
||||||
|
#elif MG_ENABLE_DRIVER_STM32N
|
||||||
|
#define SYNOPSYS_ENET_V5 1
|
||||||
|
#define SYNOPSYS_ENET_SINGLEQ 0
|
||||||
|
#define SYNOPSYS_ENET_NOHASHTABLE 1
|
||||||
|
#define SYNOPSYS_ENET_GbE 1
|
||||||
|
#elif MG_ENABLE_DRIVER_MCXN
|
||||||
|
#define SYNOPSYS_ENET_V5 1
|
||||||
|
#define SYNOPSYS_ENET_SINGLEQ 0
|
||||||
|
#define SYNOPSYS_ENET_NOHASHTABLE 1
|
||||||
|
#define SYNOPSYS_ENET_GbE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
struct synopsys_enet_qos {
|
struct synopsys_enet_qos {
|
||||||
volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
|
volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
|
||||||
RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
|
RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
|
||||||
@@ -36,9 +55,9 @@ struct synopsys_enet_qos {
|
|||||||
};
|
};
|
||||||
#undef ETH
|
#undef ETH
|
||||||
#if MG_ENABLE_DRIVER_STM32H
|
#if MG_ENABLE_DRIVER_STM32H
|
||||||
#define ETH \
|
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40028000UL)
|
||||||
((struct synopsys_enet_qos *) (uintptr_t) (0x40000000UL + 0x00020000UL + \
|
#elif MG_ENABLE_DRIVER_STM32N
|
||||||
0x8000UL))
|
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x48036000UL)
|
||||||
#elif MG_ENABLE_DRIVER_MCXN
|
#elif MG_ENABLE_DRIVER_MCXN
|
||||||
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL)
|
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL)
|
||||||
#endif
|
#endif
|
||||||
@@ -47,11 +66,74 @@ struct synopsys_enet_qos {
|
|||||||
#define ETH_DESC_CNT 4 // Descriptors count
|
#define ETH_DESC_CNT 4 // Descriptors count
|
||||||
#define ETH_DS 4 // Descriptor size (words)
|
#define ETH_DS 4 // Descriptor size (words)
|
||||||
|
|
||||||
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
|
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_STM32N
|
||||||
static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
|
#define CACHE_LINESZ 32 // must be a whole number of (d)words (see DESC_SZW)
|
||||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
|
#ifndef SCB
|
||||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
|
struct m7_scb {
|
||||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
volatile uint32_t CPUID, RESERVED1[4], CCR, RESERVED2[145], DCIMVAC, DCISW,
|
||||||
|
DCCMVAU, DCCMVAC, DCCSW, DCCIMVAC, DCCISW, RESERVED3[10], CACR,
|
||||||
|
RESERVED4[3];
|
||||||
|
};
|
||||||
|
#define SCB ((struct m7_scb *) (uintptr_t) 0xE000ED00UL)
|
||||||
|
#endif
|
||||||
|
// ending ISB is not needed because we don't cache instructions in data space
|
||||||
|
static inline void MG_CACHE_INVAL(uint8_t *addr, int32_t len) {
|
||||||
|
#if MG_ENABLE_DRIVER_STM32H
|
||||||
|
if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7
|
||||||
|
#endif
|
||||||
|
if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled
|
||||||
|
MG_DSB();
|
||||||
|
while (len > 0) {
|
||||||
|
SCB->DCIMVAC = (uint32_t) addr;
|
||||||
|
addr += CACHE_LINESZ;
|
||||||
|
len -= CACHE_LINESZ;
|
||||||
|
}
|
||||||
|
MG_DSB();
|
||||||
|
}
|
||||||
|
static inline void MG_CACHE_FLUSH(uint8_t *addr, int32_t len) {
|
||||||
|
#if MG_ENABLE_DRIVER_STM32H
|
||||||
|
if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7
|
||||||
|
#endif
|
||||||
|
if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled
|
||||||
|
MG_DSB();
|
||||||
|
while (len > 0) {
|
||||||
|
SCB->DCCMVAC = (uint32_t) addr;
|
||||||
|
addr += CACHE_LINESZ;
|
||||||
|
len -= CACHE_LINESZ;
|
||||||
|
}
|
||||||
|
MG_DSB();
|
||||||
|
}
|
||||||
|
#define ETH_RAM_ALIGNED MG_32BYTE_ALIGNED // depends on CACHE_LINESZ and ETH
|
||||||
|
#define CACHE_ALIGN(x) \
|
||||||
|
((((size_t) (x)) + CACHE_LINESZ - 1) & ~(CACHE_LINESZ - 1))
|
||||||
|
#define DESC_SZ CACHE_ALIGN(4 * ETH_DS) // grow descriptors to fit a line
|
||||||
|
#define DESC_SZW (DESC_SZ / 4)
|
||||||
|
#define BUFF_SZ CACHE_ALIGN(ETH_PKT_SIZE) // grow buffers to fit n lines
|
||||||
|
#if MG_ENABLE_DRIVER_STM32H
|
||||||
|
#define DESC_SKIPW (DESC_SZW - ETH_DS) // tell DMA the descriptor size, words
|
||||||
|
#else
|
||||||
|
// MG_ENABLE_DRIVER_STM32N, DMA is AXI and specs skip in 64-bit double-words
|
||||||
|
#define DESC_SKIPW ((DESC_SZW - ETH_DS) / 2)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define MG_CACHE_FLUSH(a, b)
|
||||||
|
#define MG_CACHE_INVAL(a, b)
|
||||||
|
#define ETH_RAM_ALIGNED MG_8BYTE_ALIGNED // depends on ETH DMA alone
|
||||||
|
#define DESC_SZ 0
|
||||||
|
#define DESC_SZW ETH_DS
|
||||||
|
#define BUFF_SZ ETH_PKT_SIZE
|
||||||
|
#define DESC_SKIPW 0 // no need to skip, as we're not aligning to cache lines
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// array[rows][cols] = coldata coldata ... for all rows, keeps alignment
|
||||||
|
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM
|
||||||
|
ETH_RAM_ALIGNED;
|
||||||
|
static volatile uint32_t s_txdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM
|
||||||
|
ETH_RAM_ALIGNED;
|
||||||
|
static uint8_t s_rxbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED;
|
||||||
|
static uint8_t s_txbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED;
|
||||||
|
|
||||||
|
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||||
|
|
||||||
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||||
ETH->MACMDIOAR &= (0xF << 8);
|
ETH->MACMDIOAR &= (0xF << 8);
|
||||||
@@ -77,15 +159,19 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
|||||||
uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf;
|
uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf;
|
||||||
|
|
||||||
// Init RX descriptors
|
// Init RX descriptors
|
||||||
|
memset((char *) s_rxdesc, 0, sizeof(s_rxdesc)); // manual init
|
||||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
||||||
s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
|
s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
|
||||||
s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
|
s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
|
||||||
}
|
}
|
||||||
|
MG_CACHE_FLUSH((uint8_t *) s_rxdesc, sizeof(s_rxdesc));
|
||||||
|
|
||||||
// Init TX descriptors
|
// Init TX descriptors
|
||||||
|
memset((char *) s_txdesc, 0, sizeof(s_txdesc)); // manual init
|
||||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
||||||
s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
|
s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
|
||||||
}
|
}
|
||||||
|
MG_CACHE_FLUSH((uint8_t *) s_txdesc, sizeof(s_txdesc));
|
||||||
|
|
||||||
ETH->DMAMR |= MG_BIT(0); // Software reset
|
ETH->DMAMR |= MG_BIT(0); // Software reset
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
@@ -102,7 +188,7 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
|||||||
ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed
|
ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed
|
||||||
ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
|
ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
|
||||||
ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause
|
ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause
|
||||||
#if !MG_ENABLE_DRIVER_MCXN
|
#if !SYNOPSYS_ENET_V5
|
||||||
ETH->MACPFR = MG_BIT(10); // Perfect filtering
|
ETH->MACPFR = MG_BIT(10); // Perfect filtering
|
||||||
#endif
|
#endif
|
||||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||||
@@ -118,15 +204,15 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
|||||||
ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
|
ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
|
||||||
ETH->DMACTDTPR =
|
ETH->DMACTDTPR =
|
||||||
(uint32_t) (uintptr_t) s_txdesc; // first available descriptor address
|
(uint32_t) (uintptr_t) s_txdesc; // first available descriptor address
|
||||||
ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value)
|
ETH->DMACCR = DESC_SKIPW << 18; // DSL (contiguous/sparse descriptor table)
|
||||||
#if !MG_ENABLE_DRIVER_STM32H
|
#if SYNOPSYS_ENET_V5
|
||||||
MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16));
|
MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16));
|
||||||
MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16));
|
MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16));
|
||||||
#endif
|
#endif
|
||||||
ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE
|
ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE
|
||||||
ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) |
|
ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) |
|
||||||
MG_BIT(15); // RE, TE, Duplex, Fast, Reserved
|
MG_BIT(15); // RE, TE, Duplex, Fast, (10/100)/Reserved
|
||||||
#if MG_ENABLE_DRIVER_STM32H
|
#if SYNOPSYS_ENET_SINGLEQ
|
||||||
ETH->MTLTQOMR |= MG_BIT(1); // TSF
|
ETH->MTLTQOMR |= MG_BIT(1); // TSF
|
||||||
ETH->MTLRQOMR |= MG_BIT(5); // RSF
|
ETH->MTLRQOMR |= MG_BIT(5); // RSF
|
||||||
#else
|
#else
|
||||||
@@ -150,18 +236,23 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
|
|||||||
struct mg_tcpip_if *ifp) {
|
struct mg_tcpip_if *ifp) {
|
||||||
if (len > sizeof(s_txbuf[s_txno])) {
|
if (len > sizeof(s_txbuf[s_txno])) {
|
||||||
MG_ERROR(("Frame too big, %ld", (long) len));
|
MG_ERROR(("Frame too big, %ld", (long) len));
|
||||||
len = 0; // Frame is too big
|
return 0; // Frame is too big
|
||||||
} else if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
|
}
|
||||||
|
MG_CACHE_INVAL((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
|
||||||
|
if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
|
||||||
ifp->nerr++;
|
ifp->nerr++;
|
||||||
MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
|
MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
|
||||||
s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR));
|
s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR));
|
||||||
|
MG_CACHE_INVAL((uint8_t *) s_txdesc, sizeof(s_txdesc));
|
||||||
for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
|
for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
|
||||||
len = 0; // All descriptors are busy, fail
|
len = 0; // All descriptors are busy, fail
|
||||||
} else {
|
} else {
|
||||||
memcpy(s_txbuf[s_txno], buf, len); // Copy data
|
memcpy(s_txbuf[s_txno], buf, len); // Copy data
|
||||||
|
MG_CACHE_FLUSH((uint8_t *) &s_txbuf[s_txno], BUFF_SZ);
|
||||||
s_txdesc[s_txno][2] = (uint32_t) len; // Set data len
|
s_txdesc[s_txno][2] = (uint32_t) len; // Set data len
|
||||||
s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD
|
s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD
|
||||||
s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over
|
s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over
|
||||||
|
MG_CACHE_FLUSH((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
|
||||||
if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
|
if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
|
||||||
}
|
}
|
||||||
ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS
|
ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS
|
||||||
@@ -171,7 +262,7 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) {
|
static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) {
|
||||||
#if MG_ENABLE_DRIVER_MCXN
|
#if SYNOPSYS_ENET_NOHASHTABLE
|
||||||
ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames)
|
ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames)
|
||||||
#else
|
#else
|
||||||
// TODO(): read database, rebuild hash table
|
// TODO(): read database, rebuild hash table
|
||||||
@@ -182,7 +273,7 @@ static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) {
|
|||||||
ETH->MACA1HR = (uint32_t) mcast_addr[5] << 8 | (uint32_t) mcast_addr[4];
|
ETH->MACA1HR = (uint32_t) mcast_addr[5] << 8 | (uint32_t) mcast_addr[4];
|
||||||
ETH->MACA1HR |= MG_BIT(31); // AE
|
ETH->MACA1HR |= MG_BIT(31); // AE
|
||||||
#endif
|
#endif
|
||||||
(void) ifp;
|
(void) ifp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) {
|
static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||||
@@ -203,8 +294,11 @@ static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) {
|
|||||||
// if(link is slow or half) set flags otherwise
|
// if(link is slow or half) set flags otherwise
|
||||||
// reg = tmp
|
// reg = tmp
|
||||||
uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex
|
uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex
|
||||||
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
|
#if SYNOPSYS_ENET_GbE
|
||||||
if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex
|
if (speed == MG_PHY_SPEED_1000M) maccr &= ~MG_BIT(15); // 1000M
|
||||||
|
#endif
|
||||||
|
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
|
||||||
|
if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex
|
||||||
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
|
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
|
||||||
MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10,
|
MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10,
|
||||||
maccr & MG_BIT(13) ? "full" : "half"));
|
maccr & MG_BIT(13) ? "full" : "half"));
|
||||||
@@ -216,13 +310,17 @@ static uint32_t s_rxno;
|
|||||||
#if MG_ENABLE_DRIVER_MCXN
|
#if MG_ENABLE_DRIVER_MCXN
|
||||||
void ETHERNET_IRQHandler(void);
|
void ETHERNET_IRQHandler(void);
|
||||||
void ETHERNET_IRQHandler(void) {
|
void ETHERNET_IRQHandler(void) {
|
||||||
#else
|
#elif MG_ENABLE_DRIVER_STM32H
|
||||||
void ETH_IRQHandler(void);
|
void ETH_IRQHandler(void);
|
||||||
void ETH_IRQHandler(void) {
|
void ETH_IRQHandler(void) {
|
||||||
|
#else
|
||||||
|
void ETH1_IRQHandler(void);
|
||||||
|
void ETH1_IRQHandler(void) {
|
||||||
#endif
|
#endif
|
||||||
if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop
|
if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop
|
||||||
ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag
|
ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag
|
||||||
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
|
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
|
||||||
|
MG_CACHE_INVAL((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ);
|
||||||
if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done
|
if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done
|
||||||
if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) ==
|
if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) ==
|
||||||
(MG_BIT(28) | MG_BIT(29))) &&
|
(MG_BIT(28) | MG_BIT(29))) &&
|
||||||
@@ -230,10 +328,12 @@ void ETH_IRQHandler(void) {
|
|||||||
uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1);
|
uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1);
|
||||||
// MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
|
// MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
|
||||||
// ETH->DMACSR));
|
// ETH->DMACSR));
|
||||||
|
MG_CACHE_INVAL((uint8_t *) &s_rxbuf[s_rxno], BUFF_SZ);
|
||||||
mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
|
mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
|
||||||
}
|
}
|
||||||
s_rxdesc[s_rxno][3] =
|
s_rxdesc[s_rxno][3] =
|
||||||
MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
|
MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
|
||||||
|
MG_CACHE_FLUSH((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ);
|
||||||
if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
|
if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-1
@@ -7,7 +7,10 @@
|
|||||||
#if !defined(MG_ENABLE_DRIVER_MCXN)
|
#if !defined(MG_ENABLE_DRIVER_MCXN)
|
||||||
#define MG_ENABLE_DRIVER_MCXN 0
|
#define MG_ENABLE_DRIVER_MCXN 0
|
||||||
#endif
|
#endif
|
||||||
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN
|
#if !defined(MG_ENABLE_DRIVER_STM32N)
|
||||||
|
#define MG_ENABLE_DRIVER_STM32N 0
|
||||||
|
#endif
|
||||||
|
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || MG_ENABLE_DRIVER_STM32N
|
||||||
|
|
||||||
struct mg_tcpip_driver_stm32h_data {
|
struct mg_tcpip_driver_stm32h_data {
|
||||||
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
|
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
|
||||||
@@ -46,6 +49,18 @@ struct mg_tcpip_driver_stm32h_data {
|
|||||||
#define MG_ENABLE_ETH_IRQ()
|
#define MG_ENABLE_ETH_IRQ()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
#define MG_IPV6_INIT(mif) \
|
||||||
|
do { \
|
||||||
|
memcpy(mif.ip6ll, (uint8_t[16]) MG_TCPIP_IPV6_LINKLOCAL, 16); \
|
||||||
|
memcpy(mif.ip6, (uint8_t[16]) MG_TCPIP_GLOBAL, 16); \
|
||||||
|
memcpy(mif.gw6, (uint8_t[16]) MG_TCPIP_GW6, 16); \
|
||||||
|
mif.prefix_len = MG_TCPIP_PREFIX_LEN; \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define MG_IPV6_INIT(mif)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||||
do { \
|
do { \
|
||||||
static struct mg_tcpip_driver_stm32h_data driver_data_; \
|
static struct mg_tcpip_driver_stm32h_data driver_data_; \
|
||||||
@@ -59,6 +74,7 @@ struct mg_tcpip_driver_stm32h_data {
|
|||||||
mif_.driver = &mg_tcpip_driver_stm32h; \
|
mif_.driver = &mg_tcpip_driver_stm32h; \
|
||||||
mif_.driver_data = &driver_data_; \
|
mif_.driver_data = &driver_data_; \
|
||||||
MG_SET_MAC_ADDRESS(mif_.mac); \
|
MG_SET_MAC_ADDRESS(mif_.mac); \
|
||||||
|
MG_IPV6_INIT(mif_); \
|
||||||
mg_tcpip_init(mgr, &mif_); \
|
mg_tcpip_init(mgr, &mif_); \
|
||||||
MG_ENABLE_ETH_IRQ(); \
|
MG_ENABLE_ETH_IRQ(); \
|
||||||
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
|
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||||
|
|||||||
+7
-6
@@ -111,11 +111,11 @@ static int guess_mdc_cr(void) {
|
|||||||
uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values
|
uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values
|
||||||
uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers
|
uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers
|
||||||
uint32_t sysclk = get_sysclk(); // Guess system SYSCLK
|
uint32_t sysclk = get_sysclk(); // Guess system SYSCLK
|
||||||
int result = -1; // Invalid CR value
|
int i, result = -1; // Invalid CR value
|
||||||
if (sysclk < 25000000) {
|
if (sysclk < 25000000) {
|
||||||
MG_ERROR(("SYSCLK too low"));
|
MG_ERROR(("SYSCLK too low"));
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
|
if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
|
||||||
result = crs[i];
|
result = crs[i];
|
||||||
break;
|
break;
|
||||||
@@ -130,10 +130,11 @@ static int guess_mdc_cr(void) {
|
|||||||
static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) {
|
static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) {
|
||||||
struct mg_tcpip_driver_tm4c_data *d =
|
struct mg_tcpip_driver_tm4c_data *d =
|
||||||
(struct mg_tcpip_driver_tm4c_data *) ifp->driver_data;
|
(struct mg_tcpip_driver_tm4c_data *) ifp->driver_data;
|
||||||
|
int i;
|
||||||
s_ifp = ifp;
|
s_ifp = ifp;
|
||||||
|
|
||||||
// Init RX descriptors
|
// Init RX descriptors
|
||||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
for (i = 0; i < ETH_DESC_CNT; i++) {
|
||||||
s_rxdesc[i][0] = MG_BIT(31); // Own
|
s_rxdesc[i][0] = MG_BIT(31); // Own
|
||||||
s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained
|
s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained
|
||||||
s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
|
s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
|
||||||
@@ -143,7 +144,7 @@ static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init TX descriptors
|
// Init TX descriptors
|
||||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
for (i = 0; i < ETH_DESC_CNT; i++) {
|
||||||
s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
|
s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
|
||||||
s_txdesc[i][3] =
|
s_txdesc[i][3] =
|
||||||
(uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
|
(uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
|
||||||
@@ -204,7 +205,6 @@ static size_t mg_tcpip_driver_tm4c_tx(const void *buf, size_t len,
|
|||||||
EMAC->EMACDMARIS = MG_BIT(2) | MG_BIT(5); // Clear any prior TU/UNF
|
EMAC->EMACDMARIS = MG_BIT(2) | MG_BIT(5); // Clear any prior TU/UNF
|
||||||
EMAC->EMACTXPOLLD = 0; // and resume
|
EMAC->EMACTXPOLLD = 0; // and resume
|
||||||
return len;
|
return len;
|
||||||
(void) ifp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mg_tcpip_driver_tm4c_update_hash_table(struct mg_tcpip_if *ifp) {
|
static void mg_tcpip_driver_tm4c_update_hash_table(struct mg_tcpip_if *ifp) {
|
||||||
@@ -245,9 +245,10 @@ static bool mg_tcpip_driver_tm4c_poll(struct mg_tcpip_if *ifp, bool s1) {
|
|||||||
void EMAC0_IRQHandler(void);
|
void EMAC0_IRQHandler(void);
|
||||||
static uint32_t s_rxno;
|
static uint32_t s_rxno;
|
||||||
void EMAC0_IRQHandler(void) {
|
void EMAC0_IRQHandler(void) {
|
||||||
|
int i;
|
||||||
if (EMAC->EMACDMARIS & MG_BIT(6)) { // Frame received, loop
|
if (EMAC->EMACDMARIS & MG_BIT(6)) { // Frame received, loop
|
||||||
EMAC->EMACDMARIS = MG_BIT(16) | MG_BIT(6); // Clear flag
|
EMAC->EMACDMARIS = MG_BIT(16) | MG_BIT(6); // Clear flag
|
||||||
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
|
for (i = 0; i < 10; i++) { // read as they arrive but not forever
|
||||||
if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done
|
if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done
|
||||||
if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) ==
|
if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) ==
|
||||||
(MG_BIT(8) | MG_BIT(9))) &&
|
(MG_BIT(8) | MG_BIT(9))) &&
|
||||||
|
|||||||
+4
-10
@@ -35,18 +35,12 @@ struct ETH_GLOBAL_TypeDef {
|
|||||||
#define ETH_DESC_CNT 4 // Descriptors count
|
#define ETH_DESC_CNT 4 // Descriptors count
|
||||||
#define ETH_DS 4 // Descriptor size (words)
|
#define ETH_DS 4 // Descriptor size (words)
|
||||||
|
|
||||||
#ifndef ETH_RAM_SECTION
|
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
|
||||||
// if no section is specified, then the data will be placed in the default
|
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
|
||||||
// bss section
|
|
||||||
#define ETH_RAM_SECTION
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] ETH_RAM_SECTION;
|
|
||||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] ETH_RAM_SECTION;
|
|
||||||
static uint32_t s_rxdesc[ETH_DESC_CNT]
|
static uint32_t s_rxdesc[ETH_DESC_CNT]
|
||||||
[ETH_DS] ETH_RAM_SECTION; // RX descriptors
|
[ETH_DS] MG_ETH_RAM; // RX descriptors
|
||||||
static uint32_t s_txdesc[ETH_DESC_CNT]
|
static uint32_t s_txdesc[ETH_DESC_CNT]
|
||||||
[ETH_DS] ETH_RAM_SECTION; // TX descriptors
|
[ETH_DS] MG_ETH_RAM; // TX descriptors
|
||||||
static uint8_t s_txno; // Current TX descriptor
|
static uint8_t s_txno; // Current TX descriptor
|
||||||
static uint8_t s_rxno; // Current RX descriptor
|
static uint8_t s_rxno; // Current RX descriptor
|
||||||
|
|
||||||
|
|||||||
+6
-9
@@ -59,15 +59,12 @@ struct ETH_Type {
|
|||||||
#define ETH_DESC_CNT 4 // Descriptors count
|
#define ETH_DESC_CNT 4 // Descriptors count
|
||||||
#define ETH_DS 2 // Descriptor size (words)
|
#define ETH_DS 2 // Descriptor size (words)
|
||||||
|
|
||||||
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
|
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
|
||||||
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U))))
|
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
|
||||||
|
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE];
|
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE];
|
static uint8_t s_txno; // Current TX descriptor
|
||||||
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
|
static uint8_t s_rxno; // Current RX descriptor
|
||||||
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
|
|
||||||
static uint8_t s_txno MG_8BYTE_ALIGNED; // Current TX descriptor
|
|
||||||
static uint8_t s_rxno MG_8BYTE_ALIGNED; // Current RX descriptor
|
|
||||||
|
|
||||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||||
enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 };
|
enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 };
|
||||||
|
|||||||
@@ -27,5 +27,7 @@ enum {
|
|||||||
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
||||||
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
|
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
|
||||||
MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data
|
MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data
|
||||||
|
MG_EV_MDNS_REQ, // mDNS request struct mg_mdns_req *
|
||||||
|
MG_EV_MDNS_RESP, // mDNS response struct mg_mdns_resp *
|
||||||
MG_EV_USER // Starting ID for user events
|
MG_EV_USER // Starting ID for user events
|
||||||
};
|
};
|
||||||
@@ -22,7 +22,8 @@ static int xisinf(double x) {
|
|||||||
union {
|
union {
|
||||||
double f;
|
double f;
|
||||||
uint64_t u;
|
uint64_t u;
|
||||||
} ieee754 = {x};
|
} ieee754;
|
||||||
|
ieee754.f = x;
|
||||||
return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
|
return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
|
||||||
((unsigned) ieee754.u == 0);
|
((unsigned) ieee754.u == 0);
|
||||||
}
|
}
|
||||||
@@ -31,7 +32,8 @@ static int xisnan(double x) {
|
|||||||
union {
|
union {
|
||||||
double f;
|
double f;
|
||||||
uint64_t u;
|
uint64_t u;
|
||||||
} ieee754 = {x};
|
} ieee754;
|
||||||
|
ieee754.f = x;
|
||||||
return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) +
|
return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) +
|
||||||
((unsigned) ieee754.u != 0) >
|
((unsigned) ieee754.u != 0) >
|
||||||
0x7ff00000;
|
0x7ff00000;
|
||||||
@@ -99,7 +101,7 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes
|
while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes
|
||||||
if (tz && n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
|
if (tz && n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
|
||||||
n += s;
|
n += s;
|
||||||
if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
|
if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
@@ -129,7 +131,7 @@ static size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size_t scpy(void (*out)(char, void *), void *ptr, char *buf,
|
static size_t scpy(void (*out)(char, void *), void *ptr, char *buf,
|
||||||
size_t len) {
|
size_t len) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < len && buf[i] != '\0') out(buf[i++], ptr);
|
while (i < len && buf[i] != '\0') out(buf[i++], ptr);
|
||||||
return i;
|
return i;
|
||||||
|
|||||||
@@ -86,7 +86,8 @@ static void mg_fs_ls_fn(const char *filename, void *param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool mg_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len) {
|
bool mg_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len) {
|
||||||
struct mg_str s = {buf, len};
|
struct mg_str s;
|
||||||
|
s.buf = buf, s.len = len;
|
||||||
fs->ls(path, mg_fs_ls_fn, &s);
|
fs->ls(path, mg_fs_ls_fn, &s);
|
||||||
return buf[0] != '\0';
|
return buf[0] != '\0';
|
||||||
}
|
}
|
||||||
+29
-22
@@ -1,7 +1,7 @@
|
|||||||
|
#include "http.h"
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include "http.h"
|
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
@@ -237,6 +237,8 @@ static const char *skiptorn(const char *s, const char *end, struct mg_str *v) {
|
|||||||
static bool mg_http_parse_headers(const char *s, const char *end,
|
static bool mg_http_parse_headers(const char *s, const char *end,
|
||||||
struct mg_http_header *h, size_t max_hdrs) {
|
struct mg_http_header *h, size_t max_hdrs) {
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
|
int cl_count = 0, te_count = 0, auth_count = 0;
|
||||||
|
int conn_count = 0, cookie_count = 0;
|
||||||
for (i = 0; i < max_hdrs; i++) {
|
for (i = 0; i < max_hdrs; i++) {
|
||||||
struct mg_str k = {NULL, 0}, v = {NULL, 0};
|
struct mg_str k = {NULL, 0}, v = {NULL, 0};
|
||||||
if (s >= end) return false;
|
if (s >= end) return false;
|
||||||
@@ -252,6 +254,13 @@ static bool mg_http_parse_headers(const char *s, const char *end,
|
|||||||
while (v.len > 0 && (v.buf[v.len - 1] == ' ' || v.buf[v.len - 1] == '\t')) {
|
while (v.len > 0 && (v.buf[v.len - 1] == ' ' || v.buf[v.len - 1] == '\t')) {
|
||||||
v.len--; // Trim spaces
|
v.len--; // Trim spaces
|
||||||
}
|
}
|
||||||
|
// detect duplicated headers -> discard
|
||||||
|
if (((mg_strcasecmp(k, mg_str("Content-Length")) == 0) && (++cl_count > 1)) ||
|
||||||
|
((mg_strcasecmp(k, mg_str("Transfer-Encoding")) == 0) && (++te_count > 1)) ||
|
||||||
|
((mg_strcasecmp(k, mg_str("Authorization")) == 0) && (++auth_count > 1)) ||
|
||||||
|
((mg_strcasecmp(k, mg_str("Cookie")) == 0) && (++cookie_count > 1)) ||
|
||||||
|
((mg_strcasecmp(k, mg_str("Connection")) == 0) && (++conn_count > 1)))
|
||||||
|
return false;
|
||||||
// MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.buf, (int) v.len, v.buf));
|
// MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.buf, (int) v.len, v.buf));
|
||||||
h[i].name = k, h[i].value = v; // Success. Assign values
|
h[i].name = k, h[i].value = v; // Success. Assign values
|
||||||
}
|
}
|
||||||
@@ -286,6 +295,8 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
|||||||
// If we're given a version, check that it is HTTP/x.x
|
// If we're given a version, check that it is HTTP/x.x
|
||||||
version_prefix_valid =
|
version_prefix_valid =
|
||||||
hm->proto.len > 5 && (mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0);
|
hm->proto.len > 5 && (mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0);
|
||||||
|
if (!is_response && !version_prefix_valid)
|
||||||
|
return -1; // no version detected in request
|
||||||
if (!is_response && hm->proto.len > 0 &&
|
if (!is_response && hm->proto.len > 0 &&
|
||||||
(!version_prefix_valid || hm->proto.len != 8 ||
|
(!version_prefix_valid || hm->proto.len != 8 ||
|
||||||
(hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') ||
|
(hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') ||
|
||||||
@@ -317,17 +328,9 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
|||||||
// responses. If HTTP response does not have Content-Length set, then
|
// responses. If HTTP response does not have Content-Length set, then
|
||||||
// body is read until socket is closed, i.e. body.len is infinite (~0).
|
// body is read until socket is closed, i.e. body.len is infinite (~0).
|
||||||
//
|
//
|
||||||
// For HTTP requests though, according to
|
// For HTTP requests though, if Content-Length is not specified
|
||||||
// http://tools.ietf.org/html/rfc7231#section-8.1.3,
|
// set body length to 0.
|
||||||
// only POST and PUT methods have defined body semantics.
|
if (hm->body.len == (size_t) ~0 && !is_response) {
|
||||||
// Therefore, if Content-Length is not specified and methods are
|
|
||||||
// not one of PUT or POST, set body length to 0.
|
|
||||||
//
|
|
||||||
// So, if it is HTTP request, and Content-Length is not set,
|
|
||||||
// and method is not (PUT or POST) then reset body length to zero.
|
|
||||||
if (hm->body.len == (size_t) ~0 && !is_response &&
|
|
||||||
mg_strcasecmp(hm->method, mg_str("PUT")) != 0 &&
|
|
||||||
mg_strcasecmp(hm->method, mg_str("POST")) != 0) {
|
|
||||||
hm->body.len = 0;
|
hm->body.len = 0;
|
||||||
hm->message.len = (size_t) req_len;
|
hm->message.len = (size_t) req_len;
|
||||||
}
|
}
|
||||||
@@ -346,14 +349,14 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
|||||||
static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
|
static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
|
||||||
va_list *ap) {
|
va_list *ap) {
|
||||||
size_t len = c->send.len;
|
size_t len = c->send.len;
|
||||||
mg_send(c, " \r\n", 10);
|
if (!mg_send(c, " \r\n", 10)) mg_error(c, "OOM");
|
||||||
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
|
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
|
||||||
if (c->send.len >= len + 10) {
|
if (c->send.len >= len + 10) {
|
||||||
mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10);
|
mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10);
|
||||||
c->send.buf[len + 8] = '\r';
|
c->send.buf[len + 8] = '\r';
|
||||||
if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker
|
if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker
|
||||||
}
|
}
|
||||||
mg_send(c, "\r\n", 2);
|
if (!mg_send(c, "\r\n", 2)) mg_error(c, "OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
|
void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
|
||||||
@@ -365,8 +368,7 @@ void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
|
|||||||
|
|
||||||
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
|
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
|
||||||
mg_printf(c, "%lx\r\n", (unsigned long) len);
|
mg_printf(c, "%lx\r\n", (unsigned long) len);
|
||||||
mg_send(c, buf, len);
|
if (!mg_send(c, buf, len) || !mg_send(c, "\r\n", 2)) mg_error(c, "OOM");
|
||||||
mg_send(c, "\r\n", 2);
|
|
||||||
if (len == 0) c->is_resp = 0;
|
if (len == 0) c->is_resp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,10 +651,10 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
|
|||||||
status, mg_http_status_code_str(status), (int) mime.len, mime.buf,
|
status, mg_http_status_code_str(status), (int) mime.len, mime.buf,
|
||||||
etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
|
etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
|
||||||
range, opts->extra_headers ? opts->extra_headers : "");
|
range, opts->extra_headers ? opts->extra_headers : "");
|
||||||
if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0) {
|
if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0 || c->is_closing) {
|
||||||
c->is_resp = 0;
|
c->is_resp = 0;
|
||||||
mg_fs_close(fd);
|
mg_fs_close(fd);
|
||||||
} else {
|
} else { // start serving static content only if not closing, see #3354
|
||||||
// Track to-be-sent content length at the end of c->data, aligned
|
// Track to-be-sent content length at the end of c->data, aligned
|
||||||
size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
|
size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
|
||||||
sizeof(size_t) * sizeof(size_t)];
|
sizeof(size_t) * sizeof(size_t)];
|
||||||
@@ -1021,7 +1023,7 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
const char *buf = (char *) c->recv.buf + ofs;
|
const char *buf = (char *) c->recv.buf + ofs;
|
||||||
int n = mg_http_parse(buf, c->recv.len - ofs, &hm);
|
int n = mg_http_parse(buf, c->recv.len - ofs, &hm);
|
||||||
struct mg_str *te; // Transfer - encoding header
|
struct mg_str *te; // Transfer - encoding header
|
||||||
bool is_chunked = false;
|
bool is_chunked = false, is_http_1_0 = false;
|
||||||
size_t old_len = c->recv.len;
|
size_t old_len = c->recv.len;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
// We don't use mg_error() here, to avoid closing pipelined requests
|
// We don't use mg_error() here, to avoid closing pipelined requests
|
||||||
@@ -1044,7 +1046,11 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG
|
hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG
|
||||||
hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf);
|
hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf);
|
||||||
}
|
}
|
||||||
if ((te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
|
is_http_1_0 =
|
||||||
|
hm.proto.len > 8 && mg_ncasecmp(hm.proto.buf, "HTTP/1.0", 8) == 0;
|
||||||
|
// HTTP/1.0 does not use "Transfer-Encoding: chunked"
|
||||||
|
if (!is_http_1_0 &&
|
||||||
|
(te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
|
||||||
if (mg_strcasecmp(*te, mg_str("chunked")) == 0) {
|
if (mg_strcasecmp(*te, mg_str("chunked")) == 0) {
|
||||||
is_chunked = true;
|
is_chunked = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -1059,9 +1065,10 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
if (!is_response && (mg_strcasecmp(hm.method, mg_str("POST")) == 0 ||
|
if (!is_response && (mg_strcasecmp(hm.method, mg_str("POST")) == 0 ||
|
||||||
mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) {
|
mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) {
|
||||||
// POST and PUT should include an entity body. Therefore, they should
|
// POST and PUT should include an entity body. Therefore, they should
|
||||||
// contain a Content-length header. Other requests can also contain a
|
// contain a Content-length header (unless the body length is 0, in
|
||||||
|
// which case it can be omitted). Other requests can also contain a
|
||||||
// body, but their content has no defined semantics (RFC 7231)
|
// body, but their content has no defined semantics (RFC 7231)
|
||||||
require_content_len = true;
|
if (hm.body.len != 0) require_content_len = true;
|
||||||
ofs += (size_t) n; // this request has been processed
|
ofs += (size_t) n; // this request has been processed
|
||||||
} else if (is_response) {
|
} else if (is_response) {
|
||||||
// HTTP spec 7.2 Entity body: All other responses must include a body
|
// HTTP spec 7.2 Entity body: All other responses must include a body
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
|
|||||||
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
|
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
|
||||||
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
|
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
|
||||||
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
|
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
|
||||||
void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm);
|
|
||||||
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data);
|
mg_event_handler_t fn, void *fn_data);
|
||||||
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
||||||
|
|||||||
+6
-5
@@ -1,5 +1,5 @@
|
|||||||
#include "arch.h"
|
|
||||||
#include "iobuf.h"
|
#include "iobuf.h"
|
||||||
|
#include "arch.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@@ -7,8 +7,8 @@ static size_t roundup(size_t size, size_t align) {
|
|||||||
return align == 0 ? size : (size + align - 1) / align * align;
|
return align == 0 ? size : (size + align - 1) / align * align;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
|
bool mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
|
||||||
int ok = 1;
|
bool ok = true;
|
||||||
new_size = roundup(new_size, io->align);
|
new_size = roundup(new_size, io->align);
|
||||||
if (new_size == 0) {
|
if (new_size == 0) {
|
||||||
mg_bzero(io->buf, io->size);
|
mg_bzero(io->buf, io->size);
|
||||||
@@ -25,15 +25,16 @@ int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
|
|||||||
mg_free(io->buf);
|
mg_free(io->buf);
|
||||||
io->buf = (unsigned char *) p;
|
io->buf = (unsigned char *) p;
|
||||||
io->size = new_size;
|
io->size = new_size;
|
||||||
|
io->len = len;
|
||||||
} else {
|
} else {
|
||||||
ok = 0;
|
ok = false;
|
||||||
MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size));
|
MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
|
bool mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
|
||||||
io->buf = NULL;
|
io->buf = NULL;
|
||||||
io->align = align;
|
io->align = align;
|
||||||
io->size = io->len = 0;
|
io->size = io->len = 0;
|
||||||
|
|||||||
+2
-2
@@ -9,8 +9,8 @@ struct mg_iobuf {
|
|||||||
size_t align; // Alignment during allocation
|
size_t align; // Alignment during allocation
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
|
bool mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
|
||||||
int mg_iobuf_resize(struct mg_iobuf *, size_t);
|
bool mg_iobuf_resize(struct mg_iobuf *, size_t);
|
||||||
void mg_iobuf_free(struct mg_iobuf *);
|
void mg_iobuf_free(struct mg_iobuf *);
|
||||||
size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
|
size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
|
||||||
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
|
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
|
||||||
+17
-4
@@ -60,15 +60,28 @@ static double mg_atod(const char *p, int len, int *numlen) {
|
|||||||
|
|
||||||
// Exponential
|
// Exponential
|
||||||
if (i < len && (p[i] == 'e' || p[i] == 'E')) {
|
if (i < len && (p[i] == 'e' || p[i] == 'E')) {
|
||||||
int j, exp = 0, minus = 0;
|
int exp = 0, minus = 0;
|
||||||
i++;
|
i++;
|
||||||
if (i < len && p[i] == '-') minus = 1, i++;
|
if (i < len && p[i] == '-') minus = 1, i++;
|
||||||
if (i < len && p[i] == '+') i++;
|
if (i < len && p[i] == '+') i++;
|
||||||
while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
|
while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
|
||||||
exp = exp * 10 + (p[i++] - '0');
|
exp = exp * 10 + (p[i++] - '0');
|
||||||
if (minus) exp = -exp;
|
// use fast exponentiation
|
||||||
for (j = 0; j < exp; j++) d *= 10.0;
|
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
||||||
for (j = 0; j < -exp; j++) d /= 10.0;
|
if (exp != 0) {
|
||||||
|
double x = 10, y = 1;
|
||||||
|
if (exp > 308) exp = 308;
|
||||||
|
if (minus) x = 0.1;
|
||||||
|
while (exp > 1) {
|
||||||
|
if (exp & 1) {
|
||||||
|
y *= x;
|
||||||
|
--exp;
|
||||||
|
}
|
||||||
|
x *= x;
|
||||||
|
exp >>= 1;
|
||||||
|
}
|
||||||
|
d *= x * y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numlen != NULL) *numlen = i;
|
if (numlen != NULL) *numlen = i;
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
#include "l2.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "net_builtin.h"
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
|
||||||
|
// L2 API
|
||||||
|
void mg_l2_init(enum mg_l2type type, uint8_t *addr, uint16_t *mtu,
|
||||||
|
uint16_t *framesize);
|
||||||
|
uint8_t *mg_l2_header(enum mg_l2type type, enum mg_l2proto proto, uint8_t *src,
|
||||||
|
uint8_t *dst, uint8_t *frame);
|
||||||
|
size_t mg_l2_footer(enum mg_l2type type, size_t len, uint8_t *frame);
|
||||||
|
bool mg_l2_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto,
|
||||||
|
struct mg_str *pay, struct mg_str *raw);
|
||||||
|
// TODO(): ? bool mg_l2_rx(enum mg_l2type type, struct mg_l2opts *opts, uint8_t
|
||||||
|
// *addr, enum mg_l2proto *proto, struct mg_str *pay, struct mg_str *raw);
|
||||||
|
uint8_t *mg_l2_getaddr(enum mg_l2type type, uint8_t *frame);
|
||||||
|
uint8_t *mg_l2_mapip(enum mg_l2type type, enum mg_l2addrtype addrtype,
|
||||||
|
struct mg_addr *ip);
|
||||||
|
bool mg_l2_genip6(enum mg_l2type type, uint64_t *ip6, uint8_t prefix_len,
|
||||||
|
uint8_t *addr);
|
||||||
|
bool mg_l2_ip6get(enum mg_l2type type, uint8_t *addr, uint8_t *opts,
|
||||||
|
uint8_t len);
|
||||||
|
uint8_t mg_l2_ip6put(enum mg_l2type type, uint8_t *addr, uint8_t *opts);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
extern void mg_l2_eth_init(struct mg_l2addr *, uint16_t *, uint16_t *);
|
||||||
|
extern uint8_t *mg_l2_eth_header(enum mg_l2proto, struct mg_l2addr *, struct mg_l2addr *, uint8_t *);
|
||||||
|
extern size_t mg_l2_eth_footer(size_t, uint8_t *);
|
||||||
|
extern bool mg_l2_eth_rx(struct mg_tcpip_if *, enum mg_l2proto *, struct mg_str *, struct mg_str *);
|
||||||
|
extern struct mg_l2addr *mg_l2_eth_getaddr(uint8_t *);
|
||||||
|
extern struct mg_l2addr *mg_l2_eth_mapip(enum mg_l2addrtype, struct mg_addr *);
|
||||||
|
extern bool mg_l2_eth_genip6(uint64_t *, uint8_t, struct mg_l2addr *);
|
||||||
|
extern bool mg_l2_eth_ip6get(struct mg_l2addr *, uint8_t *, uint8_t);
|
||||||
|
extern uint8_t mg_l2_eth_ip6put(struct mg_l2addr *, uint8_t *);
|
||||||
|
|
||||||
|
extern void mg_l2_ppp_init(struct mg_l2addr *, uint16_t *, uint16_t *);
|
||||||
|
extern uint8_t *mg_l2_ppp_header(enum mg_l2proto, struct mg_l2addr *, struct mg_l2addr *, uint8_t *);
|
||||||
|
extern size_t mg_l2_ppp_footer(size_t, uint8_t *);
|
||||||
|
extern bool mg_l2_ppp_rx(struct mg_tcpip_if *, enum mg_l2proto *, struct mg_str *, struct mg_str *);
|
||||||
|
extern struct mg_l2addr *mg_l2_ppp_getaddr(uint8_t *);
|
||||||
|
extern struct mg_l2addr *mg_l2_ppp_mapip(enum mg_l2addrtype, struct mg_addr *);
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
extern bool mg_l2_ppp_genip6(uint64_t *, uint8_t, struct mg_l2addr *);
|
||||||
|
extern bool mg_l2_ppp_ip6get(struct mg_l2addr *, uint8_t *, uint8_t);
|
||||||
|
extern uint8_t mg_l2_ppp_ip6put(struct mg_l2addr *, uint8_t *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*l2_init_fn)(struct mg_l2addr *, uint16_t *, uint16_t *);
|
||||||
|
typedef uint8_t *((*l2_header_fn)(enum mg_l2proto, struct mg_l2addr *, struct mg_l2addr *, uint8_t *));
|
||||||
|
typedef size_t (*l2_footer_fn)(size_t, uint8_t *);
|
||||||
|
typedef bool (*l2_rx_fn)(struct mg_tcpip_if *, enum mg_l2proto *, struct mg_str *, struct mg_str *);
|
||||||
|
typedef struct mg_l2addr (*(*l2_getaddr_fn)(uint8_t *));
|
||||||
|
typedef struct mg_l2addr (*(*l2_mapip_fn)(enum mg_l2addrtype, struct mg_addr *));
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
typedef bool (*l2_genip6_fn)(uint64_t *, uint8_t, struct mg_l2addr *);
|
||||||
|
typedef bool (*l2_ip6get_fn)(struct mg_l2addr *, uint8_t *, uint8_t);
|
||||||
|
typedef uint8_t (*l2_ip6put_fn)(struct mg_l2addr *, uint8_t *);
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const l2_init_fn l2_init[] = {mg_l2_eth_init, mg_l2_ppp_init};
|
||||||
|
static const l2_header_fn l2_header[] = {mg_l2_eth_header, mg_l2_ppp_header};
|
||||||
|
static const l2_footer_fn l2_footer[] = {mg_l2_eth_footer, mg_l2_ppp_footer};
|
||||||
|
static const l2_rx_fn l2_rx[] = {mg_l2_eth_rx, mg_l2_ppp_rx};
|
||||||
|
static const l2_getaddr_fn l2_getaddr[] = {mg_l2_eth_getaddr,
|
||||||
|
mg_l2_ppp_getaddr};
|
||||||
|
static const l2_mapip_fn l2_mapip[] = {mg_l2_eth_mapip, mg_l2_ppp_mapip};
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
static const l2_genip6_fn l2_genip6[] = {mg_l2_eth_genip6, mg_l2_ppp_genip6};
|
||||||
|
static const l2_ip6get_fn l2_ip6get[] = {mg_l2_eth_ip6get, mg_l2_ppp_ip6get};
|
||||||
|
static const l2_ip6put_fn l2_ip6put[] = {mg_l2_eth_ip6put, mg_l2_ppp_ip6put};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void mg_l2_init(enum mg_l2type type, uint8_t *addr, uint16_t *mtu,
|
||||||
|
uint16_t *framesize) {
|
||||||
|
l2_init[type]((struct mg_l2addr *) addr, mtu, framesize);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *mg_l2_header(enum mg_l2type type, enum mg_l2proto proto, uint8_t *src,
|
||||||
|
uint8_t *dst, uint8_t *frame) {
|
||||||
|
return l2_header[type](proto, (struct mg_l2addr *) src,
|
||||||
|
(struct mg_l2addr *) dst, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mg_l2_footer(enum mg_l2type type, size_t len, uint8_t *frame) {
|
||||||
|
return l2_footer[type](len, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_l2_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto,
|
||||||
|
struct mg_str *pay, struct mg_str *raw) {
|
||||||
|
return l2_rx[ifp->l2type](ifp, proto, pay, raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *mg_l2_getaddr(enum mg_l2type type, uint8_t *frame) {
|
||||||
|
return (uint8_t *) l2_getaddr[type](frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_l2addr s_mapip;
|
||||||
|
|
||||||
|
uint8_t *mg_l2_mapip(enum mg_l2type type, enum mg_l2addrtype addrtype,
|
||||||
|
struct mg_addr *ip) {
|
||||||
|
return (uint8_t *) l2_mapip[type](addrtype, ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
bool mg_l2_genip6(enum mg_l2type type, uint64_t *ip6, uint8_t prefix_len,
|
||||||
|
uint8_t *addr) {
|
||||||
|
return l2_genip6[type](ip6, prefix_len, (struct mg_l2addr *) addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_l2_ip6get(enum mg_l2type type, uint8_t *addr, uint8_t *opts,
|
||||||
|
uint8_t len) {
|
||||||
|
return l2_ip6get[type]((struct mg_l2addr *) addr, opts, len);
|
||||||
|
}
|
||||||
|
uint8_t mg_l2_ip6put(enum mg_l2type type, uint8_t *addr, uint8_t *opts) {
|
||||||
|
return l2_ip6put[type]((struct mg_l2addr *) addr, opts);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "arch.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
|
||||||
|
// no config defaults to 0 => Ethernet
|
||||||
|
enum mg_l2type { MG_TCPIP_L2_ETH = 0, MG_TCPIP_L2_PPP }; // MG_TCPIP_L2_PPPoE
|
||||||
|
|
||||||
|
#if defined(__DCC__)
|
||||||
|
#pragma pack(1)
|
||||||
|
#else
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct mg_l2addr {
|
||||||
|
union {
|
||||||
|
uint8_t mac[6];
|
||||||
|
} addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__DCC__)
|
||||||
|
#pragma pack(0)
|
||||||
|
#else
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
TODO(): ?
|
||||||
|
struct eth_opts {
|
||||||
|
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
|
||||||
|
bool enable_mac_check; // Do a MAC check on RX frames
|
||||||
|
};
|
||||||
|
struct mg_l2opts {
|
||||||
|
union {
|
||||||
|
struct eth_opts eth;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum mg_l2proto {
|
||||||
|
MG_TCPIP_L2PROTO_IPV4 = 0,
|
||||||
|
MG_TCPIP_L2PROTO_IPV6,
|
||||||
|
MG_TCPIP_L2PROTO_ARP,
|
||||||
|
MG_TCPIP_L2PROTO_PPPoE_DISC,
|
||||||
|
MG_TCPIP_L2PROTO_PPPoE_SESS
|
||||||
|
};
|
||||||
|
enum mg_l2addrtype {
|
||||||
|
MG_TCPIP_L2ADDR_BCAST,
|
||||||
|
MG_TCPIP_L2ADDR_MCAST,
|
||||||
|
MG_TCPIP_L2ADDR_MCAST6
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+171
@@ -0,0 +1,171 @@
|
|||||||
|
#include "l2.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "net_builtin.h"
|
||||||
|
#include "printf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
|
||||||
|
#if defined(__DCC__)
|
||||||
|
#pragma pack(1)
|
||||||
|
#else
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct eth {
|
||||||
|
uint8_t dst[6]; // Destination MAC address
|
||||||
|
uint8_t src[6]; // Source MAC address
|
||||||
|
uint16_t type; // Ethernet type
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__DCC__)
|
||||||
|
#pragma pack(0)
|
||||||
|
#else
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const uint16_t eth_types[] = {
|
||||||
|
// order is vital, see l2.h
|
||||||
|
0x800, // IPv4
|
||||||
|
0x86dd, // IPv6
|
||||||
|
0x806, // ARP
|
||||||
|
0x8863, // PPPoE Discovery Stage
|
||||||
|
0x8864 // PPPoE Session Stage
|
||||||
|
};
|
||||||
|
|
||||||
|
void mg_l2_eth_init(struct mg_l2addr *l2addr, uint16_t *mtu,
|
||||||
|
uint16_t *framesize) {
|
||||||
|
// If MAC is not set, make a random one
|
||||||
|
if (l2addr->addr.mac[0] == 0 && l2addr->addr.mac[1] == 0 &&
|
||||||
|
l2addr->addr.mac[2] == 0 && l2addr->addr.mac[3] == 0 &&
|
||||||
|
l2addr->addr.mac[4] == 0 && l2addr->addr.mac[5] == 0) {
|
||||||
|
l2addr->addr.mac[0] = 0x02; // Locally administered, unicast
|
||||||
|
mg_random(&l2addr->addr.mac[1], sizeof(l2addr->addr.mac) - 1);
|
||||||
|
MG_INFO(
|
||||||
|
("MAC not set. Generated random: %M", mg_print_mac, l2addr->addr.mac));
|
||||||
|
}
|
||||||
|
*mtu = 1500;
|
||||||
|
*framesize = 1540;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *mg_l2_eth_header(enum mg_l2proto proto, struct mg_l2addr *src,
|
||||||
|
struct mg_l2addr *dst, uint8_t *frame) {
|
||||||
|
struct eth *eth = (struct eth *) frame;
|
||||||
|
eth->type = mg_htons(eth_types[(unsigned int) proto]);
|
||||||
|
memcpy(eth->src, src->addr.mac, sizeof(eth->dst));
|
||||||
|
memcpy(eth->dst, dst->addr.mac, sizeof(eth->dst));
|
||||||
|
return (uint8_t *) (eth + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mg_l2_eth_footer(size_t len, uint8_t *frame) {
|
||||||
|
struct eth *eth = (struct eth *) frame;
|
||||||
|
// nothing to do; there is no len field in Ethernet, CRC is hw-calculated
|
||||||
|
return len + sizeof(*eth);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_l2addr *mg_l2_eth_mapip(enum mg_l2addrtype addrtype,
|
||||||
|
struct mg_addr *addr);
|
||||||
|
|
||||||
|
bool mg_l2_eth_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto,
|
||||||
|
struct mg_str *pay, struct mg_str *raw) {
|
||||||
|
struct eth *eth = (struct eth *) raw->buf;
|
||||||
|
uint16_t type, len;
|
||||||
|
unsigned int i;
|
||||||
|
if (raw->len < sizeof(*eth)) return false; // Truncated - runt?
|
||||||
|
len = (uint16_t) raw->len;
|
||||||
|
if (ifp->enable_mac_check &&
|
||||||
|
memcmp(eth->dst, ifp->mac, sizeof(eth->dst)) != 0 &&
|
||||||
|
memcmp(eth->dst, mg_l2_eth_mapip(MG_TCPIP_L2ADDR_BCAST, NULL),
|
||||||
|
sizeof(eth->dst)) != 0)
|
||||||
|
return false; // TODO(): add multicast addresses
|
||||||
|
if (ifp->enable_crc32_check && len > sizeof(*eth) + 4) {
|
||||||
|
uint32_t crc;
|
||||||
|
len -= 4; // TODO(scaprile): check on bigendian
|
||||||
|
crc = mg_crc32(0, (const char *) raw->buf, len);
|
||||||
|
if (memcmp((void *) ((size_t) raw->buf + len), &crc, sizeof(crc)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pay->buf = (char *) (eth + 1);
|
||||||
|
pay->len = len - sizeof(*eth);
|
||||||
|
|
||||||
|
type = mg_htons(eth->type);
|
||||||
|
for (i = 0; i < sizeof(eth_types) / sizeof(uint16_t); i++) {
|
||||||
|
if (type == eth_types[i]) break;
|
||||||
|
}
|
||||||
|
if (i == sizeof(eth_types)) {
|
||||||
|
MG_DEBUG(("Unknown eth type %x", type));
|
||||||
|
if (mg_log_level >= MG_LL_VERBOSE)
|
||||||
|
mg_hexdump(raw->buf, raw->len >= 32 ? 32 : raw->len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*proto = (enum mg_l2proto) i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_l2addr *mg_l2_eth_getaddr(uint8_t *frame) {
|
||||||
|
struct eth *eth = (struct eth *) frame;
|
||||||
|
return (struct mg_l2addr *) ð->src;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern struct mg_l2addr s_mapip;
|
||||||
|
|
||||||
|
struct mg_l2addr *mg_l2_eth_mapip(enum mg_l2addrtype addrtype,
|
||||||
|
struct mg_addr *addr) {
|
||||||
|
switch (addrtype) {
|
||||||
|
case MG_TCPIP_L2ADDR_BCAST:
|
||||||
|
memset(s_mapip.addr.mac, 0xff, sizeof(s_mapip.addr.mac));
|
||||||
|
break;
|
||||||
|
case MG_TCPIP_L2ADDR_MCAST: {
|
||||||
|
uint8_t *ip = (uint8_t *) &addr->addr.ip4;
|
||||||
|
// IP multicast group MAC, RFC-1112 6.4
|
||||||
|
s_mapip.addr.mac[0] = 0x01, s_mapip.addr.mac[1] = 0x00,
|
||||||
|
s_mapip.addr.mac[2] = 0x5E;
|
||||||
|
s_mapip.addr.mac[3] = ip[1] & 0x7F; // 23 LSb
|
||||||
|
s_mapip.addr.mac[4] = ip[2];
|
||||||
|
s_mapip.addr.mac[5] = ip[3];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MG_TCPIP_L2ADDR_MCAST6: {
|
||||||
|
// IPv6 multicast address mapping, RFC-2464 7
|
||||||
|
uint8_t *ip = (uint8_t *) &addr->addr.ip6;
|
||||||
|
s_mapip.addr.mac[0] = 0x33, s_mapip.addr.mac[1] = 0x33;
|
||||||
|
s_mapip.addr.mac[2] = ip[12], s_mapip.addr.mac[3] = ip[13],
|
||||||
|
s_mapip.addr.mac[4] = ip[14], s_mapip.addr.mac[5] = ip[15];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &s_mapip;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
static void meui64(uint8_t *addr, uint8_t *mac) {
|
||||||
|
*addr++ = *mac++ ^ (uint8_t) 0x02, *addr++ = *mac++, *addr++ = *mac++;
|
||||||
|
*addr++ = 0xff, *addr++ = 0xfe;
|
||||||
|
*addr++ = *mac++, *addr++ = *mac++, *addr = *mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_l2_eth_genip6(uint64_t *ip6, uint8_t prefix_len,
|
||||||
|
struct mg_l2addr *l2addr) {
|
||||||
|
if (prefix_len > 64) {
|
||||||
|
MG_ERROR(("Prefix length > 64, UNSUPPORTED"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ip6[0] = 0;
|
||||||
|
meui64(((uint8_t *) &ip6[1]), l2addr->addr.mac); // RFC-4291 2.5.4, 2.5.1
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_l2_eth_ip6get(struct mg_l2addr *l2addr, uint8_t *opts, uint8_t len) {
|
||||||
|
if (len != 1) return false;
|
||||||
|
memcpy(l2addr->addr.mac, opts, 6);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t mg_l2_eth_ip6put(struct mg_l2addr *l2addr, uint8_t *opts) {
|
||||||
|
memcpy(opts, l2addr->addr.mac, 6);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
#include "l2.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "net_builtin.h"
|
||||||
|
#include "printf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
|
||||||
|
#if defined(__DCC__)
|
||||||
|
#pragma pack(1)
|
||||||
|
#else
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ppp { // RFC-1662
|
||||||
|
uint8_t addr, ctrl;
|
||||||
|
uint16_t proto;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lcp { // RFC-1661
|
||||||
|
uint8_t code, id, len[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipcp { // RFC-1332
|
||||||
|
uint8_t code;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipv6cp { // RFC-5072
|
||||||
|
uint8_t code;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__DCC__)
|
||||||
|
#pragma pack(0)
|
||||||
|
#else
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void mg_l2_ppp_init(struct mg_l2addr *addr, uint16_t *mtu,
|
||||||
|
uint16_t *framesize) {
|
||||||
|
(void) addr;
|
||||||
|
*mtu = 1500; // 1492 for PPPoE
|
||||||
|
*framesize = 1540; // *** TODO(scaprile): actual value, check for PPPoE too
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *mg_l2_ppp_header(enum mg_l2proto proto, struct mg_l2addr *src,
|
||||||
|
struct mg_l2addr *dst, uint8_t *frame) {
|
||||||
|
(void) src;
|
||||||
|
(void) dst;
|
||||||
|
(void) proto;
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mg_l2_ppp_footer(size_t len, uint8_t *frame) {
|
||||||
|
(void) frame;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_l2_ppp_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto,
|
||||||
|
struct mg_str *pay, struct mg_str *raw) {
|
||||||
|
#if 0
|
||||||
|
if (ppp->addr == MG_PPP_ADDR && ppp->ctrl == MG_PPP_CTRL) {
|
||||||
|
code = ntohs(ppp->proto);
|
||||||
|
payload = (uint8_t *) (ppp + 1);
|
||||||
|
} else { // Address-and-Control-Field-Compressed PPP header
|
||||||
|
uint16_t *cppp = (uint16_t *) ppp;
|
||||||
|
code = ntohs(*cppp);
|
||||||
|
payload = (uint8_t *) (cppp + 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*pay = *raw;
|
||||||
|
*proto = MG_TCPIP_L2PROTO_IPV4;
|
||||||
|
(void) ifp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_l2addr *mg_l2_ppp_getaddr(uint8_t *frame) {
|
||||||
|
(void) frame;
|
||||||
|
return &s_mapip; // bogus
|
||||||
|
}
|
||||||
|
|
||||||
|
extern struct mg_l2addr s_mapip;
|
||||||
|
|
||||||
|
struct mg_l2addr *mg_l2_ppp_mapip(enum mg_l2addrtype addrtype,
|
||||||
|
struct mg_addr *addr) {
|
||||||
|
(void) addrtype;
|
||||||
|
(void) addr;
|
||||||
|
return &s_mapip; // bogus
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
bool mg_l2_ppp_genip6(uint64_t *ip6, uint8_t prefix_len,
|
||||||
|
struct mg_l2addr *addr) {
|
||||||
|
(void) ip6;
|
||||||
|
(void) prefix_len;
|
||||||
|
(void) addr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_l2_ppp_ip6get(struct mg_l2addr *addr, uint8_t *opts, uint8_t len) {
|
||||||
|
(void) addr;
|
||||||
|
(void) opts;
|
||||||
|
(void) len;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t mg_l2_ppp_ip6put(struct mg_l2addr *addr, uint8_t *opts) {
|
||||||
|
(void) addr;
|
||||||
|
(void) opts;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,12 +16,18 @@ void mg_log_set_fn(mg_pfn_t fn, void *param);
|
|||||||
#define mg_log_set(level_) mg_log_level = (level_)
|
#define mg_log_set(level_) mg_log_level = (level_)
|
||||||
|
|
||||||
#if MG_ENABLE_LOG
|
#if MG_ENABLE_LOG
|
||||||
#define MG_LOG(level, args) \
|
#if !defined(_MSC_VER) && \
|
||||||
do { \
|
(!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
|
||||||
if ((level) <= mg_log_level) { \
|
#define MG___FUNC__ ""
|
||||||
mg_log_prefix((level), __FILE__, __LINE__, __func__); \
|
#else
|
||||||
mg_log args; \
|
#define MG___FUNC__ __func__ // introduced in C99
|
||||||
} \
|
#endif
|
||||||
|
#define MG_LOG(level, args) \
|
||||||
|
do { \
|
||||||
|
if ((level) <= mg_log_level) { \
|
||||||
|
mg_log_prefix((level), __FILE__, __LINE__, MG___FUNC__); \
|
||||||
|
mg_log args; \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define MG_LOG(level, args) \
|
#define MG_LOG(level, args) \
|
||||||
|
|||||||
+148
-88
@@ -1,8 +1,8 @@
|
|||||||
#include "mqtt.h"
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "mqtt.h"
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@@ -46,8 +46,8 @@ static const struct mg_mqtt_pmap s_prop_map[] = {
|
|||||||
{MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE},
|
{MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE},
|
||||||
{MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}};
|
{MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}};
|
||||||
|
|
||||||
void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
|
static bool mqtt_send_header(struct mg_connection *c, uint8_t cmd,
|
||||||
uint32_t len) {
|
uint8_t flags, uint32_t len) {
|
||||||
uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
|
uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
|
||||||
buf[0] = (uint8_t) ((cmd << 4) | flags);
|
buf[0] = (uint8_t) ((cmd << 4) | flags);
|
||||||
do {
|
do {
|
||||||
@@ -56,15 +56,20 @@ void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
|
|||||||
if (len > 0) *vlen |= 0x80;
|
if (len > 0) *vlen |= 0x80;
|
||||||
vlen++;
|
vlen++;
|
||||||
} while (len > 0 && vlen < &buf[sizeof(buf)]);
|
} while (len > 0 && vlen < &buf[sizeof(buf)]);
|
||||||
mg_send(c, buf, (size_t) (vlen - buf));
|
return mg_send(c, buf, (size_t) (vlen - buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mg_send_u16(struct mg_connection *c, uint16_t value) {
|
void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
|
||||||
mg_send(c, &value, sizeof(value));
|
uint32_t len) {
|
||||||
|
if (!mqtt_send_header(c, cmd, flags, len)) mg_error(c, "OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mg_send_u32(struct mg_connection *c, uint32_t value) {
|
static bool mg_send_u16(struct mg_connection *c, uint16_t value) {
|
||||||
mg_send(c, &value, sizeof(value));
|
return mg_send(c, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_send_u32(struct mg_connection *c, uint32_t value) {
|
||||||
|
return mg_send(c, &value, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t varint_size(size_t length) {
|
static uint8_t varint_size(size_t length) {
|
||||||
@@ -132,17 +137,10 @@ static size_t get_properties_length(struct mg_mqtt_prop *props, size_t count) {
|
|||||||
case MQTT_PROP_TYPE_VARIABLE_INT:
|
case MQTT_PROP_TYPE_VARIABLE_INT:
|
||||||
size += varint_size((uint32_t) props[i].iv);
|
size += varint_size((uint32_t) props[i].iv);
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_INT:
|
case MQTT_PROP_TYPE_INT: size += (uint32_t) sizeof(uint32_t); break;
|
||||||
size += (uint32_t) sizeof(uint32_t);
|
case MQTT_PROP_TYPE_SHORT: size += (uint32_t) sizeof(uint16_t); break;
|
||||||
break;
|
case MQTT_PROP_TYPE_BYTE: size += (uint32_t) sizeof(uint8_t); break;
|
||||||
case MQTT_PROP_TYPE_SHORT:
|
default: return size; // cannot parse further down
|
||||||
size += (uint32_t) sizeof(uint16_t);
|
|
||||||
break;
|
|
||||||
case MQTT_PROP_TYPE_BYTE:
|
|
||||||
size += (uint32_t) sizeof(uint8_t);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return size; // cannot parse further down
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,46 +155,50 @@ static size_t get_props_size(struct mg_mqtt_prop *props, size_t count) {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mg_send_mqtt_properties(struct mg_connection *c,
|
static bool mg_send_mqtt_properties(struct mg_connection *c,
|
||||||
struct mg_mqtt_prop *props, size_t nprops) {
|
struct mg_mqtt_prop *props, size_t nprops) {
|
||||||
size_t total_size = get_properties_length(props, nprops);
|
size_t total_size = get_properties_length(props, nprops);
|
||||||
uint8_t buf_v[4] = {0, 0, 0, 0};
|
uint8_t buf_v[4] = {0, 0, 0, 0};
|
||||||
uint8_t buf[4] = {0, 0, 0, 0};
|
uint8_t buf[4] = {0, 0, 0, 0};
|
||||||
size_t i, len = encode_varint(buf, total_size);
|
size_t i, len = encode_varint(buf, total_size);
|
||||||
|
|
||||||
mg_send(c, buf, (size_t) len);
|
if (!mg_send(c, buf, (size_t) len)) return false;
|
||||||
for (i = 0; i < nprops; i++) {
|
for (i = 0; i < nprops; i++) {
|
||||||
mg_send(c, &props[i].id, sizeof(props[i].id));
|
if (!mg_send(c, &props[i].id, sizeof(props[i].id))) return false;
|
||||||
switch (mqtt_prop_type_by_id(props[i].id)) {
|
switch (mqtt_prop_type_by_id(props[i].id)) {
|
||||||
case MQTT_PROP_TYPE_STRING_PAIR:
|
case MQTT_PROP_TYPE_STRING_PAIR:
|
||||||
mg_send_u16(c, mg_htons((uint16_t) props[i].key.len));
|
if (!mg_send_u16(c, mg_htons((uint16_t) props[i].key.len)) ||
|
||||||
mg_send(c, props[i].key.buf, props[i].key.len);
|
!mg_send(c, props[i].key.buf, props[i].key.len) ||
|
||||||
mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
|
!mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)) ||
|
||||||
mg_send(c, props[i].val.buf, props[i].val.len);
|
!mg_send(c, props[i].val.buf, props[i].val.len))
|
||||||
|
return false;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_BYTE:
|
case MQTT_PROP_TYPE_BYTE:
|
||||||
mg_send(c, &props[i].iv, sizeof(uint8_t));
|
if (!mg_send(c, &props[i].iv, sizeof(uint8_t))) return false;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_SHORT:
|
case MQTT_PROP_TYPE_SHORT:
|
||||||
mg_send_u16(c, mg_htons((uint16_t) props[i].iv));
|
if (!mg_send_u16(c, mg_htons((uint16_t) props[i].iv))) return false;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_INT:
|
case MQTT_PROP_TYPE_INT:
|
||||||
mg_send_u32(c, mg_htonl((uint32_t) props[i].iv));
|
if (!mg_send_u32(c, mg_htonl((uint32_t) props[i].iv))) return false;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_STRING:
|
case MQTT_PROP_TYPE_STRING:
|
||||||
mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
|
if (!mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)) ||
|
||||||
mg_send(c, props[i].val.buf, props[i].val.len);
|
!mg_send(c, props[i].val.buf, props[i].val.len))
|
||||||
|
return false;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_BINARY_DATA:
|
case MQTT_PROP_TYPE_BINARY_DATA:
|
||||||
mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
|
if (!mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)) ||
|
||||||
mg_send(c, props[i].val.buf, props[i].val.len);
|
!mg_send(c, props[i].val.buf, props[i].val.len))
|
||||||
|
return false;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_VARIABLE_INT:
|
case MQTT_PROP_TYPE_VARIABLE_INT:
|
||||||
len = encode_varint(buf_v, props[i].iv);
|
len = encode_varint(buf_v, props[i].iv);
|
||||||
mg_send(c, buf_v, (size_t) len);
|
if (!mg_send(c, buf_v, (size_t) len)) return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
|
size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
|
||||||
@@ -204,50 +206,64 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
|
|||||||
uint8_t *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs;
|
uint8_t *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs;
|
||||||
uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len;
|
uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len;
|
||||||
size_t new_pos = ofs, len;
|
size_t new_pos = ofs, len;
|
||||||
prop->id = i[0];
|
|
||||||
|
|
||||||
if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size)
|
if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size || (i + 1) >= end)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
memset(prop, 0, sizeof(struct mg_mqtt_prop));
|
||||||
|
prop->id = i[0];
|
||||||
i++, new_pos++;
|
i++, new_pos++;
|
||||||
|
|
||||||
switch (mqtt_prop_type_by_id(prop->id)) {
|
switch (mqtt_prop_type_by_id(prop->id)) {
|
||||||
case MQTT_PROP_TYPE_STRING_PAIR:
|
case MQTT_PROP_TYPE_STRING_PAIR:
|
||||||
|
if (i + 2 >= end) return 0;
|
||||||
prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
||||||
prop->key.buf = (char *) i + 2;
|
prop->key.buf = (char *) i + 2;
|
||||||
i += 2 + prop->key.len;
|
i += 2 + prop->key.len;
|
||||||
|
if (i + 2 >= end) return 0;
|
||||||
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
||||||
prop->val.buf = (char *) i + 2;
|
prop->val.buf = (char *) i + 2;
|
||||||
|
if (i + 2 + prop->val.len >= end) return 0;
|
||||||
new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len;
|
new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_BYTE:
|
case MQTT_PROP_TYPE_BYTE:
|
||||||
|
if (i + 1 >= end) return 0;
|
||||||
prop->iv = (uint8_t) i[0];
|
prop->iv = (uint8_t) i[0];
|
||||||
new_pos++;
|
new_pos++;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_SHORT:
|
case MQTT_PROP_TYPE_SHORT:
|
||||||
|
if (i + 2 >= end) return 0;
|
||||||
prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
||||||
new_pos += sizeof(uint16_t);
|
new_pos += sizeof(uint16_t);
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_INT:
|
case MQTT_PROP_TYPE_INT:
|
||||||
|
if (i + 4 >= end) return 0;
|
||||||
prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) |
|
prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) |
|
||||||
((uint32_t) i[2] << 8) | i[3];
|
((uint32_t) i[2] << 8) | i[3];
|
||||||
new_pos += sizeof(uint32_t);
|
new_pos += sizeof(uint32_t);
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_STRING:
|
case MQTT_PROP_TYPE_STRING:
|
||||||
|
if (i + 2 >= end) return 0;
|
||||||
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
||||||
prop->val.buf = (char *) i + 2;
|
prop->val.buf = (char *) i + 2;
|
||||||
|
if (i + 2 + prop->val.len >= end) return 0;
|
||||||
new_pos += 2 + prop->val.len;
|
new_pos += 2 + prop->val.len;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_BINARY_DATA:
|
case MQTT_PROP_TYPE_BINARY_DATA:
|
||||||
|
if (i + 2 >= end) return 0;
|
||||||
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
|
||||||
prop->val.buf = (char *) i + 2;
|
prop->val.buf = (char *) i + 2;
|
||||||
|
if (i + 2 + prop->val.len >= end) return 0;
|
||||||
new_pos += 2 + prop->val.len;
|
new_pos += 2 + prop->val.len;
|
||||||
break;
|
break;
|
||||||
case MQTT_PROP_TYPE_VARIABLE_INT:
|
case MQTT_PROP_TYPE_VARIABLE_INT:
|
||||||
len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv);
|
len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv);
|
||||||
new_pos = (!len) ? 0 : new_pos + len;
|
if (i + len >= end) return 0;
|
||||||
|
new_pos = (len == 0) ? 0 : new_pos + len;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
new_pos = 0;
|
new_pos = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_pos;
|
return new_pos;
|
||||||
@@ -257,7 +273,8 @@ void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
|
|||||||
char client_id[21];
|
char client_id[21];
|
||||||
struct mg_str cid = opts->client_id;
|
struct mg_str cid = opts->client_id;
|
||||||
size_t total_len = 7 + 1 + 2 + 2;
|
size_t total_len = 7 + 1 + 2 + 2;
|
||||||
uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0};
|
uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', 0, 0};
|
||||||
|
hdr[6] = opts->version;
|
||||||
|
|
||||||
if (cid.len == 0) {
|
if (cid.len == 0) {
|
||||||
mg_random_str(client_id, sizeof(client_id) - 1);
|
mg_random_str(client_id, sizeof(client_id) - 1);
|
||||||
@@ -289,33 +306,41 @@ void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
|
|||||||
total_len += get_props_size(opts->will_props, opts->num_will_props);
|
total_len += get_props_size(opts->will_props, opts->num_will_props);
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len);
|
|
||||||
mg_send(c, hdr, sizeof(hdr));
|
|
||||||
// keepalive == 0 means "do not disconnect us!"
|
// keepalive == 0 means "do not disconnect us!"
|
||||||
mg_send_u16(c, mg_htons((uint16_t) opts->keepalive));
|
if (!mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len) ||
|
||||||
|
!mg_send(c, hdr, sizeof(hdr)) ||
|
||||||
|
!mg_send_u16(c, mg_htons((uint16_t) opts->keepalive)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
|
if (c->is_mqtt5 && !mg_send_mqtt_properties(c, opts->props, opts->num_props))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
mg_send_u16(c, mg_htons((uint16_t) cid.len));
|
if (!mg_send_u16(c, mg_htons((uint16_t) cid.len)) ||
|
||||||
mg_send(c, cid.buf, cid.len);
|
!mg_send(c, cid.buf, cid.len))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (hdr[7] & MQTT_HAS_WILL) {
|
if (hdr[7] & MQTT_HAS_WILL) {
|
||||||
if (c->is_mqtt5)
|
if (c->is_mqtt5 &&
|
||||||
mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props);
|
!mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
|
if (!mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)) ||
|
||||||
mg_send(c, opts->topic.buf, opts->topic.len);
|
!mg_send(c, opts->topic.buf, opts->topic.len) ||
|
||||||
mg_send_u16(c, mg_htons((uint16_t) opts->message.len));
|
!mg_send_u16(c, mg_htons((uint16_t) opts->message.len)) ||
|
||||||
mg_send(c, opts->message.buf, opts->message.len);
|
!mg_send(c, opts->message.buf, opts->message.len))
|
||||||
}
|
goto fail;
|
||||||
if (opts->user.len > 0) {
|
|
||||||
mg_send_u16(c, mg_htons((uint16_t) opts->user.len));
|
|
||||||
mg_send(c, opts->user.buf, opts->user.len);
|
|
||||||
}
|
|
||||||
if (opts->pass.len > 0) {
|
|
||||||
mg_send_u16(c, mg_htons((uint16_t) opts->pass.len));
|
|
||||||
mg_send(c, opts->pass.buf, opts->pass.len);
|
|
||||||
}
|
}
|
||||||
|
if (opts->user.len > 0 &&
|
||||||
|
(!mg_send_u16(c, mg_htons((uint16_t) opts->user.len)) ||
|
||||||
|
!mg_send(c, opts->user.buf, opts->user.len)))
|
||||||
|
goto fail;
|
||||||
|
if (opts->pass.len > 0 &&
|
||||||
|
(!mg_send_u16(c, mg_htons((uint16_t) opts->pass.len)) ||
|
||||||
|
!mg_send(c, opts->pass.buf, opts->pass.len)))
|
||||||
|
goto fail;
|
||||||
|
return;
|
||||||
|
fail:
|
||||||
|
mg_error(c, "OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
|
uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
|
||||||
@@ -330,36 +355,60 @@ uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
|
|||||||
if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props);
|
if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props);
|
||||||
|
|
||||||
if (opts->qos > 0 && id != 0) flags |= 1 << 3;
|
if (opts->qos > 0 && id != 0) flags |= 1 << 3;
|
||||||
mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len);
|
if (!mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len) ||
|
||||||
mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
|
!mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)) ||
|
||||||
mg_send(c, opts->topic.buf, opts->topic.len);
|
!mg_send(c, opts->topic.buf, opts->topic.len))
|
||||||
|
goto fail;
|
||||||
if (opts->qos > 0) { // need to send 'id' field
|
if (opts->qos > 0) { // need to send 'id' field
|
||||||
if (id == 0) { // generate new one if not resending
|
if (id == 0) { // generate new one if not resending
|
||||||
if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
|
if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
|
||||||
id = c->mgr->mqtt_id;
|
id = c->mgr->mqtt_id;
|
||||||
}
|
}
|
||||||
mg_send_u16(c, mg_htons(id));
|
if (!mg_send_u16(c, mg_htons(id))) goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
|
if (c->is_mqtt5 && !mg_send_mqtt_properties(c, opts->props, opts->num_props))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (opts->message.len > 0) mg_send(c, opts->message.buf, opts->message.len);
|
if (opts->message.len > 0 &&
|
||||||
|
!mg_send(c, opts->message.buf, opts->message.len))
|
||||||
|
goto fail;
|
||||||
|
return id;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
mg_error(c, "OOM");
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
|
static void mg_mqtt_sub_unsub(struct mg_connection *c,
|
||||||
|
const struct mg_mqtt_opts *opts, uint8_t cmd) {
|
||||||
uint8_t qos_ = opts->qos & 3;
|
uint8_t qos_ = opts->qos & 3;
|
||||||
|
bool is_sub = cmd == MQTT_CMD_SUBSCRIBE;
|
||||||
size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0;
|
size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0;
|
||||||
size_t len = 2 + opts->topic.len + 2 + 1 + plen;
|
size_t len = 2 + opts->topic.len + 2 + (is_sub ? 1 : 0) + plen;
|
||||||
|
|
||||||
mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, (uint32_t) len);
|
if (!mqtt_send_header(c, cmd, 2, (uint32_t) len)) goto fail;
|
||||||
if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
|
if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
|
||||||
mg_send_u16(c, mg_htons(c->mgr->mqtt_id));
|
if (!mg_send_u16(c, mg_htons(c->mgr->mqtt_id))) goto fail;
|
||||||
if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
|
|
||||||
|
|
||||||
mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
|
if (c->is_mqtt5 && !mg_send_mqtt_properties(c, opts->props, opts->num_props))
|
||||||
mg_send(c, opts->topic.buf, opts->topic.len);
|
goto fail;
|
||||||
mg_send(c, &qos_, sizeof(qos_));
|
|
||||||
|
if (!mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)) ||
|
||||||
|
!mg_send(c, opts->topic.buf, opts->topic.len))
|
||||||
|
goto fail;
|
||||||
|
if (is_sub && !mg_send(c, &qos_, sizeof(qos_))) goto fail;
|
||||||
|
return;
|
||||||
|
fail:
|
||||||
|
mg_error(c, "OOM");
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
|
||||||
|
mg_mqtt_sub_unsub(c, opts, MQTT_CMD_SUBSCRIBE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_mqtt_unsub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
|
||||||
|
mg_mqtt_sub_unsub(c, opts, MQTT_CMD_UNSUBSCRIBE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
|
int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
|
||||||
@@ -427,8 +476,7 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
|
|||||||
m->data.len = (size_t) (end - p);
|
m->data.len = (size_t) (end - p);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return MQTT_OK;
|
return MQTT_OK;
|
||||||
}
|
}
|
||||||
@@ -466,15 +514,16 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
uint32_t remaining_len = sizeof(id);
|
uint32_t remaining_len = sizeof(id);
|
||||||
if (c->is_mqtt5) remaining_len += 2; // 3.4.2
|
if (c->is_mqtt5) remaining_len += 2; // 3.4.2
|
||||||
|
|
||||||
mg_mqtt_send_header(
|
if (!mqtt_send_header(c,
|
||||||
c,
|
(uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC
|
||||||
(uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC : MQTT_CMD_PUBACK),
|
: MQTT_CMD_PUBACK),
|
||||||
0, remaining_len);
|
0, remaining_len) ||
|
||||||
mg_send(c, &id, sizeof(id));
|
!mg_send(c, &id, sizeof(id)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (c->is_mqtt5) {
|
if (c->is_mqtt5) {
|
||||||
uint16_t zero = 0;
|
uint16_t zero = 0;
|
||||||
mg_send(c, &zero, sizeof(zero));
|
if (!mg_send(c, &zero, sizeof(zero))) goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mg_call(c, MG_EV_MQTT_MSG, &mm); // let the app handle qos stuff
|
mg_call(c, MG_EV_MQTT_MSG, &mm); // let the app handle qos stuff
|
||||||
@@ -483,15 +532,18 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc
|
case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc
|
||||||
uint16_t id = mg_ntohs(mm.id);
|
uint16_t id = mg_ntohs(mm.id);
|
||||||
uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1
|
uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1
|
||||||
mg_mqtt_send_header(c, MQTT_CMD_PUBREL, 2, remaining_len);
|
if (!mqtt_send_header(c, MQTT_CMD_PUBREL, 2,
|
||||||
mg_send(c, &id, sizeof(id)); // MQTT5 3.6.1-1, flags = 2
|
remaining_len) // MQTT5 3.6.1-1, flags = 2
|
||||||
|
|| !mg_send(c, &id, sizeof(id)))
|
||||||
|
goto fail;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc
|
case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc
|
||||||
uint16_t id = mg_ntohs(mm.id);
|
uint16_t id = mg_ntohs(mm.id);
|
||||||
uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1
|
uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1
|
||||||
mg_mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len);
|
if (!mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len) ||
|
||||||
mg_send(c, &id, sizeof(id));
|
!mg_send(c, &id, sizeof(id)))
|
||||||
|
goto fail;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -503,6 +555,9 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void) ev_data;
|
(void) ev_data;
|
||||||
|
return;
|
||||||
|
fail:
|
||||||
|
mg_error(c, "OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_mqtt_ping(struct mg_connection *nc) {
|
void mg_mqtt_ping(struct mg_connection *nc) {
|
||||||
@@ -517,19 +572,24 @@ void mg_mqtt_disconnect(struct mg_connection *c,
|
|||||||
const struct mg_mqtt_opts *opts) {
|
const struct mg_mqtt_opts *opts) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props);
|
if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props);
|
||||||
mg_mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len);
|
if (!mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len)) goto fail;
|
||||||
|
|
||||||
if (c->is_mqtt5) {
|
if (c->is_mqtt5) {
|
||||||
uint8_t zero = 0;
|
uint8_t zero = 0;
|
||||||
mg_send(c, &zero, sizeof(zero)); // reason code
|
if (!mg_send(c, &zero, sizeof(zero)) // reason code
|
||||||
mg_send_mqtt_properties(c, opts->props, opts->num_props);
|
|| !mg_send_mqtt_properties(c, opts->props, opts->num_props))
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
fail:
|
||||||
|
mg_error(c, "OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
|
struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
|
||||||
const struct mg_mqtt_opts *opts,
|
const struct mg_mqtt_opts *opts,
|
||||||
mg_event_handler_t fn, void *fn_data) {
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
struct mg_connection *c = mg_connect_svc(mgr, url, fn, fn_data, mqtt_cb, NULL);
|
struct mg_connection *c =
|
||||||
|
mg_connect_svc(mgr, url, fn, fn_data, mqtt_cb, NULL);
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
struct mg_mqtt_opts empty;
|
struct mg_mqtt_opts empty;
|
||||||
memset(&empty, 0, sizeof(empty));
|
memset(&empty, 0, sizeof(empty));
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
|
|||||||
void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
||||||
uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
||||||
void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts);
|
void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts);
|
||||||
|
void mg_mqtt_unsub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
|
||||||
int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
|
int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
|
||||||
void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
|
void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
|
||||||
uint32_t len);
|
uint32_t len);
|
||||||
|
|||||||
@@ -9,8 +9,14 @@
|
|||||||
|
|
||||||
size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) {
|
size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) {
|
||||||
size_t old = c->send.len;
|
size_t old = c->send.len;
|
||||||
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
|
size_t expected = mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
|
||||||
return c->send.len - old;
|
size_t actual = c->send.len - old;
|
||||||
|
if (actual != expected) {
|
||||||
|
mg_error(c, "OOM");
|
||||||
|
c->send.len = old;
|
||||||
|
actual = 0;
|
||||||
|
}
|
||||||
|
return actual;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
|
size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
|
||||||
@@ -25,14 +31,14 @@ size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
|
|||||||
static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
|
static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
|
||||||
uint32_t localhost = mg_htonl(0x7f000001);
|
uint32_t localhost = mg_htonl(0x7f000001);
|
||||||
if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false;
|
if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false;
|
||||||
memcpy(addr->ip, &localhost, sizeof(uint32_t));
|
memcpy(addr->addr.ip, &localhost, sizeof(uint32_t));
|
||||||
addr->is_ip6 = false;
|
addr->is_ip6 = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
|
static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
|
||||||
if (str.len > 0) return false;
|
if (str.len > 0) return false;
|
||||||
memset(addr->ip, 0, sizeof(addr->ip));
|
memset(addr->addr.ip, 0, sizeof(addr->addr.ip));
|
||||||
addr->is_ip6 = false;
|
addr->is_ip6 = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -53,7 +59,7 @@ static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (num_dots != 3 || str.buf[i - 1] == '.') return false;
|
if (num_dots != 3 || str.buf[i - 1] == '.') return false;
|
||||||
memcpy(&addr->ip, data, sizeof(data));
|
memcpy(&addr->addr.ip, data, sizeof(data));
|
||||||
addr->is_ip6 = false;
|
addr->is_ip6 = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -68,10 +74,10 @@ static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
|
|||||||
}
|
}
|
||||||
// struct mg_str s = mg_str_n(&str.buf[7], str.len - 7);
|
// struct mg_str s = mg_str_n(&str.buf[7], str.len - 7);
|
||||||
if (!mg_aton4(mg_str_n(&str.buf[7], str.len - 7), addr)) return false;
|
if (!mg_aton4(mg_str_n(&str.buf[7], str.len - 7), addr)) return false;
|
||||||
memcpy(&ipv4, addr->ip, sizeof(ipv4));
|
memcpy(&ipv4, addr->addr.ip, sizeof(ipv4));
|
||||||
memset(addr->ip, 0, sizeof(addr->ip));
|
memset(addr->addr.ip, 0, sizeof(addr->addr.ip));
|
||||||
addr->ip[10] = addr->ip[11] = 255;
|
addr->addr.ip[10] = addr->addr.ip[11] = 255;
|
||||||
memcpy(&addr->ip[12], &ipv4, 4);
|
memcpy(&addr->addr.ip[12], &ipv4, 4);
|
||||||
addr->is_ip6 = true;
|
addr->is_ip6 = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -80,7 +86,7 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
|
|||||||
size_t i, j = 0, n = 0, dc = 42;
|
size_t i, j = 0, n = 0, dc = 42;
|
||||||
addr->scope_id = 0;
|
addr->scope_id = 0;
|
||||||
if (str.len > 2 && str.buf[0] == '[') str.buf++, str.len -= 2;
|
if (str.len > 2 && str.buf[0] == '[') str.buf++, str.len -= 2;
|
||||||
if (mg_v4mapped(str, addr)) return true;
|
if (mg_v4mapped(str, addr)) return true; // sets addr->is_ip6
|
||||||
for (i = 0; i < str.len; i++) {
|
for (i = 0; i < str.len; i++) {
|
||||||
if ((str.buf[i] >= '0' && str.buf[i] <= '9') ||
|
if ((str.buf[i] >= '0' && str.buf[i] <= '9') ||
|
||||||
(str.buf[i] >= 'a' && str.buf[i] <= 'f') ||
|
(str.buf[i] >= 'a' && str.buf[i] <= 'f') ||
|
||||||
@@ -89,8 +95,8 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
|
|||||||
if (i > j + 3) return false;
|
if (i > j + 3) return false;
|
||||||
// MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j]));
|
// MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j]));
|
||||||
mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val));
|
mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val));
|
||||||
addr->ip[n] = (uint8_t) ((val >> 8) & 255);
|
addr->addr.ip[n] = (uint8_t) ((val >> 8) & 255);
|
||||||
addr->ip[n + 1] = (uint8_t) (val & 255);
|
addr->addr.ip[n + 1] = (uint8_t) (val & 255);
|
||||||
} else if (str.buf[i] == ':') {
|
} else if (str.buf[i] == ':') {
|
||||||
j = i + 1;
|
j = i + 1;
|
||||||
if (i > 0 && str.buf[i - 1] == ':') {
|
if (i > 0 && str.buf[i - 1] == ':') {
|
||||||
@@ -100,18 +106,23 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
|
|||||||
n += 2;
|
n += 2;
|
||||||
}
|
}
|
||||||
if (n > 14) return false;
|
if (n > 14) return false;
|
||||||
addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
|
addr->addr.ip[n] = addr->addr.ip[n + 1] = 0; // For trailing ::
|
||||||
} else if (str.buf[i] == '%') { // Scope ID, last in string
|
} else if (str.buf[i] == '%') { // Scope ID, last in string
|
||||||
return mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10,
|
if (mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10,
|
||||||
&addr->scope_id, sizeof(uint8_t));
|
&addr->scope_id, sizeof(uint8_t))) {
|
||||||
|
addr->is_ip6 = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (n < 14 && dc == 42) return false;
|
if (n < 14 && dc == 42) return false;
|
||||||
if (n < 14) {
|
if (n < 14) {
|
||||||
memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2);
|
memmove(&addr->addr.ip[dc + (14 - n)], &addr->addr.ip[dc], n - dc + 2);
|
||||||
memset(&addr->ip[dc], 0, 14 - n);
|
memset(&addr->addr.ip[dc], 0, 14 - n);
|
||||||
}
|
}
|
||||||
|
|
||||||
addr->is_ip6 = true;
|
addr->is_ip6 = true;
|
||||||
@@ -162,6 +173,10 @@ struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
|
|||||||
struct mg_connection *c = NULL;
|
struct mg_connection *c = NULL;
|
||||||
if (url == NULL || url[0] == '\0') {
|
if (url == NULL || url[0] == '\0') {
|
||||||
MG_ERROR(("null url"));
|
MG_ERROR(("null url"));
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
} else if (mgr->ifp != NULL && mgr->ifp->state != MG_TCPIP_STATE_READY) {
|
||||||
|
MG_ERROR(("Network is down"));
|
||||||
|
#endif
|
||||||
} else if ((c = mg_alloc_conn(mgr)) == NULL) {
|
} else if ((c = mg_alloc_conn(mgr)) == NULL) {
|
||||||
MG_ERROR(("OOM"));
|
MG_ERROR(("OOM"));
|
||||||
} else {
|
} else {
|
||||||
@@ -295,3 +310,13 @@ void mg_mgr_init(struct mg_mgr *mgr) {
|
|||||||
: MG_TLS == MG_TLS_WOLFSSL ? "WolfSSL"
|
: MG_TLS == MG_TLS_WOLFSSL ? "WolfSSL"
|
||||||
: "custom"));
|
: "custom"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
void mg_tcpip_mapip(struct mg_connection *, struct mg_addr *);
|
||||||
|
#endif
|
||||||
|
void mg_multicast_restore(struct mg_connection *c, uint8_t *from) {
|
||||||
|
memcpy(&c->rem, from, sizeof(c->rem));
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
mg_tcpip_mapip(c, &c->rem);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -14,7 +14,11 @@ struct mg_dns {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mg_addr {
|
struct mg_addr {
|
||||||
uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order
|
union { // Holds IPv4 or IPv6 address, in network byte order
|
||||||
|
uint8_t ip[16];
|
||||||
|
uint32_t ip4;
|
||||||
|
uint64_t ip6[2];
|
||||||
|
} addr;
|
||||||
uint16_t port; // TCP or UDP port in network byte order
|
uint16_t port; // TCP or UDP port in network byte order
|
||||||
uint8_t scope_id; // IPv6 scope ID
|
uint8_t scope_id; // IPv6 scope ID
|
||||||
bool is_ip6; // True when address is IPv6 address
|
bool is_ip6; // True when address is IPv6 address
|
||||||
@@ -108,3 +112,4 @@ struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
|
|||||||
struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
|
struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data,
|
mg_event_handler_t fn, void *fn_data,
|
||||||
mg_event_handler_t pfn, void *pfn_data);
|
mg_event_handler_t pfn, void *pfn_data);
|
||||||
|
void mg_multicast_restore(struct mg_connection *c, uint8_t *from);
|
||||||
+1350
-441
File diff suppressed because it is too large.
Load diff
+84
-26
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
|
#include "l2.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
@@ -20,45 +21,58 @@ typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev,
|
|||||||
void *ev_data);
|
void *ev_data);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
|
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
|
||||||
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
|
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
|
||||||
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
|
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
|
||||||
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
|
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
|
||||||
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
|
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
|
||||||
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct mg_wifi_scan_bss_data *
|
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct
|
||||||
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
|
// mg_wifi_scan_bss_data *
|
||||||
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and chip specific
|
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
|
||||||
MG_TCPIP_EV_DRIVER, // Driver event driver specific
|
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and
|
||||||
MG_TCPIP_EV_USER // Starting ID for user events
|
// chip specific
|
||||||
|
MG_TCPIP_EV_DRIVER, // Driver event driver specific
|
||||||
|
MG_TCPIP_EV_ST6_CHG, // state6 change uint8_t *
|
||||||
|
// (&ifp->state6)
|
||||||
|
MG_TCPIP_EV_USER // Starting ID for user events
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Network interface
|
// Network interface
|
||||||
struct mg_tcpip_if {
|
struct mg_tcpip_if {
|
||||||
uint8_t mac[6]; // MAC address. Must be set to a valid MAC
|
uint8_t mac[sizeof(struct mg_l2addr)]; // hw address. Set to a valid addr
|
||||||
uint32_t ip, mask, gw; // IP address, mask, default gateway
|
uint32_t ip, mask, gw; // IP address, mask, default gateway
|
||||||
struct mg_str tx; // Output (TX) buffer
|
struct mg_str tx; // Output (TX) buffer
|
||||||
bool enable_dhcp_client; // Enable DCHP client
|
bool enable_dhcp_client; // Enable DCHP client
|
||||||
bool enable_dhcp_server; // Enable DCHP server
|
bool enable_dhcp_server; // Enable DCHP server
|
||||||
bool enable_get_gateway; // DCHP server sets client as gateway
|
bool enable_get_gateway; // DCHP server sets client as gateway
|
||||||
bool enable_req_dns; // DCHP client requests DNS server
|
bool enable_req_dns; // DCHP client requests DNS server
|
||||||
bool enable_req_sntp; // DCHP client requests SNTP server
|
bool enable_req_sntp; // DCHP client requests SNTP server
|
||||||
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
|
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
|
||||||
bool enable_mac_check; // Do a MAC check on RX frames
|
bool enable_mac_check; // Do a MAC check on RX frames
|
||||||
bool update_mac_hash_table; // Signal drivers to update MAC controller
|
bool update_mac_hash_table; // Signal drivers to update MAC controller
|
||||||
struct mg_tcpip_driver *driver; // Low level driver
|
struct mg_tcpip_driver *driver; // Low level driver
|
||||||
void *driver_data; // Driver-specific data
|
void *driver_data; // Driver-specific data
|
||||||
|
mg_tcpip_event_handler_t pfn; // Driver-specific event handler function
|
||||||
mg_tcpip_event_handler_t fn; // User-specified event handler function
|
mg_tcpip_event_handler_t fn; // User-specified event handler function
|
||||||
struct mg_mgr *mgr; // Mongoose event manager
|
struct mg_mgr *mgr; // Mongoose event manager
|
||||||
struct mg_queue recv_queue; // Receive queue
|
struct mg_queue recv_queue; // Receive queue
|
||||||
char dhcp_name[12]; // Name reported to DHCP, "mip" if unset
|
char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Name for DHCP, "mip" if unset
|
||||||
uint16_t mtu; // Interface MTU
|
uint16_t mtu; // Interface link payload
|
||||||
#define MG_TCPIP_MTU_DEFAULT 1500
|
uint16_t framesize; // Interface frame max length
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses,
|
||||||
|
uint8_t prefix[8]; // prefix,
|
||||||
|
uint8_t prefix_len; // prefix length,
|
||||||
|
uint64_t gw6[2]; // default gateway.
|
||||||
|
bool enable_slaac; // Enable IPv6 address autoconfiguration
|
||||||
|
bool enable_dhcp6_client; // Enable DCHPv6 client TODO()
|
||||||
|
#endif
|
||||||
|
|
||||||
// Internal state, user can use it but should not change it
|
// Internal state, user can use it but should not change it
|
||||||
uint8_t gwmac[6]; // Router's MAC
|
uint8_t gwmac[sizeof(struct mg_l2addr)]; // Router's hw address
|
||||||
char *dns4_url; // DNS server URL
|
enum mg_l2type l2type; // Ethernet, PPP, etc.
|
||||||
uint64_t now; // Current time
|
char *dns4_url; // DNS server URL
|
||||||
|
uint64_t now; // Current time
|
||||||
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
|
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
|
||||||
uint64_t lease_expire; // Lease expiration time, in ms
|
uint64_t lease_expire; // Lease expiration time, in ms
|
||||||
uint16_t eport; // Next ephemeral port
|
uint16_t eport; // Next ephemeral port
|
||||||
@@ -66,12 +80,18 @@ struct mg_tcpip_if {
|
|||||||
volatile uint32_t nrecv; // Number of received frames
|
volatile uint32_t nrecv; // Number of received frames
|
||||||
volatile uint32_t nsent; // Number of transmitted frames
|
volatile uint32_t nsent; // Number of transmitted frames
|
||||||
volatile uint32_t nerr; // Number of driver errors
|
volatile uint32_t nerr; // Number of driver errors
|
||||||
uint8_t state; // Current state
|
uint8_t state; // Current link and IPv4 state
|
||||||
#define MG_TCPIP_STATE_DOWN 0 // Interface is down
|
#define MG_TCPIP_STATE_DOWN 0 // Interface is down
|
||||||
#define MG_TCPIP_STATE_UP 1 // Interface is up
|
#define MG_TCPIP_STATE_UP 1 // Interface is up
|
||||||
#define MG_TCPIP_STATE_REQ 2 // Interface is up, DHCP REQUESTING state
|
#define MG_TCPIP_STATE_REQ 2 // Interface is up, DHCP REQUESTING state
|
||||||
#define MG_TCPIP_STATE_IP 3 // Interface is up and has an IP assigned
|
#define MG_TCPIP_STATE_IP 3 // Interface is up and has an IP assigned
|
||||||
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work
|
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work
|
||||||
|
bool gw_ready; // We've got a hw address for the router
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
uint8_t gw6mac[sizeof(struct mg_l2addr)]; // IPV6 Router's hw address
|
||||||
|
uint8_t state6; // Current IPv6 state
|
||||||
|
bool gw6_ready; // We've got a hw address for the IPv6 router
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
|
void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
|
||||||
@@ -95,6 +115,8 @@ extern struct mg_tcpip_driver mg_tcpip_driver_ppp;
|
|||||||
extern struct mg_tcpip_driver mg_tcpip_driver_pico_w;
|
extern struct mg_tcpip_driver mg_tcpip_driver_pico_w;
|
||||||
extern struct mg_tcpip_driver mg_tcpip_driver_rw612;
|
extern struct mg_tcpip_driver mg_tcpip_driver_rw612;
|
||||||
extern struct mg_tcpip_driver mg_tcpip_driver_cyw;
|
extern struct mg_tcpip_driver mg_tcpip_driver_cyw;
|
||||||
|
extern struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi;
|
||||||
|
extern struct mg_tcpip_driver mg_tcpip_driver_st67w6;
|
||||||
|
|
||||||
// Drivers that require SPI, can use this SPI abstraction
|
// Drivers that require SPI, can use this SPI abstraction
|
||||||
struct mg_tcpip_spi {
|
struct mg_tcpip_spi {
|
||||||
@@ -104,5 +126,41 @@ struct mg_tcpip_spi {
|
|||||||
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
|
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Alignment and memory section requirements
|
||||||
|
#ifndef MG_8BYTE_ALIGNED
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U))))
|
||||||
|
#else
|
||||||
|
#define MG_8BYTE_ALIGNED
|
||||||
|
#endif // compiler
|
||||||
|
#endif // 8BYTE_ALIGNED
|
||||||
|
|
||||||
|
#ifndef MG_16BYTE_ALIGNED
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define MG_16BYTE_ALIGNED __attribute__((aligned((16U))))
|
||||||
|
#else
|
||||||
|
#define MG_16BYTE_ALIGNED
|
||||||
|
#endif // compiler
|
||||||
|
#endif // 16BYTE_ALIGNED
|
||||||
|
|
||||||
|
#ifndef MG_32BYTE_ALIGNED
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define MG_32BYTE_ALIGNED __attribute__((aligned((32U))))
|
||||||
|
#else
|
||||||
|
#define MG_32BYTE_ALIGNED
|
||||||
|
#endif // compiler
|
||||||
|
#endif // 32BYTE_ALIGNED
|
||||||
|
|
||||||
|
#ifndef MG_64BYTE_ALIGNED
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define MG_64BYTE_ALIGNED __attribute__((aligned((64U))))
|
||||||
|
#else
|
||||||
|
#define MG_64BYTE_ALIGNED
|
||||||
|
#endif // compiler
|
||||||
|
#endif // 64BYTE_ALIGNED
|
||||||
|
|
||||||
|
#ifndef MG_ETH_RAM
|
||||||
|
#define MG_ETH_RAM
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
#define MG_OTA_RT1060 302 // IMXRT1060
|
#define MG_OTA_RT1060 302 // IMXRT1060
|
||||||
#define MG_OTA_RT1064 303 // IMXRT1064
|
#define MG_OTA_RT1064 303 // IMXRT1064
|
||||||
#define MG_OTA_RT1170 304 // IMXRT1170
|
#define MG_OTA_RT1170 304 // IMXRT1170
|
||||||
#define MG_OTA_MCXN 310 // MCXN947
|
#define MG_OTA_MCXN 310 // MCXN947
|
||||||
#define MG_OTA_FRDM 320 // FRDM-RW612
|
#define MG_OTA_RW612 320 // FRDM-RW612
|
||||||
#define MG_OTA_FLASH 900 // OTA via an internal flash
|
#define MG_OTA_FLASH 900 // OTA via an internal flash
|
||||||
#define MG_OTA_ESP32 910 // ESP32 OTA implementation
|
#define MG_OTA_ESP32 910 // ESP32 OTA implementation
|
||||||
#define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash
|
#define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "ota.h"
|
#include "ota.h"
|
||||||
|
|
||||||
#if MG_OTA == MG_OTA_FRDM
|
#if MG_OTA == MG_OTA_RW612
|
||||||
|
|
||||||
MG_IRAM static bool mg_frdm_write(void *, const void *, size_t);
|
MG_IRAM static bool mg_frdm_write(void *, const void *, size_t);
|
||||||
static bool mg_frdm_swap(void);
|
static bool mg_frdm_swap(void);
|
||||||
+38
-25
@@ -1,25 +1,20 @@
|
|||||||
#include "printf.h"
|
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
|
#include "printf.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
size_t mg_queue_vprintf(struct mg_queue *q, const char *fmt, va_list *ap) {
|
|
||||||
size_t len = mg_snprintf(NULL, 0, fmt, ap);
|
|
||||||
char *buf;
|
|
||||||
if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1) {
|
|
||||||
len = 0; // Nah. Not enough space
|
|
||||||
} else {
|
|
||||||
len = mg_vsnprintf((char *) buf, len + 1, fmt, ap);
|
|
||||||
mg_queue_add(q, len);
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) {
|
size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) {
|
||||||
va_list ap;
|
char *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
va_start(ap, fmt);
|
va_list ap1, ap2;
|
||||||
len = mg_queue_vprintf(q, fmt, &ap);
|
va_start(ap1, fmt);
|
||||||
va_end(ap);
|
len = mg_vsnprintf(NULL, 0, fmt, &ap1);
|
||||||
|
va_end(ap1);
|
||||||
|
if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1)
|
||||||
|
return 0; // Nah. Not enough space
|
||||||
|
va_start(ap2, fmt);
|
||||||
|
len = mg_vsnprintf(buf, len + 1, fmt, &ap2);
|
||||||
|
mg_queue_add(q, len);
|
||||||
|
va_end(ap2);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +29,7 @@ static void mg_pfn_iobuf_private(char ch, void *param, bool expand) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mg_putchar_iobuf_static(char ch, void *param) {
|
void mg_pfn_iobuf_noresize(char ch, void *param) {
|
||||||
mg_pfn_iobuf_private(ch, param, false);
|
mg_pfn_iobuf_private(ch, param, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,8 +38,10 @@ void mg_pfn_iobuf(char ch, void *param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) {
|
size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) {
|
||||||
struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0};
|
struct mg_iobuf io = {0, 0, 0, 0};
|
||||||
size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap);
|
size_t n;
|
||||||
|
io.buf = (uint8_t *) buf, io.size = len;
|
||||||
|
n = mg_vxprintf(mg_pfn_iobuf_noresize, &io, fmt, ap);
|
||||||
if (n < len) buf[n] = '\0';
|
if (n < len) buf[n] = '\0';
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -101,8 +98,8 @@ size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) {
|
|||||||
|
|
||||||
size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
|
size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
|
||||||
struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
|
struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
|
||||||
if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip);
|
if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->addr.ip);
|
||||||
return print_ip4(out, arg, (uint8_t *) &addr->ip);
|
return print_ip4(out, arg, (uint8_t *) &addr->addr.ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) {
|
size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) {
|
||||||
@@ -110,12 +107,27 @@ size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) {
|
|||||||
return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port));
|
return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) {
|
static size_t print_mac(void (*out)(char, void *), void *arg, uint8_t *p) {
|
||||||
uint8_t *p = va_arg(*ap, uint8_t *);
|
|
||||||
return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2],
|
return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2],
|
||||||
p[3], p[4], p[5]);
|
p[3], p[4], p[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) {
|
||||||
|
uint8_t *p = va_arg(*ap, uint8_t *);
|
||||||
|
return print_mac(out, arg, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP
|
||||||
|
size_t mg_print_l2addr(void (*out)(char, void *), void *arg, va_list *ap) {
|
||||||
|
enum mg_l2type type = (enum mg_l2type) va_arg(*ap, int);
|
||||||
|
if (type == MG_TCPIP_L2_ETH) {
|
||||||
|
uint8_t *p = va_arg(*ap, uint8_t *);
|
||||||
|
return print_mac(out, arg, p);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static char mg_esc(int c, bool esc) {
|
static char mg_esc(int c, bool esc) {
|
||||||
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
|
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
|
||||||
for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
|
for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
|
||||||
@@ -150,7 +162,8 @@ static size_t bcpy(void (*out)(char, void *), void *arg, uint8_t *buf,
|
|||||||
for (i = 0; i < len; i += 3) {
|
for (i = 0; i < len; i += 3) {
|
||||||
uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0,
|
uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0,
|
||||||
c3 = i + 2 < len ? buf[i + 2] : 0;
|
c3 = i + 2 < len ? buf[i + 2] : 0;
|
||||||
char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='};
|
char tmp[4] = {0, 0, '=', '='};
|
||||||
|
tmp[0] = t[c1 >> 2], tmp[1] = t[(c1 & 3) << 4 | (c2 >> 4)];
|
||||||
if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)];
|
if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)];
|
||||||
if (i + 2 < len) tmp[3] = t[c3 & 63];
|
if (i + 2 < len) tmp[3] = t[c3 & 63];
|
||||||
for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg);
|
for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg);
|
||||||
|
|||||||
+4
-3
@@ -9,7 +9,6 @@ size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap);
|
|||||||
size_t mg_snprintf(char *, size_t, const char *fmt, ...);
|
size_t mg_snprintf(char *, size_t, const char *fmt, ...);
|
||||||
char *mg_vmprintf(const char *fmt, va_list *ap);
|
char *mg_vmprintf(const char *fmt, va_list *ap);
|
||||||
char *mg_mprintf(const char *fmt, ...);
|
char *mg_mprintf(const char *fmt, ...);
|
||||||
size_t mg_queue_vprintf(struct mg_queue *, const char *fmt, va_list *);
|
|
||||||
size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
|
size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
|
||||||
|
|
||||||
// %M print helper functions
|
// %M print helper functions
|
||||||
@@ -21,10 +20,12 @@ size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap);
|
|||||||
size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap);
|
size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap);
|
||||||
size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap);
|
size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap);
|
||||||
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap);
|
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap);
|
||||||
|
size_t mg_print_l2addr(void (*out)(char, void *), void *arg, va_list *ap);
|
||||||
|
|
||||||
// Various output functions
|
// Various output functions
|
||||||
void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf *
|
void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf *
|
||||||
void mg_pfn_stdout(char c, void *param); // param: ignored
|
void mg_pfn_iobuf_noresize(char ch, void *param); // param: struct mg_iobuf *
|
||||||
|
void mg_pfn_stdout(char c, void *param); // param: ignored
|
||||||
|
|
||||||
// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
|
// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
|
||||||
#define MG_ESC(str) mg_print_esc, 0, (str)
|
#define MG_ESC(str) mg_print_esc, 0, (str)
|
||||||
+43
-1
@@ -180,6 +180,35 @@ void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data,
|
|||||||
#define sig164(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ ((x) >> 6))
|
#define sig164(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ ((x) >> 6))
|
||||||
|
|
||||||
static const uint64_t mg_sha256_k2[80] = {
|
static const uint64_t mg_sha256_k2[80] = {
|
||||||
|
#if defined(__DCC__)
|
||||||
|
0x428a2f98d728ae22ull, 0x7137449123ef65cdull, 0xb5c0fbcfec4d3b2full,
|
||||||
|
0xe9b5dba58189dbbcull, 0x3956c25bf348b538ull, 0x59f111f1b605d019ull,
|
||||||
|
0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull, 0xd807aa98a3030242ull,
|
||||||
|
0x12835b0145706fbeull, 0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull,
|
||||||
|
0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull, 0x9bdc06a725c71235ull,
|
||||||
|
0xc19bf174cf692694ull, 0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull,
|
||||||
|
0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull, 0x2de92c6f592b0275ull,
|
||||||
|
0x4a7484aa6ea6e483ull, 0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull,
|
||||||
|
0x983e5152ee66dfabull, 0xa831c66d2db43210ull, 0xb00327c898fb213full,
|
||||||
|
0xbf597fc7beef0ee4ull, 0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull,
|
||||||
|
0x06ca6351e003826full, 0x142929670a0e6e70ull, 0x27b70a8546d22ffcull,
|
||||||
|
0x2e1b21385c26c926ull, 0x4d2c6dfc5ac42aedull, 0x53380d139d95b3dfull,
|
||||||
|
0x650a73548baf63deull, 0x766a0abb3c77b2a8ull, 0x81c2c92e47edaee6ull,
|
||||||
|
0x92722c851482353bull, 0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull,
|
||||||
|
0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull, 0xd192e819d6ef5218ull,
|
||||||
|
0xd69906245565a910ull, 0xf40e35855771202aull, 0x106aa07032bbd1b8ull,
|
||||||
|
0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull, 0x2748774cdf8eeb99ull,
|
||||||
|
0x34b0bcb5e19b48a8ull, 0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull,
|
||||||
|
0x5b9cca4f7763e373ull, 0x682e6ff3d6b2b8a3ull, 0x748f82ee5defb2fcull,
|
||||||
|
0x78a5636f43172f60ull, 0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull,
|
||||||
|
0x90befffa23631e28ull, 0xa4506cebde82bde9ull, 0xbef9a3f7b2c67915ull,
|
||||||
|
0xc67178f2e372532bull, 0xca273eceea26619cull, 0xd186b8c721c0c207ull,
|
||||||
|
0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull, 0x06f067aa72176fbaull,
|
||||||
|
0x0a637dc5a2c898a6ull, 0x113f9804bef90daeull, 0x1b710b35131c471bull,
|
||||||
|
0x28db77f523047d84ull, 0x32caab7b40c72493ull, 0x3c9ebe0a15c9bebcull,
|
||||||
|
0x431d67c49c100d4cull, 0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull,
|
||||||
|
0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull
|
||||||
|
#else
|
||||||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
|
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
|
||||||
0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
|
0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
|
||||||
0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
|
0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
|
||||||
@@ -206,7 +235,9 @@ static const uint64_t mg_sha256_k2[80] = {
|
|||||||
0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
|
0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
|
||||||
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
|
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
|
||||||
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
|
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
|
||||||
0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
|
0x5fcb6fab3ad6faec, 0x6c44198c4a475817
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
static void mg_sha384_transform(mg_sha384_ctx *ctx, const uint8_t data[]) {
|
static void mg_sha384_transform(mg_sha384_ctx *ctx, const uint8_t data[]) {
|
||||||
uint64_t m[80];
|
uint64_t m[80];
|
||||||
@@ -257,6 +288,16 @@ void mg_sha384_init(mg_sha384_ctx *ctx) {
|
|||||||
ctx->datalen = 0;
|
ctx->datalen = 0;
|
||||||
ctx->bitlen[0] = 0;
|
ctx->bitlen[0] = 0;
|
||||||
ctx->bitlen[1] = 0;
|
ctx->bitlen[1] = 0;
|
||||||
|
#if defined(__DCC__)
|
||||||
|
ctx->state[0] = 0xcbbb9d5dc1059ed8ull;
|
||||||
|
ctx->state[1] = 0x629a292a367cd507ull;
|
||||||
|
ctx->state[2] = 0x9159015a3070dd17ull;
|
||||||
|
ctx->state[3] = 0x152fecd8f70e5939ull;
|
||||||
|
ctx->state[4] = 0x67332667ffc00b31ull;
|
||||||
|
ctx->state[5] = 0x8eb44a8768581511ull;
|
||||||
|
ctx->state[6] = 0xdb0c2e0d64f98fa7ull;
|
||||||
|
ctx->state[7] = 0x47b5481dbefa4fa4ull;
|
||||||
|
#else
|
||||||
ctx->state[0] = 0xcbbb9d5dc1059ed8;
|
ctx->state[0] = 0xcbbb9d5dc1059ed8;
|
||||||
ctx->state[1] = 0x629a292a367cd507;
|
ctx->state[1] = 0x629a292a367cd507;
|
||||||
ctx->state[2] = 0x9159015a3070dd17;
|
ctx->state[2] = 0x9159015a3070dd17;
|
||||||
@@ -265,6 +306,7 @@ void mg_sha384_init(mg_sha384_ctx *ctx) {
|
|||||||
ctx->state[5] = 0x8eb44a8768581511;
|
ctx->state[5] = 0x8eb44a8768581511;
|
||||||
ctx->state[6] = 0xdb0c2e0d64f98fa7;
|
ctx->state[6] = 0xdb0c2e0d64f98fa7;
|
||||||
ctx->state[7] = 0x47b5481dbefa4fa4;
|
ctx->state[7] = 0x47b5481dbefa4fa4;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len) {
|
void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len) {
|
||||||
|
|||||||
+50
-21
@@ -57,13 +57,13 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
|
|||||||
memset(usa, 0, sizeof(*usa));
|
memset(usa, 0, sizeof(*usa));
|
||||||
usa->sin.sin_family = AF_INET;
|
usa->sin.sin_family = AF_INET;
|
||||||
usa->sin.sin_port = a->port;
|
usa->sin.sin_port = a->port;
|
||||||
memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t));
|
memcpy(&usa->sin.sin_addr, a->addr.ip, sizeof(uint32_t));
|
||||||
#if MG_ENABLE_IPV6
|
#if MG_ENABLE_IPV6
|
||||||
if (a->is_ip6) {
|
if (a->is_ip6) {
|
||||||
usa->sin.sin_family = AF_INET6;
|
usa->sin.sin_family = AF_INET6;
|
||||||
usa->sin6.sin6_port = a->port;
|
usa->sin6.sin6_port = a->port;
|
||||||
usa->sin6.sin6_scope_id = a->scope_id;
|
usa->sin6.sin6_scope_id = a->scope_id;
|
||||||
memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip));
|
memcpy(&usa->sin6.sin6_addr, a->addr.ip, sizeof(a->addr.ip));
|
||||||
len = sizeof(usa->sin6);
|
len = sizeof(usa->sin6);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -72,15 +72,17 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
|
|||||||
|
|
||||||
static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
|
static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
|
||||||
a->is_ip6 = is_ip6;
|
a->is_ip6 = is_ip6;
|
||||||
a->port = usa->sin.sin_port;
|
|
||||||
memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t));
|
|
||||||
#if MG_ENABLE_IPV6
|
#if MG_ENABLE_IPV6
|
||||||
if (is_ip6) {
|
if (is_ip6) {
|
||||||
memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip));
|
memcpy(a->addr.ip, &usa->sin6.sin6_addr, sizeof(a->addr.ip));
|
||||||
a->port = usa->sin6.sin6_port;
|
a->port = usa->sin6.sin6_port;
|
||||||
a->scope_id = (uint8_t) usa->sin6.sin6_scope_id;
|
a->scope_id = (uint8_t) usa->sin6.sin6_scope_id;
|
||||||
}
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
a->port = usa->sin.sin_port;
|
||||||
|
memcpy(&a->addr.ip, &usa->sin.sin_addr, sizeof(uint32_t));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) {
|
static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) {
|
||||||
@@ -91,6 +93,29 @@ static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the local 'addr' the stack will use to connect to 'to'
|
||||||
|
void mg_getlocaddr(struct mg_connection *c, struct mg_addr *to, struct mg_addr *addr);
|
||||||
|
void mg_getlocaddr(struct mg_connection *c, struct mg_addr *to, struct mg_addr *addr) {
|
||||||
|
union usa usa;
|
||||||
|
socklen_t slen;
|
||||||
|
MG_SOCKET_TYPE fd;
|
||||||
|
int rc, af = to->is_ip6 ? AF_INET6 : AF_INET;
|
||||||
|
fd = socket(af, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if (fd == MG_INVALID_SOCKET) {
|
||||||
|
mg_error(c, "socket(): %d", MG_SOCK_ERR(-1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// NOTE(): TI-RTOS NDK may require binding
|
||||||
|
slen = tousa(to, &usa);
|
||||||
|
if ((rc = connect(fd, &usa.sa, slen)) != 0) {
|
||||||
|
mg_error(c, "connect: %d", MG_SOCK_ERR(rc));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setlocaddr(fd, addr);
|
||||||
|
closesocket(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void iolog(struct mg_connection *c, char *buf, long n, bool r) {
|
static void iolog(struct mg_connection *c, char *buf, long n, bool r) {
|
||||||
if (n == MG_IO_WAIT) {
|
if (n == MG_IO_WAIT) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
@@ -141,7 +166,9 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
|
|||||||
iolog(c, (char *) buf, n, false);
|
iolog(c, (char *) buf, n, false);
|
||||||
return n > 0;
|
return n > 0;
|
||||||
} else {
|
} else {
|
||||||
return mg_iobuf_add(&c->send, c->send.len, buf, len);
|
return len == 0 || mg_iobuf_add(&c->send, c->send.len, buf, len) > 0;
|
||||||
|
// returning 0 means an OOM condition (iobuf couldn't resize), yet this is
|
||||||
|
// so far recoverable, let the caller decide
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +190,7 @@ static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
|
|||||||
#elif MG_ARCH == MG_ARCH_THREADX
|
#elif MG_ARCH == MG_ARCH_THREADX
|
||||||
// NetxDuo fails to send large blocks of data to the non-blocking sockets
|
// NetxDuo fails to send large blocks of data to the non-blocking sockets
|
||||||
(void) fd;
|
(void) fd;
|
||||||
//fcntl(fd, F_SETFL, O_NONBLOCK);
|
// fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||||
#elif MG_ARCH == MG_ARCH_TIRTOS
|
#elif MG_ARCH == MG_ARCH_TIRTOS
|
||||||
int val = 0;
|
int val = 0;
|
||||||
setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
|
setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
|
||||||
@@ -181,7 +208,7 @@ static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
|
|||||||
void mg_multicast_add(struct mg_connection *c, char *ip);
|
void mg_multicast_add(struct mg_connection *c, char *ip);
|
||||||
void mg_multicast_add(struct mg_connection *c, char *ip) {
|
void mg_multicast_add(struct mg_connection *c, char *ip) {
|
||||||
#if MG_ENABLE_RL
|
#if MG_ENABLE_RL
|
||||||
#error UNSUPPORTED
|
MG_ERROR(("unsupported"));
|
||||||
#elif MG_ENABLE_FREERTOS_TCP
|
#elif MG_ENABLE_FREERTOS_TCP
|
||||||
// TODO(): prvAllowIPPacketIPv4()
|
// TODO(): prvAllowIPPacketIPv4()
|
||||||
#else
|
#else
|
||||||
@@ -195,9 +222,10 @@ void mg_multicast_add(struct mg_connection *c, char *ip) {
|
|||||||
struct ip_mreq mreq;
|
struct ip_mreq mreq;
|
||||||
mreq.imr_multiaddr.s_addr = inet_addr(ip);
|
mreq.imr_multiaddr.s_addr = inet_addr(ip);
|
||||||
mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY);
|
mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY);
|
||||||
setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
|
setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq,
|
||||||
#endif // !Zephyr
|
sizeof(mreq));
|
||||||
#endif // !lwIP
|
#endif // !Zephyr
|
||||||
|
#endif // !lwIP
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,9 +343,9 @@ static void read_conn(struct mg_connection *c) {
|
|||||||
if (n == MG_IO_ERR || n == MG_IO_RESET) { // Windows, see #3031
|
if (n == MG_IO_ERR || n == MG_IO_RESET) { // Windows, see #3031
|
||||||
if (c->rtls.len == 0 || m < 0) {
|
if (c->rtls.len == 0 || m < 0) {
|
||||||
// Close only when we have fully drained both rtls and TLS buffers
|
// Close only when we have fully drained both rtls and TLS buffers
|
||||||
c->is_closing = 1; // or there's nothing we can do about it.
|
c->is_closing = 1; // or there's nothing we can do about it.
|
||||||
if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104
|
if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104
|
||||||
} else { // see #2885
|
} else { // see #2885
|
||||||
// TLS buffer is capped to max record size, even though, there can
|
// TLS buffer is capped to max record size, even though, there can
|
||||||
// be more than one record, give TLS a chance to process them.
|
// be more than one record, give TLS a chance to process them.
|
||||||
}
|
}
|
||||||
@@ -338,6 +366,7 @@ static void write_conn(struct mg_connection *c) {
|
|||||||
char *buf = (char *) c->send.buf;
|
char *buf = (char *) c->send.buf;
|
||||||
size_t len = c->send.len;
|
size_t len = c->send.len;
|
||||||
long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len);
|
long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len);
|
||||||
|
// TODO(): mg_tls_send() may return 0 forever on steady OOM
|
||||||
MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
|
MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
|
||||||
(long) c->send.len, (long) c->send.size, (long) c->recv.len,
|
(long) c->send.len, (long) c->send.size, (long) c->recv.len,
|
||||||
(long) c->recv.size, n, MG_SOCK_ERR(n)));
|
(long) c->recv.size, n, MG_SOCK_ERR(n)));
|
||||||
@@ -367,7 +396,7 @@ static void connect_conn(struct mg_connection *c) {
|
|||||||
mg_call(c, MG_EV_CONNECT, NULL);
|
mg_call(c, MG_EV_CONNECT, NULL);
|
||||||
MG_EPOLL_MOD(c, 0);
|
MG_EPOLL_MOD(c, 0);
|
||||||
if (c->is_tls_hs) mg_tls_handshake(c);
|
if (c->is_tls_hs) mg_tls_handshake(c);
|
||||||
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
|
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
|
||||||
} else {
|
} else {
|
||||||
mg_error(c, "socket error");
|
mg_error(c, "socket error");
|
||||||
}
|
}
|
||||||
@@ -419,9 +448,9 @@ void mg_connect_resolved(struct mg_connection *c) {
|
|||||||
rc = connect(FD(c), &usa.sa, slen); // Attempt to connect
|
rc = connect(FD(c), &usa.sa, slen); // Attempt to connect
|
||||||
if (rc == 0) { // Success
|
if (rc == 0) { // Success
|
||||||
setlocaddr(FD(c), &c->loc);
|
setlocaddr(FD(c), &c->loc);
|
||||||
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
|
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
|
||||||
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
|
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
|
||||||
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
|
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
|
||||||
MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
|
MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
|
||||||
c->is_connecting = 1;
|
c->is_connecting = 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -471,7 +500,7 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
|
|||||||
setsockopts(c);
|
setsockopts(c);
|
||||||
c->is_accepted = 1;
|
c->is_accepted = 1;
|
||||||
c->is_hexdumping = lsn->is_hexdumping;
|
c->is_hexdumping = lsn->is_hexdumping;
|
||||||
c->loc = lsn->loc;
|
setlocaddr(fd, &c->loc); // set local addr to where the client connected to
|
||||||
c->pfn = lsn->pfn;
|
c->pfn = lsn->pfn;
|
||||||
c->pfn_data = lsn->pfn_data;
|
c->pfn_data = lsn->pfn_data;
|
||||||
c->fn = lsn->fn;
|
c->fn = lsn->fn;
|
||||||
@@ -481,7 +510,7 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
|
|||||||
&c->rem, mg_print_ip_port, &c->loc));
|
&c->rem, mg_print_ip_port, &c->loc));
|
||||||
mg_call(c, MG_EV_OPEN, NULL);
|
mg_call(c, MG_EV_OPEN, NULL);
|
||||||
mg_call(c, MG_EV_ACCEPT, NULL);
|
mg_call(c, MG_EV_ACCEPT, NULL);
|
||||||
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
|
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
#include "ssi.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
#include "ssi.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#ifndef MG_MAX_SSI_DEPTH
|
#ifndef MG_MAX_SSI_DEPTH
|
||||||
@@ -31,31 +31,35 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
|
|||||||
mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
|
mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
|
||||||
if (depth < MG_MAX_SSI_DEPTH &&
|
if (depth < MG_MAX_SSI_DEPTH &&
|
||||||
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
|
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
|
||||||
mg_iobuf_add(&b, b.len, data, strlen(data));
|
size_t datalen = strlen(data);
|
||||||
|
size_t ret = mg_iobuf_add(&b, b.len, data, datalen);
|
||||||
mg_free(data);
|
mg_free(data);
|
||||||
|
if (datalen > 0 && ret == 0) goto fail;
|
||||||
} else {
|
} else {
|
||||||
MG_ERROR(("%s: file=%s error or too deep", path, arg));
|
MG_ERROR(("%s: file=%s error or too deep", path, arg));
|
||||||
}
|
} // TODO(): or OOM at recursive call
|
||||||
} else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg) > 0) {
|
} else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg) > 0) {
|
||||||
char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data;
|
char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data;
|
||||||
mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
|
mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
|
||||||
if (depth < MG_MAX_SSI_DEPTH &&
|
if (depth < MG_MAX_SSI_DEPTH &&
|
||||||
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
|
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
|
||||||
mg_iobuf_add(&b, b.len, data, strlen(data));
|
size_t datalen = strlen(data);
|
||||||
|
size_t ret = mg_iobuf_add(&b, b.len, data, datalen);
|
||||||
mg_free(data);
|
mg_free(data);
|
||||||
|
if (datalen > 0 && ret == 0) goto fail;
|
||||||
} else {
|
} else {
|
||||||
MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
|
MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
|
||||||
}
|
} // TODO(): or OOM at recursive call
|
||||||
} else {
|
} else {
|
||||||
// Unknown SSI tag
|
// Unknown SSI tag
|
||||||
MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf));
|
MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf));
|
||||||
mg_iobuf_add(&b, b.len, buf, len);
|
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
|
||||||
}
|
}
|
||||||
intag = 0;
|
intag = 0;
|
||||||
len = 0;
|
len = 0;
|
||||||
} else if (ch == '<') {
|
} else if (ch == '<') {
|
||||||
intag = 1;
|
intag = 1;
|
||||||
if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
|
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
|
||||||
len = 0;
|
len = 0;
|
||||||
buf[len++] = (char) (ch & 0xff);
|
buf[len++] = (char) (ch & 0xff);
|
||||||
} else if (intag) {
|
} else if (intag) {
|
||||||
@@ -69,24 +73,33 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
|
|||||||
} else {
|
} else {
|
||||||
buf[len++] = (char) (ch & 0xff);
|
buf[len++] = (char) (ch & 0xff);
|
||||||
if (len >= sizeof(buf)) {
|
if (len >= sizeof(buf)) {
|
||||||
mg_iobuf_add(&b, b.len, buf, len);
|
if (mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
|
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
|
||||||
if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1); // nul-terminate
|
if (b.len > 0 && mg_iobuf_add(&b, b.len, "", 1) == 0) // nul-terminate
|
||||||
|
goto fail;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
(void) depth;
|
(void) depth;
|
||||||
(void) root;
|
(void) root;
|
||||||
return (char *) b.buf;
|
return (char *) b.buf;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
fclose(fp);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
|
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
|
||||||
const char *fullpath) {
|
const char *fullpath) {
|
||||||
const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
|
const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
|
||||||
char *data = mg_ssi(fullpath, root, 0);
|
char *data = mg_ssi(fullpath, root, 0);
|
||||||
|
if (data == NULL) {
|
||||||
|
mg_error(c, "OOM");
|
||||||
|
return;
|
||||||
|
}
|
||||||
mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
|
mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
|
||||||
mg_free(data);
|
mg_free(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,14 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
struct mg_str mg_str_s(const char *s) {
|
struct mg_str mg_str_s(const char *s) {
|
||||||
struct mg_str str = {(char *) s, s == NULL ? 0 : strlen(s)};
|
struct mg_str str;
|
||||||
|
str.buf = (char *) s, str.len = (s == NULL) ? 0 : strlen(s);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mg_str mg_str_n(const char *s, size_t n) {
|
struct mg_str mg_str_n(const char *s, size_t n) {
|
||||||
struct mg_str str = {(char *) s, n};
|
struct mg_str str;
|
||||||
|
str.buf = (char *) s, str.len = n;
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +87,9 @@ bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
|
|||||||
} else if (i < p.len && (p.buf[i] == '*' || p.buf[i] == '#')) {
|
} else if (i < p.len && (p.buf[i] == '*' || p.buf[i] == '#')) {
|
||||||
if (caps && !caps->buf) caps->len = 0, caps->buf = &s.buf[j]; // Init cap
|
if (caps && !caps->buf) caps->len = 0, caps->buf = &s.buf[j]; // Init cap
|
||||||
ni = i++, nj = j + 1;
|
ni = i++, nj = j + 1;
|
||||||
} else if (nj > 0 && nj <= s.len && (p.buf[ni] == '#' || s.buf[j] != '/')) {
|
} else if (nj > 0 && nj <= s.len &&
|
||||||
|
((ni < p.len && p.buf[ni] == '#') ||
|
||||||
|
(j < s.len && s.buf[j] != '/'))) {
|
||||||
i = ni, j = nj;
|
i = ni, j = nj;
|
||||||
if (caps && caps->buf == NULL && caps->len == 0) {
|
if (caps && caps->buf == NULL && caps->len == 0) {
|
||||||
caps--, caps->len = 0; // Restart previous cap
|
caps--, caps->len = 0; // Restart previous cap
|
||||||
@@ -166,8 +170,7 @@ bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) {
|
|||||||
i++, ndigits++;
|
i++, ndigits++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default: return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (ndigits == 0) return false;
|
if (ndigits == 0) return false;
|
||||||
if (i != str.len) return false;
|
if (i != str.len) return false;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ void mg_tls_handshake(struct mg_connection *);
|
|||||||
// Private
|
// Private
|
||||||
void mg_tls_ctx_init(struct mg_mgr *);
|
void mg_tls_ctx_init(struct mg_mgr *);
|
||||||
void mg_tls_ctx_free(struct mg_mgr *);
|
void mg_tls_ctx_free(struct mg_mgr *);
|
||||||
|
#define MG_IS_DER(buf) (((uint8_t *) (buf))[0] == 0x30) // DER begins with 0x30
|
||||||
|
|
||||||
// Low-level IO primives used by TLS layer
|
// Low-level IO primives used by TLS layer
|
||||||
enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
|
enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
|
||||||
|
|||||||
+93
-81
@@ -40,45 +40,47 @@ static void aes_init_keygen_tables(void);
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* AES_SETKEY : called to expand the key for encryption or decryption
|
* AES_SETKEY : called to expand the key for encryption or decryption
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static int aes_setkey(aes_context *ctx, // pointer to context
|
static int aes_setkey(
|
||||||
int mode, // 1 or 0 for Encrypt/Decrypt
|
aes_context *ctx, // pointer to context
|
||||||
const unsigned char *key, // AES input key
|
int mode, // 1 or 0 for Encrypt/Decrypt
|
||||||
unsigned int keysize); // size in bytes (must be 16, 24, 32 for
|
const unsigned char *key, // AES input key
|
||||||
// 128, 192 or 256-bit keys respectively)
|
unsigned int keysize); // size in bytes (must be 16, 24, 32 for
|
||||||
// returns 0 for success
|
// 128, 192 or 256-bit keys respectively)
|
||||||
|
// returns 0 for success
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
|
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static int aes_cipher(aes_context *ctx, // pointer to context
|
static int aes_cipher(
|
||||||
const unsigned char input[16], // 128-bit block to en/decipher
|
aes_context *ctx, // pointer to context
|
||||||
unsigned char output[16]); // 128-bit output result block
|
const unsigned char input[16], // 128-bit block to en/decipher
|
||||||
// returns 0 for success
|
unsigned char output[16]); // 128-bit output result block
|
||||||
|
// returns 0 for success
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
|
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int mode; // cipher direction: encrypt/decrypt
|
int mode; // cipher direction: encrypt/decrypt
|
||||||
uint64_t len; // cipher data length processed so far
|
uint64_t len; // cipher data length processed so far
|
||||||
uint64_t add_len; // total add data length
|
uint64_t add_len; // total add data length
|
||||||
uint64_t HL[16]; // precalculated lo-half HTable
|
uint64_t HL[16]; // precalculated lo-half HTable
|
||||||
uint64_t HH[16]; // precalculated hi-half HTable
|
uint64_t HH[16]; // precalculated hi-half HTable
|
||||||
unsigned char base_ectr[16]; // first counter-mode cipher output for tag
|
unsigned char base_ectr[16]; // first counter-mode cipher output for tag
|
||||||
unsigned char y[16]; // the current cipher-input IV|Counter value
|
unsigned char y[16]; // the current cipher-input IV|Counter value
|
||||||
unsigned char buf[16]; // buf working value
|
unsigned char buf[16]; // buf working value
|
||||||
aes_context aes_ctx; // cipher context used
|
aes_context aes_ctx; // cipher context used
|
||||||
} gcm_context;
|
} gcm_context;
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* GCM_SETKEY : sets the GCM (and AES) keying material for use
|
* GCM_SETKEY : sets the GCM (and AES) keying material for use
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static int gcm_setkey(
|
static int gcm_setkey(
|
||||||
gcm_context *ctx, // caller-provided context ptr
|
gcm_context *ctx, // caller-provided context ptr
|
||||||
const unsigned char *key, // pointer to cipher key
|
const unsigned char *key, // pointer to cipher key
|
||||||
const unsigned int keysize // size in bytes (must be 16, 24, 32 for
|
const unsigned int keysize // size in bytes (must be 16, 24, 32 for
|
||||||
// 128, 192 or 256-bit keys respectively)
|
// 128, 192 or 256-bit keys respectively)
|
||||||
); // returns 0 for success
|
); // returns 0 for success
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
@@ -98,17 +100,17 @@ static int gcm_setkey(
|
|||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static int gcm_crypt_and_tag(
|
static int gcm_crypt_and_tag(
|
||||||
gcm_context *ctx, // gcm context with key already setup
|
gcm_context *ctx, // gcm context with key already setup
|
||||||
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
|
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||||
const unsigned char *iv, // pointer to the 12-byte initialization vector
|
const unsigned char *iv, // pointer to the 12-byte initialization vector
|
||||||
size_t iv_len, // byte length if the IV. should always be 12
|
size_t iv_len, // byte length if the IV. should always be 12
|
||||||
const unsigned char *add, // pointer to the non-ciphered additional data
|
const unsigned char *add, // pointer to the non-ciphered additional data
|
||||||
size_t add_len, // byte length of the additional AEAD data
|
size_t add_len, // byte length of the additional AEAD data
|
||||||
const unsigned char *input, // pointer to the cipher data source
|
const unsigned char *input, // pointer to the cipher data source
|
||||||
unsigned char *output, // pointer to the cipher data destination
|
unsigned char *output, // pointer to the cipher data destination
|
||||||
size_t length, // byte length of the cipher data
|
size_t length, // byte length of the cipher data
|
||||||
unsigned char *tag, // pointer to the tag to be generated
|
unsigned char *tag, // pointer to the tag to be generated
|
||||||
size_t tag_len); // byte length of the tag to be generated
|
size_t tag_len); // byte length of the tag to be generated
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
@@ -119,12 +121,12 @@ static int gcm_crypt_and_tag(
|
|||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static int gcm_start(
|
static int gcm_start(
|
||||||
gcm_context *ctx, // pointer to user-provided GCM context
|
gcm_context *ctx, // pointer to user-provided GCM context
|
||||||
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
|
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
|
||||||
const unsigned char *iv, // pointer to initialization vector
|
const unsigned char *iv, // pointer to initialization vector
|
||||||
size_t iv_len, // IV length in bytes (should == 12)
|
size_t iv_len, // IV length in bytes (should == 12)
|
||||||
const unsigned char *add, // pointer to additional AEAD data (NULL if none)
|
const unsigned char *add, // pointer to additional AEAD data (NULL if none)
|
||||||
size_t add_len); // length of additional AEAD data (bytes)
|
size_t add_len); // length of additional AEAD data (bytes)
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
@@ -140,7 +142,7 @@ static int gcm_start(
|
|||||||
static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||||
size_t length, // length, in bytes, of data to process
|
size_t length, // length, in bytes, of data to process
|
||||||
const unsigned char *input, // pointer to source data
|
const unsigned char *input, // pointer to source data
|
||||||
unsigned char *output); // pointer to destination data
|
unsigned char *output); // pointer to destination data
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
@@ -151,9 +153,9 @@ static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static int gcm_finish(
|
static int gcm_finish(
|
||||||
gcm_context *ctx, // pointer to user-provided GCM context
|
gcm_context *ctx, // pointer to user-provided GCM context
|
||||||
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
|
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
|
||||||
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
@@ -204,15 +206,15 @@ static int aes_tables_inited = 0; // run-once flag for performing key
|
|||||||
* decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
|
* decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
|
||||||
*/
|
*/
|
||||||
// We always need our forward tables
|
// We always need our forward tables
|
||||||
static unsigned char FSb[256]; // Forward substitution box (FSb)
|
static unsigned char FSb[256]; // Forward substitution box (FSb)
|
||||||
static uint32_t FT0[256]; // Forward key schedule assembly tables
|
static uint32_t FT0[256]; // Forward key schedule assembly tables
|
||||||
static uint32_t FT1[256];
|
static uint32_t FT1[256];
|
||||||
static uint32_t FT2[256];
|
static uint32_t FT2[256];
|
||||||
static uint32_t FT3[256];
|
static uint32_t FT3[256];
|
||||||
|
|
||||||
#if AES_DECRYPTION // We ONLY need reverse for decryption
|
#if AES_DECRYPTION // We ONLY need reverse for decryption
|
||||||
static unsigned char RSb[256]; // Reverse substitution box (RSb)
|
static unsigned char RSb[256]; // Reverse substitution box (RSb)
|
||||||
static uint32_t RT0[256]; // Reverse key schedule assembly tables
|
static uint32_t RT0[256]; // Reverse key schedule assembly tables
|
||||||
static uint32_t RT1[256];
|
static uint32_t RT1[256];
|
||||||
static uint32_t RT2[256];
|
static uint32_t RT2[256];
|
||||||
static uint32_t RT3[256];
|
static uint32_t RT3[256];
|
||||||
@@ -230,8 +232,8 @@ static uint32_t RCON[10]; // AES round constants
|
|||||||
((uint32_t) (b)[(i) + 2] << 16) | ((uint32_t) (b)[(i) + 3] << 24); \
|
((uint32_t) (b)[(i) + 2] << 16) | ((uint32_t) (b)[(i) + 3] << 24); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PUT_UINT32_LE(n, b, i) \
|
#define PUT_UINT32_LE(n, b, i) \
|
||||||
{ \
|
{ \
|
||||||
(b)[(i)] = (unsigned char) ((n)); \
|
(b)[(i)] = (unsigned char) ((n)); \
|
||||||
(b)[(i) + 1] = (unsigned char) ((n) >> 8); \
|
(b)[(i) + 1] = (unsigned char) ((n) >> 8); \
|
||||||
(b)[(i) + 2] = (unsigned char) ((n) >> 16); \
|
(b)[(i) + 2] = (unsigned char) ((n) >> 16); \
|
||||||
@@ -376,7 +378,7 @@ void aes_init_keygen_tables(void) {
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static int aes_set_encryption_key(aes_context *ctx, const unsigned char *key,
|
static int aes_set_encryption_key(aes_context *ctx, const unsigned char *key,
|
||||||
unsigned int keysize) {
|
unsigned int keysize) {
|
||||||
unsigned int i; // general purpose iteration local
|
unsigned int i; // general purpose iteration local
|
||||||
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
|
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
|
||||||
|
|
||||||
for (i = 0; i < (keysize >> 2); i++) {
|
for (i = 0; i < (keysize >> 2); i++) {
|
||||||
@@ -711,8 +713,8 @@ static const uint64_t last4[16] = {
|
|||||||
((uint32_t) (b)[(i) + 2] << 8) | ((uint32_t) (b)[(i) + 3]); \
|
((uint32_t) (b)[(i) + 2] << 8) | ((uint32_t) (b)[(i) + 3]); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PUT_UINT32_BE(n, b, i) \
|
#define PUT_UINT32_BE(n, b, i) \
|
||||||
{ \
|
{ \
|
||||||
(b)[(i)] = (unsigned char) ((n) >> 24); \
|
(b)[(i)] = (unsigned char) ((n) >> 24); \
|
||||||
(b)[(i) + 1] = (unsigned char) ((n) >> 16); \
|
(b)[(i) + 1] = (unsigned char) ((n) >> 16); \
|
||||||
(b)[(i) + 2] = (unsigned char) ((n) >> 8); \
|
(b)[(i) + 2] = (unsigned char) ((n) >> 8); \
|
||||||
@@ -745,9 +747,10 @@ int mg_gcm_initialize(void) {
|
|||||||
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
|
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static void gcm_mult(gcm_context *ctx, // pointer to established context
|
static void gcm_mult(
|
||||||
const unsigned char x[16], // pointer to 128-bit input vector
|
gcm_context *ctx, // pointer to established context
|
||||||
unsigned char output[16]) // pointer to 128-bit output vector
|
const unsigned char x[16], // pointer to 128-bit input vector
|
||||||
|
unsigned char output[16]) // pointer to 128-bit output vector
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned char lo, hi, rem;
|
unsigned char lo, hi, rem;
|
||||||
@@ -792,10 +795,10 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
|
|||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static int gcm_setkey(
|
static int gcm_setkey(
|
||||||
gcm_context *ctx, // pointer to caller-provided gcm context
|
gcm_context *ctx, // pointer to caller-provided gcm context
|
||||||
const unsigned char *key, // pointer to the AES encryption key
|
const unsigned char *key, // pointer to the AES encryption key
|
||||||
const unsigned int keysize) // size in bytes (must be 16, 24, 32 for
|
const unsigned int keysize) // size in bytes (must be 16, 24, 32 for
|
||||||
// 128, 192 or 256-bit keys respectively)
|
// 128, 192 or 256-bit keys respectively)
|
||||||
{
|
{
|
||||||
int ret, i, j;
|
int ret, i, j;
|
||||||
uint64_t hi, lo;
|
uint64_t hi, lo;
|
||||||
@@ -864,18 +867,19 @@ static int gcm_setkey(
|
|||||||
* mode, and preprocesses the initialization vector and additional AEAD data.
|
* mode, and preprocesses the initialization vector and additional AEAD data.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
int gcm_start(
|
||||||
int mode, // GCM_ENCRYPT or GCM_DECRYPT
|
gcm_context *ctx, // pointer to user-provided GCM context
|
||||||
const unsigned char *iv, // pointer to initialization vector
|
int mode, // GCM_ENCRYPT or GCM_DECRYPT
|
||||||
size_t iv_len, // IV length in bytes (should == 12)
|
const unsigned char *iv, // pointer to initialization vector
|
||||||
const unsigned char *add, // ptr to additional AEAD data (NULL if none)
|
size_t iv_len, // IV length in bytes (should == 12)
|
||||||
size_t add_len) // length of additional AEAD data (bytes)
|
const unsigned char *add, // ptr to additional AEAD data (NULL if none)
|
||||||
|
size_t add_len) // length of additional AEAD data (bytes)
|
||||||
{
|
{
|
||||||
int ret; // our error return if the AES encrypt fails
|
int ret; // our error return if the AES encrypt fails
|
||||||
unsigned char work_buf[16]; // XOR source built from provided IV if len != 16
|
unsigned char work_buf[16]; // XOR source built from provided IV if len != 16
|
||||||
const unsigned char *p; // general purpose array pointer
|
const unsigned char *p; // general purpose array pointer
|
||||||
size_t use_len; // byte count to process, up to 16 bytes
|
size_t use_len; // byte count to process, up to 16 bytes
|
||||||
size_t i; // local loop iterator
|
size_t i; // local loop iterator
|
||||||
|
|
||||||
// since the context might be reused under the same key
|
// since the context might be reused under the same key
|
||||||
// we zero the working buffers for this next new process
|
// we zero the working buffers for this next new process
|
||||||
@@ -932,15 +936,15 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
* have a partial block length of < 128 bits.)
|
* have a partial block length of < 128 bits.)
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||||
size_t length, // length, in bytes, of data to process
|
size_t length, // length, in bytes, of data to process
|
||||||
const unsigned char *input, // pointer to source data
|
const unsigned char *input, // pointer to source data
|
||||||
unsigned char *output) // pointer to destination data
|
unsigned char *output) // pointer to destination data
|
||||||
{
|
{
|
||||||
int ret; // our error return if the AES encrypt fails
|
int ret; // our error return if the AES encrypt fails
|
||||||
unsigned char ectr[16]; // counter-mode cipher output for XORing
|
unsigned char ectr[16]; // counter-mode cipher output for XORing
|
||||||
size_t use_len; // byte count to process, up to 16 bytes
|
size_t use_len; // byte count to process, up to 16 bytes
|
||||||
size_t i; // local loop iterator
|
size_t i; // local loop iterator
|
||||||
|
|
||||||
ctx->len += length; // bump the GCM context's running length count
|
ctx->len += length; // bump the GCM context's running length count
|
||||||
|
|
||||||
@@ -996,9 +1000,9 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
* It performs the final GHASH to produce the resulting authentication TAG.
|
* It performs the final GHASH to produce the resulting authentication TAG.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
||||||
unsigned char *tag, // pointer to buffer which receives the tag
|
unsigned char *tag, // pointer to buffer which receives the tag
|
||||||
size_t tag_len) // length, in bytes, of the tag-receiving buf
|
size_t tag_len) // length, in bytes, of the tag-receiving buf
|
||||||
{
|
{
|
||||||
unsigned char work_buf[16];
|
unsigned char work_buf[16];
|
||||||
uint64_t orig_len = ctx->len * 8;
|
uint64_t orig_len = ctx->len * 8;
|
||||||
@@ -1040,22 +1044,22 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
int gcm_crypt_and_tag(
|
int gcm_crypt_and_tag(
|
||||||
gcm_context *ctx, // gcm context with key already setup
|
gcm_context *ctx, // gcm context with key already setup
|
||||||
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
|
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
|
||||||
const unsigned char *iv, // pointer to the 12-byte initialization vector
|
const unsigned char *iv, // pointer to the 12-byte initialization vector
|
||||||
size_t iv_len, // byte length if the IV. should always be 12
|
size_t iv_len, // byte length if the IV. should always be 12
|
||||||
const unsigned char *add, // pointer to the non-ciphered additional data
|
const unsigned char *add, // pointer to the non-ciphered additional data
|
||||||
size_t add_len, // byte length of the additional AEAD data
|
size_t add_len, // byte length of the additional AEAD data
|
||||||
const unsigned char *input, // pointer to the cipher data source
|
const unsigned char *input, // pointer to the cipher data source
|
||||||
unsigned char *output, // pointer to the cipher data destination
|
unsigned char *output, // pointer to the cipher data destination
|
||||||
size_t length, // byte length of the cipher data
|
size_t length, // byte length of the cipher data
|
||||||
unsigned char *tag, // pointer to the tag to be generated
|
unsigned char *tag, // pointer to the tag to be generated
|
||||||
size_t tag_len) // byte length of the tag to be generated
|
size_t tag_len) // byte length of the tag to be generated
|
||||||
{ /*
|
{ /*
|
||||||
assuming that the caller has already invoked gcm_setkey to
|
assuming that the caller has already invoked gcm_setkey to
|
||||||
prepare the gcm context with the keying material, we simply
|
prepare the gcm context with the keying material, we simply
|
||||||
invoke each of the three GCM sub-functions in turn...
|
invoke each of the three GCM sub-functions in turn...
|
||||||
*/
|
*/
|
||||||
gcm_start(ctx, mode, iv, iv_len, add, add_len);
|
gcm_start(ctx, mode, iv, iv_len, add, add_len);
|
||||||
gcm_update(ctx, length, input, output);
|
gcm_update(ctx, length, input, output);
|
||||||
gcm_finish(ctx, tag, tag_len);
|
gcm_finish(ctx, tag, tag_len);
|
||||||
@@ -1105,20 +1109,28 @@ int mg_aes_gcm_encrypt(unsigned char *output, //
|
|||||||
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||||
size_t input_length, const unsigned char *key,
|
size_t input_length, const unsigned char *key,
|
||||||
const size_t key_len, const unsigned char *iv,
|
const size_t key_len, const unsigned char *iv,
|
||||||
const size_t iv_len) {
|
const size_t iv_len, unsigned char *aead,
|
||||||
|
size_t aead_len, const unsigned char *tag,
|
||||||
|
const size_t tag_len) {
|
||||||
int ret = 0; // our return value
|
int ret = 0; // our return value
|
||||||
gcm_context ctx; // includes the AES context structure
|
gcm_context ctx; // includes the AES context structure
|
||||||
|
unsigned char computed_tag[16];
|
||||||
|
size_t i;
|
||||||
|
int diff = 0;
|
||||||
|
|
||||||
size_t tag_len = 0;
|
if (tag_len > sizeof(computed_tag)) return -1;
|
||||||
unsigned char *tag_buf = NULL;
|
|
||||||
|
|
||||||
gcm_setkey(&ctx, key, (unsigned int) key_len);
|
gcm_setkey(&ctx, key, (unsigned int) key_len);
|
||||||
|
|
||||||
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, NULL, 0, input, output,
|
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, aead, aead_len, input,
|
||||||
input_length, tag_buf, tag_len);
|
output, input_length, computed_tag, tag_len);
|
||||||
|
|
||||||
gcm_zero_ctx(&ctx);
|
gcm_zero_ctx(&ctx);
|
||||||
|
|
||||||
|
// compare tags
|
||||||
|
for (i = 0; i < tag_len; i++) diff |= computed_tag[i] ^ tag[i];
|
||||||
|
if (diff != 0) ret = -1;
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+3
-1
@@ -59,7 +59,9 @@ int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
|
|||||||
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||||
size_t input_length, const unsigned char *key,
|
size_t input_length, const unsigned char *key,
|
||||||
const size_t key_len, const unsigned char *iv,
|
const size_t key_len, const unsigned char *iv,
|
||||||
const size_t iv_len);
|
const size_t iv_len, unsigned char *aead,
|
||||||
|
size_t aead_len, const unsigned char *tag,
|
||||||
|
const size_t tag_len);
|
||||||
|
|
||||||
#endif /* TLS_AES128_H */
|
#endif /* TLS_AES128_H */
|
||||||
|
|
||||||
|
|||||||
+1001
-198
File diff suppressed because it is too large.
Load diff
+29
-15
@@ -79,9 +79,11 @@ static PORTABLE_8439_DECL void poly1305_finish(poly1305_context *ctx,
|
|||||||
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
|
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
|
||||||
defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \
|
defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \
|
||||||
defined(__MIPSEL) || defined(__MIPSEL__) || defined(__XTENSA_EL__) || \
|
defined(__MIPSEL) || defined(__MIPSEL__) || defined(__XTENSA_EL__) || \
|
||||||
defined(__AVR__) || defined(LITTLE_ENDIAN)
|
defined(__AVR__)
|
||||||
#define __HAVE_LITTLE_ENDIAN 1
|
#define __HAVE_LITTLE_ENDIAN 1
|
||||||
#endif
|
#endif
|
||||||
|
// DO NOT test for LITTLE_ENDIAN, as it is defined as 1234 when including
|
||||||
|
// sys/types.h in GCC
|
||||||
|
|
||||||
#ifndef TEST_SLOW_PATH
|
#ifndef TEST_SLOW_PATH
|
||||||
#if defined(__HAVE_LITTLE_ENDIAN)
|
#if defined(__HAVE_LITTLE_ENDIAN)
|
||||||
@@ -177,7 +179,7 @@ static void core_block(const uint32_t *restrict start,
|
|||||||
TIMES16(__FIN)
|
TIMES16(__FIN)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define U8(x) ((uint8_t) ((x) &0xFF))
|
#define U8(x) ((uint8_t) ((x) & 0xFF))
|
||||||
|
|
||||||
#ifdef FAST_PATH
|
#ifdef FAST_PATH
|
||||||
#define xor32_le(dst, src, pad) \
|
#define xor32_le(dst, src, pad) \
|
||||||
@@ -502,7 +504,7 @@ static unsigned short U8TO16(const unsigned char *p) {
|
|||||||
/* store a 16 bit unsigned integer as two 8 bit unsigned integers in little
|
/* store a 16 bit unsigned integer as two 8 bit unsigned integers in little
|
||||||
* endian */
|
* endian */
|
||||||
static void U16TO8(unsigned char *p, unsigned short v) {
|
static void U16TO8(unsigned char *p, unsigned short v) {
|
||||||
p[0] = (v) &0xff;
|
p[0] = (v) & 0xff;
|
||||||
p[1] = (v >> 8) & 0xff;
|
p[1] = (v >> 8) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,7 +515,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
|||||||
|
|
||||||
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
||||||
t0 = U8TO16(&key[0]);
|
t0 = U8TO16(&key[0]);
|
||||||
st->r[0] = (t0) &0x1fff;
|
st->r[0] = (t0) & 0x1fff;
|
||||||
t1 = U8TO16(&key[2]);
|
t1 = U8TO16(&key[2]);
|
||||||
st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff;
|
st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff;
|
||||||
t2 = U8TO16(&key[4]);
|
t2 = U8TO16(&key[4]);
|
||||||
@@ -553,7 +555,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
|
|||||||
|
|
||||||
/* h += m[i] */
|
/* h += m[i] */
|
||||||
t0 = U8TO16(&m[0]);
|
t0 = U8TO16(&m[0]);
|
||||||
st->h[0] += (t0) &0x1fff;
|
st->h[0] += (t0) & 0x1fff;
|
||||||
t1 = U8TO16(&m[2]);
|
t1 = U8TO16(&m[2]);
|
||||||
st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff;
|
st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff;
|
||||||
t2 = U8TO16(&m[4]);
|
t2 = U8TO16(&m[4]);
|
||||||
@@ -715,7 +717,7 @@ static unsigned long U8TO32(const unsigned char *p) {
|
|||||||
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little
|
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little
|
||||||
* endian */
|
* endian */
|
||||||
static void U32TO8(unsigned char *p, unsigned long v) {
|
static void U32TO8(unsigned char *p, unsigned long v) {
|
||||||
p[0] = (unsigned char) ((v) &0xff);
|
p[0] = (unsigned char) ((v) & 0xff);
|
||||||
p[1] = (unsigned char) ((v >> 8) & 0xff);
|
p[1] = (unsigned char) ((v >> 8) & 0xff);
|
||||||
p[2] = (unsigned char) ((v >> 16) & 0xff);
|
p[2] = (unsigned char) ((v >> 16) & 0xff);
|
||||||
p[3] = (unsigned char) ((v >> 24) & 0xff);
|
p[3] = (unsigned char) ((v >> 24) & 0xff);
|
||||||
@@ -979,8 +981,8 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
|
|||||||
#define MUL128(out, x, y) out = ((uint128_t) x * y)
|
#define MUL128(out, x, y) out = ((uint128_t) x * y)
|
||||||
#define ADD(out, in) out += in
|
#define ADD(out, in) out += in
|
||||||
#define ADDLO(out, in) out += in
|
#define ADDLO(out, in) out += in
|
||||||
#define SHR(in, shift) (uint64_t)(in >> (shift))
|
#define SHR(in, shift) (uint64_t) (in >> (shift))
|
||||||
#define LO(in) (uint64_t)(in)
|
#define LO(in) (uint64_t) (in)
|
||||||
|
|
||||||
#define POLY1305_NOINLINE __attribute__((noinline))
|
#define POLY1305_NOINLINE __attribute__((noinline))
|
||||||
#endif
|
#endif
|
||||||
@@ -1009,7 +1011,7 @@ static uint64_t U8TO64(const unsigned char *p) {
|
|||||||
/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little
|
/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little
|
||||||
* endian */
|
* endian */
|
||||||
static void U64TO8(unsigned char *p, uint64_t v) {
|
static void U64TO8(unsigned char *p, uint64_t v) {
|
||||||
p[0] = (unsigned char) ((v) &0xff);
|
p[0] = (unsigned char) ((v) & 0xff);
|
||||||
p[1] = (unsigned char) ((v >> 8) & 0xff);
|
p[1] = (unsigned char) ((v >> 8) & 0xff);
|
||||||
p[2] = (unsigned char) ((v >> 16) & 0xff);
|
p[2] = (unsigned char) ((v >> 16) & 0xff);
|
||||||
p[3] = (unsigned char) ((v >> 24) & 0xff);
|
p[3] = (unsigned char) ((v >> 24) & 0xff);
|
||||||
@@ -1027,7 +1029,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
|||||||
t0 = U8TO64(&key[0]);
|
t0 = U8TO64(&key[0]);
|
||||||
t1 = U8TO64(&key[8]);
|
t1 = U8TO64(&key[8]);
|
||||||
|
|
||||||
st->r[0] = (t0) &0xffc0fffffff;
|
st->r[0] = (t0) & 0xffc0fffffff;
|
||||||
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
|
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
|
||||||
st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
|
st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
|
||||||
|
|
||||||
@@ -1071,7 +1073,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
|
|||||||
t0 = U8TO64(&m[0]);
|
t0 = U8TO64(&m[0]);
|
||||||
t1 = U8TO64(&m[8]);
|
t1 = U8TO64(&m[8]);
|
||||||
|
|
||||||
h0 += ((t0) &0xfffffffffff);
|
h0 += ((t0) & 0xfffffffffff);
|
||||||
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
|
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
|
||||||
h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
|
h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
|
||||||
|
|
||||||
@@ -1178,7 +1180,7 @@ static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx,
|
|||||||
t0 = st->pad[0];
|
t0 = st->pad[0];
|
||||||
t1 = st->pad[1];
|
t1 = st->pad[1];
|
||||||
|
|
||||||
h0 += ((t0) &0xfffffffffff);
|
h0 += ((t0) & 0xfffffffffff);
|
||||||
c = (h0 >> 44);
|
c = (h0 >> 44);
|
||||||
h0 &= 0xfffffffffff;
|
h0 &= 0xfffffffffff;
|
||||||
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
|
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
|
||||||
@@ -1255,7 +1257,7 @@ static PORTABLE_8439_DECL void pad_if_needed(poly1305_context *ctx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __u8(v) ((uint8_t) ((v) &0xFF))
|
#define __u8(v) ((uint8_t) ((v) & 0xFF))
|
||||||
|
|
||||||
// TODO: make this depending on the unaligned/native read size possible
|
// TODO: make this depending on the unaligned/native read size possible
|
||||||
static PORTABLE_8439_DECL void write_64bit_int(poly1305_context *ctx,
|
static PORTABLE_8439_DECL void write_64bit_int(poly1305_context *ctx,
|
||||||
@@ -1328,14 +1330,26 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
|
|||||||
|
|
||||||
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
||||||
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
||||||
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad,
|
||||||
const uint8_t *restrict cipher_text, size_t cipher_text_size) {
|
size_t ad_size, const uint8_t *restrict cipher_text,
|
||||||
|
size_t cipher_text_size) {
|
||||||
// first we calculate the mac and see if it lines up, only then do we decrypt
|
// first we calculate the mac and see if it lines up, only then do we decrypt
|
||||||
size_t actual_size = cipher_text_size - RFC_8439_TAG_SIZE;
|
size_t actual_size = cipher_text_size - RFC_8439_TAG_SIZE;
|
||||||
|
uint8_t computed_mac[RFC_8439_TAG_SIZE];
|
||||||
|
int diff = 0;
|
||||||
|
size_t i;
|
||||||
if (MG_OVERLAPPING(plain_text, actual_size, cipher_text, cipher_text_size)) {
|
if (MG_OVERLAPPING(plain_text, actual_size, cipher_text, cipher_text_size)) {
|
||||||
return (size_t) -1;
|
return (size_t) -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
poly1305_calculate_mac(computed_mac, cipher_text, actual_size, key, nonce, ad,
|
||||||
|
ad_size);
|
||||||
|
|
||||||
|
// compare tags
|
||||||
|
for (i = 0; i < RFC_8439_TAG_SIZE; i++)
|
||||||
|
diff |= computed_mac[i] ^ cipher_text[actual_size + i];
|
||||||
|
if (diff != 0) return (size_t) -1;
|
||||||
|
|
||||||
chacha20_xor_stream(plain_text, cipher_text, actual_size, key, nonce, 1);
|
chacha20_xor_stream(plain_text, cipher_text, actual_size, key, nonce, 1);
|
||||||
return actual_size;
|
return actual_size;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
|
|||||||
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
||||||
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
|
||||||
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
const uint8_t nonce[RFC_8439_NONCE_SIZE],
|
||||||
|
const uint8_t *restrict ad, size_t ad_size,
|
||||||
const uint8_t *restrict cipher_text, size_t cipher_text_size);
|
const uint8_t *restrict cipher_text, size_t cipher_text_size);
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-17
@@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
#if MG_TLS == MG_TLS_MBED
|
#if MG_TLS == MG_TLS_MBED
|
||||||
|
|
||||||
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
|
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \
|
||||||
|
MBEDTLS_VERSION_NUMBER < 0x04000000
|
||||||
#define MG_MBEDTLS_RNG_GET , mg_mbed_rng, NULL
|
#define MG_MBEDTLS_RNG_GET , mg_mbed_rng, NULL
|
||||||
#else
|
#else
|
||||||
#define MG_MBEDTLS_RNG_GET
|
#define MG_MBEDTLS_RNG_GET
|
||||||
@@ -19,16 +20,19 @@ static int mg_tls_err(struct mg_connection *c, int rc) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x04000000
|
||||||
|
#else
|
||||||
static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) {
|
static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) {
|
||||||
mg_random(buf, len);
|
mg_random(buf, len);
|
||||||
(void) ctx;
|
(void) ctx;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) {
|
static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) {
|
||||||
int rc;
|
int rc;
|
||||||
if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true;
|
if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true;
|
||||||
if (str.buf[0] == '-') str.len++; // PEM, include trailing NUL
|
if (!MG_IS_DER(str.buf)) str.len++; // PEM, include trailing NUL
|
||||||
if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.buf, str.len)) != 0) {
|
if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.buf, str.len)) != 0) {
|
||||||
MG_ERROR(("cert err %#x", -rc));
|
MG_ERROR(("cert err %#x", -rc));
|
||||||
return false;
|
return false;
|
||||||
@@ -39,7 +43,7 @@ static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) {
|
|||||||
static bool mg_load_key(struct mg_str str, mbedtls_pk_context *p) {
|
static bool mg_load_key(struct mg_str str, mbedtls_pk_context *p) {
|
||||||
int rc;
|
int rc;
|
||||||
if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true;
|
if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true;
|
||||||
if (str.buf[0] == '-') str.len++; // PEM, include trailing NUL
|
if (!MG_IS_DER(str.buf)) str.len++; // PEM, include trailing NUL
|
||||||
if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.buf, str.len, NULL,
|
if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.buf, str.len, NULL,
|
||||||
0 MG_MBEDTLS_RNG_GET)) != 0) {
|
0 MG_MBEDTLS_RNG_GET)) != 0) {
|
||||||
MG_ERROR(("key err %#x", -rc));
|
MG_ERROR(("key err %#x", -rc));
|
||||||
@@ -59,6 +63,9 @@ void mg_tls_free(struct mg_connection *c) {
|
|||||||
#ifdef MBEDTLS_SSL_SESSION_TICKETS
|
#ifdef MBEDTLS_SSL_SESSION_TICKETS
|
||||||
mbedtls_ssl_ticket_free(&tls->ticket);
|
mbedtls_ssl_ticket_free(&tls->ticket);
|
||||||
#endif
|
#endif
|
||||||
|
// PSA has global data. Do not call mbedtls_psa_crypto_free() here,
|
||||||
|
// it will free all global resources. Call it when actually freeing all
|
||||||
|
// application resources (main() exits)
|
||||||
mg_free(tls);
|
mg_free(tls);
|
||||||
c->tls = NULL;
|
c->tls = NULL;
|
||||||
}
|
}
|
||||||
@@ -118,6 +125,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
|||||||
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \
|
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \
|
||||||
defined(MBEDTLS_PSA_CRYPTO_C)
|
defined(MBEDTLS_PSA_CRYPTO_C)
|
||||||
psa_crypto_init(); // https://github.com/Mbed-TLS/mbedtls/issues/9072#issuecomment-2084845711
|
psa_crypto_init(); // https://github.com/Mbed-TLS/mbedtls/issues/9072#issuecomment-2084845711
|
||||||
|
// this initializes global resources and then just returns when called again
|
||||||
#endif
|
#endif
|
||||||
mbedtls_ssl_init(&tls->ssl);
|
mbedtls_ssl_init(&tls->ssl);
|
||||||
mbedtls_ssl_config_init(&tls->conf);
|
mbedtls_ssl_config_init(&tls->conf);
|
||||||
@@ -135,7 +143,11 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
|||||||
mg_error(c, "tls defaults %#x", -mg_tls_err(c, rc));
|
mg_error(c, "tls defaults %#x", -mg_tls_err(c, rc));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x04000000
|
||||||
|
MG_INFO(("PSA is in control of random number generation"));
|
||||||
|
#else
|
||||||
mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c);
|
mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (opts->ca.len == 0 || mg_strcmp(opts->ca, mg_str("*")) == 0) {
|
if (opts->ca.len == 0 || mg_strcmp(opts->ca, mg_str("*")) == 0) {
|
||||||
// NOTE: MBEDTLS_SSL_VERIFY_NONE is not supported for TLS1.3 on client side
|
// NOTE: MBEDTLS_SSL_VERIFY_NONE is not supported for TLS1.3 on client side
|
||||||
@@ -144,11 +156,16 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
|||||||
} else {
|
} else {
|
||||||
if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail;
|
if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail;
|
||||||
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
|
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
|
||||||
if (c->is_client && opts->name.buf != NULL && opts->name.buf[0] != '\0') {
|
if (c->is_client) {
|
||||||
char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf);
|
if (opts->name.buf != NULL && opts->name.buf[0] != '\0') {
|
||||||
mbedtls_ssl_set_hostname(&tls->ssl, host);
|
char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf);
|
||||||
MG_DEBUG(("%lu hostname verification: %s", c->id, host));
|
mbedtls_ssl_set_hostname(&tls->ssl, host);
|
||||||
mg_free(host);
|
MG_DEBUG(("%lu hostname verification: %s", c->id, host));
|
||||||
|
mg_free(host);
|
||||||
|
} else {
|
||||||
|
MG_DEBUG(("%lu skipping hostname verification", c->id));
|
||||||
|
mbedtls_ssl_set_hostname(&tls->ssl, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||||
}
|
}
|
||||||
@@ -187,7 +204,7 @@ size_t mg_tls_pending(struct mg_connection *c) {
|
|||||||
long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
|
long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
|
||||||
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
||||||
long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
|
long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
|
||||||
if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP
|
if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP
|
||||||
if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
|
if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||||
return MG_IO_WAIT;
|
return MG_IO_WAIT;
|
||||||
#if defined(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
|
#if defined(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
|
||||||
@@ -211,10 +228,11 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
|
|||||||
(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE);
|
(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE);
|
||||||
if (was_throttled) return MG_IO_WAIT; // flushed throttled data instead
|
if (was_throttled) return MG_IO_WAIT; // flushed throttled data instead
|
||||||
if (c->is_tls_throttled) {
|
if (c->is_tls_throttled) {
|
||||||
tls->throttled_buf = (unsigned char *)buf; // MbedTLS code actually ignores
|
tls->throttled_buf =
|
||||||
tls->throttled_len = len; // these, but let's play API rules
|
(unsigned char *) buf; // MbedTLS code actually ignores
|
||||||
return (long) len; // already encripted that when throttled
|
tls->throttled_len = len; // these, but let's play API rules
|
||||||
} // if last chunk fails to be sent, it needs to be flushed
|
return (long) len; // already encripted that when throttled
|
||||||
|
} // if last chunk fails to be sent, it needs to be flushed
|
||||||
if (n <= 0) return MG_IO_ERR;
|
if (n <= 0) return MG_IO_ERR;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -222,8 +240,10 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
|
|||||||
void mg_tls_flush(struct mg_connection *c) {
|
void mg_tls_flush(struct mg_connection *c) {
|
||||||
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
||||||
if (c->is_tls_throttled) {
|
if (c->is_tls_throttled) {
|
||||||
long n = mbedtls_ssl_write(&tls->ssl, tls->throttled_buf, tls->throttled_len);
|
long n =
|
||||||
c->is_tls_throttled = (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE);
|
mbedtls_ssl_write(&tls->ssl, tls->throttled_buf, tls->throttled_len);
|
||||||
|
c->is_tls_throttled =
|
||||||
|
(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,9 +255,14 @@ void mg_tls_ctx_init(struct mg_mgr *mgr) {
|
|||||||
#ifdef MBEDTLS_SSL_SESSION_TICKETS
|
#ifdef MBEDTLS_SSL_SESSION_TICKETS
|
||||||
int rc;
|
int rc;
|
||||||
mbedtls_ssl_ticket_init(&ctx->tickets);
|
mbedtls_ssl_ticket_init(&ctx->tickets);
|
||||||
|
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x04000000
|
||||||
|
if ((rc = mbedtls_ssl_ticket_setup(&ctx->tickets, PSA_ALG_GCM,
|
||||||
|
PSA_KEY_TYPE_AES, 128, 86400))
|
||||||
|
#else
|
||||||
if ((rc = mbedtls_ssl_ticket_setup(&ctx->tickets, mg_mbed_rng, NULL,
|
if ((rc = mbedtls_ssl_ticket_setup(&ctx->tickets, mg_mbed_rng, NULL,
|
||||||
MBEDTLS_CIPHER_AES_128_GCM, 86400)) !=
|
MBEDTLS_CIPHER_AES_128_GCM, 86400))
|
||||||
0) {
|
#endif
|
||||||
|
!= 0) {
|
||||||
MG_ERROR((" mbedtls_ssl_ticket_setup %#x", -rc));
|
MG_ERROR((" mbedtls_ssl_ticket_setup %#x", -rc));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+21
-4
@@ -28,6 +28,7 @@ static int mg_tls_err(struct mg_connection *c, struct mg_tls *tls, int res) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MG_TLS != MG_TLS_WOLFSSL
|
||||||
static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) {
|
static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) {
|
||||||
BIO *bio = BIO_new_mem_buf(ca.buf, (int) ca.len);
|
BIO *bio = BIO_new_mem_buf(ca.buf, (int) ca.len);
|
||||||
STACK_OF(X509_INFO) *certs =
|
STACK_OF(X509_INFO) *certs =
|
||||||
@@ -39,6 +40,7 @@ static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) {
|
|||||||
static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
|
static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
|
||||||
int i;
|
int i;
|
||||||
X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx);
|
X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx);
|
||||||
|
if (cert_store == NULL) return false;
|
||||||
for (i = 0; i < sk_X509_INFO_num(certs); i++) {
|
for (i = 0; i < sk_X509_INFO_num(certs); i++) {
|
||||||
X509_INFO *cert_info = sk_X509_INFO_value(certs, i);
|
X509_INFO *cert_info = sk_X509_INFO_value(certs, i);
|
||||||
if (cert_info->x509 && !X509_STORE_add_cert(cert_store, cert_info->x509))
|
if (cert_info->x509 && !X509_STORE_add_cert(cert_store, cert_info->x509))
|
||||||
@@ -46,6 +48,7 @@ static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static EVP_PKEY *load_key(struct mg_str s) {
|
static EVP_PKEY *load_key(struct mg_str s) {
|
||||||
BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len);
|
BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len);
|
||||||
@@ -57,9 +60,9 @@ static EVP_PKEY *load_key(struct mg_str s) {
|
|||||||
static X509 *load_cert(struct mg_str s) {
|
static X509 *load_cert(struct mg_str s) {
|
||||||
BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len);
|
BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len);
|
||||||
X509 *cert = bio == NULL ? NULL
|
X509 *cert = bio == NULL ? NULL
|
||||||
: s.buf[0] == '-'
|
: MG_IS_DER(s.buf)
|
||||||
? PEM_read_bio_X509(bio, NULL, NULL, NULL) // PEM
|
? d2i_X509_bio(bio, NULL) // DER
|
||||||
: d2i_X509_bio(bio, NULL); // DER
|
: PEM_read_bio_X509(bio, NULL, NULL, NULL); // PEM
|
||||||
if (bio) BIO_free(bio);
|
if (bio) BIO_free(bio);
|
||||||
return cert;
|
return cert;
|
||||||
}
|
}
|
||||||
@@ -170,9 +173,21 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
|||||||
SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL);
|
SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (opts->ca.buf != NULL && opts->ca.buf[0] != '\0') {
|
if (opts->ca.buf != NULL && opts->ca.buf[0] != '\0') {
|
||||||
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||||
NULL);
|
NULL);
|
||||||
|
#if MG_TLS == MG_TLS_WOLFSSL
|
||||||
|
extern int wolfSSL_CTX_load_verify_buffer(SSL_CTX *, const unsigned char *,
|
||||||
|
long, int);
|
||||||
|
rc = wolfSSL_CTX_load_verify_buffer(tls->ctx,
|
||||||
|
(const unsigned char *) opts->ca.buf,
|
||||||
|
(long) opts->ca.len, SSL_FILETYPE_PEM);
|
||||||
|
if (rc != 1) {
|
||||||
|
mg_error(c, "CA err");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#else
|
||||||
STACK_OF(X509_INFO) *certs = load_ca_certs(opts->ca);
|
STACK_OF(X509_INFO) *certs = load_ca_certs(opts->ca);
|
||||||
rc = add_ca_certs(tls->ctx, certs);
|
rc = add_ca_certs(tls->ctx, certs);
|
||||||
sk_X509_INFO_pop_free(certs, X509_INFO_free);
|
sk_X509_INFO_pop_free(certs, X509_INFO_free);
|
||||||
@@ -180,7 +195,9 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
|||||||
mg_error(c, "CA err");
|
mg_error(c, "CA err");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->cert.buf != NULL && opts->cert.buf[0] != '\0') {
|
if (opts->cert.buf != NULL && opts->cert.buf[0] != '\0') {
|
||||||
X509 *cert = load_cert(opts->cert);
|
X509 *cert = load_cert(opts->cert);
|
||||||
rc = cert == NULL ? 0 : SSL_use_certificate(tls->ssl, cert);
|
rc = cert == NULL ? 0 : SSL_use_certificate(tls->ssl, cert);
|
||||||
@@ -258,7 +275,7 @@ size_t mg_tls_pending(struct mg_connection *c) {
|
|||||||
long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
|
long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
|
||||||
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
||||||
int n = SSL_read(tls->ssl, buf, (int) len);
|
int n = SSL_read(tls->ssl, buf, (int) len);
|
||||||
if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP
|
if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP
|
||||||
if (n < 0 && mg_tls_err(c, tls, n) == 0) return MG_IO_WAIT;
|
if (n < 0 && mg_tls_err(c, tls, n) == 0) return MG_IO_WAIT;
|
||||||
if (n <= 0) return MG_IO_ERR;
|
if (n <= 0) return MG_IO_ERR;
|
||||||
return n;
|
return n;
|
||||||
|
|||||||
+45
-2
@@ -1520,7 +1520,6 @@ NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/**
|
/**
|
||||||
* @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
|
* @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
|
||||||
*
|
*
|
||||||
@@ -1533,6 +1532,7 @@ NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) {
|
|||||||
* @param qInv [in] CRT's qInv bigint
|
* @param qInv [in] CRT's qInv bigint
|
||||||
* @return The result of the CRT operation
|
* @return The result of the CRT operation
|
||||||
*/
|
*/
|
||||||
|
#if 1
|
||||||
NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ,
|
NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ,
|
||||||
bigint *p, bigint *q, bigint *qInv) {
|
bigint *p, bigint *q, bigint *qInv) {
|
||||||
bigint *m1, *m2, *h;
|
bigint *m1, *m2, *h;
|
||||||
@@ -1559,7 +1559,6 @@ NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Proper lib usage:
|
// Proper lib usage:
|
||||||
// - BI_CTX *c = bi_initialize()
|
// - BI_CTX *c = bi_initialize()
|
||||||
// - allocate bigints (e.g.: calling bi_import(), int_to_bi(), ...)
|
// - allocate bigints (e.g.: calling bi_import(), int_to_bi(), ...)
|
||||||
@@ -1588,4 +1587,48 @@ int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
|
||||||
|
const uint8_t *dP, size_t dP_len,
|
||||||
|
const uint8_t *dQ, size_t dQ_len,
|
||||||
|
const uint8_t *p, size_t p_len,
|
||||||
|
const uint8_t *q, size_t q_len,
|
||||||
|
const uint8_t *qInv, size_t qInv_len,
|
||||||
|
uint8_t *signature, size_t sig_len) {
|
||||||
|
BI_CTX *ctx;
|
||||||
|
bigint *em_bi, *dP_bi, *dQ_bi, *p_bi, *q_bi, *qInv_bi, *result_bi;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
ctx = bi_initialize();
|
||||||
|
if (ctx == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
em_bi = bi_import(ctx, em, (int) em_len);
|
||||||
|
dP_bi = bi_import(ctx, dP, (int) dP_len);
|
||||||
|
dQ_bi = bi_import(ctx, dQ, (int) dQ_len);
|
||||||
|
p_bi = bi_import(ctx, p, (int) p_len);
|
||||||
|
q_bi = bi_import(ctx, q, (int) q_len);
|
||||||
|
qInv_bi = bi_import(ctx, qInv, (int) qInv_len);
|
||||||
|
|
||||||
|
if (em_bi == NULL || dP_bi == NULL || dQ_bi == NULL ||
|
||||||
|
p_bi == NULL || q_bi == NULL || qInv_bi == NULL) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
bi_set_mod(ctx, bi_clone(ctx, p_bi), BIGINT_P_OFFSET);
|
||||||
|
bi_set_mod(ctx, bi_clone(ctx, q_bi), BIGINT_Q_OFFSET);
|
||||||
|
|
||||||
|
result_bi = bi_crt(ctx, em_bi, dP_bi, dQ_bi, p_bi, q_bi, qInv_bi);
|
||||||
|
if (result_bi == NULL) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
bi_export(ctx, result_bi, signature, (int) sig_len);
|
||||||
|
ret = 0; // Success!
|
||||||
|
cleanup:
|
||||||
|
bi_free_mod(ctx, BIGINT_P_OFFSET); // cloned p_bi stored in mod context
|
||||||
|
bi_free_mod(ctx, BIGINT_Q_OFFSET); // cloned q_bi stored in mod context
|
||||||
|
bi_terminate(ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* MG_TLS == MG_TLS_BUILTIN */
|
#endif /* MG_TLS == MG_TLS_BUILTIN */
|
||||||
+7
-1
@@ -3,5 +3,11 @@
|
|||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
|
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
|
||||||
|
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
|
||||||
|
const uint8_t *dP, size_t dP_len,
|
||||||
|
const uint8_t *dQ, size_t dQ_len,
|
||||||
|
const uint8_t *p, size_t p_len,
|
||||||
|
const uint8_t *q, size_t q_len,
|
||||||
|
const uint8_t *qInv, size_t qInv_len,
|
||||||
|
uint8_t *signature, size_t sig_len);
|
||||||
#endif // TLS_RSA_H
|
#endif // TLS_RSA_H
|
||||||
+15
-3
@@ -27,6 +27,15 @@ bool mg_random(void *buf, size_t len) {
|
|||||||
#elif MG_ARCH == MG_ARCH_PICOSDK
|
#elif MG_ARCH == MG_ARCH_PICOSDK
|
||||||
while (len--) *p++ = (unsigned char) (get_rand_32() & 255);
|
while (len--) *p++ = (unsigned char) (get_rand_32() & 255);
|
||||||
success = true;
|
success = true;
|
||||||
|
#elif MG_ARCH == MG_ARCH_ZEPHYR
|
||||||
|
#if MG_TLS == MG_TLS_BUILTIN || \
|
||||||
|
(MG_TLS == MG_TLS_MBED && (!defined(MBEDTLS_VERSION_NUMBER) || \
|
||||||
|
MBEDTLS_VERSION_NUMBER < 0x04000000))
|
||||||
|
return (sys_csrand_get(buf, len) == 0); // do not fallback on reseed error
|
||||||
|
#else
|
||||||
|
sys_rand_get(buf, len);
|
||||||
|
success = true;
|
||||||
|
#endif
|
||||||
#elif MG_ARCH == MG_ARCH_WIN32
|
#elif MG_ARCH == MG_ARCH_WIN32
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1700
|
#if defined(_MSC_VER) && _MSC_VER < 1700
|
||||||
static bool initialised = false;
|
static bool initialised = false;
|
||||||
@@ -120,7 +129,7 @@ int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip) {
|
|||||||
if (remote_ip->is_ip6) {
|
if (remote_ip->is_ip6) {
|
||||||
return -1; // TODO(): handle IPv6 ACL and addresses
|
return -1; // TODO(): handle IPv6 ACL and addresses
|
||||||
} else { // IPv4
|
} else { // IPv4
|
||||||
memcpy((void *) &remote_ip4, remote_ip->ip, sizeof(remote_ip4));
|
memcpy((void *) &remote_ip4, remote_ip->addr.ip, sizeof(remote_ip4));
|
||||||
while (mg_span(acl, &entry, &acl, ',')) {
|
while (mg_span(acl, &entry, &acl, ',')) {
|
||||||
uint32_t net, mask;
|
uint32_t net, mask;
|
||||||
if (entry.buf[0] != '+' && entry.buf[0] != '-') return -1;
|
if (entry.buf[0] != '+' && entry.buf[0] != '-') return -1;
|
||||||
@@ -134,7 +143,7 @@ int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip) {
|
|||||||
bool mg_path_is_sane(const struct mg_str path) {
|
bool mg_path_is_sane(const struct mg_str path) {
|
||||||
const char *s = path.buf;
|
const char *s = path.buf;
|
||||||
size_t n = path.len;
|
size_t n = path.len;
|
||||||
if (path.buf[0] == '~') return false; // Starts with ~
|
if (path.buf[0] == '~') return false; // Starts with ~
|
||||||
if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with ..
|
if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with ..
|
||||||
for (; s[0] != '\0' && n > 0; s++, n--) {
|
for (; s[0] != '\0' && n > 0; s++, n--) {
|
||||||
if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir?
|
if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir?
|
||||||
@@ -204,12 +213,15 @@ uint32_t mg_ntohl(uint32_t net) {
|
|||||||
return MG_LOAD_BE32(&net);
|
return MG_LOAD_BE32(&net);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t mg_ntohll(uint64_t net) {
|
||||||
|
return MG_LOAD_BE64(&net);
|
||||||
|
}
|
||||||
|
|
||||||
void mg_delayms(unsigned int ms) {
|
void mg_delayms(unsigned int ms) {
|
||||||
uint64_t to = mg_millis() + ms + 1;
|
uint64_t to = mg_millis() + ms + 1;
|
||||||
while (mg_millis() < to) (void) 0;
|
while (mg_millis() < to) (void) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if MG_ENABLE_CUSTOM_CALLOC
|
#if MG_ENABLE_CUSTOM_CALLOC
|
||||||
#else
|
#else
|
||||||
void *mg_calloc(size_t count, size_t size) {
|
void *mg_calloc(size_t count, size_t size) {
|
||||||
|
|||||||
+31
@@ -27,6 +27,16 @@ void mg_delayms(unsigned int ms);
|
|||||||
|
|
||||||
#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
|
#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
|
||||||
|
|
||||||
|
#define MG_IPV6(a, b, c, d, e, f, g ,h) \
|
||||||
|
{ (uint8_t)((a)>>8),(uint8_t)(a), \
|
||||||
|
(uint8_t)((b)>>8),(uint8_t)(b), \
|
||||||
|
(uint8_t)((c)>>8),(uint8_t)(c), \
|
||||||
|
(uint8_t)((d)>>8),(uint8_t)(d), \
|
||||||
|
(uint8_t)((e)>>8),(uint8_t)(e), \
|
||||||
|
(uint8_t)((f)>>8),(uint8_t)(f), \
|
||||||
|
(uint8_t)((g)>>8),(uint8_t)(g), \
|
||||||
|
(uint8_t)((h)>>8),(uint8_t)(h) }
|
||||||
|
|
||||||
// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
|
// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
|
||||||
#define MG_U8P(ADDR) ((uint8_t *) (ADDR))
|
#define MG_U8P(ADDR) ((uint8_t *) (ADDR))
|
||||||
#define MG_IPADDR_PARTS(ADDR) \
|
#define MG_IPADDR_PARTS(ADDR) \
|
||||||
@@ -41,6 +51,14 @@ void mg_delayms(unsigned int ms);
|
|||||||
((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
|
((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
|
||||||
((uint32_t) MG_U8P(p)[1] << 16U) | \
|
((uint32_t) MG_U8P(p)[1] << 16U) | \
|
||||||
((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
|
((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
|
||||||
|
#define MG_LOAD_BE64(p) \
|
||||||
|
((uint64_t) (((uint64_t) MG_U8P(p)[0] << 56U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[1] << 48U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[2] << 40U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[3] << 32U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[4] << 24U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[5] << 16U) | \
|
||||||
|
((uint64_t) MG_U8P(p)[6] << 8U) | MG_U8P(p)[7]))
|
||||||
#define MG_STORE_BE16(p, n) \
|
#define MG_STORE_BE16(p, n) \
|
||||||
do { \
|
do { \
|
||||||
MG_U8P(p)[0] = ((n) >> 8U) & 255; \
|
MG_U8P(p)[0] = ((n) >> 8U) & 255; \
|
||||||
@@ -59,11 +77,24 @@ void mg_delayms(unsigned int ms);
|
|||||||
MG_U8P(p)[2] = ((n) >> 8U) & 255; \
|
MG_U8P(p)[2] = ((n) >> 8U) & 255; \
|
||||||
MG_U8P(p)[3] = (n) &255; \
|
MG_U8P(p)[3] = (n) &255; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
#define MG_STORE_BE64(p, n) \
|
||||||
|
do { \
|
||||||
|
MG_U8P(p)[0] = ((n) >> 56U) & 255; \
|
||||||
|
MG_U8P(p)[1] = ((n) >> 48U) & 255; \
|
||||||
|
MG_U8P(p)[2] = ((n) >> 40U) & 255; \
|
||||||
|
MG_U8P(p)[3] = ((n) >> 32U) & 255; \
|
||||||
|
MG_U8P(p)[4] = ((n) >> 24U) & 255; \
|
||||||
|
MG_U8P(p)[5] = ((n) >> 16U) & 255; \
|
||||||
|
MG_U8P(p)[6] = ((n) >> 8U) & 255; \
|
||||||
|
MG_U8P(p)[7] = (n) &255; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
uint16_t mg_ntohs(uint16_t net);
|
uint16_t mg_ntohs(uint16_t net);
|
||||||
uint32_t mg_ntohl(uint32_t net);
|
uint32_t mg_ntohl(uint32_t net);
|
||||||
|
uint64_t mg_ntohll(uint64_t net);
|
||||||
#define mg_htons(x) mg_ntohs(x)
|
#define mg_htons(x) mg_ntohs(x)
|
||||||
#define mg_htonl(x) mg_ntohl(x)
|
#define mg_htonl(x) mg_ntohl(x)
|
||||||
|
#define mg_htonll(x) mg_ntohll(x)
|
||||||
|
|
||||||
#define MG_REG(x) ((volatile uint32_t *) (x))[0]
|
#define MG_REG(x) ((volatile uint32_t *) (x))[0]
|
||||||
#define MG_BIT(x) (((uint32_t) 1U) << (x))
|
#define MG_BIT(x) (((uint32_t) 1U) << (x))
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
#define MG_VERSION "7.19"
|
#define MG_VERSION "7.21"
|
||||||
+31
-17
@@ -4,26 +4,40 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
struct mg_wifi_scan_bss_data {
|
struct mg_wifi_data {
|
||||||
struct mg_str SSID;
|
char *ssid, *pass; // STA mode, SSID to connect to
|
||||||
char *BSSID;
|
char *apssid, *appass; // AP mode, our SSID
|
||||||
int16_t RSSI;
|
uint32_t apip, apmask; // AP mode, our IP address and mask
|
||||||
uint8_t security;
|
uint8_t security; // STA mode, TBD
|
||||||
#define MG_WIFI_SECURITY_OPEN 0
|
uint8_t apsecurity; // AP mode, TBD
|
||||||
#define MG_WIFI_SECURITY_WEP MG_BIT(0)
|
uint8_t apchannel; // AP mode, channel to use
|
||||||
#define MG_WIFI_SECURITY_WPA MG_BIT(1)
|
bool apmode; // start in AP mode; 'false' -> connect to 'ssid' != NULL
|
||||||
#define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
|
|
||||||
#define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
|
|
||||||
uint8_t channel;
|
|
||||||
unsigned band :2;
|
|
||||||
#define MG_WIFI_BAND_2G 0
|
|
||||||
#define MG_WIFI_BAND_5G 1
|
|
||||||
unsigned has_n :1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mg_wifi_scan_bss_data {
|
||||||
|
struct mg_str SSID;
|
||||||
|
char *BSSID;
|
||||||
|
int16_t RSSI;
|
||||||
|
uint8_t security;
|
||||||
|
#define MG_WIFI_SECURITY_OPEN 0
|
||||||
|
#define MG_WIFI_SECURITY_WEP MG_BIT(0)
|
||||||
|
#define MG_WIFI_SECURITY_WPA MG_BIT(1)
|
||||||
|
#define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
|
||||||
|
#define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
|
||||||
|
#define MG_WIFI_SECURITY_WPA_ENTERPRISE MG_BIT(4)
|
||||||
|
#define MG_WIFI_SECURITY_WPA2_ENTERPRISE MG_BIT(5)
|
||||||
|
#define MG_WIFI_SECURITY_WPA3_ENTERPRISE MG_BIT(6)
|
||||||
|
uint8_t channel;
|
||||||
|
unsigned band : 2;
|
||||||
|
#define MG_WIFI_BAND_2G 0
|
||||||
|
#define MG_WIFI_BAND_5G 1
|
||||||
|
unsigned has_n : 1;
|
||||||
|
unsigned has_ac : 1;
|
||||||
|
unsigned has_ax : 1;
|
||||||
|
};
|
||||||
|
|
||||||
bool mg_wifi_scan(void);
|
bool mg_wifi_scan(void);
|
||||||
bool mg_wifi_connect(char *ssid, char *pass);
|
bool mg_wifi_connect(struct mg_wifi_data *);
|
||||||
bool mg_wifi_disconnect(void);
|
bool mg_wifi_disconnect(void);
|
||||||
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel);
|
bool mg_wifi_ap_start(struct mg_wifi_data *);
|
||||||
bool mg_wifi_ap_stop(void);
|
bool mg_wifi_ap_stop(void);
|
||||||
+7
-8
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
#if (!defined(MG_ENABLE_DRIVER_PICO_W) || !MG_ENABLE_DRIVER_PICO_W) && \
|
#if (!defined(MG_ENABLE_DRIVER_PICO_W) || !MG_ENABLE_DRIVER_PICO_W) && \
|
||||||
(!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW) && \
|
(!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW) && \
|
||||||
(!defined(MG_ENABLE_DRIVER_CYW_SDIO) || !MG_ENABLE_DRIVER_CYW_SDIO)
|
(!defined(MG_ENABLE_DRIVER_CYW_SDIO) || !MG_ENABLE_DRIVER_CYW_SDIO) && \
|
||||||
|
(!defined(MG_ENABLE_DRIVER_NXP_WIFI) || !MG_ENABLE_DRIVER_NXP_WIFI) && \
|
||||||
|
(!defined(MG_ENABLE_DRIVER_ST67W6) || !MG_ENABLE_DRIVER_ST67W6)
|
||||||
|
|
||||||
|
|
||||||
bool mg_wifi_scan(void) {
|
bool mg_wifi_scan(void) {
|
||||||
@@ -10,9 +12,8 @@ bool mg_wifi_scan(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_wifi_connect(char *ssid, char *pass) {
|
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
|
||||||
(void) ssid;
|
(void) wifi;
|
||||||
(void) pass;
|
|
||||||
return mg_wifi_scan();
|
return mg_wifi_scan();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,10 +21,8 @@ bool mg_wifi_disconnect(void) {
|
|||||||
return mg_wifi_scan();
|
return mg_wifi_scan();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
|
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
|
||||||
(void) ssid;
|
(void) wifi;
|
||||||
(void) pass;
|
|
||||||
(void) channel;
|
|
||||||
return mg_wifi_scan();
|
return mg_wifi_scan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ static void ws_handshake(struct mg_connection *c, const struct mg_str *wskey,
|
|||||||
mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len,
|
mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len,
|
||||||
wsproto->buf);
|
wsproto->buf);
|
||||||
}
|
}
|
||||||
mg_send(c, "\r\n", 2);
|
if (!mg_send(c, "\r\n", 2)) mg_error(c, "OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t be32(const uint8_t *p) {
|
static uint32_t be32(const uint8_t *p) {
|
||||||
@@ -173,9 +173,13 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
|
|
||||||
while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
|
while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
|
||||||
char *s = (char *) c->recv.buf + ofs + msg.header_len;
|
char *s = (char *) c->recv.buf + ofs + msg.header_len;
|
||||||
struct mg_ws_message m = {{s, msg.data_len}, msg.flags};
|
struct mg_ws_message m;
|
||||||
size_t len = msg.header_len + msg.data_len;
|
size_t len;
|
||||||
uint8_t final = msg.flags & 128, op = msg.flags & 15;
|
uint8_t final, op;
|
||||||
|
m.data.buf = s, m.data.len = msg.data_len, m.flags = msg.flags;
|
||||||
|
len = msg.header_len + msg.data_len;
|
||||||
|
final = msg.flags & 128;
|
||||||
|
op = msg.flags & 15;
|
||||||
// MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op,
|
// MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op,
|
||||||
// (int) m.data.len, (int) m.data.len, m.data.buf));
|
// (int) m.data.len, (int) m.data.len, m.data.buf));
|
||||||
switch (op) {
|
switch (op) {
|
||||||
@@ -292,6 +296,6 @@ size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) {
|
|||||||
memmove(p, p - header_len, len); // Shift data
|
memmove(p, p - header_len, len); // Shift data
|
||||||
memcpy(p - header_len, header, header_len); // Prepend header
|
memcpy(p - header_len, header, header_len); // Prepend header
|
||||||
mg_ws_mask(c, len); // Mask data
|
mg_ws_mask(c, len); // Mask data
|
||||||
}
|
} // returning 0 means an OOM condition (iobuf couldn't resize), yet this is
|
||||||
return c->send.len;
|
return c->send.len; // so far recoverable, let the caller decide
|
||||||
}
|
}
|
||||||
+26
-4
@@ -91,9 +91,18 @@ mip_tap_test: mip_tap_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_mult
|
|||||||
$(CC) mip_tap_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
|
$(CC) mip_tap_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
|
||||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||||
|
|
||||||
|
# bridge UDP port <--> TAP interface
|
||||||
|
port_tap_bridge: port_tap_bridge.c
|
||||||
|
cc port_tap_bridge.c -o $@
|
||||||
|
|
||||||
|
# requires port_tap_bridge to be running
|
||||||
|
mip_port_test: mip_port_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_multirec/server
|
||||||
|
$(CC) mip_port_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
|
||||||
|
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||||
|
|
||||||
mip_vc98: mip_test.c mongoose.c mongoose.h packed_fs.c Makefile
|
mip_vc98: mip_test.c mongoose.c mongoose.h packed_fs.c Makefile
|
||||||
$(DOCKER) mdashnet/vc98 wine cl mip_test.c packed_fs.c $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
|
$(DOCKER) mdashnet/vc98 wine cl mip_test.c packed_fs.c $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
|
||||||
$(DOCKER) mdashnet/vc98 wine $@.exe
|
$(DOCKER) -e WINEPREFIX=/tmp/wineprefix mdashnet/vc98 wine $@.exe
|
||||||
|
|
||||||
packed_fs.c: Makefile data/ssi.h fuzz.c data/a.txt data/ca.pem certs/ca.crt certs/server.crt certs/server.key
|
packed_fs.c: Makefile data/ssi.h fuzz.c data/a.txt data/ca.pem certs/ca.crt certs/server.crt certs/server.key
|
||||||
$(CC) $(CFLAGS) pack.c -o pack
|
$(CC) $(CFLAGS) pack.c -o pack
|
||||||
@@ -179,11 +188,23 @@ armhf: test
|
|||||||
s390: ASAN=
|
s390: ASAN=
|
||||||
s390: IPV6=0
|
s390: IPV6=0
|
||||||
s390: CFLAGS += -Wno-stringop-overflow
|
s390: CFLAGS += -Wno-stringop-overflow
|
||||||
s390: DEFS += -DMG_ENABLE_CHACHA20=0
|
|
||||||
s390: CC = $(DOCKER) mdashnet/s390 cc
|
s390: CC = $(DOCKER) mdashnet/s390 cc
|
||||||
s390: RUN = $(DOCKER) --init mdashnet/s390
|
s390: RUN = $(DOCKER) --init mdashnet/s390
|
||||||
s390: test
|
s390: test
|
||||||
|
|
||||||
|
mip_s390: ASAN=
|
||||||
|
mip_s390: CC = $(DOCKER) mdashnet/s390 cc
|
||||||
|
mip_s390: RUN = $(DOCKER) --init mdashnet/s390
|
||||||
|
mip_s390: mip_test
|
||||||
|
|
||||||
|
mip_port_s390: ASAN=
|
||||||
|
mip_port_s390: IPV6=0
|
||||||
|
# This test requires curl, not present in this image
|
||||||
|
mip_port_s390: CFLAGS += -DNO_HTTPSERVER_TEST
|
||||||
|
mip_port_s390: CC = $(DOCKER) mdashnet/s390 cc
|
||||||
|
mip_port_s390: RUN = $(DOCKER) --init mdashnet/s390
|
||||||
|
mip_port_s390: mip_port_test
|
||||||
|
|
||||||
arm: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_ARMGCC -DNO_SLEEP_ABORT
|
arm: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_ARMGCC -DNO_SLEEP_ABORT
|
||||||
arm: mongoose.h $(SRCS)
|
arm: mongoose.h $(SRCS)
|
||||||
$(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test -nostartfiles --specs nosys.specs -e 0
|
$(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test -nostartfiles --specs nosys.specs -e 0
|
||||||
@@ -194,7 +215,7 @@ riscv: mongoose.h $(SRCS)
|
|||||||
|
|
||||||
vc98: Makefile mongoose.h $(SRCS)
|
vc98: Makefile mongoose.h $(SRCS)
|
||||||
$(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
|
$(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
|
||||||
$(DOCKER) mdashnet/vc98 wine $@.exe
|
$(DOCKER) -e WINEPREFIX=/tmp/wineprefix mdashnet/vc98 wine $@.exe
|
||||||
|
|
||||||
vc17: Makefile mongoose.h $(SRCS)
|
vc17: Makefile mongoose.h $(SRCS)
|
||||||
$(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
|
$(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
|
||||||
@@ -230,11 +251,12 @@ mongoose.c: Makefile $(wildcard ../src/*.c) $(wildcard ../src/drivers/*.c)
|
|||||||
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
||||||
|
|
||||||
mongoose.h: $(HDRS) Makefile
|
mongoose.h: $(HDRS) Makefile
|
||||||
cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/flash.h src/wifi.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/flash.h src/wifi.h src/l2.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
||||||
|
|
||||||
|
|
||||||
clean: clean_tutorials clean_tutorials_embedded
|
clean: clean_tutorials clean_tutorials_embedded
|
||||||
rm -rf $(PROG) *.exe *.o *.dSYM *_test ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* packed_fs.c pack
|
rm -rf $(PROG) *.exe *.o *.dSYM *_test ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* packed_fs.c pack
|
||||||
|
$(MAKE) -C tls_multirec $@
|
||||||
#find tutorials -maxdepth 3 -name zephyr -prune -o -name Makefile -print | xargs dirname | xargs -n1 make clean -C
|
#find tutorials -maxdepth 3 -name zephyr -prune -o -name Makefile -print | xargs dirname | xargs -n1 make clean -C
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
- Make sure your PEM file starts with a dash -
|
|
||||||
|
|
||||||
|
|
||||||
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
|
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
|
||||||
Not Before: Mar 13 00:00:00 2024 GMT
|
Not Before: Mar 13 00:00:00 2024 GMT
|
||||||
Not After : Mar 12 23:59:59 2027 GMT
|
Not After : Mar 12 23:59:59 2027 GMT
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
- Make sure your PEM file starts with a dash -
|
|
||||||
|
|
||||||
|
|
||||||
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
|
|
||||||
Not Before: Mar 13 00:00:00 2024 GMT
|
|
||||||
Not After : Mar 12 23:59:59 2027 GMT
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw
|
|
||||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
|
||||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
|
|
||||||
WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
|
||||||
RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK
|
|
||||||
a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO
|
|
||||||
VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw
|
|
||||||
gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
|
|
||||||
ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw
|
|
||||||
i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
|
|
||||||
AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g
|
|
||||||
BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu
|
|
||||||
Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C
|
|
||||||
2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+
|
|
||||||
bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG
|
|
||||||
6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV
|
|
||||||
XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO
|
|
||||||
koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq
|
|
||||||
cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI
|
|
||||||
E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e
|
|
||||||
K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX
|
|
||||||
GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL
|
|
||||||
sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd
|
|
||||||
VQD9F6Na/+zmXCc=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
1 s:C=US, O=Let's Encrypt, CN=E8
|
||||||
|
i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
|
||||||
|
a:PKEY: id-ecPublicKey, 384 (bit); sigalg: RSA-SHA256
|
||||||
|
v:NotBefore: Mar 13 00:00:00 2024 GMT; NotAfter: Mar 12 23:59:59 2027 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP
|
||||||
|
MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy
|
||||||
|
Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa
|
||||||
|
Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF
|
||||||
|
bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c
|
||||||
|
S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb
|
||||||
|
R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB
|
||||||
|
9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB
|
||||||
|
MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j
|
||||||
|
cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB
|
||||||
|
BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE
|
||||||
|
DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j
|
||||||
|
ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0
|
||||||
|
RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d
|
||||||
|
AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8
|
||||||
|
otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA
|
||||||
|
aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm
|
||||||
|
Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2
|
||||||
|
HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1
|
||||||
|
Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR
|
||||||
|
xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d
|
||||||
|
tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/
|
||||||
|
jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS
|
||||||
|
u1igv3OefnWjSQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
- Make sure your PEM file starts with a dash -
|
|
||||||
|
|
||||||
Certificate:
|
Certificate:
|
||||||
Data:
|
Data:
|
||||||
Version: 3 (0x2)
|
Version: 3 (0x2)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
- Make sure your PEM file starts with a dash -
|
|
||||||
|
|
||||||
Certificate:
|
Certificate:
|
||||||
Data:
|
Data:
|
||||||
Version: 3 (0x2)
|
Version: 3 (0x2)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
- Make sure your PEM file starts with a dash -
|
|
||||||
|
|
||||||
Certificate:
|
Certificate:
|
||||||
Data:
|
Data:
|
||||||
Version: 3 (0x2)
|
Version: 3 (0x2)
|
||||||
|
|||||||
+52
-18
@@ -62,6 +62,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
mg_crc32(0, mm.topic.buf, mm.topic.len);
|
mg_crc32(0, mm.topic.buf, mm.topic.len);
|
||||||
mg_crc32(0, mm.data.buf, mm.data.len);
|
mg_crc32(0, mm.data.buf, mm.data.len);
|
||||||
mg_crc32(0, mm.dgram.buf, mm.dgram.len);
|
mg_crc32(0, mm.dgram.buf, mm.dgram.len);
|
||||||
|
{
|
||||||
|
struct mg_mqtt_prop prop;
|
||||||
|
size_t ofs = 0;
|
||||||
|
while ((ofs = mg_mqtt_next_prop(&mm, &prop, ofs)) > 0) {
|
||||||
|
mg_crc32(0, prop.key.buf, prop.key.len);
|
||||||
|
mg_crc32(0, prop.val.buf, prop.val.len);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mg_mqtt_parse(NULL, 0, 5, &mm);
|
mg_mqtt_parse(NULL, 0, 5, &mm);
|
||||||
|
|
||||||
@@ -86,9 +94,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
|
|
||||||
// Test built-in TCP/IP stack
|
// Test built-in TCP/IP stack
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
struct mg_tcpip_if mif = {.ip = 0x01020304,
|
struct mg_tcpip_if mif = {.ip = 1,
|
||||||
.mask = 255,
|
.mask = 255,
|
||||||
.gw = 0x01010101,
|
.gw = 1,
|
||||||
|
.gw_ready = true,
|
||||||
|
.state = MG_TCPIP_STATE_READY,
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
.ip6[0] = 1;
|
||||||
|
.prefix[0] = 1;
|
||||||
|
.prefix_len = 64;
|
||||||
|
.gw6[0] = 1;
|
||||||
|
.gw6_ready = true;
|
||||||
|
.state6 = MG_TCPIP_STATE_READY; // so mg_send() works and RS stops
|
||||||
|
#endif
|
||||||
.driver = &mg_tcpip_driver_mock};
|
.driver = &mg_tcpip_driver_mock};
|
||||||
struct mg_mgr mgr;
|
struct mg_mgr mgr;
|
||||||
mg_mgr_init(&mgr);
|
mg_mgr_init(&mgr);
|
||||||
@@ -100,45 +118,61 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
memcpy(pkt, data, size);
|
memcpy(pkt, data, size);
|
||||||
if (size > sizeof(*eth)) {
|
if (size > sizeof(*eth)) {
|
||||||
static size_t i;
|
static size_t i;
|
||||||
uint16_t eth_types[] = {0x800, 0x806, 0x86dd}; // IPv4, ARP, IPv6
|
// eth_types[] exists in l2_eth.c
|
||||||
memcpy(eth->dst, mif.mac, 6); // Set valid destination MAC
|
memcpy(eth->dst, mif.mac, 6); // Set valid destination MAC
|
||||||
// send all handled eth types, then 2 random ones
|
// send all handled eth types, then 2 random ones
|
||||||
if (i >= (sizeof(eth_types) / sizeof(eth_types[0]) + 2)) i = 0;
|
if (i >= (sizeof(eth_types) / sizeof(eth_types[0]) + 2)) i = 0;
|
||||||
if (i < (sizeof(eth_types) / sizeof(eth_types[0]))) eth->type = (eth_types[i++]);
|
if (i < (sizeof(eth_types) / sizeof(eth_types[0]))) eth->type = mg_htons(eth_types[i++]);
|
||||||
// build proper layer-3 datagrams, to be able to exercise layers above
|
// build proper layer-3 datagrams, to be able to exercise layers above
|
||||||
if (eth->type == mg_htons(0x800) && size > (sizeof(*eth) + sizeof(struct ip))) { // IPv4
|
if (eth->type == mg_htons(0x800) && size > (sizeof(*eth) + sizeof(struct ip))) { // IPv4
|
||||||
static size_t j;
|
static size_t j;
|
||||||
uint8_t ip_protos[] = {1, 6, 17}; // ICMP, TCP, UDP
|
uint8_t ip_protos[] = {1, 6, 17}; // ICMP, TCP, UDP
|
||||||
struct ip *ip4 = (struct ip *) (eth + 1);
|
struct ip *ip4 = (struct ip *) (eth + 1);
|
||||||
ip4->ver = (ip4->ver & ~0xf0) | (4 << 4);
|
ip4->ver = (ip4->ver & ~0xf0) | (4 << 4);
|
||||||
// send all handled ip protos, then 2 random ones
|
// send all handled IP protos, then 2 random ones
|
||||||
if (j >= (sizeof(ip_protos) / sizeof(ip_protos[0]) + 2)) j = 0;
|
if (j >= (sizeof(ip_protos) / sizeof(ip_protos[0]) + 2)) j = 0;
|
||||||
if (j < (sizeof(ip_protos) / sizeof(ip_protos[0]))) ip4->proto = (ip_protos[j++]);
|
if (j < (sizeof(ip_protos) / sizeof(ip_protos[0]))) ip4->proto = (ip_protos[j++]);
|
||||||
if (ip4->proto == 1) { // ICMP
|
if (ip4->proto == 1) { // ICMP
|
||||||
} else if (ip4->proto == 6) { // TCP
|
} else if (ip4->proto == 6) { // TCP
|
||||||
} else if (ip4->proto == 17 && size > (sizeof(*eth) + sizeof(struct ip) + sizeof(struct udp))) { // UDP
|
} else if (ip4->proto == 17) { // UDP
|
||||||
static size_t k;
|
if (size > (sizeof(*eth) + sizeof(struct ip) + sizeof(struct udp))) {
|
||||||
uint16_t udp_ports[] = {67, 68}; // DHCP server and client
|
static size_t k;
|
||||||
struct udp *udp = (struct udp *) (ip4 + 1);
|
uint16_t udp_ports[] = {67, 68}; // DHCP server and client
|
||||||
// send all handled udp ports, then 2 random ones
|
struct udp *udp = (struct udp *) (ip4 + 1);
|
||||||
if (k >= (sizeof(udp_ports) / sizeof(udp_ports[0]) + 2)) k = 0;
|
// send all handled UDP ports, then 2 random ones
|
||||||
if (k < (sizeof(udp_ports) / sizeof(udp_ports[0]))) udp->dport = mg_htons(udp_ports[k++]);
|
if (k >= (sizeof(udp_ports) / sizeof(udp_ports[0]) + 2)) k = 0;
|
||||||
|
if (k < (sizeof(udp_ports) / sizeof(udp_ports[0]))) udp->dport = mg_htons(udp_ports[k++]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (eth->type == mg_htons(0x806)) { // ARP
|
} else if (eth->type == mg_htons(0x806)) { // ARP
|
||||||
|
|
||||||
} else if (eth->type == mg_htons(0x86dd) && size > (sizeof(*eth) + sizeof(struct ip6))) { // IPv6
|
} else if (eth->type == mg_htons(0x86dd) && size > (sizeof(*eth) + sizeof(struct ip6))) { // IPv6
|
||||||
static size_t j;
|
static size_t j;
|
||||||
uint8_t ip6_protos[] = {6, 17}; // TCP, UDP
|
uint8_t ip6_protos[] = {6, 17, 58}; // TCP, UDP, ICMPv6
|
||||||
struct ip6 *ip6 = (struct ip6 *) (eth + 1);
|
struct ip6 *ip6 = (struct ip6 *) (eth + 1);
|
||||||
ip6->ver = (ip6->ver & ~0xf0) | (6 << 4);
|
ip6->ver = (ip6->ver & ~0xf0) | (6 << 4);
|
||||||
// send all handled ip6 "next headers", then 2 random ones
|
// send all handled IPv6 "next headers", then 2 random ones
|
||||||
if (j >= (sizeof(ip6_protos) / sizeof(ip6_protos[0]) + 2)) j = 0;
|
if (j >= (sizeof(ip6_protos) / sizeof(ip6_protos[0]) + 2)) j = 0;
|
||||||
if (j < (sizeof(ip6_protos) / sizeof(ip6_protos[0]))) ip6->proto = (ip6_protos[j++]);
|
if (j < (sizeof(ip6_protos) / sizeof(ip6_protos[0]))) ip6->next = (ip6_protos[j++]);
|
||||||
if (ip6->proto == 6) { // TCP
|
if (ip6->next == 6) { // TCP
|
||||||
} else if (ip6->proto == 17) { // UDP
|
} else if (ip6->next == 17) { // UDP
|
||||||
}
|
} else if (ip6->next == 58) { // ICMPv6
|
||||||
|
if (size >= (sizeof(*eth) + sizeof(struct ip6) + sizeof(struct icmp6))) {
|
||||||
|
static size_t k;
|
||||||
|
uint8_t icmp6_types[] = {128, 134, 135, 136}; // Echo Request, RA, NS, NA
|
||||||
|
struct icmp6 *icmp6 = (struct icmp6 *) (ip6 + 1);
|
||||||
|
// send all handled ICMPv6 types, then 2 random ones
|
||||||
|
if (k >= (sizeof(icmp6_types) / sizeof(icmp6_types[0]) + 2)) k = 0;
|
||||||
|
if (k < (sizeof(icmp6_types) / sizeof(icmp6_types[0]))) icmp6->type = icmp6_types[k++];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MAIN)
|
||||||
|
printf("Sending to net_builtin:\n");
|
||||||
|
mg_hexdump(pkt, size);
|
||||||
|
#endif
|
||||||
mg_tcpip_rx(&mif, pkt, size);
|
mg_tcpip_rx(&mif, pkt, size);
|
||||||
|
|
||||||
// Test HTTP serving (via our built-in TCP/IP stack)
|
// Test HTTP serving (via our built-in TCP/IP stack)
|
||||||
|
|||||||
+29
-7
@@ -18,10 +18,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
|
|||||||
// Preprocessor magic, just add/remove functions here and leave the rest alone
|
// Preprocessor magic, just add/remove functions here and leave the rest alone
|
||||||
#define TABLE(_) \
|
#define TABLE(_) \
|
||||||
_(mg_tls_server_recv_hello) \
|
_(mg_tls_server_recv_hello) \
|
||||||
//_(mg_tls_client_recv_hello) \
|
_(mg_tls_server_recv_finish) \
|
||||||
//_(mg_tls_client_recv_ext ) \
|
_(mg_tls_client_recv_hello) \
|
||||||
//_(mg_tls_client_recv_cert) \
|
_(mg_tls_client_recv_finish) \
|
||||||
//_(mg_tls_client_recv_cert_verify) \
|
_(mg_tls_client_recv_ext) \
|
||||||
|
_(mg_tls_recv_cert_verify) \
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
struct f {
|
struct f {
|
||||||
@@ -52,7 +53,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
c = &c_[i];
|
c = &c_[i];
|
||||||
io = &c->rtls;
|
io = &c->rtls;
|
||||||
if (i > 0) memcpy(c, &c_[0], sizeof(*c)); // copy from 1st one
|
if (i > 0) memcpy(c, &c_[0], sizeof(*c)); // copy from 1st one
|
||||||
if (i > 0) c->is_client = 1; // from 1 on, client functions
|
if (i > 1) c->is_client = 1; // from 2 on, client functions
|
||||||
memset(&tls_[i], 0, sizeof(struct tls_data));
|
memset(&tls_[i], 0, sizeof(struct tls_data));
|
||||||
if (io->size - io->len < size && !mg_iobuf_resize(io, io->len + size)) {
|
if (io->size - io->len < size && !mg_iobuf_resize(io, io->len + size)) {
|
||||||
mg_error(c, "oom");
|
mg_error(c, "oom");
|
||||||
@@ -64,10 +65,31 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
#ifdef PRINT_FUNCNAME
|
#ifdef PRINT_FUNCNAME
|
||||||
printf("CALLING %s\n", f_[i].name);
|
printf("CALLING %s\n", f_[i].name);
|
||||||
#endif
|
#endif
|
||||||
f_[i].f(&c[i]);
|
f_[i].f(c);
|
||||||
mg_iobuf_free(io);
|
mg_iobuf_free(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mg_tls_recv_cert() has an extra bool parameter
|
||||||
|
c = &c_[0]; // reuse first one
|
||||||
|
c->tls = &tls_[0];
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
struct mg_iobuf *io;
|
||||||
|
io = &c->rtls;
|
||||||
|
c->is_client = (i > 0);
|
||||||
|
memset(c->tls, 0, sizeof(struct tls_data));
|
||||||
|
if (io->size - io->len < size && !mg_iobuf_resize(io, io->len + size)) {
|
||||||
|
mg_error(c, "oom");
|
||||||
|
return 0; // drop it
|
||||||
|
}
|
||||||
|
memcpy(&io->buf[io->len], data, size);
|
||||||
|
io->len += size;
|
||||||
|
#ifdef PRINT_FUNCNAME
|
||||||
|
printf("CALLING mg_tls_recv_cert\n");
|
||||||
|
#endif
|
||||||
|
mg_tls_recv_cert(c, !c->is_client); // call server for client and client for server
|
||||||
|
mg_iobuf_free(io);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env -S gawk -f
|
||||||
|
# gawk used to avoid "towc" errors seen on MacOS. env used to circumvent brew installing it wherever they like
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
FS="\t"
|
||||||
|
print "{"
|
||||||
|
}
|
||||||
|
/HEALTH_DASHBOARD/ { print $2 }
|
||||||
|
END {
|
||||||
|
print "}"
|
||||||
|
}
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd /data/downloads/health
|
||||||
|
find . -mtime +28 -not -name 'index*.json' -delete
|
||||||
|
find . -name "*.json" -not -name 'index*.json' | jq -R . | jq -s . > index.json
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
#define MIPPORTTEST_USING_DHCP 1
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include "mip_x_test.c"
|
||||||
|
|
||||||
|
struct port_driver_data {
|
||||||
|
int sockfd;
|
||||||
|
struct sockaddr_in port_addr;
|
||||||
|
struct sockaddr_in tap_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// MIP Socket driver
|
||||||
|
static size_t sock_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
||||||
|
ssize_t received = recv(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
|
||||||
|
usleep(1); // This is to avoid 100% CPU
|
||||||
|
if (received < 0) return 0;
|
||||||
|
return (size_t) received;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t sock_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
||||||
|
ssize_t res = send(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
|
||||||
|
if (res < 0) {
|
||||||
|
MG_ERROR(("sock_tx failed: %d", errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (size_t) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sock_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||||
|
return s1 && ifp->driver_data ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
bool result;
|
||||||
|
const char *debug_level = getenv("V");
|
||||||
|
// Setup interface
|
||||||
|
const uint16_t port = 0xAA55; // UDP port
|
||||||
|
const uint16_t tap_port = 0x55AA; // UDP port for TAP socket
|
||||||
|
const char *mac = "02:00:01:02:03:78"; // MAC address
|
||||||
|
|
||||||
|
struct port_driver_data pdd;
|
||||||
|
pdd.sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
pdd.port_addr.sin_family = AF_INET;
|
||||||
|
pdd.port_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
pdd.port_addr.sin_port = htons(port);
|
||||||
|
if (bind(pdd.sockfd, (struct sockaddr *) &pdd.port_addr, sizeof(pdd.port_addr)) < 0) return EXIT_FAILURE;
|
||||||
|
printf("Opened UDP socket: 127.0.0.1:%u (0x%04x)\n", port, port);
|
||||||
|
|
||||||
|
pdd.tap_addr.sin_family = AF_INET;
|
||||||
|
pdd.tap_addr.sin_addr.s_addr = htonl(0x7f000001U); // 127.0.0.1
|
||||||
|
pdd.tap_addr.sin_port = htons(0x55AA);
|
||||||
|
if (connect(pdd.sockfd, (struct sockaddr *) &pdd.tap_addr, sizeof(pdd.tap_addr)) < 0) return EXIT_FAILURE;
|
||||||
|
printf("Connected to TAP UDP socket: 127.0.0.1:%u (0x%04x)\n", tap_port, tap_port);
|
||||||
|
|
||||||
|
usleep(200000); // 200 ms
|
||||||
|
|
||||||
|
if (debug_level == NULL) debug_level = "3";
|
||||||
|
mg_log_set(atoi(debug_level));
|
||||||
|
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
|
||||||
|
// MIP driver
|
||||||
|
struct mg_tcpip_driver driver;
|
||||||
|
memset(&driver, 0, sizeof(driver));
|
||||||
|
|
||||||
|
driver.tx = sock_tx;
|
||||||
|
driver.poll = sock_poll;
|
||||||
|
driver.rx = sock_rx;
|
||||||
|
|
||||||
|
struct mg_tcpip_if mif;
|
||||||
|
memset(&mif, 0, sizeof(mif));
|
||||||
|
|
||||||
|
mif.driver = &driver;
|
||||||
|
mif.driver_data = &pdd;
|
||||||
|
|
||||||
|
#if MIPPORTTEST_USING_DHCP == 1
|
||||||
|
#else
|
||||||
|
mif.ip = mg_htonl(MG_U32(192, 168, 32, 2)); // Triggering a network failure
|
||||||
|
mif.mask = mg_htonl(MG_U32(255, 255, 255, 0));
|
||||||
|
mif.gw = mg_htonl(MG_U32(192, 168, 32, 1));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1],
|
||||||
|
&mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]);
|
||||||
|
|
||||||
|
mg_tcpip_init(&mgr, &mif);
|
||||||
|
MG_INFO(("Init done, starting main loop"));
|
||||||
|
usleep(200000); // 200 ms
|
||||||
|
|
||||||
|
// Stack initialization, Network configuration (DHCP lease, ...)
|
||||||
|
#if MIPPORTTEST_USING_DHCP == 0
|
||||||
|
MG_INFO(("MIF configuration: Static IP"));
|
||||||
|
ASSERT(mif.ip != 0); // Check we have a satic IP assigned
|
||||||
|
mg_mgr_poll(&mgr, 100); // For initialisation
|
||||||
|
#else
|
||||||
|
MG_INFO(("MIF configuration: DHCP"));
|
||||||
|
ASSERT(!mif.ip); // Check we are set for DHCP
|
||||||
|
int pc = 500; // Timeout on DHCP lease 500 ~ approx 5s (typical delay <1s)
|
||||||
|
while (((pc--) > 0) && !mif.ip) {
|
||||||
|
mg_mgr_poll(&mgr, 100);
|
||||||
|
usleep(10000); // 10 ms
|
||||||
|
}
|
||||||
|
if (!mif.ip) MG_ERROR(("No ip assigned (DHCP lease may have failed).\n"));
|
||||||
|
ASSERT(mif.ip); // We have an IP (lease or static)
|
||||||
|
#endif
|
||||||
|
while (mif.state != MG_TCPIP_STATE_READY) {
|
||||||
|
mg_mgr_poll(&mgr, 100);
|
||||||
|
usleep(10000); // 10 ms
|
||||||
|
}
|
||||||
|
|
||||||
|
// RUN TESTS
|
||||||
|
result = mip_x_test(&mgr);
|
||||||
|
close(pdd.sockfd);
|
||||||
|
if (!result) return EXIT_FAILURE;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
+5
-425
@@ -1,10 +1,5 @@
|
|||||||
#define MG_ENABLE_TCPIP 1
|
|
||||||
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
|
|
||||||
|
|
||||||
#define MIPTAPTEST_USING_DHCP 1
|
#define MIPTAPTEST_USING_DHCP 1
|
||||||
|
|
||||||
#define FETCH_BUF_SIZE (16 * 1024)
|
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#ifndef __OpenBSD__
|
#ifndef __OpenBSD__
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
@@ -16,105 +11,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
#include "mongoose.c"
|
#include "mip_x_test.c"
|
||||||
|
|
||||||
#include "driver_mock.c"
|
|
||||||
|
|
||||||
#ifdef MQTT_LOCALHOST
|
|
||||||
#define MQTT_URL "mqtt://127.0.0.1:1883"
|
|
||||||
#else
|
|
||||||
#define MQTT_URL "mqtt://broker.hivemq.com:1883"
|
|
||||||
#endif
|
|
||||||
#if MG_TLS == MG_TLS_BUILTIN
|
|
||||||
#define MQTTS_URL "mqtts://mongoose.ws:8883" // test requires TLS 1.3
|
|
||||||
#define MQTTS_CA mg_str(s_ca_cert)
|
|
||||||
static const char *s_ca_cert =
|
|
||||||
"-----BEGIN CERTIFICATE-----\n"
|
|
||||||
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
|
|
||||||
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n"
|
|
||||||
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n"
|
|
||||||
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n"
|
|
||||||
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n"
|
|
||||||
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n"
|
|
||||||
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n"
|
|
||||||
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n"
|
|
||||||
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n"
|
|
||||||
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n"
|
|
||||||
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n"
|
|
||||||
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n"
|
|
||||||
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n"
|
|
||||||
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n"
|
|
||||||
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n"
|
|
||||||
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n"
|
|
||||||
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
|
|
||||||
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n"
|
|
||||||
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n"
|
|
||||||
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n"
|
|
||||||
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n"
|
|
||||||
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n"
|
|
||||||
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n"
|
|
||||||
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n"
|
|
||||||
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n"
|
|
||||||
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n"
|
|
||||||
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n"
|
|
||||||
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n"
|
|
||||||
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n"
|
|
||||||
"-----END CERTIFICATE-----\n";
|
|
||||||
#elif MG_TLS
|
|
||||||
#ifdef MQTT_LOCALHOST
|
|
||||||
// we'll generate MQTTS_URL
|
|
||||||
#define MQTTS_CA mg_str(s_ca_cert)
|
|
||||||
static const char *s_ca_cert =
|
|
||||||
"-----BEGIN CERTIFICATE-----\n"
|
|
||||||
"MIIBFTCBvAIJAMNTFtpfcq8NMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv\n"
|
|
||||||
"b3NlMB4XDTI0MDUwNzE0MzczNloXDTM0MDUwNTE0MzczNlowEzERMA8GA1UEAwwI\n"
|
|
||||||
"TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuP+86T/rOWnGpEVhl\n"
|
|
||||||
"fxYZ+pjMbCmDZ+vdnP0rjoxudwRMRQCv5slRlDK7Lxue761sdvqxWr0Ma6TFGTNg\n"
|
|
||||||
"epsRMAoGCCqGSM49BAMCA0gAMEUCIQCwb2CxuAKm51s81S6BIoy1IcandXSohnqs\n"
|
|
||||||
"us64BAA7QgIgGGtUrpkgFSS0oPBlCUG6YPHFVw42vTfpTC0ySwAS0M4=\n"
|
|
||||||
"-----END CERTIFICATE-----\n";
|
|
||||||
#else
|
|
||||||
#define MQTTS_URL "mqtts://broker.hivemq.com:8883"
|
|
||||||
#define MQTTS_CA mg_unpacked("/data/ca.pem")
|
|
||||||
#endif // MQTT_LOCALHOST
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static char *host_ip;
|
|
||||||
|
|
||||||
static int s_num_tests = 0;
|
|
||||||
|
|
||||||
#ifdef NO_SLEEP_ABORT
|
|
||||||
#define ABORT() abort()
|
|
||||||
#else
|
|
||||||
#define ABORT() \
|
|
||||||
sleep(2); /* 2s, GH print reason */ \
|
|
||||||
abort();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ASSERT(expr) \
|
|
||||||
do { \
|
|
||||||
s_num_tests++; \
|
|
||||||
if (!(expr)) { \
|
|
||||||
printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \
|
|
||||||
fflush(stdout); \
|
|
||||||
ABORT(); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static struct mg_http_message gethm(const char *buf) {
|
|
||||||
struct mg_http_message hm;
|
|
||||||
memset(&hm, 0, sizeof(hm));
|
|
||||||
mg_http_parse(buf, strlen(buf), &hm);
|
|
||||||
return hm;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmpbody(const char *buf, const char *str) {
|
|
||||||
struct mg_str s = mg_str(str);
|
|
||||||
struct mg_http_message hm = gethm(buf);
|
|
||||||
size_t len = strlen(buf);
|
|
||||||
if (hm.body.len > len) hm.body.len = len - (size_t) (hm.body.buf - buf);
|
|
||||||
return mg_strcmp(hm.body, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MIP TUNTAP driver
|
// MIP TUNTAP driver
|
||||||
static size_t tap_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
static size_t tap_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
||||||
@@ -137,311 +35,9 @@ static bool tap_poll(struct mg_tcpip_if *ifp, bool s1) {
|
|||||||
return s1 && ifp->driver_data ? true : false;
|
return s1 && ifp->driver_data ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eh1(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
struct mg_tls_opts *topts = (struct mg_tls_opts *) c->fn_data;
|
|
||||||
if (ev == MG_EV_ACCEPT && topts != NULL) mg_tls_init(c, topts);
|
|
||||||
if (ev == MG_EV_HTTP_MSG) {
|
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
|
||||||
MG_DEBUG(("[%.*s %.*s] message len %d", (int) hm->method.len,
|
|
||||||
hm->method.buf, (int) hm->uri.len, hm->uri.buf,
|
|
||||||
(int) hm->message.len));
|
|
||||||
if (mg_match(hm->uri, mg_str("/foo/*"), NULL)) {
|
|
||||||
mg_http_reply(c, 200, "", "uri: %.*s", hm->uri.len - 5, hm->uri.buf + 5);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/ws"), NULL)) {
|
|
||||||
mg_ws_upgrade(c, hm, NULL);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/body"), NULL)) {
|
|
||||||
mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.buf);
|
|
||||||
} else {
|
|
||||||
struct mg_http_serve_opts sopts;
|
|
||||||
memset(&sopts, 0, sizeof(sopts));
|
|
||||||
sopts.root_dir = "./data";
|
|
||||||
mg_http_serve_dir(c, hm, &sopts);
|
|
||||||
}
|
|
||||||
} else if (ev == MG_EV_WS_OPEN) {
|
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
|
||||||
ASSERT(mg_strcmp(hm->uri, mg_str("/ws")) == 0);
|
|
||||||
mg_ws_send(c, "opened", 6, WEBSOCKET_OP_BINARY);
|
|
||||||
} else if (ev == MG_EV_WS_MSG) {
|
|
||||||
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
|
||||||
mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_BINARY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
struct fetch_data {
|
|
||||||
char *buf;
|
|
||||||
const char *url;
|
|
||||||
int code, closed;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void fcb(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
struct fetch_data *fd = (struct fetch_data *) c->fn_data;
|
|
||||||
if (ev == MG_EV_CONNECT) {
|
|
||||||
MG_DEBUG(("CONNECT"));
|
|
||||||
if (mg_url_is_ssl(fd->url)) {
|
|
||||||
struct mg_tls_opts opts;
|
|
||||||
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
|
|
||||||
if (host_ip != NULL && strstr(fd->url, host_ip) != NULL) {
|
|
||||||
MG_DEBUG(("Local connection, using self-signed certificates"));
|
|
||||||
opts.name = mg_str_s("localhost");
|
|
||||||
opts.ca = mg_unpacked("/certs/ca.crt");
|
|
||||||
} else {
|
|
||||||
opts.name = mg_url_host(fd->url);
|
|
||||||
opts.ca = mg_unpacked("/data/ca.pem");
|
|
||||||
#if MG_TLS == MG_TLS_BUILTIN
|
|
||||||
// our TLS does not search for the proper CA in a bundle
|
|
||||||
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
mg_tls_init(c, &opts);
|
|
||||||
#if MG_TLS == MG_TLS_BUILTIN
|
|
||||||
mg_free((void *) opts.ca.buf);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else if (ev == MG_EV_HTTP_MSG) {
|
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
|
||||||
snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len,
|
|
||||||
hm->message.buf);
|
|
||||||
fd->code = atoi(hm->uri.buf);
|
|
||||||
fd->closed = 1;
|
|
||||||
c->is_closing = 1;
|
|
||||||
MG_DEBUG(("CODE: %d, MSG: %.*s", fd->code, (int) hm->message.len,
|
|
||||||
hm->message.buf));
|
|
||||||
(void) c;
|
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
|
||||||
MG_DEBUG(("CLOSE"));
|
|
||||||
fd->closed = 1;
|
|
||||||
} else if (ev == MG_EV_READ) {
|
|
||||||
long bytes = *(long *) ev_data;
|
|
||||||
MG_DEBUG(("READ %d: %.*s", (int) bytes, (int) bytes, c->recv.buf));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
|
|
||||||
const char *fmt, ...) {
|
|
||||||
struct fetch_data fd = {buf, url, 0, 0};
|
|
||||||
int i;
|
|
||||||
struct mg_connection *c = NULL;
|
|
||||||
va_list ap;
|
|
||||||
mg_mgr_poll(mgr, 0); // update ifp->now to avoid ARP lookup using an old
|
|
||||||
// timestamp (from an ancient call in other test)
|
|
||||||
c = mg_http_connect(mgr, url, fcb, &fd);
|
|
||||||
ASSERT(c != NULL);
|
|
||||||
va_start(ap, fmt);
|
|
||||||
mg_vprintf(c, fmt, &ap);
|
|
||||||
va_end(ap);
|
|
||||||
buf[0] = '\0';
|
|
||||||
// - TLS: multiple (small) records: allow enough loops so mg_mgr_poll can
|
|
||||||
// process buffered records when no more frames are coming in
|
|
||||||
for (i = 0; i < 500 && buf[0] == '\0' && !fd.closed; i++) {
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
usleep(5000); // 5 ms. Slow down poll loop to ensure packet transit, but
|
|
||||||
// allow enough loops to get the ARP response, otherwise,
|
|
||||||
// given enough traffic, the timer expires before we get a
|
|
||||||
// chance to see the response
|
|
||||||
}
|
|
||||||
if (!fd.closed) c->is_closing = 1;
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
return fd.code;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_http_client(struct mg_mgr *mgr) {
|
|
||||||
char buf[FETCH_BUF_SIZE];
|
|
||||||
int rc = 0;
|
|
||||||
const bool ipv6 = 0;
|
|
||||||
#if MG_TLS
|
|
||||||
if (ipv6) {
|
|
||||||
rc = fetch(mgr, buf, "https://ipv6.google.com",
|
|
||||||
"GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n");
|
|
||||||
} else {
|
|
||||||
rc = fetch(mgr, buf, "https://cesanta.com",
|
|
||||||
"GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n");
|
|
||||||
}
|
|
||||||
ASSERT(rc == 200); // OK
|
|
||||||
#else
|
|
||||||
if (ipv6) {
|
|
||||||
rc = fetch(mgr, buf, "http://ipv6.google.com",
|
|
||||||
"GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n");
|
|
||||||
} else {
|
|
||||||
rc = fetch(mgr, buf, "http://cesanta.com",
|
|
||||||
"GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n");
|
|
||||||
}
|
|
||||||
ASSERT(rc == 301); // OK: Permanently moved (HTTP->HTTPS redirect)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mg_connection *s_conn;
|
|
||||||
static char s_topic[16];
|
|
||||||
|
|
||||||
struct mqtt_data {
|
|
||||||
char *url;
|
|
||||||
bool passed;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
struct mqtt_data *data = (struct mqtt_data *) c->fn_data;
|
|
||||||
if (ev == MG_EV_CONNECT) {
|
|
||||||
MG_DEBUG(("CONNECT"));
|
|
||||||
#if MG_TLS
|
|
||||||
struct mg_tls_opts opts;
|
|
||||||
memset(&opts, 0, sizeof(opts));
|
|
||||||
opts.ca = MQTTS_CA;
|
|
||||||
opts.name = mg_url_host(data->url);
|
|
||||||
mg_tls_init(c, &opts);
|
|
||||||
#endif
|
|
||||||
} else if (ev == MG_EV_MQTT_OPEN) {
|
|
||||||
MG_DEBUG(("MQTT CONNECT"));
|
|
||||||
struct mg_mqtt_opts sub_opts;
|
|
||||||
memset(&sub_opts, 0, sizeof(sub_opts));
|
|
||||||
sub_opts.topic = mg_str(mg_random_str(s_topic, sizeof(s_topic)));
|
|
||||||
sub_opts.qos = 1;
|
|
||||||
mg_mqtt_sub(c, &sub_opts);
|
|
||||||
struct mg_mqtt_opts pub_opts;
|
|
||||||
memset(&pub_opts, 0, sizeof(pub_opts));
|
|
||||||
pub_opts.topic = sub_opts.topic;
|
|
||||||
pub_opts.message = mg_str("hi");
|
|
||||||
pub_opts.qos = 1, pub_opts.retain = false;
|
|
||||||
mg_mqtt_pub(c, &pub_opts);
|
|
||||||
} else if (ev == MG_EV_MQTT_MSG) {
|
|
||||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
|
||||||
MG_DEBUG(("TOPIC: %.*s, MSG: %.*s", (int) mm->topic.len, mm->topic.buf,
|
|
||||||
mm->data.len > 10 ? 10 : (int) mm->data.len, mm->data.buf));
|
|
||||||
ASSERT(mm->topic.len == strlen(s_topic) &&
|
|
||||||
strncmp(mm->topic.buf, s_topic, mm->topic.len) == 0);
|
|
||||||
if (mm->data.len == 2 && strncmp(mm->data.buf, "hi", 2) == 0) {
|
|
||||||
struct mg_mqtt_opts pub_opts;
|
|
||||||
memset(&pub_opts, 0, sizeof(pub_opts));
|
|
||||||
pub_opts.topic = mm->topic;
|
|
||||||
// send more than 1 record, content is not relevant
|
|
||||||
pub_opts.message = mg_str_n((char *)(size_t) mqtt_fn, 21098);
|
|
||||||
pub_opts.qos = 1, pub_opts.retain = false;
|
|
||||||
mg_mqtt_pub(c, &pub_opts);
|
|
||||||
} else if (mm->data.len == 8 && strncmp(mm->data.buf, "farewell", 8) == 0) {
|
|
||||||
// close on farewell
|
|
||||||
MG_INFO(("%lu CLOSING", c->id));
|
|
||||||
mg_mqtt_disconnect(c, NULL);
|
|
||||||
data->passed = true;
|
|
||||||
} else if (mm->data.len == 21098) {
|
|
||||||
struct mg_mqtt_opts pub_opts;
|
|
||||||
ASSERT(memcmp((const char *) (size_t) mqtt_fn, mm->data.buf, 21098) == 0);
|
|
||||||
// send farewell after receiving big data
|
|
||||||
memset(&pub_opts, 0, sizeof(pub_opts));
|
|
||||||
pub_opts.topic = mm->topic;
|
|
||||||
pub_opts.message = mg_str("farewell");
|
|
||||||
pub_opts.qos = 1, pub_opts.retain = false;
|
|
||||||
mg_mqtt_pub(c, &pub_opts);
|
|
||||||
}
|
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
|
||||||
MG_DEBUG(("CLOSE"));
|
|
||||||
s_conn = NULL;
|
|
||||||
} else if (ev == MG_EV_ERROR) {
|
|
||||||
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
|
|
||||||
struct mqtt_data data;
|
|
||||||
struct mg_mqtt_opts opts;
|
|
||||||
memset(&opts, 0, sizeof(opts));
|
|
||||||
opts.clean = true, opts.version = 4;
|
|
||||||
data.passed = false;
|
|
||||||
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
|
||||||
if (host_ip == NULL) {
|
|
||||||
printf("\nMQTT_LOCALHOST defined but no HOST_IP provided, skipping MQTTS tests\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
printf("HOST_IP: %s\n", host_ip);
|
|
||||||
#endif
|
|
||||||
#if MG_TLS
|
|
||||||
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
|
||||||
data.url = mg_mprintf("mqtts://%s:8883", host_ip);
|
|
||||||
#else
|
|
||||||
data.url = strdup(MQTTS_URL);
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#ifdef MQTT_LOCALHOST
|
|
||||||
data.url = mg_mprintf("mqtt://%s:1883", host_ip);
|
|
||||||
#else
|
|
||||||
data.url = strdup(MQTT_URL);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
s_conn = mg_mqtt_connect(mgr, data.url, &opts, mqtt_fn, &data);
|
|
||||||
ASSERT(s_conn != NULL);
|
|
||||||
for (int i = 0; i < 1000 && s_conn != NULL && !s_conn->is_closing; i++) {
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
usleep(10000); // 10 ms. Slow down poll loop to ensure packets transit
|
|
||||||
}
|
|
||||||
ASSERT(data.passed);
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
free(data.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
static void *poll_thread(void *p) {
|
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) p;
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 300; i++) {
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
usleep(10000); // 10 ms. Slow down poll loop to ensure packet transit
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_http_server(struct mg_mgr *mgr) {
|
|
||||||
struct mg_connection *c;
|
|
||||||
char *cmd;
|
|
||||||
pthread_t thread_id = (pthread_t) 0;
|
|
||||||
#if MG_TLS
|
|
||||||
struct mg_tls_opts opts;
|
|
||||||
memset(&opts, 0, sizeof(opts));
|
|
||||||
// opts.ca = mg_str(s_tls_ca);
|
|
||||||
opts.cert = mg_unpacked("/certs/server.crt");
|
|
||||||
opts.key = mg_unpacked("/certs/server.key");
|
|
||||||
c = mg_http_listen(mgr, "https://0.0.0.0:12347", eh1, &opts);
|
|
||||||
cmd = mg_mprintf("./mip_curl.sh --insecure https://%M:12347", mg_print_ip4,
|
|
||||||
&mgr->ifp->ip);
|
|
||||||
#else
|
|
||||||
c = mg_http_listen(mgr, "http://0.0.0.0:12347", eh1, NULL);
|
|
||||||
cmd =
|
|
||||||
mg_mprintf("./mip_curl.sh http://%M:12347", mg_print_ip4, &mgr->ifp->ip);
|
|
||||||
#endif
|
|
||||||
ASSERT(c != NULL);
|
|
||||||
pthread_create(&thread_id, NULL, poll_thread,
|
|
||||||
mgr); // simpler this way, no concurrency anyway
|
|
||||||
MG_DEBUG(("CURL"));
|
|
||||||
ASSERT(system(cmd) == 0); // wait for curl
|
|
||||||
MG_DEBUG(("MONGOOSE"));
|
|
||||||
pthread_join(thread_id, NULL); // wait for Mongoose
|
|
||||||
MG_DEBUG(("DONE"));
|
|
||||||
free(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_tls(struct mg_mgr *mgr) {
|
|
||||||
#if MG_TLS
|
|
||||||
char *url;
|
|
||||||
char buf[FETCH_BUF_SIZE]; // make sure it can hold Makefile
|
|
||||||
struct mg_str data = mg_unpacked("/Makefile");
|
|
||||||
if (host_ip == NULL) {
|
|
||||||
printf("\nNo HOST_IP provided, skipping TLS tests\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
printf("HOST_IP: %s\n", host_ip);
|
|
||||||
// - POST a large file, make sure we drain TLS buffers and read all: done at
|
|
||||||
// server test, using curl as POSTing client
|
|
||||||
// - Fire patched server, test multiple TLS records per TCP segment handling
|
|
||||||
url = mg_mprintf("https://%s:8443", host_ip); // for historic reasons
|
|
||||||
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
|
|
||||||
sleep(1);
|
|
||||||
ASSERT(fetch(mgr, buf, url, "GET /thefile HTTP/1.0\n\n") == 200);
|
|
||||||
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
|
|
||||||
ASSERT(system("killall tls_multirec/server") == 0);
|
|
||||||
free(url);
|
|
||||||
#else
|
|
||||||
(void) cmpbody("", "");
|
|
||||||
(void) mgr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
bool result;
|
||||||
const char *debug_level = getenv("V");
|
const char *debug_level = getenv("V");
|
||||||
// Setup interface
|
// Setup interface
|
||||||
const char *iface = "tap0"; // Network iface
|
const char *iface = "tap0"; // Network iface
|
||||||
@@ -476,9 +72,6 @@ int main(void) {
|
|||||||
if (debug_level == NULL) debug_level = "3";
|
if (debug_level == NULL) debug_level = "3";
|
||||||
mg_log_set(atoi(debug_level));
|
mg_log_set(atoi(debug_level));
|
||||||
|
|
||||||
host_ip = getenv("HOST_IP");
|
|
||||||
|
|
||||||
// Events
|
|
||||||
struct mg_mgr mgr; // Event manager
|
struct mg_mgr mgr; // Event manager
|
||||||
mg_mgr_init(&mgr); // Initialise event manager
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
|
||||||
@@ -532,21 +125,8 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RUN TESTS
|
// RUN TESTS
|
||||||
usleep(500000); // 500 ms
|
result = mip_x_test(&mgr);
|
||||||
test_http_client(&mgr);
|
|
||||||
usleep(500000); // 500 ms
|
|
||||||
test_http_server(&mgr);
|
|
||||||
usleep(500000); // 500 ms
|
|
||||||
test_tls(&mgr);
|
|
||||||
usleep(500000); // 500 ms
|
|
||||||
test_mqtt_connsubpub(&mgr);
|
|
||||||
usleep(500000); // 500 ms
|
|
||||||
|
|
||||||
printf("SUCCESS. Total tests: %d\n", s_num_tests);
|
|
||||||
|
|
||||||
// Clear
|
|
||||||
mg_mgr_free(&mgr);
|
|
||||||
ASSERT(mgr.conns == NULL); // Deconstruction OK
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
if (!result) return EXIT_FAILURE;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
+1074
-95
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,468 @@
|
|||||||
|
#define MG_ENABLE_TCPIP 1
|
||||||
|
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
|
||||||
|
|
||||||
|
#define FETCH_BUF_SIZE (16 * 1024)
|
||||||
|
|
||||||
|
#include "mongoose.c"
|
||||||
|
|
||||||
|
bool mip_x_test(struct mg_mgr *);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MQTT_LOCALHOST
|
||||||
|
#define MQTT_URL "mqtt://127.0.0.1:1883"
|
||||||
|
#else
|
||||||
|
#define MQTT_URL "mqtt://broker.hivemq.com:1883"
|
||||||
|
#endif
|
||||||
|
#if MG_TLS == MG_TLS_BUILTIN
|
||||||
|
#define MQTTS_URL "mqtts://mongoose.ws:8883" // test requires TLS 1.3
|
||||||
|
#define MQTTS_CA mg_str(s_ca_cert)
|
||||||
|
static const char *s_ca_cert =
|
||||||
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
|
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
|
||||||
|
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n"
|
||||||
|
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n"
|
||||||
|
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n"
|
||||||
|
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n"
|
||||||
|
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n"
|
||||||
|
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n"
|
||||||
|
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n"
|
||||||
|
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n"
|
||||||
|
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n"
|
||||||
|
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n"
|
||||||
|
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n"
|
||||||
|
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n"
|
||||||
|
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n"
|
||||||
|
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n"
|
||||||
|
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n"
|
||||||
|
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
|
||||||
|
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n"
|
||||||
|
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n"
|
||||||
|
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n"
|
||||||
|
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n"
|
||||||
|
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n"
|
||||||
|
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n"
|
||||||
|
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n"
|
||||||
|
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n"
|
||||||
|
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n"
|
||||||
|
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n"
|
||||||
|
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n"
|
||||||
|
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n"
|
||||||
|
"-----END CERTIFICATE-----\n";
|
||||||
|
#elif MG_TLS
|
||||||
|
#ifdef MQTT_LOCALHOST
|
||||||
|
// we'll generate MQTTS_URL
|
||||||
|
#define MQTTS_CA mg_str(s_ca_cert)
|
||||||
|
static const char *s_ca_cert =
|
||||||
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
|
"MIIBFTCBvAIJAMNTFtpfcq8NMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv\n"
|
||||||
|
"b3NlMB4XDTI0MDUwNzE0MzczNloXDTM0MDUwNTE0MzczNlowEzERMA8GA1UEAwwI\n"
|
||||||
|
"TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuP+86T/rOWnGpEVhl\n"
|
||||||
|
"fxYZ+pjMbCmDZ+vdnP0rjoxudwRMRQCv5slRlDK7Lxue761sdvqxWr0Ma6TFGTNg\n"
|
||||||
|
"epsRMAoGCCqGSM49BAMCA0gAMEUCIQCwb2CxuAKm51s81S6BIoy1IcandXSohnqs\n"
|
||||||
|
"us64BAA7QgIgGGtUrpkgFSS0oPBlCUG6YPHFVw42vTfpTC0ySwAS0M4=\n"
|
||||||
|
"-----END CERTIFICATE-----\n";
|
||||||
|
#else
|
||||||
|
#define MQTTS_URL "mqtts://broker.hivemq.com:8883"
|
||||||
|
#define MQTTS_CA mg_unpacked("/data/ca.pem")
|
||||||
|
#endif // MQTT_LOCALHOST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char *host_ip;
|
||||||
|
|
||||||
|
static int s_num_tests = 0;
|
||||||
|
static bool s_error = false;
|
||||||
|
|
||||||
|
#ifdef NO_ABORT
|
||||||
|
static int s_abort = 0;
|
||||||
|
#define ABORT() ++s_abort, s_error = true
|
||||||
|
#else
|
||||||
|
#ifdef NO_SLEEP_ABORT
|
||||||
|
#define ABORT() abort()
|
||||||
|
#else
|
||||||
|
#define ABORT() \
|
||||||
|
sleep(2); /* 2s, GH print reason */ \
|
||||||
|
abort();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ASSERT(expr) \
|
||||||
|
do { \
|
||||||
|
s_num_tests++; \
|
||||||
|
if (!(expr)) { \
|
||||||
|
printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \
|
||||||
|
fflush(stdout); \
|
||||||
|
ABORT(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
static struct mg_http_message gethm(const char *buf) {
|
||||||
|
struct mg_http_message hm;
|
||||||
|
memset(&hm, 0, sizeof(hm));
|
||||||
|
mg_http_parse(buf, strlen(buf), &hm);
|
||||||
|
return hm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmpbody(const char *buf, const char *str) {
|
||||||
|
struct mg_str s = mg_str(str);
|
||||||
|
struct mg_http_message hm = gethm(buf);
|
||||||
|
size_t len = strlen(buf);
|
||||||
|
if (hm.body.len > len) hm.body.len = len - (size_t) (hm.body.buf - buf);
|
||||||
|
return mg_strcmp(hm.body, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NO_HTTPSERVER_TEST
|
||||||
|
static void eh1(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
|
struct mg_tls_opts *topts = (struct mg_tls_opts *) c->fn_data;
|
||||||
|
if (ev == MG_EV_ACCEPT && topts != NULL) mg_tls_init(c, topts);
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
MG_DEBUG(("[%.*s %.*s] message len %d", (int) hm->method.len,
|
||||||
|
hm->method.buf, (int) hm->uri.len, hm->uri.buf,
|
||||||
|
(int) hm->message.len));
|
||||||
|
if (mg_match(hm->uri, mg_str("/foo/*"), NULL)) {
|
||||||
|
mg_http_reply(c, 200, "", "uri: %.*s", hm->uri.len - 5, hm->uri.buf + 5);
|
||||||
|
} else if (mg_match(hm->uri, mg_str("/ws"), NULL)) {
|
||||||
|
mg_ws_upgrade(c, hm, NULL);
|
||||||
|
} else if (mg_match(hm->uri, mg_str("/body"), NULL)) {
|
||||||
|
mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.buf);
|
||||||
|
} else {
|
||||||
|
struct mg_http_serve_opts sopts;
|
||||||
|
memset(&sopts, 0, sizeof(sopts));
|
||||||
|
sopts.root_dir = "./data";
|
||||||
|
mg_http_serve_dir(c, hm, &sopts);
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_WS_OPEN) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
ASSERT(mg_strcmp(hm->uri, mg_str("/ws")) == 0);
|
||||||
|
mg_ws_send(c, "opened", 6, WEBSOCKET_OP_BINARY);
|
||||||
|
} else if (ev == MG_EV_WS_MSG) {
|
||||||
|
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
||||||
|
mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_BINARY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct fetch_data {
|
||||||
|
char *buf;
|
||||||
|
const char *url;
|
||||||
|
int code, closed;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void fcb(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
|
struct fetch_data *fd = (struct fetch_data *) c->fn_data;
|
||||||
|
if (ev == MG_EV_CONNECT) {
|
||||||
|
MG_DEBUG(("CONNECT"));
|
||||||
|
if (mg_url_is_ssl(fd->url)) {
|
||||||
|
struct mg_tls_opts opts;
|
||||||
|
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
|
||||||
|
if (host_ip != NULL && strstr(fd->url, host_ip) != NULL) {
|
||||||
|
MG_DEBUG(("Local connection, using self-signed certificates"));
|
||||||
|
opts.name = mg_str_s("localhost");
|
||||||
|
opts.ca = mg_unpacked("/certs/ca.crt");
|
||||||
|
} else {
|
||||||
|
opts.name = mg_url_host(fd->url);
|
||||||
|
opts.ca = mg_unpacked("/data/ca.pem");
|
||||||
|
#if MG_TLS == MG_TLS_BUILTIN
|
||||||
|
// our TLS does not search for the proper CA in a bundle
|
||||||
|
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
#if MG_TLS == MG_TLS_BUILTIN
|
||||||
|
mg_free((void *) opts.ca.buf);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len,
|
||||||
|
hm->message.buf);
|
||||||
|
fd->code = atoi(hm->uri.buf);
|
||||||
|
fd->closed = 1;
|
||||||
|
c->is_closing = 1;
|
||||||
|
MG_DEBUG(("CODE: %d, MSG: %.*s", fd->code, (int) hm->message.len,
|
||||||
|
hm->message.buf));
|
||||||
|
(void) c;
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
MG_DEBUG(("CLOSE"));
|
||||||
|
fd->closed = 1;
|
||||||
|
} else if (ev == MG_EV_READ) {
|
||||||
|
long bytes = *(long *) ev_data;
|
||||||
|
MG_DEBUG(("READ %d: %.*s", (int) bytes, (int) bytes, c->recv.buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
|
||||||
|
const char *fmt, ...) {
|
||||||
|
struct fetch_data fd = {buf, url, 0, 0};
|
||||||
|
int i;
|
||||||
|
struct mg_connection *c = NULL;
|
||||||
|
va_list ap;
|
||||||
|
mg_mgr_poll(mgr, 0); // update ifp->now to avoid ARP lookup using an old
|
||||||
|
// timestamp (from an ancient call in other test)
|
||||||
|
c = mg_http_connect(mgr, url, fcb, &fd);
|
||||||
|
ASSERT(c != NULL);
|
||||||
|
va_start(ap, fmt);
|
||||||
|
mg_vprintf(c, fmt, &ap);
|
||||||
|
va_end(ap);
|
||||||
|
buf[0] = '\0';
|
||||||
|
// - TLS: multiple (small) records: allow enough loops so mg_mgr_poll can
|
||||||
|
// process buffered records when no more frames are coming in
|
||||||
|
for (i = 0; i < 500 && buf[0] == '\0' && !fd.closed; i++) {
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
usleep(5000); // 5 ms. Slow down poll loop to ensure packet transit, but
|
||||||
|
// allow enough loops to get the ARP response, otherwise,
|
||||||
|
// given enough traffic, the timer expires before we get a
|
||||||
|
// chance to see the response
|
||||||
|
}
|
||||||
|
if (!fd.closed) c->is_closing = 1;
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
return fd.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_http_client(struct mg_mgr *mgr) {
|
||||||
|
char buf[FETCH_BUF_SIZE];
|
||||||
|
int rc = 0;
|
||||||
|
const bool ipv6 = MG_ENABLE_IPV6;
|
||||||
|
#if MG_TLS
|
||||||
|
if (ipv6) {
|
||||||
|
rc = fetch(mgr, buf, "https://ipv6.google.com",
|
||||||
|
"GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n");
|
||||||
|
} else {
|
||||||
|
rc = fetch(mgr, buf, "https://cesanta.com",
|
||||||
|
"GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n");
|
||||||
|
}
|
||||||
|
ASSERT(rc == 200); // OK
|
||||||
|
#else
|
||||||
|
if (ipv6) {
|
||||||
|
rc = fetch(mgr, buf, "http://ipv6.google.com",
|
||||||
|
"GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n");
|
||||||
|
ASSERT(rc == 200); // OK
|
||||||
|
} else {
|
||||||
|
rc = fetch(mgr, buf, "http://cesanta.com",
|
||||||
|
"GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n");
|
||||||
|
ASSERT(rc == 301); // OK: Permanently moved (HTTP->HTTPS redirect)
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mg_connection *s_conn;
|
||||||
|
static char s_topic[16];
|
||||||
|
|
||||||
|
struct mqtt_data {
|
||||||
|
char *url;
|
||||||
|
bool passed;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
|
struct mqtt_data *data = (struct mqtt_data *) c->fn_data;
|
||||||
|
if (ev == MG_EV_CONNECT) {
|
||||||
|
MG_DEBUG(("CONNECT"));
|
||||||
|
#if MG_TLS
|
||||||
|
struct mg_tls_opts opts;
|
||||||
|
memset(&opts, 0, sizeof(opts));
|
||||||
|
opts.ca = MQTTS_CA;
|
||||||
|
opts.name = mg_url_host(data->url);
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
#endif
|
||||||
|
} else if (ev == MG_EV_MQTT_OPEN) {
|
||||||
|
MG_DEBUG(("MQTT CONNECT"));
|
||||||
|
struct mg_mqtt_opts sub_opts;
|
||||||
|
memset(&sub_opts, 0, sizeof(sub_opts));
|
||||||
|
sub_opts.topic = mg_str(mg_random_str(s_topic, sizeof(s_topic)));
|
||||||
|
sub_opts.qos = 1;
|
||||||
|
mg_mqtt_sub(c, &sub_opts);
|
||||||
|
struct mg_mqtt_opts pub_opts;
|
||||||
|
memset(&pub_opts, 0, sizeof(pub_opts));
|
||||||
|
pub_opts.topic = sub_opts.topic;
|
||||||
|
pub_opts.message = mg_str("hi");
|
||||||
|
pub_opts.qos = 1, pub_opts.retain = false;
|
||||||
|
mg_mqtt_pub(c, &pub_opts);
|
||||||
|
} else if (ev == MG_EV_MQTT_MSG) {
|
||||||
|
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||||
|
MG_DEBUG(("TOPIC: %.*s, MSG: %.*s", (int) mm->topic.len, mm->topic.buf,
|
||||||
|
mm->data.len > 10 ? 10 : (int) mm->data.len, mm->data.buf));
|
||||||
|
ASSERT(mm->topic.len == strlen(s_topic) &&
|
||||||
|
strncmp(mm->topic.buf, s_topic, mm->topic.len) == 0);
|
||||||
|
if (mm->data.len == 2 && strncmp(mm->data.buf, "hi", 2) == 0) {
|
||||||
|
struct mg_mqtt_opts pub_opts;
|
||||||
|
memset(&pub_opts, 0, sizeof(pub_opts));
|
||||||
|
pub_opts.topic = mm->topic;
|
||||||
|
// send more than 1 record, content is not relevant
|
||||||
|
pub_opts.message = mg_str_n((char *)(size_t) mqtt_fn, 21098);
|
||||||
|
pub_opts.qos = 1, pub_opts.retain = false;
|
||||||
|
mg_mqtt_pub(c, &pub_opts);
|
||||||
|
} else if (mm->data.len == 8 && strncmp(mm->data.buf, "farewell", 8) == 0) {
|
||||||
|
// close on farewell
|
||||||
|
MG_INFO(("%lu CLOSING", c->id));
|
||||||
|
mg_mqtt_disconnect(c, NULL);
|
||||||
|
data->passed = true;
|
||||||
|
} else if (mm->data.len == 21098) {
|
||||||
|
struct mg_mqtt_opts pub_opts;
|
||||||
|
ASSERT(memcmp((const char *) (size_t) mqtt_fn, mm->data.buf, 21098) == 0);
|
||||||
|
// send farewell after receiving big data
|
||||||
|
memset(&pub_opts, 0, sizeof(pub_opts));
|
||||||
|
pub_opts.topic = mm->topic;
|
||||||
|
pub_opts.message = mg_str("farewell");
|
||||||
|
pub_opts.qos = 1, pub_opts.retain = false;
|
||||||
|
mg_mqtt_pub(c, &pub_opts);
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
MG_DEBUG(("CLOSE"));
|
||||||
|
s_conn = NULL;
|
||||||
|
} else if (ev == MG_EV_ERROR) {
|
||||||
|
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
|
||||||
|
struct mqtt_data data;
|
||||||
|
struct mg_mqtt_opts opts;
|
||||||
|
memset(&opts, 0, sizeof(opts));
|
||||||
|
opts.clean = true, opts.version = 4;
|
||||||
|
data.passed = false;
|
||||||
|
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
||||||
|
if (host_ip == NULL) {
|
||||||
|
printf("\nMQTT_LOCALHOST defined but no HOST_IP provided, skipping MQTTS tests\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("HOST_IP: %s\n", host_ip);
|
||||||
|
#endif
|
||||||
|
#if MG_TLS
|
||||||
|
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
||||||
|
data.url = mg_mprintf("mqtts://%s:8883", host_ip);
|
||||||
|
#else
|
||||||
|
data.url = strdup(MQTTS_URL);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef MQTT_LOCALHOST
|
||||||
|
data.url = mg_mprintf("mqtt://%s:1883", host_ip);
|
||||||
|
#else
|
||||||
|
data.url = strdup(MQTT_URL);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
s_conn = mg_mqtt_connect(mgr, data.url, &opts, mqtt_fn, &data);
|
||||||
|
ASSERT(s_conn != NULL);
|
||||||
|
for (int i = 0; i < 1000 && s_conn != NULL && !s_conn->is_closing; i++) {
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
usleep(10000); // 10 ms. Slow down poll loop to ensure packets transit
|
||||||
|
}
|
||||||
|
ASSERT(data.passed);
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
free(data.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NO_HTTPSERVER_TEST
|
||||||
|
#include <pthread.h>
|
||||||
|
static void *poll_thread(void *p) {
|
||||||
|
struct mg_mgr *mgr = (struct mg_mgr *) p;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 300; i++) {
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
usleep(10000); // 10 ms. Slow down poll loop to ensure packet transit
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void test_http_server(struct mg_mgr *mgr) {
|
||||||
|
#ifdef NO_HTTPSERVER_TEST
|
||||||
|
(void) mgr;
|
||||||
|
#else
|
||||||
|
struct mg_connection *c;
|
||||||
|
char *cmd;
|
||||||
|
pthread_t thread_id = (pthread_t) 0;
|
||||||
|
#if MG_TLS
|
||||||
|
struct mg_tls_opts opts;
|
||||||
|
memset(&opts, 0, sizeof(opts));
|
||||||
|
// opts.ca = mg_str(s_tls_ca);
|
||||||
|
opts.cert = mg_unpacked("/certs/server.crt");
|
||||||
|
opts.key = mg_unpacked("/certs/server.key");
|
||||||
|
c = mg_http_listen(mgr, "https://0.0.0.0:12347", eh1, &opts);
|
||||||
|
cmd = mg_mprintf("./mip_curl.sh --insecure https://%M:12347", mg_print_ip4,
|
||||||
|
&mgr->ifp->ip);
|
||||||
|
#else
|
||||||
|
c = mg_http_listen(mgr, "http://0.0.0.0:12347", eh1, NULL);
|
||||||
|
cmd =
|
||||||
|
mg_mprintf("./mip_curl.sh http://%M:12347", mg_print_ip4, &mgr->ifp->ip);
|
||||||
|
#endif
|
||||||
|
ASSERT(c != NULL);
|
||||||
|
ASSERT (mg_send(c, "NADA", 0)); // check mg_send allows len=0
|
||||||
|
pthread_create(&thread_id, NULL, poll_thread,
|
||||||
|
mgr); // simpler this way, no concurrency anyway
|
||||||
|
MG_DEBUG(("CURL"));
|
||||||
|
ASSERT(system(cmd) == 0); // wait for curl
|
||||||
|
MG_DEBUG(("MONGOOSE"));
|
||||||
|
pthread_join(thread_id, NULL); // wait for Mongoose
|
||||||
|
MG_DEBUG(("DONE"));
|
||||||
|
free(cmd);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_tls(struct mg_mgr *mgr) {
|
||||||
|
#if MG_TLS
|
||||||
|
char *url;
|
||||||
|
char buf[FETCH_BUF_SIZE]; // make sure it can hold Makefile
|
||||||
|
struct mg_str data = mg_unpacked("/Makefile");
|
||||||
|
if (host_ip == NULL) {
|
||||||
|
printf("\nNo HOST_IP provided, skipping TLS tests\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("HOST_IP: %s\n", host_ip);
|
||||||
|
// - POST a large file, make sure we drain TLS buffers and read all: done at
|
||||||
|
// server test, using curl as POSTing client
|
||||||
|
// - Fire patched server, test multiple TLS records per TCP segment handling
|
||||||
|
url = mg_mprintf("https://%s:8443", host_ip); // for historic reasons
|
||||||
|
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
|
||||||
|
sleep(1);
|
||||||
|
ASSERT(fetch(mgr, buf, url, "GET /thefile HTTP/1.0\n\n") == 200);
|
||||||
|
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
|
||||||
|
ASSERT(system("killall tls_multirec/server") == 0);
|
||||||
|
free(url);
|
||||||
|
#else
|
||||||
|
(void) cmpbody("", "");
|
||||||
|
(void) mgr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mip_x_test(struct mg_mgr *mgr) {
|
||||||
|
|
||||||
|
host_ip = getenv("HOST_IP");
|
||||||
|
|
||||||
|
#define DASHBOARD(x) printf("HEALTH_DASHBOARD\t\"%s\": %s,\n", x, s_error ? "false":"true");
|
||||||
|
|
||||||
|
usleep(500000); // 500 ms
|
||||||
|
s_error = false;
|
||||||
|
test_http_client(mgr);
|
||||||
|
DASHBOARD("http_client");
|
||||||
|
|
||||||
|
usleep(500000); // 500 ms
|
||||||
|
s_error = false;
|
||||||
|
test_http_server(mgr);
|
||||||
|
DASHBOARD("http_server");
|
||||||
|
|
||||||
|
usleep(500000); // 500 ms
|
||||||
|
s_error = false;
|
||||||
|
test_tls(mgr);
|
||||||
|
DASHBOARD("tls");
|
||||||
|
|
||||||
|
usleep(500000); // 500 ms
|
||||||
|
s_error = false;
|
||||||
|
test_mqtt_connsubpub(mgr);
|
||||||
|
DASHBOARD("mqtt");
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
s_error = false;
|
||||||
|
mg_mgr_free(mgr);
|
||||||
|
ASSERT(mgr->conns == NULL); // Deconstruction OK
|
||||||
|
printf("HEALTH_DASHBOARD\t\"cleanup\": %s\n", s_error ? "false":"true");
|
||||||
|
// last entry with no comma
|
||||||
|
|
||||||
|
#ifdef NO_ABORT
|
||||||
|
if (s_abort != 0) return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
printf("SUCCESS. Total tests: %d\n", s_num_tests);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
#ifndef __OpenBSD__
|
||||||
|
#include <linux/if.h>
|
||||||
|
#include <linux/if_tun.h>
|
||||||
|
#else
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_tun.h>
|
||||||
|
#include <net/if_types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int s_signo;
|
||||||
|
void signal_handler(int signo) {
|
||||||
|
s_signo = signo;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// Setup interface
|
||||||
|
const char *iface = "tap0"; // Network iface
|
||||||
|
const uint16_t port = 0x55AA; // UDP port
|
||||||
|
#ifndef __OpenBSD__
|
||||||
|
const char *tuntap_device = "/dev/net/tun";
|
||||||
|
#else
|
||||||
|
const char *tuntap_device = "/dev/tap0";
|
||||||
|
#endif
|
||||||
|
int fd = open(tuntap_device, O_RDWR);
|
||||||
|
struct ifreq ifr;
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||||
|
#ifndef __OpenBSD__
|
||||||
|
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||||
|
if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
|
||||||
|
#else
|
||||||
|
ifr.ifr_flags = (short) (IFF_UP | IFF_BROADCAST | IFF_MULTICAST);
|
||||||
|
if (ioctl(fd, TUNSIFMODE, (void *) &ifr) < 0) {
|
||||||
|
#endif
|
||||||
|
printf("Failed to setup TAP interface: %s", ifr.ifr_name);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
printf("Opened TAP interface: %s\n", iface);
|
||||||
|
|
||||||
|
int sockfd;
|
||||||
|
struct sockaddr_in tap_addr, port_addr;
|
||||||
|
|
||||||
|
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
tap_addr.sin_family = AF_INET;
|
||||||
|
tap_addr.sin_addr.s_addr = htonl(0x7f000001U); // 127.0.0.1
|
||||||
|
tap_addr.sin_port = htons(port);
|
||||||
|
if (bind(sockfd, (struct sockaddr *) &tap_addr, sizeof(tap_addr)) < 0) return EXIT_FAILURE;
|
||||||
|
printf("Opened UDP socket: 127.0.0.1:%u (0x%04x)\n", port, port);
|
||||||
|
|
||||||
|
memset(&port_addr, 0, sizeof(port_addr));
|
||||||
|
|
||||||
|
while (s_signo == 0) {
|
||||||
|
struct pollfd pfd[2];
|
||||||
|
int result;
|
||||||
|
do {
|
||||||
|
pfd[0].fd = fd;
|
||||||
|
pfd[0].events = POLLIN | POLLPRI; // will wait for input available (read ready), use POLLOUT for write
|
||||||
|
pfd[1].fd = sockfd;
|
||||||
|
pfd[1].events = POLLIN | POLLPRI; // will wait for input available (read ready), use POLLOUT for write
|
||||||
|
|
||||||
|
// only read ready shown here, for write ready use the 3rd arg, and the 4th for exceptions
|
||||||
|
result = poll(pfd, 2, 1000); // 2 pfd, TIMEOUT in milliseconds
|
||||||
|
switch(result) {
|
||||||
|
case -1: // error
|
||||||
|
break;
|
||||||
|
case 0: // timeout (if a timeout struct was passed to select)
|
||||||
|
break;
|
||||||
|
default: // the number of fd/sockets with data available (see pfd.revents for each one);
|
||||||
|
uint8_t buf[1540];
|
||||||
|
if (pfd[0].revents & (POLLIN | POLLPRI)) {
|
||||||
|
ssize_t nread = read(fd, buf, 1540);
|
||||||
|
// printf("Got at TAP: %d bytes\n", (int) nread);
|
||||||
|
if (port_addr.sin_family != 0) { // something has been written to this struct (we got a conterpart)
|
||||||
|
sendto(sockfd, buf, (size_t) nread, 0, (struct sockaddr *) &port_addr, sizeof(port_addr));
|
||||||
|
// printf("Sent to %s port %d\n", inet_ntoa(port_addr.sin_addr), ntohs(port_addr.sin_port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pfd[1].revents & (POLLIN | POLLPRI)) {
|
||||||
|
socklen_t len = sizeof(port_addr);
|
||||||
|
ssize_t nread = recvfrom(sockfd, buf, 1540, 0, (struct sockaddr *) &port_addr, &len);
|
||||||
|
// printf("Got at UDP: %d bytes from %s port %d\n", nread, inet_ntoa(port_addr.sin_addr), ntohs(port_addr.sin_port));
|
||||||
|
write(fd, buf, (size_t) nread);
|
||||||
|
// printf("Sent to TAP\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (result >= 0);
|
||||||
|
printf("looks like we got an error here... should I quit ? Waiting for CTRL-C\n");
|
||||||
|
}
|
||||||
|
close(sockfd);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
@@ -6,4 +6,4 @@ server: main.c patched_mongoose.c mongoose.h Makefile
|
|||||||
$(CC) main.c patched_mongoose.c $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@
|
$(CC) main.c patched_mongoose.c $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f server
|
rm -rf server *.exe *.o *.dSYM
|
||||||
+293
-71
@@ -4,7 +4,12 @@
|
|||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
static int s_num_tests = 0;
|
static int s_num_tests = 0;
|
||||||
|
static bool s_error = false;
|
||||||
|
|
||||||
|
#ifdef NO_ABORT
|
||||||
|
static int s_abort = 0;
|
||||||
|
#define ABORT() ++s_abort, s_error = true
|
||||||
|
#else
|
||||||
#ifdef NO_SLEEP_ABORT
|
#ifdef NO_SLEEP_ABORT
|
||||||
#define ABORT() abort()
|
#define ABORT() abort()
|
||||||
#else
|
#else
|
||||||
@@ -12,6 +17,7 @@ static int s_num_tests = 0;
|
|||||||
sleep(2); /* 2s, GH print reason */ \
|
sleep(2); /* 2s, GH print reason */ \
|
||||||
abort();
|
abort();
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ASSERT(expr) \
|
#define ASSERT(expr) \
|
||||||
do { \
|
do { \
|
||||||
@@ -66,6 +72,13 @@ static void test_match(void) {
|
|||||||
ASSERT(mg_match(mg_str_n("caabxa", 6), mg_str_n("#aa#bb#", 7), NULL) == 0);
|
ASSERT(mg_match(mg_str_n("caabxa", 6), mg_str_n("#aa#bb#", 7), NULL) == 0);
|
||||||
ASSERT(mg_match(mg_str_n("a__b_c", 6), mg_str_n("a*b*c", 5), NULL) == 1);
|
ASSERT(mg_match(mg_str_n("a__b_c", 6), mg_str_n("a*b*c", 5), NULL) == 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
char *ae_value = (char *) malloc(1); // Exact size for ASAN
|
||||||
|
ae_value[0] = 'g';
|
||||||
|
mg_match(mg_str_n(ae_value, 1), mg_str("*gzip*"), NULL); // Check for OOB
|
||||||
|
free(ae_value);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
struct mg_str caps[3];
|
struct mg_str caps[3];
|
||||||
ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), NULL) == true);
|
ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), NULL) == true);
|
||||||
@@ -316,6 +329,8 @@ static void test_iobuf(void) {
|
|||||||
mg_iobuf_add(&io, io.len, "a", 1);
|
mg_iobuf_add(&io, io.len, "a", 1);
|
||||||
ASSERT(io.buf != NULL && io.size == 20 && io.len == 11);
|
ASSERT(io.buf != NULL && io.size == 20 && io.len == 11);
|
||||||
ASSERT(memcmp(io.buf, "xhi!123456a", io.len) == 0);
|
ASSERT(memcmp(io.buf, "xhi!123456a", io.len) == 0);
|
||||||
|
mg_iobuf_resize(&io, 1);
|
||||||
|
ASSERT(io.buf != NULL && io.size == 10 && io.len == 10);
|
||||||
mg_iobuf_free(&io);
|
mg_iobuf_free(&io);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +446,7 @@ static const char *s_ca_cert =
|
|||||||
#else
|
#else
|
||||||
#define MQTTS_URL "mqtts://broker.hivemq.com:8883"
|
#define MQTTS_URL "mqtts://broker.hivemq.com:8883"
|
||||||
#define MQTTS_CA mg_unpacked("/data/ca.pem")
|
#define MQTTS_CA mg_unpacked("/data/ca.pem")
|
||||||
#endif // MQTT_LOCALHOST
|
#endif // MQTT_LOCALHOST
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct mqtt_data {
|
struct mqtt_data {
|
||||||
@@ -446,6 +461,7 @@ struct mqtt_data {
|
|||||||
#define flags_received (1 << 2)
|
#define flags_received (1 << 2)
|
||||||
#define flags_released (1 << 3)
|
#define flags_released (1 << 3)
|
||||||
#define flags_completed (1 << 4)
|
#define flags_completed (1 << 4)
|
||||||
|
#define flags_unsubscribed (1 << 5)
|
||||||
|
|
||||||
static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
struct mqtt_data *test_data = (struct mqtt_data *) c->fn_data;
|
struct mqtt_data *test_data = (struct mqtt_data *) c->fn_data;
|
||||||
@@ -455,7 +471,7 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
struct mg_tls_opts opts;
|
struct mg_tls_opts opts;
|
||||||
memset(&opts, 0, sizeof(opts));
|
memset(&opts, 0, sizeof(opts));
|
||||||
opts.ca = MQTTS_CA;
|
opts.ca = MQTTS_CA;
|
||||||
#if defined( MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
||||||
MG_ERROR(("Hostname not tested"));
|
MG_ERROR(("Hostname not tested"));
|
||||||
#else
|
#else
|
||||||
opts.name = mg_url_host(MQTTS_URL);
|
opts.name = mg_url_host(MQTTS_URL);
|
||||||
@@ -479,6 +495,8 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
test_data->flags |= flags_released;
|
test_data->flags |= flags_released;
|
||||||
} else if (mm->cmd == MQTT_CMD_PUBCOMP) {
|
} else if (mm->cmd == MQTT_CMD_PUBCOMP) {
|
||||||
test_data->flags |= flags_completed;
|
test_data->flags |= flags_completed;
|
||||||
|
} else if (mm->cmd == MQTT_CMD_UNSUBACK) {
|
||||||
|
test_data->flags = flags_unsubscribed;
|
||||||
}
|
}
|
||||||
} else if (ev == MG_EV_MQTT_MSG) {
|
} else if (ev == MG_EV_MQTT_MSG) {
|
||||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||||
@@ -491,7 +509,7 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
size_t pos = 0, i = 0, j = 0;
|
size_t pos = 0, i = 0, j = 0;
|
||||||
struct mg_mqtt_prop prop;
|
struct mg_mqtt_prop prop;
|
||||||
|
|
||||||
for (i = 0; i < 5 ; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
|
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
|
||||||
if (prop.id == MQTT_PROP_MESSAGE_EXPIRY_INTERVAL) {
|
if (prop.id == MQTT_PROP_MESSAGE_EXPIRY_INTERVAL) {
|
||||||
ASSERT(prop.iv == 10);
|
ASSERT(prop.iv == 10);
|
||||||
@@ -500,14 +518,20 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
j += 2;
|
j += 2;
|
||||||
continue;
|
continue;
|
||||||
} else if (prop.id == MQTT_PROP_CONTENT_TYPE) {
|
} else if (prop.id == MQTT_PROP_CONTENT_TYPE) {
|
||||||
ASSERT(strncmp(prop.val.buf, "test_content_val_2", prop.val.len) == 0 && prop.val.len == strlen("test_content_val_2"));
|
ASSERT(strncmp(prop.val.buf, "test_content_val_2", prop.val.len) ==
|
||||||
|
0 &&
|
||||||
|
prop.val.len == strlen("test_content_val_2"));
|
||||||
j += 4;
|
j += 4;
|
||||||
} else if (prop.id == MQTT_PROP_USER_PROPERTY) {
|
} else if (prop.id == MQTT_PROP_USER_PROPERTY) {
|
||||||
if (strncmp(prop.key.buf, "test_key_1", prop.key.len) == 0 && prop.key.len == strlen("test_key_1")) {
|
if (strncmp(prop.key.buf, "test_key_1", prop.key.len) == 0 &&
|
||||||
ASSERT(strncmp(prop.val.buf, "test_value_1", prop.val.len) == 0 && prop.val.len == strlen("test_value_1"));
|
prop.key.len == strlen("test_key_1")) {
|
||||||
|
ASSERT(strncmp(prop.val.buf, "test_value_1", prop.val.len) == 0 &&
|
||||||
|
prop.val.len == strlen("test_value_1"));
|
||||||
j += 8;
|
j += 8;
|
||||||
} else if (strncmp(prop.key.buf, "test_key_2", prop.key.len) == 0 && prop.key.len == strlen("test_key_2")) {
|
} else if (strncmp(prop.key.buf, "test_key_2", prop.key.len) == 0 &&
|
||||||
ASSERT(strncmp(prop.val.buf, "test_value_2", prop.val.len) == 0 && prop.val.len == strlen("test_value_2"));
|
prop.key.len == strlen("test_key_2")) {
|
||||||
|
ASSERT(strncmp(prop.val.buf, "test_value_2", prop.val.len) == 0 &&
|
||||||
|
prop.val.len == strlen("test_value_2"));
|
||||||
j += 16;
|
j += 16;
|
||||||
} else {
|
} else {
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
@@ -751,6 +775,12 @@ static void test_mqtt_ver(uint8_t mqtt_version) {
|
|||||||
memset(mbuf + 1, 0, sizeof(mbuf) - 1);
|
memset(mbuf + 1, 0, sizeof(mbuf) - 1);
|
||||||
test_data.flags = 0;
|
test_data.flags = 0;
|
||||||
|
|
||||||
|
opts.props = 0; opts.num_props = 0;
|
||||||
|
mg_mqtt_unsub(c, &opts);
|
||||||
|
for (i = 0; i < 500 && test_data.flags == 0; i++) mg_mgr_poll(&mgr, 10);
|
||||||
|
ASSERT(test_data.flags == flags_unsubscribed);
|
||||||
|
test_data.flags = 0;
|
||||||
|
|
||||||
// dirty disconnect
|
// dirty disconnect
|
||||||
mg_mgr_free(&mgr);
|
mg_mgr_free(&mgr);
|
||||||
ASSERT(mgr.conns == NULL);
|
ASSERT(mgr.conns == NULL);
|
||||||
@@ -867,8 +897,10 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
|
|||||||
if (strstr(url, "localhost") != NULL) {
|
if (strstr(url, "localhost") != NULL) {
|
||||||
// Local connection, use self-signed certificates
|
// Local connection, use self-signed certificates
|
||||||
opts.ca = mg_unpacked("/certs/ca.crt");
|
opts.ca = mg_unpacked("/certs/ca.crt");
|
||||||
// opts.cert = mg_str(s_tls_cert);
|
if (strstr(url, "23456") != NULL) { // hinted from caller
|
||||||
// opts.key = mg_str(s_tls_key);
|
opts.cert = mg_unpacked("/certs/client.crt");
|
||||||
|
opts.key = mg_unpacked("/certs/client.key");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mg_tls_init(c, &opts);
|
mg_tls_init(c, &opts);
|
||||||
}
|
}
|
||||||
@@ -1414,7 +1446,6 @@ static void test_tls(void) {
|
|||||||
struct mg_str bd;
|
struct mg_str bd;
|
||||||
ASSERT(data.buf != NULL && data.len > 0);
|
ASSERT(data.buf != NULL && data.len > 0);
|
||||||
memset(&opts, 0, sizeof(opts));
|
memset(&opts, 0, sizeof(opts));
|
||||||
// opts.ca = mg_str(s_tls_ca);
|
|
||||||
opts.cert = mg_unpacked("/certs/server.crt");
|
opts.cert = mg_unpacked("/certs/server.crt");
|
||||||
opts.key = mg_unpacked("/certs/server.key");
|
opts.key = mg_unpacked("/certs/server.key");
|
||||||
mg_mgr_init(&mgr);
|
mg_mgr_init(&mgr);
|
||||||
@@ -1442,7 +1473,7 @@ static void test_tls(void) {
|
|||||||
"%s",
|
"%s",
|
||||||
bd.len, bd.buf) == 200);
|
bd.len, bd.buf) == 200);
|
||||||
ASSERT(cmpbody(buf, bd.buf) == 0);
|
ASSERT(cmpbody(buf, bd.buf) == 0);
|
||||||
#if MG_TLS == MG_TLS_BUILTIN && defined(__linux__)
|
#if MG_TLS == MG_TLS_BUILTIN && defined(__linux__) && MG_ENABLE_CHACHA20 // skip for non-CHACHA tests
|
||||||
// fire patched server, test multiple TLS records per TCP segment handling
|
// fire patched server, test multiple TLS records per TCP segment handling
|
||||||
// skip other TLS stacks to avoid "bad client hello", we are 1.3 only
|
// skip other TLS stacks to avoid "bad client hello", we are 1.3 only
|
||||||
if (access("tls_multirec/server", X_OK) == 0) {
|
if (access("tls_multirec/server", X_OK) == 0) {
|
||||||
@@ -1455,7 +1486,8 @@ static void test_tls(void) {
|
|||||||
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
|
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
|
||||||
ASSERT(system("killall tls_multirec/server") == 0);
|
ASSERT(system("killall tls_multirec/server") == 0);
|
||||||
} else {
|
} else {
|
||||||
MG_ERROR(("SKIPPED TLS MULTIPLE RECORDS TEST, tls_multirec/server NOT PRESENT"));
|
MG_ERROR(
|
||||||
|
("SKIPPED TLS MULTIPLE RECORDS TEST, tls_multirec/server NOT PRESENT"));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
printf(
|
printf(
|
||||||
@@ -1463,6 +1495,20 @@ static void test_tls(void) {
|
|||||||
"is 1.3 only; re-enable when other stacks can be easily configured for "
|
"is 1.3 only; re-enable when other stacks can be easily configured for "
|
||||||
"1.3\n");
|
"1.3\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Repeat the simplest test with two-way authentication
|
||||||
|
opts.ca = mg_unpacked("/certs/ca.crt"); // configure the server for two-way
|
||||||
|
// make it fail: the client will not use 2-way
|
||||||
|
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") != 200);
|
||||||
|
// make it work
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
ASSERT(mgr.conns == NULL);
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
url = "https://localhost:23456"; // port # hints the client to use two-way
|
||||||
|
c = mg_http_listen(&mgr, url, eh1, &opts);
|
||||||
|
ASSERT(c != NULL);
|
||||||
|
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
|
||||||
|
ASSERT(cmpbody(buf, "hello\n") == 0);
|
||||||
mg_mgr_free(&mgr);
|
mg_mgr_free(&mgr);
|
||||||
ASSERT(mgr.conns == NULL);
|
ASSERT(mgr.conns == NULL);
|
||||||
#endif
|
#endif
|
||||||
@@ -1473,7 +1519,8 @@ static void f3(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
// MG_INFO(("%d", ev));
|
// MG_INFO(("%d", ev));
|
||||||
if (ev == MG_EV_CONNECT) {
|
if (ev == MG_EV_CONNECT) {
|
||||||
// c->is_hexdumping = 1;
|
// c->is_hexdumping = 1;
|
||||||
ASSERT((c->loc.ip[0] != 0)); // Make sure that c->loc address is populated
|
ASSERT((c->loc.addr.ip[0] !=
|
||||||
|
0)); // Make sure that c->loc address is populated
|
||||||
mg_printf(c, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
|
mg_printf(c, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
|
||||||
c->rem.is_ip6 ? "" : "/robots.txt",
|
c->rem.is_ip6 ? "" : "/robots.txt",
|
||||||
c->rem.is_ip6 ? "ipv6.google.com" : "cesanta.com");
|
c->rem.is_ip6 ? "ipv6.google.com" : "cesanta.com");
|
||||||
@@ -1510,12 +1557,12 @@ static void test_http_client(void) {
|
|||||||
ASSERT(ok == 301 || ok == 200);
|
ASSERT(ok == 301 || ok == 200);
|
||||||
mg_mgr_poll(&mgr, 0);
|
mg_mgr_poll(&mgr, 0);
|
||||||
ok = 0;
|
ok = 0;
|
||||||
#if MG_TLS
|
#if MG_TLS && MG_TLS != MG_TLS_BUILTIN
|
||||||
url = "https://cesanta.com";
|
url = "https://cesanta.com";
|
||||||
opts.name = mg_url_host(url);
|
opts.name = mg_url_host(url);
|
||||||
#if MG_TLS == MG_TLS_BUILTIN
|
#if MG_TLS == MG_TLS_BUILTIN
|
||||||
// our TLS does not search for the proper CA in a bundle
|
// our TLS does not search for the proper CA in a bundle
|
||||||
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
|
opts.ca = mg_file_read(&mg_fs_posix, "data/e8.crt");
|
||||||
#endif
|
#endif
|
||||||
c = mg_http_connect(&mgr, url, f3, &ok);
|
c = mg_http_connect(&mgr, url, f3, &ok);
|
||||||
ASSERT(c != NULL);
|
ASSERT(c != NULL);
|
||||||
@@ -1525,7 +1572,7 @@ static void test_http_client(void) {
|
|||||||
ASSERT(ok == 200);
|
ASSERT(ok == 200);
|
||||||
mg_mgr_poll(&mgr, 1);
|
mg_mgr_poll(&mgr, 1);
|
||||||
|
|
||||||
// Make host validationfail
|
// Make host validation fail
|
||||||
c = mg_http_connect(&mgr, url, f3, &ok);
|
c = mg_http_connect(&mgr, url, f3, &ok);
|
||||||
ASSERT(c != NULL);
|
ASSERT(c != NULL);
|
||||||
opts.name = mg_str("dummy"); // Set some invalid hostname value
|
opts.name = mg_str("dummy"); // Set some invalid hostname value
|
||||||
@@ -1535,6 +1582,16 @@ static void test_http_client(void) {
|
|||||||
MG_INFO(("OK: %d", ok));
|
MG_INFO(("OK: %d", ok));
|
||||||
ASSERT(ok == 777);
|
ASSERT(ok == 777);
|
||||||
mg_mgr_poll(&mgr, 1);
|
mg_mgr_poll(&mgr, 1);
|
||||||
|
// Skip host validation
|
||||||
|
c = mg_http_connect(&mgr, url, f3, &ok);
|
||||||
|
ASSERT(c != NULL);
|
||||||
|
opts.name = mg_str("");
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
ok = 0;
|
||||||
|
for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
|
||||||
|
MG_INFO(("OK: %d", ok));
|
||||||
|
ASSERT(ok == 200);
|
||||||
|
mg_mgr_poll(&mgr, 1);
|
||||||
opts.name = mg_url_host(url);
|
opts.name = mg_url_host(url);
|
||||||
#if MG_TLS == MG_TLS_BUILTIN
|
#if MG_TLS == MG_TLS_BUILTIN
|
||||||
mg_free((void *) opts.ca.buf);
|
mg_free((void *) opts.ca.buf);
|
||||||
@@ -1622,14 +1679,12 @@ static void test_http_no_content_length(void) {
|
|||||||
// 12348 is in TIME_WAIT, use another port
|
// 12348 is in TIME_WAIT, use another port
|
||||||
mg_mgr_init(&mgr);
|
mg_mgr_init(&mgr);
|
||||||
mg_http_listen(&mgr, url2, f41, (void *) NULL);
|
mg_http_listen(&mgr, url2, f41, (void *) NULL);
|
||||||
ASSERT(fetch(&mgr, buf, url2, "POST / HTTP/1.1\r\n\r\n") == 411);
|
ASSERT(fetch(&mgr, buf, url2, "POST / HTTP/1.1\r\n\r\n") == 200);
|
||||||
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 200\r\n\r\n") == 411);
|
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 200\r\n\r\n") == 411);
|
||||||
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 100\r\n\r\n") != 411);
|
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 100\r\n\r\n") != 411);
|
||||||
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 304\r\n\r\n") != 411);
|
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 304\r\n\r\n") != 411);
|
||||||
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 305\r\n\r\n") == 411);
|
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 305\r\n\r\n") == 411);
|
||||||
ASSERT(fetch(&mgr, buf, url2, post_req) != 411);
|
ASSERT(fetch(&mgr, buf, url2, post_req) != 411);
|
||||||
// Check it is processed only once (see #2811)
|
|
||||||
ASSERT(fpr(&mgr, buf, url2, "POST / HTTP/1.1\r\n\r\n") == 411);
|
|
||||||
mg_mgr_free(&mgr);
|
mg_mgr_free(&mgr);
|
||||||
ASSERT(mgr.conns == NULL);
|
ASSERT(mgr.conns == NULL);
|
||||||
}
|
}
|
||||||
@@ -1748,15 +1803,15 @@ static void test_http_parse(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// #2292: fail on stray \r inside the headers
|
// #2292: fail on stray \r inside the headers
|
||||||
ASSERT(mg_http_parse("a є\n\n", 6, &req) == 6);
|
ASSERT(mg_http_parse("a є HTTP/1.0\n\n", 15, &req) == 15);
|
||||||
ASSERT(mg_http_parse("a b\n\n", 5, &req) == 5);
|
ASSERT(mg_http_parse("a b HTTP/1.0\n\n", 14, &req) == 14);
|
||||||
ASSERT(mg_http_parse("a b\na:\n\n", 8, &req) > 0);
|
ASSERT(mg_http_parse("a b HTTP/1.0\na:\n\n", 17, &req) > 0);
|
||||||
ASSERT(mg_http_parse("a b\na:\r\n\n", 9, &req) > 0);
|
ASSERT(mg_http_parse("a b HTTP/1.0\na:\r\n\n", 18, &req) > 0);
|
||||||
ASSERT(mg_http_parse("a b\n\ra:\r\n\n", 10, &req) == -1);
|
ASSERT(mg_http_parse("a b HTTP/1.0\n\ra:\r\n\n", 19, &req) == -1);
|
||||||
ASSERT(mg_http_parse("a b\na:\r1\n\n", 10, &req) == -1);
|
ASSERT(mg_http_parse("a b HTTP/1.0\na:\r1\n\n", 19, &req) == -1);
|
||||||
ASSERT(mg_http_parse("a b\na: \r1\n\n", 11, &req) == -1);
|
ASSERT(mg_http_parse("a b HTTP/1.0\na: \r1\n\n", 20, &req) == -1);
|
||||||
ASSERT(mg_http_parse("a b\na: \rb:\n\n", 12, &req) == -1);
|
ASSERT(mg_http_parse("a b HTTP/1.0\na: \rb:\n\n", 21, &req) == -1);
|
||||||
ASSERT(mg_http_parse("a b\na: \nb:\n\n", 12, &req) > 0);
|
ASSERT(mg_http_parse("a b HTTP/1.0\na: \nb:\n\n", 21, &req) > 0);
|
||||||
|
|
||||||
{
|
{
|
||||||
const char *s = "ґєт /слеш HTTP/1.0\nмісто: кіїв \n\n";
|
const char *s = "ґєт /слеш HTTP/1.0\nмісто: кіїв \n\n";
|
||||||
@@ -1794,7 +1849,7 @@ static void test_http_parse(void) {
|
|||||||
{
|
{
|
||||||
const char *s = "POST /x HTTP/1.0\n\n";
|
const char *s = "POST /x HTTP/1.0\n\n";
|
||||||
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
|
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
|
||||||
ASSERT(req.body.len == (size_t) ~0);
|
ASSERT(req.body.len == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1833,8 +1888,7 @@ static void test_http_parse(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
static const char *s =
|
const char *s = "a b HTTP/1.0\na:1\nb:2\nc:3\nd:4\ne:5\nf:6\ng:7\nh:8\n\n";
|
||||||
"a b HTTP/1.0\na:1\nb:2\nc:3\nd:4\ne:5\nf:6\ng:7\nh:8\n\n";
|
|
||||||
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
|
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
|
||||||
ASSERT((v = mg_http_get_header(&req, "e")) != NULL);
|
ASSERT((v = mg_http_get_header(&req, "e")) != NULL);
|
||||||
ASSERT(vcmp(*v, "5"));
|
ASSERT(vcmp(*v, "5"));
|
||||||
@@ -1843,6 +1897,24 @@ static void test_http_parse(void) {
|
|||||||
ASSERT((v = mg_http_get_header(&req, "h")) == NULL); // MG_MAX_HTTP_HEADERS
|
ASSERT((v = mg_http_get_header(&req, "h")) == NULL); // MG_MAX_HTTP_HEADERS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// no HTTP version
|
||||||
|
const char *s = "a b\na:1\nb:2\nc:2\n\n";
|
||||||
|
ASSERT(mg_http_parse(s, strlen(s), &req) == -1);
|
||||||
|
|
||||||
|
// HTTP version
|
||||||
|
s = "a b HTTP/1.0\na:1\nb:2\nc:2\n\n";
|
||||||
|
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
|
||||||
|
|
||||||
|
// Content-Length
|
||||||
|
s = "a b HTTP/1.0\nContent-Length:10\nb:2\nc:2\n\n";
|
||||||
|
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
|
||||||
|
|
||||||
|
// duplicated Content-Length
|
||||||
|
s = "a b HTTP/1.0\nContent-Length:10\nb:2\nContent-Length:20\n\n";
|
||||||
|
ASSERT(mg_http_parse(s, strlen(s), &req) == -1);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
struct mg_connection c;
|
struct mg_connection c;
|
||||||
struct mg_str s,
|
struct mg_str s,
|
||||||
@@ -1868,15 +1940,15 @@ static void test_http_parse(void) {
|
|||||||
struct mg_http_message hm;
|
struct mg_http_message hm;
|
||||||
const char *s = "a b HTTP/1.0\n\n";
|
const char *s = "a b HTTP/1.0\n\n";
|
||||||
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
||||||
s = "a b\nc:d\n\n";
|
s = "a b HTTP/1.0\nc:d\n\n";
|
||||||
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
||||||
s = "a\nb:b\nc:c\n\n";
|
s = "a\nb:b\nc:c\n\n";
|
||||||
ASSERT(mg_http_parse(s, strlen(s), &hm) < 0);
|
ASSERT(mg_http_parse(s, strlen(s), &hm) < 0);
|
||||||
s = "a b\nc: \xc0\n\n"; // Invalid UTF in the header value: accept
|
s = "a b HTTP/1.0\nc: \xc0\n\n"; // Invalid UTF in the header value: accept
|
||||||
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
|
||||||
ASSERT((v = mg_http_get_header(&hm, "c")) != NULL);
|
ASSERT((v = mg_http_get_header(&hm, "c")) != NULL);
|
||||||
ASSERT(vcmp(*v, "\xc0"));
|
ASSERT(vcmp(*v, "\xc0"));
|
||||||
s = "a b\n\xc0: 2\n\n"; // Invalid UTF in the header name: do NOT accept
|
s = "a b HTTP/1.0\n\xc0: 2\n\n"; // Invalid UTF in the header name: do NOT accept
|
||||||
ASSERT(mg_http_parse(s, strlen(s), &hm) == -1);
|
ASSERT(mg_http_parse(s, strlen(s), &hm) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2232,6 +2304,16 @@ static void test_str(void) {
|
|||||||
ASSERT(sn("%s ", "a"));
|
ASSERT(sn("%s ", "a"));
|
||||||
ASSERT(sn("%s %s", "a", "b"));
|
ASSERT(sn("%s %s", "a", "b"));
|
||||||
ASSERT(sn("%2s %s", "a", "b"));
|
ASSERT(sn("%2s %s", "a", "b"));
|
||||||
|
{ // mg_queue_printf()
|
||||||
|
struct mg_queue q;
|
||||||
|
char buf[128];
|
||||||
|
uint32_t p = 0xffffffff;
|
||||||
|
size_t len;
|
||||||
|
mg_queue_init(&q, buf, sizeof(buf));
|
||||||
|
len = mg_queue_printf(&q, "A%p%p%pB", p, p, p);
|
||||||
|
ASSERT(len == 32);
|
||||||
|
ASSERT(memcmp(buf + 4, "A0xffffffff0xffffffff0xffffffffB", 32) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Non-standard formatting
|
// Non-standard formatting
|
||||||
{
|
{
|
||||||
@@ -2435,7 +2517,7 @@ static void test_str(void) {
|
|||||||
char buf[100];
|
char buf[100];
|
||||||
struct mg_addr a;
|
struct mg_addr a;
|
||||||
uint32_t addr = mg_htonl(0x2000001);
|
uint32_t addr = mg_htonl(0x2000001);
|
||||||
memcpy(a.ip, &addr, sizeof(uint32_t));
|
memcpy(a.addr.ip, &addr, sizeof(uint32_t));
|
||||||
a.port = mg_htons(3);
|
a.port = mg_htons(3);
|
||||||
a.is_ip6 = false;
|
a.is_ip6 = false;
|
||||||
|
|
||||||
@@ -2445,8 +2527,8 @@ static void test_str(void) {
|
|||||||
11);
|
11);
|
||||||
ASSERT(strcmp(buf, "2.0.0.1:3 7") == 0);
|
ASSERT(strcmp(buf, "2.0.0.1:3 7") == 0);
|
||||||
|
|
||||||
memset(a.ip, 0, sizeof(a.ip));
|
memset(a.addr.ip, 0, sizeof(a.addr.ip));
|
||||||
a.ip[0] = 1, a.ip[1] = 100, a.ip[2] = 33;
|
a.addr.ip[0] = 1, a.addr.ip[1] = 100, a.addr.ip[2] = 33;
|
||||||
a.is_ip6 = true;
|
a.is_ip6 = true;
|
||||||
ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 24);
|
ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 24);
|
||||||
ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0] 7") == 0);
|
ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0] 7") == 0);
|
||||||
@@ -2574,6 +2656,8 @@ static void test_util(void) {
|
|||||||
const char *e;
|
const char *e;
|
||||||
char buf[100], *s;
|
char buf[100], *s;
|
||||||
struct mg_addr a;
|
struct mg_addr a;
|
||||||
|
uint64_t ipv3;
|
||||||
|
uint8_t d64[8] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef};
|
||||||
uint32_t ipv4;
|
uint32_t ipv4;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
struct mg_str data;
|
struct mg_str data;
|
||||||
@@ -2591,7 +2675,7 @@ static void test_util(void) {
|
|||||||
ASSERT(mg_aton(mg_str("0.0.0.-1"), &a) == false);
|
ASSERT(mg_aton(mg_str("0.0.0.-1"), &a) == false);
|
||||||
ASSERT(mg_aton(mg_str("127.0.0.1"), &a) == true);
|
ASSERT(mg_aton(mg_str("127.0.0.1"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == false);
|
ASSERT(a.is_ip6 == false);
|
||||||
memcpy(&ipv4, a.ip, sizeof(ipv4));
|
memcpy(&ipv4, &a.addr.ip4, sizeof(ipv4));
|
||||||
ASSERT(ipv4 == mg_htonl(0x7f000001));
|
ASSERT(ipv4 == mg_htonl(0x7f000001));
|
||||||
ASSERT(mg_ntohl(ipv4) == 0x7f000001);
|
ASSERT(mg_ntohl(ipv4) == 0x7f000001);
|
||||||
MG_STORE_BE32(&ipv4, 0x5678abcd);
|
MG_STORE_BE32(&ipv4, 0x5678abcd);
|
||||||
@@ -2608,48 +2692,62 @@ static void test_util(void) {
|
|||||||
((uint8_t *) &ipv4)[2] == 0x45);
|
((uint8_t *) &ipv4)[2] == 0x45);
|
||||||
ASSERT(MG_LOAD_BE24(&ipv4) == 0xef2345);
|
ASSERT(MG_LOAD_BE24(&ipv4) == 0xef2345);
|
||||||
|
|
||||||
memset(a.ip, 0xa5, sizeof(a.ip));
|
memcpy(&ipv3, d64, sizeof(ipv3));
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1700
|
||||||
|
// VC98 doesn't suppport LL suffix
|
||||||
|
#else
|
||||||
|
ASSERT(ipv3 == mg_htonll(0x1234567890abcdefLL));
|
||||||
|
ASSERT(mg_ntohll(ipv3) == 0x1234567890abcdefLL);
|
||||||
|
#endif
|
||||||
|
MG_STORE_BE64(&ipv3, 0x5678abcd12349ef0);
|
||||||
|
ASSERT(((uint8_t *) &ipv3)[0] == 0x56 && ((uint8_t *) &ipv3)[1] == 0x78 &&
|
||||||
|
((uint8_t *) &ipv3)[2] == 0xab && ((uint8_t *) &ipv3)[3] == 0xcd &&
|
||||||
|
((uint8_t *) &ipv3)[4] == 0x12 && ((uint8_t *) &ipv3)[5] == 0x34 &&
|
||||||
|
((uint8_t *) &ipv3)[6] == 0x9e && ((uint8_t *) &ipv3)[7] == 0xf0);
|
||||||
|
ASSERT(MG_LOAD_BE64(&ipv3) == 0x5678abcd12349ef0);
|
||||||
|
|
||||||
|
memset(a.addr.ip, 0xa5, sizeof(a.addr.ip)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true);
|
ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
e = "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08";
|
e = "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08";
|
||||||
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
|
ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
|
||||||
|
|
||||||
memset(a.ip, 0xa5, sizeof(a.ip));
|
memset(a.addr.ip, 0xa5, sizeof(a.addr.ip)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("1:2::3"), &a) == true);
|
ASSERT(mg_aton(mg_str("1:2::3"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
e = "\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03";
|
e = "\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03";
|
||||||
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
|
ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("1::1"), &a) == true);
|
ASSERT(mg_aton(mg_str("1::1"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
|
e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
|
||||||
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
|
ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true);
|
ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04";
|
e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04";
|
||||||
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
|
ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("::1"), &a) == true);
|
ASSERT(mg_aton(mg_str("::1"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
ASSERT(a.scope_id == 0);
|
ASSERT(a.scope_id == 0);
|
||||||
e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
|
e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
|
||||||
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
|
ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("1::"), &a) == true);
|
ASSERT(mg_aton(mg_str("1::"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||||
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
|
ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true);
|
ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
e = "\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88";
|
e = "\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88";
|
||||||
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
|
ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
|
||||||
|
|
||||||
ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);
|
ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);
|
||||||
ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
|
ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
|
||||||
@@ -2658,22 +2756,22 @@ static void test_util(void) {
|
|||||||
ASSERT(mg_url_decode("a=%123", 6, buf, sizeof(buf), 0) == 4 &&
|
ASSERT(mg_url_decode("a=%123", 6, buf, sizeof(buf), 0) == 4 &&
|
||||||
buf[2] == 0x12 && buf[3] == '3');
|
buf[2] == 0x12 && buf[3] == '3');
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(&a, 0, sizeof(a));
|
||||||
ASSERT(mg_aton(mg_str("::1%1"), &a) == true);
|
ASSERT(mg_aton(mg_str("::1%1"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
ASSERT(a.scope_id == 1);
|
ASSERT(a.scope_id == 1);
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(&a, 0, sizeof(a));
|
||||||
ASSERT(mg_aton(mg_str("abcd::aabb:ccdd%17"), &a) == true);
|
ASSERT(mg_aton(mg_str("abcd::aabb:ccdd%17"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
ASSERT(a.scope_id == 17);
|
ASSERT(a.scope_id == 17);
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(&a, 0xaa, sizeof(a)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("::1%17"), &a) == true);
|
ASSERT(mg_aton(mg_str("::1%17"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
ASSERT(a.scope_id == 17);
|
ASSERT(a.scope_id == 17);
|
||||||
|
|
||||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
memset(&a, 0xaa, sizeof(a)), a.is_ip6 = false;
|
||||||
ASSERT(mg_aton(mg_str("::1%255"), &a) == true);
|
ASSERT(mg_aton(mg_str("::1%255"), &a) == true);
|
||||||
ASSERT(a.is_ip6 == true);
|
ASSERT(a.is_ip6 == true);
|
||||||
ASSERT(a.scope_id == 255);
|
ASSERT(a.scope_id == 255);
|
||||||
@@ -2918,6 +3016,14 @@ static void eZ(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
(void) ev_data;
|
(void) ev_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void eS(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
ASSERT(mg_send(c, "NADA", 0));
|
||||||
|
mg_http_reply(c, 200, "", "abcd");
|
||||||
|
}
|
||||||
|
(void) ev_data;
|
||||||
|
}
|
||||||
|
|
||||||
// Do not delete chunks as they arrive
|
// Do not delete chunks as they arrive
|
||||||
static void eh4(struct mg_connection *c, int ev, void *ev_data) {
|
static void eh4(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
uint32_t *crc = (uint32_t *) c->fn_data;
|
uint32_t *crc = (uint32_t *) c->fn_data;
|
||||||
@@ -2953,6 +3059,9 @@ static void test_http_chunked_case(mg_event_handler_t s, mg_event_handler_t c,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_http_chunked(void) {
|
static void test_http_chunked(void) {
|
||||||
|
// test mg_send allows calls with 0 length
|
||||||
|
test_http_chunked_case(eS, eh4, 1, "abcd");
|
||||||
|
|
||||||
// Non-chunked encoding
|
// Non-chunked encoding
|
||||||
test_http_chunked_case(eY, eh4, 1, "abcd"); // Chunks not deleted
|
test_http_chunked_case(eY, eh4, 1, "abcd"); // Chunks not deleted
|
||||||
test_http_chunked_case(eY, eh4, 2, "abcdabcd");
|
test_http_chunked_case(eY, eh4, 2, "abcdabcd");
|
||||||
@@ -3176,7 +3285,7 @@ static void test_udp(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_check_ip_acl(void) {
|
static void test_check_ip_acl(void) {
|
||||||
struct mg_addr ip = {{1, 2, 3, 4}, 0, 0, false}; // 1.2.3.4
|
struct mg_addr ip = {{{1, 2, 3, 4}}, 0, 0, false}; // 1.2.3.4
|
||||||
ASSERT(mg_check_ip_acl(mg_str(NULL), &ip) == 1);
|
ASSERT(mg_check_ip_acl(mg_str(NULL), &ip) == 1);
|
||||||
ASSERT(mg_check_ip_acl(mg_str(""), &ip) == 1);
|
ASSERT(mg_check_ip_acl(mg_str(""), &ip) == 1);
|
||||||
ASSERT(mg_check_ip_acl(mg_str("invalid"), &ip) == -1);
|
ASSERT(mg_check_ip_acl(mg_str("invalid"), &ip) == -1);
|
||||||
@@ -3540,6 +3649,39 @@ static void test_json(void) {
|
|||||||
val = mg_json_get_tok(json, "$.a");
|
val = mg_json_get_tok(json, "$.a");
|
||||||
ASSERT(mg_strcmp(val, expected) == 0);
|
ASSERT(mg_strcmp(val, expected) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mg_json_get_num: parsing exponential
|
||||||
|
{
|
||||||
|
double d = 0.0, tolerance = 1e-12;
|
||||||
|
json = mg_str(
|
||||||
|
"{"
|
||||||
|
"\"i\":1e3,"
|
||||||
|
"\"n\":-2.5e2,"
|
||||||
|
"\"p\":3E+4,"
|
||||||
|
"\"m\":4.25E-1,"
|
||||||
|
"\"z\":0e0,"
|
||||||
|
"\"s\":-0.0e+0,"
|
||||||
|
"\"a\":[6.123456789e3,-1e-9],"
|
||||||
|
"\"bad\":\"1e3\""
|
||||||
|
"}");
|
||||||
|
ASSERT(mg_json_get_num(json, "$.i", &d) == true);
|
||||||
|
ASSERT(fabs(d - 1000.0) < tolerance);
|
||||||
|
ASSERT(mg_json_get_num(json, "$.n", &d) == true);
|
||||||
|
ASSERT(fabs(d - -250.0) < tolerance);
|
||||||
|
ASSERT(mg_json_get_num(json, "$.p", &d) == true);
|
||||||
|
ASSERT(fabs(d - 30000.0) < tolerance);
|
||||||
|
ASSERT(mg_json_get_num(json, "$.m", &d) == true);
|
||||||
|
ASSERT(fabs(d - 0.425) < tolerance);
|
||||||
|
ASSERT(mg_json_get_num(json, "$.z", &d) == true);
|
||||||
|
ASSERT(fabs(d - 0.0) < tolerance);
|
||||||
|
ASSERT(mg_json_get_num(json, "$.s", &d) == true);
|
||||||
|
ASSERT(fabs(d - 0.0) < tolerance);
|
||||||
|
ASSERT(mg_json_get_num(json, "$.a[0]", &d) == true);
|
||||||
|
ASSERT(fabs(d - 6123.456789) < tolerance);
|
||||||
|
ASSERT(mg_json_get_num(json, "$.a[1]", &d) == true);
|
||||||
|
ASSERT(fabs(d - -1e-9) < tolerance);
|
||||||
|
ASSERT(mg_json_get_num(json, "$.bad", &d) == false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resp_rpc(struct mg_rpc_req *r) {
|
static void resp_rpc(struct mg_rpc_req *r) {
|
||||||
@@ -3953,54 +4095,134 @@ static void test_crypto(void) {
|
|||||||
test_rsa();
|
test_rsa();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DASHBOARD(x) \
|
||||||
|
printf("HEALTH_DASHBOARD\t\"%s\": %s,\n", x, s_error ? "false" : "true");
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
const char *debug_level = getenv("V");
|
const char *debug_level = getenv("V");
|
||||||
if (debug_level == NULL) debug_level = "3";
|
if (debug_level == NULL) debug_level = "3";
|
||||||
mg_log_set(atoi(debug_level));
|
mg_log_set(atoi(debug_level));
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_crypto();
|
test_crypto();
|
||||||
|
DASHBOARD("crypto");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_split();
|
test_split();
|
||||||
test_json();
|
test_util();
|
||||||
test_queue();
|
|
||||||
test_rpc();
|
|
||||||
test_str();
|
test_str();
|
||||||
test_match();
|
test_match();
|
||||||
|
test_crc32();
|
||||||
|
DASHBOARD("misc");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
|
test_json();
|
||||||
|
DASHBOARD("json");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
|
test_queue();
|
||||||
|
DASHBOARD("queue");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
|
test_rpc();
|
||||||
|
DASHBOARD("rpc");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
|
test_check_ip_acl();
|
||||||
|
DASHBOARD("ip_acl");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
|
test_udp();
|
||||||
|
DASHBOARD("udp");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_get_header_var();
|
test_get_header_var();
|
||||||
|
test_http_get_var();
|
||||||
test_http_parse();
|
test_http_parse();
|
||||||
test_rewrites();
|
test_rewrites();
|
||||||
test_check_ip_acl();
|
|
||||||
test_udp();
|
|
||||||
test_packed();
|
|
||||||
test_crc32();
|
|
||||||
test_multipart();
|
test_multipart();
|
||||||
test_invalid_listen_addr();
|
test_invalid_listen_addr();
|
||||||
test_http_chunked();
|
test_http_chunked();
|
||||||
test_http_upload();
|
DASHBOARD("http_support");
|
||||||
test_http_stream_buffer();
|
|
||||||
test_util();
|
s_error = false;
|
||||||
|
test_packed();
|
||||||
|
DASHBOARD("packed_fs");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_dns();
|
test_dns();
|
||||||
|
DASHBOARD("dns");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_timer();
|
test_timer();
|
||||||
|
DASHBOARD("timers");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_url();
|
test_url();
|
||||||
|
DASHBOARD("url");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_iobuf();
|
test_iobuf();
|
||||||
|
DASHBOARD("iobuf");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_base64();
|
test_base64();
|
||||||
test_http_get_var();
|
DASHBOARD("base64");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_tls();
|
test_tls();
|
||||||
|
DASHBOARD("tls");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_ws();
|
test_ws();
|
||||||
test_ws_fragmentation();
|
test_ws_fragmentation();
|
||||||
|
DASHBOARD("ws");
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
|
test_http_upload();
|
||||||
|
test_http_stream_buffer();
|
||||||
test_http_server();
|
test_http_server();
|
||||||
test_http_404();
|
test_http_404();
|
||||||
test_http_no_content_length();
|
test_http_no_content_length();
|
||||||
test_http_pipeline();
|
test_http_pipeline();
|
||||||
test_http_range();
|
test_http_range();
|
||||||
|
DASHBOARD("http_server");
|
||||||
|
|
||||||
#ifndef LOCALHOST_ONLY
|
#ifndef LOCALHOST_ONLY
|
||||||
|
s_error = false;
|
||||||
test_sntp();
|
test_sntp();
|
||||||
test_mqtt(); // sorry, MQTT_LOCALHOST is also skipped
|
DASHBOARD("sntp");
|
||||||
|
|
||||||
|
#if MG_TLS != MG_TLS_BUILTIN
|
||||||
|
s_error = false;
|
||||||
|
test_mqtt(); // sorry, MQTT_LOCALHOST is also skipped
|
||||||
|
DASHBOARD("mqtt");
|
||||||
|
#else
|
||||||
|
(void) test_mqtt;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s_error = false;
|
||||||
test_http_client();
|
test_http_client();
|
||||||
|
DASHBOARD("http_client");
|
||||||
|
|
||||||
#else
|
#else
|
||||||
(void) test_sntp, (void) test_mqtt, (void) test_http_client;
|
(void) test_sntp, (void) test_mqtt, (void) test_http_client;
|
||||||
#endif
|
#endif
|
||||||
|
s_error = false;
|
||||||
test_poll();
|
test_poll();
|
||||||
printf("SUCCESS. Total tests: %d\n", s_num_tests);
|
printf("HEALTH_DASHBOARD\t\"poll\": %s\n", s_error ? "false" : "true");
|
||||||
|
// last entry with no comma
|
||||||
|
|
||||||
|
#ifdef NO_ABORT
|
||||||
|
if (s_abort != 0) return EXIT_FAILURE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \
|
||||||
|
defined(MBEDTLS_PSA_CRYPTO_C)
|
||||||
|
// Call mbedtls_psa_crypto_free() here to avoid triggering memory-leak
|
||||||
|
// detectors. We are actually freeing all our resources and leaving
|
||||||
|
mbedtls_psa_crypto_free();
|
||||||
|
#endif
|
||||||
|
printf("SUCCESS. Total tests: %d\n", s_num_tests);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
SOURCES = main.c mongoose.c # Source code files
|
||||||
|
CFLAGS = -W -Wall -Wextra -g -I. # Build options
|
||||||
|
|
||||||
|
# O(1) Heap
|
||||||
|
SOURCES += o1heap/o1heap/o1heap.c
|
||||||
|
CFLAGS += -Io1heap/o1heap
|
||||||
|
|
||||||
|
# Mongoose build options. See https://mongoose.ws/documentation/#build-options
|
||||||
|
CFLAGS_MONGOOSE += -DMG_ENABLE_CUSTOM_CALLOC
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
# Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD
|
||||||
|
PROG ?= example.exe # Use .exe suffix for the binary
|
||||||
|
CC = gcc # Use MinGW gcc compiler
|
||||||
|
CFLAGS += -lws2_32 # Link against Winsock library
|
||||||
|
DELETE = cmd /C del /f /q /s # Command prompt command to delete files
|
||||||
|
else
|
||||||
|
# Mac, Linux
|
||||||
|
PROG ?= example
|
||||||
|
DELETE = rm -rf
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(RUN) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@
|
||||||
|
|
||||||
|
o1heap/o1heap/o1heap.c: # O(1) Heap sources
|
||||||
|
git clone --depth 1 -b 2.1.0 https://github.com/pavel-kirienko/o1heap.git
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(DELETE) $(PROG) *.o *.obj *.exe *.dSYM
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) 2025 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
#include "o1heap.h"
|
||||||
|
|
||||||
|
#define POOL_SIZE (5 * MG_IO_SIZE)
|
||||||
|
|
||||||
|
O1HeapInstance *s_mem;
|
||||||
|
|
||||||
|
// memory allocation
|
||||||
|
void *mg_calloc(size_t count, size_t size) {
|
||||||
|
size_t bytes = count * size;
|
||||||
|
void *ptr = o1heapAllocate(s_mem, bytes);
|
||||||
|
if (ptr != NULL) memset(ptr, 0, bytes);
|
||||||
|
if (ptr != NULL) MG_DEBUG(("%lu bytes @%p", bytes, ptr));
|
||||||
|
if (ptr == NULL) MG_ERROR(("Failed to allocate %lu bytes", bytes));
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_free(void *ptr) {
|
||||||
|
o1heapFree(s_mem, ptr);
|
||||||
|
if (ptr != NULL) MG_DEBUG(("block @%p", ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP request callback
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (mg_match(hm->uri, mg_str("/hi"), NULL)) {
|
||||||
|
mg_http_reply(c, 200, "Host: foo.com\r\n", "hi\n");
|
||||||
|
} else if (mg_match(hm->uri, mg_str("/echo"), NULL)) {
|
||||||
|
mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.buf);
|
||||||
|
} else if (mg_match(hm->uri, mg_str("/stats"), NULL)) {
|
||||||
|
struct mg_connection *t;
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
mg_http_printf_chunk(c, "ID PROTO TYPE LOCAL REMOTE\n");
|
||||||
|
for (t = c->mgr->conns; t != NULL; t = t->next) {
|
||||||
|
mg_http_printf_chunk(c, "%-3lu %4s %s %M %M\n", t->id,
|
||||||
|
t->is_udp ? "UDP" : "TCP",
|
||||||
|
t->is_listening ? "LISTENING"
|
||||||
|
: t->is_accepted ? "ACCEPTED "
|
||||||
|
: "CONNECTED",
|
||||||
|
mg_print_ip, &t->loc, mg_print_ip, &t->rem);
|
||||||
|
}
|
||||||
|
mg_http_printf_chunk(c, ""); // Don't forget the last empty chunk
|
||||||
|
} else {
|
||||||
|
struct mg_http_serve_opts opts;
|
||||||
|
memset(&opts, 0, sizeof(opts));
|
||||||
|
opts.root_dir = ".";
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
|
||||||
|
void *pool = malloc(POOL_SIZE + O1HEAP_ALIGNMENT);
|
||||||
|
void *aligned = (void *) (((uintptr_t) pool) & ~(O1HEAP_ALIGNMENT - 1));
|
||||||
|
O1HeapDiagnostics d;
|
||||||
|
s_mem = o1heapInit(aligned, POOL_SIZE);
|
||||||
|
d = o1heapGetDiagnostics(s_mem);
|
||||||
|
MG_INFO(
|
||||||
|
("Created aligned %lu-byte pool @%p, out of a %lu-byte allocated system "
|
||||||
|
"memory pool",
|
||||||
|
d.capacity, s_mem, POOL_SIZE));
|
||||||
|
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
||||||
|
mg_http_listen(&mgr, "http://localhost:8000", fn, NULL); // Create listener
|
||||||
|
for (;;) { // Event loop
|
||||||
|
mg_mgr_poll(&mgr, 1000);
|
||||||
|
}
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../../mongoose.c
|
||||||
Loaded 100 of 552 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user