diff --git a/src/WebSockets.cpp b/src/WebSockets.cpp index ce4017b..28407f3 100644 --- a/src/WebSockets.cpp +++ b/src/WebSockets.cpp @@ -74,7 +74,7 @@ void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * rea */ void WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool mask, bool fin, bool headerToPayload) { - if(!client->tcp.connected()) { + if(client->tcp && !client->tcp->connected()) { DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not Connected!?\n", client->num); return; } @@ -171,14 +171,14 @@ void WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay // header has be added to payload // payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings // offset in payload is calculatetd 14 - headerSize - client->tcp.write(&payload[(14 - headerSize)], (length + headerSize)); + client->tcp->write(&payload[(14 - headerSize)], (length + headerSize)); } else { // send header - client->tcp.write(&buffer[0], headerSize); + client->tcp->write(&buffer[0], headerSize); if(payload && length > 0) { // send payload - client->tcp.write(&payload[0], length); + client->tcp->write(&payload[0], length); } } } @@ -385,7 +385,7 @@ bool WebSockets::readWait(WSclient_t * client, uint8_t *out, size_t n) { size_t len; while(n > 0) { - if(!client->tcp.connected()) { + if(client->tcp && !client->tcp->connected()) { DEBUG_WEBSOCKETS("[readWait] not connected!\n"); return false; } @@ -395,14 +395,14 @@ bool WebSockets::readWait(WSclient_t * client, uint8_t *out, size_t n) { return false; } - if(!client->tcp.available()) { + if(!client->tcp->available()) { #ifdef ESP8266 delay(0); #endif continue; } - len = client->tcp.read((uint8_t*) out, n); + len = client->tcp->read((uint8_t*) out, n); if(len) { t = millis(); out += len; diff --git a/src/WebSockets.h b/src/WebSockets.h index 44a8c6e..1b34ffc 100644 --- a/src/WebSockets.h +++ b/src/WebSockets.h @@ -27,25 +27,59 @@ #include -#ifdef ESP8266 -#include -#else -#include -#ifndef UIPETHERNET_H -#include -#include -#endif -#endif - -//#define DEBUG_WEBSOCKETS(...) Serial1.printf( __VA_ARGS__ ) +#define DEBUG_WEBSOCKETS(...) Serial1.printf( __VA_ARGS__ ) #ifndef DEBUG_WEBSOCKETS #define DEBUG_WEBSOCKETS(...) #endif +#ifdef ESP8266 #define WEBSOCKETS_MAX_DATA_SIZE (15*1024) +#else +//atmega328p has only 2KB ram! +#define WEBSOCKETS_MAX_DATA_SIZE (1024) +#endif + #define WEBSOCKETS_TCP_TIMEOUT (1500) +#define NETWORK_ESP8266 (1) +#define NETWORK_W5100 (2) +#define NETWORK_ENC28J60 (3) + + +// select Network type based +#ifdef ESP8266 +#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266 +#else +#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 +#endif + + +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + +#ifndef ESP8266 +#error "network type ESP8266 only possible on the ESP mcu!" +#endif + +#include +#define WEBSOCKETS_NETWORK_CLASS WiFiClient + +#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100) + +#include +#include +#define WEBSOCKETS_NETWORK_CLASS EthernetClient + +#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60) + +#include +#define WEBSOCKETS_NETWORK_CLASS UIPClient + +#else +#error "no network type selected!" +#endif + + typedef enum { WSC_NOT_CONNECTED, WSC_HEADER, @@ -75,15 +109,14 @@ typedef struct { uint8_t num; ///< connection number WSclientsStatus_t status; -#ifdef ESP8266 - WiFiClient tcp; -#else -#ifdef UIPETHERNET_H - UIPClient tcp; -#else - EthernetClient tcp; -#endif + + WEBSOCKETS_NETWORK_CLASS * tcp; + +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + bool isSSL; ///< run in ssl mode + WiFiClientSecure * ssl; #endif + String cUrl; ///< http url uint16_t cCode; ///< http code diff --git a/src/WebSocketsClient.cpp b/src/WebSocketsClient.cpp index 210bd6b..2848893 100644 --- a/src/WebSocketsClient.cpp +++ b/src/WebSocketsClient.cpp @@ -28,7 +28,6 @@ WebSocketsClient::WebSocketsClient() { _cbEvent = NULL; _client.num = 0; - } WebSocketsClient::~WebSocketsClient() { @@ -42,7 +41,13 @@ void WebSocketsClient::begin(const char *host, uint16_t port, const char * url) _host = host; _port = port; + _client.num = 0; _client.status = WSC_NOT_CONNECTED; + _client.tcp = NULL; +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + _client.isSSL = false; + _client.ssl = NULL; +#endif _client.cUrl = url; _client.cCode = 0; _client.cIsUpgrade = false; @@ -53,8 +58,12 @@ void WebSocketsClient::begin(const char *host, uint16_t port, const char * url) _client.cExtensions = ""; _client.cVersion = 0; +#ifdef ESP8266 + randomSeed(RANDOM_REG32); +#else // todo find better seed randomSeed(millis()); +#endif } void WebSocketsClient::begin(String host, uint16_t port, String url) { @@ -66,16 +75,44 @@ void WebSocketsClient::begin(String host, uint16_t port, String url) { */ void WebSocketsClient::loop(void) { if(!clientIsConnected(&_client)) { - if(_client.tcp.connect(_host.c_str(), _port)) { + +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + if(_client.isSSL) { + DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n"); + if(_client.ssl) { + delete _client.ssl; + _client.ssl = NULL; + _client.tcp = NULL; + } + _client.ssl = new WiFiClientSecure(); + _client.tcp = _client.ssl; + } else { + DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n"); + if(_client.tcp) { + delete _client.tcp; + _client.tcp = NULL; + } + _client.tcp = new WiFiClient(); + } +#else + _client.tcp = new WEBSOCKETS_NETWORK_CLASS(); +#endif + + if(!_client.tcp) { + DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); + return; + } + + if(_client.tcp->connect(_host.c_str(), _port)) { DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n", _host.c_str(), _port); _client.status = WSC_HEADER; // set Timeout for readBytesUntil and readStringUntil - _client.tcp.setTimeout(WEBSOCKETS_TCP_TIMEOUT); + _client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); -#ifdef ESP8266 - _client.tcp.setNoDelay(true); +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + _client.tcp->setNoDelay(true); #endif // send Header to Server @@ -190,9 +227,25 @@ void WebSocketsClient::messageRecived(WSclient_t * client, WSopcode_t opcode, ui */ void WebSocketsClient::clientDisconnect(WSclient_t * client) { +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + if(client->isSSL && client->ssl) { + if(client->ssl->connected()) { + client->ssl->flush(); + client->ssl->stop(); + } + delete client->ssl; + client->ssl = NULL; + client->tcp = NULL; + } +#endif + if(client->tcp) { - client->tcp.flush(); - client->tcp.stop(); + if(client->tcp->connected()) { + client->tcp->flush(); + client->tcp->stop(); + } + delete client->tcp; + client->tcp = NULL; } client->cCode = 0; @@ -218,7 +271,11 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) { */ bool WebSocketsClient::clientIsConnected(WSclient_t * client) { - if(client->tcp.connected()) { + if(!client->tcp) { + return false; + } + + if(client->tcp->connected()) { if(client->status != WSC_NOT_CONNECTED) { return true; } @@ -230,6 +287,12 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) { clientDisconnect(client); } } + + if(client->tcp) { + // do cleanup + clientDisconnect(client); + } + return false; } @@ -237,7 +300,7 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) { * Handel incomming data from Client */ void WebSocketsClient::handleClientData(void) { - int len = _client.tcp.available(); + int len = _client.tcp->available(); if(len > 0) { switch(_client.status) { case WSC_HEADER: @@ -289,7 +352,7 @@ void WebSocketsClient::sendHeader(WSclient_t * client) { handshake += "\r\n"; - client->tcp.write(handshake.c_str(), handshake.length()); + client->tcp->write(handshake.c_str(), handshake.length()); DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%uus).\n", (micros() - start)); @@ -301,7 +364,7 @@ void WebSocketsClient::sendHeader(WSclient_t * client) { */ void WebSocketsClient::handleHeader(WSclient_t * client) { - String headerLine = client->tcp.readStringUntil('\n'); + String headerLine = client->tcp->readStringUntil('\n'); headerLine.trim(); // remove \r if(headerLine.length() > 0) { @@ -392,7 +455,7 @@ void WebSocketsClient::handleHeader(WSclient_t * client) { } else { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n"); - client->tcp.write("This is a webSocket client!"); + client->tcp->write("This is a webSocket client!"); clientDisconnect(client); } } diff --git a/src/WebSocketsServer.cpp b/src/WebSocketsServer.cpp index f8ca998..df147d1 100644 --- a/src/WebSocketsServer.cpp +++ b/src/WebSocketsServer.cpp @@ -34,7 +34,10 @@ WebSocketsServer::WebSocketsServer(uint16_t port) { } WebSocketsServer::~WebSocketsServer() { - // todo how to close server? + // disconnect all clients + disconnect(); + + // TODO how to close server? } /** @@ -48,20 +51,31 @@ void WebSocketsServer::begin(void) { client = &_clients[i]; client->num = i; + client->status = WSC_NOT_CONNECTED; + client->tcp = NULL; +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + 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->status = WSC_NOT_CONNECTED; } - // todo find better seed +#ifdef ESP8266 + randomSeed(RANDOM_REG32); +#else + // TODO find better seed randomSeed(millis()); +#endif _server->begin(); + + DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n"); } /** @@ -235,7 +249,7 @@ IPAddress WebSocketsServer::remoteIP(uint8_t num) { if(num < WEBSOCKETS_SERVER_CLIENT_MAX) { WSclient_t * client = &_clients[num]; if(clientIsConnected(client)) { - return client->tcp.remoteIP(); + return client->tcp->remoteIP(); } } @@ -275,9 +289,26 @@ void WebSocketsServer::messageRecived(WSclient_t * client, WSopcode_t opcode, ui */ void WebSocketsServer::clientDisconnect(WSclient_t * client) { + +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + if(client->isSSL && client->ssl) { + if(client->ssl->connected()) { + client->ssl->flush(); + client->ssl->stop(); + } + delete client->ssl; + client->ssl = NULL; + client->tcp = NULL; + } +#endif + if(client->tcp) { - client->tcp.flush(); - client->tcp.stop(); + if(client->tcp->connected()) { + client->tcp->flush(); + client->tcp->stop(); + } + delete client->tcp; + client->tcp = NULL; } client->cUrl = ""; @@ -302,7 +333,11 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) { */ bool WebSocketsServer::clientIsConnected(WSclient_t * client) { - if(client->tcp.connected()) { + if(!client->tcp) { + return false; + } + + if(client->tcp->connected()) { if(client->status != WSC_NOT_CONNECTED) { return true; } @@ -314,6 +349,12 @@ bool WebSocketsServer::clientIsConnected(WSclient_t * client) { clientDisconnect(client); } } + + if(client->tcp) { + // do cleanup + clientDisconnect(client); + } + return false; } @@ -332,15 +373,22 @@ void WebSocketsServer::handleNewClients(void) { if(!clientIsConnected(client)) { // store new connection - client->tcp = _server->available(); -#ifdef ESP8266 - client->tcp.setNoDelay(true); + client->tcp = new WEBSOCKETS_NETWORK_CLASS(_server->available()); + + if(!client->tcp) { + DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); + return; + } + +#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) + client->isSSL = false; + client->tcp->setNoDelay(true); #endif // set Timeout for readBytesUntil and readStringUntil - client->tcp.setTimeout(WEBSOCKETS_TCP_TIMEOUT); + client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); client->status = WSC_HEADER; - IPAddress ip = client->tcp.remoteIP(); + IPAddress ip = client->tcp->remoteIP(); DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]); ok = true; break; @@ -349,7 +397,7 @@ void WebSocketsServer::handleNewClients(void) { if(!ok) { // no free space to handle client - WiFiClient tcpClient = _server->available(); + WEBSOCKETS_NETWORK_CLASS tcpClient = _server->available(); IPAddress ip = tcpClient.remoteIP(); DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); tcpClient.stop(); @@ -370,7 +418,7 @@ void WebSocketsServer::handleClientData(void) { for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { client = &_clients[i]; if(clientIsConnected(client)) { - int len = client->tcp.available(); + int len = client->tcp->available(); if(len > 0) { switch(client->status) { @@ -398,7 +446,7 @@ void WebSocketsServer::handleClientData(void) { */ void WebSocketsServer::handleHeader(WSclient_t * client) { - String headerLine = client->tcp.readStringUntil('\n'); + String headerLine = client->tcp->readStringUntil('\n'); headerLine.trim(); // remove \r if(headerLine.length() > 0) { @@ -470,22 +518,22 @@ void WebSocketsServer::handleHeader(WSclient_t * client) { client->status = WSC_CONNECTED; - client->tcp.write("HTTP/1.1 101 Switching Protocols\r\n" + client->tcp->write("HTTP/1.1 101 Switching Protocols\r\n" "Server: arduino-WebSocketsServer\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Version: 13\r\n" "Sec-WebSocket-Accept: "); - client->tcp.write(sKey.c_str(), sKey.length()); - client->tcp.write("\r\n"); + client->tcp->write(sKey.c_str(), sKey.length()); + client->tcp->write("\r\n"); if(client->cProtocol.length() > 0) { - // todo add api to set Protocol of Server - client->tcp.write("Sec-WebSocket-Protocol: arduino\r\n"); + // TODO add api to set Protocol of Server + client->tcp->write("Sec-WebSocket-Protocol: arduino\r\n"); } // header end - client->tcp.write("\r\n"); + client->tcp->write("\r\n"); // send ping WebSockets::sendFrame(client, WSop_ping); diff --git a/src/WebSocketsServer.h b/src/WebSocketsServer.h index 86ad970..bef170e 100644 --- a/src/WebSocketsServer.h +++ b/src/WebSocketsServer.h @@ -26,17 +26,6 @@ #define WEBSOCKETSSERVER_H_ #include - -#ifdef ESP8266 -#include -#else -#include -#ifndef UIPETHERNET_H -#include -#include -#endif -#endif - #include "WebSockets.h" #define WEBSOCKETS_SERVER_CLIENT_MAX (5) @@ -115,7 +104,7 @@ protected: */ virtual void handleNonWebsocketConnection(WSclient_t * client) { DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num); - client->tcp.write("HTTP/1.1 400 Bad Request\r\n" + client->tcp->write("HTTP/1.1 400 Bad Request\r\n" "Server: arduino-WebSocket-Server\r\n" "Content-Type: text/plain\r\n" "Content-Length: 32\r\n"