mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-25 19:56:30 +00:00
Add telnet graceful close
This commit is contained in:
parent
1ada6da6b8
commit
73cace5274
@ -529,10 +529,10 @@ enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE
|
|||||||
|
|
||||||
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
|
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
|
||||||
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,
|
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,
|
||||||
SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_SSERIAL, SRC_USBCONSOLE, SRC_SO47, SRC_SENSOR, SRC_WEB, SRC_MAX };
|
SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_SSERIAL, SRC_USBCONSOLE, SRC_SO47, SRC_SENSOR, SRC_WEB, SRC_TELNET, SRC_MAX };
|
||||||
const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|"
|
const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|"
|
||||||
"Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|"
|
"Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|"
|
||||||
"Thermostat|Chat|TCL|Berry|File|SSerial|UsbConsole|SO47|Sensor|Web";
|
"Thermostat|Chat|TCL|Berry|File|SSerial|UsbConsole|SO47|Sensor|Web|Telnet";
|
||||||
|
|
||||||
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };
|
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };
|
||||||
|
|
||||||
|
@ -9,19 +9,32 @@
|
|||||||
#ifdef USE_TELNET
|
#ifdef USE_TELNET
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* Telnet console support for a single connection
|
* Telnet console support for a single connection
|
||||||
|
*
|
||||||
|
* Supported commands:
|
||||||
|
* Telnet - Show telnet server state
|
||||||
|
* Telnet 0 - Disable telnet server
|
||||||
|
* Telnet 1 - Enable telnet server on port 23
|
||||||
|
* Telnet 23 - Enable telnet server on port 23
|
||||||
|
* Telnet 1, 192.168.2.1 - Enable telnet server and only allow connection from 192.168.2.1
|
||||||
|
* TelnetBuffer - Show current input buffer size (default 256)
|
||||||
|
* TelnetBuffer 300 - Change input buffer size to 300 characters
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
#define XDRV_78 78
|
#define XDRV_78 78
|
||||||
|
|
||||||
#ifndef TELNET_BUF_SIZE
|
#ifndef TELNET_BUF_SIZE
|
||||||
#define TELNET_BUF_SIZE 255 // size of the buffer
|
#define TELNET_BUF_SIZE 256 // Size of input buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TELNET_PROMPT_COLOR
|
||||||
|
#define TELNET_PROMPT_COLOR 33 // Yellow - ANSI color escape code
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
WiFiServer *server = nullptr;
|
WiFiServer *server = nullptr;
|
||||||
WiFiClient client;
|
WiFiClient client;
|
||||||
IPAddress ip_filter;
|
IPAddress ip_filter;
|
||||||
char *buffer = nullptr; // data transfer buffer
|
char *buffer = nullptr;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
uint16_t buffer_size = TELNET_BUF_SIZE;
|
uint16_t buffer_size = TELNET_BUF_SIZE;
|
||||||
bool ip_filter_enabled = false;
|
bool ip_filter_enabled = false;
|
||||||
@ -52,8 +65,8 @@ void TelnetLoop(void) {
|
|||||||
if (Telnet.ip_filter != new_client.remoteIP()) {
|
if (Telnet.ip_filter != new_client.remoteIP()) {
|
||||||
AddLog(LOG_LEVEL_INFO, PSTR("TLN: Rejected due to filtering"));
|
AddLog(LOG_LEVEL_INFO, PSTR("TLN: Rejected due to filtering"));
|
||||||
new_client.stop();
|
new_client.stop();
|
||||||
} else {
|
// } else {
|
||||||
AddLog(LOG_LEVEL_INFO, PSTR("TLN: Allowed through filter"));
|
// AddLog(LOG_LEVEL_INFO, PSTR("TLN: Allowed through filter"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,8 +76,8 @@ void TelnetLoop(void) {
|
|||||||
}
|
}
|
||||||
client = new_client;
|
client = new_client;
|
||||||
if (client) {
|
if (client) {
|
||||||
client.printf("Tasmota %s %s (%s)\r\n\n", TasmotaGlobal.hostname, TasmotaGlobal.version, GetBuildDateAndTime().c_str());
|
client.printf("Tasmota %s %s (%s) %s\r\n\n", TasmotaGlobal.hostname, TasmotaGlobal.version, GetBuildDateAndTime().c_str(), GetDeviceHardware().c_str());
|
||||||
uint32_t index = 1;
|
uint32_t index = 1; // Dump start of log buffer for restart messages
|
||||||
char* line;
|
char* line;
|
||||||
size_t len;
|
size_t len;
|
||||||
while (GetLog(TasmotaGlobal.seriallog_level, &index, &line, &len)) {
|
while (GetLog(TasmotaGlobal.seriallog_level, &index, &line, &len)) {
|
||||||
@ -72,7 +85,8 @@ void TelnetLoop(void) {
|
|||||||
client.write(line, len -1);
|
client.write(line, len -1);
|
||||||
client.write("\r\n");
|
client.write("\r\n");
|
||||||
}
|
}
|
||||||
client.printf("%s:# ", TasmotaGlobal.hostname);
|
// client.printf("\e[%dm%s:#\e[0m ", TELNET_PROMPT_COLOR, TasmotaGlobal.hostname); // \e[33m = Yellow, \e[0m = end color
|
||||||
|
client.printf("\x1b[%dm%s:#\x1b[0m ", TELNET_PROMPT_COLOR, TasmotaGlobal.hostname); // \x1b[33m = Yellow, \x1b[0m = end color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,8 +94,8 @@ void TelnetLoop(void) {
|
|||||||
uint32_t buf_len = 0;
|
uint32_t buf_len = 0;
|
||||||
do {
|
do {
|
||||||
busy = false; // exit loop if no data was transferred
|
busy = false; // exit loop if no data was transferred
|
||||||
WiFiClient &client = Telnet.client;
|
|
||||||
bool overrun = false;
|
bool overrun = false;
|
||||||
|
WiFiClient &client = Telnet.client;
|
||||||
while (client && (client.available())) {
|
while (client && (client.available())) {
|
||||||
uint8_t c = client.read();
|
uint8_t c = client.read();
|
||||||
if (c >= 0) {
|
if (c >= 0) {
|
||||||
@ -100,35 +114,38 @@ void TelnetLoop(void) {
|
|||||||
AddLog(LOG_LEVEL_INFO, PSTR("TLN: buffer overrun"));
|
AddLog(LOG_LEVEL_INFO, PSTR("TLN: buffer overrun"));
|
||||||
} else {
|
} else {
|
||||||
AddLog(LOG_LEVEL_INFO, PSTR("TLN: %s"), Telnet.buffer);
|
AddLog(LOG_LEVEL_INFO, PSTR("TLN: %s"), Telnet.buffer);
|
||||||
ExecuteCommand(Telnet.buffer, SRC_REMOTE);
|
ExecuteCommand(Telnet.buffer, SRC_TELNET);
|
||||||
}
|
}
|
||||||
client.flush();
|
client.flush();
|
||||||
client.printf("%s:# ", TasmotaGlobal.hostname);
|
// client.printf("\e[%dm%s:#\e[0m ", TELNET_PROMPT_COLOR, TasmotaGlobal.hostname); // \e[33m = Yellow, \e[0m = end color
|
||||||
|
client.printf("\x1b[%dm%s:#\x1b[0m ", TELNET_PROMPT_COLOR, TasmotaGlobal.hostname); // \x1b[33m = Yellow, \x1b[0m = end color
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
yield(); // avoid WDT if heavy traffic
|
yield(); // Avoid WDT if heavy traffic
|
||||||
} while (busy);
|
} while (busy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Commands
|
|
||||||
\*********************************************************************************************/
|
|
||||||
|
|
||||||
void TelnetStop(void) {
|
void TelnetStop(void) {
|
||||||
Telnet.server->stop();
|
Telnet.server->stop();
|
||||||
delete Telnet.server;
|
delete Telnet.server;
|
||||||
Telnet.server = nullptr;
|
Telnet.server = nullptr;
|
||||||
|
|
||||||
WiFiClient &client = Telnet.client;
|
WiFiClient &client = Telnet.client;
|
||||||
|
if (client) {
|
||||||
client.stop();
|
client.stop();
|
||||||
|
}
|
||||||
|
|
||||||
free(Telnet.buffer);
|
free(Telnet.buffer);
|
||||||
Telnet.buffer = nullptr;
|
Telnet.buffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char kTelnetCommands[] PROGMEM = "Telnet|" // prefix
|
/*********************************************************************************************\
|
||||||
|
* Commands
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
const char kTelnetCommands[] PROGMEM = "Telnet|" // Prefix
|
||||||
"|Buffer";
|
"|Buffer";
|
||||||
|
|
||||||
void (* const TelnetCommand[])(void) PROGMEM = {
|
void (* const TelnetCommand[])(void) PROGMEM = {
|
||||||
@ -149,19 +166,16 @@ void CmndTelnet(void) {
|
|||||||
Telnet.ip_filter.fromString(ArgV(sub_string, 2));
|
Telnet.ip_filter.fromString(ArgV(sub_string, 2));
|
||||||
Telnet.ip_filter_enabled = true;
|
Telnet.ip_filter_enabled = true;
|
||||||
} else {
|
} else {
|
||||||
// Disable whitelist if previously set
|
Telnet.ip_filter_enabled = false; // Disable whitelist if previously set
|
||||||
Telnet.ip_filter_enabled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Telnet.server) {
|
if (Telnet.server) {
|
||||||
TelnetStop();
|
TelnetStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Telnet.port > 0) {
|
if (Telnet.port > 0) {
|
||||||
if (!Telnet.buffer) {
|
if (!Telnet.buffer) {
|
||||||
Telnet.buffer = (char*)malloc(Telnet.buffer_size);
|
Telnet.buffer = (char*)malloc(Telnet.buffer_size);
|
||||||
if (!Telnet.buffer) { return; }
|
if (Telnet.buffer) {
|
||||||
|
|
||||||
if (1 == Telnet.port) { Telnet.port = 23; }
|
if (1 == Telnet.port) { Telnet.port = 23; }
|
||||||
Telnet.server = new WiFiServer(Telnet.port);
|
Telnet.server = new WiFiServer(Telnet.port);
|
||||||
Telnet.server->begin(); // start TCP server
|
Telnet.server->begin(); // start TCP server
|
||||||
@ -169,6 +183,7 @@ void CmndTelnet(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (Telnet.server) {
|
if (Telnet.server) {
|
||||||
ResponseCmndChar_P(PSTR("Started"));
|
ResponseCmndChar_P(PSTR("Started"));
|
||||||
} else {
|
} else {
|
||||||
@ -178,7 +193,7 @@ void CmndTelnet(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CmndTelnetBuffer(void) {
|
void CmndTelnetBuffer(void) {
|
||||||
// TelnetBuffer - Show current input buffer size (default 255)
|
// TelnetBuffer - Show current input buffer size (default 256)
|
||||||
// TelnetBuffer 300 - Change input buffer size to 300 characters
|
// TelnetBuffer 300 - Change input buffer size to 300 characters
|
||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
uint16_t bsize = Telnet.buffer_size;
|
uint16_t bsize = Telnet.buffer_size;
|
||||||
@ -187,7 +202,7 @@ void CmndTelnetBuffer(void) {
|
|||||||
Telnet.buffer_size = MIN_INPUT_BUFFER_SIZE; // 256 / 256
|
Telnet.buffer_size = MIN_INPUT_BUFFER_SIZE; // 256 / 256
|
||||||
}
|
}
|
||||||
else if (XdrvMailbox.payload > INPUT_BUFFER_SIZE) {
|
else if (XdrvMailbox.payload > INPUT_BUFFER_SIZE) {
|
||||||
Telnet.buffer_size = INPUT_BUFFER_SIZE; // 256 / 800
|
Telnet.buffer_size = INPUT_BUFFER_SIZE; // 800
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Telnet.buffer && (bsize != Telnet.buffer_size)) {
|
if (Telnet.buffer && (bsize != Telnet.buffer_size)) {
|
||||||
@ -216,6 +231,9 @@ bool Xdrv78(uint32_t function) {
|
|||||||
case FUNC_LOOP:
|
case FUNC_LOOP:
|
||||||
TelnetLoop();
|
TelnetLoop();
|
||||||
break;
|
break;
|
||||||
|
case FUNC_SAVE_BEFORE_RESTART:
|
||||||
|
TelnetStop();
|
||||||
|
break;
|
||||||
case FUNC_ACTIVE:
|
case FUNC_ACTIVE:
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user