diff --git a/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino b/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino index d4dfa63..48d38a7 100644 --- a/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino +++ b/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino @@ -54,7 +54,7 @@ void setStatePinToNewValue(const char* path, bool state); void afterVoltageIsUpdated(const char* code, int voltage); void setup() { - Serial.begin(9600); + .begin(9600); startWiFi(); // This initializes the SDK's configurations and returns reference to your project. project = grandeur.init(apiKey, token); diff --git a/library.properties b/library.properties index e845779..a4c32c2 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Grandeur -version=1.0.2 +version=1.0.3 author=Grandeur Technologies maintainer=Grandeur Technologies sentence=Let your arduinos and ESPs communicate with Grandeur in realtime. diff --git a/src/Data.cpp b/src/Data.cpp index ba0dd4e..740e5bd 100644 --- a/src/Data.cpp +++ b/src/Data.cpp @@ -74,8 +74,8 @@ void Grandeur::Project::Device::Data::set(const char* path, Var data) { oPayload["path"] = path; oPayload["data"] = data; - // Sending the packet and scheduling callback. - _duplex->send("/device/data/set", oPayload, NULL); + // Sending the packet without response. + _duplex->send("/device/data/set", oPayload); } Grandeur::Project::Device::Event Grandeur::Project::Device::Data::on(const char* path, Callback cb) { diff --git a/src/DuplexHandler.cpp b/src/DuplexHandler.cpp index f991b44..89c3ac9 100644 --- a/src/DuplexHandler.cpp +++ b/src/DuplexHandler.cpp @@ -46,7 +46,7 @@ void DuplexHandler::loop(bool valve) { timeSinceLastMessage = millis(); DEBUG_GRANDEUR("Pinging Grandeur."); - send("ping", NULL); + send("ping"); } // Running duplex loop _client.loop(); @@ -111,6 +111,22 @@ Message DuplexHandler::send(const char* task, Callback cb) { return {message.id, message.str}; } +Message DuplexHandler::send(const char* task) { + // Preparing a new message. + Message message = prepareMessage(task); + + // If channel isn't connected yet, buffer the message and return. + if(_status != CONNECTED) { + _buffer.push(message.id, message.str); + return {message.id, message.str}; + } + + // Sending message. + sendMessage(message.str.c_str()); + + return {message.id, message.str}; +} + Message DuplexHandler::send(const char* task, Var payload, Callback cb) { // Preparing a new message. Message message = prepareMessage(task, payload); @@ -130,6 +146,22 @@ Message DuplexHandler::send(const char* task, Var payload, Callback cb) { return {message.id, message.str}; } +Message DuplexHandler::send(const char* task, Var payload) { + // Preparing a new message. + Message message = prepareMessage(task, payload); + + // If channel isn't connected yet, buffer the message and return. + if(_status != CONNECTED) { + _buffer.push(message.id, message.str); + return {message.id, message.str}; + } + + // Sending message. + sendMessage(message.str.c_str()); + + return {message.id, message.str}; +} + void DuplexHandler::receive(Var header, Var payload) { // Extracting task and id from header and code. const char* task = header["task"]; @@ -254,8 +286,7 @@ void DuplexHandler::duplexEventHandler(WStype_t eventType, uint8_t* message, siz // We do not need to handle the unpair event in Device SDKs. if(strcmp(task, "unpair") == 0); // Ping has no data so we simply emit. - else if(strcmp(task, "ping") == 0) - _tasks.emit((gId) header["id"], "", undefined); + else if(strcmp(task, "ping") == 0); // If it is an update event rather than a task (response message). else if(strcmp(task, "update") == 0) publish(payload["event"], payload["path"], payload["update"]); diff --git a/src/DuplexHandler.h b/src/DuplexHandler.h index 0c7b023..9c8be2e 100644 --- a/src/DuplexHandler.h +++ b/src/DuplexHandler.h @@ -72,9 +72,15 @@ class DuplexHandler { // Constructor DuplexHandler(); void init(Config config); - // Sends a message to duplex channel. + // Sends a message to duplex channel: + // without payload. Message send(const char* task, Callback cb); + // without payload, without response. + Message send(const char* task); + // with payload. Message send(const char* task, Var payload, Callback cb); + // with payload, without response. + Message send(const char* task, Var payload); // Subscribes to a topic. gId subscribe(const char* topic, Var payload, Callback updateHandler); diff --git a/src/arduinoWebSockets/SocketIOclient.cpp b/src/arduinoWebSockets/SocketIOclient.cpp index 6b14319..a06efa2 100644 --- a/src/arduinoWebSockets/SocketIOclient.cpp +++ b/src/arduinoWebSockets/SocketIOclient.cpp @@ -18,11 +18,59 @@ SocketIOclient::~SocketIOclient() { void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) { WebSocketsClient::beginSocketIO(host, port, url, protocol); WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); + initClient(); } void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) { WebSocketsClient::beginSocketIO(host, port, url, protocol); WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); + initClient(); +} +#if defined(HAS_SSL) +void SocketIOclient::beginSSL(const char * host, uint16_t port, const char * url, const char * protocol) { + WebSocketsClient::beginSocketIOSSL(host, port, url, protocol); + WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); + initClient(); +} + +void SocketIOclient::beginSSL(String host, uint16_t port, String url, String protocol) { + WebSocketsClient::beginSocketIOSSL(host, port, url, protocol); + WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); + initClient(); +} +#if defined(SSL_BARESSL) +void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) { + WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol); + WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); + initClient(); +} + +void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) { + WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol); + WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); + initClient(); +} + +void SocketIOclient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) { + WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey); +} + +void SocketIOclient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) { + WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey); +} + +#endif +#endif + +void SocketIOclient::configureEIOping(bool disableHeartbeat) { + _disableHeartbeat = disableHeartbeat; +} + +void SocketIOclient::initClient(void) { + if(_client.cUrl.indexOf("EIO=4") != -1) { + DEBUG_WEBSOCKETS("[wsIOc] found EIO=4 disable EIO ping on client\n"); + configureEIOping(true); + } } /** @@ -51,7 +99,7 @@ bool SocketIOclient::send(socketIOmessageType_t type, uint8_t * payload, size_t if(length == 0) { length = strlen((const char *)payload); } - if(clientIsConnected(&_client)) { + if(clientIsConnected(&_client) && _client.status == WSC_CONNECTED) { if(!headerToPayload) { // webSocket Header ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true); @@ -118,8 +166,8 @@ bool SocketIOclient::sendEVENT(String & payload) { void SocketIOclient::loop(void) { WebSocketsClient::loop(); unsigned long t = millis(); - if((t - _lastConnectionFail) > EIO_HEARTBEAT_INTERVAL) { - _lastConnectionFail = t; + if(!_disableHeartbeat && (t - _lastHeartbeat) > EIO_HEARTBEAT_INTERVAL) { + _lastHeartbeat = t; DEBUG_WEBSOCKETS("[wsIOc] send ping\n"); WebSocketsClient::sendTXT(eIOtype_PING); } @@ -135,6 +183,7 @@ void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t leng DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload); // send message to server when Connected // Engine.io upgrade confirmation message (required) + WebSocketsClient::sendTXT("2probe"); WebSocketsClient::sendTXT(eIOtype_UPGRADE); runIOCbEvent(sIOtype_CONNECT, payload, length); } break; @@ -165,6 +214,8 @@ void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t leng DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data); break; case sIOtype_CONNECT: + DEBUG_WEBSOCKETS("[wsIOc] connected (%d): %s\n", lData, data); + return; case sIOtype_DISCONNECT: case sIOtype_ACK: case sIOtype_ERROR: diff --git a/src/arduinoWebSockets/SocketIOclient.h b/src/arduinoWebSockets/SocketIOclient.h index ca0a69b..6deb168 100644 --- a/src/arduinoWebSockets/SocketIOclient.h +++ b/src/arduinoWebSockets/SocketIOclient.h @@ -49,6 +49,16 @@ class SocketIOclient : protected WebSocketsClient { void begin(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); void begin(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); +#ifdef HAS_SSL + void beginSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); + void beginSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); +#ifndef SSL_AXTLS + void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino"); + void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino"); + void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL); + void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL); +#endif +#endif bool isConnected(void); void onEvent(SocketIOclientEvent cbEvent); @@ -67,7 +77,10 @@ class SocketIOclient : protected WebSocketsClient { void loop(void); + void configureEIOping(bool disableHeartbeat = false); + protected: + bool _disableHeartbeat = false; uint64_t _lastHeartbeat = 0; SocketIOclientEvent _cbEvent; virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) { @@ -76,6 +89,8 @@ class SocketIOclient : protected WebSocketsClient { } } + void initClient(void); + // Handeling events from websocket layer virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) { handleCbEvent(type, payload, length); diff --git a/src/arduinoWebSockets/WebSockets.cpp b/src/arduinoWebSockets/WebSockets.cpp index 6132d28..ef8224c 100644 --- a/src/arduinoWebSockets/WebSockets.cpp +++ b/src/arduinoWebSockets/WebSockets.cpp @@ -39,7 +39,14 @@ extern "C" { #ifdef ESP8266 #include #elif defined(ESP32) +#include + +#if ESP_IDF_VERSION_MAJOR >= 4 +#include +#else #include +#endif + #else extern "C" { @@ -494,7 +501,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t reasonCode = payload[0] << 8 | payload[1]; } #endif - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode); + DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d\n", client->num, reasonCode); if(header->payloadLen > 2) { DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2)); } else { @@ -503,6 +510,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t clientDisconnect(client, 1000); } break; default: + DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] got unknown opcode: %d\n", client->num, header->opCode); clientDisconnect(client, 1002); break; } @@ -623,7 +631,7 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait } if(!client->tcp->available()) { - WEBSOCKETS_YIELD(); + WEBSOCKETS_YIELD_MORE(); continue; } @@ -636,7 +644,9 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait } else { //DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n); } - WEBSOCKETS_YIELD(); + if(n > 0) { + WEBSOCKETS_YIELD(); + } } if(cb) { cb(client, true); @@ -686,9 +696,11 @@ size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) { total += len; //DEBUG_WEBSOCKETS("write %d left %d!\n", len, n); } else { - //DEBUG_WEBSOCKETS("write %d failed left %d!\n", len, n); + DEBUG_WEBSOCKETS("WS write %d failed left %d!\n", len, n); + } + if(n > 0) { + WEBSOCKETS_YIELD(); } - WEBSOCKETS_YIELD(); } WEBSOCKETS_YIELD(); return total; diff --git a/src/arduinoWebSockets/WebSockets.h b/src/arduinoWebSockets/WebSockets.h index 08514af..4c7e1f4 100644 --- a/src/arduinoWebSockets/WebSockets.h +++ b/src/arduinoWebSockets/WebSockets.h @@ -42,12 +42,18 @@ #include #endif +#include "WebSocketsVersion.h" + #if DEBUG_WS #define DEBUG_ESP_PORT Serial #endif /* DEBUG */ #ifndef NODEBUG_WEBSOCKETS #ifdef DEBUG_ESP_PORT -#define DEBUG_WEBSOCKETS(...) DEBUG_ESP_PORT.printf(__VA_ARGS__) +#define DEBUG_WEBSOCKETS(...) \ + { \ + DEBUG_ESP_PORT.printf(__VA_ARGS__); \ + DEBUG_ESP_PORT.flush(); \ + } #else //#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ ) #endif @@ -55,8 +61,10 @@ #ifndef DEBUG_WEBSOCKETS #define DEBUG_WEBSOCKETS(...) +#ifndef NODEBUG_WEBSOCKETS #define NODEBUG_WEBSOCKETS #endif +#endif #if defined(ESP8266) || defined(ESP32) @@ -68,8 +76,10 @@ #if defined(ESP8266) #define WEBSOCKETS_YIELD() delay(0) +#define WEBSOCKETS_YIELD_MORE() delay(1) #elif defined(ESP32) #define WEBSOCKETS_YIELD() yield() +#define WEBSOCKETS_YIELD_MORE() delay(1) #endif #elif defined(STM32_DEVICE) @@ -78,7 +88,7 @@ #define WEBSOCKETS_USE_BIG_MEM #define GET_FREE_HEAP System.freeMemory() #define WEBSOCKETS_YIELD() - +#define WEBSOCKETS_YIELD_MORE() #else //atmega328p has only 2KB ram! @@ -86,7 +96,7 @@ // moves all Header strings to Flash #define WEBSOCKETS_SAVE_RAM #define WEBSOCKETS_YIELD() - +#define WEBSOCKETS_YIELD_MORE() #endif #define WEBSOCKETS_TCP_TIMEOUT (5000) @@ -129,6 +139,7 @@ #elif defined(ESP32) #include #include +#define SSL_AXTLS #elif defined(ESP31B) #include #else @@ -148,6 +159,11 @@ #ifdef ESP8266 #include +#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h) +#define SSL_BARESSL +#else +#define SSL_AXTLS +#endif #else #include #endif @@ -177,6 +193,7 @@ #include #include +#define SSL_AXTLS #define WEBSOCKETS_NETWORK_CLASS WiFiClient #define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure #define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer @@ -205,6 +222,7 @@ typedef enum { WSC_NOT_CONNECTED, WSC_HEADER, + WSC_BODY, WSC_CONNECTED } WSclientsStatus_t; @@ -248,34 +266,44 @@ typedef struct { } WSMessageHeader_t; typedef struct { - uint8_t num; ///< connection number + void init(uint8_t num, + uint32_t pingInterval, + uint32_t pongTimeout, + uint8_t disconnectTimeoutCount) { + this->num = num; + this->pingInterval = pingInterval; + this->pongTimeout = pongTimeout; + this->disconnectTimeoutCount = disconnectTimeoutCount; + } + + uint8_t num = 0; ///< connection number - WSclientsStatus_t status; + WSclientsStatus_t status = WSC_NOT_CONNECTED; - WEBSOCKETS_NETWORK_CLASS * tcp; + WEBSOCKETS_NETWORK_CLASS * tcp = nullptr; - bool isSocketIO; ///< client for socket.io server + bool isSocketIO = false; ///< client for socket.io server #if defined(HAS_SSL) - bool isSSL; ///< run in ssl mode + bool isSSL = false; ///< run in ssl mode WEBSOCKETS_NETWORK_SSL_CLASS * ssl; #endif - String cUrl; ///< http url - uint16_t cCode; ///< http code + String cUrl; ///< http url + uint16_t cCode = 0; ///< http code - bool cIsClient = false; ///< will be used for masking - bool cIsUpgrade; ///< Connection == Upgrade - bool cIsWebsocket; ///< Upgrade == websocket + bool cIsClient = false; ///< will be used for masking + bool cIsUpgrade = false; ///< Connection == Upgrade + bool cIsWebsocket = false; ///< Upgrade == websocket - String cSessionId; ///< client Set-Cookie (session id) - String cKey; ///< client Sec-WebSocket-Key - String cAccept; ///< client Sec-WebSocket-Accept - String cProtocol; ///< client Sec-WebSocket-Protocol - String cExtensions; ///< client Sec-WebSocket-Extensions - uint16_t cVersion; ///< client Sec-WebSocket-Version + String cSessionId; ///< client Set-Cookie (session id) + String cKey; ///< client Sec-WebSocket-Key + String cAccept; ///< client Sec-WebSocket-Accept + String cProtocol; ///< client Sec-WebSocket-Protocol + String cExtensions; ///< client Sec-WebSocket-Extensions + uint16_t cVersion = 0; ///< client Sec-WebSocket-Version - uint8_t cWsRXsize; ///< State of the RX + uint8_t cWsRXsize = 0; ///< State of the RX uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer WSMessageHeader_t cWsHeaderDecode; @@ -284,15 +312,15 @@ typedef struct { String extraHeaders; - bool cHttpHeadersValid; ///< non-websocket http header validity indicator - size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count + bool cHttpHeadersValid = false; ///< non-websocket http header validity indicator + size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count - bool pongReceived; - uint32_t pingInterval; // how often ping will be sent, 0 means "heartbeat is not active" - uint32_t lastPing; // millis when last pong has been received - uint32_t pongTimeout; // interval in millis after which pong is considered to timeout - uint8_t disconnectTimeoutCount; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect" - uint8_t pongTimeoutCount; // current pong timeout count + bool pongReceived = false; + uint32_t pingInterval = 0; // how often ping will be sent, 0 means "heartbeat is not active" + uint32_t lastPing = 0; // millis when last pong has been received + uint32_t pongTimeout = 0; // interval in millis after which pong is considered to timeout + uint8_t disconnectTimeoutCount = 0; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect" + uint8_t pongTimeoutCount = 0; // current pong timeout count #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) String cHttpLine; ///< HTTP header lines diff --git a/src/arduinoWebSockets/WebSockets4WebServer.h b/src/arduinoWebSockets/WebSockets4WebServer.h new file mode 100644 index 0000000..ba2b020 --- /dev/null +++ b/src/arduinoWebSockets/WebSockets4WebServer.h @@ -0,0 +1,80 @@ +/** + * @file WebSocketsServer.cpp + * @date 28.10.2020 + * @author Markus Sattler & esp8266/arduino community + * + * Copyright (c) 2020 Markus Sattler. All rights reserved. + * This file is part of the WebSockets for Arduino. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __WEBSOCKETS4WEBSERVER_H +#define __WEBSOCKETS4WEBSERVER_H + +#include +#include + +#if WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK + +class WebSockets4WebServer : public WebSocketsServerCore { + public: + WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino") + : WebSocketsServerCore(origin, protocol) { + begin(); + } + + ESP8266WebServer::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) { + onEvent(event); + + return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, ESP8266WebServer::ContentTypeFunction contentType) { + (void)contentType; + + if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) { + return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE; + } + + // allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients()) + WEBSOCKETS_NETWORK_CLASS * newTcpClient = new WEBSOCKETS_NETWORK_CLASS(*tcpClient); + + // Then initialize a new WSclient_t (like in WebSocketsServer::handleNewClient()) + WSclient_t * client = handleNewClient(newTcpClient); + + if(client) { + // give "GET " + String headerLine; + headerLine.reserve(url.length() + 5); + headerLine = "GET "; + headerLine += url; + handleHeader(client, &headerLine); + } + + // tell webserver to not close but forget about this client + return ESP8266WebServer::CLIENT_IS_GIVEN; + }; + } +}; +#else // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK + +#ifndef WEBSERVER_HAS_HOOK +#error Your current Framework / Arduino core version does not support Webserver Hook Functions +#else +#error Your Hardware Platform does not support Webserver Hook Functions +#endif + +#endif // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK + +#endif // __WEBSOCKETS4WEBSERVER_H diff --git a/src/arduinoWebSockets/WebSocketsClient.cpp b/src/arduinoWebSockets/WebSocketsClient.cpp index ae30322..6b18d7b 100644 --- a/src/arduinoWebSockets/WebSocketsClient.cpp +++ b/src/arduinoWebSockets/WebSocketsClient.cpp @@ -31,6 +31,8 @@ WebSocketsClient::WebSocketsClient() { _client.cIsClient = true; _client.extraHeaders = WEBSOCKETS_STRING("Origin: file://"); _reconnectInterval = 500; + _port = 0; + _host = ""; } WebSocketsClient::~WebSocketsClient() { @@ -44,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 @@ -83,6 +85,9 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url, #endif _lastConnectionFail = 0; + _lastHeaderSent = 0; + + DEBUG_WEBSOCKETS("[WS-Client] Websocket Version: " WEBSOCKETS_VERSION "\n"); } void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) { @@ -94,6 +99,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 +114,39 @@ 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, BearSSL::X509List * CA_cert, const char * protocol) { + begin(host, port, url, protocol); + _client.isSSL = true; + _fingerprint = SSL_FINGERPRINT_NULL; + _CA_cert = CA_cert; +} + +void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) { + beginSslWithCA(host, port, url, new BearSSL::X509List(CA_cert), protocol); +} + +void WebSocketsClient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) { + _client_cert = clientCert; + _client_key = clientPrivateKey; +} + +void WebSocketsClient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) { + setSSLClientCertKey(new BearSSL::X509List(clientCert), new BearSSL::PrivateKey(clientPrivateKey)); +} + +#endif // SSL_AXTLS +#endif // HAS_SSL void WebSocketsClient::beginSocketIO(const char * host, uint16_t port, const char * url, const char * protocol) { begin(host, port, url, protocol); @@ -127,27 +162,45 @@ 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) { beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str()); } -void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) { +#if defined(SSL_BARESSL) +void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) { begin(host, port, url, protocol); _client.isSocketIO = true; _client.isSSL = true; - _fingerprint = ""; + _fingerprint = SSL_FINGERPRINT_NULL; _CA_cert = CA_cert; } #endif +void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) { + begin(host, port, url, protocol); + _client.isSocketIO = true; + _client.isSSL = true; + _fingerprint = SSL_FINGERPRINT_NULL; +#if defined(SSL_BARESSL) + _CA_cert = new BearSSL::X509List(CA_cert); +#else + _CA_cert = CA_cert; +#endif +} + +#endif + #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) /** * called in arduino loop */ void WebSocketsClient::loop(void) { + if(_port == 0) { + return; + } WEBSOCKETS_YIELD(); if(!clientIsConnected(&_client)) { // do not flood the server @@ -164,22 +217,31 @@ void WebSocketsClient::loop(void) { _client.tcp = NULL; } _client.ssl = new WEBSOCKETS_NETWORK_SSL_CLASS(); - /** Added ourselves */ - // Bug Fix - // Patch the Library to allow connection without - // Certificate Origin Confirmation -#if defined(ESP8266) - _client.ssl->setInsecure(); -#endif _client.tcp = _client.ssl; if(_CA_cert) { DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate"); #if defined(ESP32) _client.ssl->setCACert(_CA_cert); -#elif defined(ESP8266) +#elif defined(ESP8266) && defined(SSL_AXTLS) _client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1); +#elif defined(ESP8266) && defined(SSL_BARESSL) + _client.ssl->setTrustAnchors(_CA_cert); #else #error setCACert not implemented +#endif +#if defined(ESP32) + } else if(!SSL_FINGERPRINT_IS_SET) { + Serial.println("SET INSECURE."); + _client.ssl->setInsecure(); +#elif defined(SSL_BARESSL) + } else if(SSL_FINGERPRINT_IS_SET) { + _client.ssl->setFingerprint(_fingerprint); + } else { + _client.ssl->setInsecure(); + } + if(_client_cert && _client_key) { + _client.ssl->setClientRSACert(_client_cert, _client_key); + DEBUG_WEBSOCKETS("[WS-Client] setting client certificate and key"); #endif } } else { @@ -449,7 +511,8 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) { client->cIsWebsocket = false; client->cSessionId = ""; - client->status = WSC_NOT_CONNECTED; + client->status = WSC_NOT_CONNECTED; + _lastConnectionFail = millis(); DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n"); if(event) { @@ -492,6 +555,13 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) { * Handel incomming data from Client */ void WebSocketsClient::handleClientData(void) { + if((_client.status == WSC_HEADER || _client.status == WSC_BODY) && _lastHeaderSent + WEBSOCKETS_TCP_TIMEOUT < millis()) { + DEBUG_WEBSOCKETS("[WS-Client][handleClientData] header response timeout.. disconnecting!\n"); + clientDisconnect(&_client); + WEBSOCKETS_YIELD(); + return; + } + int len = _client.tcp->available(); if(len > 0) { switch(_client.status) { @@ -499,6 +569,12 @@ void WebSocketsClient::handleClientData(void) { String headerLine = _client.tcp->readStringUntil('\n'); handleHeader(&_client, &headerLine); } break; + case WSC_BODY: { + char buf[256] = { 0 }; + _client.tcp->readBytes(&buf[0], std::min((size_t)len, sizeof(buf))); + String bodyLine = buf; + handleHeader(&_client, &bodyLine); + } break; case WSC_CONNECTED: WebSockets::handleWebsocket(&_client); break; @@ -574,7 +650,7 @@ void WebSocketsClient::sendHeader(WSclient_t * client) { } // add extra headers; by default this includes "Origin: file://" - if(client->extraHeaders) { + if(client->extraHeaders.length() > 0) { handshake += client->extraHeaders + NEW_LINE; } @@ -600,6 +676,7 @@ void WebSocketsClient::sendHeader(WSclient_t * client) { #endif DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start)); + _lastHeaderSent = millis(); } /** @@ -609,6 +686,22 @@ void WebSocketsClient::sendHeader(WSclient_t * client) { void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { headerLine->trim(); // remove \r + // this code handels the http body for Socket.IO V3 requests + if(headerLine->length() > 0 && client->isSocketIO && client->status == WSC_BODY && client->cSessionId.length() == 0) { + DEBUG_WEBSOCKETS("[WS-Client][handleHeader] socket.io json: %s\n", headerLine->c_str()); + String sid_begin = WEBSOCKETS_STRING("\"sid\":\""); + if(headerLine->indexOf(sid_begin) > -1) { + int start = headerLine->indexOf(sid_begin) + sid_begin.length(); + int end = headerLine->indexOf('"', start); + client->cSessionId = headerLine->substring(start, end); + DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str()); + + // Trigger websocket connection code path + *headerLine = ""; + } + } + + // headle HTTP header if(headerLine->length() > 0) { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str()); @@ -642,7 +735,7 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) { client->cVersion = headerValue.toInt(); } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) { - if(headerValue.indexOf(WEBSOCKETS_STRING("HttpOnly")) > -1) { + if(headerValue.indexOf(';') > -1) { client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";")); } else { client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1); @@ -673,6 +766,14 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str()); + if(client->isSocketIO && client->cSessionId.length() == 0 && clientIsConnected(client)) { + DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still missing cSessionId try socket.io V3\n"); + client->status = WSC_BODY; + return; + } else { + client->status = WSC_HEADER; + } + bool ok = (client->cIsUpgrade && client->cIsWebsocket); if(ok) { @@ -713,15 +814,20 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { headerDone(client); runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length()); - } else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) { - if(_client.tcp->available()) { - // read not needed data - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available()); - while(_client.tcp->available() > 0) { - _client.tcp->read(); +#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) + } else if(client->isSocketIO) { + if(client->cSessionId.length() > 0) { + DEBUG_WEBSOCKETS("[WS-Client][handleHeader] found cSessionId\n"); + if(clientIsConnected(client) && _client.tcp->available()) { + // read not needed data + DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available()); + while(_client.tcp->available() > 0) { + _client.tcp->read(); + } } + sendHeader(client); } - sendHeader(client); +#endif } else { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n"); _lastConnectionFail = millis(); @@ -762,14 +868,18 @@ void WebSocketsClient::connectedCb() { #endif #if defined(HAS_SSL) - if(_client.isSSL && _fingerprint.length()) { +#if defined(SSL_AXTLS) || defined(ESP32) + if(_client.isSSL && SSL_FINGERPRINT_IS_SET) { if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) { DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n"); WebSockets::clientDisconnect(&_client, 1000); return; } +#else + if(_client.isSSL && SSL_FINGERPRINT_IS_SET) { +#endif } else if(_client.isSSL && !_CA_cert) { -#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h) +#if defined(SSL_BARESSL) _client.ssl->setInsecure(); #endif } @@ -839,6 +949,9 @@ void WebSocketsClient::handleHBPing() { if(sendPing()) { _client.lastPing = millis(); _client.pongReceived = false; + } else { + DEBUG_WEBSOCKETS("[WS-Client] sending HB ping failed\n"); + WebSockets::clientDisconnect(&_client, 1000); } } } diff --git a/src/arduinoWebSockets/WebSocketsClient.h b/src/arduinoWebSockets/WebSocketsClient.h index ed3f630..efa7631 100644 --- a/src/arduinoWebSockets/WebSocketsClient.h +++ b/src/arduinoWebSockets/WebSocketsClient.h @@ -43,8 +43,15 @@ 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"); + void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL); + void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL); +#endif void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino"); #endif @@ -54,7 +61,11 @@ class WebSocketsClient : protected WebSockets { #if defined(HAS_SSL) void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); + void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino"); +#if defined(SSL_BARESSL) + void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino"); +#endif #endif #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) @@ -91,15 +102,27 @@ 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_IS_SET (_fingerprint.length()) +#define SSL_FINGERPRINT_NULL "" +#else + const uint8_t * _fingerprint; + BearSSL::X509List * _CA_cert; + BearSSL::X509List * _client_cert; + BearSSL::PrivateKey * _client_key; +#define SSL_FINGERPRINT_IS_SET (_fingerprint != NULL) +#define SSL_FINGERPRINT_NULL NULL +#endif + #endif WSclient_t _client; @@ -107,6 +130,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); diff --git a/src/arduinoWebSockets/WebSocketsServer.cpp b/src/arduinoWebSockets/WebSocketsServer.cpp index a682ec9..495cb55 100644 --- a/src/arduinoWebSockets/WebSocketsServer.cpp +++ b/src/arduinoWebSockets/WebSocketsServer.cpp @@ -25,8 +25,7 @@ #include "WebSockets.h" #include "WebSocketsServer.h" -WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol) { - _port = port; +WebSocketsServerCore::WebSocketsServerCore(const String & origin, const String & protocol) { _origin = origin; _protocol = protocol; _runnning = false; @@ -34,25 +33,28 @@ WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol _pongTimeout = 0; _disconnectTimeoutCount = 0; + _cbEvent = NULL; + + _httpHeaderValidationFunc = NULL; + _mandatoryHttpHeaders = NULL; + _mandatoryHttpHeaderCount = 0; +} + +WebSocketsServer::WebSocketsServer(uint16_t port, const String & origin, const String & protocol) + : WebSocketsServerCore(origin, protocol) { + _port = 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)); + ((WebSocketsServerCore *)s)->newClient(new AsyncTCPbuffer(c)); }, this); #endif - - _cbEvent = NULL; - - _httpHeaderValidationFunc = NULL; - _mandatoryHttpHeaders = NULL; - _mandatoryHttpHeaderCount = 0; - - memset(&_clients[0], 0x00, (sizeof(WSclient_t) * WEBSOCKETS_SERVER_CLIENT_MAX)); } -WebSocketsServer::~WebSocketsServer() { +WebSocketsServerCore::~WebSocketsServerCore() { // disconnect all clients close(); @@ -62,42 +64,20 @@ WebSocketsServer::~WebSocketsServer() { _mandatoryHttpHeaderCount = 0; } +WebSocketsServer::~WebSocketsServer() { +} + /** * called to initialize the Websocket server */ -void WebSocketsServer::begin(void) { - WSclient_t * client; - - // init client storage - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - - client->num = i; - client->status = WSC_NOT_CONNECTED; - client->tcp = NULL; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - client->isSSL = false; - client->ssl = NULL; -#endif - client->cUrl = ""; - client->cCode = 0; - client->cKey = ""; - client->cProtocol = ""; - client->cVersion = 0; - client->cIsUpgrade = false; - client->cIsWebsocket = false; - - client->base64Authorization = ""; - - client->cWsRXsize = 0; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->cHttpLine = ""; -#endif - - client->pingInterval = _pingInterval; - client->pongTimeout = _pongTimeout; - client->disconnectTimeoutCount = _disconnectTimeoutCount; +void WebSocketsServerCore::begin(void) { + // adjust clients storage: + // _clients[i]'s constructor are already called, + // all its members are initialized to their default value, + // except the ones explicitly detailed in WSclient_t() constructor. + // Then we need to initialize some members to non-trivial values: + for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { + _clients[i].init(i, _pingInterval, _pongTimeout, _disconnectTimeoutCount); } #ifdef ESP8266 @@ -111,43 +91,26 @@ void WebSocketsServer::begin(void) { #endif _runnning = true; - _server->begin(); - DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n"); + DEBUG_WEBSOCKETS("[WS-Server] Websocket Version: " WEBSOCKETS_VERSION "\n"); } -void WebSocketsServer::close(void) { +void WebSocketsServerCore::close(void) { _runnning = false; disconnect(); -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - _server->close(); -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - _server->end(); -#else - // TODO how to close server? -#endif -} - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) -/** - * called in arduino loop - */ -void WebSocketsServer::loop(void) { - if(_runnning) { - WEBSOCKETS_YIELD(); - handleNewClients(); - WEBSOCKETS_YIELD(); - handleClientData(); + // restore _clients[] to their initial state + // before next call to ::begin() + for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { + _clients[i] = WSclient_t(); } } -#endif /** * set callback function * @param cbEvent WebSocketServerEvent */ -void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) { +void WebSocketsServerCore::onEvent(WebSocketServerEvent cbEvent) { _cbEvent = cbEvent; } @@ -157,7 +120,7 @@ void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) { * @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( +void WebSocketsServerCore::onValidateHttpHeader( WebSocketServerHttpHeaderValFunc validationFunc, const char * mandatoryHttpHeaders[], size_t mandatoryHttpHeaderCount) { @@ -182,7 +145,7 @@ void WebSocketsServer::onValidateHttpHeader( * @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) { +bool WebSocketsServerCore::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { return false; } @@ -196,19 +159,19 @@ bool WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bo return false; } -bool WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) { +bool WebSocketsServerCore::sendTXT(uint8_t num, const uint8_t * payload, size_t length) { return sendTXT(num, (uint8_t *)payload, length); } -bool WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) { +bool WebSocketsServerCore::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) { return sendTXT(num, (uint8_t *)payload, length, headerToPayload); } -bool WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) { +bool WebSocketsServerCore::sendTXT(uint8_t num, const char * payload, size_t length) { return sendTXT(num, (uint8_t *)payload, length); } -bool WebSocketsServer::sendTXT(uint8_t num, String & payload) { +bool WebSocketsServerCore::sendTXT(uint8_t num, String & payload) { return sendTXT(num, (uint8_t *)payload.c_str(), payload.length()); } @@ -219,7 +182,7 @@ bool WebSocketsServer::sendTXT(uint8_t num, String & payload) { * @param headerToPayload bool (see sendFrame for more details) * @return true if ok */ -bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) { +bool WebSocketsServerCore::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) { WSclient_t * client; bool ret = true; if(length == 0) { @@ -238,19 +201,19 @@ bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool heade return ret; } -bool WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) { +bool WebSocketsServerCore::broadcastTXT(const uint8_t * payload, size_t length) { return broadcastTXT((uint8_t *)payload, length); } -bool WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) { +bool WebSocketsServerCore::broadcastTXT(char * payload, size_t length, bool headerToPayload) { return broadcastTXT((uint8_t *)payload, length, headerToPayload); } -bool WebSocketsServer::broadcastTXT(const char * payload, size_t length) { +bool WebSocketsServerCore::broadcastTXT(const char * payload, size_t length) { return broadcastTXT((uint8_t *)payload, length); } -bool WebSocketsServer::broadcastTXT(String & payload) { +bool WebSocketsServerCore::broadcastTXT(String & payload) { return broadcastTXT((uint8_t *)payload.c_str(), payload.length()); } @@ -262,7 +225,7 @@ bool WebSocketsServer::broadcastTXT(String & payload) { * @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) { +bool WebSocketsServerCore::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { return false; } @@ -273,7 +236,7 @@ bool WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bo return false; } -bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) { +bool WebSocketsServerCore::sendBIN(uint8_t num, const uint8_t * payload, size_t length) { return sendBIN(num, (uint8_t *)payload, length); } @@ -284,7 +247,7 @@ bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t leng * @param headerToPayload bool (see sendFrame for more details) * @return true if ok */ -bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) { +bool WebSocketsServerCore::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) { WSclient_t * client; bool ret = true; for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { @@ -299,7 +262,7 @@ bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool heade return ret; } -bool WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) { +bool WebSocketsServerCore::broadcastBIN(const uint8_t * payload, size_t length) { return broadcastBIN((uint8_t *)payload, length); } @@ -310,7 +273,7 @@ bool WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) { * @param length size_t * @return true if ping is send out */ -bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) { +bool WebSocketsServerCore::sendPing(uint8_t num, uint8_t * payload, size_t length) { if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { return false; } @@ -321,7 +284,7 @@ bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) { return false; } -bool WebSocketsServer::sendPing(uint8_t num, String & payload) { +bool WebSocketsServerCore::sendPing(uint8_t num, String & payload) { return sendPing(num, (uint8_t *)payload.c_str(), payload.length()); } @@ -331,7 +294,7 @@ bool WebSocketsServer::sendPing(uint8_t num, String & payload) { * @param length size_t * @return true if ping is send out */ -bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) { +bool WebSocketsServerCore::broadcastPing(uint8_t * payload, size_t length) { WSclient_t * client; bool ret = true; for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { @@ -346,14 +309,14 @@ bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) { return ret; } -bool WebSocketsServer::broadcastPing(String & payload) { +bool WebSocketsServerCore::broadcastPing(String & payload) { return broadcastPing((uint8_t *)payload.c_str(), payload.length()); } /** * disconnect all clients */ -void WebSocketsServer::disconnect(void) { +void WebSocketsServerCore::disconnect(void) { WSclient_t * client; for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { client = &_clients[i]; @@ -367,7 +330,7 @@ void WebSocketsServer::disconnect(void) { * disconnect one client * @param num uint8_t client id */ -void WebSocketsServer::disconnect(uint8_t num) { +void WebSocketsServerCore::disconnect(uint8_t num) { if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { return; } @@ -382,7 +345,7 @@ void WebSocketsServer::disconnect(uint8_t num) { * @param user const char * * @param password const char * */ -void WebSocketsServer::setAuthorization(const char * user, const char * password) { +void WebSocketsServerCore::setAuthorization(const char * user, const char * password) { if(user && password) { String auth = user; auth += ":"; @@ -395,7 +358,7 @@ void WebSocketsServer::setAuthorization(const char * user, const char * password * set the Authorizatio for the http request * @param auth const char * base64 */ -void WebSocketsServer::setAuthorization(const char * auth) { +void WebSocketsServerCore::setAuthorization(const char * auth) { if(auth) { _base64Authorization = auth; } @@ -405,7 +368,7 @@ void WebSocketsServer::setAuthorization(const char * auth) { * count the connected clients (optional ping them) * @param ping bool ping the connected clients */ -int WebSocketsServer::connectedClients(bool ping) { +int WebSocketsServerCore::connectedClients(bool ping) { WSclient_t * client; int count = 0; for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { @@ -419,13 +382,25 @@ int WebSocketsServer::connectedClients(bool ping) { return count; } +/** + * see if one client is connected + * @param num uint8_t client id + */ +bool WebSocketsServerCore::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 * @param num uint8_t client id * @return IPAddress */ -IPAddress WebSocketsServer::remoteIP(uint8_t num) { +IPAddress WebSocketsServerCore::remoteIP(uint8_t num) { if(num < WEBSOCKETS_SERVER_CLIENT_MAX) { WSclient_t * client = &_clients[num]; if(clientIsConnected(client)) { @@ -445,7 +420,7 @@ IPAddress WebSocketsServer::remoteIP(uint8_t num) { * handle new client connection * @param client */ -bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) { +WSclient_t * WebSocketsServerCore::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++) { @@ -474,7 +449,7 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) { #endif #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->tcp->onDisconnect(std::bind([](WebSocketsServer * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool { + client->tcp->onDisconnect(std::bind([](WebSocketsServerCore * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool { DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num); AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp; @@ -486,7 +461,7 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) { }, this, std::placeholders::_1, client)); - client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine))); + client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine))); #endif client->pingInterval = _pingInterval; @@ -495,11 +470,11 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) { client->lastPing = millis(); client->pongReceived = false; - return true; + return client; break; } } - return false; + return nullptr; } /** @@ -509,7 +484,7 @@ bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) { * @param payload uint8_t * * @param length size_t */ -void WebSocketsServer::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) { +void WebSocketsServerCore::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) { WStype_t type = WStype_ERROR; switch(opcode) { @@ -536,11 +511,32 @@ void WebSocketsServer::messageReceived(WSclient_t * client, WSopcode_t opcode, u runCbEvent(client->num, type, payload, length); } +/** + * Discard a native client + * @param client WSclient_t * ptr to the client struct contaning the native client "->tcp" + */ +void WebSocketsServerCore::dropNativeClient(WSclient_t * client) { + if(client->tcp) { + if(client->tcp->connected()) { +#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32) + client->tcp->flush(); +#endif + client->tcp->stop(); + } +#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) + client->status = WSC_NOT_CONNECTED; +#else + delete client->tcp; +#endif + client->tcp = NULL; + } +} + /** * Disconnect an client * @param client WSclient_t * ptr to the client struct */ -void WebSocketsServer::clientDisconnect(WSclient_t * client) { +void WebSocketsServerCore::clientDisconnect(WSclient_t * client) { #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) if(client->isSSL && client->ssl) { if(client->ssl->connected()) { @@ -553,20 +549,7 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) { } #endif - if(client->tcp) { - if(client->tcp->connected()) { -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - client->tcp->flush(); -#endif - client->tcp->stop(); - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->status = WSC_NOT_CONNECTED; -#else - delete client->tcp; -#endif - client->tcp = NULL; - } + dropNativeClient(client); client->cUrl = ""; client->cKey = ""; @@ -593,7 +576,7 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) { * @param client WSclient_t * ptr to the client struct * @return true = connected */ -bool WebSocketsServer::clientIsConnected(WSclient_t * client) { +bool WebSocketsServerCore::clientIsConnected(WSclient_t * client) { if(!client->tcp) { return false; } @@ -620,6 +603,30 @@ bool WebSocketsServer::clientIsConnected(WSclient_t * client) { return false; } #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) +/** + * Handle incoming Connection Request + */ +WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient) { + WSclient_t * client = newClient(tcpClient); + + if(!client) { + // 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"); +#endif + dropNativeClient(client); + } + + WEBSOCKETS_YIELD(); + + return client; +} + /** * Handle incoming Connection Request */ @@ -627,36 +634,16 @@ void WebSocketsServer::handleNewClients(void) { #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) while(_server->hasClient()) { #endif - bool ok = false; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) // store new connection WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available()); -#else - WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available()); -#endif - if(!tcpClient) { DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); return; } - ok = newClient(tcpClient); - - 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"); -#endif - tcpClient->stop(); - } + handleNewClient(tcpClient); - WEBSOCKETS_YIELD(); #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) } #endif @@ -665,7 +652,7 @@ void WebSocketsServer::handleNewClients(void) { /** * Handel incomming data from Client */ -void WebSocketsServer::handleClientData(void) { +void WebSocketsServerCore::handleClientData(void) { WSclient_t * client; for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { client = &_clients[i]; @@ -682,6 +669,7 @@ void WebSocketsServer::handleClientData(void) { WebSockets::handleWebsocket(client); break; default: + DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] unknown client status %d\n", client->num, client->status); WebSockets::clientDisconnect(client, 1002); break; } @@ -699,7 +687,7 @@ void WebSocketsServer::handleClientData(void) { * 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) { +bool WebSocketsServerCore::hasMandatoryHeader(String headerName) { for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) { if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName)) return true; @@ -712,7 +700,7 @@ bool WebSocketsServer::hasMandatoryHeader(String headerName) { * @param client WSclient_t * ///< pointer to the client struct * @param headerLine String ///< the header being read / processed */ -void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { +void WebSocketsServerCore::handleHeader(WSclient_t * client, String * headerLine) { static const char * NEW_LINE = "\r\n"; headerLine->trim(); // remove \r @@ -771,7 +759,7 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { (*headerLine) = ""; #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine))); + client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine))); #endif } else { DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num); @@ -868,7 +856,7 @@ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { /** * send heartbeat ping to server in set intervals */ -void WebSocketsServer::handleHBPing(WSclient_t * client) { +void WebSocketsServerCore::handleHBPing(WSclient_t * client) { if(client->pingInterval == 0) return; uint32_t pi = millis() - client->lastPing; @@ -887,7 +875,7 @@ void WebSocketsServer::handleHBPing(WSclient_t * client) { * @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) { +void WebSocketsServerCore::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) { _pingInterval = pingInterval; _pongTimeout = pongTimeout; _disconnectTimeoutCount = disconnectTimeoutCount; @@ -902,7 +890,7 @@ void WebSocketsServer::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeo /** * disable ping/pong heartbeat process */ -void WebSocketsServer::disableHeartbeat() { +void WebSocketsServerCore::disableHeartbeat() { _pingInterval = 0; WSclient_t * client; @@ -910,4 +898,51 @@ void WebSocketsServer::disableHeartbeat() { client = &_clients[i]; client->pingInterval = 0; } -} \ No newline at end of file +} + +//////////////////// +// WebSocketServer + +/** + * called to initialize the Websocket server + */ +void WebSocketsServer::begin(void) { + WebSocketsServerCore::begin(); + _server->begin(); + + DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n"); +} + +void WebSocketsServer::close(void) { + WebSocketsServerCore::close(); +#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + _server->close(); +#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) + _server->end(); +#else + // TODO how to close server? +#endif +} + +#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) +/** + * called in arduino loop + */ +void WebSocketsServerCore::loop(void) { + if(_runnning) { + WEBSOCKETS_YIELD(); + handleClientData(); + } +} + +/** + * called in arduino loop + */ +void WebSocketsServer::loop(void) { + if(_runnning) { + WEBSOCKETS_YIELD(); + handleNewClients(); + WebSocketsServerCore::loop(); + } +} +#endif diff --git a/src/arduinoWebSockets/WebSocketsServer.h b/src/arduinoWebSockets/WebSocketsServer.h index 19c934d..5bdcd04 100644 --- a/src/arduinoWebSockets/WebSocketsServer.h +++ b/src/arduinoWebSockets/WebSocketsServer.h @@ -31,8 +31,14 @@ #define WEBSOCKETS_SERVER_CLIENT_MAX (5) #endif -class WebSocketsServer : protected WebSockets { +class WebSocketsServerCore : protected WebSockets { public: + WebSocketsServerCore(const String & origin = "", const String & protocol = "arduino"); + virtual ~WebSocketsServerCore(void); + + void begin(void); + void close(void); + #ifdef __AVR__ typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length); typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue); @@ -41,19 +47,6 @@ class WebSocketsServer : protected WebSockets { typedef std::function WebSocketServerHttpHeaderValFunc; #endif - WebSocketsServer(uint16_t port, String origin = "", String protocol = "arduino"); - virtual ~WebSocketsServer(void); - - void begin(void); - void close(void); - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - void loop(void); -#else - // Async interface not need a loop call - void loop(void) __attribute__((deprecated)) {} -#endif - void onEvent(WebSocketServerEvent cbEvent); void onValidateHttpHeader( WebSocketServerHttpHeaderValFunc validationFunc, @@ -92,6 +85,8 @@ 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(); @@ -99,16 +94,19 @@ class WebSocketsServer : protected WebSockets { IPAddress remoteIP(uint8_t num); #endif +#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) + void loop(void); // handle client data only +#endif + + WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient); + protected: - uint16_t _port; String _origin; String _protocol; String _base64Authorization; ///< Base64 encoded Auth request String * _mandatoryHttpHeaders; size_t _mandatoryHttpHeaderCount; - WEBSOCKETS_NETWORK_SERVER_CLASS * _server; - WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX]; WebSocketServerEvent _cbEvent; @@ -120,15 +118,12 @@ class WebSocketsServer : protected WebSockets { 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); void clientDisconnect(WSclient_t * client); bool clientIsConnected(WSclient_t * client); #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - void handleNewClients(void); void handleClientData(void); #endif @@ -204,6 +199,15 @@ class WebSocketsServer : protected WebSockets { return true; } +#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) + WSclient_t * handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient); +#endif + + /** + * drop native tcp connection (client->tcp) + */ + void dropNativeClient(WSclient_t * client); + private: /* * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection @@ -212,4 +216,28 @@ class WebSocketsServer : protected WebSockets { bool hasMandatoryHeader(String headerName); }; +class WebSocketsServer : public WebSocketsServerCore { + public: + WebSocketsServer(uint16_t port, const String & origin = "", const String & protocol = "arduino"); + virtual ~WebSocketsServer(void); + + void begin(void); + void close(void); + +#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) + void loop(void); // handle incoming client and client data +#else + // Async interface not need a loop call + void loop(void) __attribute__((deprecated)) {} +#endif + + protected: +#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) + void handleNewClients(void); +#endif + + uint16_t _port; + WEBSOCKETS_NETWORK_SERVER_CLASS * _server; +}; + #endif /* WEBSOCKETSSERVER_H_ */ diff --git a/src/arduinoWebSockets/WebSocketsVersion.h b/src/arduinoWebSockets/WebSocketsVersion.h new file mode 100644 index 0000000..3e1aa0c --- /dev/null +++ b/src/arduinoWebSockets/WebSocketsVersion.h @@ -0,0 +1,36 @@ +/** + * @file WebSocketsVersion.h + * @date 09.02.2021 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the WebSockets for Arduino. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef WEBSOCKETSVERSION_H_ +#define WEBSOCKETSVERSION_H_ + +#define WEBSOCKETS_VERSION "2.3.5" + +#define WEBSOCKETS_VERSION_MAJOR 2 +#define WEBSOCKETS_VERSION_MINOR 3 +#define WEBSOCKETS_VERSION_PATCH 5 + +#define WEBSOCKETS_VERSION_INT 2003005 + +#endif /* WEBSOCKETSVERSION_H_ */ diff --git a/src/debug.h b/src/debug.h index fe97286..9e9f52f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -1,6 +1,6 @@ // Debugging macros #define DEBUG 0 -#define DEBUG_WS 0 +#define DEBUG_WS 1 #if DEBUG || DEBUG_WS #define DEBUG_PORT Serial #endif /* DEBUG || DEBUG_WS */