Initial migration to platformIO

This commit is contained in:
Ollo 2023-04-24 21:49:13 +02:00
parent d9209b854c
commit e711668f90
13 changed files with 106 additions and 2327 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

16
platformio.ini Normal file
View File

@ -0,0 +1,16 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:megaatmega2560]
platform = atmelavr
board = megaatmega2560
framework = arduino
lib_deps = arduino-libraries/Ethernet@^2.0.2
build_flags -DHOST_NAME=DepartureSign

View File

@ -1,80 +0,0 @@
#include "ProtocolDL.hpp"
ProtocolDL::ProtocolDL(Image& img):
image(&img)
{
}
void ProtocolDL::newByte(uint8_t data)
{
switch(cnt)
{
case 0:
complete = false;
source.width = (data << 8);
cnt = 1;
break;
case 1:
source.width |= data;
cnt = 2;
break;
case 2:
source.height = (data << 8);
cnt = 3;
break;
case 3:
source.height |= data;
cnt = 4;
break;
case 4:
source.delay = (data << 8);
cnt = 5;
break;
case 5:
source.delay |= data;
image->set_size(source.width, source.height);
source.x = 0;
source.y = 0;
cnt = 6;
break;
default:
for (int shift = 7; shift >= 0; shift--) {
byte pixel = (data >> shift) & 1;
image->set_pixel(source.x, source.y, pixel);
if(source.x == (source.width - 1) && source.y == (source.height - 1))
{
//this was the last pixel
complete = true;
cnt = 0;
}
else
{
source.x++;
if (source.x >= source.width) {
source.x = 0;
source.y++;
if (source.y >= source.height) {
source.y = 0;
}
}
}
}
break;
}
}
bool ProtocolDL::isComplete()
{
return complete;
}

View File

@ -1,35 +0,0 @@
#ifndef PROTOCOL_DL_HPP
#define PROTOCOL_DL_HPP
#include "image.hpp"
class ProtocolDL
{
public:
ProtocolDL(Image& img);
void newByte(uint8_t data);
bool isComplete();
private:
struct source_t {
// width and height of current frame
unsigned int width;
unsigned int height;
// delay until next frame is shown
unsigned int delay;
// position of current pixel
int x;
int y;
};
source_t source;
uint16_t cnt = 0;
bool complete = true;
Image* image;
};
#endif

View File

