diff --git a/src/TCPClientInterface.cpp b/src/TCPClientInterface.cpp index 2cda6a52..85d9220e 100644 --- a/src/TCPClientInterface.cpp +++ b/src/TCPClientInterface.cpp @@ -265,7 +265,9 @@ void TCPClientInterface::handle_disconnect() { #ifdef ARDUINO /*static*/ void TCPClientInterface::tcp_task(void* arg) { - static_cast(arg)->task_loop(); + auto* self = static_cast(arg); + self->task_loop(); + self->_task_done = true; // let stop() join before the object is freed vTaskDelete(nullptr); } @@ -299,11 +301,16 @@ void TCPClientInterface::task_loop() { /*virtual*/ void TCPClientInterface::stop() { #ifdef ARDUINO - // Stop the connect task first; wait long enough for any in-flight connect() - // (bounded by CONNECT_TIMEOUT_MS) to finish so we don't close _client under it. + // Join the task: signal it, then wait until it has actually left task_loop() + // before tearing anything down. An in-flight connect() can overrun + // CONNECT_TIMEOUT_MS on a slow DNS server, and ~TCPClientInterface() calls + // stop() — returning early would risk a use-after-free on `this`. _task_running = false; if (_task_handle != nullptr) { - vTaskDelay(pdMS_TO_TICKS(CONNECT_TIMEOUT_MS + 500)); + uint32_t deadline = millis() + CONNECT_TIMEOUT_MS + 2000; + while (!_task_done && (int32_t)(millis() - deadline) < 0) { + vTaskDelay(pdMS_TO_TICKS(20)); + } _task_handle = nullptr; } _conn_state.store(DISCONNECTED); diff --git a/src/TCPClientInterface.h b/src/TCPClientInterface.h index 1fac05f2..de52846d 100644 --- a/src/TCPClientInterface.h +++ b/src/TCPClientInterface.h @@ -94,6 +94,7 @@ private: void task_loop(); TaskHandle_t _task_handle = nullptr; volatile bool _task_running = false; + volatile bool _task_done = false; // task sets this right before exit; stop() joins on it std::atomic _conn_state{DISCONNECTED}; #endif @@ -107,7 +108,12 @@ private: // Connection state bool _initiator = true; +#ifdef ARDUINO + // Touched by both task_loop() (core 0) and handle_disconnect() (core 1). + std::atomic _last_connect_attempt{0}; +#else uint32_t _last_connect_attempt = 0; +#endif #ifdef ARDUINO std::atomic _reconnected{false}; // re-established after offline (task-set) #else