mirror of
https://github.com/Links2004/arduinoWebSockets.git
synced 2025-06-25 15:01:36 +02:00
Compare commits
299 Commits
2.0.2
...
esp32-ssl-
Author | SHA1 | Date | |
---|---|---|---|
f6e730c2b4 | |||
7c3b1b7408 | |||
738e43fda4 | |||
f55bf8d4ed | |||
a484da47ed | |||
4355199120 | |||
0a4fcd44c2 | |||
3a2b757155 | |||
900d81e534 | |||
0ecef8c552 | |||
410489f7c5 | |||
ec22d67c12 | |||
39e6a8e709 | |||
784b7f9cb8 | |||
fd83d6ad45 | |||
0e729cd896 | |||
2f21590e55 | |||
c98baafda7 | |||
983b9801fb | |||
e70262dab9 | |||
4a05eab627 | |||
822618f606 | |||
1b4f186fa6 | |||
c68e015322 | |||
dc30a2b7bf | |||
6bee53a8bd | |||
ebb87cdc8a | |||
e7ab913693 | |||
52547ec47c | |||
74411bf729 | |||
f0cc36dede | |||
074a674833 | |||
8239e1625e | |||
c5900db636 | |||
9470961d85 | |||
04919f848f | |||
25318111a1 | |||
08caf3bfc6 | |||
fb26433e75 | |||
4f52a0f38e | |||
f20fbbfcd9 | |||
28cd929e7e | |||
826c6b423a | |||
7fea0b8bdf | |||
4db14451fb | |||
80bf087cd0 | |||
5caff59f7f | |||
b90fe4c1d7 | |||
a086303c87 | |||
217c7ce4ea | |||
13a304a8c9 | |||
9b873978ba | |||
ca52afeec0 | |||
beba0f88e3 | |||
f2265118b4 | |||
9982818cfa | |||
91b02341ba | |||
a00d3edcb7 | |||
c73c77e988 | |||
e1ddbfe1a5 | |||
f65e8d9062 | |||
508e0fb691 | |||
083683425f | |||
05ec18e49b | |||
e185668a97 | |||
7e34a8b246 | |||
4acc7eff8a | |||
b3c5348e9b | |||
19c39d5ea0 | |||
ebdc8def4a | |||
44fb41e3b7 | |||
cadbd6458f | |||
f244741caa | |||
3f1cedb21c | |||
ba6275e7fe | |||
a71a480676 | |||
1e271b5e12 | |||
0c3b15c5e7 | |||
7a4160814c | |||
784088d9cc | |||
9048ef9ee4 | |||
80b0867786 | |||
b9e1336826 | |||
ac9b2ccdf6 | |||
12684582aa | |||
420cc55960 | |||
64296cced7 | |||
c3f01e43fc | |||
04e4be03fe | |||
ebd7a528ac | |||
516911900b | |||
674a6e98c9 | |||
4ee0ba5630 | |||
370f217a30 | |||
c038f100d6 | |||
0444a78441 | |||
8cc20b6e4b | |||
40152be197 | |||
e2669c1c5e | |||
771831c57e | |||
06a7bb177b | |||
bd158c9c5c | |||
9a803e1fb3 | |||
c64f2b81e5 | |||
4ef8d733dc | |||
7816bb3fa4 | |||
adf2b07f3b | |||
d3fde2ba34 | |||
c164c47f08 | |||
6a76efa791 | |||
5d26a65df4 | |||
007b5ba9a8 | |||
dbca2ab420 | |||
dfa35fa9ae | |||
794163cec9 | |||
294436840c | |||
b1b21d188f | |||
3063ad27ae | |||
e8df841b7f | |||
0aa07421a6 | |||
df3ef524b6 | |||
8ec27b0468 | |||
c361895a4b | |||
31bade1530 | |||
4223a9e41f | |||
72731beb10 | |||
1b6b42b877 | |||
d6dd7be987 | |||
d325bd338e | |||
d693437908 | |||
9b6ce7563a | |||
68800e2e7a | |||
eaef4f0801 | |||
4db22fe5e4 | |||
50e2e366cc | |||
e8249f76e6 | |||
a70d644f5d | |||
a3079f5645 | |||
2626b26315 | |||
38a881a86a | |||
32dd01b91b | |||
db8167f9c7 | |||
388683d4cd | |||
38c401b8af | |||
f7a7ab6ab4 | |||
bdee8b9744 | |||
50903cd410 | |||
f95c014342 | |||
8967356af3 | |||
d2043bf8ef | |||
7ddcdc2bd3 | |||
bde97179bf | |||
9ce044e550 | |||
a796079b0c | |||
e8c0d775fb | |||
5636b02b46 | |||
4b33575af1 | |||
486a612693 | |||
ea8e81c6ce | |||
8a187b523b | |||
ac8d806085 | |||
02e0128802 | |||
01e1fdfb50 | |||
d02932ef21 | |||
5bf8b2407e | |||
50d9a8d6e5 | |||
7443f9b1dc | |||
4b04f6fa53 | |||
a67a8dd0e0 | |||
4759a66a62 | |||
48e690a42a | |||
b059d0711c | |||
a09b8c48ee | |||
94eb4b12e5 | |||
2df62558f1 | |||
86074c90ae | |||
d73e3ecc9c | |||
f62aa6478d | |||
d340c89b09 | |||
05f4cfd7bf | |||
46cff38287 | |||
0b35e32b2a | |||
255f40eaa7 | |||
5e1f9b1c26 | |||
30b6deedd2 | |||
0e6e1c76ee | |||
887683fabb | |||
0b10299549 | |||
1d300084e0 | |||
d9e1e97cf6 | |||
642750e232 | |||
a0c714bf10 | |||
c5461d5779 | |||
b87bce4466 | |||
9608c2d210 | |||
4baf4896cc | |||
4fd2e9d993 | |||
fa580a568f | |||
a93a845780 | |||
83a1539e1e | |||
1bd4638621 | |||
f40a390ab1 | |||
b6c27f74cd | |||
c64a082270 | |||
522a67bc1b | |||
29df9c30f7 | |||
4c1c5378cb | |||
dbabc1025b | |||
1d40160d99 | |||
a388676b40 | |||
8c19d7ba48 | |||
4fc80871a6 | |||
0ca020bbd2 | |||
cc3ce02c67 | |||
96c266101e | |||
64c8908b05 | |||
87c6c80c67 | |||
adb255bda0 | |||
d0ab6c4fd1 | |||
fcb623ce91 | |||
669f0b489e | |||
32cb052f23 | |||
42ab3168c5 | |||
86d2e2400a | |||
ad07f3c665 | |||
a4533a028c | |||
ae3dd103a1 | |||
40f84c19f4 | |||
f68d9d8030 | |||
c911776860 | |||
adb52b11e9 | |||
81e567b248 | |||
1afe317c7d | |||
177ec8239d | |||
e675c7590e | |||
615926ae1e | |||
acd0a603eb | |||
26140be6c9 | |||
3b1dabbe1e | |||
55bc7db7ad | |||
1a6f46c67d | |||
210f2e8fa1 | |||
34a2d282e4 | |||
e93a323e56 | |||
6da0bc97e8 | |||
ae2ba7effe | |||
dc426c9a61 | |||
60e3d1080e | |||
26fc61f7a2 | |||
604a781122 | |||
f52d718cf2 | |||
6757b8b74c | |||
bef2541ede | |||
dac71c4c23 | |||
60903a2fa5 | |||
0aaf50f87f | |||
2add886219 | |||
ab3b5bae46 | |||
45bb7dbe23 | |||
92032289ec | |||
5cd68c5304 | |||
ddaeea0e4b | |||
a097f0defd | |||
689e3ef921 | |||
75133dfa6d | |||
d2719573d4 | |||
0d9aa043f0 | |||
7810d0d0b3 | |||
1defe6d8e1 | |||
d036dcd8e2 | |||
529a86cc26 | |||
958ab08a6b | |||
7361e2b1b6 | |||
1961ddc159 | |||
cdee9fec05 | |||
ab0d8ff526 | |||
b3d4367d10 | |||
ab51930730 | |||
1ed734ec3f | |||
b99bae459d | |||
26130dc874 | |||
815093a123 | |||
7e5c64a573 | |||
97443ae777 | |||
e589b40b25 | |||
eb2351a4fd | |||
bf3cfa6237 | |||
f8a5acc9b7 | |||
8190e8121c | |||
6a914fc5ea | |||
48ee5fc6fb | |||
b1685962c5 | |||
c4e5f5c7e7 | |||
6972f7a84e | |||
93b0b9eeaf | |||
dd14850bb6 | |||
d36f7bb100 | |||
10a8d3ca67 | |||
4f55c36c80 |
63
.clang-format
Normal file
63
.clang-format
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
BasedOnStyle: Google
|
||||||
|
AccessModifierOffset: '-2'
|
||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
AlignConsecutiveAssignments: 'true'
|
||||||
|
AlignConsecutiveDeclarations: 'false'
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignTrailingComments: 'true'
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||||
|
AllowShortBlocksOnASingleLine: 'false'
|
||||||
|
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||||
|
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||||
|
AllowShortIfStatementsOnASingleLine: 'true'
|
||||||
|
AllowShortLoopsOnASingleLine: 'true'
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: 'true'
|
||||||
|
AlwaysBreakTemplateDeclarations: 'false'
|
||||||
|
BinPackParameters: 'true'
|
||||||
|
BreakAfterJavaFieldAnnotations: 'false'
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: 'false'
|
||||||
|
BreakBeforeTernaryOperators: 'false'
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakStringLiterals: 'false'
|
||||||
|
ColumnLimit: '0'
|
||||||
|
CompactNamespaces: 'true'
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||||
|
ConstructorInitializerIndentWidth: '4'
|
||||||
|
ContinuationIndentWidth: '4'
|
||||||
|
Cpp11BracedListStyle: 'false'
|
||||||
|
DerivePointerAlignment: 'false'
|
||||||
|
FixNamespaceComments: 'true'
|
||||||
|
IndentCaseLabels: 'true'
|
||||||
|
IndentWidth: '4'
|
||||||
|
IndentWrappedFunctionNames: 'false'
|
||||||
|
JavaScriptQuotes: Single
|
||||||
|
JavaScriptWrapImports: 'false'
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
||||||
|
MaxEmptyLinesToKeep: '1'
|
||||||
|
NamespaceIndentation: All
|
||||||
|
ObjCBlockIndentWidth: '4'
|
||||||
|
ObjCSpaceAfterProperty: 'false'
|
||||||
|
ObjCSpaceBeforeProtocolList: 'false'
|
||||||
|
PointerAlignment: Middle
|
||||||
|
SortIncludes: 'false'
|
||||||
|
SortUsingDeclarations: 'true'
|
||||||
|
SpaceAfterCStyleCast: 'false'
|
||||||
|
SpaceAfterTemplateKeyword: 'false'
|
||||||
|
SpaceBeforeAssignmentOperators: 'true'
|
||||||
|
SpaceBeforeParens: Never
|
||||||
|
SpaceInEmptyParentheses: 'false'
|
||||||
|
SpacesBeforeTrailingComments: '4'
|
||||||
|
SpacesInAngles: 'false'
|
||||||
|
SpacesInCStyleCastParentheses: 'false'
|
||||||
|
SpacesInContainerLiterals: 'false'
|
||||||
|
SpacesInParentheses: 'false'
|
||||||
|
SpacesInSquareBrackets: 'false'
|
||||||
|
TabWidth: '4'
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
...
|
188
.github/workflows/main.yml
vendored
Normal file
188
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 5'
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
release:
|
||||||
|
types: [ published, created, edited ]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
check_version_files:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: check version
|
||||||
|
run: |
|
||||||
|
$GITHUB_WORKSPACE/travis/version.py --check
|
||||||
|
|
||||||
|
prepare_example_json:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: generate examples
|
||||||
|
id: set-matrix
|
||||||
|
run: |
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
echo -en "::set-output name=matrix::"
|
||||||
|
echo -en "["
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.6.13 esp8266com:esp8266:generic:xtal=80
|
||||||
|
echo -en ","
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.6.13 esp8266com:esp8266:generic:xtal=80,dbg=Serial1
|
||||||
|
echo -en ","
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp8266 esp8266 1.8.13 esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80
|
||||||
|
echo -en ","
|
||||||
|
|
||||||
|
get_sketches_json_matrix arduino $GITHUB_WORKSPACE/examples/esp32 esp32 1.8.13 espressif:esp32:esp32:FlashFreq=80
|
||||||
|
|
||||||
|
echo -en "]"
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
|
|
||||||
|
prepare_ide:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
IDE_VERSION: [1.8.13, 1.6.13]
|
||||||
|
env:
|
||||||
|
IDE_VERSION: ${{ matrix.IDE_VERSION }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get Date
|
||||||
|
id: get-date
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
id: cache_all
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/home/runner/arduino_ide
|
||||||
|
/home/runner/Arduino
|
||||||
|
key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ matrix.IDE_VERSION }}
|
||||||
|
|
||||||
|
- name: download IDE
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz -q
|
||||||
|
tar xf arduino-$IDE_VERSION-linux64.tar.xz
|
||||||
|
mv arduino-$IDE_VERSION $HOME/arduino_ide
|
||||||
|
|
||||||
|
- name: download ArduinoJson
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/Arduino/libraries
|
||||||
|
wget https://github.com/bblanchon/ArduinoJson/archive/6.x.zip -q
|
||||||
|
unzip 6.x.zip
|
||||||
|
mv ArduinoJson-6.x $HOME/Arduino/libraries/ArduinoJson
|
||||||
|
|
||||||
|
- name: download esp8266
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
get_core esp8266
|
||||||
|
|
||||||
|
- name: download esp32
|
||||||
|
if: steps.cache_all.outputs.cache-hit != 'true' && matrix.IDE_VERSION != '1.6.13'
|
||||||
|
run: |
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
get_core esp32
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: [prepare_ide, prepare_example_json]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include: ${{ fromJson(needs.prepare_example_json.outputs.matrix) }}
|
||||||
|
env:
|
||||||
|
CPU: ${{ matrix.cpu }}
|
||||||
|
BOARD: ${{ matrix.board }}
|
||||||
|
IDE_VERSION: ${{ matrix.ideversion }}
|
||||||
|
SKETCH: ${{ matrix.sketch }}
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: install libgtk2.0-0
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y libgtk2.0-0
|
||||||
|
|
||||||
|
- name: Get Date
|
||||||
|
id: get-date
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
id: cache_all
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/home/runner/arduino_ide
|
||||||
|
/home/runner/Arduino
|
||||||
|
key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ matrix.ideversion }}
|
||||||
|
|
||||||
|
- name: install python serial
|
||||||
|
if: matrix.cpu == 'esp32'
|
||||||
|
run: |
|
||||||
|
sudo pip3 install pyserial
|
||||||
|
sudo pip install pyserial
|
||||||
|
# sudo apt install python-is-python3
|
||||||
|
|
||||||
|
- name: start DISPLAY
|
||||||
|
run: |
|
||||||
|
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
|
||||||
|
export DISPLAY=:1.0
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
- name: test IDE
|
||||||
|
run: |
|
||||||
|
export PATH="$HOME/arduino_ide:$PATH"
|
||||||
|
which arduino
|
||||||
|
|
||||||
|
- name: copy code
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/Arduino/libraries/
|
||||||
|
cp -r $GITHUB_WORKSPACE $HOME/Arduino/libraries/arduinoWebSockets
|
||||||
|
|
||||||
|
- name: config IDE
|
||||||
|
run: |
|
||||||
|
export DISPLAY=:1.0
|
||||||
|
export PATH="$HOME/arduino_ide:$PATH"
|
||||||
|
arduino --board $BOARD --save-prefs
|
||||||
|
arduino --get-pref sketchbook.path
|
||||||
|
arduino --pref update.check=false
|
||||||
|
|
||||||
|
- name: build example
|
||||||
|
timeout-minutes: 20
|
||||||
|
run: |
|
||||||
|
export DISPLAY=:1.0
|
||||||
|
export PATH="$HOME/arduino_ide:$PATH"
|
||||||
|
source $GITHUB_WORKSPACE/travis/common.sh
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
build_sketch arduino $SKETCH
|
||||||
|
|
||||||
|
done:
|
||||||
|
needs: [prepare_ide, prepare_example_json, build, check_version_files]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Done
|
||||||
|
run: |
|
||||||
|
echo DONE
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -27,3 +27,11 @@
|
|||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
/tests/webSocketServer/node_modules
|
/tests/webSocketServer/node_modules
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode
|
||||||
|
.cproject
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
45
.travis.yml
Normal file
45
.travis.yml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
sudo: false
|
||||||
|
dist:
|
||||||
|
- xenial
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- xvfb
|
||||||
|
language: bash
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
env:
|
||||||
|
matrix:
|
||||||
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80" IDE_VERSION=1.6.13
|
||||||
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,dbg=Serial1" IDE_VERSION=1.6.13
|
||||||
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.13
|
||||||
|
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.5
|
||||||
|
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.9
|
||||||
|
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.13
|
||||||
|
script:
|
||||||
|
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
|
||||||
|
- export DISPLAY=:1.0
|
||||||
|
- sleep 3
|
||||||
|
- wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz
|
||||||
|
- tar xf arduino-$IDE_VERSION-linux64.tar.xz
|
||||||
|
- mv arduino-$IDE_VERSION $HOME/arduino_ide
|
||||||
|
- export PATH="$HOME/arduino_ide:$PATH"
|
||||||
|
- which arduino
|
||||||
|
- mkdir -p $HOME/Arduino/libraries
|
||||||
|
|
||||||
|
- wget https://github.com/bblanchon/ArduinoJson/archive/6.x.zip
|
||||||
|
- unzip 6.x.zip
|
||||||
|
- mv ArduinoJson-6.x $HOME/Arduino/libraries/ArduinoJson
|
||||||
|
- cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/arduinoWebSockets
|
||||||
|
- source $TRAVIS_BUILD_DIR/travis/common.sh
|
||||||
|
- get_core $CPU
|
||||||
|
- cd $TRAVIS_BUILD_DIR
|
||||||
|
- arduino --board $BOARD --save-prefs
|
||||||
|
- arduino --get-pref sketchbook.path
|
||||||
|
- arduino --pref update.check=false
|
||||||
|
- build_sketches arduino $HOME/Arduino/libraries/arduinoWebSockets/examples/$CPU $CPU
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
on_success: change
|
||||||
|
on_failure: change
|
77
README.md
77
README.md
@ -1,54 +1,95 @@
|
|||||||
WebSocket Server and Client for Arduino
|
WebSocket Server and Client for Arduino [](https://github.com/Links2004/arduinoWebSockets/actions?query=workflow%3ACI+branch%3Amaster)
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
a WebSocket Server and Client for Arduino based on RFC6455.
|
a WebSocket Server and Client for Arduino based on RFC6455.
|
||||||
|
|
||||||
|
|
||||||
##### Supported features of RFC6455 #####
|
##### Supported features of RFC6455 #####
|
||||||
- text frame
|
- text frame
|
||||||
- binary frame
|
- binary frame
|
||||||
- connection close
|
- connection close
|
||||||
- ping
|
- ping
|
||||||
- pong
|
- pong
|
||||||
|
|
||||||
##### Not supported features of RFC6455 #####
|
|
||||||
- continuation frame
|
- continuation frame
|
||||||
|
|
||||||
##### Limitations #####
|
##### Limitations #####
|
||||||
- max input length is limited to the ram size and the ```WEBSOCKETS_MAX_DATA_SIZE``` define
|
- max input length is limited to the ram size and the ```WEBSOCKETS_MAX_DATA_SIZE``` define
|
||||||
- max output length has no limit (the hardware is the limit)
|
- max output length has no limit (the hardware is the limit)
|
||||||
- Client send big frames with mask 0x00000000 (on AVR all frames)
|
- Client send big frames with mask 0x00000000 (on AVR all frames)
|
||||||
|
- continuation frame reassembly need to be handled in the application code
|
||||||
|
|
||||||
##### Limitations for Async #####
|
##### Limitations for Async #####
|
||||||
- Functions called from within the context of the websocket event might not honor `yield()` and/or `delay()`. See [this issue](https://github.com/Links2004/arduinoWebSockets/issues/58#issuecomment-192376395) for more info and a potential workaround.
|
- Functions called from within the context of the websocket event might not honor `yield()` and/or `delay()`. See [this issue](https://github.com/Links2004/arduinoWebSockets/issues/58#issuecomment-192376395) for more info and a potential workaround.
|
||||||
- wss / SSL is not possible.
|
- wss / SSL is not possible.
|
||||||
|
|
||||||
##### Supported Hardware #####
|
##### Supported Hardware #####
|
||||||
- ESP8266 [Arduino for ESP8266](https://github.com/Links2004/Arduino)
|
- ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/)
|
||||||
|
- ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32)
|
||||||
- ESP31B
|
- ESP31B
|
||||||
- ATmega328 with Ethernet Shield (ATmega branch)
|
- Particle with STM32 ARM Cortex M3
|
||||||
- ATmega328 with enc28j60 (ATmega branch)
|
- ATmega328 with Ethernet Shield (ATmega branch)
|
||||||
- ATmega2560 with Ethernet Shield (ATmega branch)
|
- ATmega328 with enc28j60 (ATmega branch)
|
||||||
- ATmega2560 with enc28j60 (ATmega branch)
|
- ATmega2560 with Ethernet Shield (ATmega branch)
|
||||||
|
- ATmega2560 with enc28j60 (ATmega branch)
|
||||||
|
|
||||||
###### Note: ######
|
###### Note: ######
|
||||||
|
|
||||||
version 2.0 and up is not compatible with AVR/ATmega, check ATmega branch.
|
version 2.0.0 and up is not compatible with AVR/ATmega, check ATmega branch.
|
||||||
|
|
||||||
|
version 2.3.0 has API changes for the ESP8266 BareSSL (may brakes existing code)
|
||||||
|
|
||||||
Arduino for AVR not supports std namespace of c++.
|
Arduino for AVR not supports std namespace of c++.
|
||||||
|
|
||||||
### wss / SSL ###
|
### wss / SSL ###
|
||||||
supported for:
|
supported for:
|
||||||
- wss client on the ESP8266
|
- wss client on the ESP8266
|
||||||
|
- wss / SSL is not natively supported in WebSocketsServer however it is possible to achieve secure websockets
|
||||||
|
by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a
|
||||||
|
sample Nginx server configuration file to enable this.
|
||||||
|
|
||||||
### ESP Async TCP ###
|
### ESP Async TCP ###
|
||||||
|
|
||||||
This libary can run in Async TCP mode on the ESP.
|
This libary can run in Async TCP mode on the ESP.
|
||||||
|
|
||||||
The mode can be aktivated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE define).
|
The mode can be activated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE define).
|
||||||
|
|
||||||
[ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) libary is required.
|
[ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) libary is required.
|
||||||
|
|
||||||
|
|
||||||
|
### High Level Client API ###
|
||||||
|
|
||||||
|
- `begin` : Initiate connection sequence to the websocket host.
|
||||||
|
```c++
|
||||||
|
void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
||||||
|
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
|
||||||
|
```
|
||||||
|
- `onEvent`: Callback to handle for websocket events
|
||||||
|
|
||||||
|
```c++
|
||||||
|
void onEvent(WebSocketClientEvent cbEvent);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `WebSocketClientEvent`: Handler for websocket events
|
||||||
|
```c++
|
||||||
|
void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length)
|
||||||
|
```
|
||||||
|
Where `WStype_t type` is defined as:
|
||||||
|
```c++
|
||||||
|
typedef enum {
|
||||||
|
WStype_ERROR,
|
||||||
|
WStype_DISCONNECTED,
|
||||||
|
WStype_CONNECTED,
|
||||||
|
WStype_TEXT,
|
||||||
|
WStype_BIN,
|
||||||
|
WStype_FRAGMENT_TEXT_START,
|
||||||
|
WStype_FRAGMENT_BIN_START,
|
||||||
|
WStype_FRAGMENT,
|
||||||
|
WStype_FRAGMENT_FIN,
|
||||||
|
WStype_PING,
|
||||||
|
WStype_PONG,
|
||||||
|
} WStype_t;
|
||||||
|
```
|
||||||
|
|
||||||
### Issues ###
|
### Issues ###
|
||||||
Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues
|
Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues
|
||||||
|
|
||||||
|
83
examples/Nginx/esp8266.ssl.reverse.proxy.conf
Normal file
83
examples/Nginx/esp8266.ssl.reverse.proxy.conf
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# ESP8266 nginx SSL reverse proxy configuration file (tested and working on nginx v1.10.0)
|
||||||
|
|
||||||
|
# proxy cache location
|
||||||
|
proxy_cache_path /opt/etc/nginx/cache levels=1:2 keys_zone=ESP8266_cache:10m max_size=10g inactive=5m use_temp_path=off;
|
||||||
|
|
||||||
|
# webserver proxy
|
||||||
|
server {
|
||||||
|
|
||||||
|
# general server parameters
|
||||||
|
listen 50080;
|
||||||
|
server_name myDomain.net;
|
||||||
|
access_log /opt/var/log/nginx/myDomain.net.access.log;
|
||||||
|
|
||||||
|
# SSL configuration
|
||||||
|
ssl on;
|
||||||
|
ssl_certificate /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/fullchain.pem;
|
||||||
|
ssl_certificate_key /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/privkey.pem;
|
||||||
|
ssl_session_cache builtin:1000 shared:SSL:10m;
|
||||||
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
|
||||||
|
# proxy caching configuration
|
||||||
|
proxy_cache ESP8266_cache;
|
||||||
|
proxy_cache_revalidate on;
|
||||||
|
proxy_cache_min_uses 1;
|
||||||
|
proxy_cache_use_stale off;
|
||||||
|
proxy_cache_lock on;
|
||||||
|
# proxy_cache_bypass $http_cache_control;
|
||||||
|
# include the sessionId cookie value as part of the cache key - keeps the cache per user
|
||||||
|
# proxy_cache_key $proxy_host$request_uri$cookie_sessionId;
|
||||||
|
|
||||||
|
# header pass through configuration
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# ESP8266 custom headers which identify to the device that it's running through an SSL proxy
|
||||||
|
proxy_set_header X-SSL On;
|
||||||
|
proxy_set_header X-SSL-WebserverPort 50080;
|
||||||
|
proxy_set_header X-SSL-WebsocketPort 50081;
|
||||||
|
|
||||||
|
# extra debug headers
|
||||||
|
add_header X-Proxy-Cache $upstream_cache_status;
|
||||||
|
add_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
# actual proxying configuration
|
||||||
|
proxy_ssl_session_reuse on;
|
||||||
|
# target the IP address of the device with proxy_pass
|
||||||
|
proxy_pass http://192.168.0.20;
|
||||||
|
proxy_read_timeout 90;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# websocket proxy
|
||||||
|
server {
|
||||||
|
|
||||||
|
# general server parameters
|
||||||
|
listen 50081;
|
||||||
|
server_name myDomain.net;
|
||||||
|
access_log /opt/var/log/nginx/myDomain.net.wss.access.log;
|
||||||
|
|
||||||
|
# SSL configuration
|
||||||
|
ssl on;
|
||||||
|
ssl_certificate /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/fullchain.pem;
|
||||||
|
ssl_certificate_key /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/privkey.pem;
|
||||||
|
ssl_session_cache builtin:1000 shared:SSL:10m;
|
||||||
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
|
||||||
|
# websocket upgrade tunnel configuration
|
||||||
|
proxy_pass http://192.168.0.20:81;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "Upgrade";
|
||||||
|
proxy_read_timeout 86400;
|
||||||
|
}
|
||||||
|
}
|
110
examples/esp32/WebSocketClient/WebSocketClient.ino
Normal file
110
examples/esp32/WebSocketClient/WebSocketClient.ino
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClient.ino
|
||||||
|
*
|
||||||
|
* Created on: 24.05.2015
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
|
||||||
|
WiFiMulti WiFiMulti;
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
|
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||||
|
const uint8_t* src = (const uint8_t*) mem;
|
||||||
|
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||||
|
for(uint32_t i = 0; i < len; i++) {
|
||||||
|
if(i % cols == 0) {
|
||||||
|
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("%02X ", *src);
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
webSocket.begin("192.168.0.123", 81, "/");
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// use HTTP Basic Authorization this is optional remove if not needed
|
||||||
|
webSocket.setAuthorization("user", "Password");
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -1,26 +1,40 @@
|
|||||||
/*
|
/*
|
||||||
* WebSocketClient.ino
|
* WebSocketClientSSL.ino
|
||||||
*
|
*
|
||||||
* Created on: 24.05.2015
|
* Created on: 10.12.2015
|
||||||
|
*
|
||||||
|
* note SSL is only possible with the ESP8266
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <ESP8266WiFiMulti.h>
|
#include <WiFiMulti.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
|
||||||
#include <WebSocketsClient.h>
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
#include <Hash.h>
|
|
||||||
|
|
||||||
ESP8266WiFiMulti WiFiMulti;
|
WiFiMulti WiFiMulti;
|
||||||
WebSocketsClient webSocket;
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
|
||||||
#define USE_SERIAL Serial1
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) {
|
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||||
|
const uint8_t* src = (const uint8_t*) mem;
|
||||||
|
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||||
|
for(uint32_t i = 0; i < len; i++) {
|
||||||
|
if(i % cols == 0) {
|
||||||
|
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("%02X ", *src);
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -30,7 +44,7 @@ void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) {
|
|||||||
case WStype_CONNECTED:
|
case WStype_CONNECTED:
|
||||||
{
|
{
|
||||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
// send message to server when Connected
|
// send message to server when Connected
|
||||||
webSocket.sendTXT("Connected");
|
webSocket.sendTXT("Connected");
|
||||||
}
|
}
|
||||||
@ -42,12 +56,18 @@ void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) {
|
|||||||
// webSocket.sendTXT("message here");
|
// webSocket.sendTXT("message here");
|
||||||
break;
|
break;
|
||||||
case WStype_BIN:
|
case WStype_BIN:
|
||||||
USE_SERIAL.printf("[WSc] get binary lenght: %u\n", lenght);
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
hexdump(payload, lenght);
|
hexdump(payload, length);
|
||||||
|
|
||||||
// send data to server
|
// send data to server
|
||||||
// webSocket.sendBIN(payload, lenght);
|
// webSocket.sendBIN(payload, length);
|
||||||
break;
|
break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -76,8 +96,7 @@ void setup() {
|
|||||||
delay(100);
|
delay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
webSocket.begin("192.168.0.123", 81);
|
webSocket.beginSSL("192.168.0.123", 81);
|
||||||
//webSocket.setAuthorization("user", "Password"); // HTTP Basic Authorization
|
|
||||||
webSocket.onEvent(webSocketEvent);
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
}
|
}
|
104
examples/esp32/WebSocketServer/WebSocketServer.ino
Normal file
104
examples/esp32/WebSocketServer/WebSocketServer.ino
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketServer.ino
|
||||||
|
*
|
||||||
|
* Created on: 22.05.2015
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
|
||||||
|
#include <WebSocketsServer.h>
|
||||||
|
|
||||||
|
WiFiMulti WiFiMulti;
|
||||||
|
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
|
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||||
|
const uint8_t* src = (const uint8_t*) mem;
|
||||||
|
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||||
|
for(uint32_t i = 0; i < len; i++) {
|
||||||
|
if(i % cols == 0) {
|
||||||
|
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("%02X ", *src);
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
USE_SERIAL.printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
{
|
||||||
|
IPAddress ip = webSocket.remoteIP(num);
|
||||||
|
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
webSocket.sendTXT(num, "Connected");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
// webSocket.sendTXT(num, "message here");
|
||||||
|
|
||||||
|
// send data to all connected clients
|
||||||
|
// webSocket.broadcastTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
// webSocket.sendBIN(num, payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
webSocket.begin();
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
106
examples/esp8266/WebSocketClient/WebSocketClient.ino
Normal file
106
examples/esp8266/WebSocketClient/WebSocketClient.ino
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClient.ino
|
||||||
|
*
|
||||||
|
* Created on: 24.05.2015
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED: {
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
case WStype_PING:
|
||||||
|
// pong will be send automatically
|
||||||
|
USE_SERIAL.printf("[WSc] get ping\n");
|
||||||
|
break;
|
||||||
|
case WStype_PONG:
|
||||||
|
// answer to a ping we send
|
||||||
|
USE_SERIAL.printf("[WSc] get pong\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
webSocket.begin("192.168.0.123", 81, "/");
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
// use HTTP Basic Authorization this is optional remove if not needed
|
||||||
|
webSocket.setAuthorization("user", "Password");
|
||||||
|
|
||||||
|
// try ever 5000 again if connection has failed
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
|
||||||
|
// start heartbeat (optional)
|
||||||
|
// ping server every 15000 ms
|
||||||
|
// expect pong from server within 3000 ms
|
||||||
|
// consider connection disconnected if pong is not received 2 times
|
||||||
|
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClientSSLWithCA.ino
|
||||||
|
*
|
||||||
|
* Created on: 27.10.2019
|
||||||
|
*
|
||||||
|
* note SSL is only possible with the ESP8266
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
|
|
||||||
|
// Can be obtained with:
|
||||||
|
// openssl s_client -showcerts -connect echo.websocket.org:443 </dev/null
|
||||||
|
const char ENDPOINT_CA_CERT[] PROGMEM = R"EOF(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||||
|
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0NlowSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
|
||||||
|
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
|
||||||
|
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
|
||||||
|
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWAa6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
|
||||||
|
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
|
||||||
|
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNvbTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
|
||||||
|
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAwVAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
|
||||||
|
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
|
||||||
|
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsFAAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
|
||||||
|
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
|
||||||
|
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlGPfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
|
||||||
|
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)EOF";
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
{
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server when Connected
|
||||||
|
webSocket.sendTXT("Connected");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
//When using BearSSL, client certificate and private key can be set:
|
||||||
|
//webSocket.setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||||
|
//clientCert and clientPrivateKey can be of types (const char *, const char *) , or of types (BearSSL::X509List, BearSSL::PrivateKey)
|
||||||
|
|
||||||
|
webSocket.beginSslWithCA("echo.websocket.org", 443, "/", ENDPOINT_CA_CERT);
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClientSocketIO.ino
|
||||||
|
*
|
||||||
|
* Created on: 06.06.2016
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
#include <SocketIOclient.h>
|
||||||
|
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
SocketIOclient socketIO;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
|
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case sIOtype_DISCONNECT:
|
||||||
|
USE_SERIAL.printf("[IOc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case sIOtype_CONNECT:
|
||||||
|
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// join default namespace (no auto join in Socket.IO V3)
|
||||||
|
socketIO.send(sIOtype_CONNECT, "/");
|
||||||
|
break;
|
||||||
|
case sIOtype_EVENT:
|
||||||
|
USE_SERIAL.printf("[IOc] get event: %s\n", payload);
|
||||||
|
break;
|
||||||
|
case sIOtype_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_ERROR:
|
||||||
|
USE_SERIAL.printf("[IOc] get error: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_EVENT:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable AP
|
||||||
|
if(WiFi.getMode() & WIFI_AP) {
|
||||||
|
WiFi.softAPdisconnect(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ip = WiFi.localIP().toString();
|
||||||
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
socketIO.begin("10.11.100.100", 8880);
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
socketIO.onEvent(socketIOEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long messageTimestamp = 0;
|
||||||
|
void loop() {
|
||||||
|
socketIO.loop();
|
||||||
|
|
||||||
|
uint64_t now = millis();
|
||||||
|
|
||||||
|
if(now - messageTimestamp > 2000) {
|
||||||
|
messageTimestamp = now;
|
||||||
|
|
||||||
|
// creat JSON message for Socket.IO (event)
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
JsonArray array = doc.to<JsonArray>();
|
||||||
|
|
||||||
|
// add evnet name
|
||||||
|
// Hint: socket.on('event_name', ....
|
||||||
|
array.add("event_name");
|
||||||
|
|
||||||
|
// add payload (parameters) for the event
|
||||||
|
JsonObject param1 = array.createNestedObject();
|
||||||
|
param1["now"] = (uint32_t) now;
|
||||||
|
|
||||||
|
// JSON to String (serializion)
|
||||||
|
String output;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
|
||||||
|
// Send event
|
||||||
|
socketIO.sendEVENT(output);
|
||||||
|
|
||||||
|
// Print JSON for debugging
|
||||||
|
USE_SERIAL.println(output);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketClientSocketIOack.ino
|
||||||
|
*
|
||||||
|
* Created on: 20.07.2019
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
#include <SocketIOclient.h>
|
||||||
|
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
SocketIOclient socketIO;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
|
||||||
|
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case sIOtype_DISCONNECT:
|
||||||
|
USE_SERIAL.printf("[IOc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case sIOtype_CONNECT:
|
||||||
|
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
// join default namespace (no auto join in Socket.IO V3)
|
||||||
|
socketIO.send(sIOtype_CONNECT, "/");
|
||||||
|
break;
|
||||||
|
case sIOtype_EVENT:
|
||||||
|
{
|
||||||
|
char * sptr = NULL;
|
||||||
|
int id = strtol((char *)payload, &sptr, 10);
|
||||||
|
USE_SERIAL.printf("[IOc] get event: %s id: %d\n", payload, id);
|
||||||
|
if(id) {
|
||||||
|
payload = (uint8_t *)sptr;
|
||||||
|
}
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
DeserializationError error = deserializeJson(doc, payload, length);
|
||||||
|
if(error) {
|
||||||
|
USE_SERIAL.print(F("deserializeJson() failed: "));
|
||||||
|
USE_SERIAL.println(error.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String eventName = doc[0];
|
||||||
|
USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str());
|
||||||
|
|
||||||
|
// Message Includes a ID for a ACK (callback)
|
||||||
|
if(id) {
|
||||||
|
// creat JSON message for Socket.IO (ack)
|
||||||
|
DynamicJsonDocument docOut(1024);
|
||||||
|
JsonArray array = docOut.to<JsonArray>();
|
||||||
|
|
||||||
|
// add payload (parameters) for the ack (callback function)
|
||||||
|
JsonObject param1 = array.createNestedObject();
|
||||||
|
param1["now"] = millis();
|
||||||
|
|
||||||
|
// JSON to String (serializion)
|
||||||
|
String output;
|
||||||
|
output += id;
|
||||||
|
serializeJson(docOut, output);
|
||||||
|
|
||||||
|
// Send event
|
||||||
|
socketIO.send(sIOtype_ACK, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case sIOtype_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_ERROR:
|
||||||
|
USE_SERIAL.printf("[IOc] get error: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_EVENT:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
//USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable AP
|
||||||
|
if(WiFi.getMode() & WIFI_AP) {
|
||||||
|
WiFi.softAPdisconnect(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
//WiFi.disconnect();
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ip = WiFi.localIP().toString();
|
||||||
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
socketIO.begin("10.11.100.100", 8880);
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
socketIO.onEvent(socketIOEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long messageTimestamp = 0;
|
||||||
|
void loop() {
|
||||||
|
socketIO.loop();
|
||||||
|
|
||||||
|
uint64_t now = millis();
|
||||||
|
|
||||||
|
if(now - messageTimestamp > 2000) {
|
||||||
|
messageTimestamp = now;
|
||||||
|
|
||||||
|
// creat JSON message for Socket.IO (event)
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
JsonArray array = doc.to<JsonArray>();
|
||||||
|
|
||||||
|
// add evnet name
|
||||||
|
// Hint: socket.on('event_name', ....
|
||||||
|
array.add("event_name");
|
||||||
|
|
||||||
|
// add payload (parameters) for the event
|
||||||
|
JsonObject param1 = array.createNestedObject();
|
||||||
|
param1["now"] = (uint32_t) now;
|
||||||
|
|
||||||
|
// JSON to String (serializion)
|
||||||
|
String output;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
|
||||||
|
// Send event
|
||||||
|
socketIO.sendEVENT(output);
|
||||||
|
|
||||||
|
// Print JSON for debugging
|
||||||
|
USE_SERIAL.println(output);
|
||||||
|
}
|
||||||
|
}
|
149
examples/esp8266/WebSocketClientStomp/WebSocketClientStomp.ino
Normal file
149
examples/esp8266/WebSocketClientStomp/WebSocketClientStomp.ino
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
WebSocketClientStomp.ino
|
||||||
|
|
||||||
|
Example for connecting and maintining a connection with a STOMP websocket connection.
|
||||||
|
In this example, we connect to a Spring application (see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html).
|
||||||
|
|
||||||
|
Created on: 25.09.2017
|
||||||
|
Author: Martin Becker <mgbckr>, Contact: becker@informatik.uni-wuerzburg.de
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PRE
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
|
||||||
|
// LIBRARIES
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
|
||||||
|
// SETTINGS
|
||||||
|
|
||||||
|
const char* wlan_ssid = "yourssid";
|
||||||
|
const char* wlan_password = "somepassword";
|
||||||
|
|
||||||
|
const char* ws_host = "the.host.net";
|
||||||
|
const int ws_port = 80;
|
||||||
|
|
||||||
|
// URL for STOMP endpoint.
|
||||||
|
// For the default config of Spring's STOMP support, the default URL is "/socketentry/websocket".
|
||||||
|
const char* stompUrl = "/socketentry/websocket"; // don't forget the leading "/" !!!
|
||||||
|
|
||||||
|
|
||||||
|
// VARIABLES
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
|
||||||
|
// FUNCTIONS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STOMP messages need to be NULL-terminated (i.e., \0 or \u0000).
|
||||||
|
* However, when we send a String or a char[] array without specifying
|
||||||
|
* a length, the size of the message payload is derived by strlen() internally,
|
||||||
|
* thus dropping any NULL values appended to the "msg"-String.
|
||||||
|
*
|
||||||
|
* To solve this, we first convert the String to a NULL terminated char[] array
|
||||||
|
* via "c_str" and set the length of the payload to include the NULL value.
|
||||||
|
*/
|
||||||
|
void sendMessage(String & msg) {
|
||||||
|
webSocket.sendTXT(msg.c_str(), msg.length() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
{
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
|
||||||
|
String msg = "CONNECT\r\naccept-version:1.1,1.0\r\nheart-beat:10000,10000\r\n\r\n";
|
||||||
|
sendMessage(msg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
{
|
||||||
|
// #####################
|
||||||
|
// handle STOMP protocol
|
||||||
|
// #####################
|
||||||
|
|
||||||
|
String text = (char*) payload;
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
if (text.startsWith("CONNECTED")) {
|
||||||
|
|
||||||
|
// subscribe to some channels
|
||||||
|
|
||||||
|
String msg = "SUBSCRIBE\nid:sub-0\ndestination:/user/queue/messages\n\n";
|
||||||
|
sendMessage(msg);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// and send a message
|
||||||
|
|
||||||
|
msg = "SEND\ndestination:/app/message\n\n{\"user\":\"esp\",\"message\":\"Hello!\"}";
|
||||||
|
sendMessage(msg);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// do something with messages
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
// setup serial
|
||||||
|
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
// USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
|
||||||
|
// connect to WiFi
|
||||||
|
|
||||||
|
USE_SERIAL.print("Logging into WLAN: "); Serial.print(wlan_ssid); Serial.print(" ...");
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(wlan_ssid, wlan_password);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
USE_SERIAL.print(".");
|
||||||
|
}
|
||||||
|
USE_SERIAL.println(" success.");
|
||||||
|
USE_SERIAL.print("IP: "); USE_SERIAL.println(WiFi.localIP());
|
||||||
|
|
||||||
|
|
||||||
|
// connect to websocket
|
||||||
|
webSocket.begin(ws_host, ws_port, stompUrl);
|
||||||
|
webSocket.setExtraHeaders(); // remove "Origin: file://" header because it breaks the connection with Spring's default websocket config
|
||||||
|
// webSocket.setExtraHeaders("foo: I am so funny\r\nbar: not"); // some headers, in case you feel funny
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
WebSocketClientStompOverSockJs.ino
|
||||||
|
|
||||||
|
Example for connecting and maintining a connection with a SockJS+STOMP websocket connection.
|
||||||
|
In this example, we connect to a Spring application (see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html).
|
||||||
|
|
||||||
|
Created on: 18.07.2017
|
||||||
|
Author: Martin Becker <mgbckr>, Contact: becker@informatik.uni-wuerzburg.de
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PRE
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
|
||||||
|
// LIBRARIES
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
|
||||||
|
|
||||||
|
// SETTINGS
|
||||||
|
|
||||||
|
const char* wlan_ssid = "yourssid";
|
||||||
|
const char* wlan_password = "somepassword";
|
||||||
|
|
||||||
|
const char* ws_host = "the.host.net";
|
||||||
|
const int ws_port = 80;
|
||||||
|
|
||||||
|
// base URL for SockJS (websocket) connection
|
||||||
|
// The complete URL will look something like this(cf. http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-36):
|
||||||
|
// ws://<ws_host>:<ws_port>/<ws_baseurl>/<3digits>/<randomstring>/websocket
|
||||||
|
// For the default config of Spring's SockJS/STOMP support, the default base URL is "/socketentry/".
|
||||||
|
const char* ws_baseurl = "/socketentry/"; // don't forget leading and trailing "/" !!!
|
||||||
|
|
||||||
|
|
||||||
|
// VARIABLES
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
|
||||||
|
// FUNCTIONS
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
{
|
||||||
|
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
{
|
||||||
|
// #####################
|
||||||
|
// handle SockJs+STOMP protocol
|
||||||
|
// #####################
|
||||||
|
|
||||||
|
String text = (char*) payload;
|
||||||
|
|
||||||
|
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
if (payload[0] == 'h') {
|
||||||
|
|
||||||
|
USE_SERIAL.println("Heartbeat!");
|
||||||
|
|
||||||
|
} else if (payload[0] == 'o') {
|
||||||
|
|
||||||
|
// on open connection
|
||||||
|
char *msg = "[\"CONNECT\\naccept-version:1.1,1.0\\nheart-beat:10000,10000\\n\\n\\u0000\"]";
|
||||||
|
webSocket.sendTXT(msg);
|
||||||
|
|
||||||
|
} else if (text.startsWith("a[\"CONNECTED")) {
|
||||||
|
|
||||||
|
// subscribe to some channels
|
||||||
|
|
||||||
|
char *msg = "[\"SUBSCRIBE\\nid:sub-0\\ndestination:/user/queue/messages\\n\\n\\u0000\"]";
|
||||||
|
webSocket.sendTXT(msg);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// and send a message
|
||||||
|
|
||||||
|
msg = "[\"SEND\\ndestination:/app/message\\n\\n{\\\"user\\\":\\\"esp\\\",\\\"message\\\":\\\"Hello!\\\"}\\u0000\"]";
|
||||||
|
webSocket.sendTXT(msg);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send data to server
|
||||||
|
// webSocket.sendBIN(payload, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
// setup serial
|
||||||
|
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
// USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
|
||||||
|
// connect to WiFi
|
||||||
|
|
||||||
|
USE_SERIAL.print("Logging into WLAN: "); Serial.print(wlan_ssid); Serial.print(" ...");
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(wlan_ssid, wlan_password);
|
||||||
|
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
USE_SERIAL.print(".");
|
||||||
|
}
|
||||||
|
USE_SERIAL.println(" success.");
|
||||||
|
USE_SERIAL.print("IP: "); USE_SERIAL.println(WiFi.localIP());
|
||||||
|
|
||||||
|
|
||||||
|
// #####################
|
||||||
|
// create socket url according to SockJS protocol (cf. http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-36)
|
||||||
|
// #####################
|
||||||
|
String socketUrl = ws_baseurl;
|
||||||
|
socketUrl += random(0, 999);
|
||||||
|
socketUrl += "/";
|
||||||
|
socketUrl += random(0, 999999); // should be a random string, but this works (see )
|
||||||
|
socketUrl += "/websocket";
|
||||||
|
|
||||||
|
// connect to websocket
|
||||||
|
webSocket.begin(ws_host, ws_port, socketUrl);
|
||||||
|
webSocket.setExtraHeaders(); // remove "Origin: file://" header because it breaks the connection with Spring's default websocket config
|
||||||
|
// webSocket.setExtraHeaders("foo: I am so funny\r\nbar: not"); // some headers, in case you feel funny
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
@ -18,7 +18,7 @@ WebSocketsServer webSocket = WebSocketsServer(81);
|
|||||||
|
|
||||||
#define USE_SERIAL Serial1
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case WStype_DISCONNECTED:
|
case WStype_DISCONNECTED:
|
||||||
@ -43,11 +43,11 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
|
|||||||
// webSocket.broadcastTXT("message here");
|
// webSocket.broadcastTXT("message here");
|
||||||
break;
|
break;
|
||||||
case WStype_BIN:
|
case WStype_BIN:
|
||||||
USE_SERIAL.printf("[%u] get binary lenght: %u\n", num, lenght);
|
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||||
hexdump(payload, lenght);
|
hexdump(payload, length);
|
||||||
|
|
||||||
// send message to client
|
// send message to client
|
||||||
// webSocket.sendBIN(num, payload, lenght);
|
// webSocket.sendBIN(num, payload, length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketServerAllFunctionsDemo.ino
|
||||||
|
*
|
||||||
|
* Created on: 10.05.2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
#include <WebSocketsServer.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
#define LED_RED 15
|
||||||
|
#define LED_GREEN 12
|
||||||
|
#define LED_BLUE 13
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
|
||||||
|
ESP8266WebServer server(80);
|
||||||
|
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||||
|
|
||||||
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED: {
|
||||||
|
IPAddress ip = webSocket.remoteIP(num);
|
||||||
|
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
webSocket.sendTXT(num, "Connected");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||||
|
|
||||||
|
if(payload[0] == '#') {
|
||||||
|
// we get RGB data
|
||||||
|
|
||||||
|
// decode rgb data
|
||||||
|
uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);
|
||||||
|
|
||||||
|
analogWrite(LED_RED, ((rgb >> 16) & 0xFF));
|
||||||
|
analogWrite(LED_GREEN, ((rgb >> 8) & 0xFF));
|
||||||
|
analogWrite(LED_BLUE, ((rgb >> 0) & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
//USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
pinMode(LED_RED, OUTPUT);
|
||||||
|
pinMode(LED_GREEN, OUTPUT);
|
||||||
|
pinMode(LED_BLUE, OUTPUT);
|
||||||
|
|
||||||
|
digitalWrite(LED_RED, 1);
|
||||||
|
digitalWrite(LED_GREEN, 1);
|
||||||
|
digitalWrite(LED_BLUE, 1);
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start webSocket server
|
||||||
|
webSocket.begin();
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
|
if(MDNS.begin("esp8266")) {
|
||||||
|
USE_SERIAL.println("MDNS responder started");
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle index
|
||||||
|
server.on("/", []() {
|
||||||
|
// send index.html
|
||||||
|
server.send(200, "text/html", "<html><head><script>var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);connection.onopen = function () { connection.send('Connect ' + new Date()); }; connection.onerror = function (error) { console.log('WebSocket Error ', error);};connection.onmessage = function (e) { console.log('Server: ', e.data);};function sendRGB() { var r = parseInt(document.getElementById('r').value).toString(16); var g = parseInt(document.getElementById('g').value).toString(16); var b = parseInt(document.getElementById('b').value).toString(16); if(r.length < 2) { r = '0' + r; } if(g.length < 2) { g = '0' + g; } if(b.length < 2) { b = '0' + b; } var rgb = '#'+r+g+b; console.log('RGB: ' + rgb); connection.send(rgb); }</script></head><body>LED Control:<br/><br/>R: <input id=\"r\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/>G: <input id=\"g\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/>B: <input id=\"b\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/></body></html>");
|
||||||
|
});
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
|
||||||
|
// Add service to MDNS
|
||||||
|
MDNS.addService("http", "tcp", 80);
|
||||||
|
MDNS.addService("ws", "tcp", 81);
|
||||||
|
|
||||||
|
digitalWrite(LED_RED, 0);
|
||||||
|
digitalWrite(LED_GREEN, 0);
|
||||||
|
digitalWrite(LED_BLUE, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long last_10sec = 0;
|
||||||
|
unsigned int counter = 0;
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
unsigned long t = millis();
|
||||||
|
webSocket.loop();
|
||||||
|
server.handleClient();
|
||||||
|
|
||||||
|
if((t - last_10sec) > 10 * 1000) {
|
||||||
|
counter++;
|
||||||
|
bool ping = (counter % 2);
|
||||||
|
int i = webSocket.connectedClients(ping);
|
||||||
|
USE_SERIAL.printf("%d Connected websocket clients ping: %d\n", i, ping);
|
||||||
|
last_10sec = millis();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketServer.ino
|
||||||
|
*
|
||||||
|
* Created on: 22.05.2015
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
#include <WebSocketsServer.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
|
||||||
|
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
String fragmentBuffer = "";
|
||||||
|
|
||||||
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED: {
|
||||||
|
IPAddress ip = webSocket.remoteIP(num);
|
||||||
|
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
webSocket.sendTXT(num, "Connected");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Fragmentation / continuation opcode handling
|
||||||
|
// case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
fragmentBuffer = (char*)payload;
|
||||||
|
USE_SERIAL.printf("[%u] get start start of Textfragment: %s\n", num, payload);
|
||||||
|
break;
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
fragmentBuffer += (char*)payload;
|
||||||
|
USE_SERIAL.printf("[%u] get Textfragment : %s\n", num, payload);
|
||||||
|
break;
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
fragmentBuffer += (char*)payload;
|
||||||
|
USE_SERIAL.printf("[%u] get end of Textfragment: %s\n", num, payload);
|
||||||
|
USE_SERIAL.printf("[%u] full frame: %s\n", num, fragmentBuffer.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
webSocket.begin();
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
||||||
|
|
103
examples/esp8266/WebSocketServerHooked/WebSocketServerHooked.ino
Normal file
103
examples/esp8266/WebSocketServerHooked/WebSocketServerHooked.ino
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketServerHooked.ino
|
||||||
|
*
|
||||||
|
* Created on: 22.05.2015
|
||||||
|
* Hooked on: 28.10.2020
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
#include <WebSockets4WebServer.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
|
||||||
|
ESP8266WebServer server(80);
|
||||||
|
WebSockets4WebServer webSocket;
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial
|
||||||
|
|
||||||
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
USE_SERIAL.printf("[%u] Disconnected!\n", num);
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
{
|
||||||
|
IPAddress ip = webSocket.remoteIP(num);
|
||||||
|
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
webSocket.sendTXT(num, "Connected");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
// webSocket.sendTXT(num, "message here");
|
||||||
|
|
||||||
|
// send data to all connected clients
|
||||||
|
// webSocket.broadcastTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
|
||||||
|
// send message to client
|
||||||
|
// webSocket.sendBIN(num, payload, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
server.on("/", []() {
|
||||||
|
server.send(200, "text/plain", "I am a regular webserver on port 80!\r\n");
|
||||||
|
server.send(200, "text/plain", "I am also a websocket server on '/ws' on the same port 80\r\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
server.addHook(webSocket.hookForWebserver("/ws", webSocketEvent));
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
Serial.println("HTTP server started on port 80");
|
||||||
|
Serial.println("WebSocket server started on the same port");
|
||||||
|
Serial.printf("my network address is either 'arduinoWebsockets.local' (mDNS) or '%s'\n", WiFi.localIP().toString().c_str());
|
||||||
|
|
||||||
|
if (!MDNS.begin("arduinoWebsockets")) {
|
||||||
|
Serial.println("Error setting up MDNS responder!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
server.handleClient();
|
||||||
|
webSocket.loop();
|
||||||
|
MDNS.update();
|
||||||
|
}
|
20
examples/esp8266/WebSocketServerHooked/emu
Executable file
20
examples/esp8266/WebSocketServerHooked/emu
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# linux script to compile&run arduinoWebSockets in a mock environment
|
||||||
|
|
||||||
|
if [ -z "$ESP8266ARDUINO" ]; then
|
||||||
|
echo "please set ESP8266ARDUINO env-var to where esp8266/arduino sits"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
where=$(pwd)
|
||||||
|
|
||||||
|
cd $ESP8266ARDUINO/tests/host/
|
||||||
|
|
||||||
|
make -j FORCE32=0 \
|
||||||
|
ULIBDIRS=../../libraries/Hash/:~/dev/proj/arduino/libraries/arduinoWebSockets \
|
||||||
|
${where}/WebSocketServerHooked
|
||||||
|
|
||||||
|
valgrind ./bin/WebSocketServerHooked/WebSocketServerHooked -b "$@"
|
45
examples/esp8266/WebSocketServerHooked/ws-testclient.py
Executable file
45
examples/esp8266/WebSocketServerHooked/ws-testclient.py
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# python websocket client to test with
|
||||||
|
# emulator: server is at ws://127.0.0.1:9080/ws
|
||||||
|
# esp8266: server is at ws:///ws
|
||||||
|
# (uncomment the right line below)
|
||||||
|
|
||||||
|
#uri = "ws://127.0.0.1:9080/ws"
|
||||||
|
uri = "ws://arduinoWebsockets.local/ws"
|
||||||
|
|
||||||
|
import websocket
|
||||||
|
try:
|
||||||
|
import thread
|
||||||
|
except ImportError:
|
||||||
|
import _thread as thread
|
||||||
|
import time
|
||||||
|
|
||||||
|
def on_message(ws, message):
|
||||||
|
print("message");
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
def on_error(ws, error):
|
||||||
|
print("error")
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
def on_close(ws):
|
||||||
|
print("### closed ###")
|
||||||
|
|
||||||
|
def on_open(ws):
|
||||||
|
print("opened")
|
||||||
|
def run(*args):
|
||||||
|
for i in range(3):
|
||||||
|
time.sleep(1)
|
||||||
|
ws.send("Hello %d" % i)
|
||||||
|
time.sleep(1)
|
||||||
|
ws.close()
|
||||||
|
print("thread terminating...")
|
||||||
|
thread.start_new_thread(run, ())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
websocket.enableTrace(True)
|
||||||
|
ws = websocket.WebSocketApp(uri, on_message = on_message, on_error = on_error, on_close = on_close)
|
||||||
|
ws.on_open = on_open
|
||||||
|
ws.run_forever()
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* WebSocketServerHttpHeaderValidation.ino
|
||||||
|
*
|
||||||
|
* Created on: 08.06.2016
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
#include <WebSocketsServer.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
|
||||||
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
|
||||||
|
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||||
|
|
||||||
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
|
const unsigned long int validSessionId = 12345; //some arbitrary value to act as a valid sessionId
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a bool value as an indicator to describe whether a user is allowed to initiate a websocket upgrade
|
||||||
|
* based on the value of a cookie. This function expects the rawCookieHeaderValue to look like this "sessionId=<someSessionIdNumberValue>|"
|
||||||
|
*/
|
||||||
|
bool isCookieValid(String rawCookieHeaderValue) {
|
||||||
|
|
||||||
|
if (rawCookieHeaderValue.indexOf("sessionId") != -1) {
|
||||||
|
String sessionIdStr = rawCookieHeaderValue.substring(rawCookieHeaderValue.indexOf("sessionId=") + 10, rawCookieHeaderValue.indexOf("|"));
|
||||||
|
unsigned long int sessionId = strtoul(sessionIdStr.c_str(), NULL, 10);
|
||||||
|
return sessionId == validSessionId;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The WebSocketServerHttpHeaderValFunc delegate passed to webSocket.onValidateHttpHeader
|
||||||
|
*/
|
||||||
|
bool validateHttpHeader(String headerName, String headerValue) {
|
||||||
|
|
||||||
|
//assume a true response for any headers not handled by this validator
|
||||||
|
bool valid = true;
|
||||||
|
|
||||||
|
if(headerName.equalsIgnoreCase("Cookie")) {
|
||||||
|
//if the header passed is the Cookie header, validate it according to the rules in 'isCookieValid' function
|
||||||
|
valid = isCookieValid(headerValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// USE_SERIAL.begin(921600);
|
||||||
|
USE_SERIAL.begin(115200);
|
||||||
|
|
||||||
|
//Serial.setDebugOutput(true);
|
||||||
|
USE_SERIAL.setDebugOutput(true);
|
||||||
|
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
USE_SERIAL.println();
|
||||||
|
|
||||||
|
for(uint8_t t = 4; t > 0; t--) {
|
||||||
|
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||||
|
USE_SERIAL.flush();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
|
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
//connecting clients must supply a valid session cookie at websocket upgrade handshake negotiation time
|
||||||
|
const char * headerkeys[] = { "Cookie" };
|
||||||
|
size_t headerKeyCount = sizeof(headerkeys) / sizeof(char*);
|
||||||
|
webSocket.onValidateHttpHeader(validateHttpHeader, headerkeys, headerKeyCount);
|
||||||
|
webSocket.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
||||||
|
|
@ -23,10 +23,10 @@
|
|||||||
|
|
||||||
ESP8266WiFiMulti WiFiMulti;
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
|
|
||||||
ESP8266WebServer server = ESP8266WebServer(80);
|
ESP8266WebServer server(80);
|
||||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||||
|
|
||||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case WStype_DISCONNECTED:
|
case WStype_DISCONNECTED:
|
||||||
@ -100,7 +100,7 @@ void setup() {
|
|||||||
// handle index
|
// handle index
|
||||||
server.on("/", []() {
|
server.on("/", []() {
|
||||||
// send index.html
|
// send index.html
|
||||||
server.send(200, "text/html", "<html><head><script>var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);connection.onopen = function () { connection.send('Connect ' + new Date()); }; connection.onerror = function (error) { console.log('WebSocket Error ', error);};connection.onmessage = function (e) { console.log('Server: ', e.data);};function sendRGB() { var r = parseInt(document.getElementById('r').value).toString(16); var g = parseInt(document.getElementById('g').value).toString(16); var b = parseInt(document.getElementById('b').value).toString(16); if(r.length < 2) { r = '0' + r; } if(g.length < 2) { g = '0' + g; } if(b.length < 2) { b = '0' + b; } var rgb = '#'+r+g+b; console.log('RGB: ' + rgb); connection.send(rgb); }</script></head><body>LED Control:<br/><br/>R: <input id=\"r\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" onchange=\"sendRGB();\" /><br/>G: <input id=\"g\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" onchange=\"sendRGB();\" /><br/>B: <input id=\"b\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" onchange=\"sendRGB();\" /><br/></body></html>");
|
server.send(200, "text/html", "<html><head><script>var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);connection.onopen = function () { connection.send('Connect ' + new Date()); }; connection.onerror = function (error) { console.log('WebSocket Error ', error);};connection.onmessage = function (e) { console.log('Server: ', e.data);};function sendRGB() { var r = parseInt(document.getElementById('r').value).toString(16); var g = parseInt(document.getElementById('g').value).toString(16); var b = parseInt(document.getElementById('b').value).toString(16); if(r.length < 2) { r = '0' + r; } if(g.length < 2) { g = '0' + g; } if(b.length < 2) { b = '0' + b; } var rgb = '#'+r+g+b; console.log('RGB: ' + rgb); connection.send(rgb); }</script></head><body>LED Control:<br/><br/>R: <input id=\"r\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/>G: <input id=\"g\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/>B: <input id=\"b\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\" /><br/></body></html>");
|
||||||
});
|
});
|
||||||
|
|
||||||
server.begin();
|
server.begin();
|
||||||
@ -119,4 +119,3 @@ void loop() {
|
|||||||
webSocket.loop();
|
webSocket.loop();
|
||||||
server.handleClient();
|
server.handleClient();
|
||||||
}
|
}
|
||||||
|
|
46
examples/particle/ParticleWebSocketClient/application.cpp
Normal file
46
examples/particle/ParticleWebSocketClient/application.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* To compile using make CLI, create a folder under \firmware\user\applications and copy application.cpp there.
|
||||||
|
* Then, copy src files under particleWebSocket folder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
#include "particleWebSocket/WebSocketsClient.h"
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
|
||||||
|
void webSocketEvent(WStype_t type, uint8_t* payload, size_t length)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
Serial.printlnf("[WSc] Disconnected!");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
Serial.printlnf("[WSc] Connected to URL: %s", payload);
|
||||||
|
webSocket.sendTXT("Connected\r\n");
|
||||||
|
break;
|
||||||
|
case WStype_TEXT:
|
||||||
|
Serial.printlnf("[WSc] get text: %s", payload);
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
Serial.printlnf("[WSc] get binary length: %u", length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
WiFi.setCredentials("[SSID]", "[PASSWORD]", WPA2, WLAN_CIPHER_AES_TKIP);
|
||||||
|
WiFi.connect();
|
||||||
|
|
||||||
|
webSocket.begin("192.168.1.153", 85, "/ClientService/?variable=Test1212");
|
||||||
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
webSocket.sendTXT("Hello world!");
|
||||||
|
delay(500);
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
42
library.json
42
library.json
@ -1,19 +1,25 @@
|
|||||||
{
|
{
|
||||||
"name": "WebSockets",
|
"authors": [
|
||||||
"keywords": "wifi, http, web, server, client, websocket",
|
{
|
||||||
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
"maintainer": true,
|
||||||
"repository":
|
"name": "Markus Sattler",
|
||||||
{
|
"url": "https://github.com/Links2004"
|
||||||
"type": "git",
|
}
|
||||||
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
],
|
||||||
},
|
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
||||||
"exclude": "tests",
|
"export": {
|
||||||
"frameworks": "arduino",
|
"exclude": [
|
||||||
"platforms": "*",
|
"tests"
|
||||||
"authors":
|
]
|
||||||
{
|
},
|
||||||
"name": "Markus Sattler",
|
"frameworks": "arduino",
|
||||||
"url": "https://github.com/Links2004",
|
"keywords": "wifi, http, web, server, client, websocket",
|
||||||
"maintainer": true
|
"license": "LGPL-2.1",
|
||||||
}
|
"name": "WebSockets",
|
||||||
}
|
"platforms": "atmelavr, espressif8266, espressif32",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
||||||
|
},
|
||||||
|
"version": "2.3.5"
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
name=WebSockets
|
name=WebSockets
|
||||||
version=2.0.2
|
version=2.3.5
|
||||||
author=Markus Sattler
|
author=Markus Sattler
|
||||||
maintainer=Markus Sattler
|
maintainer=Markus Sattler
|
||||||
sentence=WebSockets for Arduino (Server + Client)
|
sentence=WebSockets for Arduino (Server + Client)
|
||||||
paragraph=use 2.x.x for ESP and 1.3 for AVR
|
paragraph=use 2.x.x for ESP and 1.3 for AVR
|
||||||
category=Communication
|
category=Communication
|
||||||
|
252
src/SocketIOclient.cpp
Normal file
252
src/SocketIOclient.cpp
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* SocketIOclient.cpp
|
||||||
|
*
|
||||||
|
* Created on: May 12, 2018
|
||||||
|
* Author: links
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "WebSockets.h"
|
||||||
|
#include "WebSocketsClient.h"
|
||||||
|
#include "SocketIOclient.h"
|
||||||
|
|
||||||
|
SocketIOclient::SocketIOclient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketIOclient::~SocketIOclient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||||
|
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) {
|
||||||
|
WebSocketsClient::beginSocketIO(host, port, url, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
#if defined(HAS_SSL)
|
||||||
|
void SocketIOclient::beginSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||||
|
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::beginSSL(String host, uint16_t port, String url, String protocol) {
|
||||||
|
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
|
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||||
|
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
||||||
|
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
|
||||||
|
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
|
||||||
|
initClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
|
||||||
|
WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) {
|
||||||
|
WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SocketIOclient::configureEIOping(bool disableHeartbeat) {
|
||||||
|
_disableHeartbeat = disableHeartbeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::initClient(void) {
|
||||||
|
if(_client.cUrl.indexOf("EIO=4") != -1) {
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] found EIO=4 disable EIO ping on client\n");
|
||||||
|
configureEIOping(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set callback function
|
||||||
|
* @param cbEvent SocketIOclientEvent
|
||||||
|
*/
|
||||||
|
void SocketIOclient::onEvent(SocketIOclientEvent cbEvent) {
|
||||||
|
_cbEvent = cbEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::isConnected(void) {
|
||||||
|
return WebSocketsClient::isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send text data to client
|
||||||
|
* @param num uint8_t client id
|
||||||
|
* @param type socketIOmessageType_t
|
||||||
|
* @param payload uint8_t *
|
||||||
|
* @param length size_t
|
||||||
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
|
* @return true if ok
|
||||||
|
*/
|
||||||
|
bool SocketIOclient::send(socketIOmessageType_t type, uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
|
bool ret = false;
|
||||||
|
if(length == 0) {
|
||||||
|
length = strlen((const char *)payload);
|
||||||
|
}
|
||||||
|
if(clientIsConnected(&_client) && _client.status == WSC_CONNECTED) {
|
||||||
|
if(!headerToPayload) {
|
||||||
|
// webSocket Header
|
||||||
|
ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true);
|
||||||
|
// Engine.IO / Socket.IO Header
|
||||||
|
if(ret) {
|
||||||
|
uint8_t buf[3] = { eIOtype_MESSAGE, type, 0x00 };
|
||||||
|
ret = WebSocketsClient::write(&_client, buf, 2);
|
||||||
|
}
|
||||||
|
if(ret && payload && length > 0) {
|
||||||
|
ret = WebSocketsClient::write(&_client, payload, length);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
// TODO implement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::send(socketIOmessageType_t type, const uint8_t * payload, size_t length) {
|
||||||
|
return send(type, (uint8_t *)payload, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::send(socketIOmessageType_t type, char * payload, size_t length, bool headerToPayload) {
|
||||||
|
return send(type, (uint8_t *)payload, length, headerToPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::send(socketIOmessageType_t type, const char * payload, size_t length) {
|
||||||
|
return send(type, (uint8_t *)payload, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::send(socketIOmessageType_t type, String & payload) {
|
||||||
|
return send(type, (uint8_t *)payload.c_str(), payload.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send text data to client
|
||||||
|
* @param num uint8_t client id
|
||||||
|
* @param payload uint8_t *
|
||||||
|
* @param length size_t
|
||||||
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
|
* @return true if ok
|
||||||
|
*/
|
||||||
|
bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
|
return send(sIOtype_EVENT, payload, length, headerToPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::sendEVENT(const uint8_t * payload, size_t length) {
|
||||||
|
return sendEVENT((uint8_t *)payload, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::sendEVENT(char * payload, size_t length, bool headerToPayload) {
|
||||||
|
return sendEVENT((uint8_t *)payload, length, headerToPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::sendEVENT(const char * payload, size_t length) {
|
||||||
|
return sendEVENT((uint8_t *)payload, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::sendEVENT(String & payload) {
|
||||||
|
return sendEVENT((uint8_t *)payload.c_str(), payload.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::loop(void) {
|
||||||
|
WebSocketsClient::loop();
|
||||||
|
unsigned long t = millis();
|
||||||
|
if(!_disableHeartbeat && (t - _lastHeartbeat) > EIO_HEARTBEAT_INTERVAL) {
|
||||||
|
_lastHeartbeat = t;
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] send ping\n");
|
||||||
|
WebSocketsClient::sendTXT(eIOtype_PING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
runIOCbEvent(sIOtype_DISCONNECT, NULL, 0);
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED: {
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload);
|
||||||
|
// send message to server when Connected
|
||||||
|
// Engine.io upgrade confirmation message (required)
|
||||||
|
WebSocketsClient::sendTXT("2probe");
|
||||||
|
WebSocketsClient::sendTXT(eIOtype_UPGRADE);
|
||||||
|
runIOCbEvent(sIOtype_CONNECT, payload, length);
|
||||||
|
} break;
|
||||||
|
case WStype_TEXT: {
|
||||||
|
if(length < 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
engineIOmessageType_t eType = (engineIOmessageType_t)payload[0];
|
||||||
|
switch(eType) {
|
||||||
|
case eIOtype_PING:
|
||||||
|
payload[0] = eIOtype_PONG;
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get ping send pong (%s)\n", payload);
|
||||||
|
WebSocketsClient::sendTXT(payload, length, false);
|
||||||
|
break;
|
||||||
|
case eIOtype_PONG:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get pong\n");
|
||||||
|
break;
|
||||||
|
case eIOtype_MESSAGE: {
|
||||||
|
if(length < 2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
socketIOmessageType_t ioType = (socketIOmessageType_t)payload[1];
|
||||||
|
uint8_t * data = &payload[2];
|
||||||
|
size_t lData = length - 2;
|
||||||
|
switch(ioType) {
|
||||||
|
case sIOtype_EVENT:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data);
|
||||||
|
break;
|
||||||
|
case sIOtype_CONNECT:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] connected (%d): %s\n", lData, data);
|
||||||
|
return;
|
||||||
|
case sIOtype_DISCONNECT:
|
||||||
|
case sIOtype_ACK:
|
||||||
|
case sIOtype_ERROR:
|
||||||
|
case sIOtype_BINARY_EVENT:
|
||||||
|
case sIOtype_BINARY_ACK:
|
||||||
|
default:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] Socket.IO Message Type %c (%02X) is not implemented\n", ioType, ioType);
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
runIOCbEvent(ioType, data, lData);
|
||||||
|
} break;
|
||||||
|
case eIOtype_OPEN:
|
||||||
|
case eIOtype_CLOSE:
|
||||||
|
case eIOtype_UPGRADE:
|
||||||
|
case eIOtype_NOOP:
|
||||||
|
default:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] Engine.IO Message Type %c (%02X) is not implemented\n", eType, eType);
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case WStype_ERROR:
|
||||||
|
case WStype_BIN:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
case WStype_PING:
|
||||||
|
case WStype_PONG:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
101
src/SocketIOclient.h
Normal file
101
src/SocketIOclient.h
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/**
|
||||||
|
* SocketIOclient.h
|
||||||
|
*
|
||||||
|
* Created on: May 12, 2018
|
||||||
|
* Author: links
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOCKETIOCLIENT_H_
|
||||||
|
#define SOCKETIOCLIENT_H_
|
||||||
|
|
||||||
|
#include "WebSockets.h"
|
||||||
|
|
||||||
|
#define EIO_HEARTBEAT_INTERVAL 20000
|
||||||
|
|
||||||
|
#define EIO_MAX_HEADER_SIZE (WEBSOCKETS_MAX_HEADER_SIZE + 1)
|
||||||
|
#define SIO_MAX_HEADER_SIZE (EIO_MAX_HEADER_SIZE + 1)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
eIOtype_OPEN = '0', ///< Sent from the server when a new transport is opened (recheck)
|
||||||
|
eIOtype_CLOSE = '1', ///< Request the close of this transport but does not shutdown the connection itself.
|
||||||
|
eIOtype_PING = '2', ///< Sent by the client. Server should answer with a pong packet containing the same data
|
||||||
|
eIOtype_PONG = '3', ///< Sent by the server to respond to ping packets.
|
||||||
|
eIOtype_MESSAGE = '4', ///< actual message, client and server should call their callbacks with the data
|
||||||
|
eIOtype_UPGRADE = '5', ///< Before engine.io switches a transport, it tests, if server and client can communicate over this transport. If this test succeed, the client sends an upgrade packets which requests the server to flush its cache on the old transport and switch to the new transport.
|
||||||
|
eIOtype_NOOP = '6', ///< A noop packet. Used primarily to force a poll cycle when an incoming websocket connection is received.
|
||||||
|
} engineIOmessageType_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
sIOtype_CONNECT = '0',
|
||||||
|
sIOtype_DISCONNECT = '1',
|
||||||
|
sIOtype_EVENT = '2',
|
||||||
|
sIOtype_ACK = '3',
|
||||||
|
sIOtype_ERROR = '4',
|
||||||
|
sIOtype_BINARY_EVENT = '5',
|
||||||
|
sIOtype_BINARY_ACK = '6',
|
||||||
|
} socketIOmessageType_t;
|
||||||
|
|
||||||
|
class SocketIOclient : protected WebSocketsClient {
|
||||||
|
public:
|
||||||
|
#ifdef __AVR__
|
||||||
|
typedef void (*SocketIOclientEvent)(socketIOmessageType_t type, uint8_t * payload, size_t length);
|
||||||
|
#else
|
||||||
|
typedef std::function<void(socketIOmessageType_t type, uint8_t * payload, size_t length)> SocketIOclientEvent;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SocketIOclient(void);
|
||||||
|
virtual ~SocketIOclient(void);
|
||||||
|
|
||||||
|
void begin(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||||
|
void begin(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||||
|
|
||||||
|
#ifdef HAS_SSL
|
||||||
|
void beginSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||||
|
void beginSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||||
|
#ifndef SSL_AXTLS
|
||||||
|
void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
|
void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
|
void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL);
|
||||||
|
void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
bool isConnected(void);
|
||||||
|
|
||||||
|
void onEvent(SocketIOclientEvent cbEvent);
|
||||||
|
|
||||||
|
bool sendEVENT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool sendEVENT(const uint8_t * payload, size_t length = 0);
|
||||||
|
bool sendEVENT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool sendEVENT(const char * payload, size_t length = 0);
|
||||||
|
bool sendEVENT(String & payload);
|
||||||
|
|
||||||
|
bool send(socketIOmessageType_t type, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool send(socketIOmessageType_t type, const uint8_t * payload, size_t length = 0);
|
||||||
|
bool send(socketIOmessageType_t type, char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool send(socketIOmessageType_t type, const char * payload, size_t length = 0);
|
||||||
|
bool send(socketIOmessageType_t type, String & payload);
|
||||||
|
|
||||||
|
void loop(void);
|
||||||
|
|
||||||
|
void configureEIOping(bool disableHeartbeat = false);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool _disableHeartbeat = false;
|
||||||
|
uint64_t _lastHeartbeat = 0;
|
||||||
|
SocketIOclientEvent _cbEvent;
|
||||||
|
virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
|
if(_cbEvent) {
|
||||||
|
_cbEvent(type, payload, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initClient(void);
|
||||||
|
|
||||||
|
// Handeling events from websocket layer
|
||||||
|
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
handleCbEvent(type, payload, length);
|
||||||
|
}
|
||||||
|
void handleCbEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SOCKETIOCLIENT_H_ */
|
@ -38,6 +38,15 @@ extern "C" {
|
|||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#include <Hash.h>
|
#include <Hash.h>
|
||||||
|
#elif defined(ESP32)
|
||||||
|
#include <esp_system.h>
|
||||||
|
|
||||||
|
#if ESP_IDF_VERSION_MAJOR >= 4
|
||||||
|
#include <esp32/sha.h>
|
||||||
|
#else
|
||||||
|
#include <hwcrypto/sha.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -50,14 +59,14 @@ extern "C" {
|
|||||||
*
|
*
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
* @param code uint16_t see RFC
|
* @param code uint16_t see RFC
|
||||||
* @param reason
|
* @param reason ptr to the disconnect reason message
|
||||||
* @param reasonLen
|
* @param reasonLen length of the disconnect reason message
|
||||||
*/
|
*/
|
||||||
void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) {
|
void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] clientDisconnect code: %u\n", client->num, code);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] clientDisconnect code: %u\n", client->num, code);
|
||||||
if(client->status == WSC_CONNECTED && code) {
|
if(client->status == WSC_CONNECTED && code) {
|
||||||
if(reason) {
|
if(reason) {
|
||||||
sendFrame(client, WSop_close, (uint8_t *) reason, reasonLen);
|
sendFrame(client, WSop_close, (uint8_t *)reason, reasonLen);
|
||||||
} else {
|
} else {
|
||||||
uint8_t buffer[2];
|
uint8_t buffer[2];
|
||||||
buffer[0] = ((code >> 8) & 0xFF);
|
buffer[0] = ((code >> 8) & 0xFF);
|
||||||
@ -70,43 +79,15 @@ void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * rea
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param buf uint8_t * ptr to the buffer for writing
|
||||||
* @param opcode WSopcode_t
|
* @param opcode WSopcode_t
|
||||||
* @param payload uint8_t *
|
* @param length size_t length of the payload
|
||||||
* @param length size_t
|
|
||||||
* @param mask bool add dummy mask to the frame (needed for web browser)
|
* @param mask bool add dummy mask to the frame (needed for web browser)
|
||||||
|
* @param maskkey uint8_t[4] key used for payload
|
||||||
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||||
* @param headerToPayload bool set true if the payload has reserved 14 Byte at the beginning to dynamically add the Header (payload neet to be in RAM!)
|
|
||||||
* @return true if ok
|
|
||||||
*/
|
*/
|
||||||
bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool mask, bool fin, bool headerToPayload) {
|
uint8_t WebSockets::createHeader(uint8_t * headerPtr, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin) {
|
||||||
|
|
||||||
if(client->tcp && !client->tcp->connected()) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not Connected!?\n", client->num);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(client->status != WSC_CONNECTED) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not in WSC_CONNECTED state!?\n", client->num);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] ------- send massage frame -------\n", client->num);
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] fin: %u opCode: %u mask: %u length: %u headerToPayload: %u\n", client->num, fin, opcode, mask, length, headerToPayload);
|
|
||||||
|
|
||||||
if(opcode == WSop_text) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] text: %s\n", client->num, (payload + (headerToPayload ? 14 : 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 };
|
|
||||||
|
|
||||||
uint8_t headerSize;
|
uint8_t headerSize;
|
||||||
uint8_t * headerPtr;
|
|
||||||
uint8_t * payloadPtr = payload;
|
|
||||||
bool useInternBuffer = false;
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
// calculate header Size
|
// calculate header Size
|
||||||
if(length < 126) {
|
if(length < 126) {
|
||||||
headerSize = 2;
|
headerSize = 2;
|
||||||
@ -120,29 +101,6 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
headerSize += 4;
|
headerSize += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WEBSOCKETS_USE_BIG_MEM
|
|
||||||
// only for ESP since AVR has less HEAP
|
|
||||||
// try to send data in one TCP package (only if some free Heap is there)
|
|
||||||
if(!headerToPayload && ((length > 0) && (length < 1400)) && (ESP.getFreeHeap() > 6000)) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] pack to one TCP package...\n", client->num);
|
|
||||||
uint8_t * dataPtr = (uint8_t *) malloc(length + WEBSOCKETS_MAX_HEADER_SIZE);
|
|
||||||
if(dataPtr) {
|
|
||||||
memcpy((dataPtr + WEBSOCKETS_MAX_HEADER_SIZE), payload, length);
|
|
||||||
headerToPayload = true;
|
|
||||||
useInternBuffer = true;
|
|
||||||
payloadPtr = dataPtr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// set Header Pointer
|
|
||||||
if(headerToPayload) {
|
|
||||||
// calculate offset in payload
|
|
||||||
headerPtr = (payloadPtr + (WEBSOCKETS_MAX_HEADER_SIZE - headerSize));
|
|
||||||
} else {
|
|
||||||
headerPtr = &buffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// create header
|
// create header
|
||||||
|
|
||||||
// byte 0
|
// byte 0
|
||||||
@ -150,7 +108,7 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
if(fin) {
|
if(fin) {
|
||||||
*headerPtr |= bit(7); ///< set Fin
|
*headerPtr |= bit(7); ///< set Fin
|
||||||
}
|
}
|
||||||
*headerPtr |= opcode; ///< set opcode
|
*headerPtr |= opcode; ///< set opcode
|
||||||
headerPtr++;
|
headerPtr++;
|
||||||
|
|
||||||
// byte 1
|
// byte 1
|
||||||
@ -192,36 +150,133 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(mask) {
|
if(mask) {
|
||||||
if(useInternBuffer) {
|
*headerPtr = maskKey[0];
|
||||||
// if we use a Intern Buffer we can modify the data
|
headerPtr++;
|
||||||
// by this fact its possible the do the masking
|
*headerPtr = maskKey[1];
|
||||||
for(uint8_t x = 0; x < sizeof(maskKey); x++) {
|
headerPtr++;
|
||||||
maskKey[x] = random(0xFF);
|
*headerPtr = maskKey[2];
|
||||||
*headerPtr = maskKey[x];
|
headerPtr++;
|
||||||
headerPtr++;
|
*headerPtr = maskKey[3];
|
||||||
}
|
headerPtr++;
|
||||||
|
}
|
||||||
|
return headerSize;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t * dataMaskPtr;
|
/**
|
||||||
|
*
|
||||||
|
* @param client WSclient_t * ptr to the client struct
|
||||||
|
* @param opcode WSopcode_t
|
||||||
|
* @param length size_t length of the payload
|
||||||
|
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||||
|
* @return true if ok
|
||||||
|
*/
|
||||||
|
bool WebSockets::sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length, bool fin) {
|
||||||
|
uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 };
|
||||||
|
|
||||||
if(headerToPayload) {
|
uint8_t headerSize = createHeader(&buffer[0], opcode, length, client->cIsClient, maskKey, fin);
|
||||||
dataMaskPtr = (payloadPtr + WEBSOCKETS_MAX_HEADER_SIZE);
|
|
||||||
} else {
|
|
||||||
dataMaskPtr = payloadPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t x = 0; x < length; x++) {
|
if(write(client, &buffer[0], headerSize) != headerSize) {
|
||||||
dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param client WSclient_t * ptr to the client struct
|
||||||
|
* @param opcode WSopcode_t
|
||||||
|
* @param payload uint8_t * ptr to the payload
|
||||||
|
* @param length size_t length of the payload
|
||||||
|
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||||
|
* @param headerToPayload bool set true if the payload has reserved 14 Byte at the beginning to dynamically add the Header (payload neet to be in RAM!)
|
||||||
|
* @return true if ok
|
||||||
|
*/
|
||||||
|
bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin, bool headerToPayload) {
|
||||||
|
if(client->tcp && !client->tcp->connected()) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not Connected!?\n", client->num);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client->status != WSC_CONNECTED) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not in WSC_CONNECTED state!?\n", client->num);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] ------- send message frame -------\n", client->num);
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] fin: %u opCode: %u mask: %u length: %u headerToPayload: %u\n", client->num, fin, opcode, client->cIsClient, length, headerToPayload);
|
||||||
|
|
||||||
|
if(opcode == WSop_text) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] text: %s\n", client->num, (payload + (headerToPayload ? 14 : 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 };
|
||||||
|
|
||||||
|
uint8_t headerSize;
|
||||||
|
uint8_t * headerPtr;
|
||||||
|
uint8_t * payloadPtr = payload;
|
||||||
|
bool useInternBuffer = false;
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
// calculate header Size
|
||||||
|
if(length < 126) {
|
||||||
|
headerSize = 2;
|
||||||
|
} else if(length < 0xFFFF) {
|
||||||
|
headerSize = 4;
|
||||||
|
} else {
|
||||||
|
headerSize = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client->cIsClient) {
|
||||||
|
headerSize += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WEBSOCKETS_USE_BIG_MEM
|
||||||
|
// only for ESP since AVR has less HEAP
|
||||||
|
// try to send data in one TCP package (only if some free Heap is there)
|
||||||
|
if(!headerToPayload && ((length > 0) && (length < 1400)) && (GET_FREE_HEAP > 6000)) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] pack to one TCP package...\n", client->num);
|
||||||
|
uint8_t * dataPtr = (uint8_t *)malloc(length + WEBSOCKETS_MAX_HEADER_SIZE);
|
||||||
|
if(dataPtr) {
|
||||||
|
memcpy((dataPtr + WEBSOCKETS_MAX_HEADER_SIZE), payload, length);
|
||||||
|
headerToPayload = true;
|
||||||
|
useInternBuffer = true;
|
||||||
|
payloadPtr = dataPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// set Header Pointer
|
||||||
|
if(headerToPayload) {
|
||||||
|
// calculate offset in payload
|
||||||
|
headerPtr = (payloadPtr + (WEBSOCKETS_MAX_HEADER_SIZE - headerSize));
|
||||||
|
} else {
|
||||||
|
headerPtr = &buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client->cIsClient && useInternBuffer) {
|
||||||
|
// if we use a Intern Buffer we can modify the data
|
||||||
|
// by this fact its possible the do the masking
|
||||||
|
for(uint8_t x = 0; x < sizeof(maskKey); x++) {
|
||||||
|
maskKey[x] = random(0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createHeader(headerPtr, opcode, length, client->cIsClient, maskKey, fin);
|
||||||
|
|
||||||
|
if(client->cIsClient && useInternBuffer) {
|
||||||
|
uint8_t * dataMaskPtr;
|
||||||
|
|
||||||
|
if(headerToPayload) {
|
||||||
|
dataMaskPtr = (payloadPtr + WEBSOCKETS_MAX_HEADER_SIZE);
|
||||||
} else {
|
} else {
|
||||||
*headerPtr = maskKey[0];
|
dataMaskPtr = payloadPtr;
|
||||||
headerPtr++;
|
}
|
||||||
*headerPtr = maskKey[1];
|
|
||||||
headerPtr++;
|
for(size_t x = 0; x < length; x++) {
|
||||||
*headerPtr = maskKey[2];
|
dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]);
|
||||||
headerPtr++;
|
|
||||||
*headerPtr = maskKey[3];
|
|
||||||
headerPtr++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,24 +288,24 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
// header has be added to payload
|
// header has be added to payload
|
||||||
// payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings
|
// payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings
|
||||||
// offset in payload is calculatetd 14 - headerSize
|
// offset in payload is calculatetd 14 - headerSize
|
||||||
if(client->tcp->write(&payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize)) != (length + headerSize)) {
|
if(write(client, &payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize)) != (length + headerSize)) {
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// send header
|
// send header
|
||||||
if(client->tcp->write(&buffer[0], headerSize) != headerSize) {
|
if(write(client, &buffer[0], headerSize) != headerSize) {
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(payloadPtr && length > 0) {
|
if(payloadPtr && length > 0) {
|
||||||
// send payload
|
// send payload
|
||||||
if(client->tcp->write(&payloadPtr[0], length) != length) {
|
if(write(client, &payloadPtr[0], length) != length) {
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] sending Frame Done (%uus).\n", client->num, (micros() - start));
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] sending Frame Done (%luus).\n", client->num, (micros() - start));
|
||||||
|
|
||||||
#ifdef WEBSOCKETS_USE_BIG_MEM
|
#ifdef WEBSOCKETS_USE_BIG_MEM
|
||||||
if(useInternBuffer && payloadPtr) {
|
if(useInternBuffer && payloadPtr) {
|
||||||
@ -266,10 +321,10 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
void WebSockets::headerDone(WSclient_t * client) {
|
void WebSockets::headerDone(WSclient_t * client) {
|
||||||
client->status = WSC_CONNECTED;
|
client->status = WSC_CONNECTED;
|
||||||
client->cWsRXsize = 0;
|
client->cWsRXsize = 0;
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][headerDone] Header Handling Done (%uus).\n", client->num);
|
DEBUG_WEBSOCKETS("[WS][%d][headerDone] Header Handling Done.\n", client->num);
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
client->cHttpLine = "";
|
client->cHttpLine = "";
|
||||||
handleWebsocket(client);
|
handleWebsocket(client);
|
||||||
#endif
|
#endif
|
||||||
@ -296,7 +351,7 @@ bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(size > WEBSOCKETS_MAX_HEADER_SIZE) {
|
if(size > WEBSOCKETS_MAX_HEADER_SIZE) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d to big!\n", client->num, size);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d too big!\n", client->num, size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,12 +371,12 @@ bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) {
|
|||||||
// timeout or error
|
// timeout or error
|
||||||
server->clientDisconnect(client, 1002);
|
server->clientDisconnect(client, 1002);
|
||||||
}
|
}
|
||||||
}, this, size, std::placeholders::_1, std::placeholders::_2));
|
},
|
||||||
|
this, size, std::placeholders::_1, std::placeholders::_2));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
||||||
|
|
||||||
if(!client->tcp || !client->tcp->connected()) {
|
if(!client->tcp || !client->tcp->connected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -329,7 +384,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
|||||||
uint8_t * buffer = client->cWsHeader;
|
uint8_t * buffer = client->cWsHeader;
|
||||||
|
|
||||||
WSMessageHeader_t * header = &client->cWsHeaderDecode;
|
WSMessageHeader_t * header = &client->cWsHeaderDecode;
|
||||||
uint8_t * payload = NULL;
|
uint8_t * payload = NULL;
|
||||||
|
|
||||||
uint8_t headerLen = 2;
|
uint8_t headerLen = 2;
|
||||||
|
|
||||||
@ -338,15 +393,15 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// split first 2 bytes in the data
|
// split first 2 bytes in the data
|
||||||
header->fin = ((*buffer >> 7) & 0x01);
|
header->fin = ((*buffer >> 7) & 0x01);
|
||||||
header->rsv1 = ((*buffer >> 6) & 0x01);
|
header->rsv1 = ((*buffer >> 6) & 0x01);
|
||||||
header->rsv2 = ((*buffer >> 5) & 0x01);
|
header->rsv2 = ((*buffer >> 5) & 0x01);
|
||||||
header->rsv3 = ((*buffer >> 4) & 0x01);
|
header->rsv3 = ((*buffer >> 4) & 0x01);
|
||||||
header->opCode = (WSopcode_t) (*buffer & 0x0F);
|
header->opCode = (WSopcode_t)(*buffer & 0x0F);
|
||||||
buffer++;
|
buffer++;
|
||||||
|
|
||||||
header->mask = ((*buffer >> 7) & 0x01);
|
header->mask = ((*buffer >> 7) & 0x01);
|
||||||
header->payloadLen = (WSopcode_t) (*buffer & 0x7F);
|
header->payloadLen = (WSopcode_t)(*buffer & 0x7F);
|
||||||
buffer++;
|
buffer++;
|
||||||
|
|
||||||
if(header->payloadLen == 126) {
|
if(header->payloadLen == 126) {
|
||||||
@ -364,7 +419,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) {
|
if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) {
|
||||||
// really to big!
|
// really too big!
|
||||||
header->payloadLen = 0xFFFFFFFF;
|
header->payloadLen = 0xFFFFFFFF;
|
||||||
} else {
|
} else {
|
||||||
header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
|
header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
|
||||||
@ -377,7 +432,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
|||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen);
|
||||||
|
|
||||||
if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
|
if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload to big! (%u)\n", client->num, header->payloadLen);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload too big! (%u)\n", client->num, header->payloadLen);
|
||||||
clientDisconnect(client, 1009);
|
clientDisconnect(client, 1009);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -393,7 +448,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
|||||||
|
|
||||||
if(header->payloadLen > 0) {
|
if(header->payloadLen > 0) {
|
||||||
// if text data we need one more
|
// if text data we need one more
|
||||||
payload = (uint8_t *) malloc(header->payloadLen + 1);
|
payload = (uint8_t *)malloc(header->payloadLen + 1);
|
||||||
|
|
||||||
if(!payload) {
|
if(!payload) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, header->payloadLen);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, header->payloadLen);
|
||||||
@ -407,7 +462,6 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload) {
|
void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload) {
|
||||||
|
|
||||||
WSMessageHeader_t * header = &client->cWsHeaderDecode;
|
WSMessageHeader_t * header = &client->cWsHeaderDecode;
|
||||||
if(ok) {
|
if(ok) {
|
||||||
if(header->payloadLen > 0) {
|
if(header->payloadLen > 0) {
|
||||||
@ -426,35 +480,37 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
|
||||||
// no break here!
|
// no break here!
|
||||||
case WSop_binary:
|
case WSop_binary:
|
||||||
messageRecived(client, header->opCode, payload, header->payloadLen);
|
case WSop_continuation:
|
||||||
|
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
||||||
break;
|
break;
|
||||||
case WSop_ping:
|
case WSop_ping:
|
||||||
// send pong back
|
// send pong back
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ping received (%s)\n", client->num, payload ? (const char *)payload : "");
|
||||||
sendFrame(client, WSop_pong, payload, header->payloadLen);
|
sendFrame(client, WSop_pong, payload, header->payloadLen);
|
||||||
|
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
||||||
break;
|
break;
|
||||||
case WSop_pong:
|
case WSop_pong:
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get pong (%s)\n", client->num, payload);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get pong (%s)\n", client->num, payload ? (const char *)payload : "");
|
||||||
|
client->pongReceived = true;
|
||||||
|
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
||||||
break;
|
break;
|
||||||
case WSop_close: {
|
case WSop_close: {
|
||||||
|
#ifndef NODEBUG_WEBSOCKETS
|
||||||
uint16_t reasonCode = 1000;
|
uint16_t reasonCode = 1000;
|
||||||
if(header->payloadLen >= 2) {
|
if(header->payloadLen >= 2) {
|
||||||
reasonCode = payload[0] << 8 | payload[1];
|
reasonCode = payload[0] << 8 | payload[1];
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d\n", client->num, reasonCode);
|
||||||
if(header->payloadLen > 2) {
|
if(header->payloadLen > 2) {
|
||||||
DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2));
|
DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("\n");
|
DEBUG_WEBSOCKETS("\n");
|
||||||
}
|
}
|
||||||
clientDisconnect(client, 1000);
|
clientDisconnect(client, 1000);
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
case WSop_continuation:
|
|
||||||
// continuation is not supported
|
|
||||||
clientDisconnect(client, 1003);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] got unknown opcode: %d\n", client->num, header->opCode);
|
||||||
clientDisconnect(client, 1002);
|
clientDisconnect(client, 1002);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -465,7 +521,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
|
|
||||||
// reset input
|
// reset input
|
||||||
client->cWsRXsize = 0;
|
client->cWsRXsize = 0;
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
//register callback for next message
|
//register callback for next message
|
||||||
handleWebsocketWaitFor(client, 2);
|
handleWebsocketWaitFor(client, 2);
|
||||||
#endif
|
#endif
|
||||||
@ -486,11 +542,14 @@ String WebSockets::acceptKey(String & clientKey) {
|
|||||||
uint8_t sha1HashBin[20] = { 0 };
|
uint8_t sha1HashBin[20] = { 0 };
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]);
|
sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]);
|
||||||
|
#elif defined(ESP32)
|
||||||
|
String data = clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
|
esp_sha(SHA1, (unsigned char *)data.c_str(), data.length(), &sha1HashBin[0]);
|
||||||
#else
|
#else
|
||||||
clientKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
clientKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
SHA1_CTX ctx;
|
SHA1_CTX ctx;
|
||||||
SHA1Init(&ctx);
|
SHA1Init(&ctx);
|
||||||
SHA1Update(&ctx, (const unsigned char*)clientKey.c_str(), clientKey.length());
|
SHA1Update(&ctx, (const unsigned char *)clientKey.c_str(), clientKey.length());
|
||||||
SHA1Final(&sha1HashBin[0], &ctx);
|
SHA1Final(&sha1HashBin[0], &ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -507,13 +566,13 @@ String WebSockets::acceptKey(String & clientKey) {
|
|||||||
* @return base64 encoded String
|
* @return base64 encoded String
|
||||||
*/
|
*/
|
||||||
String WebSockets::base64_encode(uint8_t * data, size_t length) {
|
String WebSockets::base64_encode(uint8_t * data, size_t length) {
|
||||||
size_t size = ((length * 1.6f) + 1);
|
size_t size = ((length * 1.6f) + 1);
|
||||||
char * buffer = (char *) malloc(size);
|
char * buffer = (char *)malloc(size);
|
||||||
if(buffer) {
|
if(buffer) {
|
||||||
base64_encodestate _state;
|
base64_encodestate _state;
|
||||||
base64_init_encodestate(&_state);
|
base64_init_encodestate(&_state);
|
||||||
int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state);
|
int len = base64_encode_block((const char *)&data[0], length, &buffer[0], &_state);
|
||||||
len = base64_encode_blockend((buffer + len), &_state);
|
len = base64_encode_blockend((buffer + len), &_state);
|
||||||
|
|
||||||
String base64 = String(buffer);
|
String base64 = String(buffer);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
@ -530,7 +589,7 @@ String WebSockets::base64_encode(uint8_t * data, size_t length) {
|
|||||||
* @return true if ok
|
* @return true if ok
|
||||||
*/
|
*/
|
||||||
bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb) {
|
bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb) {
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
if(!client->tcp || !client->tcp->connected()) {
|
if(!client->tcp || !client->tcp->connected()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -539,12 +598,13 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
|
|||||||
if(cb) {
|
if(cb) {
|
||||||
cb(client, ok);
|
cb(client, ok);
|
||||||
}
|
}
|
||||||
}, client, std::placeholders::_1, cb));
|
},
|
||||||
|
client, std::placeholders::_1, cb));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
unsigned long t = millis();
|
unsigned long t = millis();
|
||||||
size_t len;
|
ssize_t len;
|
||||||
DEBUG_WEBSOCKETS("[readCb] n: %d t: %d\n", n, t);
|
DEBUG_WEBSOCKETS("[readCb] n: %zu t: %lu\n", n, t);
|
||||||
while(n > 0) {
|
while(n > 0) {
|
||||||
if(client->tcp == NULL) {
|
if(client->tcp == NULL) {
|
||||||
DEBUG_WEBSOCKETS("[readCb] tcp is null!\n");
|
DEBUG_WEBSOCKETS("[readCb] tcp is null!\n");
|
||||||
@ -563,7 +623,7 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
|
|||||||
}
|
}
|
||||||
|
|
||||||
if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) {
|
if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) {
|
||||||
DEBUG_WEBSOCKETS("[readCb] receive TIMEOUT! %d\n", (millis() - t));
|
DEBUG_WEBSOCKETS("[readCb] receive TIMEOUT! %lu\n", (millis() - t));
|
||||||
if(cb) {
|
if(cb) {
|
||||||
cb(client, false);
|
cb(client, false);
|
||||||
}
|
}
|
||||||
@ -571,14 +631,12 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!client->tcp->available()) {
|
if(!client->tcp->available()) {
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
WEBSOCKETS_YIELD_MORE();
|
||||||
delay(0);
|
|
||||||
#endif
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = client->tcp->read((uint8_t*) out, n);
|
len = client->tcp->read((uint8_t *)out, n);
|
||||||
if(len) {
|
if(len > 0) {
|
||||||
t = millis();
|
t = millis();
|
||||||
out += len;
|
out += len;
|
||||||
n -= len;
|
n -= len;
|
||||||
@ -586,14 +644,114 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
|
|||||||
} else {
|
} else {
|
||||||
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
if(n > 0) {
|
||||||
delay(0);
|
WEBSOCKETS_YIELD();
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
if(cb) {
|
if(cb) {
|
||||||
cb(client, true);
|
cb(client, true);
|
||||||
}
|
}
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write x byte to tcp or get timeout
|
||||||
|
* @param client WSclient_t *
|
||||||
|
* @param out uint8_t * data buffer
|
||||||
|
* @param n size_t byte count
|
||||||
|
* @return bytes send
|
||||||
|
*/
|
||||||
|
size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) {
|
||||||
|
if(out == NULL)
|
||||||
|
return 0;
|
||||||
|
if(client == NULL)
|
||||||
|
return 0;
|
||||||
|
unsigned long t = millis();
|
||||||
|
size_t len = 0;
|
||||||
|
size_t total = 0;
|
||||||
|
DEBUG_WEBSOCKETS("[write] n: %zu t: %lu\n", n, t);
|
||||||
|
while(n > 0) {
|
||||||
|
if(client->tcp == NULL) {
|
||||||
|
DEBUG_WEBSOCKETS("[write] tcp is null!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!client->tcp->connected()) {
|
||||||
|
DEBUG_WEBSOCKETS("[write] not connected!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) {
|
||||||
|
DEBUG_WEBSOCKETS("[write] write TIMEOUT! %lu\n", (millis() - t));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = client->tcp->write((const uint8_t *)out, n);
|
||||||
|
if(len) {
|
||||||
|
t = millis();
|
||||||
|
out += len;
|
||||||
|
n -= len;
|
||||||
|
total += len;
|
||||||
|
//DEBUG_WEBSOCKETS("write %d left %d!\n", len, n);
|
||||||
|
} else {
|
||||||
|
DEBUG_WEBSOCKETS("WS write %d failed left %d!\n", len, n);
|
||||||
|
}
|
||||||
|
if(n > 0) {
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WebSockets::write(WSclient_t * client, const char * out) {
|
||||||
|
if(client == NULL)
|
||||||
|
return 0;
|
||||||
|
if(out == NULL)
|
||||||
|
return 0;
|
||||||
|
return write(client, (uint8_t *)out, strlen(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enable ping/pong heartbeat process
|
||||||
|
* @param client WSclient_t *
|
||||||
|
* @param pingInterval uint32_t how often ping will be sent
|
||||||
|
* @param pongTimeout uint32_t millis after which pong should timout if not received
|
||||||
|
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
|
||||||
|
*/
|
||||||
|
void WebSockets::enableHeartbeat(WSclient_t * client, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
|
if(client == NULL)
|
||||||
|
return;
|
||||||
|
client->pingInterval = pingInterval;
|
||||||
|
client->pongTimeout = pongTimeout;
|
||||||
|
client->disconnectTimeoutCount = disconnectTimeoutCount;
|
||||||
|
client->pongReceived = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle ping/pong heartbeat timeout process
|
||||||
|
* @param client WSclient_t *
|
||||||
|
*/
|
||||||
|
void WebSockets::handleHBTimeout(WSclient_t * client) {
|
||||||
|
if(client->pingInterval) { // if heartbeat is enabled
|
||||||
|
uint32_t pi = millis() - client->lastPing;
|
||||||
|
|
||||||
|
if(client->pongReceived) {
|
||||||
|
client->pongTimeoutCount = 0;
|
||||||
|
} else {
|
||||||
|
if(pi > client->pongTimeout) { // pong not received in time
|
||||||
|
client->pongTimeoutCount++;
|
||||||
|
client->lastPing = millis() - client->pingInterval - 500; // force ping on the next run
|
||||||
|
|
||||||
|
DEBUG_WEBSOCKETS("[HBtimeout] pong TIMEOUT! lp=%d millis=%d pi=%d count=%d\n", client->lastPing, millis(), pi, client->pongTimeoutCount);
|
||||||
|
|
||||||
|
if(client->disconnectTimeoutCount && client->pongTimeoutCount >= client->disconnectTimeoutCount) {
|
||||||
|
DEBUG_WEBSOCKETS("[HBtimeout] count=%d, DISCONNECTING\n", client->pongTimeoutCount);
|
||||||
|
clientDisconnect(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
302
src/WebSockets.h
302
src/WebSockets.h
@ -25,62 +25,128 @@
|
|||||||
#ifndef WEBSOCKETS_H_
|
#ifndef WEBSOCKETS_H_
|
||||||
#define WEBSOCKETS_H_
|
#define WEBSOCKETS_H_
|
||||||
|
|
||||||
|
#ifdef STM32_DEVICE
|
||||||
|
#include <application.h>
|
||||||
|
#define bit(b) (1UL << (b)) // Taken directly from Arduino.h
|
||||||
|
#else
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <IPAddress.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_AVR
|
||||||
|
#error Version 2.x.x currently does not support Arduino with AVR since there is no support for std namespace of c++.
|
||||||
|
#error Use Version 1.x.x. (ATmega branch)
|
||||||
|
#else
|
||||||
|
#include <functional>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "WebSocketsVersion.h"
|
||||||
|
|
||||||
|
#ifndef NODEBUG_WEBSOCKETS
|
||||||
|
#ifdef DEBUG_ESP_PORT
|
||||||
|
#define DEBUG_WEBSOCKETS(...) \
|
||||||
|
{ \
|
||||||
|
DEBUG_ESP_PORT.printf(__VA_ARGS__); \
|
||||||
|
DEBUG_ESP_PORT.flush(); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ )
|
//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ )
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef DEBUG_WEBSOCKETS
|
#ifndef DEBUG_WEBSOCKETS
|
||||||
#define DEBUG_WEBSOCKETS(...)
|
#define DEBUG_WEBSOCKETS(...)
|
||||||
|
#ifndef NODEBUG_WEBSOCKETS
|
||||||
#define NODEBUG_WEBSOCKETS
|
#define NODEBUG_WEBSOCKETS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
#define WEBSOCKETS_MAX_DATA_SIZE (15*1024)
|
|
||||||
#define WEBSOCKETS_USE_BIG_MEM
|
|
||||||
#else
|
|
||||||
//atmega328p has only 2KB ram!
|
|
||||||
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WEBSOCKETS_TCP_TIMEOUT (2000)
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
|
|
||||||
#define NETWORK_ESP8266_ASYNC (0)
|
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
|
||||||
#define NETWORK_ESP8266 (1)
|
#define WEBSOCKETS_USE_BIG_MEM
|
||||||
#define NETWORK_W5100 (2)
|
#define GET_FREE_HEAP ESP.getFreeHeap()
|
||||||
#define NETWORK_ENC28J60 (3)
|
// moves all Header strings to Flash (~300 Byte)
|
||||||
|
//#define WEBSOCKETS_SAVE_RAM
|
||||||
|
|
||||||
|
#if defined(ESP8266)
|
||||||
|
#define WEBSOCKETS_YIELD() delay(0)
|
||||||
|
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||||
|
#elif defined(ESP32)
|
||||||
|
#define WEBSOCKETS_YIELD() yield()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE() delay(1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(STM32_DEVICE)
|
||||||
|
|
||||||
|
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
|
||||||
|
#define WEBSOCKETS_USE_BIG_MEM
|
||||||
|
#define GET_FREE_HEAP System.freeMemory()
|
||||||
|
#define WEBSOCKETS_YIELD()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE()
|
||||||
|
#else
|
||||||
|
|
||||||
|
//atmega328p has only 2KB ram!
|
||||||
|
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
||||||
|
// moves all Header strings to Flash
|
||||||
|
#define WEBSOCKETS_SAVE_RAM
|
||||||
|
#define WEBSOCKETS_YIELD()
|
||||||
|
#define WEBSOCKETS_YIELD_MORE()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WEBSOCKETS_TCP_TIMEOUT (5000)
|
||||||
|
|
||||||
|
#define NETWORK_ESP8266_ASYNC (0)
|
||||||
|
#define NETWORK_ESP8266 (1)
|
||||||
|
#define NETWORK_W5100 (2)
|
||||||
|
#define NETWORK_ENC28J60 (3)
|
||||||
|
#define NETWORK_ESP32 (4)
|
||||||
|
#define NETWORK_ESP32_ETH (5)
|
||||||
|
|
||||||
// max size of the WS Message Header
|
// max size of the WS Message Header
|
||||||
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
|
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
|
||||||
|
|
||||||
|
#if !defined(WEBSOCKETS_NETWORK_TYPE)
|
||||||
// select Network type based
|
// select Network type based
|
||||||
#if defined(ESP8266) || defined(ESP31B)
|
#if defined(ESP8266) || defined(ESP31B)
|
||||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
||||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC
|
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC
|
||||||
|
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
||||||
|
|
||||||
|
#elif defined(ESP32)
|
||||||
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32
|
||||||
|
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH
|
||||||
#else
|
#else
|
||||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
// Includes and defined based on Network Type
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
|
||||||
// Note:
|
// Note:
|
||||||
// No SSL/WSS support for client in Async mode
|
// No SSL/WSS support for client in Async mode
|
||||||
// TLS lib need a sync interface!
|
// TLS lib need a sync interface!
|
||||||
|
|
||||||
#if !defined(ESP8266) && !defined(ESP31B)
|
#if defined(ESP8266)
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#elif defined(ESP32)
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#define SSL_AXTLS
|
||||||
|
#elif defined(ESP31B)
|
||||||
|
#include <ESP31BWiFi.h>
|
||||||
|
#else
|
||||||
#error "network type ESP8266 ASYNC only possible on the ESP mcu!"
|
#error "network type ESP8266 ASYNC only possible on the ESP mcu!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#else
|
|
||||||
#include <ESP31BWiFi.h>
|
|
||||||
#endif
|
|
||||||
#include <ESPAsyncTCP.h>
|
#include <ESPAsyncTCP.h>
|
||||||
#include <ESPAsyncTCPbuffer.h>
|
#include <ESPAsyncTCPbuffer.h>
|
||||||
#define WEBSOCKETS_NETWORK_CLASS AsyncTCPbuffer
|
#define WEBSOCKETS_NETWORK_CLASS AsyncTCPbuffer
|
||||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS AsyncServer
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS AsyncServer
|
||||||
|
|
||||||
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
|
|
||||||
#if !defined(ESP8266) && !defined(ESP31B)
|
#if !defined(ESP8266) && !defined(ESP31B)
|
||||||
#error "network type ESP8266 only possible on the ESP mcu!"
|
#error "network type ESP8266 only possible on the ESP mcu!"
|
||||||
@ -88,33 +154,70 @@
|
|||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
|
#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
|
||||||
|
#define SSL_BARESSL
|
||||||
|
#else
|
||||||
|
#define SSL_AXTLS
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#include <ESP31BWiFi.h>
|
#include <ESP31BWiFi.h>
|
||||||
#endif
|
#endif
|
||||||
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
|
||||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
|
||||||
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100)
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100)
|
||||||
|
|
||||||
|
#ifdef STM32_DEVICE
|
||||||
|
#define WEBSOCKETS_NETWORK_CLASS TCPClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS TCPServer
|
||||||
|
#else
|
||||||
#include <Ethernet.h>
|
#include <Ethernet.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#define WEBSOCKETS_NETWORK_CLASS EthernetClient
|
#define WEBSOCKETS_NETWORK_CLASS EthernetClient
|
||||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60)
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60)
|
||||||
|
|
||||||
#include <UIPEthernet.h>
|
#include <UIPEthernet.h>
|
||||||
#define WEBSOCKETS_NETWORK_CLASS UIPClient
|
#define WEBSOCKETS_NETWORK_CLASS UIPClient
|
||||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS UIPServer
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS UIPServer
|
||||||
|
|
||||||
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#define SSL_AXTLS
|
||||||
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
|
||||||
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
|
||||||
|
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32_ETH)
|
||||||
|
|
||||||
|
#include <ETH.h>
|
||||||
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "no network type selected!"
|
#error "no network type selected!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WEBSOCKETS_NETWORK_SSL_CLASS
|
||||||
|
#define HAS_SSL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// moves all Header strings to Flash (~300 Byte)
|
||||||
|
#ifdef WEBSOCKETS_SAVE_RAM
|
||||||
|
#define WEBSOCKETS_STRING(var) F(var)
|
||||||
|
#else
|
||||||
|
#define WEBSOCKETS_STRING(var) var
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WSC_NOT_CONNECTED,
|
WSC_NOT_CONNECTED,
|
||||||
WSC_HEADER,
|
WSC_HEADER,
|
||||||
|
WSC_BODY,
|
||||||
WSC_CONNECTED
|
WSC_CONNECTED
|
||||||
} WSclientsStatus_t;
|
} WSclientsStatus_t;
|
||||||
|
|
||||||
@ -123,103 +226,142 @@ typedef enum {
|
|||||||
WStype_DISCONNECTED,
|
WStype_DISCONNECTED,
|
||||||
WStype_CONNECTED,
|
WStype_CONNECTED,
|
||||||
WStype_TEXT,
|
WStype_TEXT,
|
||||||
WStype_BIN
|
WStype_BIN,
|
||||||
|
WStype_FRAGMENT_TEXT_START,
|
||||||
|
WStype_FRAGMENT_BIN_START,
|
||||||
|
WStype_FRAGMENT,
|
||||||
|
WStype_FRAGMENT_FIN,
|
||||||
|
WStype_PING,
|
||||||
|
WStype_PONG,
|
||||||
} WStype_t;
|
} WStype_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WSop_continuation = 0x00, ///< %x0 denotes a continuation frame
|
WSop_continuation = 0x00, ///< %x0 denotes a continuation frame
|
||||||
WSop_text = 0x01, ///< %x1 denotes a text frame
|
WSop_text = 0x01, ///< %x1 denotes a text frame
|
||||||
WSop_binary = 0x02, ///< %x2 denotes a binary frame
|
WSop_binary = 0x02, ///< %x2 denotes a binary frame
|
||||||
///< %x3-7 are reserved for further non-control frames
|
///< %x3-7 are reserved for further non-control frames
|
||||||
WSop_close = 0x08, ///< %x8 denotes a connection close
|
WSop_close = 0x08, ///< %x8 denotes a connection close
|
||||||
WSop_ping = 0x09, ///< %x9 denotes a ping
|
WSop_ping = 0x09, ///< %x9 denotes a ping
|
||||||
WSop_pong = 0x0A ///< %xA denotes a pong
|
WSop_pong = 0x0A ///< %xA denotes a pong
|
||||||
///< %xB-F are reserved for further control frames
|
///< %xB-F are reserved for further control frames
|
||||||
} WSopcode_t;
|
} WSopcode_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
bool fin;
|
||||||
|
bool rsv1;
|
||||||
|
bool rsv2;
|
||||||
|
bool rsv3;
|
||||||
|
|
||||||
bool fin;
|
WSopcode_t opCode;
|
||||||
bool rsv1;
|
bool mask;
|
||||||
bool rsv2;
|
|
||||||
bool rsv3;
|
|
||||||
|
|
||||||
WSopcode_t opCode;
|
size_t payloadLen;
|
||||||
bool mask;
|
|
||||||
|
|
||||||
size_t payloadLen;
|
uint8_t * maskKey;
|
||||||
|
|
||||||
uint8_t * maskKey;
|
|
||||||
} WSMessageHeader_t;
|
} WSMessageHeader_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t num; ///< connection number
|
void init(uint8_t num,
|
||||||
|
uint32_t pingInterval,
|
||||||
|
uint32_t pongTimeout,
|
||||||
|
uint8_t disconnectTimeoutCount) {
|
||||||
|
this->num = num;
|
||||||
|
this->pingInterval = pingInterval;
|
||||||
|
this->pongTimeout = pongTimeout;
|
||||||
|
this->disconnectTimeoutCount = disconnectTimeoutCount;
|
||||||
|
}
|
||||||
|
|
||||||
WSclientsStatus_t status;
|
uint8_t num = 0; ///< connection number
|
||||||
|
|
||||||
WEBSOCKETS_NETWORK_CLASS * tcp;
|
WSclientsStatus_t status = WSC_NOT_CONNECTED;
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
WEBSOCKETS_NETWORK_CLASS * tcp = nullptr;
|
||||||
bool isSSL; ///< run in ssl mode
|
|
||||||
WiFiClientSecure * ssl;
|
bool isSocketIO = false; ///< client for socket.io server
|
||||||
|
|
||||||
|
#if defined(HAS_SSL)
|
||||||
|
bool isSSL = false; ///< run in ssl mode
|
||||||
|
WEBSOCKETS_NETWORK_SSL_CLASS * ssl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String cUrl; ///< http url
|
String cUrl; ///< http url
|
||||||
uint16_t cCode; ///< http code
|
uint16_t cCode = 0; ///< http code
|
||||||
|
|
||||||
bool cIsUpgrade; ///< Connection == Upgrade
|
bool cIsClient = false; ///< will be used for masking
|
||||||
bool cIsWebsocket; ///< Upgrade == websocket
|
bool cIsUpgrade = false; ///< Connection == Upgrade
|
||||||
|
bool cIsWebsocket = false; ///< Upgrade == websocket
|
||||||
|
|
||||||
String cKey; ///< client Sec-WebSocket-Key
|
String cSessionId; ///< client Set-Cookie (session id)
|
||||||
String cAccept; ///< client Sec-WebSocket-Accept
|
String cKey; ///< client Sec-WebSocket-Key
|
||||||
String cProtocol; ///< client Sec-WebSocket-Protocol
|
String cAccept; ///< client Sec-WebSocket-Accept
|
||||||
String cExtensions; ///< client Sec-WebSocket-Extensions
|
String cProtocol; ///< client Sec-WebSocket-Protocol
|
||||||
uint16_t cVersion; ///< client Sec-WebSocket-Version
|
String cExtensions; ///< client Sec-WebSocket-Extensions
|
||||||
|
uint16_t cVersion = 0; ///< client Sec-WebSocket-Version
|
||||||
|
|
||||||
uint8_t cWsRXsize; ///< State of the RX
|
uint8_t cWsRXsize = 0; ///< State of the RX
|
||||||
uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer
|
uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer
|
||||||
WSMessageHeader_t cWsHeaderDecode;
|
WSMessageHeader_t cWsHeaderDecode;
|
||||||
|
|
||||||
String base64Authorization; ///< Base64 encoded Auth request
|
String base64Authorization; ///< Base64 encoded Auth request
|
||||||
|
String plainAuthorization; ///< Base64 encoded Auth request
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
String extraHeaders;
|
||||||
String cHttpLine; ///< HTTP header lines
|
|
||||||
|
bool cHttpHeadersValid = false; ///< non-websocket http header validity indicator
|
||||||
|
size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count
|
||||||
|
|
||||||
|
bool pongReceived = false;
|
||||||
|
uint32_t pingInterval = 0; // how often ping will be sent, 0 means "heartbeat is not active"
|
||||||
|
uint32_t lastPing = 0; // millis when last pong has been received
|
||||||
|
uint32_t pongTimeout = 0; // interval in millis after which pong is considered to timeout
|
||||||
|
uint8_t disconnectTimeoutCount = 0; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect"
|
||||||
|
uint8_t pongTimeoutCount = 0; // current pong timeout count
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
String cHttpLine; ///< HTTP header lines
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} WSclient_t;
|
} WSclient_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebSockets {
|
class WebSockets {
|
||||||
protected:
|
protected:
|
||||||
#ifdef __AVR__
|
#ifdef __AVR__
|
||||||
typedef void (*WSreadWaitCb)(WSclient_t * client, bool ok);
|
typedef void (*WSreadWaitCb)(WSclient_t * client, bool ok);
|
||||||
#else
|
#else
|
||||||
typedef std::function<void(WSclient_t * client, bool ok)> WSreadWaitCb;
|
typedef std::function<void(WSclient_t * client, bool ok)> WSreadWaitCb;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virtual void clientDisconnect(WSclient_t * client);
|
virtual void clientDisconnect(WSclient_t * client) = 0;
|
||||||
virtual bool clientIsConnected(WSclient_t * client);
|
virtual bool clientIsConnected(WSclient_t * client) = 0;
|
||||||
|
|
||||||
virtual void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
|
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
|
virtual void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) = 0;
|
||||||
bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool mask = false, bool fin = true, bool headerToPayload = false);
|
|
||||||
|
|
||||||
void headerDone(WSclient_t * client);
|
uint8_t createHeader(uint8_t * buf, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin);
|
||||||
|
bool sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length = 0, bool fin = true);
|
||||||
|
bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool fin = true, bool headerToPayload = false);
|
||||||
|
|
||||||
void handleWebsocket(WSclient_t * client);
|
void headerDone(WSclient_t * client);
|
||||||
|
|
||||||
bool handleWebsocketWaitFor(WSclient_t * client, size_t size);
|
void handleWebsocket(WSclient_t * client);
|
||||||
void handleWebsocketCb(WSclient_t * client);
|
|
||||||
void handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload);
|
|
||||||
|
|
||||||
String acceptKey(String & clientKey);
|
bool handleWebsocketWaitFor(WSclient_t * client, size_t size);
|
||||||
String base64_encode(uint8_t * data, size_t length);
|
void handleWebsocketCb(WSclient_t * client);
|
||||||
|
void handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload);
|
||||||
|
|
||||||
bool readCb(WSclient_t * client, uint8_t *out, size_t n, WSreadWaitCb cb);
|
String acceptKey(String & clientKey);
|
||||||
|
String base64_encode(uint8_t * data, size_t length);
|
||||||
|
|
||||||
|
bool readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb);
|
||||||
|
virtual size_t write(WSclient_t * client, uint8_t * out, size_t n);
|
||||||
|
size_t write(WSclient_t * client, const char * out);
|
||||||
|
|
||||||
|
void enableHeartbeat(WSclient_t * client, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
||||||
|
void handleHBTimeout(WSclient_t * client);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef UNUSED
|
||||||
|
#define UNUSED(var) (void)(var)
|
||||||
|
#endif
|
||||||
#endif /* WEBSOCKETS_H_ */
|
#endif /* WEBSOCKETS_H_ */
|
||||||
|
80
src/WebSockets4WebServer.h
Normal file
80
src/WebSockets4WebServer.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* @file WebSocketsServer.cpp
|
||||||
|
* @date 28.10.2020
|
||||||
|
* @author Markus Sattler & esp8266/arduino community
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Markus Sattler. All rights reserved.
|
||||||
|
* This file is part of the WebSockets for Arduino.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WEBSOCKETS4WEBSERVER_H
|
||||||
|
#define __WEBSOCKETS4WEBSERVER_H
|
||||||
|
|
||||||
|
#include <WebSocketsServer.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
|
||||||
|
#if WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
|
||||||
|
|
||||||
|
class WebSockets4WebServer : public WebSocketsServerCore {
|
||||||
|
public:
|
||||||
|
WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino")
|
||||||
|
: WebSocketsServerCore(origin, protocol) {
|
||||||
|
begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP8266WebServer::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) {
|
||||||
|
onEvent(event);
|
||||||
|
|
||||||
|
return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, ESP8266WebServer::ContentTypeFunction contentType) {
|
||||||
|
(void)contentType;
|
||||||
|
|
||||||
|
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
|
||||||
|
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients())
|
||||||
|
WEBSOCKETS_NETWORK_CLASS * newTcpClient = new WEBSOCKETS_NETWORK_CLASS(*tcpClient);
|
||||||
|
|
||||||
|
// Then initialize a new WSclient_t (like in WebSocketsServer::handleNewClient())
|
||||||
|
WSclient_t * client = handleNewClient(newTcpClient);
|
||||||
|
|
||||||
|
if(client) {
|
||||||
|
// give "GET <url>"
|
||||||
|
String headerLine;
|
||||||
|
headerLine.reserve(url.length() + 5);
|
||||||
|
headerLine = "GET ";
|
||||||
|
headerLine += url;
|
||||||
|
handleHeader(client, &headerLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell webserver to not close but forget about this client
|
||||||
|
return ESP8266WebServer::CLIENT_IS_GIVEN;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
|
||||||
|
|
||||||
|
#ifndef WEBSERVER_HAS_HOOK
|
||||||
|
#error Your current Framework / Arduino core version does not support Webserver Hook Functions
|
||||||
|
#else
|
||||||
|
#error Your Hardware Platform does not support Webserver Hook Functions
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
|
||||||
|
|
||||||
|
#endif // __WEBSOCKETS4WEBSERVER_H
|
@ -25,10 +25,14 @@
|
|||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
#include "WebSocketsClient.h"
|
#include "WebSocketsClient.h"
|
||||||
|
|
||||||
|
|
||||||
WebSocketsClient::WebSocketsClient() {
|
WebSocketsClient::WebSocketsClient() {
|
||||||
_cbEvent = NULL;
|
_cbEvent = NULL;
|
||||||
_client.num = 0;
|
_client.num = 0;
|
||||||
|
_client.cIsClient = true;
|
||||||
|
_client.extraHeaders = WEBSOCKETS_STRING("Origin: file://");
|
||||||
|
_reconnectInterval = 500;
|
||||||
|
_port = 0;
|
||||||
|
_host = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketsClient::~WebSocketsClient() {
|
WebSocketsClient::~WebSocketsClient() {
|
||||||
@ -38,30 +42,37 @@ WebSocketsClient::~WebSocketsClient() {
|
|||||||
/**
|
/**
|
||||||
* calles to init the Websockets server
|
* calles to init the Websockets server
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::begin(const char *host, uint16_t port, const char * url, const char * protocol) {
|
void WebSocketsClient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||||
_host = host;
|
_host = host;
|
||||||
_port = port;
|
_port = port;
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if defined(HAS_SSL)
|
||||||
_fingerprint = "";
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
_CA_cert = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_client.num = 0;
|
_client.num = 0;
|
||||||
_client.status = WSC_NOT_CONNECTED;
|
_client.status = WSC_NOT_CONNECTED;
|
||||||
_client.tcp = NULL;
|
_client.tcp = NULL;
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if defined(HAS_SSL)
|
||||||
_client.isSSL = false;
|
_client.isSSL = false;
|
||||||
_client.ssl = NULL;
|
_client.ssl = NULL;
|
||||||
#endif
|
#endif
|
||||||
_client.cUrl = url;
|
_client.cUrl = url;
|
||||||
_client.cCode = 0;
|
_client.cCode = 0;
|
||||||
_client.cIsUpgrade = false;
|
_client.cIsUpgrade = false;
|
||||||
_client.cIsWebsocket = true;
|
_client.cIsWebsocket = true;
|
||||||
_client.cKey = "";
|
_client.cKey = "";
|
||||||
_client.cAccept = "";
|
_client.cAccept = "";
|
||||||
_client.cProtocol = protocol;
|
_client.cProtocol = protocol;
|
||||||
_client.cExtensions = "";
|
_client.cExtensions = "";
|
||||||
_client.cVersion = 0;
|
_client.cVersion = 0;
|
||||||
_client.base64Authorization = "";
|
_client.base64Authorization = "";
|
||||||
|
_client.plainAuthorization = "";
|
||||||
|
_client.isSocketIO = false;
|
||||||
|
|
||||||
|
_client.lastPing = 0;
|
||||||
|
_client.pongReceived = false;
|
||||||
|
_client.pongTimeoutCount = 0;
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
randomSeed(RANDOM_REG32);
|
randomSeed(RANDOM_REG32);
|
||||||
@ -69,36 +80,135 @@ void WebSocketsClient::begin(const char *host, uint16_t port, const char * url,
|
|||||||
// todo find better seed
|
// todo find better seed
|
||||||
randomSeed(millis());
|
randomSeed(millis());
|
||||||
#endif
|
#endif
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
asyncConnect();
|
asyncConnect();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
_lastConnectionFail = 0;
|
||||||
|
_lastHeaderSent = 0;
|
||||||
|
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] Websocket Version: " WEBSOCKETS_VERSION "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
|
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
|
||||||
begin(host.c_str(), port, url.c_str(), protocol.c_str());
|
begin(host.c_str(), port, url.c_str(), protocol.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
void WebSocketsClient::begin(IPAddress host, uint16_t port, const char * url, const char * protocol) {
|
||||||
void WebSocketsClient::beginSSL(const char *host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) {
|
return begin(host.toString().c_str(), port, url, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAS_SSL)
|
||||||
|
#if defined(SSL_AXTLS)
|
||||||
|
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) {
|
||||||
begin(host, port, url, protocol);
|
begin(host, port, url, protocol);
|
||||||
_client.isSSL = true;
|
_client.isSSL = true;
|
||||||
_fingerprint = fingerprint;
|
_fingerprint = fingerprint;
|
||||||
|
_CA_cert = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) {
|
void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) {
|
||||||
beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str(), protocol.c_str());
|
beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str(), protocol.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
_CA_cert = CA_cert;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const uint8_t * fingerprint, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = fingerprint;
|
||||||
|
_CA_cert = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
_CA_cert = CA_cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||||
|
beginSslWithCA(host, port, url, new BearSSL::X509List(CA_cert), protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) {
|
||||||
|
_client_cert = clientCert;
|
||||||
|
_client_key = clientPrivateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
|
||||||
|
setSSLClientCertKey(new BearSSL::X509List(clientCert), new BearSSL::PrivateKey(clientPrivateKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SSL_AXTLS
|
||||||
|
#endif // HAS_SSL
|
||||||
|
|
||||||
|
void WebSocketsClient::beginSocketIO(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSocketIO = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::beginSocketIO(String host, uint16_t port, String url, String protocol) {
|
||||||
|
beginSocketIO(host.c_str(), port, url.c_str(), protocol.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAS_SSL)
|
||||||
|
void WebSocketsClient::beginSocketIOSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSocketIO = true;
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) {
|
||||||
|
beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
|
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSocketIO = true;
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
_CA_cert = CA_cert;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
|
||||||
|
begin(host, port, url, protocol);
|
||||||
|
_client.isSocketIO = true;
|
||||||
|
_client.isSSL = true;
|
||||||
|
_fingerprint = SSL_FINGERPRINT_NULL;
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
|
_CA_cert = new BearSSL::X509List(CA_cert);
|
||||||
|
#else
|
||||||
|
_CA_cert = CA_cert;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#endif
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
/**
|
/**
|
||||||
* called in arduino loop
|
* called in arduino loop
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::loop(void) {
|
void WebSocketsClient::loop(void) {
|
||||||
|
if(_port == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
if(!clientIsConnected(&_client)) {
|
if(!clientIsConnected(&_client)) {
|
||||||
|
// do not flood the server
|
||||||
|
if((millis() - _lastConnectionFail) < _reconnectInterval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if defined(HAS_SSL)
|
||||||
if(_client.isSSL) {
|
if(_client.isSSL) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n");
|
DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n");
|
||||||
if(_client.ssl) {
|
if(_client.ssl) {
|
||||||
@ -106,15 +216,40 @@ void WebSocketsClient::loop(void) {
|
|||||||
_client.ssl = NULL;
|
_client.ssl = NULL;
|
||||||
_client.tcp = NULL;
|
_client.tcp = NULL;
|
||||||
}
|
}
|
||||||
_client.ssl = new WiFiClientSecure();
|
_client.ssl = new WEBSOCKETS_NETWORK_SSL_CLASS();
|
||||||
_client.tcp = _client.ssl;
|
_client.tcp = _client.ssl;
|
||||||
|
if(_CA_cert) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate");
|
||||||
|
#if defined(ESP32)
|
||||||
|
_client.ssl->setCACert(_CA_cert);
|
||||||
|
#elif defined(ESP8266) && defined(SSL_AXTLS)
|
||||||
|
_client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
|
||||||
|
#elif defined(ESP8266) && defined(SSL_BARESSL)
|
||||||
|
_client.ssl->setTrustAnchors(_CA_cert);
|
||||||
|
#else
|
||||||
|
#error setCACert not implemented
|
||||||
|
#endif
|
||||||
|
#if defined(ESP32)
|
||||||
|
} else if(!SSL_FINGERPRINT_IS_SET) {
|
||||||
|
_client.ssl->setInsecure();
|
||||||
|
#elif defined(SSL_BARESSL)
|
||||||
|
} else if(SSL_FINGERPRINT_IS_SET) {
|
||||||
|
_client.ssl->setFingerprint(_fingerprint);
|
||||||
|
} else {
|
||||||
|
_client.ssl->setInsecure();
|
||||||
|
}
|
||||||
|
if(_client_cert && _client_key) {
|
||||||
|
_client.ssl->setClientRSACert(_client_cert, _client_key);
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] setting client certificate and key");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n");
|
DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n");
|
||||||
if(_client.tcp) {
|
if(_client.tcp) {
|
||||||
delete _client.tcp;
|
delete _client.tcp;
|
||||||
_client.tcp = NULL;
|
_client.tcp = NULL;
|
||||||
}
|
}
|
||||||
_client.tcp = new WiFiClient();
|
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
|
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
|
||||||
@ -124,15 +259,25 @@ void WebSocketsClient::loop(void) {
|
|||||||
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
|
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
|
#if defined(ESP32)
|
||||||
|
if(_client.tcp->connect(_host.c_str(), _port, WEBSOCKETS_TCP_TIMEOUT)) {
|
||||||
|
#else
|
||||||
if(_client.tcp->connect(_host.c_str(), _port)) {
|
if(_client.tcp->connect(_host.c_str(), _port)) {
|
||||||
|
#endif
|
||||||
connectedCb();
|
connectedCb();
|
||||||
|
_lastConnectionFail = 0;
|
||||||
} else {
|
} else {
|
||||||
connectFailedCb();
|
connectFailedCb();
|
||||||
delay(10); //some little delay to not flood the server
|
_lastConnectionFail = millis();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleClientData();
|
handleClientData();
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
|
if(_client.status == WSC_CONNECTED) {
|
||||||
|
handleHBPing();
|
||||||
|
handleHBTimeout(&_client);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -155,28 +300,34 @@ void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) {
|
|||||||
*/
|
*/
|
||||||
bool WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
if(length == 0) {
|
if(length == 0) {
|
||||||
length = strlen((const char *) payload);
|
length = strlen((const char *)payload);
|
||||||
}
|
}
|
||||||
if(clientIsConnected(&_client)) {
|
if(clientIsConnected(&_client)) {
|
||||||
return sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload);
|
return sendFrame(&_client, WSop_text, payload, length, true, headerToPayload);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) {
|
bool WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) {
|
||||||
return sendTXT((uint8_t *) payload, length);
|
return sendTXT((uint8_t *)payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) {
|
||||||
return sendTXT((uint8_t *) payload, length, headerToPayload);
|
return sendTXT((uint8_t *)payload, length, headerToPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendTXT(const char * payload, size_t length) {
|
bool WebSocketsClient::sendTXT(const char * payload, size_t length) {
|
||||||
return sendTXT((uint8_t *) payload, length);
|
return sendTXT((uint8_t *)payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendTXT(String & payload) {
|
bool WebSocketsClient::sendTXT(String & payload) {
|
||||||
return sendTXT((uint8_t *) payload.c_str(), payload.length());
|
return sendTXT((uint8_t *)payload.c_str(), payload.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebSocketsClient::sendTXT(char payload) {
|
||||||
|
uint8_t buf[WEBSOCKETS_MAX_HEADER_SIZE + 2] = { 0x00 };
|
||||||
|
buf[WEBSOCKETS_MAX_HEADER_SIZE] = payload;
|
||||||
|
return sendTXT(buf, 1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,13 +340,33 @@ bool WebSocketsClient::sendTXT(String & payload) {
|
|||||||
*/
|
*/
|
||||||
bool WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
bool WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
if(clientIsConnected(&_client)) {
|
if(clientIsConnected(&_client)) {
|
||||||
return sendFrame(&_client, WSop_binary, payload, length, true, true, headerToPayload);
|
return sendFrame(&_client, WSop_binary, payload, length, true, headerToPayload);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) {
|
bool WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) {
|
||||||
return sendBIN((uint8_t *) payload, length);
|
return sendBIN((uint8_t *)payload, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a WS ping to Server
|
||||||
|
* @param payload uint8_t *
|
||||||
|
* @param length size_t
|
||||||
|
* @return true if ping is send out
|
||||||
|
*/
|
||||||
|
bool WebSocketsClient::sendPing(uint8_t * payload, size_t length) {
|
||||||
|
if(clientIsConnected(&_client)) {
|
||||||
|
bool sent = sendFrame(&_client, WSop_ping, payload, length);
|
||||||
|
if(sent)
|
||||||
|
_client.lastPing = millis();
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebSocketsClient::sendPing(String & payload) {
|
||||||
|
return sendPing((uint8_t *)payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,10 +399,33 @@ void WebSocketsClient::setAuthorization(const char * user, const char * password
|
|||||||
*/
|
*/
|
||||||
void WebSocketsClient::setAuthorization(const char * auth) {
|
void WebSocketsClient::setAuthorization(const char * auth) {
|
||||||
if(auth) {
|
if(auth) {
|
||||||
_client.base64Authorization = auth;
|
//_client.base64Authorization = auth;
|
||||||
|
_client.plainAuthorization = auth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set extra headers for the http request;
|
||||||
|
* separate headers by "\r\n"
|
||||||
|
* @param extraHeaders const char * extraHeaders
|
||||||
|
*/
|
||||||
|
void WebSocketsClient::setExtraHeaders(const char * extraHeaders) {
|
||||||
|
_client.extraHeaders = extraHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the reconnect Interval
|
||||||
|
* how long to wait after a connection initiate failed
|
||||||
|
* @param time in ms
|
||||||
|
*/
|
||||||
|
void WebSocketsClient::setReconnectInterval(unsigned long time) {
|
||||||
|
_reconnectInterval = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebSocketsClient::isConnected(void) {
|
||||||
|
return (_client.status == WSC_CONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
@ -241,22 +435,35 @@ void WebSocketsClient::setAuthorization(const char * auth) {
|
|||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
* @param opcode WSopcode_t
|
* @param opcode WSopcode_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param lenght size_t
|
* @param length size_t
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) {
|
void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
|
||||||
WStype_t type = WStype_ERROR;
|
WStype_t type = WStype_ERROR;
|
||||||
|
|
||||||
|
UNUSED(client);
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case WSop_text:
|
case WSop_text:
|
||||||
type = WStype_TEXT;
|
type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
|
||||||
break;
|
break;
|
||||||
case WSop_binary:
|
case WSop_binary:
|
||||||
type = WStype_BIN;
|
type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START;
|
||||||
|
break;
|
||||||
|
case WSop_continuation:
|
||||||
|
type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT;
|
||||||
|
break;
|
||||||
|
case WSop_ping:
|
||||||
|
type = WStype_PING;
|
||||||
|
break;
|
||||||
|
case WSop_pong:
|
||||||
|
type = WStype_PONG;
|
||||||
|
break;
|
||||||
|
case WSop_close:
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
runCbEvent(type, payload, lenght);
|
runCbEvent(type, payload, length);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -264,10 +471,9 @@ void WebSocketsClient::messageRecived(WSclient_t * client, WSopcode_t opcode, ui
|
|||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
||||||
|
|
||||||
bool event = false;
|
bool event = false;
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||||
if(client->isSSL && client->ssl) {
|
if(client->isSSL && client->ssl) {
|
||||||
if(client->ssl->connected()) {
|
if(client->ssl->connected()) {
|
||||||
client->ssl->flush();
|
client->ssl->flush();
|
||||||
@ -282,13 +488,13 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
|||||||
|
|
||||||
if(client->tcp) {
|
if(client->tcp) {
|
||||||
if(client->tcp->connected()) {
|
if(client->tcp->connected()) {
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
client->tcp->flush();
|
client->tcp->flush();
|
||||||
#endif
|
#endif
|
||||||
client->tcp->stop();
|
client->tcp->stop();
|
||||||
}
|
}
|
||||||
event = true;
|
event = true;
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
client->status = WSC_NOT_CONNECTED;
|
client->status = WSC_NOT_CONNECTED;
|
||||||
#else
|
#else
|
||||||
delete client->tcp;
|
delete client->tcp;
|
||||||
@ -296,15 +502,16 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
|||||||
client->tcp = NULL;
|
client->tcp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
client->cCode = 0;
|
client->cCode = 0;
|
||||||
client->cKey = "";
|
client->cKey = "";
|
||||||
client->cAccept = "";
|
client->cAccept = "";
|
||||||
client->cProtocol = "";
|
client->cVersion = 0;
|
||||||
client->cVersion = 0;
|
client->cIsUpgrade = false;
|
||||||
client->cIsUpgrade = false;
|
|
||||||
client->cIsWebsocket = false;
|
client->cIsWebsocket = false;
|
||||||
|
client->cSessionId = "";
|
||||||
|
|
||||||
client->status = WSC_NOT_CONNECTED;
|
client->status = WSC_NOT_CONNECTED;
|
||||||
|
_lastConnectionFail = millis();
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
|
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
|
||||||
if(event) {
|
if(event) {
|
||||||
@ -318,7 +525,6 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
|||||||
* @return true = conneted
|
* @return true = conneted
|
||||||
*/
|
*/
|
||||||
bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
|
bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
|
||||||
|
|
||||||
if(!client->tcp) {
|
if(!client->tcp) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -343,20 +549,31 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
/**
|
/**
|
||||||
* Handel incomming data from Client
|
* Handel incomming data from Client
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::handleClientData(void) {
|
void WebSocketsClient::handleClientData(void) {
|
||||||
|
if((_client.status == WSC_HEADER || _client.status == WSC_BODY) && _lastHeaderSent + WEBSOCKETS_TCP_TIMEOUT < millis()) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleClientData] header response timeout.. disconnecting!\n");
|
||||||
|
clientDisconnect(&_client);
|
||||||
|
WEBSOCKETS_YIELD();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int len = _client.tcp->available();
|
int len = _client.tcp->available();
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
switch(_client.status) {
|
switch(_client.status) {
|
||||||
case WSC_HEADER:
|
case WSC_HEADER: {
|
||||||
{
|
|
||||||
String headerLine = _client.tcp->readStringUntil('\n');
|
String headerLine = _client.tcp->readStringUntil('\n');
|
||||||
handleHeader(&_client, &headerLine);
|
handleHeader(&_client, &headerLine);
|
||||||
}
|
} break;
|
||||||
break;
|
case WSC_BODY: {
|
||||||
|
char buf[256] = { 0 };
|
||||||
|
_client.tcp->readBytes(&buf[0], std::min((size_t)len, sizeof(buf)));
|
||||||
|
String bodyLine = buf;
|
||||||
|
handleHeader(&_client, &bodyLine);
|
||||||
|
} break;
|
||||||
case WSC_CONNECTED:
|
case WSC_CONNECTED:
|
||||||
WebSockets::handleWebsocket(&_client);
|
WebSockets::handleWebsocket(&_client);
|
||||||
break;
|
break;
|
||||||
@ -365,9 +582,7 @@ void WebSocketsClient::handleClientData(void) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
WEBSOCKETS_YIELD();
|
||||||
delay(0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -376,6 +591,7 @@ void WebSocketsClient::handleClientData(void) {
|
|||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::sendHeader(WSclient_t * client) {
|
void WebSocketsClient::sendHeader(WSclient_t * client) {
|
||||||
|
static const char * NEW_LINE = "\r\n";
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n");
|
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n");
|
||||||
|
|
||||||
@ -391,36 +607,75 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
|
|||||||
unsigned long start = micros();
|
unsigned long start = micros();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String handshake = "GET " + client->cUrl + " HTTP/1.1\r\n"
|
String handshake;
|
||||||
"Host: " + _host + "\r\n"
|
bool ws_header = true;
|
||||||
"Upgrade: websocket\r\n"
|
String url = client->cUrl;
|
||||||
"Connection: Upgrade\r\n"
|
|
||||||
"User-Agent: arduino-WebSocket-Client\r\n"
|
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
|
||||||
"Sec-WebSocket-Key: " + client->cKey + "\r\n";
|
|
||||||
|
|
||||||
if(client->cProtocol.length() > 0) {
|
if(client->isSocketIO) {
|
||||||
handshake += "Sec-WebSocket-Protocol: " + client->cProtocol + "\r\n";
|
if(client->cSessionId.length() == 0) {
|
||||||
|
url += WEBSOCKETS_STRING("&transport=polling");
|
||||||
|
ws_header = false;
|
||||||
|
} else {
|
||||||
|
url += WEBSOCKETS_STRING("&transport=websocket&sid=");
|
||||||
|
url += client->cSessionId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(client->cExtensions.length() > 0) {
|
handshake = WEBSOCKETS_STRING("GET ");
|
||||||
handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n";
|
handshake += url + WEBSOCKETS_STRING(
|
||||||
|
" HTTP/1.1\r\n"
|
||||||
|
"Host: ");
|
||||||
|
handshake += _host + ":" + _port + NEW_LINE;
|
||||||
|
|
||||||
|
if(ws_header) {
|
||||||
|
handshake += WEBSOCKETS_STRING(
|
||||||
|
"Connection: Upgrade\r\n"
|
||||||
|
"Upgrade: websocket\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"Sec-WebSocket-Key: ");
|
||||||
|
handshake += client->cKey + NEW_LINE;
|
||||||
|
|
||||||
|
if(client->cProtocol.length() > 0) {
|
||||||
|
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
|
||||||
|
handshake += client->cProtocol + NEW_LINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client->cExtensions.length() > 0) {
|
||||||
|
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Extensions: ");
|
||||||
|
handshake += client->cExtensions + NEW_LINE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handshake += WEBSOCKETS_STRING("Connection: keep-alive\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add extra headers; by default this includes "Origin: file://"
|
||||||
|
if(client->extraHeaders.length() > 0) {
|
||||||
|
handshake += client->extraHeaders + NEW_LINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
handshake += WEBSOCKETS_STRING("User-Agent: arduino-WebSocket-Client\r\n");
|
||||||
|
|
||||||
if(client->base64Authorization.length() > 0) {
|
if(client->base64Authorization.length() > 0) {
|
||||||
handshake += "Authorization: Basic " + client->base64Authorization + "\r\n";
|
handshake += WEBSOCKETS_STRING("Authorization: Basic ");
|
||||||
|
handshake += client->base64Authorization + NEW_LINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
handshake += "\r\n";
|
if(client->plainAuthorization.length() > 0) {
|
||||||
|
handshake += WEBSOCKETS_STRING("Authorization: ");
|
||||||
|
handshake += client->plainAuthorization + NEW_LINE;
|
||||||
|
}
|
||||||
|
|
||||||
client->tcp->write(handshake.c_str(), handshake.length());
|
handshake += NEW_LINE;
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] handshake %s", (uint8_t *)handshake.c_str());
|
||||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
|
write(client, (uint8_t *)handshake.c_str(), handshake.length());
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%uus).\n", (micros() - start));
|
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start));
|
||||||
|
_lastHeaderSent = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -428,46 +683,71 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
|
|||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
||||||
|
headerLine->trim(); // remove \r
|
||||||
|
|
||||||
headerLine->trim(); // remove \r
|
// this code handels the http body for Socket.IO V3 requests
|
||||||
|
if(headerLine->length() > 0 && client->isSocketIO && client->status == WSC_BODY && client->cSessionId.length() == 0) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] socket.io json: %s\n", headerLine->c_str());
|
||||||
|
String sid_begin = WEBSOCKETS_STRING("\"sid\":\"");
|
||||||
|
if(headerLine->indexOf(sid_begin) > -1) {
|
||||||
|
int start = headerLine->indexOf(sid_begin) + sid_begin.length();
|
||||||
|
int end = headerLine->indexOf('"', start);
|
||||||
|
client->cSessionId = headerLine->substring(start, end);
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
|
||||||
|
|
||||||
|
// Trigger websocket connection code path
|
||||||
|
*headerLine = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// headle HTTP header
|
||||||
if(headerLine->length() > 0) {
|
if(headerLine->length() > 0) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
|
||||||
|
|
||||||
if(headerLine->startsWith("HTTP/1.")) {
|
if(headerLine->startsWith(WEBSOCKETS_STRING("HTTP/1."))) {
|
||||||
// "HTTP/1.1 101 Switching Protocols"
|
// "HTTP/1.1 101 Switching Protocols"
|
||||||
client->cCode = headerLine->substring(9, headerLine->indexOf(' ', 9)).toInt();
|
client->cCode = headerLine->substring(9, headerLine->indexOf(' ', 9)).toInt();
|
||||||
} else if(headerLine->indexOf(':')) {
|
} else if(headerLine->indexOf(':') >= 0) {
|
||||||
String headerName = headerLine->substring(0, headerLine->indexOf(':'));
|
String headerName = headerLine->substring(0, headerLine->indexOf(':'));
|
||||||
String headerValue = headerLine->substring(headerLine->indexOf(':') + 2);
|
String headerValue = headerLine->substring(headerLine->indexOf(':') + 1);
|
||||||
|
|
||||||
if(headerName.equalsIgnoreCase("Connection")) {
|
// remove space in the beginning (RFC2616)
|
||||||
if(headerValue.indexOf("Upgrade") >= 0) {
|
if(headerValue[0] == ' ') {
|
||||||
|
headerValue.remove(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
|
||||||
|
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("upgrade"))) {
|
||||||
client->cIsUpgrade = true;
|
client->cIsUpgrade = true;
|
||||||
}
|
}
|
||||||
} else if(headerName.equalsIgnoreCase("Upgrade")) {
|
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
|
||||||
if(headerValue.equalsIgnoreCase("websocket")) {
|
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
|
||||||
client->cIsWebsocket = true;
|
client->cIsWebsocket = true;
|
||||||
}
|
}
|
||||||
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Accept")) {
|
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Accept"))) {
|
||||||
client->cAccept = headerValue;
|
client->cAccept = headerValue;
|
||||||
client->cAccept.trim(); // see rfc6455
|
client->cAccept.trim(); // see rfc6455
|
||||||
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) {
|
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
|
||||||
client->cProtocol = headerValue;
|
client->cProtocol = headerValue;
|
||||||
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) {
|
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
|
||||||
client->cExtensions = headerValue;
|
client->cExtensions = headerValue;
|
||||||
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) {
|
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
|
||||||
client->cVersion = headerValue.toInt();
|
client->cVersion = headerValue.toInt();
|
||||||
|
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) {
|
||||||
|
if(headerValue.indexOf(';') > -1) {
|
||||||
|
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
|
||||||
|
} else {
|
||||||
|
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
(*headerLine) = "";
|
(*headerLine) = "";
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
|
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n");
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n");
|
||||||
@ -483,26 +763,39 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str());
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str());
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
|
||||||
|
|
||||||
|
if(client->isSocketIO && client->cSessionId.length() == 0 && clientIsConnected(client)) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still missing cSessionId try socket.io V3\n");
|
||||||
|
client->status = WSC_BODY;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
client->status = WSC_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
||||||
|
|
||||||
if(ok) {
|
if(ok) {
|
||||||
switch(client->cCode) {
|
switch(client->cCode) {
|
||||||
case 101: ///< Switching Protocols
|
case 101: ///< Switching Protocols
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 403: ///< Forbidden
|
case 200:
|
||||||
|
if(client->isSocketIO) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 403: ///< Forbidden
|
||||||
// todo handle login
|
// todo handle login
|
||||||
default: ///< Server dont unterstand requrst
|
default: ///< Server dont unterstand requrst
|
||||||
ok = false;
|
ok = false;
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
|
||||||
clientDisconnect(client);
|
clientDisconnect(client);
|
||||||
|
_lastConnectionFail = millis();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ok) {
|
if(ok) {
|
||||||
|
|
||||||
if(client->cAccept.length() == 0) {
|
if(client->cAccept.length() == 0) {
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
} else {
|
||||||
@ -516,71 +809,92 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(ok) {
|
if(ok) {
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n");
|
||||||
headerDone(client);
|
headerDone(client);
|
||||||
|
|
||||||
|
runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
|
||||||
runCbEvent(WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length());
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
} else if(client->isSocketIO) {
|
||||||
|
if(client->cSessionId.length() > 0) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] found cSessionId\n");
|
||||||
|
if(clientIsConnected(client) && _client.tcp->available()) {
|
||||||
|
// read not needed data
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available());
|
||||||
|
while(_client.tcp->available() > 0) {
|
||||||
|
_client.tcp->read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendHeader(client);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
||||||
client->tcp->write("This is a webSocket client!");
|
_lastConnectionFail = millis();
|
||||||
|
if(clientIsConnected(client)) {
|
||||||
|
write(client, "This is a webSocket client!");
|
||||||
|
}
|
||||||
clientDisconnect(client);
|
clientDisconnect(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsClient::connectedCb() {
|
void WebSocketsClient::connectedCb() {
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n", _host.c_str(), _port);
|
DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n", _host.c_str(), _port);
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
_client.tcp->onDisconnect(std::bind([](WebSocketsClient * c, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
|
_client.tcp->onDisconnect(std::bind([](WebSocketsClient * c, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
|
||||||
client->status = WSC_NOT_CONNECTED;
|
client->status = WSC_NOT_CONNECTED;
|
||||||
client->tcp = NULL;
|
client->tcp = NULL;
|
||||||
|
|
||||||
// reconnect
|
// reconnect
|
||||||
c->asyncConnect();
|
c->asyncConnect();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, this, std::placeholders::_1, &_client));
|
},
|
||||||
|
this, std::placeholders::_1, &_client));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_client.status = WSC_HEADER;
|
_client.status = WSC_HEADER;
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
// set Timeout for readBytesUntil and readStringUntil
|
// set Timeout for readBytesUntil and readStringUntil
|
||||||
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||||
_client.tcp->setNoDelay(true);
|
_client.tcp->setNoDelay(true);
|
||||||
|
#endif
|
||||||
|
|
||||||
if(_client.isSSL && _fingerprint.length()) {
|
#if defined(HAS_SSL)
|
||||||
|
#if defined(SSL_AXTLS) || defined(ESP32)
|
||||||
|
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
|
||||||
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
||||||
WebSockets::clientDisconnect(&_client, 1000);
|
WebSockets::clientDisconnect(&_client, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
|
||||||
|
#endif
|
||||||
|
} else if(_client.isSSL && !_CA_cert) {
|
||||||
|
#if defined(SSL_BARESSL)
|
||||||
|
_client.ssl->setInsecure();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// send Header to Server
|
// send Header to Server
|
||||||
sendHeader(&_client);
|
sendHeader(&_client);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WebSocketsClient::connectFailedCb() {
|
void WebSocketsClient::connectFailedCb() {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Faild\n", _host.c_str(), _port);
|
DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Failed\n", _host.c_str(), _port);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
|
||||||
void WebSocketsClient::asyncConnect() {
|
void WebSocketsClient::asyncConnect() {
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] asyncConnect...\n");
|
DEBUG_WEBSOCKETS("[WS-Client] asyncConnect...\n");
|
||||||
|
|
||||||
AsyncClient * tcpclient = new AsyncClient();
|
AsyncClient * tcpclient = new AsyncClient();
|
||||||
@ -590,12 +904,12 @@ void WebSocketsClient::asyncConnect() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpclient->onDisconnect([](void *obj, AsyncClient* c) {
|
tcpclient->onDisconnect([](void * obj, AsyncClient * c) {
|
||||||
c->free();
|
c->free();
|
||||||
delete c;
|
delete c;
|
||||||
});
|
});
|
||||||
|
|
||||||
tcpclient->onConnect(std::bind([](WebSocketsClient * ws , AsyncClient * tcp) {
|
tcpclient->onConnect(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
|
||||||
ws->_client.tcp = new AsyncTCPbuffer(tcp);
|
ws->_client.tcp = new AsyncTCPbuffer(tcp);
|
||||||
if(!ws->_client.tcp) {
|
if(!ws->_client.tcp) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!\n");
|
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!\n");
|
||||||
@ -603,23 +917,57 @@ void WebSocketsClient::asyncConnect() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ws->connectedCb();
|
ws->connectedCb();
|
||||||
}, this, std::placeholders::_2));
|
},
|
||||||
|
this, std::placeholders::_2));
|
||||||
|
|
||||||
tcpclient->onError(std::bind([](WebSocketsClient * ws , AsyncClient * tcp) {
|
tcpclient->onError(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
|
||||||
ws->connectFailedCb();
|
ws->connectFailedCb();
|
||||||
|
|
||||||
// reconnect
|
// reconnect
|
||||||
ws->asyncConnect();
|
ws->asyncConnect();
|
||||||
}, this, std::placeholders::_2));
|
},
|
||||||
|
this, std::placeholders::_2));
|
||||||
|
|
||||||
if(!tcpclient->connect(_host.c_str(), _port)) {
|
if(!tcpclient->connect(_host.c_str(), _port)) {
|
||||||
connectFailedCb();
|
connectFailedCb();
|
||||||
delete tcpclient;
|
delete tcpclient;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send heartbeat ping to server in set intervals
|
||||||
|
*/
|
||||||
|
void WebSocketsClient::handleHBPing() {
|
||||||
|
if(_client.pingInterval == 0)
|
||||||
|
return;
|
||||||
|
uint32_t pi = millis() - _client.lastPing;
|
||||||
|
if(pi > _client.pingInterval) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] sending HB ping\n");
|
||||||
|
if(sendPing()) {
|
||||||
|
_client.lastPing = millis();
|
||||||
|
_client.pongReceived = false;
|
||||||
|
} else {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] sending HB ping failed\n");
|
||||||
|
WebSockets::clientDisconnect(&_client, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enable ping/pong heartbeat process
|
||||||
|
* @param pingInterval uint32_t how often ping will be sent
|
||||||
|
* @param pongTimeout uint32_t millis after which pong should timout if not received
|
||||||
|
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
|
||||||
|
*/
|
||||||
|
void WebSocketsClient::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
|
||||||
|
WebSockets::enableHeartbeat(&_client, pingInterval, pongTimeout, disconnectTimeoutCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disable ping/pong heartbeat process
|
||||||
|
*/
|
||||||
|
void WebSocketsClient::disableHeartbeat() {
|
||||||
|
_client.pingInterval = 0;
|
||||||
|
}
|
||||||
|
@ -25,94 +25,145 @@
|
|||||||
#ifndef WEBSOCKETSCLIENT_H_
|
#ifndef WEBSOCKETSCLIENT_H_
|
||||||
#define WEBSOCKETSCLIENT_H_
|
#define WEBSOCKETSCLIENT_H_
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
|
|
||||||
class WebSocketsClient: private WebSockets {
|
class WebSocketsClient : protected WebSockets {
|
||||||
public:
|
public:
|
||||||
#ifdef __AVR__
|
#ifdef __AVR__
|
||||||
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
|
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
|
||||||
#else
|
#else
|
||||||
typedef std::function<void (WStype_t type, uint8_t * payload, size_t length)> WebSocketClientEvent;
|
typedef std::function<void(WStype_t type, uint8_t * payload, size_t length)> WebSocketClientEvent;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
WebSocketsClient(void);
|
||||||
|
virtual ~WebSocketsClient(void);
|
||||||
|
|
||||||
WebSocketsClient(void);
|
void begin(const char * host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
||||||
~WebSocketsClient(void);
|
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
|
||||||
|
void begin(IPAddress host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
||||||
|
|
||||||
void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
|
#if defined(HAS_SSL)
|
||||||
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
|
#ifdef SSL_AXTLS
|
||||||
|
void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * fingerprint = "", const char * protocol = "arduino");
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
|
||||||
void beginSSL(const char *host, uint16_t port, const char * url = "/", const char * = "", const char * protocol = "arduino");
|
|
||||||
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
void loop(void);
|
|
||||||
#else
|
#else
|
||||||
// Async interface not need a loop call
|
void beginSSL(const char * host, uint16_t port, const char * url = "/", const uint8_t * fingerprint = NULL, const char * protocol = "arduino");
|
||||||
void loop(void) __attribute__ ((deprecated)) {}
|
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
|
void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL);
|
||||||
|
void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL);
|
||||||
|
#endif
|
||||||
|
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void onEvent(WebSocketClientEvent cbEvent);
|
void beginSocketIO(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||||
|
void beginSocketIO(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||||
|
|
||||||
bool sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
#if defined(HAS_SSL)
|
||||||
bool sendTXT(const uint8_t * payload, size_t length = 0);
|
void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
|
||||||
bool sendTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
|
||||||
bool sendTXT(const char * payload, size_t length = 0);
|
|
||||||
bool sendTXT(String & payload);
|
|
||||||
|
|
||||||
bool sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
bool sendBIN(const uint8_t * payload, size_t length);
|
#if defined(SSL_BARESSL)
|
||||||
|
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
|
||||||
void disconnect(void);
|
|
||||||
|
|
||||||
void setAuthorization(const char * user, const char * password);
|
|
||||||
void setAuthorization(const char * auth);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
String _host;
|
|
||||||
uint16_t _port;
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
|
||||||
String _fingerprint;
|
|
||||||
#endif
|
#endif
|
||||||
WSclient_t _client;
|
|
||||||
|
|
||||||
WebSocketClientEvent _cbEvent;
|
|
||||||
|
|
||||||
void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
|
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client);
|
|
||||||
bool clientIsConnected(WSclient_t * client);
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
void handleClientData(void);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void sendHeader(WSclient_t * client);
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
void handleHeader(WSclient_t * client, String * headerLine);
|
void loop(void);
|
||||||
|
#else
|
||||||
void connectedCb();
|
// Async interface not need a loop call
|
||||||
void connectFailedCb();
|
void loop(void) __attribute__((deprecated)) {}
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
void asyncConnect();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
void onEvent(WebSocketClientEvent cbEvent);
|
||||||
|
|
||||||
|
bool sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool sendTXT(const uint8_t * payload, size_t length = 0);
|
||||||
|
bool sendTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool sendTXT(const char * payload, size_t length = 0);
|
||||||
|
bool sendTXT(String & payload);
|
||||||
|
bool sendTXT(char payload);
|
||||||
|
|
||||||
|
bool sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
||||||
|
bool sendBIN(const uint8_t * payload, size_t length);
|
||||||
|
|
||||||
|
bool sendPing(uint8_t * payload = NULL, size_t length = 0);
|
||||||
|
bool sendPing(String & payload);
|
||||||
|
|
||||||
|
void disconnect(void);
|
||||||
|
|
||||||
|
void setAuthorization(const char * user, const char * password);
|
||||||
|
void setAuthorization(const char * auth);
|
||||||
|
|
||||||
|
void setExtraHeaders(const char * extraHeaders = NULL);
|
||||||
|
|
||||||
|
void setReconnectInterval(unsigned long time);
|
||||||
|
|
||||||
|
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
||||||
|
void disableHeartbeat();
|
||||||
|
|
||||||
|
bool isConnected(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
String _host;
|
||||||
|
uint16_t _port;
|
||||||
|
|
||||||
|
#if defined(HAS_SSL)
|
||||||
|
#ifdef SSL_AXTLS
|
||||||
|
String _fingerprint;
|
||||||
|
const char * _CA_cert;
|
||||||
|
#define SSL_FINGERPRINT_IS_SET (_fingerprint.length())
|
||||||
|
#define SSL_FINGERPRINT_NULL ""
|
||||||
|
#else
|
||||||
|
const uint8_t * _fingerprint;
|
||||||
|
BearSSL::X509List * _CA_cert;
|
||||||
|
BearSSL::X509List * _client_cert;
|
||||||
|
BearSSL::PrivateKey * _client_key;
|
||||||
|
#define SSL_FINGERPRINT_IS_SET (_fingerprint != NULL)
|
||||||
|
#define SSL_FINGERPRINT_NULL NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
WSclient_t _client;
|
||||||
|
|
||||||
|
WebSocketClientEvent _cbEvent;
|
||||||
|
|
||||||
|
unsigned long _lastConnectionFail;
|
||||||
|
unsigned long _reconnectInterval;
|
||||||
|
unsigned long _lastHeaderSent;
|
||||||
|
|
||||||
|
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
||||||
|
|
||||||
|
void clientDisconnect(WSclient_t * client);
|
||||||
|
bool clientIsConnected(WSclient_t * client);
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
void handleClientData(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void sendHeader(WSclient_t * client);
|
||||||
|
void handleHeader(WSclient_t * client, String * headerLine);
|
||||||
|
|
||||||
|
void connectedCb();
|
||||||
|
void connectFailedCb();
|
||||||
|
|
||||||
|
void handleHBPing(); // send ping in specified intervals
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
||||||
|
void asyncConnect();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
* called for sending a Event to the app
|
* called for sending a Event to the app
|
||||||
* @param type WStype_t
|
* @param type WStype_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
*/
|
*/
|
||||||
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
if(_cbEvent) {
|
if(_cbEvent) {
|
||||||
_cbEvent(type, payload, length);
|
_cbEvent(type, payload, length);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* WEBSOCKETSCLIENT_H_ */
|
#endif /* WEBSOCKETSCLIENT_H_ */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -25,145 +25,219 @@
|
|||||||
#ifndef WEBSOCKETSSERVER_H_
|
#ifndef WEBSOCKETSSERVER_H_
|
||||||
#define WEBSOCKETSSERVER_H_
|
#define WEBSOCKETSSERVER_H_
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
|
|
||||||
#define WEBSOCKETS_SERVER_CLIENT_MAX (5)
|
#ifndef WEBSOCKETS_SERVER_CLIENT_MAX
|
||||||
|
#define WEBSOCKETS_SERVER_CLIENT_MAX (5)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class WebSocketsServerCore : protected WebSockets {
|
||||||
|
public:
|
||||||
|
WebSocketsServerCore(const String & origin = "", const String & protocol = "arduino");
|
||||||
|
virtual ~WebSocketsServerCore(void);
|
||||||
|
|
||||||
|
void begin(void);
|
||||||
|
void close(void);
|
||||||
class WebSocketsServer: private WebSockets {
|
|
||||||
public:
|
|
||||||
|
|
||||||
#ifdef __AVR__
|
#ifdef __AVR__
|
||||||
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
|
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
|
||||||
|
typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue);
|
||||||
#else
|
#else
|
||||||
typedef std::function<void (uint8_t num, WStype_t type, uint8_t * payload, size_t length)> WebSocketServerEvent;
|
typedef std::function<void(uint8_t num, WStype_t type, uint8_t * payload, size_t length)> WebSocketServerEvent;
|
||||||
|
typedef std::function<bool(String headerName, String headerValue)> WebSocketServerHttpHeaderValFunc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WebSocketsServer(uint16_t port, String origin = "", String protocol = "arduino");
|
void onEvent(WebSocketServerEvent cbEvent);
|
||||||
~WebSocketsServer(void);
|
void onValidateHttpHeader(
|
||||||
|
WebSocketServerHttpHeaderValFunc validationFunc,
|
||||||
|
const char * mandatoryHttpHeaders[],
|
||||||
|
size_t mandatoryHttpHeaderCount);
|
||||||
|
|
||||||
void begin(void);
|
bool sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0);
|
||||||
|
bool sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool sendTXT(uint8_t num, const char * payload, size_t length = 0);
|
||||||
|
bool sendTXT(uint8_t num, String & payload);
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
bool broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
void loop(void);
|
bool broadcastTXT(const uint8_t * payload, size_t length = 0);
|
||||||
#else
|
bool broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
// Async interface not need a loop call
|
bool broadcastTXT(const char * payload, size_t length = 0);
|
||||||
void loop(void) __attribute__ ((deprecated)) {}
|
bool broadcastTXT(String & payload);
|
||||||
|
|
||||||
|
bool sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false);
|
||||||
|
bool sendBIN(uint8_t num, const uint8_t * payload, size_t length);
|
||||||
|
|
||||||
|
bool broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
||||||
|
bool broadcastBIN(const uint8_t * payload, size_t length);
|
||||||
|
|
||||||
|
bool sendPing(uint8_t num, uint8_t * payload = NULL, size_t length = 0);
|
||||||
|
bool sendPing(uint8_t num, String & payload);
|
||||||
|
|
||||||
|
bool broadcastPing(uint8_t * payload = NULL, size_t length = 0);
|
||||||
|
bool broadcastPing(String & payload);
|
||||||
|
|
||||||
|
void disconnect(void);
|
||||||
|
void disconnect(uint8_t num);
|
||||||
|
|
||||||
|
void setAuthorization(const char * user, const char * password);
|
||||||
|
void setAuthorization(const char * auth);
|
||||||
|
|
||||||
|
int connectedClients(bool ping = false);
|
||||||
|
|
||||||
|
bool clientIsConnected(uint8_t num);
|
||||||
|
|
||||||
|
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
|
||||||
|
void disableHeartbeat();
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
|
||||||
|
IPAddress remoteIP(uint8_t num);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void onEvent(WebSocketServerEvent cbEvent);
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
void loop(void); // handle client data only
|
||||||
|
|
||||||
bool sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
|
||||||
bool sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0);
|
|
||||||
bool sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false);
|
|
||||||
bool sendTXT(uint8_t num, const char * payload, size_t length = 0);
|
|
||||||
bool sendTXT(uint8_t num, String & payload);
|
|
||||||
|
|
||||||
bool broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
|
||||||
bool broadcastTXT(const uint8_t * payload, size_t length = 0);
|
|
||||||
bool broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
|
||||||
bool broadcastTXT(const char * payload, size_t length = 0);
|
|
||||||
bool broadcastTXT(String & payload);
|
|
||||||
|
|
||||||
bool sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false);
|
|
||||||
bool sendBIN(uint8_t num, const uint8_t * payload, size_t length);
|
|
||||||
|
|
||||||
bool broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
|
||||||
bool broadcastBIN(const uint8_t * payload, size_t length);
|
|
||||||
|
|
||||||
void disconnect(void);
|
|
||||||
void disconnect(uint8_t num);
|
|
||||||
|
|
||||||
void setAuthorization(const char * user, const char * password);
|
|
||||||
void setAuthorization(const char * auth);
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
IPAddress remoteIP(uint8_t num);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
|
||||||
uint16_t _port;
|
|
||||||
String _origin;
|
|
||||||
String _protocol;
|
|
||||||
String _base64Authorization; ///< Base64 encoded Auth request
|
|
||||||
|
|
||||||
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
|
protected:
|
||||||
|
String _origin;
|
||||||
|
String _protocol;
|
||||||
|
String _base64Authorization; ///< Base64 encoded Auth request
|
||||||
|
String * _mandatoryHttpHeaders;
|
||||||
|
size_t _mandatoryHttpHeaderCount;
|
||||||
|
|
||||||
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
|
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
|
||||||
|
|
||||||
WebSocketServerEvent _cbEvent;
|
WebSocketServerEvent _cbEvent;
|
||||||
|
WebSocketServerHttpHeaderValFunc _httpHeaderValidationFunc;
|
||||||
|
|
||||||
bool newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
|
bool _runnning;
|
||||||
|
|
||||||
void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
|
uint32_t _pingInterval;
|
||||||
|
uint32_t _pongTimeout;
|
||||||
|
uint8_t _disconnectTimeoutCount;
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client);
|
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
||||||
bool clientIsConnected(WSclient_t * client);
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
void clientDisconnect(WSclient_t * client);
|
||||||
void handleNewClients(void);
|
bool clientIsConnected(WSclient_t * client);
|
||||||
void handleClientData(void);
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
void handleClientData(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void handleHeader(WSclient_t * client, String * headerLine);
|
void handleHeader(WSclient_t * client, String * headerLine);
|
||||||
|
|
||||||
|
void handleHBPing(WSclient_t * client); // send ping in specified intervals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called if a non Websocket connection is coming in.
|
* called if a non Websocket connection is coming in.
|
||||||
* Note: can be override
|
* Note: can be override
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
|
||||||
client->tcp->write("HTTP/1.1 400 Bad Request\r\n"
|
client->tcp->write(
|
||||||
"Server: arduino-WebSocket-Server\r\n"
|
"HTTP/1.1 400 Bad Request\r\n"
|
||||||
"Content-Type: text/plain\r\n"
|
"Server: arduino-WebSocket-Server\r\n"
|
||||||
"Content-Length: 32\r\n"
|
"Content-Type: text/plain\r\n"
|
||||||
"Connection: close\r\n"
|
"Content-Length: 32\r\n"
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Connection: close\r\n"
|
||||||
"\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"This is a Websocket server only!");
|
"\r\n"
|
||||||
clientDisconnect(client);
|
"This is a Websocket server only!");
|
||||||
}
|
clientDisconnect(client);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called if a non Authorization connection is coming in.
|
* called if a non Authorization connection is coming in.
|
||||||
* Note: can be override
|
* Note: can be override
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
virtual void handleAuthorizationFailed(WSclient_t *client) {
|
virtual void handleAuthorizationFailed(WSclient_t * client) {
|
||||||
|
client->tcp->write(
|
||||||
|
"HTTP/1.1 401 Unauthorized\r\n"
|
||||||
|
"Server: arduino-WebSocket-Server\r\n"
|
||||||
|
"Content-Type: text/plain\r\n"
|
||||||
|
"Content-Length: 45\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"WWW-Authenticate: Basic realm=\"WebSocket Server\""
|
||||||
|
"\r\n"
|
||||||
|
"This Websocket server requires Authorization!");
|
||||||
|
clientDisconnect(client);
|
||||||
|
}
|
||||||
|
|
||||||
client->tcp->write("HTTP/1.1 401 Unauthorized\r\n"
|
/**
|
||||||
"Server: arduino-WebSocket-Server\r\n"
|
|
||||||
"Content-Type: text/plain\r\n"
|
|
||||||
"Content-Length: 45\r\n"
|
|
||||||
"Connection: close\r\n"
|
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
|
||||||
"WWW-Authenticate: Basic realm=\"WebSocket Server\""
|
|
||||||
"\r\n"
|
|
||||||
"This Websocket server requires Authorization!");
|
|
||||||
clientDisconnect(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* called for sending a Event to the app
|
* called for sending a Event to the app
|
||||||
* @param num uint8_t
|
* @param num uint8_t
|
||||||
* @param type WStype_t
|
* @param type WStype_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
*/
|
*/
|
||||||
virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
if(_cbEvent) {
|
if(_cbEvent) {
|
||||||
_cbEvent(num, type, payload, length);
|
_cbEvent(num, type, payload, length);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called at client socket connect handshake negotiation time for each http header that is not
|
||||||
|
* a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*)
|
||||||
|
* If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the
|
||||||
|
* socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected
|
||||||
|
* This mechanism can be used to enable custom authentication schemes e.g. test the value
|
||||||
|
* of a session cookie to determine if a user is logged on / authenticated
|
||||||
|
*/
|
||||||
|
virtual bool execHttpHeaderValidation(String headerName, String headerValue) {
|
||||||
|
if(_httpHeaderValidationFunc) {
|
||||||
|
//return the value of the custom http header validation function
|
||||||
|
return _httpHeaderValidationFunc(headerName, headerValue);
|
||||||
|
}
|
||||||
|
//no custom http header validation so just assume all is good
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
WSclient_t * handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drop native tcp connection (client->tcp)
|
||||||
|
*/
|
||||||
|
void dropNativeClient(WSclient_t * client);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
|
||||||
|
* @param headerName String ///< the name of the header being checked
|
||||||
|
*/
|
||||||
|
bool hasMandatoryHeader(String headerName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WebSocketsServer : public WebSocketsServerCore {
|
||||||
|
public:
|
||||||
|
WebSocketsServer(uint16_t port, const String & origin = "", const String & protocol = "arduino");
|
||||||
|
virtual ~WebSocketsServer(void);
|
||||||
|
|
||||||
|
void begin(void);
|
||||||
|
void close(void);
|
||||||
|
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
void loop(void); // handle incoming client and client data
|
||||||
|
#else
|
||||||
|
// Async interface not need a loop call
|
||||||
|
void loop(void) __attribute__((deprecated)) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
||||||
|
void handleNewClients(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint16_t _port;
|
||||||
|
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* WEBSOCKETSSERVER_H_ */
|
#endif /* WEBSOCKETSSERVER_H_ */
|
||||||
|
36
src/WebSocketsVersion.h
Normal file
36
src/WebSocketsVersion.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* @file WebSocketsVersion.h
|
||||||
|
* @date 09.02.2021
|
||||||
|
* @author Markus Sattler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
|
* This file is part of the WebSockets for Arduino.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WEBSOCKETSVERSION_H_
|
||||||
|
#define WEBSOCKETSVERSION_H_
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION "2.3.5"
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_MAJOR 2
|
||||||
|
#define WEBSOCKETS_VERSION_MINOR 3
|
||||||
|
#define WEBSOCKETS_VERSION_PATCH 5
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_INT 2003005
|
||||||
|
|
||||||
|
#endif /* WEBSOCKETSVERSION_H_ */
|
@ -9,6 +9,10 @@ For details, see http://sourceforge.net/projects/libb64
|
|||||||
#include <core_esp8266_features.h>
|
#include <core_esp8266_features.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ESP32)
|
||||||
|
#define CORE_HAS_LIBB64
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CORE_HAS_LIBB64
|
#ifndef CORE_HAS_LIBB64
|
||||||
#include "cdecode_inc.h"
|
#include "cdecode_inc.h"
|
||||||
|
|
||||||
@ -32,9 +36,9 @@ int base64_decode_block(const char* code_in, const int length_in, char* plaintex
|
|||||||
const char* codechar = code_in;
|
const char* codechar = code_in;
|
||||||
char* plainchar = plaintext_out;
|
char* plainchar = plaintext_out;
|
||||||
char fragment;
|
char fragment;
|
||||||
|
|
||||||
*plainchar = state_in->plainchar;
|
*plainchar = state_in->plainchar;
|
||||||
|
|
||||||
switch (state_in->step)
|
switch (state_in->step)
|
||||||
{
|
{
|
||||||
while (1)
|
while (1)
|
||||||
|
@ -9,6 +9,10 @@ For details, see http://sourceforge.net/projects/libb64
|
|||||||
#include <core_esp8266_features.h>
|
#include <core_esp8266_features.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ESP32)
|
||||||
|
#define CORE_HAS_LIBB64
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CORE_HAS_LIBB64
|
#ifndef CORE_HAS_LIBB64
|
||||||
#include "cencode_inc.h"
|
#include "cencode_inc.h"
|
||||||
|
|
||||||
@ -35,9 +39,9 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
|||||||
char* codechar = code_out;
|
char* codechar = code_out;
|
||||||
char result;
|
char result;
|
||||||
char fragment;
|
char fragment;
|
||||||
|
|
||||||
result = state_in->result;
|
result = state_in->result;
|
||||||
|
|
||||||
switch (state_in->step)
|
switch (state_in->step)
|
||||||
{
|
{
|
||||||
while (1)
|
while (1)
|
||||||
@ -76,7 +80,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
|||||||
*codechar++ = base64_encode_value(result);
|
*codechar++ = base64_encode_value(result);
|
||||||
result = (fragment & 0x03f) >> 0;
|
result = (fragment & 0x03f) >> 0;
|
||||||
*codechar++ = base64_encode_value(result);
|
*codechar++ = base64_encode_value(result);
|
||||||
|
|
||||||
++(state_in->stepcount);
|
++(state_in->stepcount);
|
||||||
if (state_in->stepcount == CHARS_PER_LINE/4)
|
if (state_in->stepcount == CHARS_PER_LINE/4)
|
||||||
{
|
{
|
||||||
@ -92,7 +96,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
|||||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
||||||
{
|
{
|
||||||
char* codechar = code_out;
|
char* codechar = code_out;
|
||||||
|
|
||||||
switch (state_in->step)
|
switch (state_in->step)
|
||||||
{
|
{
|
||||||
case step_B:
|
case step_B:
|
||||||
@ -108,7 +112,7 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*codechar++ = 0x00;
|
*codechar++ = 0x00;
|
||||||
|
|
||||||
return codechar - code_out;
|
return codechar - code_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ A million repetitions of "a"
|
|||||||
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
|
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
|
||||||
/* #define SHA1HANDSOFF * Copies data before messing with it. */
|
/* #define SHA1HANDSOFF * Copies data before messing with it. */
|
||||||
|
|
||||||
#ifndef ESP8266
|
#if !defined(ESP8266) && !defined(ESP32)
|
||||||
|
|
||||||
#define SHA1HANDSOFF
|
#define SHA1HANDSOFF
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ By Steve Reid <steve@edmweb.com>
|
|||||||
100% Public Domain
|
100% Public Domain
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ESP8266
|
#if !defined(ESP8266) && !defined(ESP32)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t state[5];
|
uint32_t state[5];
|
||||||
@ -18,4 +18,4 @@ void SHA1Init(SHA1_CTX* context);
|
|||||||
void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len);
|
void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len);
|
||||||
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
|
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,7 @@ var server = http.createServer(function(request, response) {
|
|||||||
response.writeHead(404);
|
response.writeHead(404);
|
||||||
response.end();
|
response.end();
|
||||||
});
|
});
|
||||||
server.listen(81, function() {
|
server.listen(8011, function() {
|
||||||
console.log((new Date()) + ' Server is listening on port 8011');
|
console.log((new Date()) + ' Server is listening on port 8011');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -54,4 +54,4 @@ wsServer.on('request', function(request) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
connection.sendUTF("Hallo Client!");
|
connection.sendUTF("Hallo Client!");
|
||||||
});
|
});
|
||||||
|
131
travis/common.sh
Normal file
131
travis/common.sh
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
function build_sketches()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local srcpath=$2
|
||||||
|
local platform=$3
|
||||||
|
local sketches=$(find $srcpath -name *.ino)
|
||||||
|
for sketch in $sketches; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
if [[ -f "$sketchdir/.$platform.skip" ]]; then
|
||||||
|
echo -e "\n\n ------------ Skipping $sketch ------------ \n\n";
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo -e "\n\n ------------ Building $sketch ------------ \n\n";
|
||||||
|
$arduino --verify $sketch;
|
||||||
|
local result=$?
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($sketch) build verbose..."
|
||||||
|
$arduino --verify --verbose --preserve-temp-files $sketch
|
||||||
|
result=$?
|
||||||
|
fi
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($1) $sketch"
|
||||||
|
return $result
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_sketch()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local sketch=$2
|
||||||
|
$arduino --verify $sketch;
|
||||||
|
local result=$?
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($sketch) build verbose..."
|
||||||
|
$arduino --verify --verbose --preserve-temp-files $sketch
|
||||||
|
result=$?
|
||||||
|
fi
|
||||||
|
if [ $result -ne 0 ]; then
|
||||||
|
echo "Build failed ($1) $sketch"
|
||||||
|
return $result
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_sketches_json()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local srcpath=$2
|
||||||
|
local platform=$3
|
||||||
|
local sketches=($(find $srcpath -name *.ino))
|
||||||
|
echo -en "["
|
||||||
|
for sketch in "${sketches[@]}" ; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
if [[ -f "$sketchdir/.$platform.skip" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo -en "\"$sketch\""
|
||||||
|
if [[ $sketch != ${sketches[-1]} ]] ; then
|
||||||
|
echo -en ","
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
echo -en "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_sketches_json_matrix()
|
||||||
|
{
|
||||||
|
local arduino=$1
|
||||||
|
local srcpath=$2
|
||||||
|
local platform=$3
|
||||||
|
local ideversion=$4
|
||||||
|
local board=$5
|
||||||
|
local sketches=($(find $srcpath -name *.ino))
|
||||||
|
for sketch in "${sketches[@]}" ; do
|
||||||
|
local sketchdir=$(dirname $sketch)
|
||||||
|
local sketchname=$(basename $sketch)
|
||||||
|
if [[ -f "$sketchdir/.$platform.skip" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo -en "{\"name\":\"$sketchname\",\"board\":\"$board\",\"ideversion\":\"$ideversion\",\"cpu\":\"$platform\",\"sketch\":\"$sketch\"}"
|
||||||
|
if [[ $sketch != ${sketches[-1]} ]] ; then
|
||||||
|
echo -en ","
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_core()
|
||||||
|
{
|
||||||
|
echo Setup core for $1
|
||||||
|
|
||||||
|
cd $HOME/arduino_ide/hardware
|
||||||
|
|
||||||
|
if [ "$1" = "esp8266" ] ; then
|
||||||
|
mkdir esp8266com
|
||||||
|
cd esp8266com
|
||||||
|
git clone --depth 1 https://github.com/esp8266/Arduino.git esp8266
|
||||||
|
cd esp8266/
|
||||||
|
rm -rf .git
|
||||||
|
cd tools
|
||||||
|
python get.py
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" = "esp32" ] ; then
|
||||||
|
mkdir espressif
|
||||||
|
cd espressif
|
||||||
|
git clone --depth 1 https://github.com/espressif/arduino-esp32.git esp32
|
||||||
|
cd esp32/
|
||||||
|
rm -rf .git
|
||||||
|
cd tools
|
||||||
|
python get.py
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function clone_library() {
|
||||||
|
local url=$1
|
||||||
|
echo clone $(basename $url)
|
||||||
|
mkdir -p $HOME/Arduino/libraries
|
||||||
|
cd $HOME/Arduino/libraries
|
||||||
|
git clone --depth 1 $url
|
||||||
|
rm -rf */.git
|
||||||
|
rm -rf */.github
|
||||||
|
rm -rf */examples
|
||||||
|
}
|
||||||
|
|
||||||
|
function hash_library_names() {
|
||||||
|
cd $HOME/Arduino/libraries
|
||||||
|
ls | sha1sum -z | cut -c1-5
|
||||||
|
}
|
132
travis/version.py
Executable file
132
travis/version.py
Executable file
@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import configparser
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
travis_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
base_dir = os.path.abspath(travis_dir + "/../")
|
||||||
|
|
||||||
|
def write_header_file(version):
|
||||||
|
hvs = version.split('.')
|
||||||
|
intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2])
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
|
||||||
|
text = f'''/**
|
||||||
|
* @file WebSocketsVersion.h
|
||||||
|
* @date {now.strftime("%d.%m.%Y")}
|
||||||
|
* @author Markus Sattler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||||
|
* This file is part of the WebSockets for Arduino.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WEBSOCKETSVERSION_H_
|
||||||
|
#define WEBSOCKETSVERSION_H_
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION "{version}"
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_MAJOR {hvs[0]}
|
||||||
|
#define WEBSOCKETS_VERSION_MINOR {hvs[1]}
|
||||||
|
#define WEBSOCKETS_VERSION_PATCH {hvs[2]}
|
||||||
|
|
||||||
|
#define WEBSOCKETS_VERSION_INT {intversion}
|
||||||
|
|
||||||
|
#endif /* WEBSOCKETSVERSION_H_ */
|
||||||
|
'''
|
||||||
|
with open(f'{base_dir}/src/WebSocketsVersion.h', 'w') as f:
|
||||||
|
f.write(text)
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_properties_version():
|
||||||
|
library_properties = {}
|
||||||
|
with open(f'{base_dir}/library.properties', 'r') as f:
|
||||||
|
library_properties = configparser.ConfigParser()
|
||||||
|
library_properties.read_string('[root]\n' + f.read())
|
||||||
|
return library_properties['root']['version']
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_json_version():
|
||||||
|
library_json = {}
|
||||||
|
with open(f'{base_dir}/library.json', 'r') as f:
|
||||||
|
library_json = json.load(f)
|
||||||
|
return library_json['version']
|
||||||
|
|
||||||
|
|
||||||
|
def get_header_versions():
|
||||||
|
data = {}
|
||||||
|
define = re.compile('^#define WEBSOCKETS_VERSION_?(.*) "?([0-9\.]*)"?$')
|
||||||
|
with open(f'{base_dir}/src/WebSocketsVersion.h', 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
m = define.match(line)
|
||||||
|
if m:
|
||||||
|
name = m[1]
|
||||||
|
if name == "":
|
||||||
|
name = "VERSION"
|
||||||
|
data[name] = m[2]
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Checks and update Version files')
|
||||||
|
parser.add_argument(
|
||||||
|
'--update', action='store_true', default=False)
|
||||||
|
parser.add_argument(
|
||||||
|
'--check', action='store_true', default=True)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.update:
|
||||||
|
library_properties_version = get_library_properties_version()
|
||||||
|
|
||||||
|
with open(f'{base_dir}/library.json', 'r') as f:
|
||||||
|
library_json = json.load(f)
|
||||||
|
|
||||||
|
library_json['version'] = library_properties_version
|
||||||
|
|
||||||
|
with open(f'{base_dir}/library.json', 'w') as f:
|
||||||
|
json.dump(library_json, f, indent=4, sort_keys=True)
|
||||||
|
|
||||||
|
write_header_file(library_properties_version)
|
||||||
|
|
||||||
|
|
||||||
|
library_json_version = get_library_json_version()
|
||||||
|
library_properties_version = get_library_properties_version()
|
||||||
|
header_version = get_header_versions()
|
||||||
|
|
||||||
|
print("WebSocketsVersion.h", header_version)
|
||||||
|
print(f"library.json: {library_json_version}")
|
||||||
|
print(f"library.properties: {library_properties_version}")
|
||||||
|
|
||||||
|
if args.check:
|
||||||
|
if library_json_version != library_properties_version or header_version['VERSION'] != library_properties_version:
|
||||||
|
raise Exception('versions did not match!')
|
||||||
|
|
||||||
|
hvs = header_version['VERSION'].split('.')
|
||||||
|
if header_version['MAJOR'] != hvs[0]:
|
||||||
|
raise Exception('header MAJOR version wrong!')
|
||||||
|
if header_version['MINOR'] != hvs[1]:
|
||||||
|
raise Exception('header MINOR version wrong!')
|
||||||
|
if header_version['PATCH'] != hvs[2]:
|
||||||
|
raise Exception('header PATCH version wrong!')
|
||||||
|
|
||||||
|
intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2])
|
||||||
|
if int(header_version['INT']) != intversion:
|
||||||
|
raise Exception('header INT version wrong!')
|
Reference in New Issue
Block a user