@ -1,592 +0,0 @@
/**
* @file WebSockets.cpp
* @date 20.05.2015
* @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
*
*/
#include "WebSockets.h"
#define LEGACY_SHA1
#ifdef ESP8266
#include <core_esp8266_features.h>
#endif
extern "C" {
#ifdef CORE_HAS_LIBB64
#include <libb64/cencode.h>
#else
#include "libb64/cencode_inc.h"
#endif
}
#ifdef ESP8266
#include <Hash.h>
#else
#ifdef LEGACY_SHA1
#include "sha1/sha1.h"
#else
extern "C" {
#include "libsha1/libsha1.h"
}
#endif
#endif
#define WEBSOCKETS_MAX_HEADER_SIZE (14)
/**
*
* @param client WSclient_t * ptr to the client struct
* @param code uint16_t see RFC
* @param reason
* @param reasonLen
*/
void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) {
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] clientDisconnect code: ");
DEBUG_WEBSOCKETS(code);
DEBUG_WEBSOCKETS("\n");
if(client->status == WSC_CONNECTED && code) {
if(reason) {
sendFrame(client, WSop_close, (uint8_t *) reason, reasonLen);
} else {
uint8_t buffer[2];
buffer[0] = ((code >> 8) & 0xFF);
buffer[1] = (code & 0xFF);
sendFrame(client, WSop_close, &buffer[0], 2);
}
}
clientDisconnect(client);
}
/**
*
* @param client WSclient_t * ptr to the client struct
* @param opcode WSopcode_t
* @param payload uint8_t *
* @param length size_t
* @param mask bool add dummy mask to the frame (needed for web browser)
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
* @param headerToPayload bool set true if the payload has reserved 14 Byte at the beginning to dynamically add the Header (payload neet to be in RAM!)
*/
bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool mask, bool fin, bool headerToPayload) {
if(client->tcp && !client->tcp->connected()) {
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][sendFrame] not Connected!?\n");
return false;
}
if(client->status != WSC_CONNECTED) {
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][sendFrame] not in WSC_CONNECTED state!?\n");
return false;
}
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][sendFrame] ------- send massage frame -------\n");
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][sendFrame] fin: ");
DEBUG_WEBSOCKETS(fin);
DEBUG_WEBSOCKETS(" opCode: ");
DEBUG_WEBSOCKETS(opcode);
DEBUG_WEBSOCKETS(" mask: ");
DEBUG_WEBSOCKETS(mask);
DEBUG_WEBSOCKETS(" length: ");
DEBUG_WEBSOCKETS(length);
DEBUG_WEBSOCKETS(" headerToPayload: ");
DEBUG_WEBSOCKETS(headerToPayload);
DEBUG_WEBSOCKETS("\n");
if(opcode == WSop_text) {
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][sendFrame] text: ");
DEBUG_WEBSOCKETS((char*) (payload + (headerToPayload ? 14 : 0)));
DEBUG_WEBSOCKETS("\n");
}
uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 };
uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 };
uint8_t headerSize;
uint8_t * headerPtr;
uint8_t * payloadPtr = payload;
bool useInternBuffer = false;
bool ret = true;
// calculate header Size
if(length < 126) {
headerSize = 2;
} else if(length < 0xFFFF) {
headerSize = 4;
} else {
headerSize = 10;
}
if(mask) {
headerSize += 4;
}
#ifdef WEBSOCKETS_USE_BIG_MEM
// only for ESP since AVR has less HEAP
// try to send data in one TCP package (only if some free Heap is there)
if(!headerToPayload && ((length > 0) && (length < 1400)) && (ESP.getFreeHeap() > 6000)) {
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][sendFrame] pack to one TCP package...\n");
uint8_t * dataPtr = (uint8_t *) malloc(length + WEBSOCKETS_MAX_HEADER_SIZE);
if(dataPtr) {
memcpy((dataPtr + WEBSOCKETS_MAX_HEADER_SIZE), payload, length);
headerToPayload = true;
useInternBuffer = true;
payloadPtr = dataPtr;
}
}
#endif
// set Header Pointer
if(headerToPayload) {
// calculate offset in payload
headerPtr = (payloadPtr + (WEBSOCKETS_MAX_HEADER_SIZE - headerSize));
} else {
headerPtr = &buffer[0];
}
// create header
// byte 0
*headerPtr = 0x00;
if(fin) {
*headerPtr |= bit(7); ///< set Fin
}
*headerPtr |= opcode; ///< set opcode
headerPtr++;
// byte 1
*headerPtr = 0x00;
if(mask) {
*headerPtr |= bit(7); ///< set mask
}
if(length < 126) {
*headerPtr |= length; headerPtr++;
} else if(length < 0xFFFF) {
*headerPtr |= 126; headerPtr++;
*headerPtr = ((length >> 8) & 0xFF); headerPtr++;
*headerPtr = (length & 0xFF); headerPtr++;
} else {
// Normally we never get here (to less memory)
*headerPtr |= 127; headerPtr++;
*headerPtr = 0x00; headerPtr++;
*headerPtr = 0x00; headerPtr++;
*headerPtr = 0x00; headerPtr++;
*headerPtr = 0x00; headerPtr++;
*headerPtr = ((length >> 24) & 0xFF); headerPtr++;
*headerPtr = ((length >> 16) & 0xFF); headerPtr++;
*headerPtr = ((length >> 8) & 0xFF); headerPtr++;
*headerPtr = (length & 0xFF); headerPtr++;
}
if(mask) {
if(useInternBuffer) {
// if we use a Intern Buffer we can modify the data
// by this fact its possible the do the masking
for(uint8_t x = 0; x < sizeof(maskKey); x++) {
maskKey[x] = random(0xFF);
*headerPtr = maskKey[x]; headerPtr++;
}
uint8_t * dataMaskPtr;
if(headerToPayload) {
dataMaskPtr = (payloadPtr + WEBSOCKETS_MAX_HEADER_SIZE);
} else {
dataMaskPtr = payloadPtr;
}
for(size_t x = 0; x < length; x++) {
dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]);
}
} else {
*headerPtr = maskKey[0]; headerPtr++;
*headerPtr = maskKey[1]; headerPtr++;
*headerPtr = maskKey[2]; headerPtr++;
*headerPtr = maskKey[3]; headerPtr++;
}
}
#ifndef NODEBUG_WEBSOCKETS
unsigned long start = micros();
#endif
if(headerToPayload) {
// header has be added to payload
// payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings
// offset in payload is calculatetd 14 - headerSize
if (client->tcp->write(&payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize)) != (length + headerSize)) {
ret = false;
}
} else {
// send header
if (client->tcp->write(&buffer[0], headerSize) != headerSize) {
ret = false;
}
if(payloadPtr && length > 0) {
// send payload
if(client->tcp->write(&payloadPtr[0], length) != length) {
ret = false;
}
}
}
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][sendFrame] sending Frame Done (");
DEBUG_WEBSOCKETS((micros() - start));
DEBUG_WEBSOCKETS("us).\n");
#ifdef WEBSOCKETS_USE_BIG_MEM
if(useInternBuffer && payloadPtr) {
free(payloadPtr);
}
#endif
return ret;
}
/**
* handle the WebSocket stream
* @param client WSclient_t * ptr to the client struct
*/
void WebSockets::handleWebsocket(WSclient_t * client) {
uint8_t buffer[8] = { 0 };
bool fin;
bool rsv1;
bool rsv2;
bool rsv3;
WSopcode_t opCode;
bool mask;
size_t payloadLen;
uint8_t maskKey[4];
uint8_t * payload = NULL;
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] ------- read massage frame -------\n");
if(!readWait(client, buffer, 2)) {
//timeout
clientDisconnect(client, 1002);
return;
}
// split first 2 bytes in the data
fin = ((buffer[0] >> 7) & 0x01);
rsv1 = ((buffer[0] >> 6) & 0x01);
rsv2 = ((buffer[0] >> 5) & 0x01);
rsv3 = ((buffer[0] >> 4) & 0x01);
opCode = (WSopcode_t) (buffer[0] & 0x0F);
mask = ((buffer[1] >> 7) & 0x01);
payloadLen = (WSopcode_t) (buffer[1] & 0x7F);
if(payloadLen == 126) {
if(!readWait(client, buffer, 2)) {
//timeout
clientDisconnect(client, 1002);
return;
}
payloadLen = buffer[0] << 8 | buffer[1];
} else if(payloadLen == 127) {
// read 64bit integer as length
if(!readWait(client, buffer, 8)) {
//timeout
clientDisconnect(client, 1002);
return;
}
if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) {
// really to big!
payloadLen = 0xFFFFFFFF;
} else {
payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
}
}
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] fin: ");
DEBUG_WEBSOCKETS(fin);
DEBUG_WEBSOCKETS(" rsv1: ");
DEBUG_WEBSOCKETS(rsv1);
DEBUG_WEBSOCKETS(" rsv2: ");
DEBUG_WEBSOCKETS(rsv2);
DEBUG_WEBSOCKETS(" rsv3: ");
DEBUG_WEBSOCKETS(rsv3);
DEBUG_WEBSOCKETS(" opCode: ");
DEBUG_WEBSOCKETS(opCode);
DEBUG_WEBSOCKETS("\n");
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] mask: ");
DEBUG_WEBSOCKETS(mask);
DEBUG_WEBSOCKETS(" payloadLen: ");
DEBUG_WEBSOCKETS(payloadLen);
DEBUG_WEBSOCKETS("\n");
if(payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] payload to big! (");
DEBUG_WEBSOCKETS(payloadLen);
DEBUG_WEBSOCKETS(")\n");
clientDisconnect(client, 1009);
return;
}
if(mask) {
if(!readWait(client, maskKey, 4)) {
//timeout
clientDisconnect(client, 1002);
return;
}
}
if(payloadLen > 0) {
// if text data we need one more
payload = (uint8_t *) malloc(payloadLen + 1);
if(!payload) {
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] to less memory to handle payload ");
DEBUG_WEBSOCKETS(payloadLen);
DEBUG_WEBSOCKETS("!\n");
clientDisconnect(client, 1011);
return;
}
if(!readWait(client, payload, payloadLen)) {
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] missing data!\n");
free(payload);
clientDisconnect(client, 1002);
return;
}
payload[payloadLen] = 0x00;
if(mask) {
//decode XOR
for(size_t i = 0; i < payloadLen; i++) {
payload[i] = (payload[i] ^ maskKey[i % 4]);
}
}
}
switch(opCode) {
case WSop_text:
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] text: ");
DEBUG_WEBSOCKETS((char*) payload);
DEBUG_WEBSOCKETS("\n");
// no break here!
case WSop_binary:
messageRecived(client, opCode, payload, payloadLen);
break;
case WSop_ping:
// send pong back
sendFrame(client, WSop_pong, payload, payloadLen);
break;
case WSop_pong:
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] get pong (");
DEBUG_WEBSOCKETS((char*) payload);
DEBUG_WEBSOCKETS(")\n");
break;
case WSop_close:
{
uint16_t reasonCode = 1000;
if(payloadLen >= 2) {
reasonCode = payload[0] << 8 | payload[1];
}
DEBUG_WEBSOCKETS("[WS][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleWebsocket] get ask for close. Code: ");
DEBUG_WEBSOCKETS(reasonCode);
if(payloadLen > 2) {
DEBUG_WEBSOCKETS(" (");
DEBUG_WEBSOCKETS((char*) (payload+2));
DEBUG_WEBSOCKETS(")\n");
} else {
DEBUG_WEBSOCKETS("\n");
}
clientDisconnect(client, 1000);
}
break;
case WSop_continuation:
// continuation is not supported
clientDisconnect(client, 1003);
break;
default:
clientDisconnect(client, 1002);
break;
}
if(payload) {
free(payload);
}
}
/**
* generate the key for Sec-WebSocket-Accept
* @param clientKey String
* @return String Accept Key
*/
String WebSockets::acceptKey(String clientKey) {
uint8_t sha1HashBin[20] = { 0 };
#ifdef ESP8266
sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]);
#else
clientKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
#ifdef LEGACY_SHA1
// Miha Nahtigal
char cbuff[clientKey.length()+1];
clientKey.toCharArray(cbuff, clientKey.length()+1);//Converts String into character array
Sha1.init();
Sha1.print(cbuff);
strcpy(sha1HashBin, Sha1.result());
Serial.println(cbuff);
//old:uint8_t *sha1HashBin = Sha1.result();
#else
SHA1_CTX ctx;
SHA1Init(&ctx);
SHA1Update(&ctx, (const unsigned char*)clientKey.c_str(), clientKey.length());
SHA1Final(&sha1HashBin[0], &ctx);
#endif
#endif
String key = base64_encode(sha1HashBin, 20);
key.trim();
return key;
}
/**
* base64_encode
* @param data uint8_t *
* @param length size_t
* @return base64 encoded String
*/
String WebSockets::base64_encode(uint8_t * data, size_t length) {
size_t size = ((length*1.6f)+1);
char * buffer = (char *) malloc(size);
if(buffer) {
base64_encodestate _state;
base64_init_encodestate(&_state);
int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state);
len = base64_encode_blockend((buffer + len), &_state);
String base64 = String(buffer);
free(buffer);
return base64;
}
return String("-FAIL-");
}
/**
* read x byte from tcp or get timeout
* @param client WSclient_t *
* @param out uint8_t * data buffer
* @param n size_t byte count
* @return true if ok
*/
bool WebSockets::readWait(WSclient_t * client, uint8_t *out, size_t n) {
unsigned long t = millis();
size_t len;
while(n > 0) {
if(!client->tcp) {
DEBUG_WEBSOCKETS("[readWait] tcp is null!\n");
return false;
}
if(!client->tcp->connected()) {
DEBUG_WEBSOCKETS("[readWait] not connected!\n");
return false;
}
if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) {
DEBUG_WEBSOCKETS("[readWait] receive TIMEOUT!\n");
return false;
}
if(!client->tcp->available()) {
#ifdef ESP8266
delay(0);
#endif
continue;
}
len = client->tcp->read((uint8_t*) out, n);
if(len) {
t = millis();
out += len;
n -= len;
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
} else {
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
}
//DEBUG_WEBSOCKETS("Receive ");
//DEBUG_WEBSOCKETS(len);
//DEBUG_WEBSOCKETS("left ");
//DEBUG_WEBSOCKETS(n);
//DEBUG_WEBSOCKETS("!\n");
#ifdef ESP8266
delay(0);
#endif
}
return true;
}

