forked from Links2004/arduinoWebSockets
Merge pull request #449 from Links2004/socketio
Socket.IO 2.0.x Support
This commit is contained in:
@ -28,6 +28,10 @@ script:
|
|||||||
- export PATH="$HOME/arduino_ide:$PATH"
|
- export PATH="$HOME/arduino_ide:$PATH"
|
||||||
- which arduino
|
- which arduino
|
||||||
- mkdir -p $HOME/Arduino/libraries
|
- mkdir -p $HOME/Arduino/libraries
|
||||||
|
|
||||||
|
- wget https://github.com/bblanchon/ArduinoJson/archive/6.x.zip
|
||||||
|
- unzip 6.x.zip
|
||||||
|
- mv ArduinoJson-6.x $HOME/Arduino/libraries/ArduinoJson
|
||||||
- cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/arduinoWebSockets
|
- cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/arduinoWebSockets
|
||||||
- source $TRAVIS_BUILD_DIR/travis/common.sh
|
- source $TRAVIS_BUILD_DIR/travis/common.sh
|
||||||
- get_core $CPU
|
- get_core $CPU
|
||||||
|
@ -10,56 +10,46 @@
|
|||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <ESP8266WiFiMulti.h>
|
#include <ESP8266WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
#include <WebSocketsClient.h>
|
#include <WebSocketsClient.h>
|
||||||
|
#include <SocketIOclient.h>
|
||||||
|
|
||||||
#include <Hash.h>
|
#include <Hash.h>
|
||||||
|
|
||||||
ESP8266WiFiMulti WiFiMulti;
|
ESP8266WiFiMulti WiFiMulti;
|
||||||
WebSocketsClient webSocket;
|
SocketIOclient socketIO;
|
||||||
|
|
||||||
|
|
||||||
#define USE_SERIAL Serial1
|
#define USE_SERIAL Serial1
|
||||||
|
|
||||||
#define MESSAGE_INTERVAL 30000
|
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
#define HEARTBEAT_INTERVAL 25000
|
|
||||||
|
|
||||||
uint64_t messageTimestamp = 0;
|
|
||||||
uint64_t heartbeatTimestamp = 0;
|
|
||||||
bool isConnected = false;
|
|
||||||
|
|
||||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
|
||||||
|
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case WStype_DISCONNECTED:
|
case sIOtype_DISCONNECT:
|
||||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
USE_SERIAL.printf("[IOc] Disconnected!\n");
|
||||||
isConnected = false;
|
|
||||||
break;
|
break;
|
||||||
case WStype_CONNECTED:
|
case sIOtype_CONNECT:
|
||||||
{
|
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
|
||||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
|
||||||
isConnected = true;
|
|
||||||
|
|
||||||
// send message to server when Connected
|
|
||||||
// socket.io upgrade confirmation message (required)
|
|
||||||
webSocket.sendTXT("5");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case WStype_TEXT:
|
case sIOtype_EVENT:
|
||||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
USE_SERIAL.printf("[IOc] get event: %s\n", payload);
|
||||||
|
|
||||||
// send message to server
|
|
||||||
// webSocket.sendTXT("message here");
|
|
||||||
break;
|
break;
|
||||||
case WStype_BIN:
|
case sIOtype_ACK:
|
||||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_ERROR:
|
||||||
|
USE_SERIAL.printf("[IOc] get error: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_EVENT:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
|
||||||
|
hexdump(payload, length);
|
||||||
|
break;
|
||||||
|
case sIOtype_BINARY_ACK:
|
||||||
|
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
|
||||||
hexdump(payload, length);
|
hexdump(payload, length);
|
||||||
|
|
||||||
// send data to server
|
|
||||||
// webSocket.sendBIN(payload, length);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
@ -79,6 +69,11 @@ void setup() {
|
|||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disable AP
|
||||||
|
if(WiFi.getMode() & WIFI_AP) {
|
||||||
|
WiFi.softAPdisconnect(true);
|
||||||
|
}
|
||||||
|
|
||||||
WiFiMulti.addAP("SSID", "passpasspass");
|
WiFiMulti.addAP("SSID", "passpasspass");
|
||||||
|
|
||||||
//WiFi.disconnect();
|
//WiFi.disconnect();
|
||||||
@ -86,28 +81,45 @@ void setup() {
|
|||||||
delay(100);
|
delay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
webSocket.beginSocketIO("192.168.0.123", 81);
|
String ip = WiFi.localIP().toString();
|
||||||
//webSocket.setAuthorization("user", "Password"); // HTTP Basic Authorization
|
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
|
||||||
webSocket.onEvent(webSocketEvent);
|
|
||||||
|
|
||||||
|
// server address, port and URL
|
||||||
|
socketIO.begin("10.11.100.100", 8880);
|
||||||
|
|
||||||
|
// event handler
|
||||||
|
socketIO.onEvent(socketIOEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long messageTimestamp = 0;
|
||||||
void loop() {
|
void loop() {
|
||||||
webSocket.loop();
|
socketIO.loop();
|
||||||
|
|
||||||
if(isConnected) {
|
|
||||||
|
|
||||||
uint64_t now = millis();
|
uint64_t now = millis();
|
||||||
|
|
||||||
if(now - messageTimestamp > MESSAGE_INTERVAL) {
|
if(now - messageTimestamp > 2000) {
|
||||||
messageTimestamp = now;
|
messageTimestamp = now;
|
||||||
// example socket.io message with type "messageType" and JSON payload
|
|
||||||
webSocket.sendTXT("42[\"messageType\",{\"greeting\":\"hello\"}]");
|
// creat JSON message for Socket.IO (event)
|
||||||
}
|
DynamicJsonDocument doc(1024);
|
||||||
if((now - heartbeatTimestamp) > HEARTBEAT_INTERVAL) {
|
JsonArray array = doc.to<JsonArray>();
|
||||||
heartbeatTimestamp = now;
|
|
||||||
// socket.io heartbeat message
|
// add evnet name
|
||||||
webSocket.sendTXT("2");
|
// Hint: socket.on('event_name', ....
|
||||||
}
|
array.add("event_name");
|
||||||
|
|
||||||
|
// add payload (parameters) for the event
|
||||||
|
JsonObject param1 = array.createNestedObject();
|
||||||
|
param1["now"] = now;
|
||||||
|
|
||||||
|
// JSON to String (serializion)
|
||||||
|
String output;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
|
||||||
|
// Send event
|
||||||
|
socketIO.sendEVENT(output);
|
||||||
|
|
||||||
|
// Print JSON for debugging
|
||||||
|
USE_SERIAL.println(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
174
src/SocketIOclient.cpp
Normal file
174
src/SocketIOclient.cpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* SocketIOclient.cpp
|
||||||
|
*
|
||||||
|
* Created on: May 12, 2018
|
||||||
|
* Author: links
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "WebSockets.h"
|
||||||
|
#include "WebSocketsClient.h"
|
||||||
|
#include "SocketIOclient.h"
|
||||||
|
|
||||||
|
SocketIOclient::SocketIOclient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set callback function
|
||||||
|
* @param cbEvent SocketIOclientEvent
|
||||||
|
*/
|
||||||
|
void SocketIOclient::onEvent(SocketIOclientEvent cbEvent) {
|
||||||
|
_cbEvent = cbEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::isConnected(void) {
|
||||||
|
return WebSocketsClient::isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send text data to client
|
||||||
|
* @param num uint8_t client id
|
||||||
|
* @param payload uint8_t *
|
||||||
|
* @param length size_t
|
||||||
|
* @param headerToPayload bool (see sendFrame for more details)
|
||||||
|
* @return true if ok
|
||||||
|
*/
|
||||||
|
bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) {
|
||||||
|
bool ret = false;
|
||||||
|
if(length == 0) {
|
||||||
|
length = strlen((const char *)payload);
|
||||||
|
}
|
||||||
|
if(clientIsConnected(&_client)) {
|
||||||
|
if(!headerToPayload) {
|
||||||
|
// webSocket Header
|
||||||
|
ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true);
|
||||||
|
// Engine.IO / Socket.IO Header
|
||||||
|
if(ret) {
|
||||||
|
uint8_t buf[3] = { eIOtype_MESSAGE, sIOtype_EVENT, 0x00 };
|
||||||
|
ret = WebSocketsClient::write(&_client, buf, 2);
|
||||||
|
}
|
||||||
|
if(ret && payload && length > 0) {
|
||||||
|
ret = WebSocketsClient::write(&_client, payload, length);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
// TODO implement
|
||||||
|
}
|
||||||
|
|
||||||
|
// return WebSocketsClient::sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::sendEVENT(const uint8_t * payload, size_t length) {
|
||||||
|
return sendEVENT((uint8_t *)payload, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::sendEVENT(char * payload, size_t length, bool headerToPayload) {
|
||||||
|
return sendEVENT((uint8_t *)payload, length, headerToPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::sendEVENT(const char * payload, size_t length) {
|
||||||
|
return sendEVENT((uint8_t *)payload, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketIOclient::sendEVENT(String & payload) {
|
||||||
|
return sendEVENT((uint8_t *)payload.c_str(), payload.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::loop(void) {
|
||||||
|
WebSocketsClient::loop();
|
||||||
|
unsigned long t = millis();
|
||||||
|
if((t - _lastConnectionFail) > EIO_HEARTBEAT_INTERVAL) {
|
||||||
|
_lastConnectionFail = t;
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] send ping\n");
|
||||||
|
WebSocketsClient::sendTXT(eIOtype_PING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
runIOCbEvent(sIOtype_DISCONNECT, NULL, 0);
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] Disconnected!\n");
|
||||||
|
break;
|
||||||
|
case WStype_CONNECTED: {
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload);
|
||||||
|
// send message to server when Connected
|
||||||
|
// Engine.io upgrade confirmation message (required)
|
||||||
|
WebSocketsClient::sendTXT(eIOtype_UPGRADE);
|
||||||
|
runIOCbEvent(sIOtype_CONNECT, payload, length);
|
||||||
|
} break;
|
||||||
|
case WStype_TEXT: {
|
||||||
|
if(length < 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
engineIOmessageType_t eType = (engineIOmessageType_t)payload[0];
|
||||||
|
switch(eType) {
|
||||||
|
case eIOtype_PING:
|
||||||
|
payload[0] = eIOtype_PONG;
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get ping send pong (%s)\n", payload);
|
||||||
|
WebSocketsClient::sendTXT(payload, length, false);
|
||||||
|
break;
|
||||||
|
case eIOtype_PONG:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get pong\n");
|
||||||
|
break;
|
||||||
|
case eIOtype_MESSAGE: {
|
||||||
|
if(length < 2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
socketIOmessageType_t ioType = (socketIOmessageType_t)payload[1];
|
||||||
|
uint8_t * data = &payload[2];
|
||||||
|
size_t lData = length - 2;
|
||||||
|
switch(ioType) {
|
||||||
|
case sIOtype_EVENT:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data);
|
||||||
|
break;
|
||||||
|
case sIOtype_CONNECT:
|
||||||
|
case sIOtype_DISCONNECT:
|
||||||
|
case sIOtype_ACK:
|
||||||
|
case sIOtype_ERROR:
|
||||||
|
case sIOtype_BINARY_EVENT:
|
||||||
|
case sIOtype_BINARY_ACK:
|
||||||
|
default:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] Socket.IO Message Type %c (%02X) is not implemented\n", ioType, ioType);
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
runIOCbEvent(ioType, data, lData);
|
||||||
|
} break;
|
||||||
|
case eIOtype_OPEN:
|
||||||
|
case eIOtype_CLOSE:
|
||||||
|
case eIOtype_UPGRADE:
|
||||||
|
case eIOtype_NOOP:
|
||||||
|
default:
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] Engine.IO Message Type %c (%02X) is not implemented\n", eType, eType);
|
||||||
|
DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case WStype_BIN:
|
||||||
|
case WStype_FRAGMENT_TEXT_START:
|
||||||
|
case WStype_FRAGMENT_BIN_START:
|
||||||
|
case WStype_FRAGMENT:
|
||||||
|
case WStype_FRAGMENT_FIN:
|
||||||
|
case WStype_PING:
|
||||||
|
case WStype_PONG:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
80
src/SocketIOclient.h
Normal file
80
src/SocketIOclient.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* SocketIOclient.h
|
||||||
|
*
|
||||||
|
* Created on: May 12, 2018
|
||||||
|
* Author: links
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOCKETIOCLIENT_H_
|
||||||
|
#define SOCKETIOCLIENT_H_
|
||||||
|
|
||||||
|
#include "WebSockets.h"
|
||||||
|
|
||||||
|
#define EIO_HEARTBEAT_INTERVAL 20000
|
||||||
|
|
||||||
|
#define EIO_MAX_HEADER_SIZE (WEBSOCKETS_MAX_HEADER_SIZE + 1)
|
||||||
|
#define SIO_MAX_HEADER_SIZE (EIO_MAX_HEADER_SIZE + 1)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
eIOtype_OPEN = '0', ///< Sent from the server when a new transport is opened (recheck)
|
||||||
|
eIOtype_CLOSE = '1', ///< Request the close of this transport but does not shutdown the connection itself.
|
||||||
|
eIOtype_PING = '2', ///< Sent by the client. Server should answer with a pong packet containing the same data
|
||||||
|
eIOtype_PONG = '3', ///< Sent by the server to respond to ping packets.
|
||||||
|
eIOtype_MESSAGE = '4', ///< actual message, client and server should call their callbacks with the data
|
||||||
|
eIOtype_UPGRADE = '5', ///< Before engine.io switches a transport, it tests, if server and client can communicate over this transport. If this test succeed, the client sends an upgrade packets which requests the server to flush its cache on the old transport and switch to the new transport.
|
||||||
|
eIOtype_NOOP = '6', ///< A noop packet. Used primarily to force a poll cycle when an incoming websocket connection is received.
|
||||||
|
} engineIOmessageType_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
sIOtype_CONNECT = '0',
|
||||||
|
sIOtype_DISCONNECT = '1',
|
||||||
|
sIOtype_EVENT = '2',
|
||||||
|
sIOtype_ACK = '3',
|
||||||
|
sIOtype_ERROR = '4',
|
||||||
|
sIOtype_BINARY_EVENT = '5',
|
||||||
|
sIOtype_BINARY_ACK = '6',
|
||||||
|
} socketIOmessageType_t;
|
||||||
|
|
||||||
|
class SocketIOclient : protected WebSocketsClient {
|
||||||
|
public:
|
||||||
|
#ifdef __AVR__
|
||||||
|
typedef void (*SocketIOclientEvent)(socketIOmessageType_t type, uint8_t * payload, size_t length);
|
||||||
|
#else
|
||||||
|
typedef std::function<void(socketIOmessageType_t type, uint8_t * payload, size_t length)> SocketIOclientEvent;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SocketIOclient(void);
|
||||||
|
virtual ~SocketIOclient(void);
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
bool isConnected(void);
|
||||||
|
|
||||||
|
void onEvent(SocketIOclientEvent cbEvent);
|
||||||
|
|
||||||
|
bool sendEVENT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool sendEVENT(const uint8_t * payload, size_t length = 0);
|
||||||
|
bool sendEVENT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
|
bool sendEVENT(const char * payload, size_t length = 0);
|
||||||
|
bool sendEVENT(String & payload);
|
||||||
|
|
||||||
|
void loop(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint64_t _lastHeartbeat = 0;
|
||||||
|
SocketIOclientEvent _cbEvent;
|
||||||
|
virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
|
||||||
|
if(_cbEvent) {
|
||||||
|
_cbEvent(type, payload, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handeling events from websocket layer
|
||||||
|
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||||
|
handleCbEvent(type, payload, length);
|
||||||
|
}
|
||||||
|
void handleCbEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SOCKETIOCLIENT_H_ */
|
@ -70,6 +70,112 @@ void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * rea
|
|||||||
clientDisconnect(client);
|
clientDisconnect(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param buf uint8_t * ptr to the buffer for writing
|
||||||
|
* @param opcode WSopcode_t
|
||||||
|
* @param length size_t length of the payload
|
||||||
|
* @param mask bool add dummy mask to the frame (needed for web browser)
|
||||||
|
* @param maskkey uint8_t[4] key used for payload
|
||||||
|
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||||
|
*/
|
||||||
|
uint8_t WebSockets::createHeader(uint8_t * headerPtr, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin) {
|
||||||
|
uint8_t headerSize;
|
||||||
|
// calculate header Size
|
||||||
|
if(length < 126) {
|
||||||
|
headerSize = 2;
|
||||||
|
} else if(length < 0xFFFF) {
|
||||||
|
headerSize = 4;
|
||||||
|
} else {
|
||||||
|
headerSize = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mask) {
|
||||||
|
headerSize += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
*headerPtr = maskKey[0];
|
||||||
|
headerPtr++;
|
||||||
|
*headerPtr = maskKey[1];
|
||||||
|
headerPtr++;
|
||||||
|
*headerPtr = maskKey[2];
|
||||||
|
headerPtr++;
|
||||||
|
*headerPtr = maskKey[3];
|
||||||
|
headerPtr++;
|
||||||
|
}
|
||||||
|
return headerSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param client WSclient_t * ptr to the client struct
|
||||||
|
* @param opcode WSopcode_t
|
||||||
|
* @param length size_t length of the payload
|
||||||
|
* @param fin bool can be used to send data in more then one frame (set fin on the last frame)
|
||||||
|
* @return true if ok
|
||||||
|
*/
|
||||||
|
bool WebSockets::sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length, bool fin) {
|
||||||
|
uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 };
|
||||||
|
|
||||||
|
uint8_t headerSize = createHeader(&buffer[0], opcode, length, client->cIsClient, maskKey, fin);
|
||||||
|
|
||||||
|
if(write(client, &buffer[0], headerSize) != headerSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param client WSclient_t * ptr to the client struct
|
* @param client WSclient_t * ptr to the client struct
|
||||||
@ -143,64 +249,17 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
headerPtr = &buffer[0];
|
headerPtr = &buffer[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// create header
|
if(client->cIsClient && useInternBuffer) {
|
||||||
|
|
||||||
// byte 0
|
|
||||||
*headerPtr = 0x00;
|
|
||||||
if(fin) {
|
|
||||||
*headerPtr |= bit(7); ///< set Fin
|
|
||||||
}
|
|
||||||
*headerPtr |= opcode; ///< set opcode
|
|
||||||
headerPtr++;
|
|
||||||
|
|
||||||
// byte 1
|
|
||||||
*headerPtr = 0x00;
|
|
||||||
if(client->cIsClient) {
|
|
||||||
*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(client->cIsClient) {
|
|
||||||
if(useInternBuffer) {
|
|
||||||
// if we use a Intern Buffer we can modify the data
|
// if we use a Intern Buffer we can modify the data
|
||||||
// by this fact its possible the do the masking
|
// by this fact its possible the do the masking
|
||||||
for(uint8_t x = 0; x < sizeof(maskKey); x++) {
|
for(uint8_t x = 0; x < sizeof(maskKey); x++) {
|
||||||
maskKey[x] = random(0xFF);
|
maskKey[x] = random(0xFF);
|
||||||
*headerPtr = maskKey[x];
|
}
|
||||||
headerPtr++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createHeader(headerPtr, opcode, length, client->cIsClient, maskKey, fin);
|
||||||
|
|
||||||
|
if(client->cIsClient && useInternBuffer) {
|
||||||
uint8_t * dataMaskPtr;
|
uint8_t * dataMaskPtr;
|
||||||
|
|
||||||
if(headerToPayload) {
|
if(headerToPayload) {
|
||||||
@ -212,17 +271,6 @@ bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
|
|||||||
for(size_t x = 0; x < length; x++) {
|
for(size_t x = 0; x < length; x++) {
|
||||||
dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]);
|
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
|
#ifndef NODEBUG_WEBSOCKETS
|
||||||
|
@ -298,9 +298,12 @@ class WebSockets {
|
|||||||
virtual void clientDisconnect(WSclient_t * client) = 0;
|
virtual void clientDisconnect(WSclient_t * client) = 0;
|
||||||
virtual bool clientIsConnected(WSclient_t * client) = 0;
|
virtual bool clientIsConnected(WSclient_t * client) = 0;
|
||||||
|
|
||||||
|
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
|
||||||
|
|
||||||
virtual void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) = 0;
|
virtual void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) = 0;
|
||||||
|
|
||||||
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
|
uint8_t createHeader(uint8_t * buf, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin);
|
||||||
|
bool sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length = 0, bool fin = true);
|
||||||
bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool fin = true, bool headerToPayload = false);
|
bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool fin = true, bool headerToPayload = false);
|
||||||
|
|
||||||
void headerDone(WSclient_t * client);
|
void headerDone(WSclient_t * client);
|
||||||
|
@ -254,6 +254,12 @@ bool WebSocketsClient::sendTXT(String & payload) {
|
|||||||
return sendTXT((uint8_t *)payload.c_str(), payload.length());
|
return sendTXT((uint8_t *)payload.c_str(), payload.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebSocketsClient::sendTXT(char payload) {
|
||||||
|
uint8_t buf[WEBSOCKETS_MAX_HEADER_SIZE + 2] = { 0x00 };
|
||||||
|
buf[WEBSOCKETS_MAX_HEADER_SIZE] = payload;
|
||||||
|
return sendTXT(buf, 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* send binary data to client
|
* send binary data to client
|
||||||
* @param num uint8_t client id
|
* @param num uint8_t client id
|
||||||
@ -346,6 +352,10 @@ void WebSocketsClient::setReconnectInterval(unsigned long time) {
|
|||||||
_reconnectInterval = time;
|
_reconnectInterval = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebSocketsClient::isConnected(void) {
|
||||||
|
return (_client.status == WSC_CONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
//#################################################################################
|
//#################################################################################
|
||||||
@ -697,6 +707,13 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
|
|||||||
|
|
||||||
runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
|
runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
|
||||||
} else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) {
|
} 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
sendHeader(client);
|
sendHeader(client);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
|
||||||
@ -745,7 +762,7 @@ void WebSocketsClient::connectedCb() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if(_client.isSSL && !_CA_cert) {
|
} else if(_client.isSSL && !_CA_cert) {
|
||||||
#if defined(wificlientbearssl_h) && !defined(USING_AXTLS)
|
#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
|
||||||
_client.ssl->setInsecure();
|
_client.ssl->setInsecure();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
|
|
||||||
class WebSocketsClient : private WebSockets {
|
class WebSocketsClient : protected WebSockets {
|
||||||
public:
|
public:
|
||||||
#ifdef __AVR__
|
#ifdef __AVR__
|
||||||
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
|
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
|
||||||
@ -71,6 +71,7 @@ class WebSocketsClient : private WebSockets {
|
|||||||
bool sendTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
bool sendTXT(char * payload, size_t length = 0, bool headerToPayload = false);
|
||||||
bool sendTXT(const char * payload, size_t length = 0);
|
bool sendTXT(const char * payload, size_t length = 0);
|
||||||
bool sendTXT(String & payload);
|
bool sendTXT(String & payload);
|
||||||
|
bool sendTXT(char payload);
|
||||||
|
|
||||||
bool sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
bool sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
|
||||||
bool sendBIN(const uint8_t * payload, size_t length);
|
bool sendBIN(const uint8_t * payload, size_t length);
|
||||||
@ -94,6 +95,8 @@ class WebSocketsClient : private WebSockets {
|
|||||||
String _host;
|
String _host;
|
||||||
uint16_t _port;
|
uint16_t _port;
|
||||||
|
|
||||||
|
bool isConnected(void);
|
||||||
|
|
||||||
#if defined(HAS_SSL)
|
#if defined(HAS_SSL)
|
||||||
String _fingerprint;
|
String _fingerprint;
|
||||||
const char * _CA_cert;
|
const char * _CA_cert;
|
||||||
|
Reference in New Issue
Block a user