@ -10,10 +10,16 @@ Parts of the code have been borrowed from Thomas Sarlandie's NetServer
# if TELNET_SUPPORT
# if TELNET_SUPPORT
# include <ESPAsyncTCP.h>
# if TELNET_SERVER == TELNET_SERVER_WIFISERVER
# include <ESP8266WiFi.h>
WiFiServer _telnetServer = WiFiServer ( TELNET_PORT ) ;
std : : unique_ptr < WiFiClient > _telnetClients [ TELNET_MAX_CLIENTS ] ;
# else
# include <ESPAsyncTCP.h>
AsyncServer _telnetServer = AsyncServer ( TELNET_PORT ) ;
std : : unique_ptr < AsyncClient > _telnetClients [ TELNET_MAX_CLIENTS ] ;
# endif
AsyncServer * _telnetServer ;
AsyncClient * _telnetClients [ TELNET_MAX_CLIENTS ] ;
bool _telnetFirst = true ;
bool _telnetFirst = true ;
bool _telnetAuth = TELNET_AUTHENTICATION ;
bool _telnetAuth = TELNET_AUTHENTICATION ;
@ -38,9 +44,11 @@ void _telnetWebSocketOnSend(JsonObject& root) {
# endif
# endif
void _telnetDisconnect ( unsigned char clientId ) {
void _telnetDisconnect ( unsigned char clientId ) {
_telnetClients [ clientId ] - > free ( ) ;
delete _telnetClients [ clientId ] ;
_telnetClients [ clientId ] = NULL ;
// ref: we are called from onDisconnect, async is already stopped
# if TELNET_SERVER == TELNET_SERVER_WIFISERVER
_telnetClients [ clientId ] - > stop ( ) ;
# endif
_telnetClients [ clientId ] = nullptr ;
wifiReconnectCheck ( ) ;
wifiReconnectCheck ( ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Client #%d disconnected \n " ) , clientId ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Client #%d disconnected \n " ) , clientId ) ;
}
}
@ -74,7 +82,6 @@ bool _telnetWrite(unsigned char clientId, const char * message) {
}
}
void _telnetData ( unsigned char clientId , void * data , size_t len ) {
void _telnetData ( unsigned char clientId , void * data , size_t len ) {
// Skip first message since it's always garbage
// Skip first message since it's always garbage
if ( _telnetFirst ) {
if ( _telnetFirst ) {
_telnetFirst = false ;
_telnetFirst = false ;
@ -87,13 +94,13 @@ void _telnetData(unsigned char clientId, void *data, size_t len) {
// C-d is sent as two bytes (sometimes repeating)
// C-d is sent as two bytes (sometimes repeating)
if ( len > = 2 ) {
if ( len > = 2 ) {
if ( ( p [ 0 ] = = 0xFF ) & & ( p [ 1 ] = = 0xEC ) ) {
if ( ( p [ 0 ] = = 0xFF ) & & ( p [ 1 ] = = 0xEC ) ) {
_telnetClients [ clientId ] - > close ( true ) ;
_telnetDisconnect ( clientId ) ;
return ;
return ;
}
}
}
}
if ( ( strncmp ( p , " close " , 5 ) = = 0 ) | | ( strncmp ( p , " quit " , 4 ) = = 0 ) ) {
if ( ( strncmp ( p , " close " , 5 ) = = 0 ) | | ( strncmp ( p , " quit " , 4 ) = = 0 ) ) {
_telnetClients [ clientId ] - > close ( ) ;
_telnetDisconnect ( clientId ) ;
return ;
return ;
}
}
@ -108,10 +115,10 @@ void _telnetData(unsigned char clientId, void *data, size_t len) {
String password = getAdminPass ( ) ;
String password = getAdminPass ( ) ;
if ( strncmp ( p , password . c_str ( ) , password . length ( ) ) = = 0 ) {
if ( strncmp ( p , password . c_str ( ) , password . length ( ) ) = = 0 ) {
DEBUG_MSG_P ( PSTR ( " [TELNET] Client #%d authenticated \n " ) , clientId ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Client #%d authenticated \n " ) , clientId ) ;
_telnetWrite ( clientId , " W elcome!\n " ) ;
_telnetWrite ( clientId , " Password correct, w elcome!\n " ) ;
_telnetClientsAuth [ clientId ] = true ;
_telnetClientsAuth [ clientId ] = true ;
} else {
} else {
_telnetWrite ( clientId , " Password: " ) ;
_telnetWrite ( clientId , " Password (try again) : " ) ;
}
}
return ;
return ;
}
}
@ -120,13 +127,101 @@ void _telnetData(unsigned char clientId, void *data, size_t len) {
# if TERMINAL_SUPPORT
# if TERMINAL_SUPPORT
terminalInject ( data , len ) ;
terminalInject ( data , len ) ;
# endif
# endif
}
void _telnetNotifyConnected ( unsigned char i ) {
DEBUG_MSG_P ( PSTR ( " [TELNET] Client #%u connected \n " ) , i ) ;
// If there is no terminal support automatically dump info and crash data
# if TERMINAL_SUPPORT == 0
info ( ) ;
wifiDebug ( ) ;
crashDump ( ) ;
crashClear ( ) ;
# endif
# ifdef ESPURNA_CORE
_telnetClientsAuth [ i ] = true ;
# else
_telnetClientsAuth [ i ] = ! _telnetAuth ;
if ( _telnetAuth ) {
if ( getAdminPass ( ) . length ( ) ) {
_telnetWrite ( i , " Password: " ) ;
} else {
_telnetClientsAuth [ i ] = true ;
}
}
# endif
_telnetFirst = true ;
wifiReconnectCheck ( ) ;
}
}
void _telnetNewClient ( AsyncClient * client ) {
# if TELNET_SERVER == TELNET_SERVER_WIFISERVER
if ( client - > localIP ( ) ! = WiFi . softAPIP ( ) ) {
void _telnetLoop ( ) {
if ( _telnetServer . hasClient ( ) ) {
int i ;
for ( i = 0 ; i < TELNET_MAX_CLIENTS ; i + + ) {
if ( ! _telnetClients [ i ] | | ! _telnetClients [ i ] - > connected ( ) ) {
_telnetClients [ i ] = std : : unique_ptr < WiFiClient > ( new WiFiClient ( _telnetServer . available ( ) ) ) ;
if ( _telnetClients [ i ] - > localIP ( ) ! = WiFi . softAPIP ( ) ) {
// Telnet is always available for the ESPurna Core image
# ifdef ESPURNA_CORE
bool telnetSTA = true ;
# else
bool telnetSTA = getSetting ( " telnetSTA " , TELNET_STA ) . toInt ( ) = = 1 ;
# endif
if ( ! telnetSTA ) {
DEBUG_MSG_P ( PSTR ( " [TELNET] Rejecting - Only local connections \n " ) ) ;
_telnetDisconnect ( i ) ;
return ;
}
}
_telnetNotifyConnected ( i ) ;
break ;
}
}
//no free/disconnected spot so reject
if ( i = = TELNET_MAX_CLIENTS ) {
DEBUG_MSG_P ( PSTR ( " [TELNET] Rejecting - Too many connections \n " ) ) ;
_telnetServer . available ( ) . stop ( ) ;
return ;
}
}
for ( int i = 0 ; i < TELNET_MAX_CLIENTS ; i + + ) {
if ( _telnetClients [ i ] ) {
// Handle client timeouts
if ( ! _telnetClients [ i ] - > connected ( ) ) {
_telnetDisconnect ( i ) ;
} else {
// Read data from clients
while ( _telnetClients [ i ] & & _telnetClients [ i ] - > available ( ) ) {
char data [ TERMINAL_BUFFER_SIZE ] ;
size_t len = _telnetClients [ i ] - > available ( ) ;
unsigned int r = _telnetClients [ i ] - > readBytes ( data , min ( sizeof ( data ) , len ) ) ;
_telnetData ( i , data , r ) ;
}
}
}
}
}
# else // TELNET_SERVER_ASYNC
void _telnetNewClient ( AsyncClient * client ) {
if ( client - > localIP ( ) ! = WiFi . softAPIP ( ) ) {
// Telnet is always available for the ESPurna Core image
// Telnet is always available for the ESPurna Core image
# ifdef ESPURNA_CORE
# ifdef ESPURNA_CORE
bool telnetSTA = true ;
bool telnetSTA = true ;
@ -137,76 +232,54 @@ void _telnetNewClient(AsyncClient *client) {
if ( ! telnetSTA ) {
if ( ! telnetSTA ) {
DEBUG_MSG_P ( PSTR ( " [TELNET] Rejecting - Only local connections \n " ) ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Rejecting - Only local connections \n " ) ) ;
client - > onDisconnect ( [ ] ( void * s , AsyncClient * c ) {
client - > onDisconnect ( [ ] ( void * s , AsyncClient * c ) {
c - > free ( ) ;
delete c ;
delete c ;
} ) ;
} ) ;
client - > close ( true ) ;
client - > close ( true ) ;
return ;
return ;
}
}
}
}
for ( unsigned char i = 0 ; i < TELNET_MAX_CLIENTS ; i + + ) {
for ( unsigned char i = 0 ; i < TELNET_MAX_CLIENTS ; i + + ) {
if ( ! _telnetClients [ i ] | | ! _telnetClients [ i ] - > connected ( ) ) {
if ( ! _telnetClients [ i ] | | ! _telnetClients [ i ] - > connected ( ) ) {
_telnetClients [ i ] = client ;
_telnetClients [ i ] = std : : unique_ptr < AsyncClient > ( client ) ;
client - > onAck ( [ i ] ( void * s , AsyncClient * c , size_t len , uint32_t time ) {
_telnetClients [ i ] - > onAck ( [ i ] ( void * s , AsyncClient * c , size_t len , uint32_t time ) {
} , 0 ) ;
} , 0 ) ;
client - > onData ( [ i ] ( void * s , AsyncClient * c , void * data , size_t len ) {
_telnetClients [ i ] - > onData ( [ i ] ( void * s , AsyncClient * c , void * data , size_t len ) {
_telnetData ( i , data , len ) ;
_telnetData ( i , data , len ) ;
} , 0 ) ;
} , 0 ) ;
client - > onDisconnect ( [ i ] ( void * s , AsyncClient * c ) {
_telnetClients [ i ] - > onDisconnect ( [ i ] ( void * s , AsyncClient * c ) {
_telnetDisconnect ( i ) ;
_telnetDisconnect ( i ) ;
} , 0 ) ;
} , 0 ) ;
client - > onError ( [ i ] ( void * s , AsyncClient * c , int8_t error ) {
_telnetClients [ i ] - > onError ( [ i ] ( void * s , AsyncClient * c , int8_t error ) {
DEBUG_MSG_P ( PSTR ( " [TELNET] Error %s (%d) on client #%u \n " ) , c - > errorToString ( error ) , error , i ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Error %s (%d) on client #%u \n " ) , c - > errorToString ( error ) , error , i ) ;
} , 0 ) ;
} , 0 ) ;
client - > onTimeout ( [ i ] ( void * s , AsyncClient * c , uint32_t time ) {
_telnetClients [ i ] - > onTimeout ( [ i ] ( void * s , AsyncClient * c , uint32_t time ) {
DEBUG_MSG_P ( PSTR ( " [TELNET] Timeout on client #%u at %lu \n " ) , i , time ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Timeout on client #%u at %lu \n " ) , i , time ) ;
c - > close ( ) ;
c - > close ( ) ;
} , 0 ) ;
} , 0 ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Client #%u connected \n " ) , i ) ;
// If there is no terminal support automatically dump info and crash data
# if TERMINAL_SUPPORT == 0
info ( ) ;
wifiDebug ( ) ;
crashDump ( ) ;
crashClear ( ) ;
# endif
# ifdef ESPURNA_CORE
_telnetClientsAuth [ i ] = true ;
# else
_telnetClientsAuth [ i ] = ! _telnetAuth ;
if ( _telnetAuth ) _telnetWrite ( i , " Password: " ) ;
# endif
_telnetFirst = true ;
wifiReconnectCheck ( ) ;
_telnetNotifyConnected ( i ) ;
return ;
return ;
}
}
}
}
DEBUG_MSG_P ( PSTR ( " [TELNET] Rejecting - Too many connections \n " ) ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Rejecting - Too many connections \n " ) ) ;
client - > onDisconnect ( [ ] ( void * s , AsyncClient * c ) {
client - > onDisconnect ( [ ] ( void * s , AsyncClient * c ) {
c - > free ( ) ;
delete c ;
delete c ;
} ) ;
} ) ;
client - > close ( true ) ;
client - > close ( true ) ;
}
}
# endif // TELNET_SERVER == TELNET_SERVER_WIFISERVER
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Public API
// Public API
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
@ -228,12 +301,16 @@ void _telnetConfigure() {
}
}
void telnetSetup ( ) {
void telnetSetup ( ) {
_telnetServer = new AsyncServer ( TELNET_PORT ) ;
_telnetServer - > onClient ( [ ] ( void * s , AsyncClient * c ) {
_telnetNewClient ( c ) ;
} , 0 ) ;
_telnetServer - > begin ( ) ;
# if TELNET_SERVER == TELNET_SERVER_WIFISERVER
espurnaRegisterLoop ( _telnetLoop ) ;
_telnetServer . setNoDelay ( true ) ;
_telnetServer . begin ( ) ;
# else
_telnetServer . onClient ( [ ] ( void * s , AsyncClient * c ) {
_telnetNewClient ( c ) ;
} , 0 ) ;
_telnetServer . begin ( ) ;
# endif
# if WEB_SUPPORT
# if WEB_SUPPORT
wsOnSendRegister ( _telnetWebSocketOnSend ) ;
wsOnSendRegister ( _telnetWebSocketOnSend ) ;
@ -243,7 +320,9 @@ void telnetSetup() {
espurnaRegisterReload ( _telnetConfigure ) ;
espurnaRegisterReload ( _telnetConfigure ) ;
_telnetConfigure ( ) ;
_telnetConfigure ( ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] Listening on port %d \n " ) , TELNET_PORT ) ;
DEBUG_MSG_P ( PSTR ( " [TELNET] %s server, Listening on port %d \n " ) ,
( TELNET_SERVER = = TELNET_SERVER_WIFISERVER ) ? " Sync " : " Async " ,
TELNET_PORT ) ;
}
}