ESPHome 2026.1.0-dev
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
12std::string format_sockaddr(const struct sockaddr_storage &storage) {
13 if (storage.ss_family == AF_INET) {
14 const struct sockaddr_in *addr = reinterpret_cast<const struct sockaddr_in *>(&storage);
15 char buf[INET_ADDRSTRLEN];
16 const char *ret = lwip_inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf));
17 if (ret == nullptr)
18 return {};
19 return std::string{buf};
20 }
21#if LWIP_IPV6
22 else if (storage.ss_family == AF_INET6) {
23 const struct sockaddr_in6 *addr = reinterpret_cast<const struct sockaddr_in6 *>(&storage);
24 char buf[INET6_ADDRSTRLEN];
25 const char *ret = lwip_inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf));
26 if (ret == nullptr)
27 return {};
28 return std::string{buf};
29 }
30#endif
31 return {};
32}
33
34class LwIPSocketImpl : public Socket {
35 public:
36 LwIPSocketImpl(int fd, bool monitor_loop = false) : fd_(fd) {
37#ifdef USE_SOCKET_SELECT_SUPPORT
38 // Register new socket with the application for select() if monitoring requested
39 if (monitor_loop && this->fd_ >= 0) {
40 // Only set loop_monitored_ to true if registration succeeds
41 this->loop_monitored_ = App.register_socket_fd(this->fd_);
42 } else {
43 this->loop_monitored_ = false;
44 }
45#else
46 // Without select support, ignore monitor_loop parameter
47 (void) monitor_loop;
48#endif
49 }
50 ~LwIPSocketImpl() override {
51 if (!this->closed_) {
52 this->close(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
53 }
54 }
55 int connect(const struct sockaddr *addr, socklen_t addrlen) override {
56 return lwip_connect(this->fd_, addr, addrlen);
57 }
58 std::unique_ptr<Socket> accept(struct sockaddr *addr, socklen_t *addrlen) override {
59 int fd = lwip_accept(this->fd_, addr, addrlen);
60 if (fd == -1)
61 return {};
62 return make_unique<LwIPSocketImpl>(fd, false);
63 }
64 std::unique_ptr<Socket> accept_loop_monitored(struct sockaddr *addr, socklen_t *addrlen) override {
65 int fd = lwip_accept(this->fd_, addr, addrlen);
66 if (fd == -1)
67 return {};
68 return make_unique<LwIPSocketImpl>(fd, true);
69 }
70
71 int bind(const struct sockaddr *addr, socklen_t addrlen) override { return lwip_bind(this->fd_, addr, addrlen); }
72 int close() override {
73 if (!this->closed_) {
74#ifdef USE_SOCKET_SELECT_SUPPORT
75 // Unregister from select() before closing if monitored
76 if (this->loop_monitored_) {
77 App.unregister_socket_fd(this->fd_);
78 }
79#endif
80 int ret = lwip_close(this->fd_);
81 this->closed_ = true;
82 return ret;
83 }
84 return 0;
85 }
86 int shutdown(int how) override { return lwip_shutdown(this->fd_, how); }
87
88 int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
89 return lwip_getpeername(this->fd_, addr, addrlen);
90 }
91 std::string getpeername() override {
92 struct sockaddr_storage storage;
93 socklen_t len = sizeof(storage);
94 if (lwip_getpeername(this->fd_, (struct sockaddr *) &storage, &len) != 0)
95 return {};
96 return format_sockaddr(storage);
97 }
98 int getsockname(struct sockaddr *addr, socklen_t *addrlen) override {
99 return lwip_getsockname(this->fd_, addr, addrlen);
100 }
101 std::string getsockname() override {
102 struct sockaddr_storage storage;
103 socklen_t len = sizeof(storage);
104 if (lwip_getsockname(this->fd_, (struct sockaddr *) &storage, &len) != 0)
105 return {};
106 return format_sockaddr(storage);
107 }
108 int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override {
109 return lwip_getsockopt(this->fd_, level, optname, optval, optlen);
110 }
111 int setsockopt(int level, int optname, const void *optval, socklen_t optlen) override {
112 return lwip_setsockopt(this->fd_, level, optname, optval, optlen);
113 }
114 int listen(int backlog) override { return lwip_listen(this->fd_, backlog); }
115 ssize_t read(void *buf, size_t len) override { return lwip_read(this->fd_, buf, len); }
116 ssize_t recvfrom(void *buf, size_t len, sockaddr *addr, socklen_t *addr_len) override {
117 return lwip_recvfrom(this->fd_, buf, len, 0, addr, addr_len);
118 }
119 ssize_t readv(const struct iovec *iov, int iovcnt) override { return lwip_readv(this->fd_, iov, iovcnt); }
120 ssize_t write(const void *buf, size_t len) override { return lwip_write(this->fd_, buf, len); }
121 ssize_t send(void *buf, size_t len, int flags) { return lwip_send(this->fd_, buf, len, flags); }
122 ssize_t writev(const struct iovec *iov, int iovcnt) override { return lwip_writev(this->fd_, iov, iovcnt); }
123 ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) override {
124 return lwip_sendto(this->fd_, buf, len, flags, to, tolen);
125 }
126 int setblocking(bool blocking) override {
127 int fl = lwip_fcntl(this->fd_, F_GETFL, 0);
128 if (blocking) {
129 fl &= ~O_NONBLOCK;
130 } else {
131 fl |= O_NONBLOCK;
132 }
133 lwip_fcntl(this->fd_, F_SETFL, fl);
134 return 0;
135 }
136
137 int get_fd() const override { return this->fd_; }
138
139#ifdef USE_SOCKET_SELECT_SUPPORT
140 bool ready() const override {
141 if (!this->loop_monitored_)
142 return true;
143 return App.is_socket_ready(this->fd_);
144 }
145#endif
146
147 protected:
148 int fd_;
149 bool closed_{false};
150#ifdef USE_SOCKET_SELECT_SUPPORT
151 bool loop_monitored_{false};
152#endif
153};
154
155// Helper to create a socket with optional monitoring
156static std::unique_ptr<Socket> create_socket(int domain, int type, int protocol, bool loop_monitored = false) {
157 int ret = lwip_socket(domain, type, protocol);
158 if (ret == -1)
159 return nullptr;
160 return std::unique_ptr<Socket>{new LwIPSocketImpl(ret, loop_monitored)};
161}
162
163std::unique_ptr<Socket> socket(int domain, int type, int protocol) {
164 return create_socket(domain, type, protocol, false);
165}
166
167std::unique_ptr<Socket> socket_loop_monitored(int domain, int type, int protocol) {
168 return create_socket(domain, type, protocol, true);
169}
170
171} // namespace esphome::socket
172
173#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::string format_sockaddr(const struct sockaddr_storage &storage)
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:533
Application App
Global storage of Application pointer - only one Application can exist.
struct in6_addr sin6_addr
Definition headers.h:77
struct in_addr sin_addr
Definition headers.h:65
sa_family_t ss_family
Definition headers.h:92