Compare commits

...

48 Commits

Author SHA1 Message Date
ca52afeec0 code style 2020-10-04 15:11:06 +02:00
beba0f88e3 fix README.md 2020-10-04 15:02:09 +02:00
f2265118b4 bump version to 2.3.0 and add note for ESP8266 BareSSL API changes 2020-10-04 14:59:51 +02:00
9982818cfa update README travis from org to com 2020-10-04 14:56:29 +02:00
91b02341ba Native BareSSL support for ESP8266
see #557, #509, #492, #555, #352
2020-10-04 14:49:22 +02:00
a00d3edcb7 Merge pull request #567 from lucalas/master
setFingerprint in WiFiClientSecure required to pass certificate Check
2020-10-03 14:52:10 +02:00
c73c77e988 Add check to set fingerprint; 2020-10-02 09:29:55 +02:00
e1ddbfe1a5 Format Code; 2020-10-01 01:14:01 +02:00
f65e8d9062 call setFingerPrint for ssl object in client with fingerprint received in beginSSL or no connection will start; 2020-10-01 01:12:54 +02:00
05ec18e49b Merge pull request #565 from tobiges/master
header response timeout added
2020-09-14 10:25:59 +02:00
e185668a97 header response timeout added 2020-09-12 17:20:03 +02:00
7e34a8b246 Merge pull request #563 from simap/accessClients
add api to check connectedness of clients by num
2020-09-08 21:08:32 +02:00
4acc7eff8a add api to check connectedness of clients by num 2020-09-08 09:54:33 -07:00
b3c5348e9b update arduino IDE version in travis test 2020-07-25 09:07:02 +02:00
19c39d5ea0 typo 2020-07-11 18:38:39 +02:00
ebdc8def4a Merge branch 'master' of github.com:Links2004/arduinoWebSockets 2020-07-11 18:17:05 +02:00
44fb41e3b7 WebSocketClientSocketIOack.ino:150:25: ARDUINOJSON_USE_LONG_LONG fix 2020-07-11 18:16:34 +02:00
cadbd6458f Merge pull request #551 from Links2004/ESP32v4
fix #525 (detect ESP32 version)
2020-07-11 18:13:13 +02:00
f244741caa WebSocketClientSocketIO.ino:113:25: ArduinoJson, you must set ARDUINOJSON_USE_LONG_LONG error 2020-07-11 18:07:16 +02:00
3f1cedb21c fix #541 allow loop() to be called before begin() 2020-07-11 17:58:36 +02:00
ba6275e7fe fix #525 (detect ESP32 vesion) 2020-07-11 17:55:18 +02:00
a71a480676 fix #539 (NODEBUG_WEBSOCKETS warning)
fix warning when using NODEBUG_WEBSOCKETS as compiler option.
2020-05-14 18:04:46 +02:00
1e271b5e12 Merge remote-tracking branch 'origin/master' 2020-05-03 13:07:13 +02:00
0c3b15c5e7 fix #454 2020-05-03 13:05:55 +02:00
7a4160814c fix #454 2020-05-03 13:04:53 +02:00
784088d9cc bump version to 2.2.1 2020-05-03 10:03:53 +02:00
9048ef9ee4 code style 2020-05-03 09:28:55 +02:00
80b0867786 update travis for IDE 1.8.12 2020-05-03 09:27:49 +02:00
b9e1336826 add new define for yield WEBSOCKETS_YIELD 2020-05-03 09:12:03 +02:00
ac9b2ccdf6 Merge pull request #521 from amrbekhit/patch-1
Initialize _reconnectInterval in constructor.
2020-04-01 19:09:53 +02:00
12684582aa Initialize _reconnectInterval in constructor.
This allows setReconnectInterval() to be called before begin() and stops begin() from overriding _reconnectInterval every time it is called.
2020-03-21 22:14:25 +03:00
420cc55960 Merge pull request #501 from amrbekhit/websockets_tcp_timeout_increase
Increased WEBSOCKETS_TCP_TIMEOUT to 5000ms.
2020-03-14 14:51:25 +01:00
64296cced7 Merge pull request #512 from maurus95/master
Implementing automatic WS server-side heartbeat
2020-02-15 22:27:40 +01:00
c3f01e43fc Merge pull request #514 from simap/master
read can return -1, check for this to avoid corrupting protocol
2020-02-15 22:18:48 +01:00
04e4be03fe Merge pull request #515 from simap/esp32yield
add a yield here for esp32 to avoid a busy loop
2020-02-15 22:18:08 +01:00
ebd7a528ac add a yield here for esp32 to avoid a busy loop
if data isn't available yet, but is expected, yielding here is nicer
than burning the cpu in a loop, just like in esp8266 case.
2020-02-15 06:43:46 -08:00
516911900b read can return -1, check for this to avoid corrupting protocol
fixes #470
2020-02-15 06:37:07 -08:00
674a6e98c9 Implemented HeartBeat in WebSocketsServer 2020-02-10 19:45:55 +01:00
4ee0ba5630 Increased WEBSOCKETS_TCP_TIMEOUT to 5000ms.
See https://github.com/Links2004/arduinoWebSockets/issues/500.
2019-12-24 17:03:32 +03:00
c038f100d6 Merge pull request #458 from Nufflee/patch-1
Syntax highlighting in README.md
2019-07-21 08:53:00 +02:00
0444a78441 [SocketIO] add example for use of ACK / callback handling 2019-07-20 14:24:55 +02:00
8cc20b6e4b Merge branch 'master' of github.com:Links2004/arduinoWebSockets 2019-07-20 13:47:55 +02:00
40152be197 code style 2019-07-20 13:47:40 +02:00
e2669c1c5e [SocketIO] allow to send any message 2019-07-20 13:46:59 +02:00
771831c57e Syntax highlighting in README.md 2019-07-15 23:13:38 +02:00
06a7bb177b Merge pull request #452 from luc-github/master
Fix warnings in platformIO
2019-07-04 16:12:21 +02:00
Luc
bd158c9c5c Fix warnings in platformIO
Fix : warning: enumeration value 'WStype_ERROR' not handled in switch [-Wswitch]
Fix : warning: variable 'ip' set but not used [-Wunused-but-set-variable]
2019-07-04 12:58:37 +02:00
9a803e1fb3 bump version to 2.2.0 2019-06-29 19:04:10 +02:00
14 changed files with 436 additions and 68 deletions

