123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 |
- /**
- * @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;
- _client.cIsClient = true;
- _client.extraHeaders = WEBSOCKETS_STRING("Origin: file://");
- }
- WebSocketsClient::~WebSocketsClient() {
- disconnect();
- }
- /**
- * calles to init the Websockets server
- */
- void WebSocketsClient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
- _host = host;
- _port = port;
- #if defined(HAS_SSL)
- _fingerprint = "";
- _CA_cert = NULL;
- #endif
- _client.num = 0;
- _client.status = WSC_NOT_CONNECTED;
- _client.tcp = NULL;
- #if defined(HAS_SSL)
- _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 = protocol;
- _client.cExtensions = "";
- _client.cVersion = 0;
- _client.base64Authorization = "";
- _client.plainAuthorization = "";
- _client.isSocketIO = false;
- _client.lastPing = 0;
- _client.pongReceived = false;
- _client.pongTimeoutCount = 0;
- #ifdef ESP8266
- randomSeed(RANDOM_REG32);
- #else
- // todo find better seed
- randomSeed(millis());
- #endif
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
- asyncConnect();
- #endif
- _lastConnectionFail = 0;
- _reconnectInterval = 500;
- }
- void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
- begin(host.c_str(), port, url.c_str(), protocol.c_str());
- }
- void WebSocketsClient::begin(IPAddress host, uint16_t port, const char * url, const char * protocol) {
- return begin(host.toString().c_str(), port, url, protocol);
- }
- #if defined(HAS_SSL)
- void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) {
- begin(host, port, url, protocol);
- _client.isSSL = true;
- _fingerprint = fingerprint;
- _CA_cert = NULL;
- }
- void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) {
- beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str(), protocol.c_str());
- }
- void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
- begin(host, port, url, protocol);
- _client.isSSL = true;
- _fingerprint = "";
- _CA_cert = CA_cert;
- }
- #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 defined(HAS_SSL)
- void WebSocketsClient::beginSocketIOSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
- begin(host, port, url, protocol);
- _client.isSocketIO = true;
- _client.isSSL = true;
- _fingerprint = "";
- }
- void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) {
- beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str());
- }
- void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
- begin(host, port, url, protocol);
- _client.isSocketIO = true;
- _client.isSSL = true;
- _fingerprint = "";
- _CA_cert = CA_cert;
- }
- #endif
- #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
- /**
- * called in arduino loop
- */
- void WebSocketsClient::loop(void) {
- if(!clientIsConnected(&_client)) {
- // do not flood the server
- if((millis() - _lastConnectionFail) < _reconnectInterval) {
- return;
- }
- #if defined(HAS_SSL)
- 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 WEBSOCKETS_NETWORK_SSL_CLASS();
- _client.tcp = _client.ssl;
- if(_CA_cert) {
- DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate");
- #if defined(ESP32)
- _client.ssl->setCACert(_CA_cert);
- #elif defined(ESP8266)
- _client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
- #else
- #error setCACert not implemented
- #endif
- }
- } else {
- DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n");
- if(_client.tcp) {
- delete _client.tcp;
- _client.tcp = NULL;
- }
- _client.tcp = new WEBSOCKETS_NETWORK_CLASS();
- }
- #else
- _client.tcp = new WEBSOCKETS_NETWORK_CLASS();
- #endif
- if(!_client.tcp) {
- DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
- return;
- }
- #if defined(ESP32)
- if(_client.tcp->connect(_host.c_str(), _port, WEBSOCKETS_TCP_TIMEOUT)) {
- #else
- if(_client.tcp->connect(_host.c_str(), _port)) {
- #endif
- connectedCb();
- _lastConnectionFail = 0;
- } else {
- connectFailedCb();
- _lastConnectionFail = millis();
- }
- } else {
- handleClientData();
- if(_client.status == WSC_CONNECTED) {
- handleHBPing();
- handleHBTimeout(&_client);
- }
- }
- }
- #endif
- /**
- * 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)
- * @return true if ok
- */
- bool WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
- if(length == 0) {
- length = strlen((const char *)payload);
- }
- if(clientIsConnected(&_client)) {
- return sendFrame(&_client, WSop_text, payload, length, true, headerToPayload);
- }
- return false;
- }
- bool WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) {
- return sendTXT((uint8_t *)payload, length);
- }
- bool WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) {
- return sendTXT((uint8_t *)payload, length, headerToPayload);
- }
- bool WebSocketsClient::sendTXT(const char * payload, size_t length) {
- return sendTXT((uint8_t *)payload, length);
- }
- bool WebSocketsClient::sendTXT(String & payload) {
- 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
- * @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 WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
- if(clientIsConnected(&_client)) {
- return sendFrame(&_client, WSop_binary, payload, length, true, headerToPayload);
- }
- return false;
- }
- bool WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) {
- return sendBIN((uint8_t *)payload, length);
- }
- /**
- * sends a WS ping to Server
- * @param payload uint8_t *
- * @param length size_t
- * @return true if ping is send out
- */
- bool WebSocketsClient::sendPing(uint8_t * payload, size_t length) {
- if(clientIsConnected(&_client)) {
- bool sent = sendFrame(&_client, WSop_ping, payload, length);
- if(sent)
- _client.lastPing = millis();
- return sent;
- }
- return false;
- }
- bool WebSocketsClient::sendPing(String & payload) {
- return sendPing((uint8_t *)payload.c_str(), payload.length());
- }
- /**
- * disconnect one client
- * @param num uint8_t client id
- */
- void WebSocketsClient::disconnect(void) {
- if(clientIsConnected(&_client)) {
- WebSockets::clientDisconnect(&_client, 1000);
- }
- }
- /**
- * set the Authorizatio for the http request
- * @param user const char *
- * @param password const char *
- */
- void WebSocketsClient::setAuthorization(const char * user, const char * password) {
- if(user && password) {
- String auth = user;
- auth += ":";
- auth += password;
- _client.base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length());
- }
- }
- /**
- * set the Authorizatio for the http request
- * @param auth const char * base64
- */
- void WebSocketsClient::setAuthorization(const char * auth) {
- if(auth) {
- //_client.base64Authorization = auth;
- _client.plainAuthorization = auth;
- }
- }
- /**
- * set extra headers for the http request;
- * separate headers by "\r\n"
- * @param extraHeaders const char * extraHeaders
- */
- void WebSocketsClient::setExtraHeaders(const char * extraHeaders) {
- _client.extraHeaders = extraHeaders;
- }
- /**
- * set the reconnect Interval
- * how long to wait after a connection initiate failed
- * @param time in ms
- */
- void WebSocketsClient::setReconnectInterval(unsigned long time) {
- _reconnectInterval = time;
- }
- bool WebSocketsClient::isConnected(void) {
- return (_client.status == WSC_CONNECTED);
- }
- //#################################################################################
- //#################################################################################
- //#################################################################################
- /**
- *
- * @param client WSclient_t * ptr to the client struct
- * @param opcode WSopcode_t
- * @param payload uint8_t *
- * @param length size_t
- */
- void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
- WStype_t type = WStype_ERROR;
- UNUSED(client);
- switch(opcode) {
- case WSop_text:
- type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
- break;
- case WSop_binary:
- type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START;
- break;
- case WSop_continuation:
- type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT;
- break;
- case WSop_ping:
- type = WStype_PING;
- break;
- case WSop_pong:
- type = WStype_PONG;
- break;
- case WSop_close:
- default:
- break;
- }
- runCbEvent(type, payload, length);
- }
- /**
- * Disconnect an client
- * @param client WSclient_t * ptr to the client struct
- */
- void WebSocketsClient::clientDisconnect(WSclient_t * client) {
- bool event = false;
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
- if(client->isSSL && client->ssl) {
- if(client->ssl->connected()) {
- client->ssl->flush();
- client->ssl->stop();
- }
- event = true;
- delete client->ssl;
- client->ssl = NULL;
- client->tcp = NULL;
- }
- #endif
- if(client->tcp) {
- if(client->tcp->connected()) {
- #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
- client->tcp->flush();
- #endif
- client->tcp->stop();
- }
- event = true;
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
- client->status = WSC_NOT_CONNECTED;
- #else
- delete client->tcp;
- #endif
- client->tcp = NULL;
- }
- client->cCode = 0;
- client->cKey = "";
- client->cAccept = "";
- client->cVersion = 0;
- client->cIsUpgrade = false;
- client->cIsWebsocket = false;
- client->cSessionId = "";
- client->status = WSC_NOT_CONNECTED;
- DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
- if(event) {
- 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;
- }
- #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
- /**
- * Handel incomming data from Client
- */
- void WebSocketsClient::handleClientData(void) {
- int len = _client.tcp->available();
- if(len > 0) {
- switch(_client.status) {
- case WSC_HEADER: {
- String headerLine = _client.tcp->readStringUntil('\n');
- handleHeader(&_client, &headerLine);
- } break;
- case WSC_CONNECTED:
- WebSockets::handleWebsocket(&_client);
- break;
- default:
- WebSockets::clientDisconnect(&_client, 1002);
- break;
- }
- }
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
- delay(0);
- #endif
- }
- #endif
- /**
- * send the WebSocket header to Server
- * @param client WSclient_t * ptr to the client struct
- */
- void WebSocketsClient::sendHeader(WSclient_t * client) {
- static const char * NEW_LINE = "\r\n";
- 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;
- bool ws_header = true;
- String url = client->cUrl;
- if(client->isSocketIO) {
- if(client->cSessionId.length() == 0) {
- url += WEBSOCKETS_STRING("&transport=polling");
- ws_header = false;
- } else {
- url += WEBSOCKETS_STRING("&transport=websocket&sid=");
- url += client->cSessionId;
- }
- }
- handshake = WEBSOCKETS_STRING("GET ");
- handshake += url + WEBSOCKETS_STRING(
- " HTTP/1.1\r\n"
- "Host: ");
- handshake += _host + ":" + _port + NEW_LINE;
- if(ws_header) {
- handshake += WEBSOCKETS_STRING(
- "Connection: Upgrade\r\n"
- "Upgrade: websocket\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Sec-WebSocket-Key: ");
- handshake += client->cKey + NEW_LINE;
- if(client->cProtocol.length() > 0) {
- handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
- handshake += client->cProtocol + NEW_LINE;
- }
- if(client->cExtensions.length() > 0) {
- handshake += WEBSOCKETS_STRING("Sec-WebSocket-Extensions: ");
- handshake += client->cExtensions + NEW_LINE;
- }
- } else {
- handshake += WEBSOCKETS_STRING("Connection: keep-alive\r\n");
- }
- // add extra headers; by default this includes "Origin: file://"
- if(client->extraHeaders) {
- handshake += client->extraHeaders + NEW_LINE;
- }
- handshake += WEBSOCKETS_STRING("User-Agent: arduino-WebSocket-Client\r\n");
- if(client->base64Authorization.length() > 0) {
- handshake += WEBSOCKETS_STRING("Authorization: Basic ");
- handshake += client->base64Authorization + NEW_LINE;
- }
- if(client->plainAuthorization.length() > 0) {
- handshake += WEBSOCKETS_STRING("Authorization: ");
- handshake += client->plainAuthorization + NEW_LINE;
- }
- handshake += NEW_LINE;
- DEBUG_WEBSOCKETS("[WS-Client][sendHeader] handshake %s", (uint8_t *)handshake.c_str());
- write(client, (uint8_t *)handshake.c_str(), handshake.length());
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
- client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
- #endif
- DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start));
- }
- /**
- * handle the WebSocket header reading
- * @param client WSclient_t * ptr to the client struct
- */
- void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
- headerLine->trim(); // remove \r
- if(headerLine->length() > 0) {
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
- if(headerLine->startsWith(WEBSOCKETS_STRING("HTTP/1."))) {
- // "HTTP/1.1 101 Switching Protocols"
- client->cCode = headerLine->substring(9, headerLine->indexOf(' ', 9)).toInt();
- } else if(headerLine->indexOf(':') >= 0) {
- String headerName = headerLine->substring(0, headerLine->indexOf(':'));
- String headerValue = headerLine->substring(headerLine->indexOf(':') + 1);
- // remove space in the beginning (RFC2616)
- if(headerValue[0] == ' ') {
- headerValue.remove(0, 1);
- }
- if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
- if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("upgrade"))) {
- client->cIsUpgrade = true;
- }
- } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
- if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
- client->cIsWebsocket = true;
- }
- } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Accept"))) {
- client->cAccept = headerValue;
- client->cAccept.trim(); // see rfc6455
- } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
- client->cProtocol = headerValue;
- } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
- client->cExtensions = headerValue;
- } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
- client->cVersion = headerValue.toInt();
- } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) {
- if(headerValue.indexOf(WEBSOCKETS_STRING("HttpOnly")) > -1) {
- client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
- } else {
- client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
- }
- }
- } else {
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
- }
- (*headerLine) = "";
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
- client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
- #endif
- } 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", client->cUrl.c_str());
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cKey: %s\n", client->cKey.c_str());
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Server header:\n");
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cCode: %d\n", client->cCode);
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsUpgrade: %d\n", client->cIsUpgrade);
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsWebsocket: %d\n", client->cIsWebsocket);
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cAccept: %s\n", client->cAccept.c_str());
- 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);
- if(ok) {
- switch(client->cCode) {
- case 101: ///< Switching Protocols
- break;
- case 200:
- if(client->isSocketIO) {
- 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", client->cCode);
- clientDisconnect(client);
- _lastConnectionFail = millis();
- 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");
- headerDone(client);
- runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
- } 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);
- } else {
- DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
- _lastConnectionFail = millis();
- if(clientIsConnected(client)) {
- write(client, "This is a webSocket client!");
- }
- clientDisconnect(client);
- }
- }
- }
- void WebSocketsClient::connectedCb() {
- DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n", _host.c_str(), _port);
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
- _client.tcp->onDisconnect(std::bind([](WebSocketsClient * c, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
- DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
- client->status = WSC_NOT_CONNECTED;
- client->tcp = NULL;
- // reconnect
- c->asyncConnect();
- return true;
- },
- this, std::placeholders::_1, &_client));
- #endif
- _client.status = WSC_HEADER;
- #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
- // set Timeout for readBytesUntil and readStringUntil
- _client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
- #endif
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
- _client.tcp->setNoDelay(true);
- #endif
- #if defined(HAS_SSL)
- 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;
- }
- } else if(_client.isSSL && !_CA_cert) {
- #if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
- _client.ssl->setInsecure();
- #endif
- }
- #endif
- // send Header to Server
- sendHeader(&_client);
- }
- void WebSocketsClient::connectFailedCb() {
- DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Failed\n", _host.c_str(), _port);
- }
- #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
- void WebSocketsClient::asyncConnect() {
- DEBUG_WEBSOCKETS("[WS-Client] asyncConnect...\n");
- AsyncClient * tcpclient = new AsyncClient();
- if(!tcpclient) {
- DEBUG_WEBSOCKETS("[WS-Client] creating AsyncClient class failed!\n");
- return;
- }
- tcpclient->onDisconnect([](void * obj, AsyncClient * c) {
- c->free();
- delete c;
- });
- tcpclient->onConnect(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
- ws->_client.tcp = new AsyncTCPbuffer(tcp);
- if(!ws->_client.tcp) {
- DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!\n");
- ws->connectFailedCb();
- return;
- }
- ws->connectedCb();
- },
- this, std::placeholders::_2));
- tcpclient->onError(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
- ws->connectFailedCb();
- // reconnect
- ws->asyncConnect();
- },
- this, std::placeholders::_2));
- if(!tcpclient->connect(_host.c_str(), _port)) {
- connectFailedCb();
- delete tcpclient;
- }
- }
- #endif
- /**
- * send heartbeat ping to server in set intervals
- */
- void WebSocketsClient::handleHBPing() {
- if(_client.pingInterval == 0)
- return;
- uint32_t pi = millis() - _client.lastPing;
- if(pi > _client.pingInterval) {
- DEBUG_WEBSOCKETS("[WS-Client] sending HB ping\n");
- if(sendPing()) {
- _client.lastPing = millis();
- _client.pongReceived = false;
- }
- }
- }
- /**
- * enable ping/pong heartbeat process
- * @param pingInterval uint32_t how often ping will be sent
- * @param pongTimeout uint32_t millis after which pong should timout if not received
- * @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
- */
- void WebSocketsClient::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
- WebSockets::enableHeartbeat(&_client, pingInterval, pongTimeout, disconnectTimeoutCount);
- }
- /**
- * disable ping/pong heartbeat process
- */
- void WebSocketsClient::disableHeartbeat() {
- _client.pingInterval = 0;
- }
|