2015-05-22 14:19:01 +02:00
/**
* @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"
2020-11-21 14:06:30 +01:00
WebSocketsServerCore :: WebSocketsServerCore ( const String & origin , const String & protocol ) {
2020-05-03 09:28:55 +02:00
_origin = origin ;
_protocol = protocol ;
_runnning = false ;
_pingInterval = 0 ;
_pongTimeout = 0 ;
2020-02-10 19:45:55 +01:00
_disconnectTimeoutCount = 0 ;
2016-01-14 17:28:00 +01:00
2015-05-22 23:02:47 +02:00
_cbEvent = NULL ;
2016-06-08 23:04:18 +01:00
_httpHeaderValidationFunc = NULL ;
2019-06-10 12:57:49 +02:00
_mandatoryHttpHeaders = NULL ;
2016-06-08 23:04:18 +01:00
_mandatoryHttpHeaderCount = 0 ;
2017-10-06 18:30:05 +02:00
memset ( & _clients [ 0 ], 0x00 , ( sizeof ( WSclient_t ) * WEBSOCKETS_SERVER_CLIENT_MAX ));
2015-05-22 14:19:01 +02:00
}
2015-05-22 20:35:51 +02:00
2020-11-21 14:06:30 +01:00
WebSocketsServer :: WebSocketsServer ( uint16_t port , const String & origin , const String & protocol )
: WebSocketsServerCore ( origin , protocol ) {
_port = port ;
2020-11-21 13:51:16 +01:00
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS ( port );
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
_server -> onClient ([]( void * s , AsyncClient * c ) {
(( WebSocketsServerCore * ) s ) -> newClient ( new AsyncTCPbuffer ( c ));
},
this );
#endif
}
WebSocketsServerCore ::~ WebSocketsServerCore () {
2015-12-10 09:36:18 +01:00
// disconnect all clients
2019-06-10 12:57:49 +02:00
close ();
2016-01-14 17:28:00 +01:00
2019-06-10 12:57:49 +02:00
if ( _mandatoryHttpHeaders )
2016-06-08 23:04:18 +01:00
delete [] _mandatoryHttpHeaders ;
_mandatoryHttpHeaderCount = 0 ;
2015-05-22 14:19:01 +02:00
}
2020-11-21 13:51:16 +01:00
WebSocketsServer ::~ WebSocketsServer () {
}
2015-05-22 23:02:47 +02:00
/**
2016-06-08 23:04:18 +01:00
* called to initialize the Websocket server
2015-05-22 23:02:47 +02:00
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: begin ( void ) {
2015-05-22 20:35:51 +02:00
WSclient_t * client ;
2015-05-22 14:19:01 +02:00
// init client storage
for ( uint8_t i = 0 ; i < WEBSOCKETS_SERVER_CLIENT_MAX ; i ++ ) {
client = & _clients [ i ];
2019-06-10 12:57:49 +02:00
client -> num = i ;
2015-12-10 09:36:18 +01:00
client -> status = WSC_NOT_CONNECTED ;
2019-06-10 12:57:49 +02:00
client -> tcp = NULL ;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2015-12-10 09:36:18 +01:00
client -> isSSL = false ;
2019-06-10 12:57:49 +02:00
client -> ssl = NULL ;
2015-12-10 09:36:18 +01:00
#endif
2019-06-10 12:57:49 +02:00
client -> cUrl = "" ;
client -> cCode = 0 ;
client -> cKey = "" ;
2020-11-21 13:51:16 +01:00
client -> cAccept = "" ;
2019-06-10 12:57:49 +02:00
client -> cProtocol = "" ;
2020-11-21 13:51:16 +01:00
client -> cExtensions = "" ;
2019-06-10 12:57:49 +02:00
client -> cVersion = 0 ;
client -> cIsUpgrade = false ;
2015-05-22 14:19:01 +02:00
client -> cIsWebsocket = false ;
2016-01-23 16:27:02 +01:00
2016-02-17 17:56:03 +01:00
client -> base64Authorization = "" ;
2020-11-21 13:51:16 +01:00
client -> plainAuthorization = "" ;
client -> extraHeaders = "" ;
2016-02-17 17:56:03 +01:00
2016-01-23 16:27:02 +01:00
client -> cWsRXsize = 0 ;
2016-06-08 23:04:18 +01:00
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
2016-01-23 16:27:02 +01:00
client -> cHttpLine = "" ;
#endif
2020-02-10 19:45:55 +01:00
2020-05-03 09:28:55 +02:00
client -> pingInterval = _pingInterval ;
client -> pongTimeout = _pongTimeout ;
2020-02-10 19:45:55 +01:00
client -> disconnectTimeoutCount = _disconnectTimeoutCount ;
2015-05-22 14:19:01 +02:00
}
2015-12-10 09:36:18 +01:00
#ifdef ESP8266
randomSeed ( RANDOM_REG32 );
2017-07-30 00:54:17 +02:00
#elif defined(ESP32)
2019-06-10 12:57:49 +02:00
#define DR_REG_RNG_BASE 0x3ff75144
2017-07-30 00:54:17 +02:00
randomSeed ( READ_PERI_REG ( DR_REG_RNG_BASE ));
2015-12-10 09:36:18 +01:00
#else
// TODO find better seed
2015-05-24 15:40:47 +02:00
randomSeed ( millis ());
2015-12-10 09:36:18 +01:00
#endif
2015-05-24 15:40:47 +02:00
2018-05-10 18:55:23 +02:00
_runnning = true ;
2015-05-22 14:19:01 +02:00
}
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: close ( void ) {
2019-06-10 12:57:49 +02:00
_runnning = false ;
disconnect ();
2018-05-10 18:55:23 +02:00
}
2015-05-22 23:02:47 +02:00
/**
* set callback function
* @param cbEvent WebSocketServerEvent
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: onEvent ( WebSocketServerEvent cbEvent ) {
2015-05-23 23:51:32 +02:00
_cbEvent = cbEvent ;
2015-05-22 23:02:47 +02:00
}
2016-06-08 23:04:18 +01:00
/*
* Sets the custom http header validator function
* @param httpHeaderValidationFunc WebSocketServerHttpHeaderValFunc ///< pointer to the custom http header validation function
2016-06-09 19:48:38 +01:00
* @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed
* @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array
2016-06-08 23:04:18 +01:00
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: onValidateHttpHeader (
2019-06-10 12:57:49 +02:00
WebSocketServerHttpHeaderValFunc validationFunc ,
const char * mandatoryHttpHeaders [],
size_t mandatoryHttpHeaderCount ) {
_httpHeaderValidationFunc = validationFunc ;
2016-06-08 23:04:18 +01:00
2019-06-10 12:57:49 +02:00
if ( _mandatoryHttpHeaders )
delete [] _mandatoryHttpHeaders ;
2016-06-08 23:04:18 +01:00
2019-06-10 12:57:49 +02:00
_mandatoryHttpHeaderCount = mandatoryHttpHeaderCount ;
_mandatoryHttpHeaders = new String [ _mandatoryHttpHeaderCount ];
2016-06-08 23:04:18 +01:00
2019-06-10 12:57:49 +02:00
for ( size_t i = 0 ; i < _mandatoryHttpHeaderCount ; i ++ ) {
_mandatoryHttpHeaders [ i ] = mandatoryHttpHeaders [ i ];
}
2016-06-08 23:04:18 +01:00
}
/*
2015-05-22 23:02:47 +02:00
* send text data to client
* @param num uint8_t client id
* @param payload uint8_t *
* @param length size_t
2015-10-11 10:11:32 +02:00
* @param headerToPayload bool (see sendFrame for more details)
2016-02-20 12:27:19 +01:00
* @return true if ok
2015-05-22 23:02:47 +02:00
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendTXT ( uint8_t num , uint8_t * payload , size_t length , bool headerToPayload ) {
2015-05-22 23:02:47 +02:00
if ( num >= WEBSOCKETS_SERVER_CLIENT_MAX ) {
2016-02-20 12:27:19 +01:00
return false ;
2015-05-22 23:02:47 +02:00
}
2015-05-23 09:02:59 +02:00
if ( length == 0 ) {
2019-06-10 12:57:49 +02:00
length = strlen (( const char * ) payload );
2015-05-23 09:02:59 +02:00
}
2015-05-22 23:02:47 +02:00
WSclient_t * client = & _clients [ num ];
if ( clientIsConnected ( client )) {
2018-09-21 23:58:48 +05:30
return sendFrame ( client , WSop_text , payload , length , true , headerToPayload );
2015-05-22 23:02:47 +02:00
}
2016-02-20 12:27:19 +01:00
return false ;
2015-05-22 23:02:47 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendTXT ( uint8_t num , const uint8_t * payload , size_t length ) {
2019-06-10 12:57:49 +02:00
return sendTXT ( num , ( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendTXT ( uint8_t num , char * payload , size_t length , bool headerToPayload ) {
2019-06-10 12:57:49 +02:00
return sendTXT ( num , ( uint8_t * ) payload , length , headerToPayload );
2015-05-23 09:02:59 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendTXT ( uint8_t num , const char * payload , size_t length ) {
2019-06-10 12:57:49 +02:00
return sendTXT ( num , ( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendTXT ( uint8_t num , String & payload ) {
2019-06-10 12:57:49 +02:00
return sendTXT ( num , ( uint8_t * ) payload . c_str (), payload . length ());
2015-05-22 23:02:47 +02:00
}
/**
* send text data to client all
* @param payload uint8_t *
* @param length size_t
2015-10-11 10:11:32 +02:00
* @param headerToPayload bool (see sendFrame for more details)
2016-02-20 12:27:19 +01:00
* @return true if ok
2015-05-22 23:02:47 +02:00
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastTXT ( uint8_t * payload , size_t length , bool headerToPayload ) {
2015-05-22 23:02:47 +02:00
WSclient_t * client ;
2016-02-20 12:27:19 +01:00
bool ret = true ;
2015-05-23 09:02:59 +02:00
if ( length == 0 ) {
2019-06-10 12:57:49 +02:00
length = strlen (( const char * ) payload );
2015-05-23 09:02:59 +02:00
}
2015-05-23 23:51:32 +02:00
2015-05-22 23:02:47 +02:00
for ( uint8_t i = 0 ; i < WEBSOCKETS_SERVER_CLIENT_MAX ; i ++ ) {
client = & _clients [ i ];
if ( clientIsConnected ( client )) {
2018-09-21 23:58:48 +05:30
if ( ! sendFrame ( client , WSop_text , payload , length , true , headerToPayload )) {
2016-02-20 12:27:19 +01:00
ret = false ;
}
2015-05-22 23:02:47 +02:00
}
2020-05-03 09:12:03 +02:00
WEBSOCKETS_YIELD ();
2015-05-22 23:02:47 +02:00
}
2016-02-20 12:27:19 +01:00
return ret ;
2015-05-22 23:02:47 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastTXT ( const uint8_t * payload , size_t length ) {
2019-06-10 12:57:49 +02:00
return broadcastTXT (( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastTXT ( char * payload , size_t length , bool headerToPayload ) {
2019-06-10 12:57:49 +02:00
return broadcastTXT (( uint8_t * ) payload , length , headerToPayload );
2015-05-23 09:02:59 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastTXT ( const char * payload , size_t length ) {
2019-06-10 12:57:49 +02:00
return broadcastTXT (( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastTXT ( String & payload ) {
2019-06-10 12:57:49 +02:00
return broadcastTXT (( uint8_t * ) payload . c_str (), payload . length ());
2015-05-22 23:02:47 +02:00
}
/**
* send binary data to client
* @param num uint8_t client id
* @param payload uint8_t *
* @param length size_t
2015-10-11 10:11:32 +02:00
* @param headerToPayload bool (see sendFrame for more details)
2016-02-20 12:27:19 +01:00
* @return true if ok
2015-05-22 23:02:47 +02:00
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendBIN ( uint8_t num , uint8_t * payload , size_t length , bool headerToPayload ) {
2015-05-22 23:02:47 +02:00
if ( num >= WEBSOCKETS_SERVER_CLIENT_MAX ) {
2016-02-20 12:27:19 +01:00
return false ;
2015-05-22 23:02:47 +02:00
}
WSclient_t * client = & _clients [ num ];
if ( clientIsConnected ( client )) {
2018-09-21 23:58:48 +05:30
return sendFrame ( client , WSop_binary , payload , length , true , headerToPayload );
2015-05-22 23:02:47 +02:00
}
2016-02-20 12:27:19 +01:00
return false ;
2015-05-22 23:02:47 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendBIN ( uint8_t num , const uint8_t * payload , size_t length ) {
2019-06-10 12:57:49 +02:00
return sendBIN ( num , ( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2015-05-22 23:02:47 +02:00
/**
* send binary data to client all
* @param payload uint8_t *
* @param length size_t
2015-10-11 10:11:32 +02:00
* @param headerToPayload bool (see sendFrame for more details)
2016-02-20 12:27:19 +01:00
* @return true if ok
2015-05-22 23:02:47 +02:00
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastBIN ( uint8_t * payload , size_t length , bool headerToPayload ) {
2015-05-22 23:02:47 +02:00
WSclient_t * client ;
2016-02-20 12:27:19 +01:00
bool ret = true ;
2015-05-22 23:02:47 +02:00
for ( uint8_t i = 0 ; i < WEBSOCKETS_SERVER_CLIENT_MAX ; i ++ ) {
client = & _clients [ i ];
if ( clientIsConnected ( client )) {
2018-09-21 23:58:48 +05:30
if ( ! sendFrame ( client , WSop_binary , payload , length , true , headerToPayload )) {
2016-02-20 12:27:19 +01:00
ret = false ;
}
2015-05-22 23:02:47 +02:00
}
2020-05-03 09:12:03 +02:00
WEBSOCKETS_YIELD ();
2015-05-22 23:02:47 +02:00
}
2016-02-20 12:27:19 +01:00
return ret ;
2015-05-22 23:02:47 +02:00
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastBIN ( const uint8_t * payload , size_t length ) {
2019-06-10 12:57:49 +02:00
return broadcastBIN (( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2016-10-22 19:47:44 +02:00
/**
* 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
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendPing ( uint8_t num , uint8_t * payload , size_t length ) {
2016-10-22 19:47:44 +02:00
if ( num >= WEBSOCKETS_SERVER_CLIENT_MAX ) {
return false ;
}
WSclient_t * client = & _clients [ num ];
if ( clientIsConnected ( client )) {
return sendFrame ( client , WSop_ping , payload , length );
}
return false ;
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: sendPing ( uint8_t num , String & payload ) {
2019-06-10 12:57:49 +02:00
return sendPing ( num , ( uint8_t * ) payload . c_str (), payload . length ());
2016-10-22 19:47:44 +02:00
}
/**
* sends a WS ping to all Client
* @param payload uint8_t *
* @param length size_t
* @return true if ping is send out
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastPing ( uint8_t * payload , size_t length ) {
2016-10-22 19:47:44 +02:00
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 ;
}
}
2020-05-03 09:12:03 +02:00
WEBSOCKETS_YIELD ();
2016-10-22 19:47:44 +02:00
}
return ret ;
}
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: broadcastPing ( String & payload ) {
2019-06-10 12:57:49 +02:00
return broadcastPing (( uint8_t * ) payload . c_str (), payload . length ());
2016-10-22 19:47:44 +02:00
}
2015-05-23 09:20:44 +02:00
/**
* disconnect all clients
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: disconnect ( void ) {
2015-05-23 09:20:44 +02:00
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
2015-05-23 09:47:39 +02:00
* @param num uint8_t client id
2015-05-23 09:20:44 +02:00
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: disconnect ( uint8_t num ) {
2015-05-23 09:20:44 +02:00
if ( num >= WEBSOCKETS_SERVER_CLIENT_MAX ) {
return ;
}
WSclient_t * client = & _clients [ num ];
if ( clientIsConnected ( client )) {
WebSockets :: clientDisconnect ( client , 1000 );
}
}
2016-06-08 23:04:18 +01:00
/*
* set the Authorization for the http request
2016-02-17 17:56:03 +01:00
* @param user const char *
* @param password const char *
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: setAuthorization ( const char * user , const char * password ) {
2016-02-17 17:56:03 +01:00
if ( user && password ) {
String auth = user ;
auth += ":" ;
auth += password ;
_base64Authorization = base64_encode (( uint8_t * ) auth . c_str (), auth . length ());
}
}
/**
* set the Authorizatio for the http request
* @param auth const char * base64
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: setAuthorization ( const char * auth ) {
2016-02-17 17:56:03 +01:00
if ( auth ) {
_base64Authorization = auth ;
}
}
2018-05-10 20:42:03 +02:00
/**
* count the connected clients (optional ping them)
* @param ping bool ping the connected clients
*/
2020-11-21 13:51:16 +01:00
int WebSocketsServerCore :: connectedClients ( bool ping ) {
2018-05-10 20:42:03 +02:00
WSclient_t * client ;
int count = 0 ;
2019-06-10 12:57:49 +02:00
for ( uint8_t i = 0 ; i < WEBSOCKETS_SERVER_CLIENT_MAX ; i ++ ) {
client = & _clients [ i ];
if ( client -> status == WSC_CONNECTED ) {
if ( ping != true || sendPing ( i )) {
count ++ ;
}
}
}
2018-05-10 20:42:03 +02:00
return count ;
}
2020-04-16 14:38:19 -07:00
/**
* see if one client is connected
* @param num uint8_t client id
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: clientIsConnected ( uint8_t num ) {
2020-10-04 14:49:22 +02:00
if ( num >= WEBSOCKETS_SERVER_CLIENT_MAX ) {
2020-04-16 14:38:19 -07:00
return false ;
}
WSclient_t * client = & _clients [ num ];
return clientIsConnected ( client );
}
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2015-05-23 09:47:39 +02:00
/**
* get an IP for a client
* @param num uint8_t client id
* @return IPAddress
*/
2020-11-21 13:51:16 +01:00
IPAddress WebSocketsServerCore :: remoteIP ( uint8_t num ) {
2015-05-23 09:47:39 +02:00
if ( num < WEBSOCKETS_SERVER_CLIENT_MAX ) {
WSclient_t * client = & _clients [ num ];
if ( clientIsConnected ( client )) {
2015-12-10 09:36:18 +01:00
return client -> tcp -> remoteIP ();
2015-05-23 09:47:39 +02:00
}
}
return IPAddress ();
}
2015-12-10 11:16:08 +01:00
#endif
2015-05-23 09:47:39 +02:00
2015-05-22 14:19:01 +02:00
//#################################################################################
//#################################################################################
//#################################################################################
2016-01-23 16:27:02 +01:00
/**
* handle new client connection
* @param client
*/
2020-11-21 13:51:16 +01:00
WSclient_t * WebSocketsServerCore :: newClient ( WEBSOCKETS_NETWORK_CLASS * TCPclient ) {
2016-01-23 16:27:02 +01:00
WSclient_t * client ;
// 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 )) {
client -> tcp = TCPclient ;
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2016-01-23 16:27:02 +01:00
client -> isSSL = false ;
client -> tcp -> setNoDelay ( true );
#endif
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
2016-01-23 16:27:02 +01:00
// set Timeout for readBytesUntil and readStringUntil
client -> tcp -> setTimeout ( WEBSOCKETS_TCP_TIMEOUT );
#endif
client -> status = WSC_HEADER ;
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2019-07-04 12:58:37 +02:00
#ifndef NODEBUG_WEBSOCKETS
2016-01-23 16:27:02 +01:00
IPAddress ip = client -> tcp -> remoteIP ();
2019-07-04 12:58:37 +02:00
#endif
2016-01-23 16:27:02 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d] new client from %d.%d.%d.%d \n " , client -> num , ip [ 0 ], ip [ 1 ], ip [ 2 ], ip [ 3 ]);
#else
DEBUG_WEBSOCKETS ( "[WS-Server][%d] new client \n " , client -> num );
#endif
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
2020-11-21 13:51:16 +01:00
client -> tcp -> onDisconnect ( std :: bind ([]( WebSocketsServerCore * server , AsyncTCPbuffer * obj , WSclient_t * client ) -> bool {
2016-01-23 18:34:30 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d] Disconnect client \n " , client -> num );
AsyncTCPbuffer ** sl = & server -> _clients [ client -> num ]. tcp ;
if ( * sl == obj ) {
client -> status = WSC_NOT_CONNECTED ;
2019-06-10 12:57:49 +02:00
* sl = NULL ;
2016-01-23 18:34:30 +01:00
}
return true ;
2019-06-10 12:57:49 +02:00
},
this , std :: placeholders :: _1 , client ));
2016-01-23 18:34:30 +01:00
2020-11-21 13:51:16 +01:00
client -> tcp -> readStringUntil ( '\n' , & ( client -> cHttpLine ), std :: bind ( & WebSocketsServerCore :: handleHeader , this , client , & ( client -> cHttpLine )));
2016-01-23 16:27:02 +01:00
#endif
2020-05-03 09:28:55 +02:00
client -> pingInterval = _pingInterval ;
client -> pongTimeout = _pongTimeout ;
2020-02-10 19:45:55 +01:00
client -> disconnectTimeoutCount = _disconnectTimeoutCount ;
2020-05-03 09:28:55 +02:00
client -> lastPing = millis ();
client -> pongReceived = false ;
2020-02-10 19:45:55 +01:00
2020-11-21 13:51:16 +01:00
return client ;
2016-01-23 16:27:02 +01:00
break ;
}
}
2020-11-21 13:51:16 +01:00
return nullptr ;
2016-01-23 16:27:02 +01:00
}
2015-05-22 23:02:47 +02:00
/**
*
* @param client WSclient_t * ptr to the client struct
* @param opcode WSopcode_t
* @param payload uint8_t *
2017-03-06 15:07:20 -05:00
* @param length size_t
2015-05-22 23:02:47 +02:00
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: messageReceived ( WSclient_t * client , WSopcode_t opcode , uint8_t * payload , size_t length , bool fin ) {
2015-05-22 23:02:47 +02:00
WStype_t type = WStype_ERROR ;
switch ( opcode ) {
case WSop_text :
2017-02-22 14:29:26 +01:00
type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START ;
2015-05-22 23:02:47 +02:00
break ;
case WSop_binary :
2017-02-22 14:29:26 +01:00
type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START ;
break ;
case WSop_continuation :
type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT ;
2015-05-22 23:02:47 +02:00
break ;
2018-05-12 11:39:59 +02:00
case WSop_ping :
2019-05-30 20:15:03 +02:00
type = WStype_PING ;
break ;
2018-05-12 11:39:59 +02:00
case WSop_pong :
2019-05-30 20:15:03 +02:00
type = WStype_PONG ;
break ;
case WSop_close :
2018-05-12 11:39:59 +02:00
default :
break ;
2015-05-22 23:02:47 +02:00
}
2017-03-06 15:07:20 -05:00
runCbEvent ( client -> num , type , payload , length );
2015-05-22 23:02:47 +02:00
}
2015-05-22 14:19:01 +02:00
/**
2020-11-21 13:51:16 +01:00
* Discard a native client
* @param client WSclient_t * ptr to the client struct contaning the native client "->tcp"
2015-05-22 14:19:01 +02:00
*/
2020-11-21 14:06:30 +01:00
void WebSocketsServerCore :: dropNativeClient ( WSclient_t * client ) {
2015-05-22 14:19:01 +02:00
if ( client -> tcp ) {
2015-12-10 09:36:18 +01:00
if ( client -> tcp -> connected ()) {
2020-09-16 11:02:02 -07:00
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32)
2015-12-10 09:36:18 +01:00
client -> tcp -> flush ();
2016-01-23 16:27:02 +01:00
#endif
2015-12-10 09:36:18 +01:00
client -> tcp -> stop ();
}
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
2016-01-23 18:34:30 +01:00
client -> status = WSC_NOT_CONNECTED ;
#else
2015-12-10 09:36:18 +01:00
delete client -> tcp ;
2016-01-23 18:34:30 +01:00
#endif
2015-12-10 09:36:18 +01:00
client -> tcp = NULL ;
2015-05-22 14:19:01 +02:00
}
2020-11-21 13:51:16 +01:00
}
/**
* Disconnect an client
* @param client WSclient_t * ptr to the client struct
*/
void WebSocketsServerCore :: clientDisconnect ( WSclient_t * client ) {
#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 ();
}
delete client -> ssl ;
client -> ssl = NULL ;
client -> tcp = NULL ;
}
#endif
dropNativeClient ( client );
2015-05-22 14:19:01 +02:00
2019-06-10 12:57:49 +02:00
client -> cUrl = "" ;
client -> cKey = "" ;
client -> cProtocol = "" ;
client -> cVersion = 0 ;
client -> cIsUpgrade = false ;
2015-05-22 14:40:46 +02:00
client -> cIsWebsocket = false ;
2016-01-23 16:27:02 +01:00
client -> cWsRXsize = 0 ;
2016-06-08 23:04:18 +01:00
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
2016-01-23 16:27:02 +01:00
client -> cHttpLine = "" ;
#endif
2015-05-22 14:19:01 +02:00
client -> status = WSC_NOT_CONNECTED ;
2015-05-22 14:40:46 +02:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d] client disconnected. \n " , client -> num );
2015-05-22 14:19:01 +02:00
2015-10-31 11:37:07 +01:00
runCbEvent ( client -> num , WStype_DISCONNECTED , NULL , 0 );
2015-05-22 14:19:01 +02:00
}
/**
* get client state
2015-05-22 23:02:47 +02:00
* @param client WSclient_t * ptr to the client struct
2016-06-08 23:04:18 +01:00
* @return true = connected
2015-05-22 14:19:01 +02:00
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: clientIsConnected ( WSclient_t * client ) {
2015-12-10 09:36:18 +01:00
if ( ! client -> tcp ) {
return false ;
}
if ( client -> tcp -> connected ()) {
2015-12-05 11:43:03 +01:00
if ( client -> status != WSC_NOT_CONNECTED ) {
return true ;
}
} else {
// client lost
if ( client -> status != WSC_NOT_CONNECTED ) {
DEBUG_WEBSOCKETS ( "[WS-Server][%d] client connection lost. \n " , client -> num );
// do cleanup
clientDisconnect ( client );
}
2015-05-22 14:19:01 +02:00
}
2015-12-10 09:36:18 +01:00
if ( client -> tcp ) {
// do cleanup
2016-01-23 18:34:30 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d] client list cleanup. \n " , client -> num );
2015-12-10 09:36:18 +01:00
clientDisconnect ( client );
}
2015-05-22 14:19:01 +02:00
return false ;
}
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
2015-05-22 14:19:01 +02:00
/**
2016-06-08 23:04:18 +01:00
* Handle incoming Connection Request
2015-05-22 14:19:01 +02:00
*/
2020-11-21 13:51:16 +01:00
WSclient_t * WebSocketsServerCore :: handleNewClient ( WEBSOCKETS_NETWORK_CLASS * tcpClient ) {
2020-11-21 14:06:30 +01:00
WSclient_t * client = newClient ( tcpClient );
2015-12-10 09:36:18 +01:00
2020-11-21 14:06:30 +01:00
if ( ! client ) {
// no free space to handle client
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2019-07-04 12:58:37 +02:00
#ifndef NODEBUG_WEBSOCKETS
2020-11-21 14:06:30 +01:00
IPAddress ip = tcpClient -> remoteIP ();
2019-07-04 12:58:37 +02:00
#endif
2020-11-21 14:06:30 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server] no free space new client from %d.%d.%d.%d \n " , ip [ 0 ], ip [ 1 ], ip [ 2 ], ip [ 3 ]);
2015-12-10 11:16:08 +01:00
#else
2020-11-21 14:06:30 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server] no free space new client \n " );
2015-12-10 11:16:08 +01:00
#endif
2020-11-21 14:06:30 +01:00
dropNativeClient ( client );
}
2015-05-22 14:19:01 +02:00
2020-11-21 14:06:30 +01:00
WEBSOCKETS_YIELD ();
2020-11-21 13:51:16 +01:00
2020-11-21 14:06:30 +01:00
return client ;
2020-11-21 13:51:16 +01:00
}
/**
* Handle incoming Connection Request
*/
void WebSocketsServer :: handleNewClients ( void ) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
while ( _server -> hasClient ()) {
#endif
// store new connection
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS ( _server -> available ());
if ( ! tcpClient ) {
DEBUG_WEBSOCKETS ( "[WS-Client] creating Network class failed!" );
return ;
}
handleNewClient ( tcpClient );
2020-05-03 09:28:55 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2015-05-22 14:19:01 +02:00
}
2015-12-10 11:16:08 +01:00
#endif
2015-05-22 14:19:01 +02:00
}
/**
* Handel incomming data from Client
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: handleClientData ( void ) {
2015-05-22 20:35:51 +02:00
WSclient_t * client ;
2015-05-22 14:19:01 +02:00
for ( uint8_t i = 0 ; i < WEBSOCKETS_SERVER_CLIENT_MAX ; i ++ ) {
2015-05-22 14:40:46 +02:00
client = & _clients [ i ];
if ( clientIsConnected ( client )) {
2015-12-10 09:36:18 +01:00
int len = client -> tcp -> available ();
2015-05-22 14:19:01 +02:00
if ( len > 0 ) {
2016-01-23 16:27:02 +01:00
//DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len);
2015-05-22 14:19:01 +02:00
switch ( client -> status ) {
2019-06-10 12:57:49 +02:00
case WSC_HEADER : {
2016-01-23 16:27:02 +01:00
String headerLine = client -> tcp -> readStringUntil ( '\n' );
handleHeader ( client , & headerLine );
2019-06-10 12:57:49 +02:00
} break ;
2015-05-22 14:19:01 +02:00
case WSC_CONNECTED :
2015-05-22 20:35:51 +02:00
WebSockets :: handleWebsocket ( client );
2015-05-22 14:19:01 +02:00
break ;
default :
2020-09-16 11:02:02 -07:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleClientData] unknown client status %d \n " , client -> num , client -> status );
2015-05-23 09:02:59 +02:00
WebSockets :: clientDisconnect ( client , 1002 );
2015-05-22 14:19:01 +02:00
break ;
}
}
2020-05-03 09:28:55 +02:00
2020-02-10 19:45:55 +01:00
handleHBPing ( client );
handleHBTimeout ( client );
2015-05-22 14:19:01 +02:00
}
2020-05-03 09:12:03 +02:00
WEBSOCKETS_YIELD ();
2015-05-22 14:19:01 +02:00
}
}
2016-01-23 16:27:02 +01:00
#endif
2016-06-08 23:04:18 +01:00
/*
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
* @param headerName String ///< the name of the header being checked
*/
2020-11-21 13:51:16 +01:00
bool WebSocketsServerCore :: hasMandatoryHeader ( String headerName ) {
2019-06-10 12:57:49 +02:00
for ( size_t i = 0 ; i < _mandatoryHttpHeaderCount ; i ++ ) {
if ( _mandatoryHttpHeaders [ i ]. equalsIgnoreCase ( headerName ))
return true ;
}
return false ;
2016-06-08 23:04:18 +01:00
}
2015-05-22 14:19:01 +02:00
/**
2016-06-08 23:04:18 +01:00
* handles http header reading for WebSocket upgrade
* @param client WSclient_t * ///< pointer to the client struct
* @param headerLine String ///< the header being read / processed
2015-05-22 14:19:01 +02:00
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: handleHeader ( WSclient_t * client , String * headerLine ) {
2019-06-10 12:57:49 +02:00
static const char * NEW_LINE = " \r\n " ;
2015-05-22 14:19:01 +02:00
2019-06-10 12:57:49 +02:00
headerLine -> trim (); // remove \r
2017-02-22 15:30:58 +01:00
2019-06-10 12:57:49 +02:00
if ( headerLine -> length () > 0 ) {
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] RX: %s \n " , client -> num , headerLine -> c_str ());
2015-05-22 14:19:01 +02:00
2019-06-10 12:57:49 +02:00
// websocket requests always start with GET see rfc6455
if ( headerLine -> startsWith ( "GET " )) {
// cut URL out
client -> cUrl = headerLine -> substring ( 4 , headerLine -> indexOf ( ' ' , 4 ));
2015-05-22 14:19:01 +02:00
2019-06-10 12:57:49 +02:00
//reset non-websocket http header validation state for this client
client -> cHttpHeadersValid = true ;
client -> cMandatoryHeadersCount = 0 ;
2016-06-08 23:04:18 +01:00
2019-06-10 12:57:49 +02:00
} else if ( headerLine -> indexOf ( ':' ) >= 0 ) {
String headerName = headerLine -> substring ( 0 , headerLine -> indexOf ( ':' ));
String headerValue = headerLine -> substring ( headerLine -> indexOf ( ':' ) + 1 );
2016-06-08 23:04:18 +01:00
2019-06-10 12:57:49 +02:00
// remove space in the beginning (RFC2616)
if ( headerValue [ 0 ] == ' ' ) {
headerValue . remove ( 0 , 1 );
}
2016-06-08 23:04:18 +01:00
2019-06-10 12:57:49 +02:00
if ( headerName . equalsIgnoreCase ( WEBSOCKETS_STRING ( "Connection" ))) {
headerValue . toLowerCase ();
if ( headerValue . indexOf ( WEBSOCKETS_STRING ( "upgrade" )) >= 0 ) {
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-Version" ))) {
client -> cVersion = headerValue . toInt ();
} else if ( headerName . equalsIgnoreCase ( WEBSOCKETS_STRING ( "Sec-WebSocket-Key" ))) {
client -> cKey = headerValue ;
client -> cKey . 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 ( "Authorization" ))) {
client -> base64Authorization = headerValue ;
} else {
client -> cHttpHeadersValid &= execHttpHeaderValidation ( headerName , headerValue );
if ( _mandatoryHttpHeaderCount > 0 && hasMandatoryHeader ( headerName )) {
client -> cMandatoryHeadersCount ++ ;
}
}
2018-05-12 11:22:16 +02:00
2019-06-10 12:57:49 +02:00
} else {
DEBUG_WEBSOCKETS ( "[WS-Client][handleHeader] Header error (%s) \n " , headerLine -> c_str ());
}
2015-05-22 14:19:01 +02:00
2016-01-23 16:27:02 +01:00
( * headerLine ) = "" ;
2019-06-10 12:57:49 +02:00
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
2020-11-21 13:51:16 +01:00
client -> tcp -> readStringUntil ( '\n' , & ( client -> cHttpLine ), std :: bind ( & WebSocketsServerCore :: handleHeader , this , client , & ( client -> cHttpLine )));
2016-01-23 16:27:02 +01:00
#endif
2015-05-22 14:19:01 +02:00
} else {
2016-06-08 23:04:18 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] Header read fin. \n " , client -> num );
2015-05-23 07:33:26 +02:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cURL: %s \n " , client -> num , client -> cUrl . c_str ());
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cIsUpgrade: %d \n " , client -> num , client -> cIsUpgrade );
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cIsWebsocket: %d \n " , client -> num , client -> cIsWebsocket );
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cKey: %s \n " , client -> num , client -> cKey . c_str ());
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cProtocol: %s \n " , client -> num , client -> cProtocol . c_str ());
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cExtensions: %s \n " , client -> num , client -> cExtensions . c_str ());
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cVersion: %d \n " , client -> num , client -> cVersion );
2016-03-05 12:13:13 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - base64Authorization: %s \n " , client -> num , client -> base64Authorization . c_str ());
2016-06-08 23:04:18 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cHttpHeadersValid: %d \n " , client -> num , client -> cHttpHeadersValid );
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - cMandatoryHeadersCount: %d \n " , client -> num , client -> cMandatoryHeadersCount );
2015-05-22 14:19:01 +02:00
bool ok = ( client -> cIsUpgrade && client -> cIsWebsocket );
2019-06-10 12:57:49 +02:00
if ( ok ) {
if ( client -> cUrl . length () == 0 ) {
ok = false ;
}
if ( client -> cKey . length () == 0 ) {
2015-05-22 14:19:01 +02:00
ok = false ;
}
2015-05-22 14:40:46 +02:00
if ( client -> cVersion != 13 ) {
2015-05-22 14:19:01 +02:00
ok = false ;
}
2016-06-08 23:04:18 +01:00
if ( ! client -> cHttpHeadersValid ) {
2019-06-10 12:57:49 +02:00
ok = false ;
2016-06-08 23:04:18 +01:00
}
2019-06-10 12:57:49 +02:00
if ( client -> cMandatoryHeadersCount != _mandatoryHttpHeaderCount ) {
ok = false ;
2016-06-08 23:04:18 +01:00
}
2015-05-22 14:19:01 +02:00
}
2016-02-17 17:56:03 +01:00
if ( _base64Authorization . length () > 0 ) {
2019-06-10 12:57:49 +02:00
String auth = WEBSOCKETS_STRING ( "Basic " );
auth += _base64Authorization ;
if ( auth != client -> base64Authorization ) {
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] HTTP Authorization failed! \n " , client -> num );
handleAuthorizationFailed ( client );
return ;
}
2016-02-17 17:56:03 +01:00
}
2015-05-22 14:19:01 +02:00
if ( ok ) {
2016-01-23 16:27:02 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] Websocket connection incoming. \n " , client -> num );
2015-05-22 14:19:01 +02:00
2015-05-22 18:44:16 +02:00
// generate Sec-WebSocket-Accept key
2015-05-23 09:34:09 +02:00
String sKey = acceptKey ( client -> cKey );
2015-05-22 18:44:16 +02:00
2015-05-23 09:34:09 +02:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] - sKey: %s \n " , client -> num , sKey . c_str ());
2015-05-22 18:44:16 +02:00
client -> status = WSC_CONNECTED ;
2019-06-10 12:57:49 +02:00
String handshake = WEBSOCKETS_STRING (
"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: " );
handshake += sKey + NEW_LINE ;
2016-01-14 17:28:00 +01:00
if ( _origin . length () > 0 ) {
2017-02-22 15:30:58 +01:00
handshake += WEBSOCKETS_STRING ( "Access-Control-Allow-Origin: " );
2019-06-10 12:57:49 +02:00
handshake += _origin + NEW_LINE ;
2016-01-14 17:28:00 +01:00
}
2015-05-22 20:35:51 +02:00
if ( client -> cProtocol . length () > 0 ) {
2019-06-10 12:57:49 +02:00
handshake += WEBSOCKETS_STRING ( "Sec-WebSocket-Protocol: " );
handshake += _protocol + NEW_LINE ;
2015-05-22 20:35:51 +02:00
}
// header end
2017-02-22 15:30:58 +01:00
handshake += NEW_LINE ;
2019-06-10 12:57:49 +02:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] handshake %s" , client -> num , ( uint8_t * ) handshake . c_str ());
2017-02-22 15:30:58 +01:00
2019-06-10 12:57:49 +02:00
write ( client , ( uint8_t * ) handshake . c_str (), handshake . length ());
2015-05-22 14:19:01 +02:00
2016-01-23 16:27:02 +01:00
headerDone ( client );
2015-05-23 09:02:59 +02:00
// send ping
WebSockets :: sendFrame ( client , WSop_ping );
2019-06-10 12:57:49 +02:00
runCbEvent ( client -> num , WStype_CONNECTED , ( uint8_t * ) client -> cUrl . c_str (), client -> cUrl . length ());
2015-05-22 23:02:47 +02:00
2015-05-22 14:19:01 +02:00
} else {
2015-08-08 19:54:36 +02:00
handleNonWebsocketConnection ( client );
2015-05-22 14:19:01 +02:00
}
}
}
2020-02-10 19:45:55 +01:00
/**
* send heartbeat ping to server in set intervals
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: handleHBPing ( WSclient_t * client ) {
2020-02-10 19:45:55 +01:00
if ( client -> pingInterval == 0 )
return ;
uint32_t pi = millis () - client -> lastPing ;
if ( pi > client -> pingInterval ) {
2020-05-03 09:28:55 +02:00
DEBUG_WEBSOCKETS ( "[WS-Server][%d] sending HB ping \n " , client -> num );
2020-02-10 19:45:55 +01:00
if ( sendPing ( client -> num )) {
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
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: enableHeartbeat ( uint32_t pingInterval , uint32_t pongTimeout , uint8_t disconnectTimeoutCount ) {
2020-05-03 09:28:55 +02:00
_pingInterval = pingInterval ;
_pongTimeout = pongTimeout ;
2020-02-10 19:45:55 +01:00
_disconnectTimeoutCount = disconnectTimeoutCount ;
2020-05-03 09:28:55 +02:00
2020-02-10 19:45:55 +01:00
WSclient_t * client ;
for ( uint8_t i = 0 ; i < WEBSOCKETS_SERVER_CLIENT_MAX ; i ++ ) {
client = & _clients [ i ];
WebSockets :: enableHeartbeat ( client , pingInterval , pongTimeout , disconnectTimeoutCount );
}
}
/**
* disable ping/pong heartbeat process
*/
2020-11-21 13:51:16 +01:00
void WebSocketsServerCore :: disableHeartbeat () {
2020-02-10 19:45:55 +01:00
_pingInterval = 0 ;
2020-05-03 09:28:55 +02:00
2020-02-10 19:45:55 +01:00
WSclient_t * client ;
for ( uint8_t i = 0 ; i < WEBSOCKETS_SERVER_CLIENT_MAX ; i ++ ) {
2020-05-03 09:28:55 +02:00
client = & _clients [ i ];
2020-02-10 19:45:55 +01:00
client -> pingInterval = 0 ;
}
2020-11-21 13:51:16 +01:00
}
////////////////////
// WebSocketServer
/**
* called to initialize the Websocket server
*/
void WebSocketsServer :: begin ( void ) {
WebSocketsServerCore :: begin ();
_server -> begin ();
DEBUG_WEBSOCKETS ( "[WS-Server] Server Started. \n " );
}
void WebSocketsServer :: close ( void ) {
WebSocketsServer :: close ();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
_server -> close ();
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
_server -> end ();
#else
// TODO how to close server?
#endif
}
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
/**
* called in arduino loop
*/
void WebSocketsServerCore :: loop ( void ) {
if ( _runnning ) {
WEBSOCKETS_YIELD ();
handleClientData ();
}
}
/**
* called in arduino loop
*/
void WebSocketsServer :: loop ( void ) {
if ( _runnning ) {
WEBSOCKETS_YIELD ();
handleNewClients ();
WebSocketsServerCore :: loop ();
}
}
#endif