Compare commits

...

293 Commits

Author SHA1 Message Date
f6e730c2b4 fix _fingerprint is set checks for ESP32
see #633 and #632
2021-03-06 09:24:07 +01:00
7c3b1b7408 install libgtk-3-0 2021-03-06 08:59:21 +01:00
738e43fda4 install libgtk-3-0 2021-03-06 08:56:08 +01:00
f55bf8d4ed bump version to 2.3.5 2021-02-09 18:26:21 +01:00
a484da47ed Merge branch 'eio_4_ping_handling' 2021-01-31 20:32:25 +01:00
4355199120 bump version 2.3.4 2021-01-31 20:31:52 +01:00
0a4fcd44c2 EIO=4 ping handling #611 2021-01-31 20:27:56 +01:00
3a2b757155 EIO=4 ping handling #611 2021-01-31 10:28:15 +01:00
900d81e534 make WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient); public 2021-01-19 16:59:03 +01:00
0ecef8c552 Fixing WebSocket Close see #610 2021-01-19 16:58:37 +01:00
410489f7c5 bump version to 2.3.3 2021-01-07 10:27:42 +01:00
ec22d67c12 version.py can now create WebSocketsVersion.h 2021-01-07 10:24:23 +01:00
39e6a8e709 print version in DEBUG mode 2021-01-07 10:14:30 +01:00
784b7f9cb8 no python3.9 on github actions 2021-01-07 10:05:30 +01:00
fd83d6ad45 add WebSocketsVersion.h and some build checks 2021-01-07 09:59:49 +01:00
0e729cd896 cleanup clone_library 2021-01-06 09:39:19 +01:00
2f21590e55 no need for a full clone 2021-01-06 09:18:27 +01:00
c98baafda7 jobs steps array 2021-01-05 21:54:58 +01:00
983b9801fb Merge branch 'master' of github.com:Links2004/arduinoWebSockets 2021-01-05 21:50:56 +01:00
e70262dab9 add done job 2021-01-05 21:50:40 +01:00
4a05eab627 Update README.md
use github actions as Build Status
2021-01-05 21:30:28 +01:00
822618f606 code style fix 2021-01-05 21:18:30 +01:00
1b4f186fa6 use github actions for build 2021-01-05 21:17:09 +01:00
c68e015322 github actions test3 2021-01-05 18:32:11 +01:00
dc30a2b7bf github actions test2 2021-01-05 18:28:59 +01:00
6bee53a8bd github actions test 2021-01-05 18:11:48 +01:00
ebb87cdc8a + constructors for scalars 2020-11-26 19:33:18 +01:00
e7ab913693 fix clearing _Client[] 2020-11-26 19:33:18 +01:00
52547ec47c fix clients init logic 2020-11-26 19:33:18 +01:00
74411bf729 use native contructor and destructor to initialize WSclient_t 2020-11-26 19:33:18 +01:00
f0cc36dede bump version to 2.3.2 2020-11-21 18:13:22 +01:00
074a674833 bionic is broken for Arduino IDE 1.6.13 so we keep xenial 2020-11-21 16:25:18 +01:00
8239e1625e update travis config 2020-11-21 16:21:04 +01:00
c5900db636 add handling for Socket.IO V3 connection 2020-11-21 16:19:59 +01:00
9470961d85 socket.io improve Cookie handling 2020-11-21 16:19:08 +01:00
04919f848f only try to send socket.io messages in WSC_CONNECTED state
handle sIOtype_CONNECT messages
send 2probe on websocket connect (#574)
2020-11-21 16:17:43 +01:00
25318111a1 add namespace join to socket.io examples 2020-11-21 16:16:59 +01:00
08caf3bfc6 code style 2020-11-21 14:45:53 +01:00
fb26433e75 add error messages if Webserver Hook Functions are not supported by platform 2020-11-21 14:33:25 +01:00
4f52a0f38e cleanup server client init 2020-11-21 14:07:32 +01:00
f20fbbfcd9 code style 2020-11-21 14:07:14 +01:00
28cd929e7e code style 2020-11-21 14:06:30 +01:00
826c6b423a esp8266: share port 80 with regular webserver (#575) 2020-11-21 13:51:16 +01:00
7fea0b8bdf Fix for Newline in Headers when extraHeaders is Empty [577] (#578)
Closes https://github.com/Links2004/arduinoWebSockets/issues/577
2020-11-14 18:17:10 +01:00
4db14451fb clang-format 2020-10-26 17:04:19 +01:00
80bf087cd0 Add SSL client certificate support (#572)
* Add client certificate support

allows WiFiClientSecureBearSSL users to use client certificate and private key for the WebSocker.
also added SSL functions for socket.io
2020-10-26 17:01:31 +01:00
5caff59f7f bump version to 2.3.1 2020-10-04 16:34:25 +02:00
b90fe4c1d7 travis 2020-10-04 16:20:27 +02:00
a086303c87 make old Arduino IDE (1.6.x) happy with CA
```
java.lang.StackOverflowError
	at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
	at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
	at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
	at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
	at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
	at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
	at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
```
2020-10-04 16:06:55 +02:00
217c7ce4ea Merge pull request #480 from kenkeiras/ssl-with-ca-example
Add example for SSL websocket with CA certificate
2020-10-04 15:41:37 +02:00
13a304a8c9 Merge pull request #569 from Links2004/esp8266_bareSSL_native
ESP8266 bare ssl native
2020-10-04 15:40:43 +02:00
9b873978ba Merge pull request #566 from simap/master
avoid flush on esp32, add/fix debugs, longer yield when waiting for data
2020-10-04 15:31:15 +02:00
ca52afeec0 code style 2020-10-04 15:11:06 +02:00
beba0f88e3 fix README.md 2020-10-04 15:02:09 +02:00
f2265118b4 bump version to 2.3.0 and add note for ESP8266 BareSSL API changes 2020-10-04 14:59:51 +02:00
9982818cfa update README travis from org to com 2020-10-04 14:56:29 +02:00
91b02341ba Native BareSSL support for ESP8266
see #557, #509, #492, #555, #352
2020-10-04 14:49:22 +02:00
a00d3edcb7 Merge pull request #567 from lucalas/master
setFingerprint in WiFiClientSecure required to pass certificate Check
2020-10-03 14:52:10 +02:00
c73c77e988 Add check to set fingerprint; 2020-10-02 09:29:55 +02:00
e1ddbfe1a5 Format Code; 2020-10-01 01:14:01 +02:00
f65e8d9062 call setFingerPrint for ssl object in client with fingerprint received in beginSSL or no connection will start; 2020-10-01 01:12:54 +02:00
508e0fb691 add missing platforms for WEBSOCKETS_YIELD_MORE 2020-09-16 11:11:24 -07:00
083683425f avoid flush on esp32, add/fix debugs, longer yield when waiting for data
flush causes a bunch of reads as we try to close the socket on esp32. I
think flush is broken on that platform. the comments indicate confusion.

added some debug logs for important cases that were missing them, some
missing newlines to exisitng logs.

added a longer yield when waiting for data, in some super busy cases it
could trigger a task watchdog or otherwise starve the system. (yield
alone doesn't always switch to lower priority tasks)

make some other yields conditional to avoid some waste when it would
double-yield.
2020-09-16 11:02:02 -07:00
05ec18e49b Merge pull request #565 from tobiges/master
header response timeout added
2020-09-14 10:25:59 +02:00
e185668a97 header response timeout added 2020-09-12 17:20:03 +02:00
7e34a8b246 Merge pull request #563 from simap/accessClients
add api to check connectedness of clients by num
2020-09-08 21:08:32 +02:00
4acc7eff8a add api to check connectedness of clients by num 2020-09-08 09:54:33 -07:00
b3c5348e9b update arduino IDE version in travis test 2020-07-25 09:07:02 +02:00
19c39d5ea0 typo 2020-07-11 18:38:39 +02:00
ebdc8def4a Merge branch 'master' of github.com:Links2004/arduinoWebSockets 2020-07-11 18:17:05 +02:00
44fb41e3b7 WebSocketClientSocketIOack.ino:150:25: ARDUINOJSON_USE_LONG_LONG fix 2020-07-11 18:16:34 +02:00
cadbd6458f Merge pull request #551 from Links2004/ESP32v4
fix #525 (detect ESP32 version)
2020-07-11 18:13:13 +02:00
f244741caa WebSocketClientSocketIO.ino:113:25: ArduinoJson, you must set ARDUINOJSON_USE_LONG_LONG error 2020-07-11 18:07:16 +02:00
3f1cedb21c fix #541 allow loop() to be called before begin() 2020-07-11 17:58:36 +02:00
ba6275e7fe fix #525 (detect ESP32 vesion) 2020-07-11 17:55:18 +02:00
a71a480676 fix #539 (NODEBUG_WEBSOCKETS warning)
fix warning when using NODEBUG_WEBSOCKETS as compiler option.
2020-05-14 18:04:46 +02:00
1e271b5e12 Merge remote-tracking branch 'origin/master' 2020-05-03 13:07:13 +02:00
0c3b15c5e7 fix #454 2020-05-03 13:05:55 +02:00
7a4160814c fix #454 2020-05-03 13:04:53 +02:00
784088d9cc bump version to 2.2.1 2020-05-03 10:03:53 +02:00
9048ef9ee4 code style 2020-05-03 09:28:55 +02:00
80b0867786 update travis for IDE 1.8.12 2020-05-03 09:27:49 +02:00
b9e1336826 add new define for yield WEBSOCKETS_YIELD 2020-05-03 09:12:03 +02:00
ac9b2ccdf6 Merge pull request #521 from amrbekhit/patch-1
Initialize _reconnectInterval in constructor.
2020-04-01 19:09:53 +02:00
12684582aa Initialize _reconnectInterval in constructor.
This allows setReconnectInterval() to be called before begin() and stops begin() from overriding _reconnectInterval every time it is called.
2020-03-21 22:14:25 +03:00
420cc55960 Merge pull request #501 from amrbekhit/websockets_tcp_timeout_increase
Increased WEBSOCKETS_TCP_TIMEOUT to 5000ms.
2020-03-14 14:51:25 +01:00
64296cced7 Merge pull request #512 from maurus95/master
Implementing automatic WS server-side heartbeat
2020-02-15 22:27:40 +01:00
c3f01e43fc Merge pull request #514 from simap/master
read can return -1, check for this to avoid corrupting protocol
2020-02-15 22:18:48 +01:00
04e4be03fe Merge pull request #515 from simap/esp32yield
add a yield here for esp32 to avoid a busy loop
2020-02-15 22:18:08 +01:00
ebd7a528ac add a yield here for esp32 to avoid a busy loop
if data isn't available yet, but is expected, yielding here is nicer
than burning the cpu in a loop, just like in esp8266 case.
2020-02-15 06:43:46 -08:00
516911900b read can return -1, check for this to avoid corrupting protocol
fixes #470
2020-02-15 06:37:07 -08:00
674a6e98c9 Implemented HeartBeat in WebSocketsServer 2020-02-10 19:45:55 +01:00
4ee0ba5630 Increased WEBSOCKETS_TCP_TIMEOUT to 5000ms.
See https://github.com/Links2004/arduinoWebSockets/issues/500.
2019-12-24 17:03:32 +03:00
370f217a30 add example for ssl websocket with CA certificate 2019-10-27 21:40:53 +01:00
c038f100d6 Merge pull request #458 from Nufflee/patch-1
Syntax highlighting in README.md
2019-07-21 08:53:00 +02:00
0444a78441 [SocketIO] add example for use of ACK / callback handling 2019-07-20 14:24:55 +02:00
8cc20b6e4b Merge branch 'master' of github.com:Links2004/arduinoWebSockets 2019-07-20 13:47:55 +02:00
40152be197 code style 2019-07-20 13:47:40 +02:00
e2669c1c5e [SocketIO] allow to send any message 2019-07-20 13:46:59 +02:00
771831c57e Syntax highlighting in README.md 2019-07-15 23:13:38 +02:00
06a7bb177b Merge pull request #452 from luc-github/master
Fix warnings in platformIO
2019-07-04 16:12:21 +02:00
Luc
bd158c9c5c Fix warnings in platformIO
Fix : warning: enumeration value 'WStype_ERROR' not handled in switch [-Wswitch]
Fix : warning: variable 'ip' set but not used [-Wunused-but-set-variable]
2019-07-04 12:58:37 +02:00
9a803e1fb3 bump version to 2.2.0 2019-06-29 19:04:10 +02:00
c64f2b81e5 Merge pull request #449 from Links2004/socketio
Socket.IO 2.0.x Support
2019-06-29 18:56:31 +02:00
4ef8d733dc add missing include 2019-06-29 18:35:21 +02:00
7816bb3fa4 adding example for new socket.IO support 2019-06-29 18:31:14 +02:00
adf2b07f3b fix #447 2019-06-23 12:14:44 +02:00
d3fde2ba34 Merge pull request #442 from Links2004/gpn19
Gpn19
2019-06-20 10:41:29 +02:00
c164c47f08 Merge branch 'gpn19' into socketio 2019-06-20 10:08:36 +02:00
6a76efa791 fix #445 #446 set TCP timeout for ESP32 on connect 2019-06-20 10:06:21 +02:00
5d26a65df4 only send payload when we have a ptr and length 2019-06-20 10:02:07 +02:00
007b5ba9a8 ignore not needed WS events for SocketIO 2019-06-10 15:13:26 +02:00
dbca2ab420 SocketIO message RX is working 2019-06-10 14:57:49 +02:00
dfa35fa9ae clang-format 2019-06-10 13:31:51 +02:00
794163cec9 Merge branch 'gpn18' into socketio 2019-06-10 13:30:54 +02:00
294436840c bump version to 2.1.4 2019-06-10 13:15:11 +02:00
b1b21d188f update gitignore to Ignore IDE files from Eclipse and VScode 2019-06-10 13:02:25 +02:00
3063ad27ae clang-format 2019-06-10 13:00:01 +02:00
e8df841b7f add support for ESP32 ETH.h see #443 2019-06-10 09:29:58 +02:00
0aa07421a6 add events for ping / pong rx #382 2019-05-30 20:15:03 +02:00
df3ef524b6 fix #428 by setting Insecure if we do not have a CA or fingerprint 2019-05-30 18:24:28 +02:00
8ec27b0468 fix indexOf #430 2019-05-30 16:52:20 +02:00
c361895a4b add setCACert based on #434 2019-05-30 16:32:30 +02:00
31bade1530 test with newer arduino IDE (1.8.9) 2019-05-30 14:33:44 +02:00
4223a9e41f fix Travis 2019-05-30 14:24:57 +02:00
72731beb10 Merge pull request #383 from sovcik/master
Implementing automatic WS client-side heartbeat
2019-01-16 16:42:59 +01:00
1b6b42b877 processing client data before potential disconnect 2018-11-03 13:16:12 +01:00
d6dd7be987 disconnecting after pong not received 2018-11-03 13:15:14 +01:00
d325bd338e Merge branch 'master' into gpn18 2018-10-26 20:33:29 +02:00
d693437908 version bump 2018-10-24 08:19:02 +02:00
9b6ce7563a added example for heartbeat 2018-10-24 08:17:37 +02:00
68800e2e7a implementing heartbeat 2018-10-23 18:01:33 +02:00
eaef4f0801 Merge pull request #369 from sanketplus/master
make masking RFC complaint and fix #208
2018-09-23 18:10:30 +02:00
4db22fe5e4 make masking RFC complaint and fix #208 2018-09-23 16:49:10 +05:30
50e2e366cc fix travis debug test build 2018-09-23 12:07:42 +02:00
e8249f76e6 travis config second fix 2018-09-23 12:02:06 +02:00
a70d644f5d adapt travis config to match esp8266 changes 2018-09-23 11:56:33 +02:00
a3079f5645 Merge commit '38a881a86a35c2cbf755f9c8da33178b70bd4f82' 2018-08-08 18:13:29 +02:00
2626b26315 Merge commit '32dd01b91bbae7f10b0b77ac200e69ea064ed44f' 2018-08-08 18:13:14 +02:00
38a881a86a bump version to 2.1.2 2018-08-08 18:12:02 +02:00
32dd01b91b bump version to 2.1.1 2018-08-08 18:11:32 +02:00
db8167f9c7 Merge pull request #355 from Links2004/ESP32_serial
ESP32 fixes
2018-08-07 18:31:43 +02:00
388683d4cd fix compiler warnings for ESP32 - #319 2018-08-07 18:10:48 +02:00
38c401b8af adapt to ESP32 repo changes
4e5cbdaa7f
2018-08-07 18:06:32 +02:00
f7a7ab6ab4 wrap reasonCode in define
see #343
2018-07-04 16:29:28 +02:00
bdee8b9744 call end for ESP8266_ASYNC TCP Server 2018-06-21 09:30:11 +02:00
50903cd410 basic event RX working 2018-05-12 17:10:17 +02:00
f95c014342 basic event sending works 2018-05-12 16:53:34 +02:00
8967356af3 improve ram usage on one char send 2018-05-12 15:27:08 +02:00
d2043bf8ef start work for socket.IO
basic Engine.IO implementation
2018-05-12 15:13:50 +02:00
7ddcdc2bd3 add info for AVR usage with version 2.x.x 2018-05-12 12:40:56 +02:00
bde97179bf fix unused parameter warnings
fix switch warinings

part of #319
2018-05-12 11:39:59 +02:00
9ce044e550 code style 2018-05-12 11:34:12 +02:00
a796079b0c fix code style 2018-05-12 11:27:03 +02:00
e8c0d775fb fix #146 HTTP Header handler 2018-05-12 11:22:16 +02:00
5636b02b46 add WebSocketServerAllFunctionsDemo (WIP) 2018-05-10 20:47:05 +02:00
4b33575af1 add connectedClients see #242 2018-05-10 20:43:08 +02:00
486a612693 allow usage of IPAddress #230 2018-05-10 20:12:48 +02:00
ea8e81c6ce add close #322 2018-05-10 18:56:31 +02:00
8a187b523b Merge pull request #323 from chemicstry/printf_fix
Fix format specifiers
2018-05-10 18:48:43 +02:00
ac8d806085 Fix format specifiers 2018-05-10 01:16:39 +03:00
02e0128802 Update index.js
fix port
2018-04-17 19:42:47 +02:00
01e1fdfb50 Merge pull request #304 from CarlosRDomin/master
Allow custom WEBSOCKETS_SERVER_CLIENT_MAX definition
2018-04-03 19:21:22 +02:00
d02932ef21 Allow custom WEBSOCKETS_SERVER_CLIENT_MAX definition 2018-04-02 22:17:34 -07:00
5bf8b2407e Merge pull request #296 from getbyte/master
fix undefined virtual methods
2018-03-18 07:34:57 +01:00
50d9a8d6e5 fix undefined virtual methods 2018-03-18 01:25:49 +03:00
7443f9b1dc Merge pull request #292 from ivankravets/patch-2
Update supported platforms, allow PIO to detect examples automatically
2018-03-07 18:49:05 +01:00
4b04f6fa53 Update supported platforms, allow PIO to detect examples automatically 2018-03-07 10:33:33 +02:00
a67a8dd0e0 Merge pull request #265 from Links2004/esp32
ESP32 support
improved test
sorted examples
2018-02-07 18:32:49 +01:00
4759a66a62 Arduino 1.8.5 is very peaky with the board parameters 2018-02-07 18:15:50 +01:00
48e690a42a bump version to 2.1.0
travis arduino 1.8.5
2018-02-07 18:11:08 +01:00
b059d0711c sort examples by platform
rework the travis tests
create ESP32 examples
2018-02-07 17:28:17 +01:00
a09b8c48ee ide version 2018-02-06 21:58:26 +01:00
94eb4b12e5 IDE version 2018-02-06 21:52:13 +01:00
2df62558f1 more verbose verify step 2018-02-06 21:48:49 +01:00
86074c90ae update IDE test 2018-02-06 21:41:47 +01:00
d73e3ecc9c skip some test for ESP32 2018-02-06 21:37:24 +01:00
f62aa6478d more ESP32 stuff 2018-02-06 21:36:44 +01:00
d340c89b09 ... 2018-02-06 21:26:06 +01:00
05f4cfd7bf fix includes for WebSocketClient.ino 2018-02-06 21:17:14 +01:00
46cff38287 fix ESP32 sha1 problem 2018-02-06 21:12:39 +01:00
0b35e32b2a examples for ESP32 2018-02-06 21:10:29 +01:00
255f40eaa7 travis.yml 2018-02-06 20:46:17 +01:00
5e1f9b1c26 CORE_HAS_LIBB64 for ESP32 2018-02-06 20:44:10 +01:00
30b6deedd2 use travis matrix 2018-02-06 20:41:36 +01:00
0e6e1c76ee Merge pull request #281 from baggior/esp32 2018-02-06 20:24:40 +01:00
887683fabb Merge branch 'master' into esp32 2018-02-06 20:24:03 +01:00
0b10299549 travis builds for ESP32 2018-02-06 20:22:29 +01:00
1d300084e0 fix 2018-02-06 09:57:04 +01:00
d9e1e97cf6 Merge branch 'master' into esp32 2018-01-23 12:40:10 +01:00
642750e232 Merge pull request #245 from PeterEmbedded/patch-1
Added some missing comments to WebSockets.cpp
2017-10-16 19:04:40 +02:00
a0c714bf10 Update WebSockets.cpp
Added some missing comments
2017-10-16 13:01:00 +02:00
c5461d5779 memset zero _clients struct for server
fixes #244
2017-10-06 18:30:05 +02:00
b87bce4466 add virtual to destructor #243 2017-10-04 19:17:21 +02:00
9608c2d210 Merge pull request #240 from mgbckr/master
Add example for plain STOMP connection
2017-09-25 21:31:24 +02:00
4baf4896cc Add missing Hash.h library 2017-09-25 17:20:07 +02:00
4fd2e9d993 Add example for plain STOMP connection 2017-09-25 15:04:56 +02:00
fa580a568f Merge pull request #223 from robokoding/master
Add ESP32 support from @robokoding
2017-09-20 18:53:55 +02:00
a93a845780 add: ESP32 support 2017-09-03 10:06:00 +02:00
83a1539e1e fix: ESP32 new client connection 2017-09-03 09:55:15 +02:00
1bd4638621 bump version to 2.0.10 2017-08-21 21:44:30 +02:00
f40a390ab1 workaround windows gcc Template issue (#228, #229) 2017-08-21 21:39:14 +02:00
b6c27f74cd bump version to 2.0.9 2017-08-19 22:05:33 +02:00
c64a082270 Merge branch 'write_big_data' 2017-08-19 21:36:10 +02:00
522a67bc1b add setReconnectInterval for the Client 2017-08-19 21:16:07 +02:00
29df9c30f7 bump version to 2.0.8 2017-08-18 17:16:51 +02:00
4c1c5378cb esp32 no hasClient function 2017-07-30 01:40:36 +02:00
dbabc1025b added esp32 support 2017-07-30 00:58:15 +02:00
1d40160d99 added esp32 support 2017-07-30 00:54:17 +02:00
a388676b40 added remoteIP for esp32 2017-07-30 00:22:23 +02:00
8c19d7ba48 Update WebSockets.cpp
added esp32 hwcrypto for sha1
2017-07-30 00:21:13 +02:00
4fc80871a6 Update WebSockets.h 2017-07-30 00:18:37 +02:00
0ca020bbd2 add build status 2017-07-20 18:47:36 +02:00
cc3ce02c67 move files to get travis working 2017-07-20 18:40:38 +02:00
96c266101e add needed includes 2017-07-20 18:32:25 +02:00
64c8908b05 add script for travis 2017-07-20 18:26:04 +02:00
87c6c80c67 setup travis 2017-07-20 18:18:35 +02:00
adb255bda0 Merge pull request #216 from mgbckr/master
Extra headers (including removal of "Origin") and SockJS+STOMP example
2017-07-20 18:09:37 +02:00
d0ab6c4fd1 Remove redundant method header and fix indent 2017-07-20 08:21:29 +02:00
fcb623ce91 Simplified example 2017-07-19 15:50:25 +02:00
669f0b489e Fix empty header issue 2017-07-19 11:12:00 +02:00
32cb052f23 Update SockJS+STOMP example 2017-07-19 10:19:32 +02:00
42ab3168c5 Switch to setting extra headers via function 2017-07-19 09:59:34 +02:00
86d2e2400a Add SockJS+Stomp example 2017-07-18 13:33:13 +02:00
ad07f3c665 Allow to disable "Origin" header
The origin header often makes trouble with current WebSocket implementations. Thus, we introduce the WEBSOCKET_HEADERS_NO_ORIGIN macro which disables this header it if defined.
2017-07-18 12:37:04 +02:00
a4533a028c fix NULL ptr when server abort the connection (#207) 2017-07-08 08:38:05 +02:00
ae3dd103a1 Merge pull request #199 from jesben/master
Added method for beginSocketIOSSL
2017-06-18 17:55:55 +02:00
40f84c19f4 Adding beginSocketIOSSL 2017-06-18 12:51:34 +02:00
f68d9d8030 Adding method for beginSocketIOSSL 2017-06-18 12:50:07 +02:00
c911776860 add virtual to write
fix some naming
2017-04-10 17:49:42 +02:00
adb52b11e9 handle cases when not all data can be written to TCP stack #187 2017-04-09 17:58:23 +02:00
81e567b248 send 401 header too if auth string is empty #116 2017-03-18 10:35:23 +01:00
1afe317c7d improve LED example
onchange to oninput #178
2017-03-13 17:25:10 +01:00
177ec8239d Merge branch 'master' of github.com:Links2004/arduinoWebSockets 2017-03-09 18:44:18 +01:00
e675c7590e add missing include for ESP with W5100 #177 2017-03-09 18:43:23 +01:00
615926ae1e Merge pull request #176 from quantumlicht/master
Fix typo accross the project
2017-03-07 17:57:53 +01:00
acd0a603eb Merge branch 'master' of https://github.com/quantumlicht/arduinoWebSockets 2017-03-06 15:09:22 -05:00
26140be6c9 fix #150 typo lenght -> length 2017-03-06 15:09:03 -05:00
3b1dabbe1e fix typo lenght -> length 2017-03-06 15:07:20 -05:00
55bc7db7ad move API docs 2017-03-06 19:16:26 +01:00
1a6f46c67d Merge pull request #175 from quantumlicht/master
Add documentation for top level API in README
2017-03-06 18:22:13 +01:00
210f2e8fa1 Add documentation for top level API in README 2017-03-06 11:03:43 -05:00
34a2d282e4 allow to moves all Header strings to Flash (~300 Byte) #152 2017-02-22 15:30:58 +01:00
e93a323e56 add support for Fragmentation / continuation opcode Receive 2017-02-22 14:29:26 +01:00
6da0bc97e8 bump version to 2.0.7 2017-02-08 19:06:06 +01:00
ae2ba7effe bump version to 2.0.7 2017-02-08 19:05:27 +01:00
dc426c9a61 Merge pull request #170 from CAOU123/master
Make library compatible with Particle devices
2017-02-08 18:58:39 +01:00
60e3d1080e Merge branch 'master' into master 2017-02-07 16:05:20 -05:00
26fc61f7a2 Merge pull request #169 from nguyenhunga5/master
Fix socket.io issue #167
2017-02-03 17:38:24 +01:00
604a781122 Merge pull request #168 from tzapu/patch-1
Update README.md
2017-02-03 17:35:02 +01:00
f52d718cf2 Update README.md 2017-02-03 13:53:46 +02:00
6757b8b74c Fix socket.io issue
Fix socket.io issue reference from https://github.com/Links2004/arduinoWebSockets/issues/167#issuecomment-276724057
2017-02-03 13:30:20 +07:00
bef2541ede fix #162
missing isSocketIO init
2017-01-21 12:31:12 +01:00
dac71c4c23 moving host header
try to fix #159
2017-01-08 09:55:28 +01:00
60903a2fa5 mask pong
#34
2017-01-06 10:48:30 +01:00
0aaf50f87f mask ping for client
fix #34
2017-01-06 10:44:25 +01:00
2add886219 Merge pull request #147 from odelot/patch-1
Update WebSocketsClient.cpp
2016-11-24 19:21:14 +01:00
ab3b5bae46 Update WebSocketsClient.cpp
fix typo that was breaking the build
2016-11-24 02:25:01 -02:00
45bb7dbe23 Update WebSocketsClient.cpp
fix #140 Socket.io client doesn't reconnect to server
2016-11-23 17:39:48 +01:00
92032289ec Merge pull request #143 from quantumlicht/master
Remove duplicate handshake headers
2016-11-17 17:48:38 +01:00
5cd68c5304 - Remove duplicate handshake headers
- Add debug log for displaying handshake headers
Host, Origin, and User-Agent were duplicated in the case the client was
not socketIO or if it was and has a sessionId
2016-11-16 18:35:14 -05:00
ddaeea0e4b Merge pull request #137 from nerochiaro/master
Change inheritance of WebSocketServer
2016-11-09 18:19:11 +01:00
a097f0defd protected inheritance is enough 2016-11-08 22:52:00 +01:00
689e3ef921 Change inheritance of WebSocketServer
to allow classes inheriting from it to call sendFrame with custom
arguments.
2016-11-08 01:48:01 +01:00
75133dfa6d version bumb 2016-10-22 19:48:16 +02:00
d2719573d4 add function to send WS ping
sendPing();

#130
2016-10-22 19:47:44 +02:00
0d9aa043f0 fix WebSocketClientSocketIO example 2016-10-22 20:36:36 +02:00
7810d0d0b3 Make library compatible with Particle devices 2016-10-20 15:46:44 -04:00
1defe6d8e1 Merge pull request #126 from Roman3349/master
Add information about library to @PlatformIO Library Registry manifest file
2016-09-28 18:28:28 +02:00
d036dcd8e2 Add information about examples, license and version to @PlatformIO Library Registry manifest file
Signed-off-by: Roman3349 <ondracek.roman@centrum.cz>
2016-09-27 11:25:56 +02:00
529a86cc26 Merge pull request #90 from kenkus-futurice/master
Add socket.io client
2016-09-11 17:13:57 +02:00
958ab08a6b Merge pull request #111 from anisimovsergey/master
WEBSOCKETS_NETWORK_TYPE exteral definition
2016-07-15 21:44:03 +02:00
7361e2b1b6 WEBSOCKETS_NETWORK_TYPE exteral definition
Making possible to define WEBSOCKETS_NETWORK_TYPE as a compile parameter.
2016-07-15 20:29:13 +01:00
1961ddc159 bump git version 2016-07-11 17:30:08 +02:00
cdee9fec05 release version 2.0.4 2016-07-11 17:29:29 +02:00
ab0d8ff526 Merge pull request #100 from chrisella/master
fix spellings
2016-06-18 12:39:40 +02:00
b3d4367d10 fix spellings 2016-06-17 15:37:07 +01:00
ab51930730 Merge pull request #93 from jjssoftware/HttpHeaderEvents
custom http header validation implementation
2016-06-13 21:01:14 +02:00
Joe
1ed734ec3f Merge pull request #2 from jlippa/master
pull from master
2016-06-11 13:13:16 +01:00
Joe
b99bae459d Merge pull request #1 from Links2004/master
pull from head
2016-06-11 13:05:44 +01:00
26130dc874 Merge pull request #95 from jlippa/Docs
wss / SSL README.md documentation update
2016-06-11 13:35:28 +02:00
joe
815093a123 wss / SSL README.md documentation update 2016-06-11 10:17:13 +01:00
joe
7e5c64a573 mandatoryHttpHeaderCount fix 2016-06-09 19:48:38 +01:00
joe
97443ae777 custom http header validation implementation; minor comment fixes 2016-06-08 23:11:21 +01:00
joe
e589b40b25 custom http header validation implementation 2016-06-08 23:04:18 +01:00
eb2351a4fd Merge pull request #89 from jlippa/nginx
Added sample ESP8266 nginx SSL reverse proxy configuration file
2016-06-07 18:02:50 +02:00
bf3cfa6237 Fix reference to INTERVAL 2016-06-06 17:50:31 +03:00
f8a5acc9b7 Add socket.io client 2016-06-06 15:21:13 +03:00
joe
8190e8121c Added sample ESP8266 nginx SSL reverse proxy configuration file 2016-06-05 16:09:22 +01:00
6a914fc5ea Merge pull request #87 from jlippa/master
RFC 6455 4.2.1.4 case sensitivity fix
2016-06-05 09:58:46 +02:00
48ee5fc6fb Firefox fix
Overlay fix for Firefox and other clients that send additional data in the Connection header e.g. "Connection: Keep-Alive, Upgrade"
2016-06-05 08:27:39 +01:00
b1685962c5 Merge pull request #1 from jlippa/jlippa-patch-1
RFC 6455 4.2.1.4 case sensitivity fix
2016-06-04 21:32:44 +01:00
c4e5f5c7e7 RFC 6455 4.2.1.4 case sensitivity fix
This is a case sensitivity fix for the Connection header Upgrade value to make this part meet the requirement of IETF websocket RFC 6455 4.2.1.4: "A |Connection| header field that includes the token "Upgrade", treated as an ASCII case-insensitive value."
2016-06-04 21:31:42 +01:00
45 changed files with 4552 additions and 815 deletions

63
.clang-format Normal file
View 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
View 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
View File

@ -27,3 +27,11 @@
*.out
*.app
/tests/webSocketServer/node_modules
# IDE
.vscode
.cproject
.project
.settings
*.swp

45
.travis.yml Normal file
View 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

View File

@ -1,4 +1,4 @@
WebSocket Server and Client for Arduino
WebSocket Server and Client for Arduino [![Build Status](https://github.com/Links2004/arduinoWebSockets/workflows/CI/badge.svg?branch=master)](https://github.com/Links2004/arduinoWebSockets/actions?query=workflow%3ACI+branch%3Amaster)
===========================================
a WebSocket Server and Client for Arduino based on RFC6455.
@ -10,22 +10,23 @@ a WebSocket Server and Client for Arduino based on RFC6455.
- connection close
- ping
- pong
##### Not supported features of RFC6455 #####
- continuation frame
##### Limitations #####
- 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)
- 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 #####
- 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.
##### 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
- Particle with STM32 ARM Cortex M3
- ATmega328 with Ethernet Shield (ATmega branch)
- ATmega328 with enc28j60 (ATmega branch)
- ATmega2560 with Ethernet Shield (ATmega branch)
@ -33,22 +34,62 @@ a WebSocket Server and Client for Arduino based on RFC6455.
###### 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++.
### wss / SSL ###
supported for:
- 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 ###
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.
### 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 ###
Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues

View 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;
}
}

View 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();
}

View File

@ -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 <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <WiFiClientSecure.h>
#include <WebSocketsClient.h>
#include <Hash.h>
ESP8266WiFiMulti WiFiMulti;
WiFiMulti WiFiMulti;
WebSocketsClient webSocket;
#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) {
@ -42,11 +56,17 @@ void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) {
// webSocket.sendTXT("message here");
break;
case WStype_BIN:
USE_SERIAL.printf("[WSc] get binary lenght: %u\n", lenght);
hexdump(payload, lenght);
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
hexdump(payload, length);
// send data to server
// webSocket.sendBIN(payload, lenght);
// 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;
}
@ -76,8 +96,7 @@ void setup() {
delay(100);
}
webSocket.begin("192.168.0.123", 81);
//webSocket.setAuthorization("user", "Password"); // HTTP Basic Authorization
webSocket.beginSSL("192.168.0.123", 81);
webSocket.onEvent(webSocketEvent);
}

View 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();
}

View 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();
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View 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();
}

View File

@ -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();
}

