ESPHome 2026.1.4
Loading...
Searching...
No Matches
bsd_sockets_impl.cpp
Go to the documentation of this file.
1#include "socket.h"
4
5#ifdef USE_SOCKET_IMPL_BSD_SOCKETS
6
7#include <cstring>
9
10#ifdef USE_ESP32
11#include <esp_idf_version.h>
12#include <lwip/sockets.h>
13#endif
14
15namespace esphome::socket {
16
17class BSDSocketImpl final : public Socket {
18 public:
19 BSDSocketImpl(int fd, bool monitor_loop = false) : fd_(fd) {
20#ifdef USE_SOCKET_SELECT_SUPPORT
21 // Register new socket with the application for select() if monitoring requested
22 if (monitor_loop && this->fd_ >= 0) {
23 // Only set loop_monitored_ to true if registration succeeds
24 this->loop_monitored_ = App.register_socket_fd(this->fd_);
25 } else {
26 this->loop_monitored_ = false;
27 }
28#else
29 // Without select support, ignore monitor_loop parameter
30 (void) monitor_loop;
31#endif
32 }
33 ~BSDSocketImpl() override {
34 if (!this->closed_) {
35 this->close(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
36 }
37 }
38 int connect(const struct sockaddr *addr, socklen_t addrlen) override { return ::connect(this->fd_, addr, addrlen); }
39 std::unique_ptr<Socket> accept(struct sockaddr *addr, socklen_t *addrlen) override {
40 int fd = ::accept(this->fd_, addr, addrlen);
41 if (fd == -1)
42 return {};
43 return make_unique<BSDSocketImpl>(fd, false);
44 }
45 std::unique_ptr<Socket> accept_loop_monitored(struct sockaddr *addr, socklen_t *addrlen) override {
46 int fd = ::accept(this->fd_, addr, addrlen);
47 if (fd == -1)
48 return {};
49 return make_unique<BSDSocketImpl>(fd, true);
50 }
51
52 int bind(const struct sockaddr *addr, socklen_t addrlen) override { return ::bind(this->fd_, addr, addrlen); }
53 int close() override {
54 if (!this->closed_) {
55#ifdef USE_SOCKET_SELECT_SUPPORT
56 // Unregister from select() before closing if monitored
57 if (this->loop_monitored_) {
58 App.unregister_socket_fd(this->fd_);
59 }
60#endif
61 int ret = ::close(this->fd_);
62 this->closed_ = true;
63 return ret;
64 }
65 return 0;
66 }
67 int shutdown(int how) override { return ::shutdown(this->fd_, how); }
68
69 int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
70 return ::getpeername(this->fd_, addr, addrlen);
71 }
72 int getsockname(struct sockaddr *addr, socklen_t *addrlen) override {
73 return ::getsockname(this->fd_, addr, addrlen);
74 }
75 int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override {
76 return ::getsockopt(this->fd_, level, optname, optval, optlen);
77 }
78 int setsockopt(int level, int optname, const void *optval, socklen_t optlen) override {
79 return ::setsockopt(this->fd_, level, optname, optval, optlen);
80 }
81 int listen(int backlog) override { return ::listen(this->fd_, backlog); }
82 ssize_t read(void *buf, size_t len) override {
83#ifdef USE_ESP32
84 return ::lwip_read(this->fd_, buf, len);
85#else
86 return ::read(this->fd_, buf, len);
87#endif
88 }
89 ssize_t recvfrom(void *buf, size_t len, sockaddr *addr, socklen_t *addr_len) override {
90#if defined(USE_ESP32) || defined(USE_HOST)
91 return ::recvfrom(this->fd_, buf, len, 0, addr, addr_len);
92#else
93 return ::lwip_recvfrom(this->fd_, buf, len, 0, addr, addr_len);
94#endif
95 }
96 ssize_t readv(const struct iovec *iov, int iovcnt) override {
97#if defined(USE_ESP32)
98 return ::lwip_readv(this->fd_, iov, iovcnt);
99#else
100 return ::readv(this->fd_, iov, iovcnt);
101#endif
102 }
103 ssize_t write(const void *buf, size_t len) override {
104#ifdef USE_ESP32
105 return ::lwip_write(this->fd_, buf, len);
106#else
107 return ::write(this->fd_, buf, len);
108#endif
109 }
110 ssize_t send(void *buf, size_t len, int flags) { return ::send(this->fd_, buf, len, flags); }
111 ssize_t writev(const struct iovec *iov, int iovcnt) override {
112#if defined(USE_ESP32)
113 return ::lwip_writev(this->fd_, iov, iovcnt);
114#else
115 return ::writev(this->fd_, iov, iovcnt);
116#endif
117 }
118
119 ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) override {
120 return ::sendto(this->fd_, buf, len, flags, to, tolen); // NOLINT(readability-suspicious-call-argument)
121 }
122
123 int setblocking(bool blocking) override {
124 int fl = ::fcntl(this->fd_, F_GETFL, 0);
125 if (blocking) {
126 fl &= ~O_NONBLOCK;
127 } else {
128 fl |= O_NONBLOCK;
129 }
130 ::fcntl(this->fd_, F_SETFL, fl);
131 return 0;
132 }
133
134 int get_fd() const override { return this->fd_; }
135
136#ifdef USE_SOCKET_SELECT_SUPPORT
137 bool ready() const override {
138 if (!this->loop_monitored_)
139 return true;
140 return App.is_socket_ready(this->fd_);
141 }
142#endif
143
144 protected:
145 int fd_;
146 bool closed_{false};
147#ifdef USE_SOCKET_SELECT_SUPPORT
148 bool loop_monitored_{false};
149#endif
150};
151
152// Helper to create a socket with optional monitoring
153static std::unique_ptr<Socket> create_socket(int domain, int type, int protocol, bool loop_monitored = false) {
154 int ret = ::socket(domain, type, protocol);
155 if (ret == -1)
156 return nullptr;
157 return std::unique_ptr<Socket>{new BSDSocketImpl(ret, loop_monitored)};
158}
159
160std::unique_ptr<Socket> socket(int domain, int type, int protocol) {
161 return create_socket(domain, type, protocol, false);
162}
163
164std::unique_ptr<Socket> socket_loop_monitored(int domain, int type, int protocol) {
165 return create_socket(domain, type, protocol, true);
166}
167
168} // namespace esphome::socket
169
170#endif // USE_SOCKET_IMPL_BSD_SOCKETS
bool is_socket_ready(int fd) const
Check if there's data available on a socket without blocking This function is thread-safe for reading...
void unregister_socket_fd(int fd)
bool register_socket_fd(int fd)
Register/unregister a socket file descriptor to be monitored for read events.
uint16_t type
uint16_t flags
uint16_t addr_len
uint32_t socklen_t
Definition headers.h:97
__int64 ssize_t
Definition httplib.h:178
std::unique_ptr< Socket > socket(int domain, int type, int protocol)
Create a socket of the given domain, type and protocol.
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::string size_t len
Definition helpers.h:595
Application App
Global storage of Application pointer - only one Application can exist.