View File

@ -1,159 +0,0 @@
/**
* @file WebSockets.h
* @date 20.05.2015
* @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 WEBSOCKETS_H_
#define WEBSOCKETS_H_
#include <Arduino.h>
//#define DEBUG_WEBSOCKETS(...) Serial.print( __VA_ARGS__ )
#ifndef DEBUG_WEBSOCKETS
#define DEBUG_WEBSOCKETS(...)
#define NODEBUG_WEBSOCKETS
#endif
#ifdef ESP8266
#define WEBSOCKETS_MAX_DATA_SIZE (15*1024)
#define WEBSOCKETS_USE_BIG_MEM
#else
//atmega328p has only 2KB ram!
#define WEBSOCKETS_MAX_DATA_SIZE (2048)
#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 <ESP8266WiFi.h>
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100)
#include <Ethernet.h>
#include <SPI.h>
#define WEBSOCKETS_NETWORK_CLASS EthernetClient
#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60)
#include <UIPEthernet.h>
#define WEBSOCKETS_NETWORK_CLASS UIPClient
#define WEBSOCKETS_NETWORK_SERVER_CLASS UIPServer
#else
#error "no network type selected!"
#endif
typedef enum {
WSC_NOT_CONNECTED,
WSC_HEADER,
WSC_CONNECTED
} WSclientsStatus_t;
typedef enum {
WStype_ERROR,
WStype_DISCONNECTED,
WStype_CONNECTED,
WStype_TEXT,
WStype_BIN
} WStype_t;
typedef enum {
WSop_continuation = 0x00, ///< %x0 denotes a continuation frame
WSop_text = 0x01, ///< %x1 denotes a text frame
WSop_binary = 0x02, ///< %x2 denotes a binary frame
///< %x3-7 are reserved for further non-control frames
WSop_close = 0x08, ///< %x8 denotes a connection close
WSop_ping = 0x09, ///< %x9 denotes a ping
WSop_pong = 0x0A ///< %xA denotes a pong
///< %xB-F are reserved for further control frames
} WSopcode_t;
typedef struct {
uint8_t num; ///< connection number
WSclientsStatus_t status;
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
bool cIsUpgrade; ///< Connection == Upgrade
bool cIsWebsocket; ///< Upgrade == websocket
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
} WSclient_t;
class WebSockets {
protected:
virtual void clientDisconnect(WSclient_t * client);
virtual bool clientIsConnected(WSclient_t * client);
virtual void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool mask = false, bool fin = true, bool headerToPayload = false);
void handleWebsocket(WSclient_t * client);
bool readWait(WSclient_t * client, uint8_t *out, size_t n);
String acceptKey(String clientKey);
String base64_encode(uint8_t * data, size_t length);
};
#endif /* WEBSOCKETS_H_ */

