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"
2016-01-14 17:28:00 +01:00
WebSocketsServer :: WebSocketsServer ( uint16_t port , String origin , String protocol ) {
2015-05-22 14:19:01 +02:00
_port = port ;
2016-01-14 17:28:00 +01:00
_origin = origin ;
_protocol = protocol ;
2018-05-10 18:55:23 +02:00
_runnning = false ;
2016-01-14 17:28:00 +01:00
2015-12-10 11:16:08 +01:00
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS ( port );
2015-05-22 23:02:47 +02:00
2016-01-23 16:27:02 +01:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
_server -> onClient ([]( void * s , AsyncClient * c ){
(( WebSocketsServer * ) s ) -> newClient ( new AsyncTCPbuffer ( c ));
}, this );
#endif
2015-05-22 23:02:47 +02:00
_cbEvent = NULL ;
2016-06-08 23:04:18 +01:00
_httpHeaderValidationFunc = NULL ;
_mandatoryHttpHeaders = NULL ;
_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
2016-01-23 16:27:02 +01:00
2015-05-22 14:19:01 +02:00
WebSocketsServer ::~ WebSocketsServer () {
2015-12-10 09:36:18 +01:00
// disconnect all clients
2018-05-10 18:55:23 +02:00
close ();
2016-01-14 17:28:00 +01:00
2016-06-08 23:04:18 +01:00
if ( _mandatoryHttpHeaders )
delete [] _mandatoryHttpHeaders ;
_mandatoryHttpHeaderCount = 0 ;
2015-05-22 14:19:01 +02:00
}
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
*/
2015-05-22 14:19:01 +02:00
void WebSocketsServer :: 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 ];
2015-05-22 14:40:46 +02:00
client -> num = i ;
2015-12-10 09:36:18 +01:00
client -> status = WSC_NOT_CONNECTED ;
client -> tcp = NULL ;
2017-07-30 00:54:17 +02:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2015-12-10 09:36:18 +01:00
client -> isSSL = false ;
client -> ssl = NULL ;
#endif
2015-05-22 14:19:01 +02:00
client -> cUrl = "" ;
2015-12-10 09:36:18 +01:00
client -> cCode = 0 ;
2015-05-22 14:19:01 +02:00
client -> cKey = "" ;
client -> cProtocol = "" ;
client -> cVersion = 0 ;
client -> cIsUpgrade = false ;
client -> cIsWebsocket = false ;
2016-01-23 16:27:02 +01:00
2016-02-17 17:56:03 +01:00
client -> base64Authorization = "" ;
2016-01-23 16:27:02 +01:00
client -> cWsRXsize = 0 ;
2016-06-08 23:04:18 +01:00
2016-01-23 16:27:02 +01:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client -> cHttpLine = "" ;
#endif
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)
#define DR_REG_RNG_BASE 0x3ff75144
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
_server -> begin ();
2015-12-10 09:36:18 +01:00
DEBUG_WEBSOCKETS ( "[WS-Server] Server Started. \n " );
2015-05-22 14:19:01 +02:00
}
2018-05-10 18:55:23 +02:00
void WebSocketsServer :: close ( void ) {
_runnning = false ;
disconnect ();
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
_server -> close ();
2018-06-21 09:30:11 +02:00
#elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
2018-05-10 18:55:23 +02:00
_server -> end ();
#else
// TODO how to close server?
#endif
}
2016-01-23 18:41:45 +01:00
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
2015-05-23 09:20:44 +02:00
/**
* called in arduino loop
*/
2015-05-22 14:19:01 +02:00
void WebSocketsServer :: loop ( void ) {
2018-05-10 18:55:23 +02:00
if ( _runnning ) {
handleNewClients ();
handleClientData ();
}
2015-05-22 14:19:01 +02:00
}
2016-01-23 18:41:45 +01:00
#endif
2015-05-22 14:19:01 +02:00
2015-05-22 23:02:47 +02:00
/**
* set callback function
* @param cbEvent WebSocketServerEvent
*/
void WebSocketsServer :: 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
*/
void WebSocketsServer :: onValidateHttpHeader (
WebSocketServerHttpHeaderValFunc validationFunc ,
2016-06-09 19:48:38 +01:00
const char * mandatoryHttpHeaders [],
size_t mandatoryHttpHeaderCount )
2016-06-08 23:04:18 +01:00
{
_httpHeaderValidationFunc = validationFunc ;
if ( _mandatoryHttpHeaders )
delete [] _mandatoryHttpHeaders ;
2016-06-09 19:48:38 +01:00
_mandatoryHttpHeaderCount = mandatoryHttpHeaderCount ;
2016-06-08 23:04:18 +01:00
_mandatoryHttpHeaders = new String [ _mandatoryHttpHeaderCount ];
for ( size_t i = 0 ; i < _mandatoryHttpHeaderCount ; i ++ ) {
_mandatoryHttpHeaders [ i ] = mandatoryHttpHeaders [ i ];
}
}
/*
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
*/
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: 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 ) {
length = strlen (( const char * ) payload );
}
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
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: sendTXT ( uint8_t num , const uint8_t * payload , size_t length ) {
return sendTXT ( num , ( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: sendTXT ( uint8_t num , char * payload , size_t length , bool headerToPayload ) {
return sendTXT ( num , ( uint8_t * ) payload , length , headerToPayload );
2015-05-23 09:02:59 +02:00
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: sendTXT ( uint8_t num , const char * payload , size_t length ) {
return sendTXT ( num , ( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: sendTXT ( uint8_t num , String & payload ) {
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
*/
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: 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 ) {
length = strlen (( const char * ) payload );
}
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
}
2016-01-23 16:27:02 +01:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
2015-05-23 23:51:32 +02:00
delay ( 0 );
2015-05-24 15:40:47 +02:00
#endif
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
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: broadcastTXT ( const uint8_t * payload , size_t length ) {
return broadcastTXT (( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: broadcastTXT ( char * payload , size_t length , bool headerToPayload ) {
return broadcastTXT (( uint8_t * ) payload , length , headerToPayload );
2015-05-23 09:02:59 +02:00
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: broadcastTXT ( const char * payload , size_t length ) {
return broadcastTXT (( uint8_t * ) payload , length );
2015-05-23 09:02:59 +02:00
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: broadcastTXT ( String & payload ) {
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
*/
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: 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
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: sendBIN ( uint8_t num , const uint8_t * payload , size_t length ) {
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
*/
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: 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
}
2016-01-23 16:27:02 +01:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
2015-05-23 23:51:32 +02:00
delay ( 0 );
2015-05-24 15:40:47 +02:00
#endif
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
}
2016-02-20 12:27:19 +01:00
bool WebSocketsServer :: broadcastBIN ( const uint8_t * payload , size_t length ) {
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
*/
bool WebSocketsServer :: sendPing ( uint8_t num , uint8_t * payload , size_t length ) {
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 ;
}
bool WebSocketsServer :: sendPing ( uint8_t num , String & payload ) {
return sendPing ( num , ( uint8_t * ) payload . c_str (), payload . length ());
}
/**
* sends a WS ping to all Client
* @param payload uint8_t *
* @param length size_t
* @return true if ping is send out
*/
bool WebSocketsServer :: broadcastPing ( uint8_t * payload , size_t length ) {
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 ;
}
}
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay ( 0 );
#endif
}
return ret ;
}
bool WebSocketsServer :: broadcastPing ( String & payload ) {
return broadcastPing (( uint8_t * ) payload . c_str (), payload . length ());
}
2015-05-23 09:20:44 +02:00
/**
* disconnect all clients
*/
void WebSocketsServer :: disconnect ( void ) {
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
*/
void WebSocketsServer :: disconnect ( uint8_t num ) {
if ( num >= WEBSOCKETS_SERVER_CLIENT_MAX ) {
return ;
}
WSclient_t * client = & _clients [ num ];
if ( clientIsConnected ( client )) {
WebSockets :: clientDisconnect ( client , 1000 );
}
}
2016-02-17 17:56:03 +01:00
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 *
*/
void WebSocketsServer :: setAuthorization ( const char * user , const char * password ) {
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
*/
void WebSocketsServer :: setAuthorization ( const char * auth ) {
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
*/
int WebSocketsServer :: connectedClients ( bool ping ) {
WSclient_t * client ;
int count = 0 ;
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 ++ ;
}
}
}
return count ;
}
2017-07-30 00:54:17 +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
*/
IPAddress WebSocketsServer :: remoteIP ( uint8_t num ) {
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
*/
bool WebSocketsServer :: newClient ( WEBSOCKETS_NETWORK_CLASS * TCPclient ) {
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 )) {
2016-01-23 18:34:30 +01:00
2016-01-23 16:27:02 +01:00
client -> tcp = TCPclient ;
2017-07-30 00:54:17 +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
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
// set Timeout for readBytesUntil and readStringUntil
client -> tcp -> setTimeout ( WEBSOCKETS_TCP_TIMEOUT );
#endif
client -> status = WSC_HEADER ;
2017-07-30 00:54:17 +02:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2016-01-23 16:27:02 +01:00
IPAddress ip = client -> tcp -> remoteIP ();
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
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
2016-01-23 18:34:30 +01:00
client -> tcp -> onDisconnect ( std :: bind ([]( WebSocketsServer * server , AsyncTCPbuffer * obj , WSclient_t * client ) -> bool {
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 ;
* sl = NULL ;
}
return true ;
}, this , std :: placeholders :: _1 , client ));
2016-01-23 16:27:02 +01:00
client -> tcp -> readStringUntil ( '\n' , & ( client -> cHttpLine ), std :: bind ( & WebSocketsServer :: handleHeader , this , client , & ( client -> cHttpLine )));
#endif
return true ;
break ;
}
}
return false ;
}
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
*/
2017-03-06 15:07:20 -05:00
void WebSocketsServer :: 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_close :
case WSop_ping :
case WSop_pong :
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-10-31 11:37:07 +01:00
2015-05-22 23:02:47 +02:00
}
2015-05-22 14:19:01 +02:00
/**
* Disconnect an client
2015-05-22 23:02:47 +02:00
* @param client WSclient_t * ptr to the client struct
2015-05-22 14:19:01 +02:00
*/
2015-05-22 20:35:51 +02:00
void WebSocketsServer :: clientDisconnect ( WSclient_t * client ) {
2015-05-22 14:19:01 +02:00
2015-12-10 09:36:18 +01:00
2017-07-30 00:54:17 +02:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2015-12-10 09:36:18 +01:00
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
2015-05-22 14:19:01 +02:00
if ( client -> tcp ) {
2015-12-10 09:36:18 +01:00
if ( client -> tcp -> connected ()) {
2016-01-23 16:27:02 +01:00
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
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 ();
}
2016-01-23 18:34:30 +01:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
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
}
2015-05-22 14:40:46 +02:00
client -> cUrl = "" ;
client -> cKey = "" ;
client -> cProtocol = "" ;
client -> cVersion = 0 ;
client -> cIsUpgrade = false ;
client -> cIsWebsocket = false ;
2016-01-23 16:27:02 +01:00
client -> cWsRXsize = 0 ;
2016-06-08 23:04:18 +01:00
2016-01-23 16:27:02 +01:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
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
*/
2015-05-22 20:35:51 +02:00
bool WebSocketsServer :: clientIsConnected ( WSclient_t * client ) {
2015-05-22 14:19:01 +02:00
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 ;
}
2016-01-23 16:27:02 +01: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
*/
void WebSocketsServer :: handleNewClients ( void ) {
2016-01-23 16:27:02 +01:00
2017-09-03 09:55:15 +02:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2015-05-22 14:19:01 +02:00
while ( _server -> hasClient ()) {
2015-12-10 11:16:08 +01:00
#endif
2015-05-22 14:19:01 +02:00
bool ok = false ;
2015-12-10 09:36:18 +01:00
2017-07-30 00:54:17 +02:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2016-01-23 16:27:02 +01:00
// store new connection
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS ( _server -> available ());
2015-12-10 11:16:08 +01:00
#else
2016-01-23 16:27:02 +01:00
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS ( _server -> available ());
2015-12-10 11:16:08 +01:00
#endif
2016-01-23 16:27:02 +01:00
if ( ! tcpClient ) {
DEBUG_WEBSOCKETS ( "[WS-Client] creating Network class failed!" );
return ;
2015-05-22 14:19:01 +02:00
}
2016-01-23 16:27:02 +01:00
ok = newClient ( tcpClient );
2015-05-22 14:19:01 +02:00
if ( ! ok ) {
// no free space to handle client
2017-07-30 00:54:17 +02:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2016-01-23 16:27:02 +01:00
IPAddress ip = tcpClient -> remoteIP ();
2015-05-22 14:19:01 +02: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
DEBUG_WEBSOCKETS ( "[WS-Server] no free space new client \n " );
#endif
2016-01-23 16:27:02 +01:00
tcpClient -> stop ();
2015-05-22 14:19:01 +02:00
}
2017-07-30 00:54:17 +02:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
2016-01-23 16:27:02 +01:00
delay ( 0 );
2015-05-22 14:19:01 +02:00
}
2015-12-10 11:16:08 +01:00
#endif
2016-01-23 16:27:02 +01:00
2015-05-22 14:19:01 +02:00
}
2016-01-23 16:27:02 +01:00
2015-05-22 14:19:01 +02:00
/**
* Handel incomming data from Client
*/
void WebSocketsServer :: 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 ) {
case WSC_HEADER :
2016-01-23 16:27:02 +01:00
{
String headerLine = client -> tcp -> readStringUntil ( '\n' );
handleHeader ( client , & headerLine );
}
2015-05-22 14:19:01 +02:00
break ;
case WSC_CONNECTED :
2015-05-22 20:35:51 +02:00
WebSockets :: handleWebsocket ( client );
2015-05-22 14:19:01 +02:00
break ;
default :
2015-05-23 09:02:59 +02:00
WebSockets :: clientDisconnect ( client , 1002 );
2015-05-22 14:19:01 +02:00
break ;
}
}
}
2016-01-23 16:27:02 +01:00
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
2015-05-22 14:19:01 +02:00
delay ( 0 );
2015-05-24 15:40:47 +02:00
#endif
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
*/
bool WebSocketsServer :: hasMandatoryHeader ( String headerName ) {
for ( size_t i = 0 ; i < _mandatoryHttpHeaderCount ; i ++ ) {
if ( _mandatoryHttpHeaders [ i ]. equalsIgnoreCase ( headerName ))
return true ;
}
return false ;
}
2015-05-22 14:19:01 +02:00
2017-02-22 15:30:58 +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
*/
2016-01-23 16:27:02 +01:00
void WebSocketsServer :: handleHeader ( WSclient_t * client , String * headerLine ) {
2015-05-22 14:19:01 +02:00
2017-02-22 15:30:58 +01:00
static const char * NEW_LINE = " \r\n " ;
2018-05-12 11:27:03 +02:00
headerLine -> trim (); // remove \r
2015-05-22 14:19:01 +02:00
2018-05-12 11:27:03 +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
2018-05-12 11:27:03 +02:00
// websocket requests always start with GET see rfc6455
if ( headerLine -> startsWith ( "GET " )) {
2016-06-08 23:04:18 +01:00
2018-05-12 11:27:03 +02:00
// cut URL out
client -> cUrl = headerLine -> substring ( 4 , headerLine -> indexOf ( ' ' , 4 ));
2016-06-08 23:04:18 +01:00
2018-05-12 11:27:03 +02:00
//reset non-websocket http header validation state for this client
2016-06-08 23:04:18 +01:00
client -> cHttpHeadersValid = true ;
client -> cMandatoryHeadersCount = 0 ;
2019-05-30 16:52:20 +02:00
} else if ( headerLine -> indexOf ( ':' ) >= 0 ) {
2018-05-12 11:27:03 +02:00
String headerName = headerLine -> substring ( 0 , headerLine -> indexOf ( ':' ));
String headerValue = headerLine -> substring ( headerLine -> indexOf ( ':' ) + 1 );
2018-05-12 11:22:16 +02:00
// remove space in the beginning (RFC2616)
if ( headerValue [ 0 ] == ' ' ) {
headerValue . remove ( 0 , 1 );
}
2015-07-26 11:08:02 +02:00
2018-05-12 11:27:03 +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 ++ ;
}
}
2016-06-08 23:04:18 +01:00
2018-05-12 11:27:03 +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 ) = "" ;
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client -> tcp -> readStringUntil ( '\n' , & ( client -> cHttpLine ), std :: bind ( & WebSocketsServer :: handleHeader , this , client , & ( client -> cHttpLine )));
#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 );
2018-05-12 11:27:03 +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 ) {
ok = false ;
}
if ( client -> cMandatoryHeadersCount != _mandatoryHttpHeaderCount ) {
ok = false ;
}
2015-05-22 14:19:01 +02:00
}
2016-02-17 17:56:03 +01:00
if ( _base64Authorization . length () > 0 ) {
2017-03-18 10:32:37 +01: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 ;
2017-02-22 15:30:58 +01:00
String handshake = WEBSOCKETS_STRING ( "HTTP/1.1 101 Switching Protocols \r\n "
2015-05-24 18:00:35 +02:00
"Server: arduino-WebSocketsServer \r\n "
2015-05-22 18:44:16 +02:00
"Upgrade: websocket \r\n "
"Connection: Upgrade \r\n "
"Sec-WebSocket-Version: 13 \r\n "
"Sec-WebSocket-Accept: " );
2017-02-22 15:30:58 +01:00
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: " );
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 ) {
2017-02-22 15:30:58 +01: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 ;
DEBUG_WEBSOCKETS ( "[WS-Server][%d][handleHeader] handshake %s" , client -> num , ( uint8_t * ) handshake . c_str ());
2017-04-09 17:58:23 +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 );
2015-10-31 11:37:07 +01: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
}
}
}
2015-05-22 20:35:51 +02:00
2015-08-08 19:54:36 +02:00