From e7c126d3dc64ef84a8dce57b3b54a71d1f7f752f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 10 Apr 2026 18:40:14 -1000 Subject: [PATCH] [socket] Rename UDP socket types so UDPSocket is the full send+recv type Swap the UDP type naming so the unsuffixed UDPSocket is the full send+recv socket and the send-only variant becomes UDPSendSocket. The previous naming inverted reader expectations (UDPSocket sounded complete but was send-only, UDPRecvSocket sounded limited but was the full one). Public: UDPSocket (was UDPRecvSocket) UDPSendSocket (was UDPSocket) socket_udp (was socket_udp_recv) socket_ip_udp (was socket_ip_udp_recv) socket_udp_loop_monitored (was socket_udp_recv_loop_monitored) socket_ip_udp_loop_monitored (was socket_ip_udp_recv_loop_monitored) socket_udp_send (was socket_udp) socket_ip_udp_send (was socket_ip_udp) Internal: LWIPRawUDPImpl (was LWIPRawUDPRecvImpl) LWIPRawUDPSendImpl (was LWIPRawUDPImpl) No consumers exist yet, so this is a clean rename with no migration. --- .../components/socket/lwip_raw_tcp_impl.cpp | 2 +- .../components/socket/lwip_raw_udp_impl.cpp | 74 +++++++++---------- esphome/components/socket/lwip_raw_udp_impl.h | 22 +++--- esphome/components/socket/socket.h | 59 +++++++-------- 4 files changed, 79 insertions(+), 78 deletions(-) diff --git a/esphome/components/socket/lwip_raw_tcp_impl.cpp b/esphome/components/socket/lwip_raw_tcp_impl.cpp index ac5011c0b1..5c75f4e999 100644 --- a/esphome/components/socket/lwip_raw_tcp_impl.cpp +++ b/esphome/components/socket/lwip_raw_tcp_impl.cpp @@ -796,7 +796,7 @@ std::unique_ptr socket_loop_monitored(int domain, int type, int 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"); + ESP_LOGE(TAG, "Use socket_udp() for UDP sockets on this platform"); errno = EPROTOTYPE; return nullptr; } diff --git a/esphome/components/socket/lwip_raw_udp_impl.cpp b/esphome/components/socket/lwip_raw_udp_impl.cpp index 806e3c9ca9..40ed6d6863 100644 --- a/esphome/components/socket/lwip_raw_udp_impl.cpp +++ b/esphome/components/socket/lwip_raw_udp_impl.cpp @@ -24,9 +24,9 @@ namespace esphome::socket { static const char *const TAG = "socket.lwip_udp"; -// ---- LWIPRawUDPImpl (send-only) methods ---- +// ---- LWIPRawUDPSendImpl (send-only) methods ---- -LWIPRawUDPImpl::LWIPRawUDPImpl(sa_family_t family) : family_(family) { +LWIPRawUDPSendImpl::LWIPRawUDPSendImpl(sa_family_t family) : family_(family) { LWIP_LOCK(); #if LWIP_IPV6 this->pcb_ = udp_new_ip_type(family == AF_INET6 ? IPADDR_TYPE_ANY : IPADDR_TYPE_V4); @@ -35,9 +35,9 @@ LWIPRawUDPImpl::LWIPRawUDPImpl(sa_family_t family) : family_(family) { #endif } -LWIPRawUDPImpl::~LWIPRawUDPImpl() { +LWIPRawUDPSendImpl::~LWIPRawUDPSendImpl() { // Early return avoids acquiring the lwip lock when pcb_ is already null - // (e.g., after LWIPRawUDPRecvImpl::close() already cleaned up). + // (e.g., after LWIPRawUDPImpl::close() already cleaned up). if (this->pcb_ == nullptr) return; LWIP_LOCK(); @@ -45,7 +45,7 @@ LWIPRawUDPImpl::~LWIPRawUDPImpl() { this->pcb_ = nullptr; } -int LWIPRawUDPImpl::bind_internal_locked_(const struct sockaddr *name, socklen_t addrlen) { +int LWIPRawUDPSendImpl::bind_internal_locked_(const struct sockaddr *name, socklen_t addrlen) { // Caller must hold LWIP_LOCK if (this->pcb_ == nullptr) { errno = EBADF; @@ -72,17 +72,17 @@ int LWIPRawUDPImpl::bind_internal_locked_(const struct sockaddr *name, socklen_t return lwip_bind_err(udp_bind(this->pcb_, &ip, port)); } -int LWIPRawUDPImpl::bind(const struct sockaddr *name, socklen_t addrlen) { +int LWIPRawUDPSendImpl::bind(const struct sockaddr *name, socklen_t addrlen) { LWIP_LOCK(); return this->bind_internal_locked_(name, addrlen); } -int LWIPRawUDPImpl::close() { +int LWIPRawUDPSendImpl::close() { LWIP_LOCK(); return this->close_internal_locked_(); } -int LWIPRawUDPImpl::close_internal_locked_() { +int LWIPRawUDPSendImpl::close_internal_locked_() { // Caller must hold LWIP_LOCK if (this->pcb_ == nullptr) { errno = EBADF; @@ -93,13 +93,13 @@ int LWIPRawUDPImpl::close_internal_locked_() { return 0; } -int LWIPRawUDPImpl::ip2sockaddr_(const ip_addr_t *ip, uint16_t port, struct sockaddr *name, socklen_t *addrlen) { +int LWIPRawUDPSendImpl::ip2sockaddr_(const ip_addr_t *ip, uint16_t port, struct sockaddr *name, socklen_t *addrlen) { // UDP recv callback provides port in host byte order return lwip_ip_to_sockaddr(this->family_, ip, port, name, addrlen); } -ssize_t LWIPRawUDPImpl::sendto(const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, - socklen_t addrlen) { +ssize_t LWIPRawUDPSendImpl::sendto(const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, + socklen_t addrlen) { (void) flags; // Flags (MSG_DONTWAIT, etc.) are ignored; raw lwip is always non-blocking LWIP_LOCK(); if (this->pcb_ == nullptr) { @@ -142,7 +142,7 @@ ssize_t LWIPRawUDPImpl::sendto(const void *buf, size_t len, int flags, const str return (ssize_t) len; } -int LWIPRawUDPImpl::setsockopt(int level, int optname, const void *optval, socklen_t optlen) { +int LWIPRawUDPSendImpl::setsockopt(int level, int optname, const void *optval, socklen_t optlen) { LWIP_LOCK(); if (this->pcb_ == nullptr) { errno = EBADF; @@ -204,7 +204,7 @@ int LWIPRawUDPImpl::setsockopt(int level, int optname, const void *optval, sockl return -1; } -int LWIPRawUDPImpl::getsockopt(int level, int optname, void *optval, socklen_t *optlen) { +int LWIPRawUDPSendImpl::getsockopt(int level, int optname, void *optval, socklen_t *optlen) { LWIP_LOCK(); if (this->pcb_ == nullptr) { errno = EBADF; @@ -223,7 +223,7 @@ int LWIPRawUDPImpl::getsockopt(int level, int optname, void *optval, socklen_t * return -1; } -int LWIPRawUDPImpl::setblocking(bool blocking) { +int LWIPRawUDPSendImpl::setblocking(bool blocking) { if (blocking) { // blocking operation not supported on raw lwip errno = EINVAL; @@ -232,15 +232,15 @@ int LWIPRawUDPImpl::setblocking(bool blocking) { return 0; } -// ---- LWIPRawUDPRecvImpl methods ---- +// ---- LWIPRawUDPImpl methods ---- -LWIPRawUDPRecvImpl::~LWIPRawUDPRecvImpl() { +LWIPRawUDPImpl::~LWIPRawUDPImpl() { // Flush rx queue and unregister callback before base destructor removes pcb if (this->pcb_ != nullptr) this->close(); } -int LWIPRawUDPRecvImpl::close() { +int LWIPRawUDPImpl::close() { LWIP_LOCK(); // Unregister recv callback before removing pcb if (this->pcb_ != nullptr) { @@ -260,19 +260,19 @@ int LWIPRawUDPRecvImpl::close() { return this->close_internal_locked_(); } -int LWIPRawUDPRecvImpl::bind(const struct sockaddr *name, socklen_t addrlen) { +int LWIPRawUDPImpl::bind(const struct sockaddr *name, socklen_t addrlen) { LWIP_LOCK(); int ret = this->bind_internal_locked_(name, addrlen); if (ret != 0) return ret; // Register recv callback now that we're bound and ready to receive - udp_recv(this->pcb_, LWIPRawUDPRecvImpl::s_recv_fn, this); + udp_recv(this->pcb_, LWIPRawUDPImpl::s_recv_fn, this); return 0; } -ssize_t LWIPRawUDPRecvImpl::read(void *buf, size_t len) { return this->recvfrom(buf, len, nullptr, nullptr); } +ssize_t LWIPRawUDPImpl::read(void *buf, size_t len) { return this->recvfrom(buf, len, nullptr, nullptr); } -ssize_t LWIPRawUDPRecvImpl::recvfrom(void *buf, size_t len, struct sockaddr *src_addr, socklen_t *addrlen) { +ssize_t LWIPRawUDPImpl::recvfrom(void *buf, size_t len, struct sockaddr *src_addr, socklen_t *addrlen) { if (buf == nullptr && len > 0) { errno = EINVAL; return -1; @@ -313,15 +313,15 @@ ssize_t LWIPRawUDPRecvImpl::recvfrom(void *buf, size_t len, struct sockaddr *src return (ssize_t) copy_len; } -void LWIPRawUDPRecvImpl::s_recv_fn(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { - auto *self = reinterpret_cast(arg); +void LWIPRawUDPImpl::s_recv_fn(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { + auto *self = reinterpret_cast(arg); self->recv_fn_(p, addr, port); } // LWIP CALLBACK — runs from IRQ context on RP2040 (low-priority user IRQ). // No heap allocation allowed — malloc is not IRQ-safe (see #14687). // No LWIP_LOCK() needed — lwip core already holds the async_context lock. -void LWIPRawUDPRecvImpl::recv_fn_(struct pbuf *p, const ip_addr_t *addr, u16_t port) { +void LWIPRawUDPImpl::recv_fn_(struct pbuf *p, const ip_addr_t *addr, u16_t port) { if (p == nullptr) return; @@ -347,6 +347,16 @@ void LWIPRawUDPRecvImpl::recv_fn_(struct pbuf *p, const ip_addr_t *addr, u16_t p // ---- UDP Factory functions ---- +std::unique_ptr socket_udp_send(int domain, int protocol) { + (void) protocol; // Raw lwip UDP ignores protocol; kept for API compatibility + auto sock = make_unique((sa_family_t) domain); + if (!sock->is_valid()) { + errno = ENOMEM; + return nullptr; + } + return sock; +} + std::unique_ptr socket_udp(int domain, int protocol) { (void) protocol; // Raw lwip UDP ignores protocol; kept for API compatibility auto sock = make_unique((sa_family_t) domain); @@ -357,19 +367,9 @@ std::unique_ptr socket_udp(int domain, int protocol) { return sock; } -std::unique_ptr socket_udp_recv(int domain, int protocol) { - (void) protocol; // Raw lwip UDP ignores protocol; kept for API compatibility - auto sock = make_unique((sa_family_t) domain); - if (!sock->is_valid()) { - errno = ENOMEM; - return nullptr; - } - 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_udp_loop_monitored(int domain, int protocol) { + // LWIPRawUDPImpl has wake built into the recv callback, so no extra monitoring needed + return socket_udp(domain, protocol); } #undef LWIP_LOCK diff --git a/esphome/components/socket/lwip_raw_udp_impl.h b/esphome/components/socket/lwip_raw_udp_impl.h index daba09883e..8afe52625e 100644 --- a/esphome/components/socket/lwip_raw_udp_impl.h +++ b/esphome/components/socket/lwip_raw_udp_impl.h @@ -16,13 +16,13 @@ namespace esphome::socket { /// Send-only UDP socket implementation for LWIP raw API. /// Non-virtual, concrete type. Uses lwip/udp.h raw API. -/// No receive capability — use LWIPRawUDPRecvImpl for sockets that need to receive. -class LWIPRawUDPImpl { +/// No receive capability — use LWIPRawUDPImpl for sockets that need to receive. +class LWIPRawUDPSendImpl { public: - LWIPRawUDPImpl(sa_family_t family); - ~LWIPRawUDPImpl(); - LWIPRawUDPImpl(const LWIPRawUDPImpl &) = delete; - LWIPRawUDPImpl &operator=(const LWIPRawUDPImpl &) = delete; + LWIPRawUDPSendImpl(sa_family_t family); + ~LWIPRawUDPSendImpl(); + LWIPRawUDPSendImpl(const LWIPRawUDPSendImpl &) = delete; + LWIPRawUDPSendImpl &operator=(const LWIPRawUDPSendImpl &) = delete; int bind(const struct sockaddr *name, socklen_t addrlen); int close(); @@ -54,17 +54,17 @@ class LWIPRawUDPImpl { }; /// UDP socket with receive support for LWIP raw API. -/// Extends LWIPRawUDPImpl with a fixed-size ring buffer for incoming packets. +/// Extends LWIPRawUDPSendImpl with a fixed-size ring buffer for incoming packets. /// The recv callback is registered on bind(). /// /// Note: close() and bind() intentionally hide the base class methods to add /// recv callback registration/cleanup. This is safe because these classes are /// never used polymorphically (no virtual dispatch) — callers always use the -/// concrete LWIPRawUDPRecvImpl type via the UDPRecvSocket alias. -class LWIPRawUDPRecvImpl : public LWIPRawUDPImpl { +/// concrete LWIPRawUDPImpl type via the UDPSocket alias. +class LWIPRawUDPImpl : public LWIPRawUDPSendImpl { public: - using LWIPRawUDPImpl::LWIPRawUDPImpl; - ~LWIPRawUDPRecvImpl(); + using LWIPRawUDPSendImpl::LWIPRawUDPSendImpl; + ~LWIPRawUDPImpl(); /// Close the socket, flushing any queued rx packets first. int close(); diff --git a/esphome/components/socket/socket.h b/esphome/components/socket/socket.h index 3d0823b170..7e80081b84 100644 --- a/esphome/components/socket/socket.h +++ b/esphome/components/socket/socket.h @@ -27,24 +27,25 @@ namespace esphome::socket { // Type aliases — only one implementation is active per build. // Socket is the concrete type for connected sockets. // ListenSocket is the concrete type for listening/server sockets. -// UDPSocket is the concrete type for UDP sockets. +// UDPSocket is the concrete type for UDP sockets (send + receive). +// UDPSendSocket is the concrete type for send-only UDP sockets. // On BSD and LWIP_SOCKETS, all aliases resolve to the same type. // On LWIP_TCP, they are different types (no virtual dispatch between them). #ifdef USE_SOCKET_IMPL_BSD_SOCKETS using Socket = BSDSocketImpl; using ListenSocket = BSDSocketImpl; +using UDPSendSocket = BSDSocketImpl; using UDPSocket = BSDSocketImpl; -using UDPRecvSocket = BSDSocketImpl; #elif defined(USE_SOCKET_IMPL_LWIP_SOCKETS) using Socket = LwIPSocketImpl; using ListenSocket = LwIPSocketImpl; +using UDPSendSocket = LwIPSocketImpl; using UDPSocket = LwIPSocketImpl; -using UDPRecvSocket = LwIPSocketImpl; #elif defined(USE_SOCKET_IMPL_LWIP_TCP) using Socket = LWIPRawImpl; using ListenSocket = LWIPRawListenImpl; +using UDPSendSocket = LWIPRawUDPSendImpl; using UDPSocket = LWIPRawUDPImpl; -using UDPRecvSocket = LWIPRawUDPRecvImpl; #endif #ifdef USE_LWIP_FAST_SELECT @@ -98,13 +99,30 @@ std::unique_ptr socket_loop_monitored(int domain, int type, int protocol /// Create a send-only UDP socket of the given domain and protocol. #ifdef USE_SOCKET_IMPL_LWIP_TCP +std::unique_ptr socket_udp_send(int domain, int protocol); +#else +inline std::unique_ptr socket_udp_send(int domain, int protocol) { + return esphome::socket::socket(domain, SOCK_DGRAM, protocol); +} +#endif +/// Create a send-only UDP socket in the newest available IP domain. +inline std::unique_ptr socket_ip_udp_send(int protocol) { +#if USE_NETWORK_IPV6 + return socket_udp_send(AF_INET6, protocol); +#else + return socket_udp_send(AF_INET, protocol); +#endif +} + +/// Create a UDP socket (send + receive) of the given domain and protocol. +#ifdef USE_SOCKET_IMPL_LWIP_TCP std::unique_ptr socket_udp(int domain, int protocol); #else inline std::unique_ptr socket_udp(int domain, int protocol) { return esphome::socket::socket(domain, SOCK_DGRAM, protocol); } #endif -/// Create a send-only UDP socket in the newest available IP domain. +/// Create a UDP socket (send + receive) in the newest available IP domain. inline std::unique_ptr socket_ip_udp(int protocol) { #if USE_NETWORK_IPV6 return socket_udp(AF_INET6, protocol); @@ -113,38 +131,21 @@ inline std::unique_ptr socket_ip_udp(int protocol) { #endif } -/// Create a UDP socket with receive support of the given domain and protocol. -#ifdef USE_SOCKET_IMPL_LWIP_TCP -std::unique_ptr socket_udp_recv(int domain, int protocol); -#else -inline std::unique_ptr socket_udp_recv(int domain, int protocol) { - return esphome::socket::socket(domain, SOCK_DGRAM, protocol); -} -#endif -/// Create a UDP socket with receive support in the newest available IP domain. -inline std::unique_ptr socket_ip_udp_recv(int protocol) { -#if USE_NETWORK_IPV6 - return socket_udp_recv(AF_INET6, protocol); -#else - return socket_udp_recv(AF_INET, protocol); -#endif -} - -/// 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(). +/// Create a UDP 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(). /// 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_udp_loop_monitored(int domain, int protocol); #else -inline std::unique_ptr socket_udp_recv_loop_monitored(int domain, int protocol) { +inline std::unique_ptr socket_udp_loop_monitored(int domain, int protocol) { return socket_loop_monitored(domain, SOCK_DGRAM, protocol); } #endif -inline std::unique_ptr socket_ip_udp_recv_loop_monitored(int protocol) { +inline std::unique_ptr socket_ip_udp_loop_monitored(int protocol) { #if USE_NETWORK_IPV6 - return socket_udp_recv_loop_monitored(AF_INET6, protocol); + return socket_udp_loop_monitored(AF_INET6, protocol); #else - return socket_udp_recv_loop_monitored(AF_INET, protocol); + return socket_udp_loop_monitored(AF_INET, protocol); #endif }