View File

@ -1,506 +0,0 @@
/**
* @file WebSocketsClient.cpp
* @date 20.05.2015
* @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
*
*/
#include "WebSockets.h"
#include "WebSocketsClient.h"
WebSocketsClient::WebSocketsClient() {
_cbEvent = NULL;
_client.num = 0;
}
WebSocketsClient::~WebSocketsClient() {
disconnect();
}
/**
* calles to init the Websockets server
*/
void WebSocketsClient::begin(const char *host, uint16_t port, const char * url) {
_host = host;
_port = port;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
_fingerprint = "";
#endif
_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;
_client.cIsWebsocket = true;
_client.cKey = "";
_client.cAccept = "";
_client.cProtocol = "";
_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) {
begin(host.c_str(), port, url.c_str());
}
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
void WebSocketsClient::beginSSL(const char *host, uint16_t port, const char * url, const char * fingerprint) {
begin(host, port, url);
_client.isSSL = true;
_fingerprint = fingerprint;
}
void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint) {
beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str());
}
#endif
/**
* called in arduino loop
*/
void WebSocketsClient::loop(void) {
if(!clientIsConnected(&_client)) {
#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");
//DEBUG_WEBSOCKETS(_host.c_str());
//DEBUG_WEBSOCKETS(_port);
_client.status = WSC_HEADER;
// set Timeout for readBytesUntil and readStringUntil
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
_client.tcp->setNoDelay(true);
if(_client.isSSL && _fingerprint.length()) {
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
WebSockets::clientDisconnect(&_client, 1000);
return;
}
}
#endif
// send Header to Server
sendHeader(&_client);
} else {
DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Faild\n");
///EBUG_WEBSOCKETS(_host.c_str());
//DEBUG_WEBSOCKETS(_port);
delay(10); //some litle delay to not flood the server
}
} else {
handleClientData();
}
}
/**
* set callback function
* @param cbEvent WebSocketServerEvent
*/
void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) {
_cbEvent = cbEvent;
}
/**
* 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)
*/
void WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
if(length == 0) {
length = strlen((const char *) payload);
}
if(clientIsConnected(&_client)) {
sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload);
}
}
void WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) {
sendTXT((uint8_t *) payload, length);
}
void WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) {
sendTXT((uint8_t *) payload, length, headerToPayload);
}
void WebSocketsClient::sendTXT(const char * payload, size_t length) {
sendTXT((uint8_t *) payload, length);
}
void WebSocketsClient::sendTXT(String payload) {
sendTXT((uint8_t *) payload.c_str(), payload.length());
}
/**
* send binary 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)
*/
void WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
if(clientIsConnected(&_client)) {
sendFrame(&_client, WSop_binary, payload, length, true, true, headerToPayload);
}
}
void WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) {
sendBIN((uint8_t *) payload, length);
}
/**
* disconnect one client
* @param num uint8_t client id
*/
void WebSocketsClient::disconnect(void) {
if(clientIsConnected(&_client)) {
WebSockets::clientDisconnect(&_client, 1000);
}
}
//#################################################################################
//#################################################################################
//#################################################################################
/**
*
* @param client WSclient_t * ptr to the client struct
* @param opcode WSopcode_t
* @param payload uint8_t *
* @param lenght size_t
*/
void WebSocketsClient::messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) {
WStype_t type = WStype_ERROR;
switch(opcode) {
case WSop_text:
type = WStype_TEXT;
break;
case WSop_binary:
type = WStype_BIN;
break;
}
runCbEvent(type, payload, lenght);
}
/**
* Disconnect an client
* @param client WSclient_t * ptr to the client struct
*/
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) {
if(client->tcp->connected()) {
client->tcp->flush();
client->tcp->stop();
}
delete client->tcp;
client->tcp = NULL;
}
client->cCode = 0;
client->cKey = "";
client->cAccept = "";
client->cProtocol = "";
client->cVersion = 0;
client->cIsUpgrade = false;
client->cIsWebsocket = false;
client->status = WSC_NOT_CONNECTED;
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
runCbEvent(WStype_DISCONNECTED, NULL, 0);
}
/**
* get client state
* @param client WSclient_t * ptr to the client struct
* @return true = conneted
*/
bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
if(!client->tcp) {
return false;
}
if(client->tcp->connected()) {
if(client->status != WSC_NOT_CONNECTED) {
return true;
}
} else {
// client lost
if(client->status != WSC_NOT_CONNECTED) {
DEBUG_WEBSOCKETS("[WS-Client] connection lost.\n");
// do cleanup
clientDisconnect(client);
}
}
if(client->tcp) {
// do cleanup
clientDisconnect(client);
}
return false;
}
/**
* Handel incomming data from Client
*/
void WebSocketsClient::handleClientData(void) {
int len = _client.tcp->available();
if(len > 0) {
switch(_client.status) {
case WSC_HEADER:
handleHeader(&_client);
break;
case WSC_CONNECTED:
WebSockets::handleWebsocket(&_client);
break;
default:
WebSockets::clientDisconnect(&_client, 1002);
break;
}
}
#ifdef ESP8266
delay(0);
#endif
}
/**
* send the WebSocket header to Server
* @param client WSclient_t * ptr to the client struct
*/
void WebSocketsClient::sendHeader(WSclient_t * client) {
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n");
uint8_t randomKey[16] = { 0 };
for(uint8_t i = 0; i < sizeof(randomKey); i++) {
randomKey[i] = random(0xFF);
}
client->cKey = base64_encode(&randomKey[0], 16);
#ifndef NODEBUG_WEBSOCKETS
unsigned long start = micros();
#endif
String handshake = "GET " + client->cUrl + " HTTP/1.1\r\n"
"Host: " + _host + "\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"User-Agent: arduino-WebSocket-Client\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Protocol: arduino\r\n"
"Sec-WebSocket-Key: " + client->cKey + "\r\n";
if(client->cExtensions.length() > 0) {
handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n";
}
handshake += "\r\n";
client->tcp->write(handshake.c_str(), handshake.length());
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%uus).\n");
//DEBUG_WEBSOCKETS((micros() - start));
}
/**
* handle the WebSocket header reading
* @param client WSclient_t * ptr to the client struct
*/
void WebSocketsClient::handleHeader(WSclient_t * client) {
String headerLine = client->tcp->readStringUntil('\n');
headerLine.trim(); // remove \r
if(headerLine.length() > 0) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n");
DEBUG_WEBSOCKETS(headerLine.c_str());
if(headerLine.startsWith("HTTP/1.")) {
// "HTTP/1.1 101 Switching Protocols"
client->cCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt();
} else if(headerLine.indexOf(':')) {
String headerName = headerLine.substring(0, headerLine.indexOf(':'));
String headerValue = headerLine.substring(headerLine.indexOf(':') + 2);
if(headerName.equalsIgnoreCase("Connection")) {
if(headerValue.indexOf("Upgrade") >= 0) {
client->cIsUpgrade = true;
}
} else if(headerName.equalsIgnoreCase("Upgrade")) {
if(headerValue.equalsIgnoreCase("websocket")) {
client->cIsWebsocket = true;
}
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Accept")) {
client->cAccept = headerValue;
client->cAccept.trim(); // see rfc6455
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) {
client->cProtocol = headerValue;
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) {
client->cExtensions = headerValue;
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) {
client->cVersion = headerValue.toInt();
}
} else {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n");
DEBUG_WEBSOCKETS(headerLine.c_str());
}
} else {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n");
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n");
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cURL: %s\n");
//DEBUG_WEBSOCKETS(client->cUrl.c_str());
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cKey: %s\n");
//DEBUG_WEBSOCKETS(client->cKey.c_str());
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Server header:\n");
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cCode: %d\n");
//DEBUG_WEBSOCKETS(client->cCode);
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsUpgrade: %d\n");
//DEBUG_WEBSOCKETS(client->cIsUpgrade);
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsWebsocket: %d\n");
//DEBUG_WEBSOCKETS(client->cIsWebsocket);
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cAccept: %s\n");
//DEBUG_WEBSOCKETS(client->cAccept.c_str());
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n");
//DEBUG_WEBSOCKETS(client->cProtocol.c_str());
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n");
//DEBUG_WEBSOCKETS(client->cExtensions.c_str());
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n");
//DEBUG_WEBSOCKETS(client->cVersion);
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
if(ok) {
switch(client->cCode) {
case 101: ///< Switching Protocols
break;
case 403: ///< Forbidden
// todo handle login
default: ///< Server dont unterstand requrst
ok = false;
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n");
//DEBUG_WEBSOCKETS(client->cCode);
clientDisconnect(client);
break;
}
}
if(ok) {
if(client->cAccept.length() == 0) {
ok = false;
} else {
// generate Sec-WebSocket-Accept key for check
String sKey = acceptKey(client->cKey);
if(sKey != client->cAccept) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Sec-WebSocket-Accept is wrong\n");
ok = false;
}
}
}
if(ok) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n");
client->status = WSC_CONNECTED;
runCbEvent(WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length());
} else {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
client->tcp->write("This is a webSocket client!");
clientDisconnect(client);
}
}
}

