ESPHome 2026.5.1
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#endif
24
25namespace esphome::socket {
26
27// Type aliases — only one implementation is active per build.
28// Socket is the concrete type for connected sockets.
29// ListenSocket is the concrete type for listening/server sockets.
30// On BSD and LWIP_SOCKETS, both aliases resolve to the same type.
31// On LWIP_TCP, they are different types (no virtual dispatch between them).
32#ifdef USE_SOCKET_IMPL_BSD_SOCKETS
35#elif defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
38#elif defined(USE_SOCKET_IMPL_LWIP_TCP)
39using Socket = LWIPRawImpl;
41#endif
42
43#ifdef USE_LWIP_FAST_SELECT
48inline bool socket_ready(struct lwip_sock *cached_sock) {
49 return cached_sock == nullptr || esphome_lwip_socket_has_data(cached_sock);
50}
51
56inline struct lwip_sock *hook_fd_for_fast_select(int fd) {
57 struct lwip_sock *sock = esphome_lwip_get_sock(fd);
58 if (sock != nullptr) {
60 }
61 return sock;
62}
63#elif defined(USE_HOST)
66bool socket_ready_fd(int fd, bool loop_monitored);
67#endif
68
69// Inline ready() — defined here because it depends on socket_ready/socket_ready_fd
70// declared above, while the impl headers are included before those declarations.
71//
72// Contract (applies to ALL socket implementations — each platform implements
73// ready() differently, but this contract holds regardless of the mechanism):
74// ready() checks if the socket has buffered data ready to read. When it returns
75// true, the caller MUST read until it would block (EAGAIN/EWOULDBLOCK), or until
76// read() returns 0 to indicate EOF / connection closed, or track that it stopped
77// early and retry without calling ready(). The next call to ready() will only
78// report new data correctly if all callers fulfill this contract. Failing to
79// drain the socket may cause ready() to return false while data remains readable.
80//
81// In practice each socket is owned by a single component, so this contract is
82// straightforward to fulfill — but the owning component must be aware of it,
83// especially if it limits how many messages it processes per loop iteration.
84#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
85inline bool Socket::ready() const {
86#ifdef USE_LWIP_FAST_SELECT
87 return socket_ready(this->cached_sock_);
88#else
89 return socket_ready_fd(this->fd_, this->loop_monitored_);
90#endif
91}
92#endif
93
95std::unique_ptr<Socket> socket(int domain, int type, int protocol);
97std::unique_ptr<Socket> socket_ip(int type, int protocol);
98
105std::unique_ptr<Socket> socket_loop_monitored(int domain, int type, int protocol);
106
110#ifdef USE_SOCKET_IMPL_LWIP_TCP
111// LWIP_TCP has separate Socket/ListenSocket types — needs distinct factory functions.
112std::unique_ptr<ListenSocket> socket_listen(int domain, int type, int protocol);
113std::unique_ptr<ListenSocket> socket_listen_loop_monitored(int domain, int type, int protocol);
114std::unique_ptr<ListenSocket> socket_ip_loop_monitored(int type, int protocol);
115#else
116// BSD and LWIP_SOCKETS: Socket == ListenSocket, so listen variants just delegate.
117inline std::unique_ptr<ListenSocket> socket_listen(int domain, int type, int protocol) {
118 return socket(domain, type, protocol);
119}
120inline std::unique_ptr<ListenSocket> socket_listen_loop_monitored(int domain, int type, int protocol) {
121 return socket_loop_monitored(domain, type, protocol);
122}
123inline std::unique_ptr<ListenSocket> socket_ip_loop_monitored(int type, int protocol) {
124#if USE_NETWORK_IPV6
125 return socket_loop_monitored(AF_INET6, type, protocol);
126#else
127 return socket_loop_monitored(AF_INET, type, protocol);
128#endif
129}
130#endif
131
138socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port);
139
141inline socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::string &ip_address, uint16_t port) {
142 return set_sockaddr(addr, addrlen, ip_address.c_str(), port);
143}
144
146socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port);
147
149size_t format_sockaddr_to(const struct sockaddr *addr_ptr, socklen_t len, std::span<char, SOCKADDR_STR_LEN> buf);
150
151} // namespace esphome::socket
152#endif
bool ready() const
Check if the socket has buffered data ready to read.
Definition socket.h:85
Connected socket implementation for LWIP raw TCP.
Listening socket implementation for LWIP raw TCP.
uint16_t type
uint32_t socklen_t
Definition headers.h:99
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:48
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().
Definition socket.cpp:107
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.
Definition socket.cpp:87
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)
Definition socket.cpp:56
std::unique_ptr< ListenSocket > socket_listen(int domain, int type, int protocol)
Create a listening socket of the given domain, type and protocol.
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.
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:56
bool socket_ready_fd(int fd, bool loop_monitored)
Shared ready() helper for fd-based socket implementations.
Definition socket.cpp:17
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().
Definition socket.cpp:146
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.cpp:98
std::string size_t len