4#ifdef USE_SOCKET_IMPL_LWIP_TCP
21static volatile bool s_socket_woke =
false;
35 s_socket_woke =
false;
36 esp_delay(ms, []() {
return !s_socket_woke; });
45static const char *
const TAG =
"socket.lwip";
49#define LWIP_LOG(msg, ...) ESP_LOGVV(TAG, "socket %p: " msg, this, ##__VA_ARGS__)
51#define LWIP_LOG(msg, ...)
57 if (this->
pcb_ !=
nullptr) {
58 LWIP_LOG(
"tcp_abort(%p)", this->
pcb_);
59 tcp_abort(this->
pcb_);
65 if (this->
pcb_ ==
nullptr) {
69 if (name ==
nullptr) {
81 auto *addr4 =
reinterpret_cast<const sockaddr_in *
>(name);
82 port = ntohs(addr4->sin_port);
83 ip.type = IPADDR_TYPE_V4;
84 ip.u_addr.ip4.addr = addr4->sin_addr.s_addr;
85 LWIP_LOG(
"tcp_bind(%p ip=%s port=%u)", this->
pcb_, ip4addr_ntoa(&ip.u_addr.ip4), port);
86 }
else if (this->
family_ == AF_INET6) {
91 auto *addr6 =
reinterpret_cast<const sockaddr_in6 *
>(name);
92 port = ntohs(addr6->sin6_port);
93 ip.type = IPADDR_TYPE_ANY;
94 memcpy(&ip.u_addr.ip6.addr, &addr6->sin6_addr.un.u8_addr, 16);
95 LWIP_LOG(
"tcp_bind(%p ip=%s port=%u)", this->
pcb_, ip6addr_ntoa(&ip.u_addr.ip6), port);
101 if (this->
family_ != AF_INET) {
105 auto *addr4 =
reinterpret_cast<const sockaddr_in *
>(name);
106 port = ntohs(addr4->sin_port);
107 ip.addr = addr4->sin_addr.s_addr;
108 LWIP_LOG(
"tcp_bind(%p ip=%u port=%u)", this->
pcb_, ip.addr, port);
110 err_t err = tcp_bind(this->
pcb_, &ip, port);
111 if (err == ERR_USE) {
112 LWIP_LOG(
" -> err ERR_USE");
116 if (err == ERR_VAL) {
117 LWIP_LOG(
" -> err ERR_VAL");
122 LWIP_LOG(
" -> err %d", err);
130 if (this->
pcb_ ==
nullptr) {
134 LWIP_LOG(
"tcp_close(%p)", this->
pcb_);
135 err_t err = tcp_close(this->
pcb_);
137 LWIP_LOG(
" -> err %d", err);
138 tcp_abort(this->
pcb_);
139 this->
pcb_ =
nullptr;
140 errno = err == ERR_MEM ? ENOMEM : EIO;
143 this->
pcb_ =
nullptr;
148 if (this->
pcb_ ==
nullptr) {
152 bool shut_rx =
false, shut_tx =
false;
153 if (how == SHUT_RD) {
155 }
else if (how == SHUT_WR) {
157 }
else if (how == SHUT_RDWR) {
158 shut_rx = shut_tx =
true;
163 LWIP_LOG(
"tcp_shutdown(%p shut_rx=%d shut_tx=%d)", this->
pcb_, shut_rx ? 1 : 0, shut_tx ? 1 : 0);
164 err_t err = tcp_shutdown(this->
pcb_, shut_rx, shut_tx);
166 LWIP_LOG(
" -> err %d", err);
167 errno = err == ERR_MEM ? ENOMEM : EIO;
174 if (this->
pcb_ ==
nullptr) {
178 if (name ==
nullptr || addrlen ==
nullptr) {
182 return this->
ip2sockaddr_(&this->
pcb_->remote_ip, this->pcb_->remote_port, name, addrlen);
186 if (this->
pcb_ ==
nullptr) {
190 if (name ==
nullptr || addrlen ==
nullptr) {
194 return this->
ip2sockaddr_(&this->
pcb_->local_ip, this->pcb_->local_port, name, addrlen);
218 if (this->
pcb_ ==
nullptr) {
222 if (optlen ==
nullptr || optval ==
nullptr) {
226 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
233 *
reinterpret_cast<int *
>(optval) = 1;
237 if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
242 *
reinterpret_cast<int *
>(optval) = this->
nodelay_;
252 if (this->
pcb_ ==
nullptr) {
256 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
265 if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
270 int val = *
reinterpret_cast<const int *
>(optval);
280 if (this->
family_ == AF_INET) {
290 inet_addr_from_ip4addr(&addr->
sin_addr, ip_2_ip4(ip));
294 else if (this->
family_ == AF_INET6) {
308 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&mapped), ip_2_ip4(ip));
309 inet6_addr_from_ip6addr(&addr->
sin6_addr, ip_2_ip6(&mapped));
311 inet6_addr_from_ip6addr(&addr->
sin6_addr, ip_2_ip6(ip));
325 if (this->
rx_buf_ !=
nullptr) {
333 LWIP_LOG(
"init(%p)", this->
pcb_);
334 tcp_arg(this->
pcb_,
this);
345 auto *arg_this =
reinterpret_cast<LWIPRawImpl *
>(arg);
346 ESP_LOGVV(TAG,
"socket %p: err(err=%d)", arg_this, err);
347 arg_this->pcb_ =
nullptr;
351 auto *arg_this =
reinterpret_cast<LWIPRawImpl *
>(arg);
352 return arg_this->
recv_fn(pb, err);
356 LWIP_LOG(
"recv(pb=%p err=%d)", pb, err);
367 if (this->
rx_buf_ ==
nullptr) {
382 if (this->
pcb_ ==
nullptr) {
392 if (this->
rx_buf_ ==
nullptr) {
398 uint8_t *buf8 =
reinterpret_cast<uint8_t *
>(buf);
400 size_t pb_len = this->
rx_buf_->len;
404 size_t copysize = std::min(
len, pb_left);
405 memcpy(buf8,
reinterpret_cast<uint8_t *
>(this->
rx_buf_->payload) + this->rx_buf_offset_, copysize);
407 if (pb_left == copysize) {
409 if (this->
rx_buf_->next ==
nullptr) {
413 this->rx_buf_offset_ = 0;
419 this->rx_buf_offset_ = 0;
422 this->rx_buf_offset_ += copysize;
424 LWIP_LOG(
"tcp_recved(%p %u)", this->
pcb_, copysize);
425 tcp_recved(this->
pcb_, copysize);
442 for (
int i = 0; i < iovcnt; i++) {
443 ssize_t err = this->
read(
reinterpret_cast<uint8_t *
>(iov[i].iov_base), iov[i].iov_len);
452 if ((
size_t) err != iov[i].iov_len)
459 if (this->
pcb_ ==
nullptr) {
465 if (buf ==
nullptr) {
469 auto space = tcp_sndbuf(this->
pcb_);
474 size_t to_send = std::min((
size_t) space,
len);
475 LWIP_LOG(
"tcp_write(%p buf=%p %u)", this->
pcb_, buf, to_send);
476 err_t err = tcp_write(this->
pcb_, buf, to_send, TCP_WRITE_FLAG_COPY);
477 if (err == ERR_MEM) {
478 LWIP_LOG(
" -> err ERR_MEM");
483 LWIP_LOG(
" -> err %d", err);
491 LWIP_LOG(
"tcp_output(%p)", this->
pcb_);
492 err_t err = tcp_output(this->
pcb_);
493 if (err == ERR_ABRT) {
498 LWIP_LOG(
" -> err ERR_ABRT");
502 LWIP_LOG(
" -> err %d", err);
527 for (
int i = 0; i < iovcnt; i++) {
537 if ((
size_t) err != iov[i].iov_len)
559 if (this->
pcb_ !=
nullptr) {
560 tcp_close(this->
pcb_);
561 this->
pcb_ =
nullptr;
566 LWIP_LOG(
"init(%p)", this->
pcb_);
567 tcp_arg(this->
pcb_,
this);
568 tcp_accept(this->
pcb_, LWIPRawListenImpl::s_accept_fn);
574 ESP_LOGVV(TAG,
"socket %p: err(err=%d)", arg_this, err);
575 arg_this->pcb_ =
nullptr;
578err_t LWIPRawListenImpl::s_accept_fn(
void *arg,
struct tcp_pcb *newpcb, err_t err) {
580 return arg_this->accept_fn_(newpcb, err);
584 if (this->
pcb_ ==
nullptr) {
588 if (this->accepted_socket_count_ == 0) {
593 std::unique_ptr<LWIPRawImpl> sock = std::move(this->accepted_sockets_[0]);
595 for (uint8_t i = 1; i < this->accepted_socket_count_; i++) {
596 this->accepted_sockets_[i - 1] = std::move(this->accepted_sockets_[i]);
598 this->accepted_socket_count_--;
599 LWIP_LOG(
"Connection accepted by application, queue size: %d", this->accepted_socket_count_);
600 if (addr !=
nullptr) {
601 sock->getpeername(addr, addrlen);
603 LWIP_LOG(
"accept(%p)", sock.get());
608 if (this->
pcb_ ==
nullptr) {
612 LWIP_LOG(
"tcp_listen_with_backlog(%p backlog=%d)", this->
pcb_, backlog);
613 struct tcp_pcb *listen_pcb = tcp_listen_with_backlog(this->
pcb_, backlog);
614 if (listen_pcb ==
nullptr) {
615 tcp_abort(this->
pcb_);
616 this->
pcb_ =
nullptr;
621 this->
pcb_ = listen_pcb;
623 LWIP_LOG(
"tcp_arg(%p)", this->
pcb_);
624 tcp_arg(this->
pcb_,
this);
625 tcp_accept(this->
pcb_, LWIPRawListenImpl::s_accept_fn);
632err_t LWIPRawListenImpl::accept_fn_(
struct tcp_pcb *newpcb, err_t err) {
633 LWIP_LOG(
"accept(newpcb=%p err=%d)", newpcb, err);
634 if (err != ERR_OK || newpcb ==
nullptr) {
642 if (this->accepted_socket_count_ >= MAX_ACCEPTED_SOCKETS) {
643 LWIP_LOG(
"Rejecting connection, queue full (%d)", this->accepted_socket_count_);
649 auto sock = make_unique<LWIPRawImpl>(this->
family_, newpcb);
651 this->accepted_sockets_[this->accepted_socket_count_++] = std::move(sock);
652 LWIP_LOG(
"Accepted connection, queue size: %d", this->accepted_socket_count_);
662std::unique_ptr<Socket>
socket(
int domain,
int type,
int protocol) {
663 if (
type != SOCK_STREAM) {
664 ESP_LOGE(TAG,
"UDP sockets not supported on this platform, use WiFiUDP");
668 auto *pcb = tcp_new();
671 auto *sock =
new LWIPRawImpl((
sa_family_t) domain, pcb);
673 return std::unique_ptr<Socket>{sock};
682 if (
type != SOCK_STREAM) {
683 ESP_LOGE(TAG,
"UDP sockets not supported on this platform, use WiFiUDP");
687 auto *pcb = tcp_new();
690 auto *sock =
new LWIPRawListenImpl((
sa_family_t) domain, pcb);
692 return std::unique_ptr<ListenSocket>{sock};
int getsockname(struct sockaddr *name, socklen_t *addrlen)
size_t getsockname_to(std::span< char, SOCKADDR_STR_LEN > buf)
Format local address into a fixed-size buffer (no heap allocation)
int bind(const struct sockaddr *name, socklen_t addrlen)
int ip2sockaddr_(ip_addr_t *ip, uint16_t port, struct sockaddr *name, socklen_t *addrlen)
int setsockopt(int level, int optname, const void *optval, socklen_t optlen)
int getsockopt(int level, int optname, void *optval, socklen_t *optlen)
int getpeername(struct sockaddr *name, 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)
Connected socket implementation for LWIP raw TCP.
static err_t s_recv_fn(void *arg, struct tcp_pcb *pcb, struct pbuf *pb, err_t err)
ssize_t readv(const struct iovec *iov, int iovcnt)
static void s_err_fn(void *arg, err_t err)
err_t recv_fn(struct pbuf *pb, err_t err)
ssize_t internal_write_(const void *buf, size_t len)
ssize_t write(const void *buf, size_t len)
ssize_t read(void *buf, size_t len)
ssize_t writev(const struct iovec *iov, int iovcnt)
Listening socket implementation for LWIP raw TCP.
static void s_err_fn(void *arg, err_t err)
std::unique_ptr< LWIPRawImpl > accept(struct sockaddr *addr, socklen_t *addrlen)
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< ListenSocket > socket_listen(int domain, int type, int protocol)
Create a listening socket of the given domain, type and protocol.
std::unique_ptr< ListenSocket > socket_listen_loop_monitored(int domain, int type, int protocol)
Create a listening socket and monitor it for data in the main loop.
void IRAM_ATTR socket_wake()
Signal socket/IO activity and wake the main loop from esp_delay() early.
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.
void socket_delay(uint32_t ms)
Delay that can be woken early by socket activity.
void HOT delay(uint32_t ms)
struct in6_addr sin6_addr