From 7cbc81ad664dcc72306f6e4a1b18000cc290085a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 28 Aug 2026 10:26:05 -0500 Subject: [PATCH] [socket] Simplify UDP implementation and deduplicate lwip helpers --- .../socket/lwip_raw_common_impl.cpp | 33 ++-- .../components/socket/lwip_raw_common_impl.h | 13 +- .../components/socket/lwip_raw_tcp_impl.cpp | 8 +- .../components/socket/lwip_raw_udp_impl.cpp | 155 ++++++------------ esphome/components/socket/lwip_raw_udp_impl.h | 29 ++-- esphome/components/socket/socket.cpp | 8 +- esphome/components/socket/socket.h | 63 +++---- 7 files changed, 109 insertions(+), 200 deletions(-) diff --git a/esphome/components/socket/lwip_raw_common_impl.cpp b/esphome/components/socket/lwip_raw_common_impl.cpp index e6fbf6bf2c..d9ffbfb54a 100644 --- a/esphome/components/socket/lwip_raw_common_impl.cpp +++ b/esphome/components/socket/lwip_raw_common_impl.cpp @@ -48,40 +48,41 @@ int lwip_ip_to_sockaddr(sa_family_t family, const ip_addr_t *ip, uint16_t port_h } bool sockaddr_to_lwip(const struct sockaddr *addr, socklen_t addrlen, ip_addr_t *ip, uint16_t *port) { + // headers.h defines sockaddr and sockaddr_in with the same size, so this covers AF_INET if (addrlen < sizeof(struct sockaddr)) return false; -#if LWIP_IPV6 if (addr->sa_family == AF_INET) { - if (addrlen < sizeof(sockaddr_in)) - return false; auto *addr4 = reinterpret_cast(addr); *port = ntohs(addr4->sin_port); - ip->type = IPADDR_TYPE_V4; - ip->u_addr.ip4.addr = addr4->sin_addr.s_addr; + IP_SET_TYPE_VAL(*ip, IPADDR_TYPE_V4); + ip_2_ip4(ip)->addr = addr4->sin_addr.s_addr; return true; } +#if LWIP_IPV6 if (addr->sa_family == AF_INET6) { if (addrlen < sizeof(sockaddr_in6)) return false; auto *addr6 = reinterpret_cast(addr); *port = ntohs(addr6->sin6_port); - ip->type = IPADDR_TYPE_V6; - memcpy(&ip->u_addr.ip6.addr, &addr6->sin6_addr.un.u8_addr, 16); - return true; - } -#else - if (addr->sa_family == AF_INET) { - if (addrlen < sizeof(sockaddr_in)) - return false; - auto *addr4 = reinterpret_cast(addr); - *port = ntohs(addr4->sin_port); - ip->addr = addr4->sin_addr.s_addr; + IP_SET_TYPE_VAL(*ip, IPADDR_TYPE_V6); + memcpy(&ip_2_ip6(ip)->addr, &addr6->sin6_addr.un.u8_addr, 16); return true; } #endif return false; } +bool sockaddr_to_lwip_bind(sa_family_t family, const struct sockaddr *addr, socklen_t addrlen, ip_addr_t *ip, + uint16_t *port) { + if (!sockaddr_to_lwip(addr, addrlen, ip, port)) + return false; +#if LWIP_IPV6 + if (family == AF_INET6) + IP_SET_TYPE_VAL(*ip, IPADDR_TYPE_ANY); +#endif + return true; +} + int lwip_bind_err(err_t err) { if (err == ERR_OK) return 0; diff --git a/esphome/components/socket/lwip_raw_common_impl.h b/esphome/components/socket/lwip_raw_common_impl.h index 8644d5a27c..dca882cdf0 100644 --- a/esphome/components/socket/lwip_raw_common_impl.h +++ b/esphome/components/socket/lwip_raw_common_impl.h @@ -3,9 +3,6 @@ #ifdef USE_SOCKET_IMPL_LWIP_TCP -#include -#include - #include "headers.h" #include "lwip/ip.h" @@ -42,11 +39,15 @@ int lwip_ip_to_sockaddr(sa_family_t family, const ip_addr_t *ip, uint16_t port_h socklen_t *addrlen); /// Convert sockaddr to lwip ip_addr_t and host-order port. -/// For IPv6, sets type to IPADDR_TYPE_V6 (callers that need dual-stack should -/// override to IPADDR_TYPE_ANY after calling). -/// Shared by both TCP (LWIPRawCommon) and UDP (LWIPRawUDPImpl) bind/sendto paths. +/// For IPv6, sets type to IPADDR_TYPE_V6 — correct for sendto destinations. +/// Bind paths must use sockaddr_to_lwip_bind() instead. bool sockaddr_to_lwip(const struct sockaddr *addr, socklen_t addrlen, ip_addr_t *ip, uint16_t *port); +/// sockaddr_to_lwip variant for bind: promotes AF_INET6 sockets to +/// IPADDR_TYPE_ANY so they accept both IPv4 and IPv6 (dual-stack). +bool sockaddr_to_lwip_bind(sa_family_t family, const struct sockaddr *addr, socklen_t addrlen, ip_addr_t *ip, + uint16_t *port); + /// Map lwip bind error to errno. Returns 0 on success, -1 on error with errno set. int lwip_bind_err(err_t err); diff --git a/esphome/components/socket/lwip_raw_tcp_impl.cpp b/esphome/components/socket/lwip_raw_tcp_impl.cpp index 2b76cf3c95..69886e60df 100644 --- a/esphome/components/socket/lwip_raw_tcp_impl.cpp +++ b/esphome/components/socket/lwip_raw_tcp_impl.cpp @@ -100,16 +100,10 @@ int LWIPRawCommon::bind(const struct sockaddr *name, socklen_t addrlen) { } ip_addr_t ip; uint16_t port; - if (!sockaddr_to_lwip(name, addrlen, &ip, &port)) { + if (!sockaddr_to_lwip_bind(this->family_, name, addrlen, &ip, &port)) { errno = EINVAL; return -1; } -#if LWIP_IPV6 - // Use IPADDR_TYPE_ANY for dual-stack (accept both IPv4 and IPv6) - if (this->family_ == AF_INET6) { - ip.type = IPADDR_TYPE_ANY; - } -#endif err_t err = tcp_bind(this->pcb_, &ip, port); LWIP_LOG(" -> err %d", err); return lwip_bind_err(err); diff --git a/esphome/components/socket/lwip_raw_udp_impl.cpp b/esphome/components/socket/lwip_raw_udp_impl.cpp index e5dc8f50e7..e232ae5215 100644 --- a/esphome/components/socket/lwip_raw_udp_impl.cpp +++ b/esphome/components/socket/lwip_raw_udp_impl.cpp @@ -24,27 +24,14 @@ namespace esphome::socket { // ---- LWIPRawUDPSendImpl (send-only) methods ---- -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); -#else - this->pcb_ = udp_new(); -#endif -} - LWIPRawUDPSendImpl::~LWIPRawUDPSendImpl() { - // Early return avoids acquiring the lwip lock when pcb_ is already null - // (e.g., after LWIPRawUDPImpl::close() already cleaned up). - if (this->pcb_ == nullptr) - return; - LWIP_LOCK(); - udp_remove(this->pcb_); - this->pcb_ = nullptr; + // Guard avoids acquiring the lwip lock when already closed + if (this->pcb_ != nullptr) + this->close(); } -int LWIPRawUDPSendImpl::bind_internal_locked_(const struct sockaddr *name, socklen_t addrlen) { - // Caller must hold LWIP_LOCK +int LWIPRawUDPSendImpl::bind(const struct sockaddr *name, socklen_t addrlen) { + LWIP_LOCK(); if (this->pcb_ == nullptr) { errno = EBADF; return -1; @@ -55,26 +42,13 @@ int LWIPRawUDPSendImpl::bind_internal_locked_(const struct sockaddr *name, sockl } ip_addr_t ip; uint16_t port; - if (!sockaddr_to_lwip(name, addrlen, &ip, &port)) { + if (!sockaddr_to_lwip_bind(this->family_, name, addrlen, &ip, &port)) { errno = EINVAL; return -1; } -#if LWIP_IPV6 - // For bind, use IPADDR_TYPE_ANY on IPv6 sockets to accept both IPv4 and IPv6 - // packets (dual-stack). sockaddr_to_lwip uses IPADDR_TYPE_V6 which is correct - // for sendto destinations but too restrictive for bind. - if (this->family_ == AF_INET6) { - ip.type = IPADDR_TYPE_ANY; - } -#endif return lwip_bind_err(udp_bind(this->pcb_, &ip, port)); } -int LWIPRawUDPSendImpl::bind(const struct sockaddr *name, socklen_t addrlen) { - LWIP_LOCK(); - return this->bind_internal_locked_(name, addrlen); -} - int LWIPRawUDPSendImpl::close() { LWIP_LOCK(); return this->close_internal_locked_(); @@ -99,11 +73,6 @@ int LWIPRawUDPSendImpl::ip2sockaddr_(const ip_addr_t *ip, uint16_t port, struct 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) { - errno = EBADF; - return -1; - } if (buf == nullptr || dest_addr == nullptr) { errno = EINVAL; return -1; @@ -122,6 +91,12 @@ ssize_t LWIPRawUDPSendImpl::sendto(const void *buf, size_t len, int flags, const return -1; } + LWIP_LOCK(); + if (this->pcb_ == nullptr) { + errno = EBADF; + return -1; + } + // Allocate pbuf and copy data struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, (uint16_t) len, PBUF_RAM); if (pb == nullptr) { @@ -164,34 +139,16 @@ int LWIPRawUDPSendImpl::setsockopt(int level, int optname, const void *optval, s } return 0; } - if (level == IPPROTO_IP && optname == IP_ADD_MEMBERSHIP) { + if (level == IPPROTO_IP && (optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP)) { if (optval == nullptr || optlen < sizeof(struct ip_mreq)) { errno = EINVAL; return -1; } auto *mreq = reinterpret_cast(optval); - ip4_addr_t multiaddr; - multiaddr.addr = mreq->imr_multiaddr.s_addr; - ip4_addr_t ifaddr; - ifaddr.addr = mreq->imr_interface.s_addr; - err_t err = igmp_joingroup(&ifaddr, &multiaddr); - if (err != ERR_OK) { - errno = EIO; - return -1; - } - return 0; - } - if (level == IPPROTO_IP && optname == IP_DROP_MEMBERSHIP) { - if (optval == nullptr || optlen < sizeof(struct ip_mreq)) { - errno = EINVAL; - return -1; - } - auto *mreq = reinterpret_cast(optval); - ip4_addr_t multiaddr; - multiaddr.addr = mreq->imr_multiaddr.s_addr; - ip4_addr_t ifaddr; - ifaddr.addr = mreq->imr_interface.s_addr; - err_t err = igmp_leavegroup(&ifaddr, &multiaddr); + ip4_addr_t multiaddr{mreq->imr_multiaddr.s_addr}; + ip4_addr_t ifaddr{mreq->imr_interface.s_addr}; + err_t err = + optname == IP_ADD_MEMBERSHIP ? igmp_joingroup(&ifaddr, &multiaddr) : igmp_leavegroup(&ifaddr, &multiaddr); if (err != ERR_OK) { errno = EIO; return -1; @@ -232,12 +189,9 @@ int LWIPRawUDPSendImpl::setblocking(bool blocking) { // ---- LWIPRawUDPImpl methods ---- -LWIPRawUDPImpl::LWIPRawUDPImpl(sa_family_t family) : LWIPRawUDPSendImpl(family) { - // Register recv here (not in bind) so unbound client sockets can receive replies - if (this->pcb_ != nullptr) { - LWIP_LOCK(); - udp_recv(this->pcb_, LWIPRawUDPImpl::s_recv_fn, this); - } +LWIPRawUDPImpl::LWIPRawUDPImpl(sa_family_t family, struct udp_pcb *pcb) : LWIPRawUDPSendImpl(family, pcb) { + // Registered here (not in bind) so unbound client sockets can receive replies + udp_recv(this->pcb_, LWIPRawUDPImpl::s_recv_fn, this); } LWIPRawUDPImpl::~LWIPRawUDPImpl() { @@ -252,15 +206,10 @@ int LWIPRawUDPImpl::close() { if (this->pcb_ != nullptr) { udp_recv(this->pcb_, nullptr, nullptr); } - // Flush any queued rx packets - while (this->rx_count_ > 0) { - auto &pkt = this->rx_queue_[this->rx_read_idx_]; - if (pkt.pb != nullptr) { - pbuf_free(pkt.pb); - pkt.pb = nullptr; - } + // Flush queued rx packets; slots within rx_count_ always hold a live pbuf + for (; this->rx_count_ > 0; this->rx_count_--) { + pbuf_free(this->rx_queue_[this->rx_read_idx_].pb); this->rx_read_idx_ = (this->rx_read_idx_ + 1) & UDP_RX_MASK; - this->rx_count_--; } // close_internal_locked_() returns EBADF if already closed, which is fine from destructor return this->close_internal_locked_(); @@ -284,32 +233,18 @@ ssize_t LWIPRawUDPImpl::recvfrom(void *buf, size_t len, struct sockaddr *src_add } auto &pkt = this->rx_queue_[this->rx_read_idx_]; - size_t pkt_len = pkt.pb->tot_len; - size_t copy_len = std::min(len, pkt_len); - - // Fill in source address if requested. - // If ip2sockaddr_ fails (e.g., addrlen too small), fail the recvfrom but - // still consume the packet — the failure is deterministic (depends only on - // family_ and *addrlen), so keeping the packet would wedge the queue forever. - bool addr_ok = true; - if (src_addr != nullptr && addrlen != nullptr && - this->ip2sockaddr_(&pkt.src_addr, pkt.src_port, src_addr, addrlen) != 0) { - addr_ok = false; + // On address conversion failure, still consume the packet — the failure is + // deterministic (family_ and *addrlen), so keeping it would wedge the queue + ssize_t ret = -1; + if (src_addr == nullptr || addrlen == nullptr || + this->ip2sockaddr_(&pkt.src_addr, pkt.src_port, src_addr, addrlen) == 0) { + ret = (ssize_t) std::min(len, (size_t) pkt.pb->tot_len); + pbuf_copy_partial(pkt.pb, buf, ret, 0); } - - // Copy data from pbuf chain — done after validation so caller buffer is - // not modified on error paths. - if (addr_ok) { - pbuf_copy_partial(pkt.pb, buf, copy_len, 0); - } - - // Free the pbuf and advance the read pointer pbuf_free(pkt.pb); - pkt.pb = nullptr; this->rx_read_idx_ = (this->rx_read_idx_ + 1) & UDP_RX_MASK; this->rx_count_--; - - return addr_ok ? (ssize_t) copy_len : -1; + return ret; } void LWIPRawUDPImpl::s_recv_fn(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { @@ -347,29 +282,35 @@ void LWIPRawUDPImpl::recv_fn_(struct pbuf *p, const ip_addr_t *addr, u16_t port) // ---- UDP Factory functions ---- +static struct udp_pcb *new_udp_pcb(int domain) { +#if LWIP_IPV6 + return udp_new_ip_type(domain == AF_INET6 ? IPADDR_TYPE_ANY : IPADDR_TYPE_V4); +#else + return udp_new(); +#endif +} + 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()) { + LWIP_LOCK(); + auto *pcb = new_udp_pcb(domain); + if (pcb == nullptr) { errno = ENOMEM; return nullptr; } - return sock; + return make_unique((sa_family_t) domain, pcb); } 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); - if (!sock->is_valid()) { + LWIP_LOCK(); + auto *pcb = new_udp_pcb(domain); + if (pcb == nullptr) { errno = ENOMEM; return nullptr; } - return sock; -} - -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); + // Ctor registers the recv callback under the lock held here + return make_unique((sa_family_t) domain, pcb); } #undef LWIP_LOCK diff --git a/esphome/components/socket/lwip_raw_udp_impl.h b/esphome/components/socket/lwip_raw_udp_impl.h index 2d28670e03..1eda7786e6 100644 --- a/esphome/components/socket/lwip_raw_udp_impl.h +++ b/esphome/components/socket/lwip_raw_udp_impl.h @@ -4,9 +4,7 @@ #ifdef USE_SOCKET_IMPL_LWIP_TCP #include -#include -#include -#include +#include #include "headers.h" #include "lwip/ip.h" @@ -19,7 +17,8 @@ namespace esphome::socket { /// No receive capability — use LWIPRawUDPImpl for sockets that need to receive. class LWIPRawUDPSendImpl { public: - LWIPRawUDPSendImpl(sa_family_t family); + /// The pcb is allocated by the factory (like the TCP impl); never null here. + LWIPRawUDPSendImpl(sa_family_t family, struct udp_pcb *pcb) : pcb_(pcb), family_(family) {} ~LWIPRawUDPSendImpl(); LWIPRawUDPSendImpl(const LWIPRawUDPSendImpl &) = delete; LWIPRawUDPSendImpl &operator=(const LWIPRawUDPSendImpl &) = delete; @@ -35,7 +34,6 @@ class LWIPRawUDPSendImpl { int setblocking(bool blocking); - bool is_valid() const { return this->pcb_ != nullptr; } bool ready() const { return false; } int get_fd() const { return -1; } @@ -43,14 +41,11 @@ class LWIPRawUDPSendImpl { /// Convert lwip ip_addr_t and port to sockaddr. int ip2sockaddr_(const ip_addr_t *ip, uint16_t port, struct sockaddr *name, socklen_t *addrlen); - /// Shared bind logic — parses sockaddr and calls udp_bind. Caller must hold LWIP_LOCK. - int bind_internal_locked_(const struct sockaddr *name, socklen_t addrlen); - - /// Shared close logic — unregisters and removes udp pcb. Caller must hold LWIP_LOCK. + /// Shared close logic — removes the udp pcb. Caller must hold LWIP_LOCK. int close_internal_locked_(); - struct udp_pcb *pcb_{nullptr}; - sa_family_t family_{0}; + struct udp_pcb *pcb_; + sa_family_t family_; }; /// UDP socket with receive support for LWIP raw API. @@ -59,13 +54,13 @@ class LWIPRawUDPSendImpl { /// pointer would leak queued pbufs on destruction). class LWIPRawUDPImpl : private LWIPRawUDPSendImpl { public: - LWIPRawUDPImpl(sa_family_t family); + /// Caller (the factory) must hold the lwip lock; registers the recv callback. + LWIPRawUDPImpl(sa_family_t family, struct udp_pcb *pcb); ~LWIPRawUDPImpl(); using LWIPRawUDPSendImpl::bind; using LWIPRawUDPSendImpl::get_fd; using LWIPRawUDPSendImpl::getsockopt; - using LWIPRawUDPSendImpl::is_valid; using LWIPRawUDPSendImpl::sendto; using LWIPRawUDPSendImpl::setblocking; using LWIPRawUDPSendImpl::setsockopt; @@ -101,10 +96,12 @@ class LWIPRawUDPImpl : private LWIPRawUDPSendImpl { static constexpr uint8_t UDP_RX_QUEUE_SIZE = 4; static constexpr uint8_t UDP_RX_MASK = UDP_RX_QUEUE_SIZE - 1; static_assert((UDP_RX_QUEUE_SIZE & UDP_RX_MASK) == 0, "UDP_RX_QUEUE_SIZE must be power of 2"); + // Fields are written by recv_fn_ before rx_count_ makes a slot visible, + // so per-member initializers would only add dead zeroing of the array. struct UDPRxPacket { - ip_addr_t src_addr{}; - struct pbuf *pb{nullptr}; - uint16_t src_port{0}; + ip_addr_t src_addr; + struct pbuf *pb; + uint16_t src_port; }; std::array rx_queue_{}; uint16_t rx_dropped_{0}; diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index 216cfcdcf1..965e8b9d0a 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -116,13 +116,7 @@ size_t format_sockaddr_to(const struct sockaddr *addr_ptr, socklen_t len, std::s return 0; } -std::unique_ptr socket_ip(int type, int protocol) { -#if USE_NETWORK_IPV6 - return socket(AF_INET6, type, protocol); -#else - return socket(AF_INET, type, protocol); -#endif /* USE_NETWORK_IPV6 */ -} +std::unique_ptr socket_ip(int type, int protocol) { return socket(IP_DOMAIN, type, protocol); } socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port) { #if USE_NETWORK_IPV6 diff --git a/esphome/components/socket/socket.h b/esphome/components/socket/socket.h index 8a136b81be..2403e7b187 100644 --- a/esphome/components/socket/socket.h +++ b/esphome/components/socket/socket.h @@ -49,6 +49,13 @@ using UDPSendSocket = LWIPRawUDPSendImpl; using UDPSocket = LWIPRawUDPImpl; #endif +// Domain used by the socket_ip_* helpers: newest available IP domain. +#if USE_NETWORK_IPV6 +inline constexpr int IP_DOMAIN = AF_INET6; +#else +inline constexpr int IP_DOMAIN = AF_INET; +#endif + #ifdef USE_LWIP_FAST_SELECT /// Shared ready() helper using cached lwip_sock pointer for direct rcvevent read. /// cached_sock == nullptr means the socket is not monitored (monitor_loop was false, fd @@ -113,56 +120,34 @@ std::unique_ptr socket_ip(int type, int protocol); /// File descriptors >= FD_SETSIZE will not be monitored and will log an error. std::unique_ptr socket_loop_monitored(int domain, int type, int protocol); -/// Create a send-only UDP socket of the given domain and protocol. +/// Create a send-only UDP socket (socket_udp_send), a UDP socket with receive +/// support (socket_udp), or a UDP socket monitored for data in the main loop +/// (socket_udp_loop_monitored). #ifdef USE_SOCKET_IMPL_LWIP_TCP std::unique_ptr socket_udp_send(int domain, int protocol); +std::unique_ptr socket_udp(int domain, int protocol); +// Wake is built into the recv callback, so monitoring needs nothing extra. +inline std::unique_ptr socket_udp_loop_monitored(int domain, int protocol) { + return socket_udp(domain, 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 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); -#else - return socket_udp(AF_INET, protocol); -#endif -} - -/// 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_loop_monitored(int domain, int protocol); -#else +// Registers the socket with the Application's select() loop. inline std::unique_ptr socket_udp_loop_monitored(int domain, int protocol) { return socket_loop_monitored(domain, SOCK_DGRAM, protocol); } #endif + +/// socket_udp* variants using the newest available IP domain. +inline std::unique_ptr socket_ip_udp_send(int protocol) { return socket_udp_send(IP_DOMAIN, protocol); } +inline std::unique_ptr socket_ip_udp(int protocol) { return socket_udp(IP_DOMAIN, protocol); } inline std::unique_ptr socket_ip_udp_loop_monitored(int protocol) { -#if USE_NETWORK_IPV6 - return socket_udp_loop_monitored(AF_INET6, protocol); -#else - return socket_udp_loop_monitored(AF_INET, protocol); -#endif + return socket_udp_loop_monitored(IP_DOMAIN, protocol); } /// Create a listening socket of the given domain, type and protocol. @@ -182,11 +167,7 @@ inline std::unique_ptr socket_listen_loop_monitored(int domain, in } #endif inline std::unique_ptr socket_ip_loop_monitored(int type, int protocol) { -#if USE_NETWORK_IPV6 - return socket_listen_loop_monitored(AF_INET6, type, protocol); -#else - return socket_listen_loop_monitored(AF_INET, type, protocol); -#endif + return socket_listen_loop_monitored(IP_DOMAIN, type, protocol); } /// Set a sockaddr to the specified address and port for the IP version used by socket_ip().