ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
bsd_sockets_impl.cpp
Go to the documentation of this file.
3#include "socket.h"
4
5#ifdef USE_SOCKET_IMPL_BSD_SOCKETS
6
7#include <cstring>
9#ifdef USE_HOST
10#include "esphome/core/wake.h"
11#endif
12
13namespace esphome::socket {
14
15BSDSocketImpl::BSDSocketImpl(int fd, bool monitor_loop) {
16 this->fd_ = fd;
17 if (this->fd_ < 0)
18 return;
19#ifdef USE_HOST
20 // Release listening ports on OTA re-exec.
21 int flags = ::fcntl(this->fd_, F_GETFD, 0);
22 if (flags >= 0)
23 ::fcntl(this->fd_, F_SETFD, flags | FD_CLOEXEC);
24#endif
25 // Guard structure matches socket_ready_fd(): non-HOST platforms (nRF52/OpenThread)
26 // do not register fds with the esphome select loop, so monitor_loop is a no-op there.
27 if (!monitor_loop)
28 return;
29#ifdef USE_LWIP_FAST_SELECT
31#elif defined(USE_HOST)
33#endif
34}
35
37
39 if (this->fd_ < 0) {
40 // Already closed, or never opened.
41 return 0;
42 }
43#ifdef USE_LWIP_FAST_SELECT
44 // Null the cached lwip_sock pointer before closing. The underlying lwip slot can be
45 // recycled for a new connection as soon as ::close() returns, so anything that might
46 // dereference cached_sock_ post-close (e.g. setsockopt(TCP_NODELAY)) would otherwise
47 // touch an unrelated socket's pcb. No per-socket callback unhook is needed —
48 // all LwIP sockets share the same static event_callback.
49 this->cached_sock_ = nullptr;
50#elif defined(USE_HOST)
51 if (this->loop_monitored_) {
53 }
54#endif
55 int ret = ::close(this->fd_);
56 this->fd_ = -1; // Sentinel for "closed" — prevents double-close and makes use-after-close visible.
57 return ret;
58}
59
60int BSDSocketImpl::setblocking(bool blocking) {
61 int fl = ::fcntl(this->fd_, F_GETFL, 0);
62 if (fl < 0) {
63 return fl;
64 }
65 if (blocking) {
66 fl &= ~O_NONBLOCK;
67 } else {
68 fl |= O_NONBLOCK;
69 }
70 return ::fcntl(this->fd_, F_SETFL, fl);
71}
72
73size_t BSDSocketImpl::getpeername_to(std::span<char, SOCKADDR_STR_LEN> buf) {
74 struct sockaddr_storage storage;
75 socklen_t len = sizeof(storage);
76 if (this->getpeername(reinterpret_cast<struct sockaddr *>(&storage), &len) != 0) {
77 buf[0] = '\0';
78 return 0;
79 }
80 return format_sockaddr_to(reinterpret_cast<struct sockaddr *>(&storage), len, buf);
81}
82
83size_t BSDSocketImpl::getsockname_to(std::span<char, SOCKADDR_STR_LEN> buf) {
84 struct sockaddr_storage storage;
85 socklen_t len = sizeof(storage);
86 if (this->getsockname(reinterpret_cast<struct sockaddr *>(&storage), &len) != 0) {
87 buf[0] = '\0';
88 return 0;
89 }
90 return format_sockaddr_to(reinterpret_cast<struct sockaddr *>(&storage), len, buf);
91}
92
93// Helper to create a socket with optional monitoring
94static std::unique_ptr<BSDSocketImpl> create_socket(int domain, int type, int protocol, bool loop_monitored = false) {
95 int ret = ::socket(domain, type, protocol);
96 if (ret == -1)
97 return nullptr;
98 return make_unique<BSDSocketImpl>(ret, loop_monitored);
99}
100
101std::unique_ptr<Socket> socket(int domain, int type, int protocol) {
102 return create_socket(domain, type, protocol, false);
103}
104
105std::unique_ptr<Socket> socket_loop_monitored(int domain, int type, int protocol) {
106 return create_socket(domain, type, protocol, true);
107}
108
109} // namespace esphome::socket
110
111#endif // USE_SOCKET_IMPL_BSD_SOCKETS
int getpeername(struct sockaddr *addr, socklen_t *addrlen)
size_t getpeername_to(std::span< char, SOCKADDR_STR_LEN > buf)
Format peer address into a fixed-size buffer (no heap allocation)
size_t getsockname_to(std::span< char, SOCKADDR_STR_LEN > buf)
Format local address into a fixed-size buffer (no heap allocation)
int getsockname(struct sockaddr *addr, socklen_t *addrlen)
BSDSocketImpl(int fd, bool monitor_loop=false)
uint16_t flags
uint8_t type
uint32_t socklen_t
Definition headers.h:109
int ret
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< 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:77
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.
const void size_t len
Definition hal.h:68
bool wake_register_fd(int fd)
Register a socket file descriptor with the host select() loop.
Definition wake_host.cpp:46
void wake_unregister_fd(int fd)
Unregister a socket file descriptor. Not thread-safe — main loop only.
Definition wake_host.cpp:65
Platform-specific main loop wake primitives.