ESPHome 2026.3.0
Loading...
Searching...
No Matches
bsd_sockets_impl.h
Go to the documentation of this file.
1#pragma once
3
4#ifdef USE_SOCKET_IMPL_BSD_SOCKETS
5
6#include <memory>
7#include <span>
8
10#include "headers.h"
11
12#ifdef USE_ESP32
13#include <lwip/sockets.h>
14#endif
15
16#ifdef USE_LWIP_FAST_SELECT
18#endif
19
20namespace esphome::socket {
21
23 public:
24 BSDSocketImpl(int fd, bool monitor_loop = false);
26 BSDSocketImpl(const BSDSocketImpl &) = delete;
28
29 int connect(const struct sockaddr *addr, socklen_t addrlen) { return ::connect(this->fd_, addr, addrlen); }
30 std::unique_ptr<BSDSocketImpl> accept(struct sockaddr *addr, socklen_t *addrlen) {
31 int fd = ::accept(this->fd_, addr, addrlen);
32 if (fd == -1)
33 return {};
34 return make_unique<BSDSocketImpl>(fd, false);
35 }
36 std::unique_ptr<BSDSocketImpl> accept_loop_monitored(struct sockaddr *addr, socklen_t *addrlen) {
37 int fd = ::accept(this->fd_, addr, addrlen);
38 if (fd == -1)
39 return {};
40 return make_unique<BSDSocketImpl>(fd, true);
41 }
42
43 int bind(const struct sockaddr *addr, socklen_t addrlen) { return ::bind(this->fd_, addr, addrlen); }
44 int close();
45 int shutdown(int how) { return ::shutdown(this->fd_, how); }
46
47 int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return ::getpeername(this->fd_, addr, addrlen); }
48 int getsockname(struct sockaddr *addr, socklen_t *addrlen) { return ::getsockname(this->fd_, addr, addrlen); }
49
51 size_t getpeername_to(std::span<char, SOCKADDR_STR_LEN> buf);
53 size_t getsockname_to(std::span<char, SOCKADDR_STR_LEN> buf);
54
55 int getsockopt(int level, int optname, void *optval, socklen_t *optlen) {
56 return ::getsockopt(this->fd_, level, optname, optval, optlen);
57 }
58 int setsockopt(int level, int optname, const void *optval, socklen_t optlen) {
59#if defined(USE_LWIP_FAST_SELECT) && defined(CONFIG_LWIP_TCPIP_CORE_LOCKING)
60 // Fast path for TCP_NODELAY: directly set the pcb flag under the TCPIP core lock,
61 // bypassing lwip_setsockopt overhead (socket lookups, hook, switch cascade, refcounting).
62 if (level == IPPROTO_TCP && optname == TCP_NODELAY && optlen == sizeof(int) && optval != nullptr) {
63 LwIPLock lock;
64 if (esphome_lwip_set_nodelay(this->cached_sock_, *reinterpret_cast<const int *>(optval) != 0))
65 return 0;
66 }
67#endif
68 return ::setsockopt(this->fd_, level, optname, optval, optlen);
69 }
70 int listen(int backlog) { return ::listen(this->fd_, backlog); }
71 ssize_t read(void *buf, size_t len) {
72#ifdef USE_ESP32
73 return ::lwip_read(this->fd_, buf, len);
74#else
75 return ::read(this->fd_, buf, len);
76#endif
77 }
78 ssize_t recvfrom(void *buf, size_t len, sockaddr *addr, socklen_t *addr_len) {
79#if defined(USE_ESP32) || defined(USE_HOST)
80 return ::recvfrom(this->fd_, buf, len, 0, addr, addr_len);
81#else
82 return ::lwip_recvfrom(this->fd_, buf, len, 0, addr, addr_len);
83#endif
84 }
85 ssize_t readv(const struct iovec *iov, int iovcnt) {
86#if defined(USE_ESP32)
87 return ::lwip_readv(this->fd_, iov, iovcnt);
88#else
89 return ::readv(this->fd_, iov, iovcnt);
90#endif
91 }
92 ssize_t write(const void *buf, size_t len) {
93#ifdef USE_ESP32
94 return ::lwip_write(this->fd_, buf, len);
95#else
96 return ::write(this->fd_, buf, len);
97#endif
98 }
99 ssize_t send(const void *buf, size_t len, int flags) { return ::send(this->fd_, buf, len, flags); }
100 ssize_t writev(const struct iovec *iov, int iovcnt) {
101#if defined(USE_ESP32)
102 return ::lwip_writev(this->fd_, iov, iovcnt);
103#else
104 return ::writev(this->fd_, iov, iovcnt);
105#endif
106 }
107
108 ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) {
109 return ::sendto(this->fd_, buf, len, flags, to, tolen); // NOLINT(readability-suspicious-call-argument)
110 }
111
112 int setblocking(bool blocking);
113 int loop() { return 0; }
114
115 bool ready() const;
116
117 int get_fd() const { return this->fd_; }
118
119 protected:
120 int fd_{-1};
121#ifdef USE_LWIP_FAST_SELECT
122 struct lwip_sock *cached_sock_{nullptr}; // Cached for direct rcvevent read in ready()
123#endif
124 bool closed_{false};
125 bool loop_monitored_{false};
126};
127
128} // namespace esphome::socket
129
130#endif // USE_SOCKET_IMPL_BSD_SOCKETS
Helper class to lock the lwIP TCPIP core when making lwIP API calls from non-TCPIP threads.
Definition helpers.h:1810
BSDSocketImpl & operator=(const BSDSocketImpl &)=delete
std::unique_ptr< BSDSocketImpl > accept(struct sockaddr *addr, socklen_t *addrlen)
int getsockopt(int level, int optname, void *optval, socklen_t *optlen)
ssize_t send(const void *buf, size_t len, int flags)
ssize_t write(const void *buf, size_t len)
BSDSocketImpl(const BSDSocketImpl &)=delete
int getpeername(struct sockaddr *addr, socklen_t *addrlen)
int connect(const struct sockaddr *addr, socklen_t addrlen)
int bind(const struct sockaddr *addr, socklen_t addrlen)
ssize_t recvfrom(void *buf, size_t len, sockaddr *addr, socklen_t *addr_len)
ssize_t read(void *buf, size_t len)
ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
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 setsockopt(int level, int optname, const void *optval, socklen_t optlen)
ssize_t writev(const struct iovec *iov, int iovcnt)
ssize_t readv(const struct iovec *iov, int iovcnt)
std::unique_ptr< BSDSocketImpl > accept_loop_monitored(struct sockaddr *addr, socklen_t *addrlen)
int getsockname(struct sockaddr *addr, socklen_t *addrlen)
BSDSocketImpl(int fd, bool monitor_loop=false)
uint16_t flags
uint16_t addr_len
uint32_t socklen_t
Definition headers.h:99
__int64 ssize_t
Definition httplib.h:178
bool esphome_lwip_set_nodelay(struct lwip_sock *sock, bool enable)
Set or clear TCP_NODELAY on a socket's tcp_pcb directly.
std::string size_t len
Definition helpers.h:892