View File

@ -18,7 +18,7 @@ WebSocketsServer webSocket = WebSocketsServer(81);
#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) {
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");
break;
case WStype_BIN:
USE_SERIAL.printf("[%u] get binary lenght: %u\n", num, lenght);
hexdump(payload, lenght);
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
hexdump(payload, length);
// send message to client
// webSocket.sendBIN(num, payload, lenght);
// webSocket.sendBIN(num, payload, length);
break;
}

View File

@ -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();
}
}

View File

@ -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();
}

View 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();
}

View 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 "$@"

View 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()

View File

@ -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();
}

View File

@ -23,10 +23,10 @@
ESP8266WiFiMulti WiFiMulti;
ESP8266WebServer server = ESP8266WebServer(80);
ESP8266WebServer server(80);
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) {
case WStype_DISCONNECTED:
@ -100,7 +100,7 @@ void setup() {
// 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\" 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();
@ -119,4 +119,3 @@ void loop() {
webSocket.loop();
server.handleClient();
}

View 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();
}

View File

@ -1,19 +1,25 @@
{
"name": "WebSockets",
"keywords": "wifi, http, web, server, client, websocket",
"description": "WebSocket Server and Client for Arduino based on RFC6455",
"repository":
"authors": [
{
"maintainer": true,
"name": "Markus Sattler",
"url": "https://github.com/Links2004"
}
],
"description": "WebSocket Server and Client for Arduino based on RFC6455",
"export": {
"exclude": [
"tests"
]
},
"frameworks": "arduino",
"keywords": "wifi, http, web, server, client, websocket",
"license": "LGPL-2.1",
"name": "WebSockets",
"platforms": "atmelavr, espressif8266, espressif32",
"repository": {
"type": "git",
"url": "https://github.com/Links2004/arduinoWebSockets.git"
},
"exclude": "tests",
"frameworks": "arduino",
"platforms": "*",
"authors":
{
"name": "Markus Sattler",
"url": "https://github.com/Links2004",
"maintainer": true
}
"version": "2.3.5"
}

View File

@ -1,5 +1,5 @@
name=WebSockets
version=2.0.2
version=2.3.5
author=Markus Sattler
maintainer=Markus Sattler
sentence=WebSockets for Arduino (Server + Client)

252
src/SocketIOclient.cpp Normal file
View 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
View 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_ */

View File

@ -38,6 +38,15 @@ extern "C" {
#ifdef ESP8266
#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
extern "C" {
@ -50,14 +59,14 @@ extern "C" {
*
* @param client WSclient_t * ptr to the client struct
* @param code uint16_t see RFC
* @param reason
* @param reasonLen
* @param reason ptr to the disconnect reason message
* @param reasonLen length of the disconnect reason message
*/
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);
if(client->status == WSC_CONNECTED && code) {
if(reason) {
sendFrame(client, WSop_close, (uint8_t *) reason, reasonLen);
sendFrame(client, WSop_close, (uint8_t *)reason, reasonLen);
} else {
uint8_t buffer[2];
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 payload uint8_t *
* @param length size_t
* @param length size_t length of the payload
* @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 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) {
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 WebSockets::createHeader(uint8_t * headerPtr, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin) {
uint8_t headerSize;
uint8_t * headerPtr;
uint8_t * payloadPtr = payload;
bool useInternBuffer = false;
bool ret = true;
// calculate header Size
if(length < 126) {
headerSize = 2;
@ -120,29 +101,6 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
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
// byte 0
@ -192,15 +150,123 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
}
if(mask) {
if(useInternBuffer) {
*headerPtr = maskKey[0];
headerPtr++;
*headerPtr = maskKey[1];
headerPtr++;
*headerPtr = maskKey[2];
headerPtr++;
*headerPtr = maskKey[3];
headerPtr++;
}
return headerSize;
}
/**
*
* @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 };
uint8_t headerSize = createHeader(&buffer[0], opcode, length, client->cIsClient, maskKey, fin);
if(write(client, &buffer[0], headerSize) != headerSize) {
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);
*headerPtr = maskKey[x];
headerPtr++;
}
}
createHeader(headerPtr, opcode, length, client->cIsClient, maskKey, fin);
if(client->cIsClient && useInternBuffer) {
uint8_t * dataMaskPtr;
if(headerToPayload) {
@ -212,17 +278,6 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
for(size_t x = 0; x < length; x++) {
dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]);
}
} else {
*headerPtr = maskKey[0];
headerPtr++;
*headerPtr = maskKey[1];
headerPtr++;
*headerPtr = maskKey[2];
headerPtr++;
*headerPtr = maskKey[3];
headerPtr++;
}
}
#ifndef NODEBUG_WEBSOCKETS
@ -233,24 +288,24 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
// 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
// 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;
}
} else {
// send header
if(client->tcp->write(&buffer[0], headerSize) != headerSize) {
if(write(client, &buffer[0], headerSize) != headerSize) {
ret = false;
}
if(payloadPtr && length > 0) {
// send payload
if(client->tcp->write(&payloadPtr[0], length) != length) {
if(write(client, &payloadPtr[0], length) != length) {
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
if(useInternBuffer && payloadPtr) {
@ -268,8 +323,8 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
void WebSockets::headerDone(WSclient_t * client) {
client->status = WSC_CONNECTED;
client->cWsRXsize = 0;
DEBUG_WEBSOCKETS("[WS][%d][headerDone] Header Handling Done (%uus).\n", client->num);
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
DEBUG_WEBSOCKETS("[WS][%d][headerDone] Header Handling Done.\n", client->num);
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client->cHttpLine = "";
handleWebsocket(client);
#endif
@ -296,7 +351,7 @@ bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t 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;
}
@ -316,12 +371,12 @@ bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) {
// timeout or error
server->clientDisconnect(client, 1002);
}
}, this, size, std::placeholders::_1, std::placeholders::_2));
},
this, size, std::placeholders::_1, std::placeholders::_2));
return false;
}
void WebSockets::handleWebsocketCb(WSclient_t * client) {
if(!client->tcp || !client->tcp->connected()) {
return;
}
@ -342,11 +397,11 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
header->rsv1 = ((*buffer >> 6) & 0x01);
header->rsv2 = ((*buffer >> 5) & 0x01);
header->rsv3 = ((*buffer >> 4) & 0x01);
header->opCode = (WSopcode_t) (*buffer & 0x0F);
header->opCode = (WSopcode_t)(*buffer & 0x0F);
buffer++;
header->mask = ((*buffer >> 7) & 0x01);
header->payloadLen = (WSopcode_t) (*buffer & 0x7F);
header->payloadLen = (WSopcode_t)(*buffer & 0x7F);
buffer++;
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) {
// really to big!
// really too big!
header->payloadLen = 0xFFFFFFFF;
} else {
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);
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);
return;
}
@ -393,7 +448,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
if(header->payloadLen > 0) {
// if text data we need one more
payload = (uint8_t *) malloc(header->payloadLen + 1);
payload = (uint8_t *)malloc(header->payloadLen + 1);
if(!payload) {
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) {
WSMessageHeader_t * header = &client->cWsHeaderDecode;
if(ok) {
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);
// no break here!
case WSop_binary:
messageRecived(client, header->opCode, payload, header->payloadLen);
case WSop_continuation:
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
break;
case WSop_ping:
// 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);
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
break;
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;
case WSop_close: {
#ifndef NODEBUG_WEBSOCKETS
uint16_t reasonCode = 1000;
if(header->payloadLen >= 2) {
reasonCode = payload[0] << 8 | payload[1];
}
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode);
#endif
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d\n", client->num, reasonCode);
if(header->payloadLen > 2) {
DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2));
} else {
DEBUG_WEBSOCKETS("\n");
}
clientDisconnect(client, 1000);
}
break;
case WSop_continuation:
// continuation is not supported
clientDisconnect(client, 1003);
break;
} break;
default:
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] got unknown opcode: %d\n", client->num, header->opCode);
clientDisconnect(client, 1002);
break;
}
@ -465,7 +521,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
// reset input
client->cWsRXsize = 0;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
//register callback for next message
handleWebsocketWaitFor(client, 2);
#endif
@ -486,11 +542,14 @@ String WebSockets::acceptKey(String & clientKey) {
uint8_t sha1HashBin[20] = { 0 };
#ifdef ESP8266
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
clientKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1_CTX 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);
#endif
@ -508,11 +567,11 @@ String WebSockets::acceptKey(String & clientKey) {
*/
String WebSockets::base64_encode(uint8_t * data, size_t length) {
size_t size = ((length * 1.6f) + 1);
char * buffer = (char *) malloc(size);
char * buffer = (char *)malloc(size);
if(buffer) {
base64_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);
String base64 = String(buffer);
@ -530,7 +589,7 @@ String WebSockets::base64_encode(uint8_t * data, size_t length) {
* @return true if ok
*/
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()) {
return false;
}
@ -539,12 +598,13 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
if(cb) {
cb(client, ok);
}
}, client, std::placeholders::_1, cb));
},
client, std::placeholders::_1, cb));
#else
unsigned long t = millis();
size_t len;
DEBUG_WEBSOCKETS("[readCb] n: %d t: %d\n", n, t);
ssize_t len;
DEBUG_WEBSOCKETS("[readCb] n: %zu t: %lu\n", n, t);
while(n > 0) {
if(client->tcp == NULL) {
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) {
DEBUG_WEBSOCKETS("[readCb] receive TIMEOUT! %d\n", (millis() - t));
DEBUG_WEBSOCKETS("[readCb] receive TIMEOUT! %lu\n", (millis() - t));
if(cb) {
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 (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD_MORE();
continue;
}
len = client->tcp->read((uint8_t*) out, n);
if(len) {
len = client->tcp->read((uint8_t *)out, n);
if(len > 0) {
t = millis();
out += len;
n -= len;
@ -586,14 +644,114 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
} else {
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
}
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
if(n > 0) {
WEBSOCKETS_YIELD();
}
}
if(cb) {
cb(client, true);
}
WEBSOCKETS_YIELD();
#endif
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);
}
}
}
}
}

