Fix telnet async input

This commit is contained in:
Theo Arends 2025-03-22 12:04:02 +01:00
parent 9e3ad52356
commit b47a1bc1e2

View File

@ -24,7 +24,7 @@
* To start telnet at restart add a rule like * To start telnet at restart add a rule like
* on system#boot do backlog telnetcolor 33,36,32; telnet 1 endon * on system#boot do backlog telnetcolor 33,36,32; telnet 1 endon
* *
* Supported color codes: * Supported ANSI Escape Color codes:
* Black 30 * Black 30
* Red 31 * Red 31
* Green 32 * Green 32
@ -59,8 +59,10 @@ struct {
char *buffer = nullptr; char *buffer = nullptr;
uint16_t port; uint16_t port;
uint16_t buffer_size; uint16_t buffer_size;
uint16_t in_byte_counter;
uint8_t prompt; uint8_t prompt;
uint8_t color[3]; uint8_t color[3];
bool overrun;
bool ip_filter_enabled; bool ip_filter_enabled;
} Telnet; } Telnet;
@ -124,61 +126,55 @@ void TelnetLoop(void) {
} }
} }
if (0 == Telnet.prompt) {
WiFiClient &client = Telnet.client; WiFiClient &client = Telnet.client;
if (client) { if (client) {
if (0 == Telnet.prompt) {
client.printf("\x1b[%dm%s:#\x1b[0m ", Telnet.color[0], TasmotaGlobal.hostname); // \x1b[33m = Yellow, \x1b[0m = end color client.printf("\x1b[%dm%s:#\x1b[0m ", Telnet.color[0], TasmotaGlobal.hostname); // \x1b[33m = Yellow, \x1b[0m = end color
Telnet.prompt = 1; // Print single linefeed for non-requested data Telnet.prompt = 1; // Print single linefeed for non-requested data
} while (client.available()) { client.read(); } // Flush input
return;
} }
bool busy; while (client.available()) {
uint32_t buf_len = 0; yield();
do { uint8_t in_byte = client.read();
busy = false; // Exit loop if no data was transferred if (isprint(in_byte)) { // Any char between 32 and 127
bool overrun = false; if (Telnet.in_byte_counter < Telnet.buffer_size -1) { // Add char to string if it still fits
WiFiClient &client = Telnet.client; Telnet.buffer[Telnet.in_byte_counter++] = in_byte;
while (client && (client.available())) {
uint8_t c = client.read();
if (c >= 0) {
busy = true;
if (isprint(c)) { // Any char between 32 and 127
if (buf_len < Telnet.buffer_size -1) { // Add char to string if it still fits
Telnet.buffer[buf_len++] = c;
} else { } else {
overrun = true; // Signal overrun but continue reading input to flush until '\n' (EOL) Telnet.overrun = true; // Signal overrun but continue reading input to flush until '\n' (EOL)
} }
} }
else if (c == '\n') { else if (in_byte == '\n') {
Telnet.buffer[buf_len] = 0; // Telnet data completed Telnet.buffer[Telnet.in_byte_counter] = 0; // Telnet data completed
TasmotaGlobal.seriallog_level = (Settings->seriallog_level < LOG_LEVEL_INFO) ? (uint8_t)LOG_LEVEL_INFO : Settings->seriallog_level; TasmotaGlobal.seriallog_level = (Settings->seriallog_level < LOG_LEVEL_INFO) ? (uint8_t)LOG_LEVEL_INFO : Settings->seriallog_level;
client.printf("\r"); // Move cursor to begin of line (needed for non-buffered input)
Telnet.prompt = 2; // Do not print linefeed for requested data Telnet.prompt = 2; // Do not print linefeed for requested data
if (overrun) { if (Telnet.overrun) {
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_TELNET); ExecuteCommand(Telnet.buffer, SRC_TELNET);
} }
Telnet.in_byte_counter = 0;
Telnet.overrun = false;
Telnet.prompt = 0; // Print prompt Telnet.prompt = 0; // Print prompt
client.flush();
return; return;
} }
} }
} }
yield(); // Avoid WDT if heavy traffic
} while (busy);
} }
void TelnetStop(void) { void TelnetStop(void) {
if (Telnet.server) {
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) { if (client) {
client.stop(); client.stop();
} }
free(Telnet.buffer); free(Telnet.buffer);
Telnet.buffer = nullptr; Telnet.buffer = nullptr;
} }
@ -228,7 +224,7 @@ void CmndTelnet(void) {
if (Telnet.buffer) { 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
Telnet.server->setNoDelay(true); Telnet.server->setNoDelay(true);
} }
} }