ESPHome 2026.1.4
Loading...
Searching...
No Matches
lwip_sockets_impl.cpp
Go to the documentation of this file.
1#include "socket.h"
4
5#ifdef USE_SOCKET_IMPL_LWIP_SOCKETS
6
7#include <cstring>
9
10namespace esphome::socket {
11
12class LwIPSocketImpl final : public Socket {
13 public:
14 LwIPSocketImpl(int fd, bool monitor_loop = false) : fd_(fd) {
15#ifdef USE_SOCKET_SELECT_SUPPORT
16 // Register new socket with the application for select() if monitoring requested
17 if (monitor_loop && this->fd_ >= 0) {
18 // Only set loop_monitored_ to true if registration succeeds
19 this->loop_monitored_ = App.register_socket_fd(this->fd_);
20 } else {
21 this->loop_monitored_ = false;
22 }
23#else
24 // Without select support, ignore monitor_loop parameter
25 (void) monitor_loop;
26#endif
27 }
28 ~LwIPSocketImpl() override {
29 if (!this->closed_) {
30 this->close(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
31 }
32 }
33 int connect(const struct sockaddr *addr, socklen_t addrlen) override {
34 return lwip_connect(this->fd_, addr, addrlen);
35 }
36 std::unique_ptr<Socket> accept(struct sockaddr *addr, socklen_t *addrlen) override {
37 int fd = lwip_accept(this->fd_, addr, addrlen);
38 if (fd == -1)
39 return {};
40 return make_unique<LwIPSocketImpl>(fd, false);
41 }
42 std::unique_ptr<Socket> accept_loop_monitored(struct sockaddr *addr, socklen_t *addrlen) override {
43 int fd = lwip_accept(this->fd_, addr, addrlen);
44 if (fd == -1)
45 return {};
46 return make_unique<LwIPSocketImpl>(fd, true);
47 }
48
49 int bind(const struct sockaddr *addr, socklen_t addrlen) override { return lwip_bind(this->fd_, addr, addrlen); }
50 int close() override {
51 if (!this->closed_) {
52#ifdef USE_SOCKET_SELECT_SUPPORT
53 // Unregister from select() before closing if monitored
54 if (this->loop_monitored_) {
55 App.unregister_socket_fd(this->fd_);
56 }
57#endif
58 int ret = lwip_close(this->fd_);
59 this->closed_ = true;
60 return ret;
61 }
62 return 0;
63 }
64 int shutdown(int how) override { return lwip_shutdown(this->fd_, how); }
65
66 int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
67 return lwip_getpeername(this->fd_, addr, addrlen);
68 }
69 int getsockname(struct sockaddr *addr, socklen_t *addrlen) override {
70 return lwip_getsockname(this->fd_, addr, addrlen);
71 }
72 int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override {
73 return lwip_getsockopt(this->fd_, level, optname, optval, optlen);
74 }
75 int setsockopt(int level, int optname, const void *optval, socklen_t optlen) override {
76 return lwip_setsockopt(this->fd_, level, optname, optval, optlen);
77 }
78 int listen(int backlog) override { return lwip_listen(this->fd_, backlog); }
79 ssize_t read(void *buf, size_t len) override { return lwip_read(this->fd_, buf, len); }
80 ssize_t recvfrom(void *buf, size_t len, sockaddr *addr, socklen_t *addr_len) override {
81 return lwip_recvfrom(this->fd_, buf, len, 0, addr, addr_len);
82 }
83 ssize_t readv(const struct iovec *iov, int iovcnt) override { return lwip_readv(this->fd_, iov, iovcnt); }
84 ssize_t write(const void *buf, size_t len) override { return lwip_write(this->fd_, buf, len); }
85 ssize_t send(void *buf, size_t len, int flags) { return lwip_send(this->fd_, buf, len, flags); }
86 ssize_t writev(const struct iovec *iov, int iovcnt) override { return lwip_writev(this->fd_, iov, iovcnt); }
87 ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) override {
88 return lwip_sendto(this->fd_, buf, len, flags, to, tolen);
89 }
90 int setblocking(bool blocking) override {
91 int fl = lwip_fcntl(this->fd_, F_GETFL, 0);
92 if (blocking) {
93 fl &= ~O_NONBLOCK;
94 } else {
95 fl |= O_NONBLOCK;
96 }
97 lwip_fcntl(this->fd_, F_SETFL, fl);
98 return 0;
99 }
100
101 int get_fd() const override { return this->fd_; }
102
103#ifdef USE_SOCKET_SELECT_SUPPORT
104 bool ready() const override {
105 if (!this->loop_monitored_)
106 return true;
107 return App.is_socket_ready(this->fd_);
108 }
109#endif
110
111 protected:
112 int fd_;
113 bool closed_{false};
114#ifdef USE_SOCKET_SELECT_SUPPORT
115 bool loop_monitored_{false};
116#endif
117};
118
119// Helper to create a socket with optional monitoring
120static std::unique_ptr<Socket> create_socket(int domain, int type, int protocol, bool loop_monitored = false) {
121 int ret = lwip_socket(domain, type, protocol);
122 if (ret == -1)
123 return nullptr;
124 return std::unique_ptr<Socket>{new LwIPSocketImpl(ret, loop_monitored)};
125}
126
127std::unique_ptr<Socket> socket(int domain, int type, int protocol) {
128 return create_socket(domain, type, protocol, false);
129}
130
131std::unique_ptr<Socket> socket_loop_monitored(int domain, int type, int protocol) {
132 return create_socket(domain, type, protocol, true);
133}
134
135} // namespace esphome::socket
136
137#endif // USE_SOCKET_IMPL_LWIP_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.