4#ifdef USE_SOCKET_IMPL_LWIP_TCP
26static volatile bool s_socket_woke =
false;
40 s_socket_woke =
false;
41 esp_delay(ms, []() {
return !s_socket_woke; });
50static const char *
const TAG =
"socket.lwip";
54#define LWIP_LOG(msg, ...) ESP_LOGVV(TAG, "socket %p: " msg, this, ##__VA_ARGS__)
56#define LWIP_LOG(msg, ...)
59class LWIPRawImpl :
public Socket {
61 LWIPRawImpl(
sa_family_t family,
struct tcp_pcb *pcb) : pcb_(pcb), family_(family) {}
62 ~LWIPRawImpl()
override {
63 if (pcb_ !=
nullptr) {
64 LWIP_LOG(
"tcp_abort(%p)", pcb_);
71 LWIP_LOG(
"init(%p)", pcb_);
73 tcp_recv(pcb_, LWIPRawImpl::s_recv_fn);
74 tcp_err(pcb_, LWIPRawImpl::s_err_fn);
77 std::unique_ptr<Socket> accept(
struct sockaddr *addr,
socklen_t *addrlen)
override {
83 if (pcb_ ==
nullptr) {
87 if (name ==
nullptr) {
94 if (family_ == AF_INET) {
99 auto *addr4 =
reinterpret_cast<const sockaddr_in *
>(name);
100 port = ntohs(addr4->sin_port);
101 ip.type = IPADDR_TYPE_V4;
102 ip.u_addr.ip4.addr = addr4->sin_addr.s_addr;
103 LWIP_LOG(
"tcp_bind(%p ip=%s port=%u)", pcb_, ip4addr_ntoa(&ip.u_addr.ip4), port);
104 }
else if (family_ == AF_INET6) {
109 auto *addr6 =
reinterpret_cast<const sockaddr_in6 *
>(name);
110 port = ntohs(addr6->sin6_port);
111 ip.type = IPADDR_TYPE_ANY;
112 memcpy(&ip.u_addr.ip6.addr, &addr6->sin6_addr.un.u8_addr, 16);
113 LWIP_LOG(
"tcp_bind(%p ip=%s port=%u)", pcb_, ip6addr_ntoa(&ip.u_addr.ip6), port);
119 if (family_ != AF_INET) {
123 auto *addr4 =
reinterpret_cast<const sockaddr_in *
>(name);
124 port = ntohs(addr4->sin_port);
125 ip.addr = addr4->sin_addr.s_addr;
126 LWIP_LOG(
"tcp_bind(%p ip=%u port=%u)", pcb_, ip.addr, port);
128 err_t err = tcp_bind(pcb_, &ip, port);
129 if (err == ERR_USE) {
130 LWIP_LOG(
" -> err ERR_USE");
134 if (err == ERR_VAL) {
135 LWIP_LOG(
" -> err ERR_VAL");
140 LWIP_LOG(
" -> err %d", err);
147 if (pcb_ ==
nullptr) {
151 LWIP_LOG(
"tcp_close(%p)", pcb_);
152 err_t err = tcp_close(pcb_);
154 LWIP_LOG(
" -> err %d", err);
157 errno = err == ERR_MEM ? ENOMEM : EIO;
163 int shutdown(
int how)
final {
164 if (pcb_ ==
nullptr) {
168 bool shut_rx =
false, shut_tx =
false;
169 if (how == SHUT_RD) {
171 }
else if (how == SHUT_WR) {
173 }
else if (how == SHUT_RDWR) {
174 shut_rx = shut_tx =
true;
179 LWIP_LOG(
"tcp_shutdown(%p shut_rx=%d shut_tx=%d)", pcb_, shut_rx ? 1 : 0, shut_tx ? 1 : 0);
180 err_t err = tcp_shutdown(pcb_, shut_rx, shut_tx);
182 LWIP_LOG(
" -> err %d", err);
183 errno = err == ERR_MEM ? ENOMEM : EIO;
190 if (pcb_ ==
nullptr) {
194 if (name ==
nullptr || addrlen ==
nullptr) {
198 return this->ip2sockaddr_(&pcb_->remote_ip, pcb_->remote_port, name, addrlen);
201 if (pcb_ ==
nullptr) {
205 if (name ==
nullptr || addrlen ==
nullptr) {
209 return this->ip2sockaddr_(&pcb_->local_ip, pcb_->local_port, name, addrlen);
211 int getsockopt(
int level,
int optname,
void *optval,
socklen_t *optlen)
final {
212 if (pcb_ ==
nullptr) {
216 if (optlen ==
nullptr || optval ==
nullptr) {
220 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
228 *
reinterpret_cast<int *
>(optval) = 1;
232 if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
237 *
reinterpret_cast<int *
>(optval) = nodelay_;
245 int setsockopt(
int level,
int optname,
const void *optval,
socklen_t optlen)
final {
246 if (pcb_ ==
nullptr) {
250 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
260 if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
265 int val = *
reinterpret_cast<const int *
>(optval);
273 int listen(
int backlog)
override {
280 if (pcb_ ==
nullptr) {
284 if (rx_closed_ && rx_buf_ ==
nullptr) {
290 if (rx_buf_ ==
nullptr) {
296 uint8_t *buf8 =
reinterpret_cast<uint8_t *
>(buf);
297 while (
len && rx_buf_ !=
nullptr) {
298 size_t pb_len = rx_buf_->len;
299 size_t pb_left = pb_len - rx_buf_offset_;
302 size_t copysize = std::min(
len, pb_left);
303 memcpy(buf8,
reinterpret_cast<uint8_t *
>(rx_buf_->payload) + rx_buf_offset_, copysize);
305 if (pb_left == copysize) {
307 if (rx_buf_->next ==
nullptr) {
313 auto *old_buf = rx_buf_;
314 rx_buf_ = rx_buf_->next;
320 rx_buf_offset_ += copysize;
322 LWIP_LOG(
"tcp_recved(%p %u)", pcb_, copysize);
323 tcp_recved(pcb_, copysize);
337 ssize_t readv(
const struct iovec *iov,
int iovcnt)
final {
339 for (
int i = 0; i < iovcnt; i++) {
340 ssize_t err = read(
reinterpret_cast<uint8_t *
>(iov[i].iov_base), iov[i].iov_len);
349 if ((
size_t) err != iov[i].iov_len)
360 ssize_t internal_write(
const void *buf,
size_t len) {
361 if (pcb_ ==
nullptr) {
367 if (buf ==
nullptr) {
371 auto space = tcp_sndbuf(pcb_);
376 size_t to_send = std::min((
size_t) space,
len);
377 LWIP_LOG(
"tcp_write(%p buf=%p %u)", pcb_, buf, to_send);
378 err_t err = tcp_write(pcb_, buf, to_send, TCP_WRITE_FLAG_COPY);
379 if (err == ERR_MEM) {
380 LWIP_LOG(
" -> err ERR_MEM");
385 LWIP_LOG(
" -> err %d", err);
391 int internal_output() {
392 LWIP_LOG(
"tcp_output(%p)", pcb_);
393 err_t err = tcp_output(pcb_);
394 if (err == ERR_ABRT) {
395 LWIP_LOG(
" -> err ERR_ABRT");
403 LWIP_LOG(
" -> err %d", err);
409 ssize_t write(
const void *buf,
size_t len)
final {
418 int err = internal_output();
424 ssize_t writev(
const struct iovec *iov,
int iovcnt)
final {
426 for (
int i = 0; i < iovcnt; i++) {
427 ssize_t err = internal_write(
reinterpret_cast<uint8_t *
>(iov[i].iov_base), iov[i].iov_len);
436 if ((
size_t) err != iov[i].iov_len)
444 int err = internal_output();
455 bool ready()
const override {
return this->rx_buf_ !=
nullptr || this->rx_closed_ || this->pcb_ ==
nullptr; }
457 int setblocking(
bool blocking)
final {
458 if (pcb_ ==
nullptr) {
470 void err_fn(err_t err) {
471 LWIP_LOG(
"err(err=%d)", err);
479 err_t recv_fn(
struct pbuf *pb, err_t err) {
480 LWIP_LOG(
"recv(pb=%p err=%d)", pb, err);
491 if (rx_buf_ ==
nullptr) {
496 pbuf_cat(rx_buf_, pb);
505 static void s_err_fn(
void *arg, err_t err) {
506 LWIPRawImpl *arg_this =
reinterpret_cast<LWIPRawImpl *
>(arg);
507 arg_this->err_fn(err);
510 static err_t s_recv_fn(
void *arg,
struct tcp_pcb *pcb,
struct pbuf *pb, err_t err) {
511 LWIPRawImpl *arg_this =
reinterpret_cast<LWIPRawImpl *
>(arg);
512 return arg_this->recv_fn(pb, err);
517 if (family_ == AF_INET) {
527 inet_addr_from_ip4addr(&addr->
sin_addr, ip_2_ip4(ip));
531 else if (family_ == AF_INET6) {
545 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&mapped), ip_2_ip4(ip));
546 inet6_addr_from_ip6addr(&addr->
sin6_addr, ip_2_ip6(&mapped));
548 inet6_addr_from_ip6addr(&addr->
sin6_addr, ip_2_ip6(ip));
558 struct tcp_pcb *pcb_;
559 pbuf *rx_buf_ =
nullptr;
560 size_t rx_buf_offset_ = 0;
561 bool rx_closed_ =
false;
564 bool nodelay_ =
false;
570class LWIPRawListenImpl final :
public LWIPRawImpl {
572 LWIPRawListenImpl(
sa_family_t family,
struct tcp_pcb *pcb) : LWIPRawImpl(family, pcb) {}
575 LWIP_LOG(
"init(%p)", pcb_);
577 tcp_accept(pcb_, LWIPRawListenImpl::s_accept_fn);
578 tcp_err(pcb_, LWIPRawImpl::s_err_fn);
581 bool ready()
const override {
return this->accepted_socket_count_ > 0; }
583 std::unique_ptr<Socket> accept(
struct sockaddr *addr,
socklen_t *addrlen)
override {
584 if (pcb_ ==
nullptr) {
588 if (accepted_socket_count_ == 0) {
593 std::unique_ptr<LWIPRawImpl> sock = std::move(accepted_sockets_[0]);
595 for (uint8_t i = 1; i < accepted_socket_count_; i++) {
596 accepted_sockets_[i - 1] = std::move(accepted_sockets_[i]);
598 accepted_socket_count_--;
599 LWIP_LOG(
"Connection accepted by application, queue size: %d", accepted_socket_count_);
600 if (addr !=
nullptr) {
601 sock->getpeername(addr, addrlen);
603 LWIP_LOG(
"accept(%p)", sock.get());
604 return std::unique_ptr<Socket>(std::move(sock));
607 int listen(
int backlog)
override {
608 if (pcb_ ==
nullptr) {
612 LWIP_LOG(
"tcp_listen_with_backlog(%p backlog=%d)", pcb_, backlog);
613 struct tcp_pcb *listen_pcb = tcp_listen_with_backlog(pcb_, backlog);
614 if (listen_pcb ==
nullptr) {
623 LWIP_LOG(
"tcp_arg(%p)", pcb_);
625 tcp_accept(pcb_, LWIPRawListenImpl::s_accept_fn);
630 err_t accept_fn_(
struct tcp_pcb *newpcb, err_t err) {
631 LWIP_LOG(
"accept(newpcb=%p err=%d)", newpcb, err);
632 if (err != ERR_OK || newpcb ==
nullptr) {
640 if (accepted_socket_count_ >= MAX_ACCEPTED_SOCKETS) {
641 LWIP_LOG(
"Rejecting connection, queue full (%d)", accepted_socket_count_);
647 auto sock = make_unique<LWIPRawImpl>(family_, newpcb);
649 accepted_sockets_[accepted_socket_count_++] = std::move(sock);
650 LWIP_LOG(
"Accepted connection, queue size: %d", accepted_socket_count_);
658 static err_t s_accept_fn(
void *arg,
struct tcp_pcb *newpcb, err_t err) {
659 LWIPRawListenImpl *arg_this =
reinterpret_cast<LWIPRawListenImpl *
>(arg);
660 return arg_this->accept_fn_(newpcb, err);
677 static constexpr size_t MAX_ACCEPTED_SOCKETS = 3;
678 std::array<std::unique_ptr<LWIPRawImpl>, MAX_ACCEPTED_SOCKETS> accepted_sockets_;
679 uint8_t accepted_socket_count_ = 0;
682std::unique_ptr<Socket>
socket(
int domain,
int type,
int protocol) {
683 auto *pcb = tcp_new();
688 auto *sock =
new LWIPRawListenImpl((
sa_family_t) domain, pcb);
690 return std::unique_ptr<Socket>{sock};
void socket_wake()
Called by lwip callbacks to signal socket activity and wake delay.
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 IRAM_ATTR HOT delay(uint32_t ms)
struct in6_addr sin6_addr