mirror of
https://github.com/Links2004/arduinoWebSockets.git
synced 2025-06-27 16:01:01 +02:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
11273d9f69 | |||
82e3c57006 | |||
3f5c7e1c46 | |||
7c5113fe2d |
24
.travis.yml
24
.travis.yml
@ -2,28 +2,30 @@ sudo: false
|
|||||||
language: bash
|
language: bash
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
|
env:
|
||||||
|
matrix:
|
||||||
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:CpuFrequency=80" IDE_VERSION=1.6.5
|
||||||
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:CpuFrequency=80,FlashSize=1M0,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.5
|
||||||
|
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:CpuFrequency=80,Debug=Serial1" IDE_VERSION=1.6.5
|
||||||
|
- CPU="avr" BOARD="arduino:avr:mega:cpu=atmega2560" IDE_VERSION=1.6.5
|
||||||
|
|
||||||
script:
|
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
|
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
|
||||||
- sleep 3
|
- sleep 3
|
||||||
- export DISPLAY=:1.0
|
- export DISPLAY=:1.0
|
||||||
- wget http://downloads.arduino.cc/arduino-1.6.5-linux64.tar.xz
|
- wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz
|
||||||
- tar xf arduino-1.6.5-linux64.tar.xz
|
- tar xf arduino-$IDE_VERSION-linux64.tar.xz
|
||||||
- mv arduino-1.6.5 $HOME/arduino_ide
|
- mv arduino-$IDE_VERSION $HOME/arduino_ide
|
||||||
- export PATH="$HOME/arduino_ide:$PATH"
|
- export PATH="$HOME/arduino_ide:$PATH"
|
||||||
- which arduino
|
- which arduino
|
||||||
- mkdir -p $HOME/Arduino/libraries
|
- mkdir -p $HOME/Arduino/libraries
|
||||||
- cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/arduinoWebSockets
|
- cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/arduinoWebSockets
|
||||||
- cd $HOME/arduino_ide/hardware
|
|
||||||
- mkdir esp8266com
|
|
||||||
- cd esp8266com
|
|
||||||
- git clone https://github.com/esp8266/Arduino.git esp8266
|
|
||||||
- cd esp8266/tools
|
|
||||||
- python get.py
|
|
||||||
- source $TRAVIS_BUILD_DIR/travis/common.sh
|
- source $TRAVIS_BUILD_DIR/travis/common.sh
|
||||||
- arduino --board esp8266com:esp8266:generic --save-prefs
|
- get_core $CPU
|
||||||
|
- cd $TRAVIS_BUILD_DIR
|
||||||
|
- arduino --board $BOARD --save-prefs
|
||||||
- arduino --get-pref sketchbook.path
|
- arduino --get-pref sketchbook.path
|
||||||
- build_sketches arduino $HOME/Arduino/libraries/arduinoWebSockets esp8266
|
- build_sketches arduino $HOME/Arduino/libraries/arduinoWebSockets/examples/$CPU $CPU
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
69
README.md
69
README.md
@ -1,4 +1,4 @@
|
|||||||
WebSocket Server and Client for Arduino [](https://travis-ci.org/Links2004/arduinoWebSockets)
|
WebSocket Server and Client for Arduino
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
a WebSocket Server and Client for Arduino based on RFC6455.
|
a WebSocket Server and Client for Arduino based on RFC6455.
|
||||||
@ -10,80 +10,25 @@ a WebSocket Server and Client for Arduino based on RFC6455.
|
|||||||
- connection close
|
- connection close
|
||||||
- ping
|
- ping
|
||||||
- pong
|
- pong
|
||||||
|
|
||||||
|
##### Not supported features of RFC6455 #####
|
||||||
- continuation frame
|
- continuation frame
|
||||||
|
|
||||||
##### Limitations #####
|
##### Limitations #####
|
||||||
- max input length is limited to the ram size and the ```WEBSOCKETS_MAX_DATA_SIZE``` define
|
- max input length is limited to the ram size and the ```WEBSOCKETS_MAX_DATA_SIZE``` define
|
||||||
- max output length has no limit (the hardware is the limit)
|
- max output length has no limit (the hardware is the limit)
|
||||||
- Client send big frames with mask 0x00000000 (on AVR all frames)
|
- Client send big frames with mask 0x00000000 (on AVR all frames)
|
||||||
- continuation frame reassembly need to be handled in the application code
|
|
||||||
|
|
||||||
##### Limitations for Async #####
|
|
||||||
- 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 #####
|
##### Supported Hardware #####
|
||||||
- ESP8266 [Arduino for ESP8266](https://github.com/Links2004/Arduino)
|
- ESP8266 [Arduino for ESP8266](https://github.com/Links2004/Arduino)
|
||||||
- ESP31B
|
- ATmega328 with Ethernet Shield (alpha)
|
||||||
- Particle with STM32 ARM Cortex M3
|
- ATmega328 with enc28j60 (alpha)
|
||||||
- ATmega328 with Ethernet Shield (ATmega branch)
|
- ATmega2560 with Ethernet Shield (alpha)
|
||||||
- ATmega328 with enc28j60 (ATmega branch)
|
- ATmega2560 with enc28j60 (alpha)
|
||||||
- ATmega2560 with Ethernet Shield (ATmega branch)
|
|
||||||
- ATmega2560 with enc28j60 (ATmega branch)
|
|
||||||
|
|
||||||
###### Note: ######
|
|
||||||
|
|
||||||
version 2.0 and up is not compatible with AVR/ATmega, check ATmega branch.
|
|
||||||
|
|
||||||
Arduino for AVR not supports std namespace of c++.
|
|
||||||
|
|
||||||
### wss / SSL ###
|
### wss / SSL ###
|
||||||
supported for:
|
supported for:
|
||||||
- wss client on the ESP8266
|
- wss client on the ESP8266
|
||||||
- wss / SSL is not natively supported in WebSocketsServer however it is possible to achieve secure websockets
|
|
||||||
by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a
|
|
||||||
sample Nginx server configuration file to enable this.
|
|
||||||
|
|
||||||
### ESP Async TCP ###
|
|
||||||
|
|
||||||
This libary can run in Async TCP mode on the ESP.
|
|
||||||
|
|
||||||
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.
|
|
||||||
```
|
|
||||||
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
|
|
||||||
|
|
||||||
```
|
|
||||||
void onEvent(WebSocketClientEvent cbEvent);
|
|
||||||
```
|
|
||||||
|
|
||||||
- `WebSocketClientEvent`: Handler for websocket events
|
|
||||||
```
|
|
||||||
void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length)
|
|
||||||
```
|
|
||||||
Where `WStype_t type` is defined as:
|
|
||||||
```
|
|
||||||
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_t;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issues ###
|
### Issues ###
|
||||||
Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues
|
Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
# 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/* 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();
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
WebSocketClientSockJsAndStomp.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 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();
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* WebSocketClientSocketIO.ino
|
|
||||||
*
|
|
||||||
* Created on: 06.06.2016
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESP8266WiFiMulti.h>
|
|
||||||
|
|
||||||
#include <WebSocketsClient.h>
|
|
||||||
|
|
||||||
#include <Hash.h>
|
|
||||||
|
|
||||||
ESP8266WiFiMulti WiFiMulti;
|
|
||||||
WebSocketsClient webSocket;
|
|
||||||
|
|
||||||
|
|
||||||
#define USE_SERIAL Serial1
|
|
||||||
|
|
||||||
#define MESSAGE_INTERVAL 30000
|
|
||||||
#define HEARTBEAT_INTERVAL 25000
|
|
||||||
|
|
||||||
uint64_t messageTimestamp = 0;
|
|
||||||
uint64_t heartbeatTimestamp = 0;
|
|
||||||
bool isConnected = false;
|
|
||||||
|
|
||||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
|
||||||
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case WStype_DISCONNECTED:
|
|
||||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
|
||||||
isConnected = false;
|
|
||||||
break;
|
|
||||||
case WStype_CONNECTED:
|
|
||||||
{
|
|
||||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
|
||||||
isConnected = true;
|
|
||||||
|
|
||||||
// send message to server when Connected
|
|
||||||
// socket.io upgrade confirmation message (required)
|
|
||||||
webSocket.sendTXT("5");
|
|
||||||
}
|
|
||||||
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(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
webSocket.beginSocketIO("192.168.0.123", 81);
|
|
||||||
//webSocket.setAuthorization("user", "Password"); // HTTP Basic Authorization
|
|
||||||
webSocket.onEvent(webSocketEvent);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
webSocket.loop();
|
|
||||||
|
|
||||||
if(isConnected) {
|
|
||||||
|
|
||||||
uint64_t now = millis();
|
|
||||||
|
|
||||||
if(now - messageTimestamp > MESSAGE_INTERVAL) {
|
|
||||||
messageTimestamp = now;
|
|
||||||
// example socket.io message with type "messageType" and JSON payload
|
|
||||||
webSocket.sendTXT("42[\"messageType\",{\"greeting\":\"hello\"}]");
|
|
||||||
}
|
|
||||||
if((now - heartbeatTimestamp) > HEARTBEAT_INTERVAL) {
|
|
||||||
heartbeatTimestamp = now;
|
|
||||||
// socket.io heartbeat message
|
|
||||||
webSocket.sendTXT("2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
|
|
@ -20,7 +20,7 @@ WebSocketsClient webSocket;
|
|||||||
|
|
||||||
#define USE_SERIAL Serial1
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) {
|
||||||
|
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -42,11 +42,11 @@ void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
|||||||
// webSocket.sendTXT("message here");
|
// webSocket.sendTXT("message here");
|
||||||
break;
|
break;
|
||||||
case WStype_BIN:
|
case WStype_BIN:
|
||||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
USE_SERIAL.printf("[WSc] get binary lenght: %u\n", lenght);
|
||||||
hexdump(payload, length);
|
hexdump(payload, lenght);
|
||||||
|
|
||||||
// send data to server
|
// send data to server
|
||||||
// webSocket.sendBIN(payload, length);
|
// webSocket.sendBIN(payload, lenght);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,6 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
webSocket.begin("192.168.0.123", 81);
|
webSocket.begin("192.168.0.123", 81);
|
||||||
//webSocket.setAuthorization("user", "Password"); // HTTP Basic Authorization
|
|
||||||
webSocket.onEvent(webSocketEvent);
|
webSocket.onEvent(webSocketEvent);
|
||||||
|
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ WebSocketsClient webSocket;
|
|||||||
|
|
||||||
#define USE_SERIAL Serial1
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) {
|
||||||
|
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -44,11 +44,11 @@ void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
|||||||
// webSocket.sendTXT("message here");
|
// webSocket.sendTXT("message here");
|
||||||
break;
|
break;
|
||||||
case WStype_BIN:
|
case WStype_BIN:
|
||||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
USE_SERIAL.printf("[WSc] get binary lenght: %u\n", lenght);
|
||||||
hexdump(payload, length);
|
hexdump(payload, lenght);
|
||||||
|
|
||||||
// send data to server
|
// send data to server
|
||||||
// webSocket.sendBIN(payload, length);
|
// webSocket.sendBIN(payload, lenght);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -18,7 +18,7 @@ WebSocketsServer webSocket = WebSocketsServer(81);
|
|||||||
|
|
||||||
#define USE_SERIAL Serial1
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case WStype_DISCONNECTED:
|
case WStype_DISCONNECTED:
|
||||||
@ -43,11 +43,11 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length
|
|||||||
// webSocket.broadcastTXT("message here");
|
// webSocket.broadcastTXT("message here");
|
||||||
break;
|
break;
|
||||||
case WStype_BIN:
|
case WStype_BIN:
|
||||||
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
|
USE_SERIAL.printf("[%u] get binary lenght: %u\n", num, lenght);
|
||||||
hexdump(payload, length);
|
hexdump(payload, lenght);
|
||||||
|
|
||||||
// send message to client
|
// send message to client
|
||||||
// webSocket.sendBIN(num, payload, length);
|
// webSocket.sendBIN(num, payload, lenght);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -26,7 +26,7 @@ ESP8266WiFiMulti WiFiMulti;
|
|||||||
ESP8266WebServer server = ESP8266WebServer(80);
|
ESP8266WebServer server = ESP8266WebServer(80);
|
||||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||||
|
|
||||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case WStype_DISCONNECTED:
|
case WStype_DISCONNECTED:
|
||||||
@ -100,7 +100,7 @@ void setup() {
|
|||||||
// handle index
|
// handle index
|
||||||
server.on("/", []() {
|
server.on("/", []() {
|
||||||
// send index.html
|
// send index.html
|
||||||
server.send(200, "text/html", "<html><head><script>var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);connection.onopen = function () { connection.send('Connect ' + new Date()); }; connection.onerror = function (error) { console.log('WebSocket Error ', error);};connection.onmessage = function (e) { console.log('Server: ', e.data);};function sendRGB() { var r = parseInt(document.getElementById('r').value).toString(16); var g = parseInt(document.getElementById('g').value).toString(16); var b = parseInt(document.getElementById('b').value).toString(16); if(r.length < 2) { r = '0' + r; } if(g.length < 2) { g = '0' + g; } if(b.length < 2) { b = '0' + b; } var rgb = '#'+r+g+b; console.log('RGB: ' + rgb); connection.send(rgb); }</script></head><body>LED Control:<br/><br/>R: <input id=\"r\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" 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.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.begin();
|
server.begin();
|
29
library.json
29
library.json
@ -1,28 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "WebSockets",
|
"name": "WebSockets",
|
||||||
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
|
||||||
"keywords": "wifi, http, web, server, client, websocket",
|
"keywords": "wifi, http, web, server, client, websocket",
|
||||||
"authors": [
|
"description": "WebSocket Server and Client for Arduino based on RFC6455",
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
||||||
|
},
|
||||||
|
"exclude": "tests",
|
||||||
|
"frameworks": "arduino",
|
||||||
|
"platforms": "*",
|
||||||
|
"authors":
|
||||||
{
|
{
|
||||||
"name": "Markus Sattler",
|
"name": "Markus Sattler",
|
||||||
"url": "https://github.com/Links2004",
|
"url": "https://github.com/Links2004",
|
||||||
"maintainer": true
|
"maintainer": true
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/Links2004/arduinoWebSockets.git"
|
|
||||||
},
|
|
||||||
"version": "2.0.7",
|
|
||||||
"license": "LGPL-2.1",
|
|
||||||
"export": {
|
|
||||||
"exclude": [
|
|
||||||
"tests"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"frameworks": "arduino",
|
|
||||||
"platforms": "*",
|
|
||||||
"examples": [
|
|
||||||
"examples/*/*.ino"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
name=WebSockets
|
name=WebSockets
|
||||||
version=2.0.7
|
version=1.3
|
||||||
author=Markus Sattler
|
author=Markus Sattler
|
||||||
maintainer=Markus Sattler
|
maintainer=Markus Sattler
|
||||||
sentence=WebSockets for Arduino (Server + Client)
|
sentence=WebSockets for Arduino (Server + Client)
|
||||||
paragraph=use 2.x.x for ESP and 1.3 for AVR
|
paragraph=
|
||||||
category=Communication
|
category=Communication
|
||||||
url=https://github.com/Links2004/arduinoWebSockets
|
url=https://github.com/Links2004/arduinoWebSockets
|
||||||
architectures=*
|
architectures=*
|
||||||
|
@ -46,6 +46,8 @@ extern "C" {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
@ -77,18 +79,17 @@ void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * rea
|
|||||||
* @param mask bool add dummy mask to the frame (needed for web browser)
|
* @param mask bool add dummy mask to the frame (needed for web browser)
|
||||||
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||||
* @param headerToPayload bool set true if the payload has reserved 14 Byte at the beginning to dynamically add the Header (payload neet to be in RAM!)
|
* @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) {
|
void 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()) {
|
if(client->tcp && !client->tcp->connected()) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not Connected!?\n", client->num);
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not Connected!?\n", client->num);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(client->status != WSC_CONNECTED) {
|
if(client->status != WSC_CONNECTED) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not in WSC_CONNECTED state!?\n", client->num);
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not in WSC_CONNECTED state!?\n", client->num);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] ------- send massage frame -------\n", client->num);
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] ------- send massage frame -------\n", client->num);
|
||||||
@ -105,7 +106,6 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
uint8_t * headerPtr;
|
uint8_t * headerPtr;
|
||||||
uint8_t * payloadPtr = payload;
|
uint8_t * payloadPtr = payload;
|
||||||
bool useInternBuffer = false;
|
bool useInternBuffer = false;
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
// calculate header Size
|
// calculate header Size
|
||||||
if(length < 126) {
|
if(length < 126) {
|
||||||
@ -120,10 +120,11 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
headerSize += 4;
|
headerSize += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef WEBSOCKETS_USE_BIG_MEM
|
#ifdef WEBSOCKETS_USE_BIG_MEM
|
||||||
// only for ESP since AVR has less HEAP
|
// only for ESP since AVR has less HEAP
|
||||||
// try to send data in one TCP package (only if some free Heap is there)
|
// 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)) {
|
if(!headerToPayload && ((length > 0) && (length < 1400)) && (ESP.getFreeHeap() > 6000)) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] pack to one TCP package...\n", client->num);
|
DEBUG_WEBSOCKETS("[WS][%d][sendFrame] pack to one TCP package...\n", client->num);
|
||||||
uint8_t * dataPtr = (uint8_t *) malloc(length + WEBSOCKETS_MAX_HEADER_SIZE);
|
uint8_t * dataPtr = (uint8_t *) malloc(length + WEBSOCKETS_MAX_HEADER_SIZE);
|
||||||
if(dataPtr) {
|
if(dataPtr) {
|
||||||
@ -160,35 +161,22 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(length < 126) {
|
if(length < 126) {
|
||||||
*headerPtr |= length;
|
*headerPtr |= length; headerPtr++;
|
||||||
headerPtr++;
|
|
||||||
} else if(length < 0xFFFF) {
|
} else if(length < 0xFFFF) {
|
||||||
*headerPtr |= 126;
|
*headerPtr |= 126; headerPtr++;
|
||||||
headerPtr++;
|
*headerPtr = ((length >> 8) & 0xFF); headerPtr++;
|
||||||
*headerPtr = ((length >> 8) & 0xFF);
|
*headerPtr = (length & 0xFF); headerPtr++;
|
||||||
headerPtr++;
|
|
||||||
*headerPtr = (length & 0xFF);
|
|
||||||
headerPtr++;
|
|
||||||
} else {
|
} else {
|
||||||
// Normally we never get here (to less memory)
|
// Normally we never get here (to less memory)
|
||||||
*headerPtr |= 127;
|
*headerPtr |= 127; headerPtr++;
|
||||||
headerPtr++;
|
*headerPtr = 0x00; headerPtr++;
|
||||||
*headerPtr = 0x00;
|
*headerPtr = 0x00; headerPtr++;
|
||||||
headerPtr++;
|
*headerPtr = 0x00; headerPtr++;
|
||||||
*headerPtr = 0x00;
|
*headerPtr = 0x00; headerPtr++;
|
||||||
headerPtr++;
|
*headerPtr = ((length >> 24) & 0xFF); headerPtr++;
|
||||||
*headerPtr = 0x00;
|
*headerPtr = ((length >> 16) & 0xFF); headerPtr++;
|
||||||
headerPtr++;
|
*headerPtr = ((length >> 8) & 0xFF); headerPtr++;
|
||||||
*headerPtr = 0x00;
|
*headerPtr = (length & 0xFF); headerPtr++;
|
||||||
headerPtr++;
|
|
||||||
*headerPtr = ((length >> 24) & 0xFF);
|
|
||||||
headerPtr++;
|
|
||||||
*headerPtr = ((length >> 16) & 0xFF);
|
|
||||||
headerPtr++;
|
|
||||||
*headerPtr = ((length >> 8) & 0xFF);
|
|
||||||
headerPtr++;
|
|
||||||
*headerPtr = (length & 0xFF);
|
|
||||||
headerPtr++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mask) {
|
if(mask) {
|
||||||
@ -197,8 +185,7 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
// by this fact its possible the do the masking
|
// by this fact its possible the do the masking
|
||||||
for(uint8_t x = 0; x < sizeof(maskKey); x++) {
|
for(uint8_t x = 0; x < sizeof(maskKey); x++) {
|
||||||
maskKey[x] = random(0xFF);
|
maskKey[x] = random(0xFF);
|
||||||
*headerPtr = maskKey[x];
|
*headerPtr = maskKey[x]; headerPtr++;
|
||||||
headerPtr++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t * dataMaskPtr;
|
uint8_t * dataMaskPtr;
|
||||||
@ -214,14 +201,10 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
*headerPtr = maskKey[0];
|
*headerPtr = maskKey[0]; headerPtr++;
|
||||||
headerPtr++;
|
*headerPtr = maskKey[1]; headerPtr++;
|
||||||
*headerPtr = maskKey[1];
|
*headerPtr = maskKey[2]; headerPtr++;
|
||||||
headerPtr++;
|
*headerPtr = maskKey[3]; headerPtr++;
|
||||||
*headerPtr = maskKey[2];
|
|
||||||
headerPtr++;
|
|
||||||
*headerPtr = maskKey[3];
|
|
||||||
headerPtr++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,20 +216,14 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
// header has be added to payload
|
// header has be added to payload
|
||||||
// payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings
|
// payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings
|
||||||
// offset in payload is calculatetd 14 - headerSize
|
// offset in payload is calculatetd 14 - headerSize
|
||||||
if(client->tcp->write(&payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize)) != (length + headerSize)) {
|
client->tcp->write(&payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize));
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// send header
|
// send header
|
||||||
if(client->tcp->write(&buffer[0], headerSize) != headerSize) {
|
client->tcp->write(&buffer[0], headerSize);
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(payloadPtr && length > 0) {
|
if(payloadPtr && length > 0) {
|
||||||
// send payload
|
// send payload
|
||||||
if(client->tcp->write(&payloadPtr[0], length) != length) {
|
client->tcp->write(&payloadPtr[0], length);
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,21 +235,6 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* callen when HTTP header is done
|
|
||||||
* @param client WSclient_t * ptr to the client struct
|
|
||||||
*/
|
|
||||||
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)
|
|
||||||
client->cHttpLine = "";
|
|
||||||
handleWebsocket(client);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -280,170 +242,129 @@ void WebSockets::headerDone(WSclient_t * client) {
|
|||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
void WebSockets::handleWebsocket(WSclient_t * client) {
|
void WebSockets::handleWebsocket(WSclient_t * client) {
|
||||||
if(client->cWsRXsize == 0) {
|
|
||||||
handleWebsocketCb(client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
uint8_t buffer[8] = { 0 };
|
||||||
* wait for
|
|
||||||
* @param client
|
|
||||||
* @param size
|
|
||||||
*/
|
|
||||||
bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) {
|
|
||||||
if(!client->tcp || !client->tcp->connected()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(size > WEBSOCKETS_MAX_HEADER_SIZE) {
|
bool fin;
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d too big!\n", client->num, size);
|
bool rsv1;
|
||||||
return false;
|
bool rsv2;
|
||||||
}
|
bool rsv3;
|
||||||
|
WSopcode_t opCode;
|
||||||
|
bool mask;
|
||||||
|
size_t payloadLen;
|
||||||
|
|
||||||
if(client->cWsRXsize >= size) {
|
uint8_t maskKey[4];
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d cWsRXsize: %d\n", client->num, size, client->cWsRXsize);
|
|
||||||
readCb(client, &client->cWsHeader[client->cWsRXsize], (size - client->cWsRXsize), std::bind([](WebSockets * server, size_t size, WSclient_t * client, bool ok) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor][readCb] size: %d ok: %d\n", client->num, size, ok);
|
|
||||||
if(ok) {
|
|
||||||
client->cWsRXsize = size;
|
|
||||||
server->handleWebsocketCb(client);
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][readCb] failed.\n", client->num);
|
|
||||||
client->cWsRXsize = 0;
|
|
||||||
// timeout or error
|
|
||||||
server->clientDisconnect(client, 1002);
|
|
||||||
}
|
|
||||||
}, this, size, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSockets::handleWebsocketCb(WSclient_t * client) {
|
|
||||||
|
|
||||||
if(!client->tcp || !client->tcp->connected()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t * buffer = client->cWsHeader;
|
|
||||||
|
|
||||||
WSMessageHeader_t * header = &client->cWsHeaderDecode;
|
|
||||||
uint8_t * payload = NULL;
|
uint8_t * payload = NULL;
|
||||||
|
|
||||||
uint8_t headerLen = 2;
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ------- read massage frame -------\n", client->num);
|
||||||
|
|
||||||
if(!handleWebsocketWaitFor(client, headerLen)) {
|
if(!readWait(client, buffer, 2)) {
|
||||||
|
//timeout
|
||||||
|
clientDisconnect(client, 1002);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// split first 2 bytes in the data
|
// split first 2 bytes in the data
|
||||||
header->fin = ((*buffer >> 7) & 0x01);
|
fin = ((buffer[0] >> 7) & 0x01);
|
||||||
header->rsv1 = ((*buffer >> 6) & 0x01);
|
rsv1 = ((buffer[0] >> 6) & 0x01);
|
||||||
header->rsv2 = ((*buffer >> 5) & 0x01);
|
rsv2 = ((buffer[0] >> 5) & 0x01);
|
||||||
header->rsv3 = ((*buffer >> 4) & 0x01);
|
rsv3 = ((buffer[0] >> 4) & 0x01);
|
||||||
header->opCode = (WSopcode_t) (*buffer & 0x0F);
|
opCode = (WSopcode_t) (buffer[0] & 0x0F);
|
||||||
buffer++;
|
|
||||||
|
|
||||||
header->mask = ((*buffer >> 7) & 0x01);
|
mask = ((buffer[1] >> 7) & 0x01);
|
||||||
header->payloadLen = (WSopcode_t) (*buffer & 0x7F);
|
payloadLen = (WSopcode_t) (buffer[1] & 0x7F);
|
||||||
buffer++;
|
|
||||||
|
|
||||||
if(header->payloadLen == 126) {
|
if(payloadLen == 126) {
|
||||||
headerLen += 2;
|
if(!readWait(client, buffer, 2)) {
|
||||||
if(!handleWebsocketWaitFor(client, headerLen)) {
|
//timeout
|
||||||
|
clientDisconnect(client, 1002);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
header->payloadLen = buffer[0] << 8 | buffer[1];
|
payloadLen = buffer[0] << 8 | buffer[1];
|
||||||
buffer += 2;
|
} else if(payloadLen == 127) {
|
||||||
} else if(header->payloadLen == 127) {
|
|
||||||
headerLen += 8;
|
|
||||||
// read 64bit integer as length
|
// read 64bit integer as length
|
||||||
if(!handleWebsocketWaitFor(client, headerLen)) {
|
if(!readWait(client, buffer, 8)) {
|
||||||
|
//timeout
|
||||||
|
clientDisconnect(client, 1002);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) {
|
if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) {
|
||||||
// really too big!
|
// really to big!
|
||||||
header->payloadLen = 0xFFFFFFFF;
|
payloadLen = 0xFFFFFFFF;
|
||||||
} else {
|
} else {
|
||||||
header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
|
payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
|
||||||
}
|
}
|
||||||
buffer += 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ------- read massage frame -------\n", client->num);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] fin: %u rsv1: %u rsv2: %u rsv3 %u opCode: %u\n", client->num, fin, rsv1, rsv2, rsv3, opCode);
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] fin: %u rsv1: %u rsv2: %u rsv3 %u opCode: %u\n", client->num, header->fin, header->rsv1, header->rsv2, header->rsv3, header->opCode);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, mask, payloadLen);
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen);
|
|
||||||
|
|
||||||
if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
|
if(payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload too big! (%u)\n", client->num, header->payloadLen);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload to big! (%u)\n", client->num, payloadLen);
|
||||||
clientDisconnect(client, 1009);
|
clientDisconnect(client, 1009);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(header->mask) {
|
if(mask) {
|
||||||
headerLen += 4;
|
if(!readWait(client, maskKey, 4)) {
|
||||||
if(!handleWebsocketWaitFor(client, headerLen)) {
|
//timeout
|
||||||
|
clientDisconnect(client, 1002);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
header->maskKey = buffer;
|
|
||||||
buffer += 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(header->payloadLen > 0) {
|
if(payloadLen > 0) {
|
||||||
// if text data we need one more
|
// if text data we need one more
|
||||||
payload = (uint8_t *) malloc(header->payloadLen + 1);
|
payload = (uint8_t *) malloc(payloadLen + 1);
|
||||||
|
|
||||||
if(!payload) {
|
if(!payload) {
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, header->payloadLen);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, payloadLen);
|
||||||
clientDisconnect(client, 1011);
|
clientDisconnect(client, 1011);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
readCb(client, payload, header->payloadLen, std::bind(&WebSockets::handleWebsocketPayloadCb, this, std::placeholders::_1, std::placeholders::_2, payload));
|
|
||||||
} else {
|
if(!readWait(client, payload, payloadLen)) {
|
||||||
handleWebsocketPayloadCb(client, true, NULL);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] missing data!\n", client->num);
|
||||||
}
|
free(payload);
|
||||||
|
clientDisconnect(client, 1002);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload) {
|
payload[payloadLen] = 0x00;
|
||||||
|
|
||||||
WSMessageHeader_t * header = &client->cWsHeaderDecode;
|
if(mask) {
|
||||||
if(ok) {
|
|
||||||
if(header->payloadLen > 0) {
|
|
||||||
payload[header->payloadLen] = 0x00;
|
|
||||||
|
|
||||||
if(header->mask) {
|
|
||||||
//decode XOR
|
//decode XOR
|
||||||
for(size_t i = 0; i < header->payloadLen; i++) {
|
for(size_t i = 0; i < payloadLen; i++) {
|
||||||
payload[i] = (payload[i] ^ header->maskKey[i % 4]);
|
payload[i] = (payload[i] ^ maskKey[i % 4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(header->opCode) {
|
switch(opCode) {
|
||||||
case WSop_text:
|
case WSop_text:
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
|
||||||
// no break here!
|
// no break here!
|
||||||
case WSop_binary:
|
case WSop_binary:
|
||||||
case WSop_continuation:
|
messageRecived(client, opCode, payload, payloadLen);
|
||||||
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);
|
|
||||||
break;
|
break;
|
||||||
case WSop_ping:
|
case WSop_ping:
|
||||||
// send pong back
|
// send pong back
|
||||||
sendFrame(client, WSop_pong, payload, header->payloadLen, true);
|
sendFrame(client, WSop_pong, payload, payloadLen);
|
||||||
break;
|
break;
|
||||||
case WSop_pong:
|
case WSop_pong:
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get pong (%s)\n", client->num, payload ? (const char*)payload : "");
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get pong (%s)\n", client->num, payload);
|
||||||
break;
|
break;
|
||||||
case WSop_close: {
|
case WSop_close:
|
||||||
|
{
|
||||||
uint16_t reasonCode = 1000;
|
uint16_t reasonCode = 1000;
|
||||||
if(header->payloadLen >= 2) {
|
if(payloadLen >= 2) {
|
||||||
reasonCode = payload[0] << 8 | payload[1];
|
reasonCode = payload[0] << 8 | payload[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode);
|
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode);
|
||||||
if(header->payloadLen > 2) {
|
if(payloadLen > 2) {
|
||||||
DEBUG_WEBSOCKETS(" (%s)\n", (payload+2));
|
DEBUG_WEBSOCKETS(" (%s)\n", (payload+2));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("\n");
|
DEBUG_WEBSOCKETS("\n");
|
||||||
@ -451,6 +372,10 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
clientDisconnect(client, 1000);
|
clientDisconnect(client, 1000);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case WSop_continuation:
|
||||||
|
// continuation is not supported
|
||||||
|
clientDisconnect(client, 1003);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
clientDisconnect(client, 1002);
|
clientDisconnect(client, 1002);
|
||||||
break;
|
break;
|
||||||
@ -460,18 +385,6 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
free(payload);
|
free(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset input
|
|
||||||
client->cWsRXsize = 0;
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
//register callback for next message
|
|
||||||
handleWebsocketWaitFor(client, 2);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] missing data!\n", client->num);
|
|
||||||
free(payload);
|
|
||||||
clientDisconnect(client, 1002);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -479,7 +392,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
|
|||||||
* @param clientKey String
|
* @param clientKey String
|
||||||
* @return String Accept Key
|
* @return String Accept Key
|
||||||
*/
|
*/
|
||||||
String WebSockets::acceptKey(String & clientKey) {
|
String WebSockets::acceptKey(String clientKey) {
|
||||||
uint8_t sha1HashBin[20] = { 0 };
|
uint8_t sha1HashBin[20] = { 0 };
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]);
|
sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]);
|
||||||
@ -526,49 +439,28 @@ String WebSockets::base64_encode(uint8_t * data, size_t length) {
|
|||||||
* @param n size_t byte count
|
* @param n size_t byte count
|
||||||
* @return true if ok
|
* @return true if ok
|
||||||
*/
|
*/
|
||||||
bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb) {
|
bool WebSockets::readWait(WSclient_t * client, uint8_t *out, size_t n) {
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
if(!client->tcp || !client->tcp->connected()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
client->tcp->readBytes(out, n, std::bind([](WSclient_t * client, bool ok, WSreadWaitCb cb) {
|
|
||||||
if(cb) {
|
|
||||||
cb(client, ok);
|
|
||||||
}
|
|
||||||
}, client, std::placeholders::_1, cb));
|
|
||||||
|
|
||||||
#else
|
|
||||||
unsigned long t = millis();
|
unsigned long t = millis();
|
||||||
size_t len;
|
size_t len;
|
||||||
DEBUG_WEBSOCKETS("[readCb] n: %d t: %d\n", n, t);
|
|
||||||
while(n > 0) {
|
while(n > 0) {
|
||||||
if(client->tcp == NULL) {
|
if(!client->tcp) {
|
||||||
DEBUG_WEBSOCKETS("[readCb] tcp is null!\n");
|
DEBUG_WEBSOCKETS("[readWait] tcp is null!\n");
|
||||||
if(cb) {
|
|
||||||
cb(client, false);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!client->tcp->connected()) {
|
if(!client->tcp->connected()) {
|
||||||
DEBUG_WEBSOCKETS("[readCb] not connected!\n");
|
DEBUG_WEBSOCKETS("[readWait] not connected!\n");
|
||||||
if(cb) {
|
|
||||||
cb(client, false);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) {
|
if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) {
|
||||||
DEBUG_WEBSOCKETS("[readCb] receive TIMEOUT! %d\n", (millis() - t));
|
DEBUG_WEBSOCKETS("[readWait] receive TIMEOUT!\n");
|
||||||
if(cb) {
|
|
||||||
cb(client, false);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!client->tcp->available()) {
|
if(!client->tcp->available()) {
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#ifdef ESP8266
|
||||||
delay(0);
|
delay(0);
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
@ -583,13 +475,9 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
|
|||||||
} else {
|
} else {
|
||||||
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#ifdef ESP8266
|
||||||
delay(0);
|
delay(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if(cb) {
|
|
||||||
cb(client, true);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
135
src/WebSockets.h
135
src/WebSockets.h
@ -25,20 +25,9 @@
|
|||||||
#ifndef WEBSOCKETS_H_
|
#ifndef WEBSOCKETS_H_
|
||||||
#define WEBSOCKETS_H_
|
#define WEBSOCKETS_H_
|
||||||
|
|
||||||
#ifdef STM32_DEVICE
|
|
||||||
#include <application.h>
|
|
||||||
#define bit(b) (1UL << (b)) // Taken directly from Arduino.h
|
|
||||||
#else
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <functional>
|
//#define DEBUG_WEBSOCKETS(...) Serial1.printf( __VA_ARGS__ )
|
||||||
|
|
||||||
#ifdef DEBUG_ESP_PORT
|
|
||||||
#define DEBUG_WEBSOCKETS(...) DEBUG_ESP_PORT.printf( __VA_ARGS__ )
|
|
||||||
#else
|
|
||||||
//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_WEBSOCKETS
|
#ifndef DEBUG_WEBSOCKETS
|
||||||
#define DEBUG_WEBSOCKETS(...)
|
#define DEBUG_WEBSOCKETS(...)
|
||||||
@ -48,88 +37,42 @@
|
|||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#define WEBSOCKETS_MAX_DATA_SIZE (15*1024)
|
#define WEBSOCKETS_MAX_DATA_SIZE (15*1024)
|
||||||
#define WEBSOCKETS_USE_BIG_MEM
|
#define WEBSOCKETS_USE_BIG_MEM
|
||||||
#define GET_FREE_HEAP ESP.getFreeHeap()
|
|
||||||
// moves all Header strings to Flash (~300 Byte)
|
|
||||||
//#define WEBSOCKETS_SAVE_RAM
|
|
||||||
#else
|
|
||||||
#ifdef STM32_DEVICE
|
|
||||||
#define WEBSOCKETS_MAX_DATA_SIZE (15*1024)
|
|
||||||
#define WEBSOCKETS_USE_BIG_MEM
|
|
||||||
#define GET_FREE_HEAP System.freeMemory()
|
|
||||||
#else
|
#else
|
||||||
//atmega328p has only 2KB ram!
|
//atmega328p has only 2KB ram!
|
||||||
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
|
||||||
// moves all Header strings to Flash
|
|
||||||
#define WEBSOCKETS_SAVE_RAM
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WEBSOCKETS_TCP_TIMEOUT (2000)
|
#define WEBSOCKETS_TCP_TIMEOUT (1500)
|
||||||
|
|
||||||
#define NETWORK_ESP8266_ASYNC (0)
|
|
||||||
#define NETWORK_ESP8266 (1)
|
#define NETWORK_ESP8266 (1)
|
||||||
#define NETWORK_W5100 (2)
|
#define NETWORK_W5100 (2)
|
||||||
#define NETWORK_ENC28J60 (3)
|
#define NETWORK_ENC28J60 (3)
|
||||||
|
|
||||||
// max size of the WS Message Header
|
|
||||||
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
|
|
||||||
|
|
||||||
#if !defined(WEBSOCKETS_NETWORK_TYPE)
|
|
||||||
// select Network type based
|
// select Network type based
|
||||||
#if defined(ESP8266) || defined(ESP31B)
|
#ifdef ESP8266
|
||||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266
|
||||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC
|
|
||||||
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
|
||||||
#else
|
#else
|
||||||
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
|
|
||||||
// Note:
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
// No SSL/WSS support for client in Async mode
|
|
||||||
// TLS lib need a sync interface!
|
|
||||||
|
|
||||||
#if !defined(ESP8266) && !defined(ESP31B)
|
#ifndef ESP8266
|
||||||
#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)
|
|
||||||
|
|
||||||
#if !defined(ESP8266) && !defined(ESP31B)
|
|
||||||
#error "network type ESP8266 only possible on the ESP mcu!"
|
#error "network type ESP8266 only possible on the ESP mcu!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#else
|
|
||||||
#include <ESP31BWiFi.h>
|
|
||||||
#endif
|
|
||||||
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
|
||||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
|
||||||
|
|
||||||
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100)
|
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100)
|
||||||
|
|
||||||
#ifdef STM32_DEVICE
|
|
||||||
#define WEBSOCKETS_NETWORK_CLASS TCPClient
|
|
||||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS TCPServer
|
|
||||||
#else
|
|
||||||
#include <Ethernet.h>
|
#include <Ethernet.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#define WEBSOCKETS_NETWORK_CLASS EthernetClient
|
#define WEBSOCKETS_NETWORK_CLASS EthernetClient
|
||||||
#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer
|
#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60)
|
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60)
|
||||||
|
|
||||||
@ -141,12 +84,6 @@
|
|||||||
#error "no network type selected!"
|
#error "no network type selected!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// moves all Header strings to Flash (~300 Byte)
|
|
||||||
#ifdef WEBSOCKETS_SAVE_RAM
|
|
||||||
#define WEBSOCKETS_STRING(var) F(var)
|
|
||||||
#else
|
|
||||||
#define WEBSOCKETS_STRING(var) var
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WSC_NOT_CONNECTED,
|
WSC_NOT_CONNECTED,
|
||||||
@ -159,11 +96,7 @@ typedef enum {
|
|||||||
WStype_DISCONNECTED,
|
WStype_DISCONNECTED,
|
||||||
WStype_CONNECTED,
|
WStype_CONNECTED,
|
||||||
WStype_TEXT,
|
WStype_TEXT,
|
||||||
WStype_BIN,
|
WStype_BIN
|
||||||
WStype_FRAGMENT_TEXT_START,
|
|
||||||
WStype_FRAGMENT_BIN_START,
|
|
||||||
WStype_FRAGMENT,
|
|
||||||
WStype_FRAGMENT_FIN,
|
|
||||||
} WStype_t;
|
} WStype_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -177,21 +110,6 @@ typedef enum {
|
|||||||
///< %xB-F are reserved for further control frames
|
///< %xB-F are reserved for further control frames
|
||||||
} WSopcode_t;
|
} WSopcode_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
bool fin;
|
|
||||||
bool rsv1;
|
|
||||||
bool rsv2;
|
|
||||||
bool rsv3;
|
|
||||||
|
|
||||||
WSopcode_t opCode;
|
|
||||||
bool mask;
|
|
||||||
|
|
||||||
size_t payloadLen;
|
|
||||||
|
|
||||||
uint8_t * maskKey;
|
|
||||||
} WSMessageHeader_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t num; ///< connection number
|
uint8_t num; ///< connection number
|
||||||
|
|
||||||
@ -199,8 +117,6 @@ typedef struct {
|
|||||||
|
|
||||||
WEBSOCKETS_NETWORK_CLASS * tcp;
|
WEBSOCKETS_NETWORK_CLASS * tcp;
|
||||||
|
|
||||||
bool isSocketIO; ///< client for socket.io server
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
bool isSSL; ///< run in ssl mode
|
bool isSSL; ///< run in ssl mode
|
||||||
WiFiClientSecure * ssl;
|
WiFiClientSecure * ssl;
|
||||||
@ -212,63 +128,32 @@ typedef struct {
|
|||||||
bool cIsUpgrade; ///< Connection == Upgrade
|
bool cIsUpgrade; ///< Connection == Upgrade
|
||||||
bool cIsWebsocket; ///< Upgrade == websocket
|
bool cIsWebsocket; ///< Upgrade == websocket
|
||||||
|
|
||||||
String cSessionId; ///< client Set-Cookie (session id)
|
|
||||||
String cKey; ///< client Sec-WebSocket-Key
|
String cKey; ///< client Sec-WebSocket-Key
|
||||||
String cAccept; ///< client Sec-WebSocket-Accept
|
String cAccept; ///< client Sec-WebSocket-Accept
|
||||||
String cProtocol; ///< client Sec-WebSocket-Protocol
|
String cProtocol; ///< client Sec-WebSocket-Protocol
|
||||||
String cExtensions; ///< client Sec-WebSocket-Extensions
|
String cExtensions; ///< client Sec-WebSocket-Extensions
|
||||||
uint16_t cVersion; ///< client Sec-WebSocket-Version
|
uint16_t cVersion; ///< client Sec-WebSocket-Version
|
||||||
|
|
||||||
uint8_t cWsRXsize; ///< 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
|
|
||||||
|
|
||||||
String extraHeaders;
|
|
||||||
|
|
||||||
bool cHttpHeadersValid; ///< non-websocket http header validity indicator
|
|
||||||
size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
String cHttpLine; ///< HTTP header lines
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} WSclient_t;
|
} WSclient_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebSockets {
|
class WebSockets {
|
||||||
protected:
|
protected:
|
||||||
#ifdef __AVR__
|
|
||||||
typedef void (*WSreadWaitCb)(WSclient_t * client, bool ok);
|
|
||||||
#else
|
|
||||||
typedef std::function<void(WSclient_t * client, bool ok)> WSreadWaitCb;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual void clientDisconnect(WSclient_t * client);
|
virtual void clientDisconnect(WSclient_t * client);
|
||||||
virtual bool clientIsConnected(WSclient_t * client);
|
virtual bool clientIsConnected(WSclient_t * client);
|
||||||
|
|
||||||
virtual void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
virtual void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
|
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
|
||||||
bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool mask = false, bool fin = true, bool headerToPayload = false);
|
void sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool mask = false, bool fin = true, bool headerToPayload = false);
|
||||||
|
|
||||||
void headerDone(WSclient_t * client);
|
|
||||||
|
|
||||||
void handleWebsocket(WSclient_t * client);
|
void handleWebsocket(WSclient_t * client);
|
||||||
|
|
||||||
bool handleWebsocketWaitFor(WSclient_t * client, size_t size);
|
bool readWait(WSclient_t * client, uint8_t *out, size_t n);
|
||||||
void handleWebsocketCb(WSclient_t * client);
|
|
||||||
void handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload);
|
|
||||||
|
|
||||||
String acceptKey(String & clientKey);
|
String acceptKey(String clientKey);
|
||||||
String base64_encode(uint8_t * data, size_t length);
|
String base64_encode(uint8_t * data, size_t length);
|
||||||
|
|
||||||
bool readCb(WSclient_t * client, uint8_t *out, size_t n, WSreadWaitCb cb);
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* WEBSOCKETS_H_ */
|
#endif /* WEBSOCKETS_H_ */
|
||||||
|
@ -25,11 +25,9 @@
|
|||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
#include "WebSocketsClient.h"
|
#include "WebSocketsClient.h"
|
||||||
|
|
||||||
|
|
||||||
WebSocketsClient::WebSocketsClient() {
|
WebSocketsClient::WebSocketsClient() {
|
||||||
_cbEvent = NULL;
|
_cbEvent = NULL;
|
||||||
_client.num = 0;
|
_client.num = 0;
|
||||||
_client.extraHeaders = WEBSOCKETS_STRING("Origin: file://");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketsClient::~WebSocketsClient() {
|
WebSocketsClient::~WebSocketsClient() {
|
||||||
@ -39,7 +37,7 @@ WebSocketsClient::~WebSocketsClient() {
|
|||||||
/**
|
/**
|
||||||
* calles to init the Websockets server
|
* calles to init the Websockets server
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::begin(const char *host, uint16_t port, const char * url, const char * protocol) {
|
void WebSocketsClient::begin(const char *host, uint16_t port, const char * url) {
|
||||||
_host = host;
|
_host = host;
|
||||||
_port = port;
|
_port = port;
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
@ -59,12 +57,9 @@ void WebSocketsClient::begin(const char *host, uint16_t port, const char * url,
|
|||||||
_client.cIsWebsocket = true;
|
_client.cIsWebsocket = true;
|
||||||
_client.cKey = "";
|
_client.cKey = "";
|
||||||
_client.cAccept = "";
|
_client.cAccept = "";
|
||||||
_client.cProtocol = protocol;
|
_client.cProtocol = "";
|
||||||
_client.cExtensions = "";
|
_client.cExtensions = "";
|
||||||
_client.cVersion = 0;
|
_client.cVersion = 0;
|
||||||
_client.base64Authorization = "";
|
|
||||||
_client.plainAuthorization = "";
|
|
||||||
_client.isSocketIO = false;
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
randomSeed(RANDOM_REG32);
|
randomSeed(RANDOM_REG32);
|
||||||
@ -72,50 +67,24 @@ void WebSocketsClient::begin(const char *host, uint16_t port, const char * url,
|
|||||||
// todo find better seed
|
// todo find better seed
|
||||||
randomSeed(millis());
|
randomSeed(millis());
|
||||||
#endif
|
#endif
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
asyncConnect();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
|
void WebSocketsClient::begin(String host, uint16_t port, String url) {
|
||||||
begin(host.c_str(), port, url.c_str(), protocol.c_str());
|
begin(host.c_str(), port, url.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#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::beginSSL(const char *host, uint16_t port, const char * url, const char * fingerprint) {
|
||||||
begin(host, port, url, protocol);
|
begin(host, port, url);
|
||||||
_client.isSSL = true;
|
_client.isSSL = true;
|
||||||
_fingerprint = fingerprint;
|
_fingerprint = fingerprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) {
|
void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint) {
|
||||||
beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str(), protocol.c_str());
|
beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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 (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
|
||||||
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 = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) {
|
|
||||||
beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
/**
|
/**
|
||||||
* called in arduino loop
|
* called in arduino loop
|
||||||
*/
|
*/
|
||||||
@ -150,16 +119,36 @@ void WebSocketsClient::loop(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(_client.tcp->connect(_host.c_str(), _port)) {
|
if(_client.tcp->connect(_host.c_str(), _port)) {
|
||||||
connectedCb();
|
DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n", _host.c_str(), _port);
|
||||||
|
|
||||||
|
_client.status = WSC_HEADER;
|
||||||
|
|
||||||
|
// set Timeout for readBytesUntil and readStringUntil
|
||||||
|
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
||||||
|
|
||||||
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
|
_client.tcp->setNoDelay(true);
|
||||||
|
|
||||||
|
if(_client.isSSL && _fingerprint.length()) {
|
||||||
|
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
||||||
|
WebSockets::clientDisconnect(&_client, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// send Header to Server
|
||||||
|
sendHeader(&_client);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
connectFailedCb();
|
DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Faild\n", _host.c_str(), _port);
|
||||||
delay(10); //some little delay to not flood the server
|
delay(10); //some litle delay to not flood the server
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleClientData();
|
handleClientData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set callback function
|
* set callback function
|
||||||
@ -175,32 +164,30 @@ void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) {
|
|||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
|
||||||
*/
|
*/
|
||||||
bool WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
void WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
if(length == 0) {
|
if(length == 0) {
|
||||||
length = strlen((const char *) payload);
|
length = strlen((const char *) payload);
|
||||||
}
|
}
|
||||||
if(clientIsConnected(&_client)) {
|
if(clientIsConnected(&_client)) {
|
||||||
return sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload);
|
sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) {
|
void WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) {
|
||||||
return sendTXT((uint8_t *) payload, length);
|
sendTXT((uint8_t *) payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) {
|
void WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) {
|
||||||
return sendTXT((uint8_t *) payload, length, headerToPayload);
|
sendTXT((uint8_t *) payload, length, headerToPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendTXT(const char * payload, size_t length) {
|
void WebSocketsClient::sendTXT(const char * payload, size_t length) {
|
||||||
return sendTXT((uint8_t *) payload, length);
|
sendTXT((uint8_t *) payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendTXT(String & payload) {
|
void WebSocketsClient::sendTXT(String payload) {
|
||||||
return sendTXT((uint8_t *) payload.c_str(), payload.length());
|
sendTXT((uint8_t *) payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -209,37 +196,17 @@ bool WebSocketsClient::sendTXT(String & payload) {
|
|||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
|
||||||
*/
|
*/
|
||||||
bool WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
void WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
if(clientIsConnected(&_client)) {
|
if(clientIsConnected(&_client)) {
|
||||||
return sendFrame(&_client, WSop_binary, payload, length, true, true, headerToPayload);
|
sendFrame(&_client, WSop_binary, payload, length, true, true, headerToPayload);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) {
|
void WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) {
|
||||||
return sendBIN((uint8_t *) payload, length);
|
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)) {
|
|
||||||
return sendFrame(&_client, WSop_ping, payload, length, true);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WebSocketsClient::sendPing(String & payload) {
|
|
||||||
return sendPing((uint8_t *) payload.c_str(), payload.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* disconnect one client
|
* disconnect one client
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
@ -250,40 +217,6 @@ void WebSocketsClient::disconnect(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* set the Authorizatio for the http request
|
|
||||||
* @param user const char *
|
|
||||||
* @param password const char *
|
|
||||||
*/
|
|
||||||
void WebSocketsClient::setAuthorization(const char * user, const char * password) {
|
|
||||||
if(user && password) {
|
|
||||||
String auth = user;
|
|
||||||
auth += ":";
|
|
||||||
auth += password;
|
|
||||||
_client.base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set the Authorizatio for the http request
|
|
||||||
* @param auth const char * base64
|
|
||||||
*/
|
|
||||||
void WebSocketsClient::setAuthorization(const char * auth) {
|
|
||||||
if(auth) {
|
|
||||||
//_client.base64Authorization = auth;
|
|
||||||
_client.plainAuthorization = auth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set extra headers for the http request;
|
|
||||||
* separate headers by "\r\n"
|
|
||||||
* @param extraHeaders const char * extraHeaders
|
|
||||||
*/
|
|
||||||
void WebSocketsClient::setExtraHeaders(const char * extraHeaders) {
|
|
||||||
_client.extraHeaders = extraHeaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
@ -293,24 +226,21 @@ void WebSocketsClient::setExtraHeaders(const char * extraHeaders) {
|
|||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
* @param opcode WSopcode_t
|
* @param opcode WSopcode_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param lenght size_t
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
|
void WebSocketsClient::messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) {
|
||||||
WStype_t type = WStype_ERROR;
|
WStype_t type = WStype_ERROR;
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case WSop_text:
|
case WSop_text:
|
||||||
type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
|
type = WStype_TEXT;
|
||||||
break;
|
break;
|
||||||
case WSop_binary:
|
case WSop_binary:
|
||||||
type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START;
|
type = WStype_BIN;
|
||||||
break;
|
|
||||||
case WSop_continuation:
|
|
||||||
type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
runCbEvent(type, payload, length);
|
runCbEvent(type, payload, lenght);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,15 +250,12 @@ void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, u
|
|||||||
*/
|
*/
|
||||||
void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
||||||
|
|
||||||
bool event = false;
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
if(client->isSSL && client->ssl) {
|
if(client->isSSL && client->ssl) {
|
||||||
if(client->ssl->connected()) {
|
if(client->ssl->connected()) {
|
||||||
client->ssl->flush();
|
client->ssl->flush();
|
||||||
client->ssl->stop();
|
client->ssl->stop();
|
||||||
}
|
}
|
||||||
event = true;
|
|
||||||
delete client->ssl;
|
delete client->ssl;
|
||||||
client->ssl = NULL;
|
client->ssl = NULL;
|
||||||
client->tcp = NULL;
|
client->tcp = NULL;
|
||||||
@ -337,17 +264,10 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
|||||||
|
|
||||||
if(client->tcp) {
|
if(client->tcp) {
|
||||||
if(client->tcp->connected()) {
|
if(client->tcp->connected()) {
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
client->tcp->flush();
|
client->tcp->flush();
|
||||||
#endif
|
|
||||||
client->tcp->stop();
|
client->tcp->stop();
|
||||||
}
|
}
|
||||||
event = true;
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->status = WSC_NOT_CONNECTED;
|
|
||||||
#else
|
|
||||||
delete client->tcp;
|
delete client->tcp;
|
||||||
#endif
|
|
||||||
client->tcp = NULL;
|
client->tcp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,14 +278,13 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
|
|||||||
client->cVersion = 0;
|
client->cVersion = 0;
|
||||||
client->cIsUpgrade = false;
|
client->cIsUpgrade = false;
|
||||||
client->cIsWebsocket = false;
|
client->cIsWebsocket = false;
|
||||||
client->cSessionId = "";
|
|
||||||
|
|
||||||
client->status = WSC_NOT_CONNECTED;
|
client->status = WSC_NOT_CONNECTED;
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
|
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
|
||||||
if(event) {
|
|
||||||
runCbEvent(WStype_DISCONNECTED, NULL, 0);
|
runCbEvent(WStype_DISCONNECTED, NULL, 0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -399,7 +318,7 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
/**
|
/**
|
||||||
* Handel incomming data from Client
|
* Handel incomming data from Client
|
||||||
*/
|
*/
|
||||||
@ -408,10 +327,7 @@ void WebSocketsClient::handleClientData(void) {
|
|||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
switch(_client.status) {
|
switch(_client.status) {
|
||||||
case WSC_HEADER:
|
case WSC_HEADER:
|
||||||
{
|
handleHeader(&_client);
|
||||||
String headerLine = _client.tcp->readStringUntil('\n');
|
|
||||||
handleHeader(&_client, &headerLine);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case WSC_CONNECTED:
|
case WSC_CONNECTED:
|
||||||
WebSockets::handleWebsocket(&_client);
|
WebSockets::handleWebsocket(&_client);
|
||||||
@ -421,12 +337,10 @@ void WebSocketsClient::handleClientData(void) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#ifdef ESP8266
|
||||||
delay(0);
|
delay(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* send the WebSocket header to Server
|
* send the WebSocket header to Server
|
||||||
@ -434,8 +348,6 @@ void WebSocketsClient::handleClientData(void) {
|
|||||||
*/
|
*/
|
||||||
void WebSocketsClient::sendHeader(WSclient_t * client) {
|
void WebSocketsClient::sendHeader(WSclient_t * client) {
|
||||||
|
|
||||||
static const char * NEW_LINE = "\r\n";
|
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n");
|
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n");
|
||||||
|
|
||||||
uint8_t randomKey[16] = { 0 };
|
uint8_t randomKey[16] = { 0 };
|
||||||
@ -450,70 +362,22 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
|
|||||||
unsigned long start = micros();
|
unsigned long start = micros();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String handshake;
|
String handshake = "GET " + client->cUrl + " HTTP/1.1\r\n"
|
||||||
bool ws_header = true;
|
"Host: " + _host + "\r\n"
|
||||||
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"
|
"Upgrade: websocket\r\n"
|
||||||
|
"Connection: Upgrade\r\n"
|
||||||
|
"User-Agent: arduino-WebSocket-Client\r\n"
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"Sec-WebSocket-Key: ");
|
"Sec-WebSocket-Protocol: arduino\r\n"
|
||||||
handshake += client->cKey + NEW_LINE;
|
"Sec-WebSocket-Key: " + client->cKey + "\r\n";
|
||||||
|
|
||||||
if(client->cProtocol.length() > 0) {
|
|
||||||
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
|
|
||||||
handshake +=client->cProtocol + NEW_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(client->cExtensions.length() > 0) {
|
if(client->cExtensions.length() > 0) {
|
||||||
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Extensions: ");
|
handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n";
|
||||||
handshake +=client->cExtensions + NEW_LINE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handshake += WEBSOCKETS_STRING("Connection: keep-alive\r\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add extra headers; by default this includes "Origin: file://"
|
handshake += "\r\n";
|
||||||
if (client->extraHeaders) {
|
|
||||||
handshake += client->extraHeaders + NEW_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
handshake += WEBSOCKETS_STRING("User-Agent: arduino-WebSocket-Client\r\n");
|
client->tcp->write(handshake.c_str(), handshake.length());
|
||||||
|
|
||||||
if(client->base64Authorization.length() > 0) {
|
|
||||||
handshake += WEBSOCKETS_STRING("Authorization: Basic ");
|
|
||||||
handshake += client->base64Authorization + NEW_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(client->plainAuthorization.length() > 0) {
|
|
||||||
handshake += WEBSOCKETS_STRING("Authorization: ");
|
|
||||||
handshake += client->plainAuthorization + NEW_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
handshake += NEW_LINE;
|
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] handshake %s", (uint8_t*)handshake.c_str());
|
|
||||||
client->tcp->write((uint8_t*)handshake.c_str(), handshake.length());
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%uus).\n", (micros() - start));
|
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%uus).\n", (micros() - start));
|
||||||
|
|
||||||
@ -523,53 +387,43 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
|
|||||||
* handle the WebSocket header reading
|
* handle the WebSocket header reading
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
void WebSocketsClient::handleHeader(WSclient_t * client) {
|
||||||
|
|
||||||
headerLine->trim(); // remove \r
|
String headerLine = client->tcp->readStringUntil('\n');
|
||||||
|
headerLine.trim(); // remove \r
|
||||||
|
|
||||||
if(headerLine->length() > 0) {
|
if(headerLine.length() > 0) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine.c_str());
|
||||||
|
|
||||||
if(headerLine->startsWith(WEBSOCKETS_STRING("HTTP/1."))) {
|
if(headerLine.startsWith("HTTP/1.")) {
|
||||||
// "HTTP/1.1 101 Switching Protocols"
|
// "HTTP/1.1 101 Switching Protocols"
|
||||||
client->cCode = headerLine->substring(9, headerLine->indexOf(' ', 9)).toInt();
|
client->cCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt();
|
||||||
} else if(headerLine->indexOf(':')) {
|
} else if(headerLine.indexOf(':')) {
|
||||||
String headerName = headerLine->substring(0, headerLine->indexOf(':'));
|
String headerName = headerLine.substring(0, headerLine.indexOf(':'));
|
||||||
String headerValue = headerLine->substring(headerLine->indexOf(':') + 2);
|
String headerValue = headerLine.substring(headerLine.indexOf(':') + 2);
|
||||||
|
|
||||||
if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
|
if(headerName.equalsIgnoreCase("Connection")) {
|
||||||
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("upgrade"))) {
|
if(headerValue.equalsIgnoreCase("Upgrade")) {
|
||||||
client->cIsUpgrade = true;
|
client->cIsUpgrade = true;
|
||||||
}
|
}
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
|
} else if(headerName.equalsIgnoreCase("Upgrade")) {
|
||||||
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
|
if(headerValue.equalsIgnoreCase("websocket")) {
|
||||||
client->cIsWebsocket = true;
|
client->cIsWebsocket = true;
|
||||||
}
|
}
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Accept"))) {
|
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Accept")) {
|
||||||
client->cAccept = headerValue;
|
client->cAccept = headerValue;
|
||||||
client->cAccept.trim(); // see rfc6455
|
client->cAccept.trim(); // see rfc6455
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
|
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) {
|
||||||
client->cProtocol = headerValue;
|
client->cProtocol = headerValue;
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
|
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) {
|
||||||
client->cExtensions = headerValue;
|
client->cExtensions = headerValue;
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
|
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) {
|
||||||
client->cVersion = headerValue.toInt();
|
client->cVersion = headerValue.toInt();
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) {
|
|
||||||
if (headerValue.indexOf(WEBSOCKETS_STRING("HttpOnly")) > -1) {
|
|
||||||
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
|
|
||||||
} else {
|
|
||||||
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
(*headerLine) = "";
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n");
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n");
|
||||||
@ -585,7 +439,6 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str());
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str());
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str());
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
|
|
||||||
|
|
||||||
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
||||||
|
|
||||||
@ -594,10 +447,6 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
case 101: ///< Switching Protocols
|
case 101: ///< Switching Protocols
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 200:
|
|
||||||
if(client->isSocketIO) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 403: ///< Forbidden
|
case 403: ///< Forbidden
|
||||||
// todo handle login
|
// todo handle login
|
||||||
default: ///< Server dont unterstand requrst
|
default: ///< Server dont unterstand requrst
|
||||||
@ -609,7 +458,6 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(ok) {
|
if(ok) {
|
||||||
|
|
||||||
if(client->cAccept.length() == 0) {
|
if(client->cAccept.length() == 0) {
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
} else {
|
||||||
@ -625,109 +473,16 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
if(ok) {
|
if(ok) {
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n");
|
||||||
headerDone(client);
|
|
||||||
|
|
||||||
|
client->status = WSC_CONNECTED;
|
||||||
|
|
||||||
runCbEvent(WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length());
|
runCbEvent(WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length());
|
||||||
|
|
||||||
} else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) {
|
|
||||||
sendHeader(client);
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
||||||
if(clientIsConnected(client)) {
|
|
||||||
client->tcp->write("This is a webSocket client!");
|
client->tcp->write("This is a webSocket client!");
|
||||||
}
|
|
||||||
clientDisconnect(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)
|
|
||||||
_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;
|
|
||||||
client->tcp = NULL;
|
|
||||||
|
|
||||||
// reconnect
|
|
||||||
c->asyncConnect();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}, this, std::placeholders::_1, &_client));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_client.status = WSC_HEADER;
|
|
||||||
|
|
||||||
#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)
|
|
||||||
_client.tcp->setNoDelay(true);
|
|
||||||
|
|
||||||
if(_client.isSSL && _fingerprint.length()) {
|
|
||||||
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
|
|
||||||
WebSockets::clientDisconnect(&_client, 1000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// send Header to Server
|
|
||||||
sendHeader(&_client);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void WebSocketsClient::connectFailedCb() {
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Faild\n", _host.c_str(), _port);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
|
|
||||||
void WebSocketsClient::asyncConnect() {
|
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] asyncConnect...\n");
|
|
||||||
|
|
||||||
AsyncClient * tcpclient = new AsyncClient();
|
|
||||||
|
|
||||||
if(!tcpclient) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] creating AsyncClient class failed!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tcpclient->onDisconnect([](void *obj, AsyncClient* c) {
|
|
||||||
c->free();
|
|
||||||
delete c;
|
|
||||||
});
|
|
||||||
|
|
||||||
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");
|
|
||||||
ws->connectFailedCb();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ws->connectedCb();
|
|
||||||
}, this, std::placeholders::_2));
|
|
||||||
|
|
||||||
tcpclient->onError(std::bind([](WebSocketsClient * ws , AsyncClient * tcp) {
|
|
||||||
ws->connectFailedCb();
|
|
||||||
|
|
||||||
// reconnect
|
|
||||||
ws->asyncConnect();
|
|
||||||
}, this, std::placeholders::_2));
|
|
||||||
|
|
||||||
if(!tcpclient->connect(_host.c_str(), _port)) {
|
|
||||||
connectFailedCb();
|
|
||||||
delete tcpclient;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -25,64 +25,40 @@
|
|||||||
#ifndef WEBSOCKETSCLIENT_H_
|
#ifndef WEBSOCKETSCLIENT_H_
|
||||||
#define WEBSOCKETSCLIENT_H_
|
#define WEBSOCKETSCLIENT_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
|
|
||||||
class WebSocketsClient: private WebSockets {
|
class WebSocketsClient: private WebSockets {
|
||||||
public:
|
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;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
|
||||||
|
|
||||||
WebSocketsClient(void);
|
WebSocketsClient(void);
|
||||||
~WebSocketsClient(void);
|
~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 = "/");
|
||||||
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
|
void begin(String host, uint16_t port, String url = "/");
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
void beginSSL(const char *host, uint16_t port, const char * url = "/", const char * = "", const char * protocol = "arduino");
|
void beginSSL(const char *host, uint16_t port, const char * url = "/", const char * = "");
|
||||||
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
|
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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 (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
|
||||||
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");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
void loop(void);
|
void loop(void);
|
||||||
#else
|
|
||||||
// Async interface not need a loop call
|
|
||||||
void loop(void) __attribute__ ((deprecated)) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void onEvent(WebSocketClientEvent cbEvent);
|
void onEvent(WebSocketClientEvent cbEvent);
|
||||||
|
|
||||||
bool sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
void sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
bool sendTXT(const uint8_t * payload, size_t length = 0);
|
void sendTXT(const uint8_t * payload, size_t length = 0);
|
||||||
bool sendTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
void sendTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
bool sendTXT(const char * payload, size_t length = 0);
|
void sendTXT(const char * payload, size_t length = 0);
|
||||||
bool sendTXT(String & payload);
|
void sendTXT(String payload);
|
||||||
|
|
||||||
bool sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
void sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
||||||
bool sendBIN(const uint8_t * payload, size_t length);
|
void 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 disconnect(void);
|
||||||
|
|
||||||
void setAuthorization(const char * user, const char * password);
|
|
||||||
void setAuthorization(const char * auth);
|
|
||||||
|
|
||||||
void setExtraHeaders(const char * extraHeaders = NULL);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
String _host;
|
String _host;
|
||||||
uint16_t _port;
|
uint16_t _port;
|
||||||
@ -94,24 +70,16 @@ class WebSocketsClient: private WebSockets {
|
|||||||
|
|
||||||
WebSocketClientEvent _cbEvent;
|
WebSocketClientEvent _cbEvent;
|
||||||
|
|
||||||
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client);
|
void clientDisconnect(WSclient_t * client);
|
||||||
bool clientIsConnected(WSclient_t * client);
|
bool clientIsConnected(WSclient_t * client);
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
void handleNewClients(void);
|
||||||
void handleClientData(void);
|
void handleClientData(void);
|
||||||
#endif
|
|
||||||
|
|
||||||
void sendHeader(WSclient_t * client);
|
void sendHeader(WSclient_t * client);
|
||||||
void handleHeader(WSclient_t * client, String * headerLine);
|
void handleHeader(WSclient_t * client);
|
||||||
|
|
||||||
void connectedCb();
|
|
||||||
void connectFailedCb();
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
void asyncConnect();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called for sending a Event to the app
|
* called for sending a Event to the app
|
||||||
|
@ -25,45 +25,23 @@
|
|||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
#include "WebSocketsServer.h"
|
#include "WebSocketsServer.h"
|
||||||
|
|
||||||
WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol) {
|
WebSocketsServer::WebSocketsServer(uint16_t port) {
|
||||||
_port = port;
|
_port = port;
|
||||||
_origin = origin;
|
|
||||||
_protocol = protocol;
|
|
||||||
|
|
||||||
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
|
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
_server->onClient([](void *s, AsyncClient* c){
|
|
||||||
((WebSocketsServer*)s)->newClient(new AsyncTCPbuffer(c));
|
|
||||||
}, this);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_cbEvent = NULL;
|
_cbEvent = NULL;
|
||||||
|
|
||||||
_httpHeaderValidationFunc = NULL;
|
|
||||||
_mandatoryHttpHeaders = NULL;
|
|
||||||
_mandatoryHttpHeaderCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WebSocketsServer::~WebSocketsServer() {
|
WebSocketsServer::~WebSocketsServer() {
|
||||||
// disconnect all clients
|
// disconnect all clients
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
|
||||||
_server->close();
|
|
||||||
#else
|
|
||||||
// TODO how to close server?
|
// TODO how to close server?
|
||||||
#endif
|
|
||||||
|
|
||||||
if (_mandatoryHttpHeaders)
|
|
||||||
delete[] _mandatoryHttpHeaders;
|
|
||||||
|
|
||||||
_mandatoryHttpHeaderCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called to initialize the Websocket server
|
* calles to init the Websockets server
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::begin(void) {
|
void WebSocketsServer::begin(void) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
@ -86,14 +64,6 @@ void WebSocketsServer::begin(void) {
|
|||||||
client->cVersion = 0;
|
client->cVersion = 0;
|
||||||
client->cIsUpgrade = false;
|
client->cIsUpgrade = false;
|
||||||
client->cIsWebsocket = false;
|
client->cIsWebsocket = false;
|
||||||
|
|
||||||
client->base64Authorization = "";
|
|
||||||
|
|
||||||
client->cWsRXsize = 0;
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->cHttpLine = "";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -108,7 +78,6 @@ void WebSocketsServer::begin(void) {
|
|||||||
DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
|
DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
/**
|
/**
|
||||||
* called in arduino loop
|
* called in arduino loop
|
||||||
*/
|
*/
|
||||||
@ -116,7 +85,6 @@ void WebSocketsServer::loop(void) {
|
|||||||
handleNewClients();
|
handleNewClients();
|
||||||
handleClientData();
|
handleClientData();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set callback function
|
* set callback function
|
||||||
@ -126,66 +94,40 @@ void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) {
|
|||||||
_cbEvent = cbEvent;
|
_cbEvent = cbEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Sets the custom http header validator function
|
|
||||||
* @param httpHeaderValidationFunc WebSocketServerHttpHeaderValFunc ///< pointer to the custom http header validation function
|
|
||||||
* @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed
|
|
||||||
* @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array
|
|
||||||
*/
|
|
||||||
void WebSocketsServer::onValidateHttpHeader(
|
|
||||||
WebSocketServerHttpHeaderValFunc validationFunc,
|
|
||||||
const char* mandatoryHttpHeaders[],
|
|
||||||
size_t mandatoryHttpHeaderCount)
|
|
||||||
{
|
|
||||||
_httpHeaderValidationFunc = validationFunc;
|
|
||||||
|
|
||||||
if (_mandatoryHttpHeaders)
|
|
||||||
delete[] _mandatoryHttpHeaders;
|
|
||||||
|
|
||||||
_mandatoryHttpHeaderCount = mandatoryHttpHeaderCount;
|
|
||||||
_mandatoryHttpHeaders = new String[_mandatoryHttpHeaderCount];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
|
|
||||||
_mandatoryHttpHeaders[i] = mandatoryHttpHeaders[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send text data to client
|
* send text data to client
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
void WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if(length == 0) {
|
if(length == 0) {
|
||||||
length = strlen((const char *) payload);
|
length = strlen((const char *) payload);
|
||||||
}
|
}
|
||||||
WSclient_t * client = &_clients[num];
|
WSclient_t * client = &_clients[num];
|
||||||
if(clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
return sendFrame(client, WSop_text, payload, length, false, true, headerToPayload);
|
sendFrame(client, WSop_text, payload, length, false, true, headerToPayload);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) {
|
void WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) {
|
||||||
return sendTXT(num, (uint8_t *) payload, length);
|
sendTXT(num, (uint8_t *) payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) {
|
void WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) {
|
||||||
return sendTXT(num, (uint8_t *) payload, length, headerToPayload);
|
sendTXT(num, (uint8_t *) payload, length, headerToPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) {
|
void WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) {
|
||||||
return sendTXT(num, (uint8_t *) payload, length);
|
sendTXT(num, (uint8_t *) payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendTXT(uint8_t num, String & payload) {
|
void WebSocketsServer::sendTXT(uint8_t num, String payload) {
|
||||||
return sendTXT(num, (uint8_t *) payload.c_str(), payload.length());
|
sendTXT(num, (uint8_t *) payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,11 +135,9 @@ bool WebSocketsServer::sendTXT(uint8_t num, String & payload) {
|
|||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
void WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
bool ret = true;
|
|
||||||
if(length == 0) {
|
if(length == 0) {
|
||||||
length = strlen((const char *) payload);
|
length = strlen((const char *) payload);
|
||||||
}
|
}
|
||||||
@ -205,31 +145,28 @@ bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool heade
|
|||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
client = &_clients[i];
|
client = &_clients[i];
|
||||||
if(clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
if(!sendFrame(client, WSop_text, payload, length, false, true, headerToPayload)) {
|
sendFrame(client, WSop_text, payload, length, false, true, headerToPayload);
|
||||||
ret = false;
|
|
||||||
}
|
}
|
||||||
}
|
#ifdef ESP8266
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
|
||||||
delay(0);
|
delay(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) {
|
void WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) {
|
||||||
return broadcastTXT((uint8_t *) payload, length);
|
broadcastTXT((uint8_t *) payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) {
|
void WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) {
|
||||||
return broadcastTXT((uint8_t *) payload, length, headerToPayload);
|
broadcastTXT((uint8_t *) payload, length, headerToPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastTXT(const char * payload, size_t length) {
|
void WebSocketsServer::broadcastTXT(const char * payload, size_t length) {
|
||||||
return broadcastTXT((uint8_t *) payload, length);
|
broadcastTXT((uint8_t *) payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastTXT(String & payload) {
|
void WebSocketsServer::broadcastTXT(String payload) {
|
||||||
return broadcastTXT((uint8_t *) payload.c_str(), payload.length());
|
broadcastTXT((uint8_t *) payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -238,21 +175,19 @@ bool WebSocketsServer::broadcastTXT(String & payload) {
|
|||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
void WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
WSclient_t * client = &_clients[num];
|
WSclient_t * client = &_clients[num];
|
||||||
if(clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
return sendFrame(client, WSop_binary, payload, length, false, true, headerToPayload);
|
sendFrame(client, WSop_binary, payload, length, false, true, headerToPayload);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) {
|
void WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) {
|
||||||
return sendBIN(num, (uint8_t *) payload, length);
|
sendBIN(num, (uint8_t *) payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -260,80 +195,24 @@ bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t leng
|
|||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param length size_t
|
||||||
* @param headerToPayload bool (see sendFrame for more details)
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
* @return true if ok
|
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
void WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
WSclient_t * client;
|
WSclient_t * client;
|
||||||
bool ret = true;
|
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
client = &_clients[i];
|
client = &_clients[i];
|
||||||
if(clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
if(!sendFrame(client, WSop_binary, payload, length, false, true, headerToPayload)) {
|
sendFrame(client, WSop_binary, payload, length, false, true, headerToPayload);
|
||||||
ret = false;
|
|
||||||
}
|
}
|
||||||
}
|
#ifdef ESP8266
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
|
||||||
delay(0);
|
delay(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) {
|
void WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) {
|
||||||
return broadcastBIN((uint8_t *) payload, length);
|
broadcastBIN((uint8_t *) payload, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sends a WS ping to Client
|
|
||||||
* @param num uint8_t client id
|
|
||||||
* @param payload uint8_t *
|
|
||||||
* @param length size_t
|
|
||||||
* @return true if ping is send out
|
|
||||||
*/
|
|
||||||
bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) {
|
|
||||||
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
WSclient_t * client = &_clients[num];
|
|
||||||
if(clientIsConnected(client)) {
|
|
||||||
return sendFrame(client, WSop_ping, payload, length);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WebSocketsServer::sendPing(uint8_t num, String & payload) {
|
|
||||||
return sendPing(num, (uint8_t *) payload.c_str(), payload.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sends a WS ping to all Client
|
|
||||||
* @param payload uint8_t *
|
|
||||||
* @param length size_t
|
|
||||||
* @return true if ping is send out
|
|
||||||
*/
|
|
||||||
bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) {
|
|
||||||
WSclient_t * client;
|
|
||||||
bool ret = true;
|
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
|
||||||
client = &_clients[i];
|
|
||||||
if(clientIsConnected(client)) {
|
|
||||||
if(!sendFrame(client, WSop_ping, payload, length)) {
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
|
||||||
delay(0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WebSocketsServer::broadcastPing(String & payload) {
|
|
||||||
return broadcastPing((uint8_t *) payload.c_str(), payload.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* disconnect all clients
|
* disconnect all clients
|
||||||
*/
|
*/
|
||||||
@ -361,32 +240,7 @@ void WebSocketsServer::disconnect(uint8_t num) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
/*
|
|
||||||
* set the Authorization for the http request
|
|
||||||
* @param user const char *
|
|
||||||
* @param password const char *
|
|
||||||
*/
|
|
||||||
void WebSocketsServer::setAuthorization(const char * user, const char * password) {
|
|
||||||
if(user && password) {
|
|
||||||
String auth = user;
|
|
||||||
auth += ":";
|
|
||||||
auth += password;
|
|
||||||
_base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set the Authorizatio for the http request
|
|
||||||
* @param auth const char * base64
|
|
||||||
*/
|
|
||||||
void WebSocketsServer::setAuthorization(const char * auth) {
|
|
||||||
if(auth) {
|
|
||||||
_base64Authorization = auth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
/**
|
/**
|
||||||
* get an IP for a client
|
* get an IP for a client
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
@ -408,84 +262,26 @@ IPAddress WebSocketsServer::remoteIP(uint8_t num) {
|
|||||||
//#################################################################################
|
//#################################################################################
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
|
|
||||||
/**
|
|
||||||
* handle new client connection
|
|
||||||
* @param client
|
|
||||||
*/
|
|
||||||
bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
|
|
||||||
WSclient_t * client;
|
|
||||||
// search free list entry for client
|
|
||||||
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
|
||||||
client = &_clients[i];
|
|
||||||
|
|
||||||
// state is not connected or tcp connection is lost
|
|
||||||
if(!clientIsConnected(client)) {
|
|
||||||
|
|
||||||
client->tcp = TCPclient;
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
|
||||||
client->isSSL = false;
|
|
||||||
client->tcp->setNoDelay(true);
|
|
||||||
#endif
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
// set Timeout for readBytesUntil and readStringUntil
|
|
||||||
client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
|
||||||
#endif
|
|
||||||
client->status = WSC_HEADER;
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
IPAddress ip = client->tcp->remoteIP();
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]);
|
|
||||||
#else
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d] new client\n", client->num);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->tcp->onDisconnect(std::bind([](WebSocketsServer * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
|
|
||||||
|
|
||||||
AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp;
|
|
||||||
if(*sl == obj) {
|
|
||||||
client->status = WSC_NOT_CONNECTED;
|
|
||||||
*sl = NULL;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}, this, std::placeholders::_1, client));
|
|
||||||
|
|
||||||
|
|
||||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
* @param opcode WSopcode_t
|
* @param opcode WSopcode_t
|
||||||
* @param payload uint8_t *
|
* @param payload uint8_t *
|
||||||
* @param length size_t
|
* @param lenght size_t
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
|
void WebSocketsServer::messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) {
|
||||||
WStype_t type = WStype_ERROR;
|
WStype_t type = WStype_ERROR;
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case WSop_text:
|
case WSop_text:
|
||||||
type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
|
type = WStype_TEXT;
|
||||||
break;
|
break;
|
||||||
case WSop_binary:
|
case WSop_binary:
|
||||||
type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START;
|
type = WStype_BIN;
|
||||||
break;
|
|
||||||
case WSop_continuation:
|
|
||||||
type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
runCbEvent(client->num, type, payload, length);
|
runCbEvent(client->num, type, payload, lenght);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,16 +306,10 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) {
|
|||||||
|
|
||||||
if(client->tcp) {
|
if(client->tcp) {
|
||||||
if(client->tcp->connected()) {
|
if(client->tcp->connected()) {
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
client->tcp->flush();
|
client->tcp->flush();
|
||||||
#endif
|
|
||||||
client->tcp->stop();
|
client->tcp->stop();
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->status = WSC_NOT_CONNECTED;
|
|
||||||
#else
|
|
||||||
delete client->tcp;
|
delete client->tcp;
|
||||||
#endif
|
|
||||||
client->tcp = NULL;
|
client->tcp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,12 +320,6 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) {
|
|||||||
client->cIsUpgrade = false;
|
client->cIsUpgrade = false;
|
||||||
client->cIsWebsocket = false;
|
client->cIsWebsocket = false;
|
||||||
|
|
||||||
client->cWsRXsize = 0;
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->cHttpLine = "";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
client->status = WSC_NOT_CONNECTED;
|
client->status = WSC_NOT_CONNECTED;
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d] client disconnected.\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d] client disconnected.\n", client->num);
|
||||||
@ -547,7 +331,7 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) {
|
|||||||
/**
|
/**
|
||||||
* get client state
|
* get client state
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
* @return true = connected
|
* @return true = conneted
|
||||||
*/
|
*/
|
||||||
bool WebSocketsServer::clientIsConnected(WSclient_t * client) {
|
bool WebSocketsServer::clientIsConnected(WSclient_t * client) {
|
||||||
|
|
||||||
@ -570,56 +354,76 @@ bool WebSocketsServer::clientIsConnected(WSclient_t * client) {
|
|||||||
|
|
||||||
if(client->tcp) {
|
if(client->tcp) {
|
||||||
// do cleanup
|
// do cleanup
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d] client list cleanup.\n", client->num);
|
|
||||||
clientDisconnect(client);
|
clientDisconnect(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
/**
|
/**
|
||||||
* Handle incoming Connection Request
|
* Handle incomming Connection Request
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::handleNewClients(void) {
|
void WebSocketsServer::handleNewClients(void) {
|
||||||
|
WSclient_t * client;
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
while(_server->hasClient()) {
|
while(_server->hasClient()) {
|
||||||
#endif
|
#endif
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
// search free list entry for client
|
||||||
|
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
|
||||||
|
client = &_clients[i];
|
||||||
|
|
||||||
|
// state is not connected or tcp connection is lost
|
||||||
|
if(!clientIsConnected(client)) {
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
// store new connection
|
// store new connection
|
||||||
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
client->tcp = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
||||||
#else
|
#else
|
||||||
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
client->tcp = new WEBSOCKETS_NETWORK_CLASS(_server->available());
|
||||||
#endif
|
#endif
|
||||||
|
if(!client->tcp) {
|
||||||
if(!tcpClient) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
|
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = newClient(tcpClient);
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
|
client->isSSL = false;
|
||||||
|
client->tcp->setNoDelay(true);
|
||||||
|
#endif
|
||||||
|
// set Timeout for readBytesUntil and readStringUntil
|
||||||
|
client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
|
||||||
|
client->status = WSC_HEADER;
|
||||||
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
|
IPAddress ip = client->tcp->remoteIP();
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]);
|
||||||
|
#else
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server][%d] new client\n", client->num);
|
||||||
|
#endif
|
||||||
|
ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!ok) {
|
if(!ok) {
|
||||||
// no free space to handle client
|
// no free space to handle client
|
||||||
|
WEBSOCKETS_NETWORK_CLASS tcpClient = _server->available();
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
IPAddress ip = tcpClient->remoteIP();
|
IPAddress ip = client->tcp->remoteIP();
|
||||||
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
||||||
#else
|
#else
|
||||||
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
|
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
|
||||||
#endif
|
#endif
|
||||||
tcpClient->stop();
|
tcpClient.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#ifdef ESP8266
|
||||||
delay(0);
|
delay(0);
|
||||||
|
#endif
|
||||||
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handel incomming data from Client
|
* Handel incomming data from Client
|
||||||
*/
|
*/
|
||||||
@ -631,13 +435,10 @@ void WebSocketsServer::handleClientData(void) {
|
|||||||
if(clientIsConnected(client)) {
|
if(clientIsConnected(client)) {
|
||||||
int len = client->tcp->available();
|
int len = client->tcp->available();
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
//DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len);
|
|
||||||
switch(client->status) {
|
switch(client->status) {
|
||||||
case WSC_HEADER:
|
case WSC_HEADER:
|
||||||
{
|
handleHeader(client);
|
||||||
String headerLine = client->tcp->readStringUntil('\n');
|
|
||||||
handleHeader(client, &headerLine);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case WSC_CONNECTED:
|
case WSC_CONNECTED:
|
||||||
WebSockets::handleWebsocket(client);
|
WebSockets::handleWebsocket(client);
|
||||||
@ -648,92 +449,57 @@ void WebSocketsServer::handleClientData(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
#ifdef ESP8266
|
||||||
delay(0);
|
delay(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 WebSocketsServer::hasMandatoryHeader(String headerName) {
|
|
||||||
for (size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
|
|
||||||
if (_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handles http header reading for WebSocket upgrade
|
* handle the WebSocket header reading
|
||||||
* @param client WSclient_t * ///< pointer to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
* @param headerLine String ///< the header being read / processed
|
|
||||||
*/
|
*/
|
||||||
void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
|
void WebSocketsServer::handleHeader(WSclient_t * client) {
|
||||||
|
|
||||||
static const char * NEW_LINE = "\r\n";
|
String headerLine = client->tcp->readStringUntil('\n');
|
||||||
|
headerLine.trim(); // remove \r
|
||||||
|
|
||||||
headerLine->trim(); // remove \r
|
if(headerLine.length() > 0) {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] RX: %s\n", client->num, headerLine.c_str());
|
||||||
if(headerLine->length() > 0) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] RX: %s\n", client->num, headerLine->c_str());
|
|
||||||
|
|
||||||
// websocket requests always start with GET see rfc6455
|
|
||||||
if(headerLine->startsWith("GET ")) {
|
|
||||||
|
|
||||||
|
// websocket request starts allways with GET see rfc6455
|
||||||
|
if(headerLine.startsWith("GET ")) {
|
||||||
// cut URL out
|
// cut URL out
|
||||||
client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4));
|
client->cUrl = headerLine.substring(4, headerLine.indexOf(' ', 4));
|
||||||
|
} else if(headerLine.indexOf(':')) {
|
||||||
|
String headerName = headerLine.substring(0, headerLine.indexOf(':'));
|
||||||
|
String headerValue = headerLine.substring(headerLine.indexOf(':') + 2);
|
||||||
|
|
||||||
//reset non-websocket http header validation state for this client
|
if(headerName.equalsIgnoreCase("Connection")) {
|
||||||
client->cHttpHeadersValid = true;
|
if(headerValue.indexOf("Upgrade") >= 0) {
|
||||||
client->cMandatoryHeadersCount = 0;
|
|
||||||
|
|
||||||
} else if(headerLine->indexOf(':')) {
|
|
||||||
String headerName = headerLine->substring(0, headerLine->indexOf(':'));
|
|
||||||
String headerValue = headerLine->substring(headerLine->indexOf(':') + 2);
|
|
||||||
|
|
||||||
if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
|
|
||||||
headerValue.toLowerCase();
|
|
||||||
if(headerValue.indexOf(WEBSOCKETS_STRING("upgrade")) >= 0) {
|
|
||||||
client->cIsUpgrade = true;
|
client->cIsUpgrade = true;
|
||||||
}
|
}
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
|
} else if(headerName.equalsIgnoreCase("Upgrade")) {
|
||||||
if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
|
if(headerValue.equalsIgnoreCase("websocket")) {
|
||||||
client->cIsWebsocket = true;
|
client->cIsWebsocket = true;
|
||||||
}
|
}
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
|
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) {
|
||||||
client->cVersion = headerValue.toInt();
|
client->cVersion = headerValue.toInt();
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Key"))) {
|
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Key")) {
|
||||||
client->cKey = headerValue;
|
client->cKey = headerValue;
|
||||||
client->cKey.trim(); // see rfc6455
|
client->cKey.trim(); // see rfc6455
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
|
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) {
|
||||||
client->cProtocol = headerValue;
|
client->cProtocol = headerValue;
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
|
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) {
|
||||||
client->cExtensions = headerValue;
|
client->cExtensions = headerValue;
|
||||||
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Authorization"))) {
|
|
||||||
client->base64Authorization = headerValue;
|
|
||||||
} else {
|
|
||||||
client->cHttpHeadersValid &= execHttpHeaderValidation(headerName, headerValue);
|
|
||||||
if (_mandatoryHttpHeaderCount > 0 && hasMandatoryHeader(headerName)) {
|
|
||||||
client->cMandatoryHeadersCount++;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
(*headerLine) = "";
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine)));
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num);
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str());
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str());
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade);
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket);
|
||||||
@ -741,9 +507,6 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str());
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str());
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str());
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str());
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion);
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - base64Authorization: %s\n", client->num, client->base64Authorization.c_str());
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cHttpHeadersValid: %d\n", client->num, client->cHttpHeadersValid);
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cMandatoryHeadersCount: %d\n", client->num, client->cMandatoryHeadersCount);
|
|
||||||
|
|
||||||
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
|
||||||
|
|
||||||
@ -757,27 +520,11 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
if(client->cVersion != 13) {
|
if(client->cVersion != 13) {
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
if(!client->cHttpHeadersValid) {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
if (client->cMandatoryHeadersCount != _mandatoryHttpHeaderCount) {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_base64Authorization.length() > 0) {
|
|
||||||
String auth = WEBSOCKETS_STRING("Basic ");
|
|
||||||
auth += _base64Authorization;
|
|
||||||
if(auth != client->base64Authorization) {
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] HTTP Authorization failed!\n", client->num);
|
|
||||||
handleAuthorizationFailed(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ok) {
|
if(ok) {
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Websocket connection incoming.\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Websocket connection incomming.\n", client->num);
|
||||||
|
|
||||||
// generate Sec-WebSocket-Accept key
|
// generate Sec-WebSocket-Accept key
|
||||||
String sKey = acceptKey(client->cKey);
|
String sKey = acceptKey(client->cKey);
|
||||||
@ -786,32 +533,22 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
|
|
||||||
client->status = WSC_CONNECTED;
|
client->status = WSC_CONNECTED;
|
||||||
|
|
||||||
String handshake = WEBSOCKETS_STRING("HTTP/1.1 101 Switching Protocols\r\n"
|
client->tcp->write("HTTP/1.1 101 Switching Protocols\r\n"
|
||||||
"Server: arduino-WebSocketsServer\r\n"
|
"Server: arduino-WebSocketsServer\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Upgrade: websocket\r\n"
|
||||||
"Connection: Upgrade\r\n"
|
"Connection: Upgrade\r\n"
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"Sec-WebSocket-Accept: ");
|
"Sec-WebSocket-Accept: ");
|
||||||
handshake += sKey + NEW_LINE;
|
client->tcp->write(sKey.c_str(), sKey.length());
|
||||||
|
client->tcp->write("\r\n");
|
||||||
if(_origin.length() > 0) {
|
|
||||||
handshake += WEBSOCKETS_STRING("Access-Control-Allow-Origin: ");
|
|
||||||
handshake +=_origin + NEW_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(client->cProtocol.length() > 0) {
|
if(client->cProtocol.length() > 0) {
|
||||||
handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
|
// TODO add api to set Protocol of Server
|
||||||
handshake +=_protocol + NEW_LINE;
|
client->tcp->write("Sec-WebSocket-Protocol: arduino\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// header end
|
// header end
|
||||||
handshake += NEW_LINE;
|
client->tcp->write("\r\n");
|
||||||
|
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] handshake %s", client->num, (uint8_t*)handshake.c_str());
|
|
||||||
|
|
||||||
client->tcp->write((uint8_t*)handshake.c_str(), handshake.length());
|
|
||||||
|
|
||||||
headerDone(client);
|
|
||||||
|
|
||||||
// send ping
|
// send ping
|
||||||
WebSockets::sendFrame(client, WSop_ping);
|
WebSockets::sendFrame(client, WSop_ping);
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#ifndef WEBSOCKETSSERVER_H_
|
#ifndef WEBSOCKETSSERVER_H_
|
||||||
#define WEBSOCKETSSERVER_H_
|
#define WEBSOCKETSSERVER_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
|
|
||||||
#define WEBSOCKETS_SERVER_CLIENT_MAX (5)
|
#define WEBSOCKETS_SERVER_CLIENT_MAX (5)
|
||||||
@ -32,102 +33,67 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebSocketsServer: protected WebSockets {
|
class WebSocketsServer: private WebSockets {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
#ifdef __AVR__
|
|
||||||
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
|
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
|
||||||
typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue);
|
|
||||||
#else
|
|
||||||
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
|
|
||||||
|
|
||||||
WebSocketsServer(uint16_t port, String origin = "", String protocol = "arduino");
|
WebSocketsServer(uint16_t port);
|
||||||
~WebSocketsServer(void);
|
~WebSocketsServer(void);
|
||||||
|
|
||||||
void begin(void);
|
void begin(void);
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
void loop(void);
|
void loop(void);
|
||||||
#else
|
|
||||||
// Async interface not need a loop call
|
|
||||||
void loop(void) __attribute__ ((deprecated)) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void onEvent(WebSocketServerEvent cbEvent);
|
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);
|
void 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);
|
void sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0);
|
||||||
bool sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false);
|
void sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
bool sendTXT(uint8_t num, const char * payload, size_t length = 0);
|
void sendTXT(uint8_t num, const char * payload, size_t length = 0);
|
||||||
bool sendTXT(uint8_t num, String & payload);
|
void sendTXT(uint8_t num, String payload);
|
||||||
|
|
||||||
bool broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
void broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
bool broadcastTXT(const uint8_t * payload, size_t length = 0);
|
void broadcastTXT(const uint8_t * payload, size_t length = 0);
|
||||||
bool broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
void broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
bool broadcastTXT(const char * payload, size_t length = 0);
|
void broadcastTXT(const char * payload, size_t length = 0);
|
||||||
bool broadcastTXT(String & payload);
|
void broadcastTXT(String payload);
|
||||||
|
|
||||||
bool sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false);
|
void sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false);
|
||||||
bool sendBIN(uint8_t num, const uint8_t * payload, size_t length);
|
void sendBIN(uint8_t num, const uint8_t * payload, size_t length);
|
||||||
|
|
||||||
bool broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
void broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
||||||
bool broadcastBIN(const uint8_t * payload, size_t length);
|
void 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(void);
|
||||||
void disconnect(uint8_t num);
|
void disconnect(uint8_t num);
|
||||||
|
|
||||||
void setAuthorization(const char * user, const char * password);
|
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
|
||||||
void setAuthorization(const char * auth);
|
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
|
|
||||||
IPAddress remoteIP(uint8_t num);
|
IPAddress remoteIP(uint8_t num);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint16_t _port;
|
uint16_t _port;
|
||||||
String _origin;
|
|
||||||
String _protocol;
|
|
||||||
String _base64Authorization; ///< Base64 encoded Auth request
|
|
||||||
String * _mandatoryHttpHeaders;
|
|
||||||
size_t _mandatoryHttpHeaderCount;
|
|
||||||
|
|
||||||
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
|
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
|
||||||
|
|
||||||
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
|
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
|
||||||
|
|
||||||
WebSocketServerEvent _cbEvent;
|
WebSocketServerEvent _cbEvent;
|
||||||
WebSocketServerHttpHeaderValFunc _httpHeaderValidationFunc;
|
|
||||||
|
|
||||||
bool newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
|
void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
|
||||||
|
|
||||||
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
|
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client);
|
void clientDisconnect(WSclient_t * client);
|
||||||
bool clientIsConnected(WSclient_t * client);
|
bool clientIsConnected(WSclient_t * client);
|
||||||
|
|
||||||
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
|
|
||||||
void handleNewClients(void);
|
void handleNewClients(void);
|
||||||
void handleClientData(void);
|
void handleClientData(void);
|
||||||
#endif
|
|
||||||
|
|
||||||
void handleHeader(WSclient_t * client, String * headerLine);
|
void handleHeader(WSclient_t * client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called if a non Websocket connection is coming in.
|
* called if a non Websocket connection is comming in.
|
||||||
* Note: can be override
|
* Note: can be overrided
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
*/
|
*/
|
||||||
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
virtual void handleNonWebsocketConnection(WSclient_t * client) {
|
||||||
@ -143,24 +109,6 @@ protected:
|
|||||||
clientDisconnect(client);
|
clientDisconnect(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* called if a non Authorization connection is coming in.
|
|
||||||
* 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"
|
|
||||||
"Server: arduino-WebSocket-Server\r\n"
|
|
||||||
"Content-Type: text/plain\r\n"
|
|
||||||
"Content-Length: 45\r\n"
|
|
||||||
"Connection: close\r\n"
|
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
|
||||||
"WWW-Authenticate: Basic realm=\"WebSocket Server\""
|
|
||||||
"\r\n"
|
|
||||||
"This Websocket server requires Authorization!");
|
|
||||||
clientDisconnect(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called for sending a Event to the app
|
* called for sending a Event to the app
|
||||||
* @param num uint8_t
|
* @param num uint8_t
|
||||||
@ -174,30 +122,6 @@ 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,11 +8,10 @@ connection.onopen = function () {
|
|||||||
connection.send('Message from Browser to ESP8266 yay its Working!! ' + new Date());
|
connection.send('Message from Browser to ESP8266 yay its Working!! ' + new Date());
|
||||||
connection.send('ping');
|
connection.send('ping');
|
||||||
|
|
||||||
/* setInterval(function() {
|
setInterval(function() {
|
||||||
connection.send('Time: ' + new Date());
|
connection.send('Time: ' + new Date());
|
||||||
}, 20);
|
}, 20);
|
||||||
*/
|
|
||||||
connection.send('Time: ' + new Date());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
connection.onerror = function (error) {
|
connection.onerror = function (error) {
|
||||||
@ -21,7 +20,6 @@ connection.onerror = function (error) {
|
|||||||
|
|
||||||
connection.onmessage = function (e) {
|
connection.onmessage = function (e) {
|
||||||
console.log('Server: ', e.data);
|
console.log('Server: ', e.data);
|
||||||
connection.send('Time: ' + new Date());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function sendRGB() {
|
function sendRGB() {
|
||||||
|
@ -41,11 +41,11 @@ wsServer.on('request', function(request) {
|
|||||||
connection.on('message', function(message) {
|
connection.on('message', function(message) {
|
||||||
if (message.type === 'utf8') {
|
if (message.type === 'utf8') {
|
||||||
console.log('Received Message: ' + message.utf8Data);
|
console.log('Received Message: ' + message.utf8Data);
|
||||||
// connection.sendUTF(message.utf8Data);
|
connection.sendUTF(message.utf8Data);
|
||||||
}
|
}
|
||||||
else if (message.type === 'binary') {
|
else if (message.type === 'binary') {
|
||||||
console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
|
console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
|
||||||
//connection.sendBytes(message.binaryData);
|
connection.sendBytes(message.binaryData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -16,9 +16,38 @@ function build_sketches()
|
|||||||
$arduino --verify $sketch;
|
$arduino --verify $sketch;
|
||||||
local result=$?
|
local result=$?
|
||||||
if [ $result -ne 0 ]; then
|
if [ $result -ne 0 ]; then
|
||||||
echo "Build failed ($1)"
|
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
|
return $result
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function get_core()
|
||||||
|
{
|
||||||
|
echo Setup core for $1
|
||||||
|
|
||||||
|
cd $HOME/arduino_ide/hardware
|
||||||
|
|
||||||
|
if [ "$1" = "esp8266" ] ; then
|
||||||
|
mkdir esp8266com
|
||||||
|
cd esp8266com
|
||||||
|
git clone https://github.com/esp8266/Arduino.git esp8266
|
||||||
|
cd esp8266/tools
|
||||||
|
python get.py
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" = "esp32" ] ; then
|
||||||
|
mkdir espressif
|
||||||
|
cd espressif
|
||||||
|
git clone https://github.com/espressif/arduino-esp32.git esp32
|
||||||
|
cd esp32/tools
|
||||||
|
python get.py
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user