View File

@ -1,98 +0,0 @@
/**
* @file WebSocketsClient.h
* @date 20.05.2015
* @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 WEBSOCKETSCLIENT_H_
#define WEBSOCKETSCLIENT_H_
#include <Arduino.h>
#include "WebSockets.h"
class WebSocketsClient: private WebSockets {
public:
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
WebSocketsClient(void);
~WebSocketsClient(void);
void begin(const char *host, uint16_t port, const char * url = "/");
void begin(String host, uint16_t port, String url = "/");
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
void beginSSL(const char *host, uint16_t port, const char * url = "/", const char * = "");
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "");
#endif
void loop(void);
void onEvent(WebSocketClientEvent cbEvent);
void sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
void sendTXT(const uint8_t * payload, size_t length = 0);
void sendTXT(char * payload, size_t length = 0, bool headerToPayload = false);
void sendTXT(const char * payload, size_t length = 0);
void sendTXT(String payload);
void sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
void sendBIN(const uint8_t * payload, size_t length);
void disconnect(void);
protected:
String _host;
uint16_t _port;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
String _fingerprint;
#endif
WSclient_t _client;
WebSocketClientEvent _cbEvent;
void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
void clientDisconnect(WSclient_t * client);
bool clientIsConnected(WSclient_t * client);
void handleNewClients(void);
void handleClientData(void);
void sendHeader(WSclient_t * client);
void handleHeader(WSclient_t * client);
/**
* called for sending a Event to the app
* @param type WStype_t
* @param payload uint8_t *
* @param length size_t
*/
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
if(_cbEvent) {
_cbEvent(type, payload, length);
}
}
};
#endif /* WEBSOCKETSCLIENT_H_ */