View File

@ -25,62 +25,128 @@
#ifndef 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 <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__ )
#endif
#endif
#ifndef DEBUG_WEBSOCKETS
#define DEBUG_WEBSOCKETS(...)
#ifndef NODEBUG_WEBSOCKETS
#define NODEBUG_WEBSOCKETS
#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
#define WEBSOCKETS_TCP_TIMEOUT (2000)
#if defined(ESP8266) || defined(ESP32)
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
#define WEBSOCKETS_USE_BIG_MEM
#define GET_FREE_HEAP ESP.getFreeHeap()
// 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
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
#if !defined(WEBSOCKETS_NETWORK_TYPE)
// select Network type based
#if defined(ESP8266) || defined(ESP31B)
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
//#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
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
#endif
#endif
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
// Includes and defined based on Network Type
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
// Note:
// No SSL/WSS support for client in Async mode
// 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!"
#endif
#ifdef ESP8266
#include <ESP8266WiFi.h>
#else
#include <ESP31BWiFi.h>
#endif
#include <ESPAsyncTCP.h>
#include <ESPAsyncTCPbuffer.h>
#define WEBSOCKETS_NETWORK_CLASS AsyncTCPbuffer
#define WEBSOCKETS_NETWORK_SERVER_CLASS AsyncServer
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
#if !defined(ESP8266) && !defined(ESP31B)
#error "network type ESP8266 only possible on the ESP mcu!"
@ -88,33 +154,70 @@
#ifdef ESP8266
#include <ESP8266WiFi.h>
#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
#define SSL_BARESSL
#else
#define SSL_AXTLS
#endif
#else
#include <ESP31BWiFi.h>
#endif
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
#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 <SPI.h>
#define WEBSOCKETS_NETWORK_CLASS EthernetClient
#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer
#endif
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60)
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60)
#include <UIPEthernet.h>
#define WEBSOCKETS_NETWORK_CLASS UIPClient
#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
#error "no network type selected!"
#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 {
WSC_NOT_CONNECTED,
WSC_HEADER,
WSC_BODY,
WSC_CONNECTED
} WSclientsStatus_t;
@ -123,7 +226,13 @@ typedef enum {
WStype_DISCONNECTED,
WStype_CONNECTED,
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;
typedef enum {
@ -138,7 +247,6 @@ typedef enum {
} WSopcode_t;
typedef struct {
bool fin;
bool rsv1;
bool rsv2;
@ -153,44 +261,68 @@ typedef struct {
} WSMessageHeader_t;
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)
bool isSSL; ///< run in ssl mode
WiFiClientSecure * ssl;
WEBSOCKETS_NETWORK_CLASS * tcp = nullptr;
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
String cUrl; ///< http url
uint16_t cCode; ///< http code
uint16_t cCode = 0; ///< http code
bool cIsUpgrade; ///< Connection == Upgrade
bool cIsWebsocket; ///< Upgrade == websocket
bool cIsClient = false; ///< will be used for masking
bool cIsUpgrade = false; ///< Connection == Upgrade
bool cIsWebsocket = false; ///< Upgrade == websocket
String cSessionId; ///< client Set-Cookie (session id)
String cKey; ///< client Sec-WebSocket-Key
String cAccept; ///< client Sec-WebSocket-Accept
String cProtocol; ///< client Sec-WebSocket-Protocol
String cExtensions; ///< client Sec-WebSocket-Extensions
uint16_t cVersion; ///< client Sec-WebSocket-Version
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
WSMessageHeader_t cWsHeaderDecode;
String base64Authorization; ///< Base64 encoded Auth request
String plainAuthorization; ///< Base64 encoded Auth request
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
String extraHeaders;
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
} WSclient_t;
class WebSockets {
protected:
#ifdef __AVR__
@ -199,13 +331,16 @@ class WebSockets {
typedef std::function<void(WSclient_t * client, bool ok)> WSreadWaitCb;
#endif
virtual void clientDisconnect(WSclient_t * client);
virtual bool clientIsConnected(WSclient_t * client);
virtual void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
virtual void clientDisconnect(WSclient_t * client) = 0;
virtual bool clientIsConnected(WSclient_t * client) = 0;
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 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);
virtual void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) = 0;
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 headerDone(WSclient_t * client);
@ -218,9 +353,15 @@ class WebSockets {
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);
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_ */

View 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

View File

@ -25,10 +25,14 @@
#include "WebSockets.h"
#include "WebSocketsClient.h"
WebSocketsClient::WebSocketsClient() {
_cbEvent = NULL;
_client.num = 0;
_client.cIsClient = true;
_client.extraHeaders = WEBSOCKETS_STRING("Origin: file://");
_reconnectInterval = 500;
_port = 0;
_host = "";
}
WebSocketsClient::~WebSocketsClient() {
@ -38,17 +42,18 @@ WebSocketsClient::~WebSocketsClient() {
/**
* 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;
_port = port;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
_fingerprint = "";
#if defined(HAS_SSL)
_fingerprint = SSL_FINGERPRINT_NULL;
_CA_cert = NULL;
#endif
_client.num = 0;
_client.status = WSC_NOT_CONNECTED;
_client.tcp = NULL;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
#if defined(HAS_SSL)
_client.isSSL = false;
_client.ssl = NULL;
#endif
@ -63,6 +68,11 @@ void WebSocketsClient::begin(const char *host, uint16_t port, const char * url,
_client.cVersion = 0;
_client.base64Authorization = "";
_client.plainAuthorization = "";
_client.isSocketIO = false;
_client.lastPing = 0;
_client.pongReceived = false;
_client.pongTimeoutCount = 0;
#ifdef ESP8266
randomSeed(RANDOM_REG32);
@ -70,36 +80,135 @@ void WebSocketsClient::begin(const char *host, uint16_t port, const char * url,
// todo find better seed
randomSeed(millis());
#endif
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
asyncConnect();
#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) {
begin(host.c_str(), port, url.c_str(), protocol.c_str());
}
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
void WebSocketsClient::beginSSL(const char *host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) {
void WebSocketsClient::begin(IPAddress host, uint16_t port, const char * url, 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);
_client.isSSL = true;
_fingerprint = fingerprint;
_CA_cert = NULL;
}
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());
}
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
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
*/
void WebSocketsClient::loop(void) {
if(_port == 0) {
return;
}
WEBSOCKETS_YIELD();
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) {
DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n");
if(_client.ssl) {
@ -107,15 +216,40 @@ void WebSocketsClient::loop(void) {
_client.ssl = NULL;
_client.tcp = NULL;
}
_client.ssl = new WiFiClientSecure();
_client.ssl = new WEBSOCKETS_NETWORK_SSL_CLASS();
_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 {
DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n");
if(_client.tcp) {
delete _client.tcp;
_client.tcp = NULL;
}
_client.tcp = new WiFiClient();
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
}
#else
_client.tcp = new WEBSOCKETS_NETWORK_CLASS();
@ -125,15 +259,25 @@ void WebSocketsClient::loop(void) {
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
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)) {
#endif
connectedCb();
_lastConnectionFail = 0;
} else {
connectFailedCb();
delay(10); //some little delay to not flood the server
_lastConnectionFail = millis();
}
} else {
handleClientData();
WEBSOCKETS_YIELD();
if(_client.status == WSC_CONNECTED) {
handleHBPing();
handleHBTimeout(&_client);
}
}
}
#endif
@ -156,28 +300,34 @@ void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) {
*/
bool WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
if(length == 0) {
length = strlen((const char *) payload);
length = strlen((const char *)payload);
}
if(clientIsConnected(&_client)) {
return sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload);
return sendFrame(&_client, WSop_text, payload, length, true, headerToPayload);
}
return false;
}
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) {
return sendTXT((uint8_t *) payload, length, headerToPayload);
return sendTXT((uint8_t *)payload, length, headerToPayload);
}
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) {
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);
}
/**
@ -190,13 +340,33 @@ bool WebSocketsClient::sendTXT(String & payload) {
*/
bool WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
if(clientIsConnected(&_client)) {
return sendFrame(&_client, WSop_binary, payload, length, true, true, headerToPayload);
return sendFrame(&_client, WSop_binary, payload, length, true, headerToPayload);
}
return false;
}
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());
}
/**
@ -234,6 +404,28 @@ void WebSocketsClient::setAuthorization(const char * 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);
}
//#################################################################################
//#################################################################################
//#################################################################################
@ -243,22 +435,35 @@ void WebSocketsClient::setAuthorization(const char * auth) {
* @param client WSclient_t * ptr to the client struct
* @param opcode WSopcode_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;
UNUSED(client);
switch(opcode) {
case WSop_text:
type = WStype_TEXT;
type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
break;
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;
}
runCbEvent(type, payload, lenght);
runCbEvent(type, payload, length);
}
/**
@ -266,10 +471,9 @@ void WebSocketsClient::messageRecived(WSclient_t * client, WSopcode_t opcode, ui
* @param client WSclient_t * ptr to the client struct
*/
void WebSocketsClient::clientDisconnect(WSclient_t * client) {
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->ssl->connected()) {
client->ssl->flush();
@ -284,13 +488,13 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
if(client->tcp) {
if(client->tcp->connected()) {
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
client->tcp->flush();
#endif
client->tcp->stop();
}
event = true;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client->status = WSC_NOT_CONNECTED;
#else
delete client->tcp;
@ -301,12 +505,13 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
client->cCode = 0;
client->cKey = "";
client->cAccept = "";
client->cProtocol = "";
client->cVersion = 0;
client->cIsUpgrade = false;
client->cIsWebsocket = false;
client->cSessionId = "";
client->status = WSC_NOT_CONNECTED;
_lastConnectionFail = millis();
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
if(event) {
@ -320,7 +525,6 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
* @return true = conneted
*/
bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
if(!client->tcp) {
return false;
}
@ -345,20 +549,31 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
return false;
}
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
/**
* Handel incomming data from Client
*/
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();
if(len > 0) {
switch(_client.status) {
case WSC_HEADER:
{
case WSC_HEADER: {
String headerLine = _client.tcp->readStringUntil('\n');
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:
WebSockets::handleWebsocket(&_client);
break;
@ -367,9 +582,7 @@ void WebSocketsClient::handleClientData(void) {
break;
}
}
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD();
}
#endif
@ -378,6 +591,7 @@ void WebSocketsClient::handleClientData(void) {
* @param client WSclient_t * ptr to the client struct
*/
void WebSocketsClient::sendHeader(WSclient_t * client) {
static const char * NEW_LINE = "\r\n";
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n");
@ -393,41 +607,75 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
unsigned long start = micros();
#endif
String handshake = "GET " + client->cUrl + " HTTP/1.1\r\n"
"Host: " + _host + ":" + _port + "\r\n"
String handshake;
bool ws_header = true;
String url = client->cUrl;
if(client->isSocketIO) {
if(client->cSessionId.length() == 0) {
url += WEBSOCKETS_STRING("&transport=polling");
ws_header = false;
} else {
url += WEBSOCKETS_STRING("&transport=websocket&sid=");
url += client->cSessionId;
}
}
handshake = WEBSOCKETS_STRING("GET ");
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"
"Origin: file://\r\n"
"User-Agent: arduino-WebSocket-Client\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Key: " + client->cKey + "\r\n";
"Sec-WebSocket-Key: ");
handshake += client->cKey + NEW_LINE;
if(client->cProtocol.length() > 0) {
handshake += "Sec-WebSocket-Protocol: " + client->cProtocol + "\r\n";
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
handshake += client->cProtocol + NEW_LINE;
}
if(client->cExtensions.length() > 0) {
handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n";
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) {
handshake += "Authorization: Basic " + client->base64Authorization + "\r\n";
handshake += WEBSOCKETS_STRING("Authorization: Basic ");
handshake += client->base64Authorization + NEW_LINE;
}
if(client->plainAuthorization.length() > 0) {
handshake += "Authorization: " + client->plainAuthorization + "\r\n";
handshake += WEBSOCKETS_STRING("Authorization: ");
handshake += client->plainAuthorization + NEW_LINE;
}
handshake += "\r\n";
handshake += NEW_LINE;
client->tcp->write(handshake.c_str(), handshake.length());
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] handshake %s", (uint8_t *)handshake.c_str());
write(client, (uint8_t *)handshake.c_str(), handshake.length());
#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)));
#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();
}
/**
@ -435,46 +683,71 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
* @param client WSclient_t * ptr to the client struct
*/
void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
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) {
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"
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 headerValue = headerLine->substring(headerLine->indexOf(':') + 2);
String headerValue = headerLine->substring(headerLine->indexOf(':') + 1);
if(headerName.equalsIgnoreCase("Connection")) {
if(headerValue.equalsIgnoreCase("upgrade")) {
// remove space in the beginning (RFC2616)
if(headerValue[0] == ' ') {
headerValue.remove(0, 1);
}
if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("upgrade"))) {
client->cIsUpgrade = true;
}
} else if(headerName.equalsIgnoreCase("Upgrade")) {
if(headerValue.equalsIgnoreCase("websocket")) {
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
client->cIsWebsocket = true;
}
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Accept")) {
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Accept"))) {
client->cAccept = headerValue;
client->cAccept.trim(); // see rfc6455
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) {
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
client->cProtocol = headerValue;
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) {
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
client->cExtensions = headerValue;
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) {
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
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 {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
}
(*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)));
#endif
} else {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n");
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n");
@ -490,6 +763,15 @@ 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] - cExtensions: %s\n", client->cExtensions.c_str());
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);
@ -498,18 +780,22 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
case 101: ///< Switching Protocols
break;
case 200:
if(client->isSocketIO) {
break;
}
case 403: ///< Forbidden
// todo handle login
default: ///< Server dont unterstand requrst
ok = false;
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
clientDisconnect(client);
_lastConnectionFail = millis();
break;
}
}
if(ok) {
if(client->cAccept.length() == 0) {
ok = false;
} else {
@ -523,26 +809,39 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
}
if(ok) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n");
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 {
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);
}
}
}
void WebSocketsClient::connectedCb() {
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 {
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
client->status = WSC_NOT_CONNECTED;
@ -552,42 +851,50 @@ void WebSocketsClient::connectedCb() {
c->asyncConnect();
return true;
}, this, std::placeholders::_1, &_client));
},
this, std::placeholders::_1, &_client));
#endif
_client.status = WSC_HEADER;
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
// set Timeout for readBytesUntil and readStringUntil
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
#endif
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
_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())) {
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
WebSockets::clientDisconnect(&_client, 1000);
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
// send Header to Server
sendHeader(&_client);
}
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() {
DEBUG_WEBSOCKETS("[WS-Client] asyncConnect...\n");
AsyncClient * tcpclient = new AsyncClient();
@ -597,12 +904,12 @@ void WebSocketsClient::asyncConnect() {
return;
}
tcpclient->onDisconnect([](void *obj, AsyncClient* c) {
tcpclient->onDisconnect([](void * obj, AsyncClient * c) {
c->free();
delete c;
});
tcpclient->onConnect(std::bind([](WebSocketsClient * ws , AsyncClient * tcp) {
tcpclient->onConnect(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
ws->_client.tcp = new AsyncTCPbuffer(tcp);
if(!ws->_client.tcp) {
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!\n");
@ -610,20 +917,57 @@ void WebSocketsClient::asyncConnect() {
return;
}
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();
// reconnect
ws->asyncConnect();
}, this, std::placeholders::_2));
},
this, std::placeholders::_2));
if(!tcpclient->connect(_host.c_str(), _port)) {
connectFailedCb();
delete tcpclient;
}
}
#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;
}

