ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
socket.h
Go to the documentation of this file.
1#pragma once
2#include <memory>
3#include <span>
4#include <string>
5
7#include "headers.h"
8
9#ifdef USE_LWIP_FAST_SELECT
11#endif
12
13#if defined(USE_SOCKET_IMPL_LWIP_TCP) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS)
14
15// Include only the active implementation's header.
16// SOCKADDR_STR_LEN is defined in headers.h.
17#ifdef USE_SOCKET_IMPL_BSD_SOCKETS
18#include "bsd_sockets_impl.h"
19#elif defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
20#include "lwip_sockets_impl.h"
21#elif defined(USE_SOCKET_IMPL_LWIP_TCP)
22#include "lwip_raw_tcp_impl.h"
23#include "lwip_raw_udp_impl.h"
24#endif
25
26namespace esphome::socket {
27
28// Type aliases — only one implementation is active per build.
29// Socket is the concrete type for connected sockets.
30// ListenSocket is the concrete type for listening/server sockets.
31// UDPSocket is the concrete type for UDP sockets (send + receive).
32// UDPSendSocket is the concrete type for send-only UDP sockets.
33// On BSD and LWIP_SOCKETS, all aliases resolve to the same type.
34// On LWIP_TCP, they are different types (no virtual dispatch between them).
35#ifdef USE_SOCKET_IMPL_BSD_SOCKETS
40#elif defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
45#elif defined(USE_SOCKET_IMPL_LWIP_TCP)
46using Socket = LWIPRawImpl;
50#endif
51
52// Domain used by the socket_ip_* helpers: newest available IP domain.
53#if USE_NETWORK_IPV6
54inline constexpr int IP_DOMAIN = AF_INET6;
55#else
56inline constexpr int IP_DOMAIN = AF_INET;
57#endif
58
59// IPv6 sockets with multicast membership; the raw lwIP implementation has no IPv6 membership support.
60#if USE_NETWORK_IPV6 && (defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS))
61#define USE_SOCKET_IPV6
62#endif
63
64#ifdef USE_LWIP_FAST_SELECT
69inline bool socket_ready(struct lwip_sock *cached_sock) {
70 return cached_sock == nullptr || esphome_lwip_socket_has_data(cached_sock);
71}
72
77inline struct lwip_sock *hook_fd_for_fast_select(int fd) {
78 struct lwip_sock *sock = esphome_lwip_get_sock(fd);
79 if (sock != nullptr) {
81 }
82 return sock;
83}
84#elif defined(USE_HOST) || defined(USE_ZEPHYR)
87bool socket_ready_fd(int fd, bool loop_monitored);
88#endif // USE_LWIP_FAST_SELECT
89
90// Inline ready() — defined here because it depends on socket_ready/socket_ready_fd
91// declared above, while the impl headers are included before those declarations.
92//
93// Contract (applies to ALL socket implementations — each platform implements
94// ready() differently, but this contract holds regardless of the mechanism):
95// ready() checks if the socket has buffered data ready to read. When it returns
96// true, the caller MUST read until it would block (EAGAIN/EWOULDBLOCK), or until
97// read() returns 0 to indicate EOF / connection closed, or track that it stopped
98// early and retry without calling ready(). The next call to ready() will only
99// report new data correctly if all callers fulfill this contract. Failing to
100// drain the socket may cause ready() to return false while data remains readable.
101//
102// In practice each socket is owned by a single component, so this contract is
103// straightforward to fulfill — but the owning component must be aware of it,
104// especially if it limits how many messages it processes per loop iteration.
105#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
106inline bool Socket::ready() const {
107#ifdef USE_LWIP_FAST_SELECT
108 return socket_ready(this->cached_sock_);
109#else
110 return socket_ready_fd(this->fd_, this->loop_monitored_);
111#endif
112}
113#endif
114
116std::unique_ptr<Socket> socket(int domain, int type, int protocol);
119std::unique_ptr<Socket> socket_ip(int type, int protocol);
120
127std::unique_ptr<Socket> socket_loop_monitored(int domain, int type, int protocol);
128
132#ifdef USE_SOCKET_IMPL_LWIP_TCP
133std::unique_ptr<UDPSendSocket> socket_udp_send(int domain, int protocol);
134std::unique_ptr<UDPSocket> socket_udp(int domain, int protocol);
135// Wake is built into the recv callback, so monitoring needs nothing extra.
136inline std::unique_ptr<UDPSocket> socket_udp_loop_monitored(int domain, int protocol) {
137 return socket_udp(domain, protocol);
138}
139#else
140inline std::unique_ptr<UDPSendSocket> socket_udp_send(int domain, int protocol) {
141 return esphome::socket::socket(domain, SOCK_DGRAM, protocol);
142}
143inline std::unique_ptr<UDPSocket> socket_udp(int domain, int protocol) {
144 return esphome::socket::socket(domain, SOCK_DGRAM, protocol);
145}
146// Registers the socket with the Application's select() loop.
147inline std::unique_ptr<UDPSocket> socket_udp_loop_monitored(int domain, int protocol) {
148 return socket_loop_monitored(domain, SOCK_DGRAM, protocol);
149}
150#endif
151
153inline std::unique_ptr<UDPSendSocket> socket_ip_udp_send(int protocol) { return socket_udp_send(IP_DOMAIN, protocol); }
154inline std::unique_ptr<UDPSocket> socket_ip_udp(int protocol) { return socket_udp(IP_DOMAIN, protocol); }
155inline std::unique_ptr<UDPSocket> socket_ip_udp_loop_monitored(int protocol) {
156 return socket_udp_loop_monitored(IP_DOMAIN, protocol);
157}
158
162#ifdef USE_SOCKET_IMPL_LWIP_TCP
163// LWIP_TCP has separate Socket/ListenSocket types — needs distinct factory functions.
164std::unique_ptr<ListenSocket> socket_listen(int domain, int type, int protocol);
165std::unique_ptr<ListenSocket> socket_listen_loop_monitored(int domain, int type, int protocol);
166#else
167// BSD and LWIP_SOCKETS: Socket == ListenSocket, so listen variants just delegate.
168inline std::unique_ptr<ListenSocket> socket_listen(int domain, int type, int protocol) {
169 return socket(domain, type, protocol);
170}
171inline std::unique_ptr<ListenSocket> socket_listen_loop_monitored(int domain, int type, int protocol) {
172 return socket_loop_monitored(domain, type, protocol);
173}
174#endif
175inline std::unique_ptr<ListenSocket> socket_ip_loop_monitored(int type, int protocol) {
177}
178
185socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port);
186
189bool sockaddr_to_ipv4(const struct sockaddr *addr, uint32_t *out);
190
192inline socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::string &ip_address, uint16_t port) {
193 return set_sockaddr(addr, addrlen, ip_address.c_str(), port);
194}
195
197socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port);
198
206bool join_multicast_group(UDPSocket *sock, const char *ip_address, uint32_t *if_index_out = nullptr);
207
208#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
209#if USE_NETWORK_IPV6
216bool set_ipv6_multicast_if(Socket *sock, uint32_t if_index_in = 0);
217#endif // USE_NETWORK_IPV6
218#endif // USE_SOCKET_IMPL_BSD_SOCKETS || USE_SOCKET_IMPL_LWIP_SOCKETS
219
222#ifdef USE_SOCKET_IMPL_LWIP_TCP
223inline ConnectPollResult poll_connect(Socket &sock, int &err_out) { return sock.poll_connect(err_out); }
224#else
225ConnectPollResult poll_connect(Socket &sock, int &err_out);
226#endif
227
229size_t format_sockaddr_to(const struct sockaddr *addr_ptr, socklen_t len, std::span<char, SOCKADDR_STR_LEN> buf);
230
231} // namespace esphome::socket
232#endif
bool ready() const
Check if the socket has buffered data ready to read.
Definition socket.h:106
Connected socket implementation for LWIP raw TCP.
Listening socket implementation for LWIP raw TCP.
UDP socket with receive support for LWIP raw API.
Send-only UDP socket implementation for LWIP raw API.
uint8_t type
std::vector< uint8_t > & out
Definition gif.cpp:49
uint32_t socklen_t
Definition headers.h:109
void esphome_lwip_hook_socket(struct lwip_sock *sock)
Hook a socket's netconn callback to notify the main loop task on receive events.
struct lwip_sock * esphome_lwip_get_sock(int fd)
Look up a LwIP socket struct from a file descriptor.
bool socket_ready(struct lwip_sock *cached_sock)
Shared ready() helper using cached lwip_sock pointer for direct rcvevent read.
Definition socket.h:69
ConnectPollResult poll_connect(Socket &sock, int &err_out)
Poll a connect() that returned EINPROGRESS.
Definition socket.h:223
std::unique_ptr< UDPSendSocket > socket_udp_send(int domain, int protocol)
Create a send-only UDP socket (socket_udp_send), a UDP socket with receive support (socket_udp),...
socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port)
Set a sockaddr to the specified address and port for the IP version used by socket_ip().
std::unique_ptr< Socket > socket_ip(int type, int protocol)
Create a socket in the newest available IP domain (IPv6 or IPv4) of the given type and protocol.
bool set_ipv6_multicast_if(Socket *sock, uint32_t if_index_in=0)
Configure the outgoing IPv6 multicast interface on the given socket.
size_t format_sockaddr_to(const struct sockaddr *addr_ptr, socklen_t len, std::span< char, SOCKADDR_STR_LEN > buf)
Format sockaddr into caller-provided buffer, returns length written (excluding null)
std::unique_ptr< ListenSocket > socket_listen(int domain, int type, int protocol)
Create a listening socket of the given domain, type and protocol.
ConnectPollResult
Outcome of polling a non-blocking connect(); see socket::poll_connect().
Definition headers.h:224
std::unique_ptr< UDPSocket > socket_ip_udp(int protocol)
Definition socket.h:154
std::unique_ptr< ListenSocket > socket_listen_loop_monitored(int domain, int type, int protocol)
std::unique_ptr< Socket > socket(int domain, int type, int protocol)
Create a socket of the given domain, type and protocol.
bool join_multicast_group(UDPSocket *sock, const char *ip_address, uint32_t *if_index_out=nullptr)
Join a multicast group on the given socket.
std::unique_ptr< UDPSocket > socket_udp(int domain, int protocol)
std::unique_ptr< UDPSocket > socket_ip_udp_loop_monitored(int protocol)
Definition socket.h:155
struct lwip_sock * hook_fd_for_fast_select(int fd)
Resolve an fd to its lwip_sock and install the netconn event-callback hook so the main loop is woken ...
Definition socket.h:77
BSDSocketImpl Socket
Definition socket.h:36
constexpr int IP_DOMAIN
Definition socket.h:54
std::unique_ptr< UDPSendSocket > socket_ip_udp_send(int protocol)
socket_udp* variants using the newest available IP domain.
Definition socket.h:153
bool sockaddr_to_ipv4(const struct sockaddr *addr, uint32_t *out)
Network order IPv4 of an AF_INET or v4 mapped AF_INET6 peer; false for anything else.
bool socket_ready_fd(int fd, bool loop_monitored)
Shared ready() helper for fd-based socket implementations.
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port)
Set a sockaddr to the any address and specified port for the IP version used by socket_ip().
std::unique_ptr< Socket > socket_loop_monitored(int domain, int type, int protocol)
Create a socket and monitor it for data in the main loop.
std::unique_ptr< ListenSocket > socket_ip_loop_monitored(int type, int protocol)
Definition socket.h:175
std::unique_ptr< UDPSocket > socket_udp_loop_monitored(int domain, int protocol)
Definition socket.h:136
const void size_t len
Definition hal.h:68
static void uint32_t