From 0a3f8c6d6720065d24bb9b7346fa0cd6ec78d776 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 9 Apr 2026 08:56:11 -1000 Subject: [PATCH] [socket] Add unified UDP recv loop-monitored factory functions Add socket_udp_recv_loop_monitored() and socket_ip_udp_recv_loop_monitored() so consumers can create UDP recv sockets with loop wake support using a single API across all platforms, without #ifdef guards. --- .../components/socket/lwip_raw_tcp_impl.cpp | 5 +++++ esphome/components/socket/socket.cpp | 12 ++++++++++++ esphome/components/socket/socket.h | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/esphome/components/socket/lwip_raw_tcp_impl.cpp b/esphome/components/socket/lwip_raw_tcp_impl.cpp index a849694321c..6b359585f34 100644 --- a/esphome/components/socket/lwip_raw_tcp_impl.cpp +++ b/esphome/components/socket/lwip_raw_tcp_impl.cpp @@ -1249,6 +1249,11 @@ std::unique_ptr socket_udp_recv(int domain, int protocol) { return sock; } +std::unique_ptr socket_udp_recv_loop_monitored(int domain, int protocol) { + // LWIPRawUDPRecvImpl has wake built into the recv callback, so no extra monitoring needed + return socket_udp_recv(domain, protocol); +} + std::unique_ptr socket_listen(int domain, int type, int protocol) { if (type != SOCK_STREAM) { ESP_LOGE(TAG, "Use socket_udp_recv() for UDP sockets on this platform"); diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index abce03ae230..6edbcf4e982 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -101,6 +101,18 @@ std::unique_ptr socket_ip_loop_monitored(int type, int protocol) { } #endif +#ifdef USE_SOCKET_IMPL_LWIP_TCP +// LWIP_TCP has separate UDPRecvSocket type — needs out-of-line factory. +// BSD and LWIP_SOCKETS define this inline in socket.h. +std::unique_ptr socket_ip_udp_recv_loop_monitored(int protocol) { +#if USE_NETWORK_IPV6 + return socket_udp_recv_loop_monitored(AF_INET6, protocol); +#else + return socket_udp_recv_loop_monitored(AF_INET, protocol); +#endif /* USE_NETWORK_IPV6 */ +} +#endif + #if !defined(USE_SOCKET_IMPL_LWIP_TCP) // BSD and LWIP_SOCKETS: UDPSocket == UDPRecvSocket == Socket, so these just delegate. std::unique_ptr socket_udp(int domain, int protocol) { diff --git a/esphome/components/socket/socket.h b/esphome/components/socket/socket.h index 8f84df9c308..d919ad8aa88 100644 --- a/esphome/components/socket/socket.h +++ b/esphome/components/socket/socket.h @@ -98,6 +98,25 @@ std::unique_ptr socket_udp_recv(int domain, int protocol); /// Create a UDP socket with receive support in the newest available IP domain. std::unique_ptr socket_ip_udp_recv(int protocol); +/// Create a UDP recv socket and monitor it for data in the main loop. +/// On LWIP_TCP platforms, wake is built into the recv callback so this just delegates to socket_udp_recv(). +/// On BSD/LWIP_SOCKETS platforms, this registers the socket with the Application's select() loop. +#ifdef USE_SOCKET_IMPL_LWIP_TCP +std::unique_ptr socket_udp_recv_loop_monitored(int domain, int protocol); +std::unique_ptr socket_ip_udp_recv_loop_monitored(int protocol); +#else +inline std::unique_ptr socket_udp_recv_loop_monitored(int domain, int protocol) { + return socket_loop_monitored(domain, SOCK_DGRAM, protocol); +} +inline std::unique_ptr socket_ip_udp_recv_loop_monitored(int protocol) { +#if USE_NETWORK_IPV6 + return socket_udp_recv_loop_monitored(AF_INET6, protocol); +#else + return socket_udp_recv_loop_monitored(AF_INET, protocol); +#endif +} +#endif + /// Create a socket and monitor it for data in the main loop. /// Like socket() but also registers the socket with the Application's select() loop. /// WARNING: These functions are NOT thread-safe. They must only be called from the main loop