View File

@ -11,13 +11,11 @@ os:
env:
matrix:
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80" IDE_VERSION=1.6.5
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.5
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.9
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,dbg=Serial1" IDE_VERSION=1.6.5
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.6.5
- CPU="esp8266" BOARD="esp8266com:esp8266:generic:xtal=80,eesz=1M,FlashMode=qio,FlashFreq=80" IDE_VERSION=1.8.13
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.5
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.9
- CPU="esp32" BOARD="espressif:esp32:esp32:FlashFreq=80" IDE_VERSION=1.8.13
script:
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
- export DISPLAY=:1.0

View File

@ -1,4 +1,4 @@
WebSocket Server and Client for Arduino [![Build Status](https://travis-ci.org/Links2004/arduinoWebSockets.svg?branch=master)](https://travis-ci.org/Links2004/arduinoWebSockets)
WebSocket Server and Client for Arduino [![Build Status](https://travis-ci.com/Links2004/arduinoWebSockets.svg?branch=master)](https://travis-ci.com/Links2004/arduinoWebSockets)
===========================================
a WebSocket Server and Client for Arduino based on RFC6455.
@ -34,7 +34,9 @@ a WebSocket Server and Client for Arduino based on RFC6455.
###### Note: ######
version 2.0 and up is not compatible with AVR/ATmega, check ATmega branch.
version 2.0.0 and up is not compatible with AVR/ATmega, check ATmega branch.
version 2.3.0 has API changes for the ESP8266 BareSSL (may brakes existing code)
Arduino for AVR not supports std namespace of c++.
@ -57,32 +59,34 @@ The mode can be activated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE
### High Level Client API ###
- `begin` : Initiate connection sequence to the websocket host.
```
```c++
void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
```
- `onEvent`: Callback to handle for websocket events
```
```c++
void onEvent(WebSocketClientEvent cbEvent);
```
- `WebSocketClientEvent`: Handler for websocket events
```
```c++
void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length)
```
Where `WStype_t type` is defined as:
```
```c++
typedef enum {
WStype_ERROR,
WStype_DISCONNECTED,
WStype_CONNECTED,
WStype_TEXT,
WStype_BIN,
WStype_FRAGMENT_TEXT_START,
WStype_FRAGMENT_BIN_START,
WStype_FRAGMENT,
WStype_FRAGMENT_FIN,
WStype_FRAGMENT_TEXT_START,
WStype_FRAGMENT_BIN_START,
WStype_FRAGMENT,
WStype_FRAGMENT_FIN,
WStype_PING,
WStype_PONG,
} WStype_t;
```

View File

@ -110,7 +110,7 @@ void loop() {
// add payload (parameters) for the event
JsonObject param1 = array.createNestedObject();
param1["now"] = now;
param1["now"] = (uint32_t) now;
// JSON to String (serializion)
String output;

View File

@ -0,0 +1,162 @@
/*
* WebSocketClientSocketIOack.ino
*
* Created on: 20.07.2019
*
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ArduinoJson.h>
#include <WebSocketsClient.h>
#include <SocketIOclient.h>
#include <Hash.h>
ESP8266WiFiMulti WiFiMulti;
SocketIOclient socketIO;
#define USE_SERIAL Serial
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
switch(type) {
case sIOtype_DISCONNECT:
USE_SERIAL.printf("[IOc] Disconnected!\n");
break;
case sIOtype_CONNECT:
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
break;
case sIOtype_EVENT:
{
char * sptr = NULL;
int id = strtol((char *)payload, &sptr, 10);
USE_SERIAL.printf("[IOc] get event: %s id: %d\n", payload, id);
if(id) {
payload = (uint8_t *)sptr;
}
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, payload, length);
if(error) {
USE_SERIAL.print(F("deserializeJson() failed: "));
USE_SERIAL.println(error.c_str());
return;
}
String eventName = doc[0];
USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str());
// Message Includes a ID for a ACK (callback)
if(id) {
// creat JSON message for Socket.IO (ack)
DynamicJsonDocument docOut(1024);
JsonArray array = docOut.to<JsonArray>();
// add payload (parameters) for the ack (callback function)
JsonObject param1 = array.createNestedObject();
param1["now"] = millis();
// JSON to String (serializion)
String output;
output += id;
serializeJson(docOut, output);
// Send event
socketIO.send(sIOtype_ACK, output);
}
}
break;
case sIOtype_ACK:
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_ERROR:
USE_SERIAL.printf("[IOc] get error: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_BINARY_EVENT:
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_BINARY_ACK:
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
hexdump(payload, length);
break;
}
}
void setup() {
//USE_SERIAL.begin(921600);
USE_SERIAL.begin(115200);
//Serial.setDebugOutput(true);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
// disable AP
if(WiFi.getMode() & WIFI_AP) {
WiFi.softAPdisconnect(true);
}
WiFiMulti.addAP("SSID", "passpasspass");
//WiFi.disconnect();
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
String ip = WiFi.localIP().toString();
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
// server address, port and URL
socketIO.begin("10.11.100.100", 8880);
// event handler
socketIO.onEvent(socketIOEvent);
}
unsigned long messageTimestamp = 0;
void loop() {
socketIO.loop();
uint64_t now = millis();
if(now - messageTimestamp > 2000) {
messageTimestamp = now;
// creat JSON message for Socket.IO (event)
DynamicJsonDocument doc(1024);
JsonArray array = doc.to<JsonArray>();
// add evnet name
// Hint: socket.on('event_name', ....
array.add("event_name");
// add payload (parameters) for the event
JsonObject param1 = array.createNestedObject();
param1["now"] = (uint32_t) now;
// JSON to String (serializion)
String output;
serializeJson(doc, output);
// Send event
socketIO.sendEVENT(output);
// Print JSON for debugging
USE_SERIAL.println(output);
}
}

View File

@ -13,7 +13,7 @@
"type": "git",
"url": "https://github.com/Links2004/arduinoWebSockets.git"
},
"version": "2.1.4",
"version": "2.3.0",
"license": "LGPL-2.1",
"export": {
"exclude": [

View File

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

View File

@ -40,12 +40,13 @@ bool SocketIOclient::isConnected(void) {
/**
* send text data to client
* @param num uint8_t client id
* @param type socketIOmessageType_t
* @param payload uint8_t *
* @param length size_t
* @param headerToPayload bool (see sendFrame for more details)
* @param headerToPayload bool (see sendFrame for more details)
* @return true if ok
*/
bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) {
bool SocketIOclient::send(socketIOmessageType_t type, uint8_t * payload, size_t length, bool headerToPayload) {
bool ret = false;
if(length == 0) {
length = strlen((const char *)payload);
@ -56,7 +57,7 @@ bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPa
ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true);
// Engine.IO / Socket.IO Header
if(ret) {
uint8_t buf[3] = { eIOtype_MESSAGE, sIOtype_EVENT, 0x00 };
uint8_t buf[3] = { eIOtype_MESSAGE, type, 0x00 };
ret = WebSocketsClient::write(&_client, buf, 2);
}
if(ret && payload && length > 0) {
@ -66,12 +67,38 @@ bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPa
} else {
// TODO implement
}
// return WebSocketsClient::sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload);
}
return false;
}
bool SocketIOclient::send(socketIOmessageType_t type, const uint8_t * payload, size_t length) {
return send(type, (uint8_t *)payload, length);
}
bool SocketIOclient::send(socketIOmessageType_t type, char * payload, size_t length, bool headerToPayload) {
return send(type, (uint8_t *)payload, length, headerToPayload);
}
bool SocketIOclient::send(socketIOmessageType_t type, const char * payload, size_t length) {
return send(type, (uint8_t *)payload, length);
}
bool SocketIOclient::send(socketIOmessageType_t type, String & payload) {
return send(type, (uint8_t *)payload.c_str(), payload.length());
}
/**
* send text data to client
* @param num uint8_t client id
* @param payload uint8_t *
* @param length size_t
* @param headerToPayload bool (see sendFrame for more details)
* @return true if ok
*/
bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) {
return send(sIOtype_EVENT, payload, length, headerToPayload);
}
bool SocketIOclient::sendEVENT(const uint8_t * payload, size_t length) {
return sendEVENT((uint8_t *)payload, length);
}
@ -161,7 +188,7 @@ void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t leng
break;
}
} break;
case WStype_ERROR:
case WStype_BIN:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:

