4#ifdef USE_SOCKET_IMPL_LWIP_TCP
20static const char *
const TAG =
"socket.lwip";
24#define LWIP_LOG(msg, ...) ESP_LOGVV(TAG, "socket %p: " msg, this, ##__VA_ARGS__)
26#define LWIP_LOG(msg, ...)
29class LWIPRawImpl :
public Socket {
31 LWIPRawImpl(
sa_family_t family,
struct tcp_pcb *pcb) : pcb_(pcb), family_(family) {}
32 ~LWIPRawImpl()
override {
33 if (pcb_ !=
nullptr) {
34 LWIP_LOG(
"tcp_abort(%p)", pcb_);
41 LWIP_LOG(
"init(%p)", pcb_);
43 tcp_recv(pcb_, LWIPRawImpl::s_recv_fn);
44 tcp_err(pcb_, LWIPRawImpl::s_err_fn);
47 std::unique_ptr<Socket> accept(
struct sockaddr *addr,
socklen_t *addrlen)
override {
53 if (pcb_ ==
nullptr) {
57 if (name ==
nullptr) {
64 if (family_ == AF_INET) {
69 auto *addr4 =
reinterpret_cast<const sockaddr_in *
>(name);
70 port = ntohs(addr4->sin_port);
71 ip.type = IPADDR_TYPE_V4;
72 ip.u_addr.ip4.addr = addr4->sin_addr.s_addr;
73 LWIP_LOG(
"tcp_bind(%p ip=%s port=%u)", pcb_, ip4addr_ntoa(&ip.u_addr.ip4), port);
74 }
else if (family_ == AF_INET6) {
79 auto *addr6 =
reinterpret_cast<const sockaddr_in6 *
>(name);
80 port = ntohs(addr6->sin6_port);
81 ip.type = IPADDR_TYPE_ANY;
82 memcpy(&ip.u_addr.ip6.addr, &addr6->sin6_addr.un.u8_addr, 16);
83 LWIP_LOG(
"tcp_bind(%p ip=%s port=%u)", pcb_, ip6addr_ntoa(&ip.u_addr.ip6), port);
89 if (family_ != AF_INET) {
93 auto *addr4 =
reinterpret_cast<const sockaddr_in *
>(name);
94 port = ntohs(addr4->sin_port);
95 ip.addr = addr4->sin_addr.s_addr;
96 LWIP_LOG(
"tcp_bind(%p ip=%u port=%u)", pcb_, ip.addr, port);
98 err_t err = tcp_bind(pcb_, &ip, port);
100 LWIP_LOG(
" -> err ERR_USE");
104 if (err == ERR_VAL) {
105 LWIP_LOG(
" -> err ERR_VAL");
110 LWIP_LOG(
" -> err %d", err);
116 int close()
override {
117 if (pcb_ ==
nullptr) {
121 LWIP_LOG(
"tcp_close(%p)", pcb_);
122 err_t err = tcp_close(pcb_);
124 LWIP_LOG(
" -> err %d", err);
127 errno = err == ERR_MEM ? ENOMEM : EIO;
133 int shutdown(
int how)
override {
134 if (pcb_ ==
nullptr) {
138 bool shut_rx =
false, shut_tx =
false;
139 if (how == SHUT_RD) {
141 }
else if (how == SHUT_WR) {
143 }
else if (how == SHUT_RDWR) {
144 shut_rx = shut_tx =
true;
149 LWIP_LOG(
"tcp_shutdown(%p shut_rx=%d shut_tx=%d)", pcb_, shut_rx ? 1 : 0, shut_tx ? 1 : 0);
150 err_t err = tcp_shutdown(pcb_, shut_rx, shut_tx);
152 LWIP_LOG(
" -> err %d", err);
153 errno = err == ERR_MEM ? ENOMEM : EIO;
160 if (pcb_ ==
nullptr) {
164 if (name ==
nullptr || addrlen ==
nullptr) {
168 return this->ip2sockaddr_(&pcb_->local_ip, pcb_->local_port, name, addrlen);
170 std::string getpeername()
override {
171 if (pcb_ ==
nullptr) {
175 return this->format_ip_address_(pcb_->remote_ip);
178 if (pcb_ ==
nullptr) {
182 if (name ==
nullptr || addrlen ==
nullptr) {
186 return this->ip2sockaddr_(&pcb_->local_ip, pcb_->local_port, name, addrlen);
188 std::string getsockname()
override {
189 if (pcb_ ==
nullptr) {
193 return this->format_ip_address_(pcb_->local_ip);
195 int getsockopt(
int level,
int optname,
void *optval,
socklen_t *optlen)
override {
196 if (pcb_ ==
nullptr) {
200 if (optlen ==
nullptr || optval ==
nullptr) {
204 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
212 *
reinterpret_cast<int *
>(optval) = 1;
216 if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
221 *
reinterpret_cast<int *
>(optval) = nodelay_;
229 int setsockopt(
int level,
int optname,
const void *optval,
socklen_t optlen)
override {
230 if (pcb_ ==
nullptr) {
234 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
244 if (level == IPPROTO_TCP && optname == TCP_NODELAY) {
249 int val = *
reinterpret_cast<const int *
>(optval);
257 int listen(
int backlog)
override {
263 ssize_t read(
void *buf,
size_t len)
override {
264 if (pcb_ ==
nullptr) {
268 if (rx_closed_ && rx_buf_ ==
nullptr) {
274 if (rx_buf_ ==
nullptr) {
280 uint8_t *buf8 =
reinterpret_cast<uint8_t *
>(buf);
281 while (
len && rx_buf_ !=
nullptr) {
282 size_t pb_len = rx_buf_->len;
283 size_t pb_left = pb_len - rx_buf_offset_;
286 size_t copysize = std::min(
len, pb_left);
287 memcpy(buf8,
reinterpret_cast<uint8_t *
>(rx_buf_->payload) + rx_buf_offset_, copysize);
289 if (pb_left == copysize) {
291 if (rx_buf_->next ==
nullptr) {
297 auto *old_buf = rx_buf_;
298 rx_buf_ = rx_buf_->next;
304 rx_buf_offset_ += copysize;
306 LWIP_LOG(
"tcp_recved(%p %u)", pcb_, copysize);
307 tcp_recved(pcb_, copysize);
321 ssize_t readv(
const struct iovec *iov,
int iovcnt)
override {
323 for (
int i = 0; i < iovcnt; i++) {
324 ssize_t err = read(
reinterpret_cast<uint8_t *
>(iov[i].iov_base), iov[i].iov_len);
332 if ((
size_t) err != iov[i].iov_len)
337 ssize_t internal_write(
const void *buf,
size_t len) {
338 if (pcb_ ==
nullptr) {
344 if (buf ==
nullptr) {
348 auto space = tcp_sndbuf(pcb_);
353 size_t to_send = std::min((
size_t) space,
len);
354 LWIP_LOG(
"tcp_write(%p buf=%p %u)", pcb_, buf, to_send);
355 err_t err = tcp_write(pcb_, buf, to_send, TCP_WRITE_FLAG_COPY);
356 if (err == ERR_MEM) {
357 LWIP_LOG(
" -> err ERR_MEM");
362 LWIP_LOG(
" -> err %d", err);
368 int internal_output() {
369 LWIP_LOG(
"tcp_output(%p)", pcb_);
370 err_t err = tcp_output(pcb_);
371 if (err == ERR_ABRT) {
372 LWIP_LOG(
" -> err ERR_ABRT");
380 LWIP_LOG(
" -> err %d", err);
386 ssize_t write(
const void *buf,
size_t len)
override {
394 int err = internal_output();
400 ssize_t writev(
const struct iovec *iov,
int iovcnt)
override {
402 for (
int i = 0; i < iovcnt; i++) {
403 ssize_t err = internal_write(
reinterpret_cast<uint8_t *
>(iov[i].iov_base), iov[i].iov_len);
411 if ((
size_t) err != iov[i].iov_len)
418 int err = internal_output();
429 int setblocking(
bool blocking)
override {
430 if (pcb_ ==
nullptr) {
442 void err_fn(err_t err) {
443 LWIP_LOG(
"err(err=%d)", err);
451 err_t recv_fn(
struct pbuf *pb, err_t err) {
452 LWIP_LOG(
"recv(pb=%p err=%d)", pb, err);
463 if (rx_buf_ ==
nullptr) {
468 pbuf_cat(rx_buf_, pb);
473 static void s_err_fn(
void *arg, err_t err) {
474 LWIPRawImpl *arg_this =
reinterpret_cast<LWIPRawImpl *
>(arg);
475 arg_this->err_fn(err);
478 static err_t s_recv_fn(
void *arg,
struct tcp_pcb *pcb,
struct pbuf *pb, err_t err) {
479 LWIPRawImpl *arg_this =
reinterpret_cast<LWIPRawImpl *
>(arg);
480 return arg_this->recv_fn(pb, err);
484 std::string format_ip_address_(
const ip_addr_t &ip) {
485 char buffer[50] = {};
486 if (IP_IS_V4_VAL(ip)) {
487 inet_ntoa_r(ip, buffer,
sizeof(buffer));
490 else if (IP_IS_V6_VAL(ip)) {
491 inet6_ntoa_r(ip, buffer,
sizeof(buffer));
494 return std::string(buffer);
498 if (family_ == AF_INET) {
508 inet_addr_from_ip4addr(&addr->
sin_addr, ip_2_ip4(ip));
512 else if (family_ == AF_INET6) {
526 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&mapped), ip_2_ip4(ip));
527 inet6_addr_from_ip6addr(&addr->
sin6_addr, ip_2_ip6(&mapped));
529 inet6_addr_from_ip6addr(&addr->
sin6_addr, ip_2_ip6(ip));
539 struct tcp_pcb *pcb_;
540 pbuf *rx_buf_ =
nullptr;
541 size_t rx_buf_offset_ = 0;
542 bool rx_closed_ =
false;
545 bool nodelay_ =
false;
551class LWIPRawListenImpl :
public LWIPRawImpl {
553 LWIPRawListenImpl(
sa_family_t family,
struct tcp_pcb *pcb) : LWIPRawImpl(family, pcb) {}
556 LWIP_LOG(
"init(%p)", pcb_);
558 tcp_accept(pcb_, LWIPRawListenImpl::s_accept_fn);
559 tcp_err(pcb_, LWIPRawImpl::s_err_fn);
562 std::unique_ptr<Socket> accept(
struct sockaddr *addr,
socklen_t *addrlen)
override {
563 if (pcb_ ==
nullptr) {
567 if (accepted_socket_count_ == 0) {
572 std::unique_ptr<LWIPRawImpl> sock = std::move(accepted_sockets_[0]);
574 for (uint8_t i = 1; i < accepted_socket_count_; i++) {
575 accepted_sockets_[i - 1] = std::move(accepted_sockets_[i]);
577 accepted_socket_count_--;
578 LWIP_LOG(
"Connection accepted by application, queue size: %d", accepted_socket_count_);
579 if (addr !=
nullptr) {
580 sock->getpeername(addr, addrlen);
582 LWIP_LOG(
"accept(%p)", sock.get());
583 return std::unique_ptr<Socket>(std::move(sock));
586 int listen(
int backlog)
override {
587 if (pcb_ ==
nullptr) {
591 LWIP_LOG(
"tcp_listen_with_backlog(%p backlog=%d)", pcb_, backlog);
592 struct tcp_pcb *listen_pcb = tcp_listen_with_backlog(pcb_, backlog);
593 if (listen_pcb ==
nullptr) {
602 LWIP_LOG(
"tcp_arg(%p)", pcb_);
604 tcp_accept(pcb_, LWIPRawListenImpl::s_accept_fn);
609 err_t accept_fn(
struct tcp_pcb *newpcb, err_t err) {
610 LWIP_LOG(
"accept(newpcb=%p err=%d)", newpcb, err);
611 if (err != ERR_OK || newpcb ==
nullptr) {
619 if (accepted_socket_count_ >= MAX_ACCEPTED_SOCKETS) {
620 LWIP_LOG(
"Rejecting connection, queue full (%d)", accepted_socket_count_);
626 auto sock = make_unique<LWIPRawImpl>(family_, newpcb);
628 accepted_sockets_[accepted_socket_count_++] = std::move(sock);
629 LWIP_LOG(
"Accepted connection, queue size: %d", accepted_socket_count_);
633 static err_t s_accept_fn(
void *arg,
struct tcp_pcb *newpcb, err_t err) {
634 LWIPRawListenImpl *arg_this =
reinterpret_cast<LWIPRawListenImpl *
>(arg);
635 return arg_this->accept_fn(newpcb, err);
652 static constexpr size_t MAX_ACCEPTED_SOCKETS = 3;
653 std::array<std::unique_ptr<LWIPRawImpl>, MAX_ACCEPTED_SOCKETS> accepted_sockets_;
654 uint8_t accepted_socket_count_ = 0;
657std::unique_ptr<Socket>
socket(
int domain,
int type,
int protocol) {
658 auto *pcb = tcp_new();
663 auto *sock =
new LWIPRawListenImpl((
sa_family_t) domain, pcb);
665 return std::unique_ptr<Socket>{sock};
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.
Providing packet encoding functions for exchanging data with a remote host.
struct in6_addr sin6_addr