diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index d3d6b0d8..dcdc39d0 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -16,6 +16,21 @@ extern "C" { // System // ----------------------------------------------------------------------------- +#define LWIP_INTERNAL +#include +#undef LWIP_INTERNAL + +extern "C" { + #include + #include + #include + #include // ip_addr_t + #include // ERR_x + #include // dns_gethostbyname + #include // ip4/ip6 helpers + #include // LWIP_VERSION_MAJOR +} + uint32_t systemResetReason(); uint8_t systemStabilityCounter(); void systemStabilityCounter(uint8_t); diff --git a/code/espurna/terminal.ino b/code/espurna/terminal.ino index bf165414..d46409c9 100644 --- a/code/espurna/terminal.ino +++ b/code/espurna/terminal.ino @@ -79,6 +79,91 @@ void _terminalKeysCommand() { } +#if LWIP_VERSION_MAJOR != 1 + +// not yet CONNECTING or LISTENING +extern struct tcp_pcb *tcp_bound_pcbs; +// accepting or sending data +extern struct tcp_pcb *tcp_active_pcbs; +// // TIME-WAIT status +extern struct tcp_pcb *tcp_tw_pcbs; + +String _terminalPcbStateToString(const unsigned char state) { + switch (state) { + case 0: return F("CLOSED"); + case 1: return F("LISTEN"); + case 2: return F("SYN_SENT"); + case 3: return F("SYN_RCVD"); + case 4: return F("ESTABLISHED"); + case 5: return F("FIN_WAIT_1"); + case 6: return F("FIN_WAIT_2"); + case 7: return F("CLOSE_WAIT"); + case 8: return F("CLOSING"); + case 9: return F("LAST_ACK"); + case 10: return F("TIME_WAIT"); + default: return String(int(state)); + }; +} + +void _terminalPrintTcpPcb(tcp_pcb* pcb) { + + char remote_ip[32] = {0}; + char local_ip[32] = {0}; + + inet_ntoa_r((pcb->local_ip), local_ip, sizeof(local_ip)); + inet_ntoa_r((pcb->remote_ip), remote_ip, sizeof(remote_ip)); + + DEBUG_MSG_P(PSTR("state=%s local=%s:%u remote=%s:%u snd_queuelen=%u lastack=%u send_wnd=%u rto=%u\n"), + _terminalPcbStateToString(pcb->state).c_str(), + local_ip, pcb->local_port, + remote_ip, pcb->remote_port, + pcb->snd_queuelen, pcb->lastack, + pcb->snd_wnd, pcb->rto + ); + +} + +void _terminalPrintTcpPcbs() { + + tcp_pcb *pcb; + //DEBUG_MSG_P(PSTR("Active PCB states:\n")); + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + _terminalPrintTcpPcb(pcb); + } + //DEBUG_MSG_P(PSTR("TIME-WAIT PCB states:\n")); + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + _terminalPrintTcpPcb(pcb); + } + //DEBUG_MSG_P(PSTR("BOUND PCB states:\n")); + for (pcb = tcp_bound_pcbs; pcb != NULL; pcb = pcb->next) { + _terminalPrintTcpPcb(pcb); + } + +} + +void _terminalPrintDnsResult(const char* name, const ip_addr_t* address) { + // TODO fix asynctcp building with lwip-ipv6 + /* + #if LWIP_IPV6 + if (IP_IS_V6(address)) { + DEBUG_MSG_P(PSTR("[DNS] %s has IPV6 address %s\n"), name, ip6addr_ntoa(ip_2_ip6(address))); + } + #endif + */ + DEBUG_MSG_P(PSTR("[DNS] %s has address %s\n"), name, ipaddr_ntoa(address)); +} + +void _terminalDnsFound(const char* name, const ip_addr_t* result, void*) { + if (!result) { + DEBUG_MSG_P(PSTR("[DNS] %s not found\n"), name); + return; + } + + _terminalPrintDnsResult(name, result); +} + +#endif // LWIP_VERSION_MAJOR != 1 + void _terminalInitCommand() { terminalRegisterCommand(F("COMMANDS"), [](Embedis* e) { @@ -229,6 +314,32 @@ void _terminalInitCommand() { } }); #endif + + #if LWIP_VERSION_MAJOR != 1 + terminalRegisterCommand(F("HOST"), [](Embedis* e) { + if (e->argc != 2) { + terminalError(F("HOST [hostname]")); + return; + } + + ip_addr_t result; + auto error = dns_gethostbyname(e->argv[1], &result, _terminalDnsFound, nullptr); + if (error == ERR_OK) { + _terminalPrintDnsResult(e->argv[1], &result); + terminalOK(); + return; + } else if (error != ERR_INPROGRESS) { + DEBUG_MSG_P(PSTR("[DNS] dns_gethostbyname error: %s\n"), lwip_strerr(error)); + return; + } + + }); + + terminalRegisterCommand(F("NETSTAT"), [](Embedis*) { + _terminalPrintTcpPcbs(); + }); + + #endif // LWIP_VERSION_MAJOR != 1 }