View File

@ -59,6 +59,12 @@ class SocketIOclient : protected WebSocketsClient {
bool sendEVENT(const char * payload, size_t length = 0);
bool sendEVENT(String & payload);
bool send(socketIOmessageType_t type, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
bool send(socketIOmessageType_t type, const uint8_t * payload, size_t length = 0);
bool send(socketIOmessageType_t type, char * payload, size_t length = 0, bool headerToPayload = false);
bool send(socketIOmessageType_t type, const char * payload, size_t length = 0);
bool send(socketIOmessageType_t type, String & payload);
void loop(void);
protected:

View File

@ -39,7 +39,14 @@ extern "C" {
#ifdef ESP8266
#include <Hash.h>
#elif defined(ESP32)
#include <esp_system.h>
#if ESP_IDF_VERSION_MAJOR >= 4
#include <esp32/sha.h>
#else
#include <hwcrypto/sha.h>
#endif
#else
extern "C" {
@ -595,7 +602,7 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
#else
unsigned long t = millis();
size_t len;
ssize_t len;
DEBUG_WEBSOCKETS("[readCb] n: %zu t: %lu\n", n, t);
while(n > 0) {
if(client->tcp == NULL) {
@ -623,14 +630,12 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
}
if(!client->tcp->available()) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD();
continue;
}
len = client->tcp->read((uint8_t *)out, n);
if(len) {
if(len > 0) {
t = millis();
out += len;
n -= len;
@ -638,13 +643,12 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
} else {
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD();
}
if(cb) {
cb(client, true);
}
WEBSOCKETS_YIELD();
#endif
return true;
}
@ -691,10 +695,9 @@ size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) {
} else {
//DEBUG_WEBSOCKETS("write %d failed left %d!\n", len, n);
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD();
}
WEBSOCKETS_YIELD();
return total;
}

View File

@ -50,8 +50,10 @@
#ifndef DEBUG_WEBSOCKETS
#define DEBUG_WEBSOCKETS(...)
#ifndef NODEBUG_WEBSOCKETS
#define NODEBUG_WEBSOCKETS
#endif
#endif
#if defined(ESP8266) || defined(ESP32)
@ -61,11 +63,18 @@
// moves all Header strings to Flash (~300 Byte)
//#define WEBSOCKETS_SAVE_RAM
#if defined(ESP8266)
#define WEBSOCKETS_YIELD() delay(0)
#elif defined(ESP32)
#define WEBSOCKETS_YIELD() yield()
#endif
#elif defined(STM32_DEVICE)
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
#define WEBSOCKETS_USE_BIG_MEM
#define GET_FREE_HEAP System.freeMemory()
#define WEBSOCKETS_YIELD()
#else
@ -73,10 +82,11 @@
#define WEBSOCKETS_MAX_DATA_SIZE (1024)
// moves all Header strings to Flash
#define WEBSOCKETS_SAVE_RAM
#define WEBSOCKETS_YIELD()
#endif
#define WEBSOCKETS_TCP_TIMEOUT (2000)
#define WEBSOCKETS_TCP_TIMEOUT (5000)
#define NETWORK_ESP8266_ASYNC (0)
#define NETWORK_ESP8266 (1)
@ -116,6 +126,7 @@
#elif defined(ESP32)
#include <WiFi.h>
#include <WiFiClientSecure.h>
#define SSL_AXTLS
#elif defined(ESP31B)
#include <ESP31BWiFi.h>
#else
@ -135,6 +146,11 @@
#ifdef ESP8266
#include <ESP8266WiFi.h>
#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
#define SSL_BARESSL
#else
#define SSL_AXTLS
#endif
#else
#include <ESP31BWiFi.h>
#endif
@ -164,6 +180,7 @@
#include <WiFi.h>
#include <WiFiClientSecure.h>
#define SSL_AXTLS
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer

View File

@ -30,6 +30,9 @@ WebSocketsClient::WebSocketsClient() {
_client.num = 0;
_client.cIsClient = true;
_client.extraHeaders = WEBSOCKETS_STRING("Origin: file://");
_reconnectInterval = 500;
_port = 0;
_host = "";
}
WebSocketsClient::~WebSocketsClient() {
@ -43,7 +46,7 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
_host = host;
_port = port;
#if defined(HAS_SSL)
_fingerprint = "";
_fingerprint = SSL_FINGERPRINT_NULL;
_CA_cert = NULL;
#endif
@ -82,7 +85,7 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
#endif
_lastConnectionFail = 0;
_reconnectInterval = 500;
_lastHeaderSent = 0;
}
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
@ -94,6 +97,7 @@ void WebSocketsClient::begin(IPAddress host, uint16_t port, const char * url, co
}
#if defined(HAS_SSL)
#if defined(SSL_AXTLS)
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) {
begin(host, port, url, protocol);
_client.isSSL = true;
@ -108,10 +112,31 @@ void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String f
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
begin(host, port, url, protocol);
_client.isSSL = true;
_fingerprint = "";
_fingerprint = SSL_FINGERPRINT_NULL;
_CA_cert = CA_cert;
}
#endif
#else
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const uint8_t * fingerprint, const char * protocol) {
begin(host, port, url, protocol);
_client.isSSL = true;
_fingerprint = fingerprint;
_CA_cert = NULL;
}
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
begin(host, port, url, protocol);
_client.isSSL = true;
_fingerprint = SSL_FINGERPRINT_NULL;
_CA_cert = new BearSSL::X509List(CA_cert);
}
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
begin(host, port, url, protocol);
_client.isSSL = true;
_fingerprint = SSL_FINGERPRINT_NULL;
_CA_cert = CA_cert;
}
#endif // SSL_AXTLS
#endif // HAS_SSL
void WebSocketsClient::beginSocketIO(const char * host, uint16_t port, const char * url, const char * protocol) {
begin(host, port, url, protocol);
@ -127,7 +152,7 @@ void WebSocketsClient::beginSocketIOSSL(const char * host, uint16_t port, const
begin(host, port, url, protocol);
_client.isSocketIO = true;
_client.isSSL = true;
_fingerprint = "";
_fingerprint = SSL_FINGERPRINT_NULL;
}
void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) {
@ -138,8 +163,12 @@ void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port,
begin(host, port, url, protocol);
_client.isSocketIO = true;
_client.isSSL = true;
_fingerprint = "";
_CA_cert = CA_cert;
_fingerprint = SSL_FINGERPRINT_NULL;
#if defined(SSL_AXTLS)
_CA_cert = CA_cert;
#else
_CA_cert = new BearSSL::X509List(CA_cert);
#endif
}
#endif
@ -148,6 +177,10 @@ void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port,
* called in arduino loop
*/
void WebSocketsClient::loop(void) {
if(_port == 0) {
return;
}
WEBSOCKETS_YIELD();
if(!clientIsConnected(&_client)) {
// do not flood the server
if((millis() - _lastConnectionFail) < _reconnectInterval) {
@ -168,10 +201,18 @@ void WebSocketsClient::loop(void) {
DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate");
#if defined(ESP32)
_client.ssl->setCACert(_CA_cert);
#elif defined(ESP8266)
#elif defined(ESP8266) && defined(SSL_AXTLS)
_client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
#elif defined(ESP8266) && defined(SSL_BARESSL)
_client.ssl->setTrustAnchors(_CA_cert);
#else
#error setCACert not implemented
#endif
#if defined(SSL_BARESSL)
} else if(_fingerprint) {
_client.ssl->setFingerprint(_fingerprint);
} else {
_client.ssl->setInsecure();
#endif
}
} else {
@ -190,6 +231,7 @@ void WebSocketsClient::loop(void) {
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
return;
}
WEBSOCKETS_YIELD();
#if defined(ESP32)
if(_client.tcp->connect(_host.c_str(), _port, WEBSOCKETS_TCP_TIMEOUT)) {
#else
@ -203,7 +245,7 @@ void WebSocketsClient::loop(void) {
}
} else {
handleClientData();
WEBSOCKETS_YIELD();
if(_client.status == WSC_CONNECTED) {
handleHBPing();
handleHBTimeout(&_client);
@ -483,6 +525,12 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
* Handel incomming data from Client
*/
void WebSocketsClient::handleClientData(void) {
if(_client.status == WSC_HEADER && _lastHeaderSent + WEBSOCKETS_TCP_TIMEOUT < millis()) {
DEBUG_WEBSOCKETS("[WS-Client][handleClientData] header response timeout.. disconnecting!\n");
clientDisconnect(&_client);
WEBSOCKETS_YIELD();
return;
}
int len = _client.tcp->available();
if(len > 0) {
switch(_client.status) {
@ -498,9 +546,7 @@ void WebSocketsClient::handleClientData(void) {
break;
}
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
delay(0);
#endif
WEBSOCKETS_YIELD();
}
#endif
@ -593,6 +639,7 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
#endif
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start));
_lastHeaderSent = millis();
}
/**
@ -706,6 +753,7 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
headerDone(client);
runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
} else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) {
if(_client.tcp->available()) {
// read not needed data
@ -715,6 +763,7 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
}
}
sendHeader(client);
#endif
} else {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
_lastConnectionFail = millis();
@ -755,14 +804,18 @@ void WebSocketsClient::connectedCb() {
#endif
#if defined(HAS_SSL)
#if defined(SSL_AXTLS) || defined(ESP32)
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;
}
#else
if(_client.isSSL && _fingerprint) {
#endif
} else if(_client.isSSL && !_CA_cert) {
#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
#if defined(SSL_BARESSL)
_client.ssl->setInsecure();
#endif
}

View File

@ -43,8 +43,13 @@ class WebSocketsClient : protected WebSockets {
void begin(IPAddress host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
#if defined(HAS_SSL)
void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * = "", const char * protocol = "arduino");
#ifdef SSL_AXTLS
void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * fingerprint = "", const char * protocol = "arduino");
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
#else
void beginSSL(const char * host, uint16_t port, const char * url = "/", const uint8_t * fingerprint = NULL, const char * protocol = "arduino");
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
#endif
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino");
#endif
@ -91,15 +96,23 @@ class WebSocketsClient : protected WebSockets {
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
void disableHeartbeat();
bool isConnected(void);
protected:
String _host;
uint16_t _port;
bool isConnected(void);
#if defined(HAS_SSL)
#ifdef SSL_AXTLS
String _fingerprint;
const char * _CA_cert;
#define SSL_FINGERPRINT_NULL ""
#else
const uint8_t * _fingerprint;
BearSSL::X509List * _CA_cert;
#define SSL_FINGERPRINT_NULL NULL
#endif
#endif
WSclient_t _client;
@ -107,6 +120,7 @@ class WebSocketsClient : protected WebSockets {
unsigned long _lastConnectionFail;
unsigned long _reconnectInterval;
unsigned long _lastHeaderSent;
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);

View File

@ -26,10 +26,13 @@
#include "WebSocketsServer.h"
WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol) {
_port = port;
_origin = origin;
_protocol = protocol;
_runnning = false;
_port = port;
_origin = origin;
_protocol = protocol;
_runnning = false;
_pingInterval = 0;
_pongTimeout = 0;
_disconnectTimeoutCount = 0;
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
@ -91,6 +94,10 @@ void WebSocketsServer::begin(void) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client->cHttpLine = "";
#endif
client->pingInterval = _pingInterval;
client->pongTimeout = _pongTimeout;
client->disconnectTimeoutCount = _disconnectTimeoutCount;
}
#ifdef ESP8266
@ -128,7 +135,9 @@ void WebSocketsServer::close(void) {
*/
void WebSocketsServer::loop(void) {
if(_runnning) {
WEBSOCKETS_YIELD();
handleNewClients();
WEBSOCKETS_YIELD();
handleClientData();
}
}
@ -224,9 +233,7 @@ bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool heade
ret = false;
}
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD();
}
return ret;
}
@ -287,9 +294,7 @@ bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool heade
ret = false;
}
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD();
}
return ret;
}
@ -336,9 +341,7 @@ bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) {
ret = false;
}
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD();
}
return ret;
}
@ -416,6 +419,18 @@ int WebSocketsServer::connectedClients(bool ping) {
return count;
}
/**
* see if one client is connected
* @param num uint8_t client id
*/
bool WebSocketsServer::clientIsConnected(uint8_t num) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return false;
}
WSclient_t * client = &_clients[num];
return clientIsConnected(client);
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
/**
* get an IP for a client
@ -462,7 +477,9 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
#endif
client->status = WSC_HEADER;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
#ifndef NODEBUG_WEBSOCKETS
IPAddress ip = client->tcp->remoteIP();
#endif
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);
@ -484,6 +501,12 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine)));
#endif
client->pingInterval = _pingInterval;
client->pongTimeout = _pongTimeout;
client->disconnectTimeoutCount = _disconnectTimeoutCount;
client->lastPing = millis();
client->pongReceived = false;
return true;
break;
}
@ -635,7 +658,9 @@ void WebSocketsServer::handleNewClients(void) {
if(!ok) {
// no free space to handle client
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
#ifndef NODEBUG_WEBSOCKETS
IPAddress ip = tcpClient->remoteIP();
#endif
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
#else
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
@ -643,8 +668,8 @@ void WebSocketsServer::handleNewClients(void) {
tcpClient->stop();
}
WEBSOCKETS_YIELD();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
delay(0);
}
#endif
}
@ -673,10 +698,11 @@ void WebSocketsServer::handleClientData(void) {
break;
}
}
handleHBPing(client);
handleHBTimeout(client);
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
WEBSOCKETS_YIELD();
}
}
#endif
@ -850,3 +876,50 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
}
}
}
/**
* send heartbeat ping to server in set intervals
*/
void WebSocketsServer::handleHBPing(WSclient_t * client) {
if(client->pingInterval == 0)
return;
uint32_t pi = millis() - client->lastPing;
if(pi > client->pingInterval) {
DEBUG_WEBSOCKETS("[WS-Server][%d] sending HB ping\n", client->num);
if(sendPing(client->num)) {
client->lastPing = millis();
client->pongReceived = false;
}
}
}
/**
* enable ping/pong heartbeat process
* @param pingInterval uint32_t how often ping will be sent
* @param pongTimeout uint32_t millis after which pong should timout if not received
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
*/
void WebSocketsServer::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
_pingInterval = pingInterval;
_pongTimeout = pongTimeout;
_disconnectTimeoutCount = disconnectTimeoutCount;
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
WebSockets::enableHeartbeat(client, pingInterval, pongTimeout, disconnectTimeoutCount);
}
}
/**
* disable ping/pong heartbeat process
*/
void WebSocketsServer::disableHeartbeat() {
_pingInterval = 0;
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
client->pingInterval = 0;
}
}

View File

@ -92,6 +92,11 @@ class WebSocketsServer : protected WebSockets {
int connectedClients(bool ping = false);
bool clientIsConnected(uint8_t num);
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
void disableHeartbeat();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
IPAddress remoteIP(uint8_t num);
#endif
@ -113,6 +118,10 @@ class WebSocketsServer : protected WebSockets {
bool _runnning;
uint32_t _pingInterval;
uint32_t _pongTimeout;
uint8_t _disconnectTimeoutCount;
bool newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
@ -127,6 +136,8 @@ class WebSocketsServer : protected WebSockets {
void handleHeader(WSclient_t * client, String * headerLine);
void handleHBPing(WSclient_t * client); // send ping in specified intervals
/**
* called if a non Websocket connection is coming in.
* Note: can be override