mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 23:37:34 +00:00
[socket] Simplify UDP implementation and deduplicate lwip helpers
This commit is contained in:
@@ -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<const sockaddr_in *>(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<const sockaddr_in6 *>(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<const sockaddr_in *>(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;
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
|
||||
#ifdef USE_SOCKET_IMPL_LWIP_TCP
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
#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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<const struct ip_mreq *>(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<const struct ip_mreq *>(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<UDPSendSocket> socket_udp_send(int domain, int protocol) {
|
||||
(void) protocol; // Raw lwip UDP ignores protocol; kept for API compatibility
|
||||
auto sock = make_unique<LWIPRawUDPSendImpl>((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<LWIPRawUDPSendImpl>((sa_family_t) domain, pcb);
|
||||
}
|
||||
|
||||
std::unique_ptr<UDPSocket> socket_udp(int domain, int protocol) {
|
||||
(void) protocol; // Raw lwip UDP ignores protocol; kept for API compatibility
|
||||
auto sock = make_unique<LWIPRawUDPImpl>((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<UDPSocket> 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<LWIPRawUDPImpl>((sa_family_t) domain, pcb);
|
||||
}
|
||||
|
||||
#undef LWIP_LOCK
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
#ifdef USE_SOCKET_IMPL_LWIP_TCP
|
||||
|
||||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
#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<UDPRxPacket, UDP_RX_QUEUE_SIZE> rx_queue_{};
|
||||
uint16_t rx_dropped_{0};
|
||||
|
||||
@@ -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> 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> 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
|
||||
|
||||
@@ -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> socket_ip(int type, int protocol);
|
||||
/// File descriptors >= FD_SETSIZE will not be monitored and will log an error.
|
||||
std::unique_ptr<Socket> 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<UDPSendSocket> socket_udp_send(int domain, int protocol);
|
||||
std::unique_ptr<UDPSocket> socket_udp(int domain, int protocol);
|
||||
// Wake is built into the recv callback, so monitoring needs nothing extra.
|
||||
inline std::unique_ptr<UDPSocket> socket_udp_loop_monitored(int domain, int protocol) {
|
||||
return socket_udp(domain, protocol);
|
||||
}
|
||||
#else
|
||||
inline std::unique_ptr<UDPSendSocket> 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<UDPSendSocket> 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<UDPSocket> socket_udp(int domain, int protocol);
|
||||
#else
|
||||
inline std::unique_ptr<UDPSocket> 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<UDPSocket> 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<UDPSocket> socket_udp_loop_monitored(int domain, int protocol);
|
||||
#else
|
||||
// Registers the socket with the Application's select() loop.
|
||||
inline std::unique_ptr<UDPSocket> 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<UDPSendSocket> socket_ip_udp_send(int protocol) { return socket_udp_send(IP_DOMAIN, protocol); }
|
||||
inline std::unique_ptr<UDPSocket> socket_ip_udp(int protocol) { return socket_udp(IP_DOMAIN, protocol); }
|
||||
inline std::unique_ptr<UDPSocket> 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<ListenSocket> socket_listen_loop_monitored(int domain, in
|
||||
}
|
||||
#endif
|
||||
inline std::unique_ptr<ListenSocket> 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().
|
||||
|
||||
Reference in New Issue
Block a user