[socket] Implement working ready() for LWIP raw TCP sockets (ESP8266/RP2040)

Previously ready() always returned true on ESP8266/RP2040, causing
every socket to be checked on every loop iteration even when no data
was available.

Override ready() in LWIPRawImpl to check rx_buf_/rx_closed_/pcb_ state,
and in LWIPRawListenImpl to check accepted_socket_count_. This uses
existing fields so no extra memory is needed per socket.

Keep ready() virtual only on the non-select path (ESP8266/RP2040) so
the select()-based path (ESP32) retains the non-virtual optimization
from the previous commit.
This commit is contained in:
J. Nick Koston
2026-02-10 17:37:42 -06:00
parent 4a6eb0b16d
commit fd683a5609
3 changed files with 12 additions and 8 deletions
@@ -452,6 +452,8 @@ class LWIPRawImpl : public Socket {
errno = ENOSYS;
return -1;
}
bool ready() const override { return this->rx_buf_ != nullptr || this->rx_closed_ || this->pcb_ == nullptr; }
int setblocking(bool blocking) final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
@@ -576,6 +578,8 @@ class LWIPRawListenImpl final : public LWIPRawImpl {
tcp_err(pcb_, LWIPRawImpl::s_err_fn); // Use base class error handler
}
bool ready() const override { return this->accepted_socket_count_ > 0; }
std::unique_ptr<Socket> accept(struct sockaddr *addr, socklen_t *addrlen) override {
if (pcb_ == nullptr) {
errno = EBADF;
+1 -5
View File
@@ -10,13 +10,9 @@ namespace esphome::socket {
Socket::~Socket() {}
bool Socket::ready() const {
#ifdef USE_SOCKET_SELECT_SUPPORT
return !this->loop_monitored_ || App.is_socket_ready_(this->fd_);
#else
return true;
bool Socket::ready() const { return !this->loop_monitored_ || App.is_socket_ready_(this->fd_); }
#endif
}
// Platform-specific inet_ntop wrappers
#if defined(USE_SOCKET_IMPL_LWIP_TCP)
+7 -3
View File
@@ -71,10 +71,14 @@ class Socket {
int get_fd() const { return -1; }
#endif
/// Check if socket has data ready to read (non-virtual for direct call)
/// For loop-monitored sockets, checks the Application's select() results
/// For non-monitored sockets, always returns true (assumes data may be available)
/// Check if socket has data ready to read
/// For select()-based sockets: non-virtual, checks Application's select() results
/// For LWIP raw TCP sockets: virtual, checks internal buffer state
#ifdef USE_SOCKET_SELECT_SUPPORT
bool ready() const;
#else
virtual bool ready() const { return true; }
#endif
protected:
#ifdef USE_SOCKET_SELECT_SUPPORT