[api] Fix ESP8266 noise API handshake deadlock and prompt socket cleanup (#13972)

This commit is contained in:
J. Nick Koston
2026-02-12 18:20:58 -06:00
committed by GitHub
parent 7dff631dcb
commit e0c03b2dfa
2 changed files with 12 additions and 6 deletions

View File

@@ -138,10 +138,12 @@ APIError APINoiseFrameHelper::handle_noise_error_(int err, const LogString *func
/// Run through handshake messages (if in that phase)
APIError APINoiseFrameHelper::loop() {
// During handshake phase, process as many actions as possible until we can't progress
// socket_->ready() stays true until next main loop, but state_action() will return
// WOULD_BLOCK when no more data is available to read
while (state_ != State::DATA && this->socket_->ready()) {
// Cache ready() outside the loop. On ESP8266 LWIP raw TCP, ready() returns false once
// the rx buffer is consumed. Re-checking each iteration would block handshake writes
// that must follow reads, deadlocking the handshake. state_action() will return
// WOULD_BLOCK when no more data is available to read.
bool socket_ready = this->socket_->ready();
while (state_ != State::DATA && socket_ready) {
APIError err = state_action_();
if (err == APIError::WOULD_BLOCK) {
break;

View File

@@ -148,12 +148,16 @@ void APIServer::loop() {
while (client_index < this->clients_.size()) {
auto &client = this->clients_[client_index];
// Common case: process active client
if (!client->flags_.remove) {
client->loop();
}
// Handle disconnection promptly - close socket to free LWIP PCB
// resources and prevent retransmit crashes on ESP8266.
if (client->flags_.remove) {
// Rare case: handle disconnection (don't increment - swapped element needs processing)
this->remove_client_(client_index);
} else {
// Common case: process active client
client->loop();
client_index++;
}
}