tcp_abort()/tcp_abandon() asserts pcb->state != LISTEN and accesses
fields beyond tcp_pcb_listen. Use tcp_close() instead and null pcb_
so the base destructor skips tcp_abort.
tcp_listen_with_backlog() converts the full tcp_pcb to a smaller
tcp_pcb_listen struct that lacks the errf field. Calling tcp_err()
on a listen PCB writes past the struct boundary, causing memory
corruption and crashes (confirmed on RP2040).
LWIP itself asserts pcb->state != LISTEN in tcp_err().
The destructor relies solely on tcp_abort() for cleanup, but LWIP
considers ownership of pbufs transferred once the recv callback
accepts them. If rx_buf_ is non-null when the socket is destroyed,
those pbufs are leaked. Free them explicitly before the base class
destructor calls tcp_abort().
Fix two pre-existing bugs found during review of #14398:
1. bind() returns 0 on nullptr name instead of -1, inconsistent with
POSIX bind() semantics and can mask invalid calls.
2. listen() doesn't re-register tcp_err after tcp_listen_with_backlog
reallocates the PCB. The error callback was set during init() on
the original PCB which is now freed, leaving the new listen PCB
without an error handler.
clang-tidy flags the forward declaration in application.h as redundant
since socket.h (included earlier via esphome.h) already declares it.
The forward declaration is needed here for the friend declaration.
- Rename internal_write/internal_output to internal_write_/internal_output_
(protected methods require trailing underscore)
- Fix getpeername/getsockname parameter name mismatch between .h and .cpp
The CI lint rule disallows ESP_LOG* references in header files.
Move LWIP_LOG macro definition and all methods that use it
(destructors, init(), static callbacks) to the .cpp file.
Co-Authored-By: J. Nick Koston <nick@koston.org>
Replace the virtual Socket base class with compile-time type aliases.
Since only one socket implementation is active per build (selected via
#ifdef), virtual dispatch was unnecessary overhead.
Each implementation (BSDSocketImpl, LwIPSocketImpl, LWIPRawImpl) is now
a concrete class in its own header with no virtual methods. socket::Socket
and socket::ListenSocket are type aliases to the active implementation.
For LWIP_TCP (ESP8266/RP2040), the listen socket is a separate type
(LWIPRawListenImpl) sharing a non-virtual LWIPRawCommon base with the
connected socket type (LWIPRawImpl). On BSD/LWIP_SOCKETS, both aliases
resolve to the same type.
This eliminates all vtable overhead, virtual destructors, and indirect
call overhead across all platforms.
Co-Authored-By: J. Nick Koston <nick@koston.org>