View File

@ -1,714 +0,0 @@
/**
* @file WebSocketsServer.cpp
* @date 20.05.2015
* @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
*
*/
#include "WebSockets.h"
#include "WebSocketsServer.h"
WebSocketsServer::WebSocketsServer(uint16_t port) {
_port = port;
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
_cbEvent = NULL;
}
WebSocketsServer::~WebSocketsServer() {
// disconnect all clients
disconnect();
// TODO how to close server?
}
/**
* calles to init the Websockets 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)
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;
}
#ifdef ESP8266
randomSeed(RANDOM_REG32);
#else
// TODO find better seed
randomSeed(millis());
#endif
_server->begin();
DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
}
/**
* called in arduino loop
*/
void WebSocketsServer::loop(void) {
handleNewClients();
handleClientData();
}
/**
* set callback function
* @param cbEvent WebSocketServerEvent
*/
void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) {
_cbEvent = cbEvent;
}
/**
* 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)
*/
void WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return;
}
if(length == 0) {
length = strlen((const char *) payload);
}
WSclient_t * client = &_clients[num];
if(clientIsConnected(client)) {
sendFrame(client, WSop_text, payload, length, false, true, headerToPayload);
}
}
void WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) {
sendTXT(num, (uint8_t *) payload, length);
}
void WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) {
sendTXT(num, (uint8_t *) payload, length, headerToPayload);
}
void WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) {
sendTXT(num, (uint8_t *) payload, length);
}
void WebSocketsServer::sendTXT(uint8_t num, String payload) {
sendTXT(num, (uint8_t *) payload.c_str(), payload.length());
}
/**
* send text data to client all
* @param payload uint8_t *
* @param length size_t
* @param headerToPayload bool (see sendFrame for more details)
*/
void WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) {
WSclient_t * client;
if(length == 0) {
length = strlen((const char *) payload);
}
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
if(clientIsConnected(client)) {
sendFrame(client, WSop_text, payload, length, false, true, headerToPayload);
}
#ifdef ESP8266
delay(0);
#endif
}
}
void WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) {
broadcastTXT((uint8_t *) payload, length);
}
void WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) {
broadcastTXT((uint8_t *) payload, length, headerToPayload);
}
void WebSocketsServer::broadcastTXT(const char * payload, size_t length) {
broadcastTXT((uint8_t *) payload, length);
}
void WebSocketsServer::broadcastTXT(String payload) {
broadcastTXT((uint8_t *) payload.c_str(), payload.length());
}
/**
* send binary 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)
*/
void WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return;
}
WSclient_t * client = &_clients[num];
if(clientIsConnected(client)) {
sendFrame(client, WSop_binary, payload, length, false, true, headerToPayload);
}
}
void WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) {
sendBIN(num, (uint8_t *) payload, length);
}
/**
* send binary data to client all
* @param payload uint8_t *
* @param length size_t
* @param headerToPayload bool (see sendFrame for more details)
*/
void WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) {
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
if(clientIsConnected(client)) {
sendFrame(client, WSop_binary, payload, length, false, true, headerToPayload);
}
#ifdef ESP8266
delay(0);
#endif
}
}
void WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) {
broadcastBIN((uint8_t *) payload, length);
}
/**
* sends a WS ping to Client
* @param num uint8_t client id
* @param payload uint8_t *
* @param length size_t
* @return true if ping is send out
*/
bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return false;
}
WSclient_t * client;
client = &_clients[num];
if(clientIsConnected(client)) {
return sendFrame(client, WSop_ping, payload, length);
}
return false;
}
bool WebSocketsServer::sendPing(uint8_t num, String & payload) {
return sendPing(num, (uint8_t *) payload.c_str(), payload.length());
}
/**
* sends a WS ping to all Client
* @param payload uint8_t *
* @param length size_t
* @return true if ping is send out
*/
bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) {
WSclient_t * client;
bool ret = true;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
if(clientIsConnected(client)) {
if(!sendFrame(client, WSop_ping, payload, length)) {
ret = false;
}
}
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
}
return ret;
}
bool WebSocketsServer::broadcastPing(String & payload) {
return broadcastPing((uint8_t *) payload.c_str(), payload.length());
}
bool WebSocketsServer::clientConnected(uint8_t num) {
WSclient_t * client;
client = &_clients[num];
return clientIsConnected(client);
}
/**
* disconnect all clients
*/
void WebSocketsServer::disconnect(void) {
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
if(clientIsConnected(client)) {
WebSockets::clientDisconnect(client, 1000);
}
}
}
/**
* disconnect one client
* @param num uint8_t client id
*/
void WebSocketsServer::disconnect(uint8_t num) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return;
}
WSclient_t * client = &_clients[num];
if(clientIsConnected(client)) {
WebSockets::clientDisconnect(client, 1000);
}
}
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
/**
* get an IP for a client
* @param num uint8_t client id
* @return IPAddress
*/
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 IPAddress();
}
#endif
//#################################################################################
//#################################################################################
//#################################################################################
/**
*
* @param client WSclient_t * ptr to the client struct
* @param opcode WSopcode_t
* @param payload uint8_t *
* @param lenght size_t
*/
void WebSocketsServer::messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) {
WStype_t type = WStype_ERROR;
switch(opcode) {
case WSop_text:
type = WStype_TEXT;
break;
case WSop_binary:
type = WStype_BIN;
break;
}
runCbEvent(client->num, type, payload, lenght);
}
/**
* Disconnect an client
* @param client WSclient_t * ptr to the client struct
*/
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) {
if(client->tcp->connected()) {
client->tcp->flush();
client->tcp->stop();
}
delete client->tcp;
client->tcp = NULL;
}
client->cUrl = "";
client->cKey = "";
client->cProtocol = "";
client->cVersion = 0;
client->cIsUpgrade = false;
client->cIsWebsocket = false;
client->status = WSC_NOT_CONNECTED;
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS(" client disconnected.\n");
runCbEvent(client->num, WStype_DISCONNECTED, NULL, 0);
}
/**
* get client state
* @param client WSclient_t * ptr to the client struct
* @return true = conneted
*/
bool WebSocketsServer::clientIsConnected(WSclient_t * client) {
if(!client->tcp) {
return false;
}
if(client->tcp->connected()) {
if(client->status != WSC_NOT_CONNECTED) {
return true;
}
} else {
// client lost
DEBUG_WEBSOCKETS(client->status);
if(client->status != WSC_NOT_CONNECTED) {
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS(" client connection lost.\n");
// do cleanup
clientDisconnect(client);
}
}
if(client->tcp) {
// do cleanup
clientDisconnect(client);
}
return false;
}
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266)
bool WebSocketsServer::clientExists(const WEBSOCKETS_NETWORK_CLASS &c)
{
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
if (clientIsConnected(client) && (*client->tcp == c))
return true;
}
return false;
}
#endif
/**
* Handle incomming Connection Request
*/
void WebSocketsServer::handleNewClients(void) {
WSclient_t * client;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
while(_server->hasClient()) {
#endif
bool ok = false;
// search free list entry for client
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
// state is not connected or tcp connection is lost
if(!clientIsConnected(client)) {
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
// store new connection
client->tcp = new WEBSOCKETS_NETWORK_CLASS(_server->available());
#else
WEBSOCKETS_NETWORK_CLASS newClient = _server->available();
if (newClient && !clientExists(newClient)) {
client->tcp = new WEBSOCKETS_NETWORK_CLASS(newClient);
} else {
return;
}
//if (!client->tcp->connected() || !client->tcp->available()) {
// DEBUG_WEBSOCKETS("[WS-Client] Not Connected!\n");
// return;
//}
#endif
if(!client->tcp) {
DEBUG_WEBSOCKETS("[WS-Server] 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->status = WSC_HEADER;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
IPAddress ip = client->tcp->remoteIP();
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS(" new client from %d.%d.%d.%d\n");
//DEBUG_WEBSOCKETS(ip[0]);
//DEBUG_WEBSOCKETS(ip[1]);
//DEBUG_WEBSOCKETS(ip[2]);
//DEBUG_WEBSOCKETS(ip[3]);
#else
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS(" new client\n");
#endif
ok = true;
break;
}
}
if(!ok) {
// no free space to handle client
WEBSOCKETS_NETWORK_CLASS tcpClient = _server->available();
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
IPAddress ip = client->tcp->remoteIP();
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n");
//DEBUG_WEBSOCKETS(ip[0]);
//DEBUG_WEBSOCKETS(ip[1]);
//DEBUG_WEBSOCKETS(ip[2]);
//DEBUG_WEBSOCKETS(ip[3]);
#else
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
#endif
tcpClient.stop();
}
#ifdef ESP8266
delay(0);
#endif
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
}
#endif
}
/**
* Handel incomming data from Client
*/
void WebSocketsServer::handleClientData(void) {
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
if(clientIsConnected(client)) {
int len = client->tcp->available();
if(len > 0) {
switch(client->status) {
case WSC_HEADER:
handleHeader(client);
break;
case WSC_CONNECTED:
WebSockets::handleWebsocket(client);
break;
default:
WebSockets::clientDisconnect(client, 1002);
break;
}
}
}
#ifdef ESP8266
delay(0);
#endif
}
}
/**
* handle the WebSocket header reading
* @param client WSclient_t * ptr to the client struct
*/
void WebSocketsServer::handleHeader(WSclient_t * client) {
String headerLine = client->tcp->readStringUntil('\n');
headerLine.trim(); // remove \r
if(headerLine.length() > 0) {
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] RX: ");
DEBUG_WEBSOCKETS(headerLine.c_str());
DEBUG_WEBSOCKETS("\n");
// websocket request starts allways with GET see rfc6455
if(headerLine.startsWith("GET ")) {
// cut URL out
client->cUrl = headerLine.substring(4, headerLine.indexOf(' ', 4));
} else if(headerLine.indexOf(':')) {
String headerName = headerLine.substring(0, headerLine.indexOf(':'));
String headerValue = headerLine.substring(headerLine.indexOf(':') + 2);
//Serial.print(headerName); Serial.print(":"); Serial.println(headerValue);
if(headerName.equalsIgnoreCase("Connection")) {
if(headerValue.indexOf("Upgrade") >= 0) {
client->cIsUpgrade = true;
}
} else if(headerName.equalsIgnoreCase("Upgrade")) {
if(headerValue.equalsIgnoreCase("websocket")) {
client->cIsWebsocket = true;
}
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) {
client->cVersion = headerValue.toInt();
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Key")) {
client->cKey = headerValue;
client->cKey.trim(); // see rfc6455
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) {
client->cProtocol = headerValue;
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) {
client->cExtensions = headerValue;
}
} else {
Serial.print("[WS-Client][handleHeader] Header error (%s)\n");
Serial.print(headerLine.c_str());
}
} else {
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] Header read fin.\n");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] - cURL: ");
DEBUG_WEBSOCKETS(client->cUrl.c_str());
DEBUG_WEBSOCKETS("\n");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] - cIsUpgrade: ");
DEBUG_WEBSOCKETS(client->cIsUpgrade);
DEBUG_WEBSOCKETS("\n");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] - cIsWebsocket: ");
DEBUG_WEBSOCKETS(client->cIsWebsocket);
DEBUG_WEBSOCKETS("\n");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] - cKey: ");
DEBUG_WEBSOCKETS(client->cKey.c_str());
DEBUG_WEBSOCKETS("\n");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] - cProtocol: ");
DEBUG_WEBSOCKETS(client->cProtocol.c_str());
DEBUG_WEBSOCKETS("\n");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] - cExtensions: ");
DEBUG_WEBSOCKETS(client->cExtensions.c_str());
DEBUG_WEBSOCKETS("\n");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] - cVersion: ");
DEBUG_WEBSOCKETS(client->cVersion);
DEBUG_WEBSOCKETS("\n\n");
bool ok = (client->cIsUpgrade && client->cIsWebsocket);
Serial.println("here0");
if (!client->cIsUpgrade) {
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] Error! Not an Upgrade\n");
}
if (!client->cIsWebsocket) {
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] Error! Not a Websocket\n");
}
if(ok) {
Serial.println("here1");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] First ok test success.\n");
if(client->cUrl.length() == 0) {
Serial.println("here2");
ok = false;
}
if(client->cKey.length() == 0) {
Serial.println("here3");
ok = false;
}
if(client->cVersion != 13) {
Serial.println("here4");
ok = false;
}
}
if(ok) {
Serial.println("here5");
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] Websocket connection incomming.\n");
// generate Sec-WebSocket-Accept key
String sKey = acceptKey(client->cKey);
DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]");
DEBUG_WEBSOCKETS("[handleHeader] - sKey: ");
DEBUG_WEBSOCKETS(sKey.c_str());
DEBUG_WEBSOCKETS("\n");
client->status = WSC_CONNECTED;
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");
if(client->cProtocol.length() > 0) {
// TODO add api to set Protocol of Server
client->tcp->write("Sec-WebSocket-Protocol: arduino\r\n");
}
// header end
client->tcp->write("\r\n");
// send ping
WebSockets::sendFrame(client, WSop_ping);
runCbEvent(client->num, WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length());
} else {
handleNonWebsocketConnection(client);
}
}
}

