mirror of
https://github.com/Links2004/arduinoWebSockets.git
synced 2025-07-12 23:16:29 +02:00
esp8266 to browser working
This commit is contained in:
@ -25,39 +25,70 @@
|
|||||||
#include "WebSockets.h"
|
#include "WebSockets.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
0 1 2 3
|
|
||||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
||||||
+-+-+-+-+-------+-+-------------+-------------------------------+
|
|
||||||
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|
|
||||||
|I|S|S|S| (4) |A| (7) | (16/64) |
|
|
||||||
|N|V|V|V| |S| | (if payload len==126/127) |
|
|
||||||
| |1|2|3| |K| | |
|
|
||||||
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
|
||||||
| Extended payload length continued, if payload len == 127 |
|
|
||||||
+ - - - - - - - - - - - - - - - +-------------------------------+
|
|
||||||
| |Masking-key, if MASK set to 1 |
|
|
||||||
+-------------------------------+-------------------------------+
|
|
||||||
| Masking-key (continued) | Payload Data |
|
|
||||||
+-------------------------------- - - - - - - - - - - - - - - - +
|
|
||||||
: Payload Data continued ... :
|
|
||||||
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|
|
||||||
| Payload Data continued ... |
|
|
||||||
+---------------------------------------------------------------+
|
|
||||||
*
|
*
|
||||||
|
* @param client WSclient_t * ptr to the client struct
|
||||||
|
* @param code
|
||||||
|
* @param reason
|
||||||
|
* @param reasonLen
|
||||||
*/
|
*/
|
||||||
|
void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) {
|
||||||
|
if(client->status == WSC_CONNECTED && code) {
|
||||||
|
//todo send reason to client
|
||||||
|
|
||||||
typedef enum {
|
if(reasonLen > 0 && reason) {
|
||||||
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;
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clientDisconnect(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param client WSclient_t * ptr to the client struct
|
||||||
|
* @param opcode WSopcode_t
|
||||||
|
* @param payload uint8_t *
|
||||||
|
* @param lenght size_t
|
||||||
|
*/
|
||||||
|
void WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) {
|
||||||
|
|
||||||
|
uint8_t buffer[16] = { 0 };
|
||||||
|
uint8_t i = 0;
|
||||||
|
|
||||||
|
//create header
|
||||||
|
|
||||||
|
buffer[i] = bit(7); // set Fin
|
||||||
|
buffer[i++] |= opcode; // set opcode
|
||||||
|
|
||||||
|
if(lenght < 126) {
|
||||||
|
buffer[i++] = lenght;
|
||||||
|
|
||||||
|
} else if(lenght < 0xFFFF) {
|
||||||
|
buffer[i++] = 126;
|
||||||
|
buffer[i++] = ((lenght >> 8) & 0xFF);
|
||||||
|
buffer[i++] = (lenght & 0xFF);
|
||||||
|
} else {
|
||||||
|
buffer[i++] = 127;
|
||||||
|
buffer[i++] = 0x00;
|
||||||
|
buffer[i++] = 0x00;
|
||||||
|
buffer[i++] = 0x00;
|
||||||
|
buffer[i++] = 0x00;
|
||||||
|
buffer[i++] = ((lenght >> 24) & 0xFF);
|
||||||
|
buffer[i++] = ((lenght >> 16) & 0xFF);
|
||||||
|
buffer[i++] = ((lenght >> 8) & 0xFF);
|
||||||
|
buffer[i++] = (lenght & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send header
|
||||||
|
client->tcp.write(&buffer[0], i);
|
||||||
|
|
||||||
|
if(payload && lenght > 0) {
|
||||||
|
// send payload
|
||||||
|
client->tcp.write(&payload[0], lenght);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handle the WebSocket stream
|
* handle the WebSocket stream
|
||||||
@ -83,7 +114,7 @@ void WebSockets::handleWebsocket(WSclient_t * client) {
|
|||||||
|
|
||||||
if(!readWait(client, buffer, 2)) {
|
if(!readWait(client, buffer, 2)) {
|
||||||
//timeout
|
//timeout
|
||||||
clientDisconnect(client);
|
clientDisconnect(client, 1002);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,15 +123,15 @@ void WebSockets::handleWebsocket(WSclient_t * client) {
|
|||||||
rsv1 = ((buffer[0] >> 6) & 0x01);
|
rsv1 = ((buffer[0] >> 6) & 0x01);
|
||||||
rsv2 = ((buffer[0] >> 5) & 0x01);
|
rsv2 = ((buffer[0] >> 5) & 0x01);
|
||||||
rsv3 = ((buffer[0] >> 4) & 0x01);
|
rsv3 = ((buffer[0] >> 4) & 0x01);
|
||||||
opCode = (WSopcode_t)(buffer[0] & 0x0F);
|
opCode = (WSopcode_t) (buffer[0] & 0x0F);
|
||||||
|
|
||||||
mask = ((buffer[1] >> 7) & 0x01);
|
mask = ((buffer[1] >> 7) & 0x01);
|
||||||
payloadLen = (WSopcode_t)(buffer[1] & 0x7F);
|
payloadLen = (WSopcode_t) (buffer[1] & 0x7F);
|
||||||
|
|
||||||
if(payloadLen == 126) {
|
if(payloadLen == 126) {
|
||||||
if(!readWait(client, buffer, 2)) {
|
if(!readWait(client, buffer, 2)) {
|
||||||
//timeout
|
//timeout
|
||||||
clientDisconnect(client);
|
clientDisconnect(client, 1002);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
payloadLen = buffer[0] << 8 | buffer[1];
|
payloadLen = buffer[0] << 8 | buffer[1];
|
||||||
@ -108,7 +139,7 @@ void WebSockets::handleWebsocket(WSclient_t * client) {
|
|||||||
// read 64bit inteager as Lenght
|
// read 64bit inteager as Lenght
|
||||||
if(!readWait(client, buffer, 8)) {
|
if(!readWait(client, buffer, 8)) {
|
||||||
//timeout
|
//timeout
|
||||||
clientDisconnect(client);
|
clientDisconnect(client, 1002);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +156,7 @@ void WebSockets::handleWebsocket(WSclient_t * client) {
|
|||||||
|
|
||||||
if(payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
|
if(payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] payload to big! (%u)\n", client->num, payloadLen);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] payload to big! (%u)\n", client->num, payloadLen);
|
||||||
clientDisconnect(client);
|
clientDisconnect(client, 1009);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,37 +166,77 @@ void WebSockets::handleWebsocket(WSclient_t * client) {
|
|||||||
|
|
||||||
if(payloadLen > 0) {
|
if(payloadLen > 0) {
|
||||||
// if text data we need one more
|
// if text data we need one more
|
||||||
payload = (uint8_t *) malloc(payloadLen+1);
|
payload = (uint8_t *) malloc(payloadLen + 1);
|
||||||
|
|
||||||
if(!payload) {
|
if(!payload) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, payloadLen);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, payloadLen);
|
||||||
clientDisconnect(client);
|
clientDisconnect(client, 1011);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!readWait(client, payload, payloadLen)) {
|
if(!readWait(client, payload, payloadLen)) {
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] missing data!\n", client->num);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] missing data!\n", client->num);
|
||||||
clientDisconnect(client);
|
clientDisconnect(client, 1002);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
payload[payloadLen] = 0x00;
|
||||||
|
|
||||||
if(mask) {
|
if(mask) {
|
||||||
//decode XOR
|
//decode XOR
|
||||||
for (size_t i = 0; i < payloadLen; i++) {
|
for(size_t i = 0; i < payloadLen; i++) {
|
||||||
payload[i] = (payload[i] ^ maskKey[i % 4]);
|
payload[i] = (payload[i] ^ maskKey[i % 4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(opCode == WSop_text) {
|
switch(opCode) {
|
||||||
payload[payloadLen] = 0x00;
|
case WSop_text:
|
||||||
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] Text: %s\n", client->num, payload);
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] text: %s\n", client->num, payload)
|
||||||
} else {
|
;
|
||||||
clientDisconnect(client);
|
// todo API for user to get message may callback
|
||||||
|
|
||||||
|
// send the frame back!
|
||||||
|
sendFrame(client, WSop_text, payload, payloadLen);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case WSop_binary:
|
||||||
|
// todo API for user to get message may callback
|
||||||
|
break;
|
||||||
|
case WSop_ping:
|
||||||
|
// todo send pong
|
||||||
|
break;
|
||||||
|
case WSop_pong:
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] get pong from Client (%s)\n", client->num, payload)
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
case WSop_close: {
|
||||||
|
uint16_t reasonCode = buffer[0] << 8 | buffer[1];
|
||||||
|
|
||||||
|
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] client ask for close. Code: %d (%s)\n", client->num, reasonCode, (payload + 2));
|
||||||
|
|
||||||
|
// todo send confimation to client
|
||||||
|
clientDisconnect(client, 1000, (char *) (payload + 2), payloadLen - 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WSop_continuation:
|
||||||
|
// continuation is not supported
|
||||||
|
clientDisconnect(client, 1003);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
clientDisconnect(client, 1002);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
bool WebSockets::readWait(WSclient_t * client, uint8_t *out, size_t n) {
|
||||||
unsigned long t = millis();
|
unsigned long t = millis();
|
||||||
size_t len;
|
size_t len;
|
||||||
|
@ -52,6 +52,17 @@ typedef enum {
|
|||||||
WSC_CONNECTED
|
WSC_CONNECTED
|
||||||
} WSclientsStatus_t;
|
} WSclientsStatus_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 {
|
typedef struct {
|
||||||
uint8_t num; ///< connection number
|
uint8_t num; ///< connection number
|
||||||
|
|
||||||
@ -81,12 +92,16 @@ typedef struct {
|
|||||||
|
|
||||||
class WebSockets {
|
class WebSockets {
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void handleWebsocket(WSclient_t * client);
|
|
||||||
|
|
||||||
virtual void clientDisconnect(WSclient_t * client);
|
virtual void clientDisconnect(WSclient_t * client);
|
||||||
virtual bool clientIsConnected(WSclient_t * client);
|
virtual bool clientIsConnected(WSclient_t * client);
|
||||||
|
|
||||||
|
|
||||||
|
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
|
||||||
|
void sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t lenght = 0);
|
||||||
|
|
||||||
|
|
||||||
|
void handleWebsocket(WSclient_t * client);
|
||||||
|
|
||||||
bool readWait(WSclient_t * client, uint8_t *out, size_t n);
|
bool readWait(WSclient_t * client, uint8_t *out, size_t n);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user