View File

@ -25,34 +25,54 @@
#ifndef WEBSOCKETSCLIENT_H_
#define WEBSOCKETSCLIENT_H_
#include <Arduino.h>
#include "WebSockets.h"
class WebSocketsClient: private WebSockets {
class WebSocketsClient : protected WebSockets {
public:
#ifdef __AVR__
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
#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
WebSocketsClient(void);
~WebSocketsClient(void);
virtual ~WebSocketsClient(void);
void begin(const char *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");
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");
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
void beginSSL(const char *host, uint16_t port, const char * url = "/", const char * = "", const char * protocol = "arduino");
#if defined(HAS_SSL)
#ifdef SSL_AXTLS
void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * fingerprint = "", const char * protocol = "arduino");
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
#else
void beginSSL(const char * host, uint16_t port, const char * url = "/", const uint8_t * fingerprint = NULL, const char * protocol = "arduino");
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
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
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");
#if defined(HAS_SSL)
void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
#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");
#endif
#endif
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void loop(void);
#else
// Async interface not need a loop call
void loop(void) __attribute__ ((deprecated)) {}
void loop(void) __attribute__((deprecated)) {}
#endif
void onEvent(WebSocketClientEvent cbEvent);
@ -62,32 +82,62 @@ class WebSocketsClient: private WebSockets {
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 (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
#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;
void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
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)
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void handleClientData(void);
#endif
@ -97,7 +147,9 @@ class WebSocketsClient: private WebSockets {
void connectedCb();
void connectFailedCb();
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
void handleHBPing(); // send ping in specified intervals
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
void asyncConnect();
#endif
@ -112,7 +164,6 @@ class WebSocketsClient: private WebSockets {
_cbEvent(type, payload, length);
}
}
};
#endif /* WEBSOCKETSCLIENT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -25,37 +25,33 @@
#ifndef WEBSOCKETSSERVER_H_
#define WEBSOCKETSSERVER_H_
#include <Arduino.h>
#include "WebSockets.h"
#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);
class WebSocketsServer: private WebSockets {
public:
void begin(void);
void close(void);
#ifdef __AVR__
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue);
#else
typedef std::function<void (uint8_t num, WStype_t type, uint8_t * payload, size_t length)> WebSocketServerEvent;
#endif
WebSocketsServer(uint16_t port, String origin = "", String protocol = "arduino");
~WebSocketsServer(void);
void begin(void);
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void loop(void);
#else
// Async interface not need a loop call
void loop(void) __attribute__ ((deprecated)) {}
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
void onEvent(WebSocketServerEvent cbEvent);
void onValidateHttpHeader(
WebSocketServerHttpHeaderValFunc validationFunc,
const char * mandatoryHttpHeaders[],
size_t mandatoryHttpHeaderCount);
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);
@ -75,42 +71,65 @@ public:
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);
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
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
protected:
uint16_t _port;
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void loop(void); // handle client data only
#endif
WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
protected:
String _origin;
String _protocol;
String _base64Authorization; ///< Base64 encoded Auth request
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
String * _mandatoryHttpHeaders;
size_t _mandatoryHttpHeaderCount;
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
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 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 handleNewClients(void);
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void handleClientData(void);
#endif
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.
@ -119,7 +138,8 @@ protected:
*/
virtual void handleNonWebsocketConnection(WSclient_t * client) {
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(
"HTTP/1.1 400 Bad Request\r\n"
"Server: arduino-WebSocket-Server\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 32\r\n"
@ -135,9 +155,9 @@ protected:
* Note: can be override
* @param client WSclient_t * ptr to the client struct
*/
virtual void handleAuthorizationFailed(WSclient_t *client) {
client->tcp->write("HTTP/1.1 401 Unauthorized\r\n"
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"
@ -162,8 +182,62 @@ protected:
}
}
/*
* 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_ */

36
src/WebSocketsVersion.h Normal file
View 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_ */

View File

@ -9,6 +9,10 @@ For details, see http://sourceforge.net/projects/libb64
#include <core_esp8266_features.h>
#endif
#if defined(ESP32)
#define CORE_HAS_LIBB64
#endif
#ifndef CORE_HAS_LIBB64
#include "cdecode_inc.h"

View File

@ -9,6 +9,10 @@ For details, see http://sourceforge.net/projects/libb64
#include <core_esp8266_features.h>
#endif
#if defined(ESP32)
#define CORE_HAS_LIBB64
#endif
#ifndef CORE_HAS_LIBB64
#include "cencode_inc.h"

View File

@ -18,7 +18,7 @@ A million repetitions of "a"
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
/* #define SHA1HANDSOFF * Copies data before messing with it. */
#ifndef ESP8266
#if !defined(ESP8266) && !defined(ESP32)
#define SHA1HANDSOFF

View File

@ -5,7 +5,7 @@ By Steve Reid <steve@edmweb.com>
100% Public Domain
*/
#ifndef ESP8266
#if !defined(ESP8266) && !defined(ESP32)
typedef struct {
uint32_t state[5];

View File

@ -7,7 +7,7 @@ var server = http.createServer(function(request, response) {
response.writeHead(404);
response.end();
});
server.listen(81, function() {
server.listen(8011, function() {
console.log((new Date()) + ' Server is listening on port 8011');
});

131
travis/common.sh Normal file
View 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
View 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!')