View File

@ -1,143 +0,0 @@
/**
* @file WebSocketsServer.h
* @date 20.05.2015
* @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 WEBSOCKETSSERVER_H_
#define WEBSOCKETSSERVER_H_
#include <Arduino.h>
#include "WebSockets.h"
#define WEBSOCKETS_SERVER_CLIENT_MAX (5)
class WebSocketsServer: private WebSockets {
public:
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
WebSocketsServer(uint16_t port);
~WebSocketsServer(void);
void begin(void);
void loop(void);
void onEvent(WebSocketServerEvent cbEvent);
void sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
void sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0);
void sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false);
void sendTXT(uint8_t num, const char * payload, size_t length = 0);
void sendTXT(uint8_t num, String payload);
void broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
void broadcastTXT(const uint8_t * payload, size_t length = 0);
void broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false);
void broadcastTXT(const char * payload, size_t length = 0);
void broadcastTXT(String payload);
void sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false);
void sendBIN(uint8_t num, const uint8_t * payload, size_t length);
bool sendPing(uint8_t num, uint8_t * payload = NULL, size_t length = 0);
bool sendPing(uint8_t num, String & payload);
bool broadcastPing(uint8_t * payload = NULL, size_t length = 0);
bool broadcastPing(String & payload);
void broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
void broadcastBIN(const uint8_t * payload, size_t length);
void disconnect(void);
void disconnect(uint8_t num);
bool clientConnected(uint8_t num);
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
IPAddress remoteIP(uint8_t num);
#else
bool clientExists(const WEBSOCKETS_NETWORK_CLASS &c);
#endif
protected:
uint16_t _port;
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
WebSocketServerEvent _cbEvent;
void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
void clientDisconnect(WSclient_t * client);
bool clientIsConnected(WSclient_t * client);
void handleNewClients(void);
void handleClientData(void);
void handleHeader(WSclient_t * client);
/**
* called if a non Websocket connection is comming in.
* Note: can be overrided
* @param client WSclient_t * ptr to the client struct
*/
virtual void handleNonWebsocketConnection(WSclient_t * client) {
DEBUG_WEBSOCKETS("[WS-Server][");
DEBUG_WEBSOCKETS(client->num);
DEBUG_WEBSOCKETS("][handleHeader] no Websocket connection close.\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"
"Connection: close\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
"This is a Websocket server only!");
clientDisconnect(client);
}
/**
* called for sending a Event to the app
* @param num uint8_t
* @param type WStype_t
* @param payload uint8_t *
* @param length size_t
*/
virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
if(_cbEvent) {
_cbEvent(num, type, payload, length);
}
}
};
#endif /* WEBSOCKETSSERVER_H_ */