diff --git a/examples/WebSocketClientSocketIO/WebSocketClientSocketIO.ino b/examples/WebSocketClientSocketIO/WebSocketClientSocketIO.ino new file mode 100644 index 0000000..6d08b02 --- /dev/null +++ b/examples/WebSocketClientSocketIO/WebSocketClientSocketIO.ino @@ -0,0 +1,113 @@ +/* + * WebSocketClientSocketIO.ino + * + * Created on: 06.06.2016 + * + */ + +#include + +#include +#include + +#include + +#include + +ESP8266WiFiMulti WiFiMulti; +WebSocketsClient webSocket; + + +#define USE_SERIAL Serial1 + +#define MESSAGE_INTERVAL 30000 +#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 lenght) { + + + switch(type) { + case WStype_DISCONNECTED: + USE_SERIAL.printf("[WSc] Disconnected!\n"); + isConnected = false; + break; + case WStype_CONNECTED: + { + 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; + case WStype_TEXT: + USE_SERIAL.printf("[WSc] get text: %s\n", payload); + + // send message to server + // webSocket.sendTXT("message here"); + break; + case WStype_BIN: + USE_SERIAL.printf("[WSc] get binary lenght: %u\n", lenght); + hexdump(payload, lenght); + + // send data to server + // webSocket.sendBIN(payload, lenght); + break; + } + +} + +void setup() { + // USE_SERIAL.begin(921600); + USE_SERIAL.begin(115200); + + //Serial.setDebugOutput(true); + USE_SERIAL.setDebugOutput(true); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + WiFiMulti.addAP("SSID", "passpasspass"); + + //WiFi.disconnect(); + while(WiFiMulti.run() != WL_CONNECTED) { + delay(100); + } + + webSocket.begin("192.168.0.123", 81); + //webSocket.setAuthorization("user", "Password"); // HTTP Basic Authorization + webSocket.onEvent(webSocketEvent); + +} + +void loop() { + webSocket.loop(); + + if(isConnected) { + + uint64_t now = millis(); + + if(now - messageTimestamp > MESSAGE_INTERVAL) { + messageTimestamp = now; + // example socket.io message with type "messageType" and JSON payload + webSocket.sendTXT("42[\"messageType\",{\"greeting\":\"hello\"}]"); + } + if((now - heartbeatTimestamp) > HEARTBEAT_INTERVAL) { + heartbeatTimestamp = now; + // socket.io heartbeat message + webSocket.sendTXT("2"); + } + } +} diff --git a/src/WebSockets.cpp b/src/WebSockets.cpp index 3c89b9d..6e9c2af 100644 --- a/src/WebSockets.cpp +++ b/src/WebSockets.cpp @@ -296,7 +296,7 @@ bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) { } if(size > WEBSOCKETS_MAX_HEADER_SIZE) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d to big!\n", client->num, size); + DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d too big!\n", client->num, size); return false; } @@ -364,7 +364,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) { } if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) { - // really to big! + // really too big! header->payloadLen = 0xFFFFFFFF; } else { header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7]; @@ -377,7 +377,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) { DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen); if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload to big! (%u)\n", client->num, header->payloadLen); + DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload too big! (%u)\n", client->num, header->payloadLen); clientDisconnect(client, 1009); return; } @@ -596,4 +596,3 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait #endif return true; } - diff --git a/src/WebSockets.h b/src/WebSockets.h index 22b1e28..c43f4d9 100644 --- a/src/WebSockets.h +++ b/src/WebSockets.h @@ -161,6 +161,8 @@ typedef struct { WEBSOCKETS_NETWORK_CLASS * tcp; + bool isSocketIO; ///< client for socket.io server + #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) bool isSSL; ///< run in ssl mode WiFiClientSecure * ssl; @@ -172,6 +174,7 @@ typedef struct { bool cIsUpgrade; ///< Connection == Upgrade bool cIsWebsocket; ///< Upgrade == websocket + String cSessionId; ///< client Set-Cookie (session id) String cKey; ///< client Sec-WebSocket-Key String cAccept; ///< client Sec-WebSocket-Accept String cProtocol; ///< client Sec-WebSocket-Protocol diff --git a/src/WebSocketsClient.cpp b/src/WebSocketsClient.cpp index af29c97..3b93a14 100644 --- a/src/WebSocketsClient.cpp +++ b/src/WebSocketsClient.cpp @@ -91,6 +91,14 @@ void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String f } #endif +void WebSocketsClient::beginSocketIO(const char *host, uint16_t port, const char * url, const char * protocol) { + begin(host, port, url, protocol); + _client.isSocketIO = true; +} + +void WebSocketsClient::beginSocketIO(String host, uint16_t port, String url, String protocol) { + beginSocketIO(host.c_str(), port, url.c_str(), protocol.c_str()); +} #if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) /** @@ -393,22 +401,37 @@ void WebSocketsClient::sendHeader(WSclient_t * client) { unsigned long start = micros(); #endif - String handshake = "GET " + client->cUrl + " HTTP/1.1\r\n" - "Host: " + _host + ":" + _port + "\r\n" - "Connection: Upgrade\r\n" - "Upgrade: websocket\r\n" - "Origin: file://\r\n" - "User-Agent: arduino-WebSocket-Client\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Sec-WebSocket-Key: " + client->cKey + "\r\n"; + String transport; + String handshake; + if(!client->isSocketIO || (client->isSocketIO && client->cSessionId.length() > 0)) { + if(client->isSocketIO) { + transport = "&transport=websocket&sid=" + client->cSessionId; + } + handshake = "GET " + client->cUrl + transport + " HTTP/1.1\r\n" + "Host: " + _host + ":" + _port + "\r\n" + "Connection: Upgrade\r\n" + "Upgrade: websocket\r\n" + "Origin: file://\r\n" + "User-Agent: arduino-WebSocket-Client\r\n" + "Sec-WebSocket-Version: 13\r\n" + "Sec-WebSocket-Key: " + client->cKey + "\r\n"; - if(client->cProtocol.length() > 0) { - handshake += "Sec-WebSocket-Protocol: " + client->cProtocol + "\r\n"; + if(client->cProtocol.length() > 0) { + handshake += "Sec-WebSocket-Protocol: " + client->cProtocol + "\r\n"; + } + + if(client->cExtensions.length() > 0) { + handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n"; + } + + } else { + handshake = "GET " + client->cUrl + "&transport=polling HTTP/1.1\r\n" + "Connection: keep-alive\r\n"; } - if(client->cExtensions.length() > 0) { - handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n"; - } + handshake += "Host: " + _host + ":" + _port + "\r\n" + "Origin: file://\r\n" + "User-Agent: arduino-WebSocket-Client\r\n"; if(client->base64Authorization.length() > 0) { handshake += "Authorization: Basic " + client->base64Authorization + "\r\n"; @@ -465,6 +488,8 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { client->cExtensions = headerValue; } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) { client->cVersion = headerValue.toInt(); + } else if(headerName.equalsIgnoreCase("Set-Cookie")) { + client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1); } } else { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str()); @@ -490,6 +515,7 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str()); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str()); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion); + DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str()); bool ok = (client->cIsUpgrade && client->cIsWebsocket); @@ -498,6 +524,10 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { case 101: ///< Switching Protocols break; + case 200: + if(client->isSocketIO) { + break; + } case 403: ///< Forbidden // todo handle login default: ///< Server dont unterstand requrst @@ -530,6 +560,8 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { runCbEvent(WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length()); + } else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) { + sendHeader(client); } else { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n"); client->tcp->write("This is a webSocket client!"); diff --git a/src/WebSocketsClient.h b/src/WebSocketsClient.h index 9fa43bd..2a8bc3e 100644 --- a/src/WebSocketsClient.h +++ b/src/WebSocketsClient.h @@ -48,6 +48,9 @@ class WebSocketsClient: private WebSockets { void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino"); #endif + void beginSocketIO(const char *host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); + void beginSocketIO(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); + #if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) void loop(void); #else