IPv6 support by MichaelDvP - #83

This commit is contained in:
proddy
2021-07-05 22:43:08 +02:00
parent 75795ab1e9
commit 05cd96f2be
4 changed files with 697 additions and 562 deletions

View File

@@ -36,7 +36,15 @@ extern "C"{
* */
typedef enum {
LWIP_TCP_SENT, LWIP_TCP_RECV, LWIP_TCP_FIN, LWIP_TCP_ERROR, LWIP_TCP_POLL, LWIP_TCP_CLEAR, LWIP_TCP_ACCEPT, LWIP_TCP_CONNECTED, LWIP_TCP_DNS
LWIP_TCP_SENT,
LWIP_TCP_RECV,
LWIP_TCP_FIN,
LWIP_TCP_ERROR,
LWIP_TCP_POLL,
LWIP_TCP_CLEAR,
LWIP_TCP_ACCEPT,
LWIP_TCP_CONNECTED,
LWIP_TCP_DNS
} lwip_event_t;
typedef struct {
@@ -563,8 +571,7 @@ AsyncClient::AsyncClient(tcp_pcb* pcb)
, _ack_timeout(ASYNC_MAX_ACK_TIME)
, _connect_port(0)
, prev(NULL)
, next(NULL)
{
, next(NULL) {
_pcb = pcb;
_closed_slot = -1;
if (_pcb) {
@@ -674,7 +681,7 @@ void AsyncClient::onPoll(AcConnectHandler cb, void* arg){
* Main Public Methods
* */
bool AsyncClient::connect(IPAddress ip, uint16_t port){
bool AsyncClient::_connect(ip_addr_t addr, uint16_t port) {
if (_pcb) {
log_w("already connected, state %d", _pcb->state);
return false;
@@ -684,11 +691,7 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){
return false;
}
ip_addr_t addr;
addr.type = IPADDR_TYPE_V4;
addr.u_addr.ip4.addr = ip;
tcp_pcb* pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
tcp_pcb * pcb = tcp_new_ip_type(addr.type);
if (!pcb) {
log_e("pcb == NULL");
return false;
@@ -699,11 +702,26 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){
tcp_recv(pcb, &_tcp_recv);
tcp_sent(pcb, &_tcp_sent);
tcp_poll(pcb, &_tcp_poll, 1);
//_tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected);
_tcp_connect(pcb, _closed_slot, &addr, port, (tcp_connected_fn)&_tcp_connected);
return true;
}
bool AsyncClient::connect(IPAddress ip, uint16_t port) {
ip_addr_t addr;
addr.type = IPADDR_TYPE_V4;
addr.u_addr.ip4.addr = ip;
return _connect(addr, port);
}
bool AsyncClient::connect(IPv6Address ip, uint16_t port) {
ip_addr_t addr;
addr.type = IPADDR_TYPE_V6;
memcpy(addr.u_addr.ip6.addr, static_cast<const uint32_t *>(ip), sizeof(uint32_t) * 4);
return _connect(addr, port);
}
bool AsyncClient::connect(const char * host, uint16_t port) {
ip_addr_t addr;
@@ -714,6 +732,9 @@ bool AsyncClient::connect(const char* host, uint16_t port){
err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this);
if (err == ERR_OK) {
if (addr.type == IPADDR_TYPE_V6) {
return connect(IPv6Address(addr.u_addr.ip6.addr), port);
}
return connect(IPAddress(addr.u_addr.ip4.addr), port);
} else if (err == ERR_INPROGRESS) {
_connect_port = port;
@@ -980,6 +1001,8 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){
void AsyncClient::_dns_found(struct ip_addr * ipaddr) {
if (ipaddr && ipaddr->u_addr.ip4.addr) {
connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port);
} else if (ipaddr && ipaddr->u_addr.ip6.addr) {
connect(IPv6Address(ipaddr->u_addr.ip6.addr), _connect_port);
} else {
if (_error_cb) {
_error_cb(_error_cb_arg, this, -55);
@@ -1071,6 +1094,15 @@ uint32_t AsyncClient::getRemoteAddress() {
return _pcb->remote_ip.u_addr.ip4.addr;
}
ip6_addr_t AsyncClient::getRemoteAddress6() {
if (!_pcb) {
ip6_addr_t nulladdr;
ip6_addr_set_zero(&nulladdr);
return nulladdr;
}
return _pcb->remote_ip.u_addr.ip6;
}
uint16_t AsyncClient::getRemotePort() {
if (!_pcb) {
return 0;
@@ -1085,6 +1117,15 @@ uint32_t AsyncClient::getLocalAddress() {
return _pcb->local_ip.u_addr.ip4.addr;
}
ip6_addr_t AsyncClient::getLocalAddress6() {
if (!_pcb) {
ip6_addr_t nulladdr;
ip6_addr_set_zero(&nulladdr);
return nulladdr;
}
return _pcb->local_ip.u_addr.ip6;
}
uint16_t AsyncClient::getLocalPort() {
if (!_pcb) {
return 0;
@@ -1096,6 +1137,10 @@ IPAddress AsyncClient::remoteIP() {
return IPAddress(getRemoteAddress());
}
IPv6Address AsyncClient::remoteIP6() {
return IPv6Address(getRemoteAddress6().addr);
}
uint16_t AsyncClient::remotePort() {
return getRemotePort();
}
@@ -1104,6 +1149,10 @@ IPAddress AsyncClient::localIP() {
return IPAddress(getLocalAddress());
}
IPv6Address AsyncClient::localIP6() {
return IPv6Address(getLocalAddress6().addr);
}
uint16_t AsyncClient::localPort() {
return getLocalPort();
}
@@ -1156,41 +1205,71 @@ bool AsyncClient::canSend(){
const char * AsyncClient::errorToString(int8_t error) {
switch (error) {
case ERR_OK: return "OK";
case ERR_MEM: return "Out of memory error";
case ERR_BUF: return "Buffer error";
case ERR_TIMEOUT: return "Timeout";
case ERR_RTE: return "Routing problem";
case ERR_INPROGRESS: return "Operation in progress";
case ERR_VAL: return "Illegal value";
case ERR_WOULDBLOCK: return "Operation would block";
case ERR_USE: return "Address in use";
case ERR_ALREADY: return "Already connected";
case ERR_CONN: return "Not connected";
case ERR_IF: return "Low-level netif error";
case ERR_ABRT: return "Connection aborted";
case ERR_RST: return "Connection reset";
case ERR_CLSD: return "Connection closed";
case ERR_ARG: return "Illegal argument";
case -55: return "DNS failed";
default: return "UNKNOWN";
case ERR_OK:
return "OK";
case ERR_MEM:
return "Out of memory error";
case ERR_BUF:
return "Buffer error";
case ERR_TIMEOUT:
return "Timeout";
case ERR_RTE:
return "Routing problem";
case ERR_INPROGRESS:
return "Operation in progress";
case ERR_VAL:
return "Illegal value";
case ERR_WOULDBLOCK:
return "Operation would block";
case ERR_USE:
return "Address in use";
case ERR_ALREADY:
return "Already connected";
case ERR_CONN:
return "Not connected";
case ERR_IF:
return "Low-level netif error";
case ERR_ABRT:
return "Connection aborted";
case ERR_RST:
return "Connection reset";
case ERR_CLSD:
return "Connection closed";
case ERR_ARG:
return "Illegal argument";
case -55:
return "DNS failed";
default:
return "UNKNOWN";
}
}
const char * AsyncClient::stateToString() {
switch (state()) {
case 0: return "Closed";
case 1: return "Listen";
case 2: return "SYN Sent";
case 3: return "SYN Received";
case 4: return "Established";
case 5: return "FIN Wait 1";
case 6: return "FIN Wait 2";
case 7: return "Close Wait";
case 8: return "Closing";
case 9: return "Last ACK";
case 10: return "Time Wait";
default: return "UNKNOWN";
case 0:
return "Closed";
case 1:
return "Listen";
case 2:
return "SYN Sent";
case 3:
return "SYN Received";
case 4:
return "Established";
case 5:
return "FIN Wait 1";
case 6:
return "FIN Wait 2";
case 7:
return "Close Wait";
case 8:
return "Closing";
case 9:
return "Last ACK";
case 10:
return "Time Wait";
default:
return "UNKNOWN";
}
}
@@ -1236,21 +1315,35 @@ int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){
AsyncServer::AsyncServer(IPAddress addr, uint16_t port)
: _port(port)
, _bind4(true)
, _addr(addr)
, _noDelay(false)
, _pcb(0)
, _connect_cb(0)
, _connect_cb_arg(0)
{}
, _connect_cb_arg(0) {
}
AsyncServer::AsyncServer(uint16_t port)
AsyncServer::AsyncServer(IPv6Address addr, uint16_t port)
: _port(port)
, _addr((uint32_t) IPADDR_ANY)
, _bind6(true)
, _addr6(addr)
, _noDelay(false)
, _pcb(0)
, _connect_cb(0)
, _connect_cb_arg(0)
{}
, _connect_cb_arg(0) {
}
AsyncServer::AsyncServer(uint16_t port)
: _port(port)
, _bind4(true)
, _bind6(true)
, _addr((uint32_t)IPADDR_ANY)
, _addr6()
, _noDelay(false)
, _pcb(0)
, _connect_cb(0)
, _connect_cb_arg(0) {
}
AsyncServer::~AsyncServer() {
end();
@@ -1270,16 +1363,26 @@ void AsyncServer::begin(){
log_e("failed to start task");
return;
}
int8_t err;
_pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
int8_t err, bind_type;
if (_bind4 && _bind6) {
bind_type = IPADDR_TYPE_ANY;
} else if (_bind6) {
bind_type = IPADDR_TYPE_V6;
} else {
bind_type = IPADDR_TYPE_V4;
}
_pcb = tcp_new_ip_type(bind_type);
if (!_pcb) {
log_e("_pcb == NULL");
return;
}
ip_addr_t local_addr;
local_addr.type = IPADDR_TYPE_V4;
local_addr.type = bind_type;
local_addr.u_addr.ip4.addr = (uint32_t)_addr;
memcpy(local_addr.u_addr.ip6.addr, static_cast<const uint32_t *>(_addr6), sizeof(uint32_t) * 4);
err = _tcp_bind(_pcb, &local_addr, _port);
if (err != ERR_OK) {

View File

@@ -23,11 +23,14 @@
#define ASYNCTCP_H_
#include "IPAddress.h"
#include "IPv6Address.h"
#include "sdkconfig.h"
#include <functional>
extern "C" {
#include "freertos/semphr.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
}
//If core is not defined, then we are running in Arduino or PIO
@@ -66,6 +69,7 @@ class AsyncClient {
return !(*this == other);
}
bool connect(IPAddress ip, uint16_t port);
bool connect(IPv6Address ip, uint16_t port);
bool connect(const char * host, uint16_t port);
void close(bool now = false);
void stop();
@@ -100,14 +104,18 @@ class AsyncClient {
bool getNoDelay();
uint32_t getRemoteAddress();
ip6_addr_t getRemoteAddress6();
uint16_t getRemotePort();
uint32_t getLocalAddress();
ip6_addr_t getLocalAddress6();
uint16_t getLocalPort();
//compatibility
IPAddress remoteIP();
IPv6Address remoteIP6();
uint16_t remotePort();
IPAddress localIP();
IPv6Address localIP6();
uint16_t localPort();
void onConnect(AcConnectHandler cb, void * arg = 0); //on successful connect
@@ -121,7 +129,9 @@ class AsyncClient {
void ackPacket(struct pbuf * pb); //ack pbuf from onPacket
size_t ack(size_t len); //ack data that you have not acked using the method below
void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData
void ackLater() {
_ack_pcb = false;
} //will not ack the current packet. Call from onData
const char * errorToString(int8_t error);
const char * stateToString();
@@ -137,9 +147,13 @@ class AsyncClient {
static void _s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg);
int8_t _recv(tcp_pcb * pcb, pbuf * pb, int8_t err);
tcp_pcb * pcb(){ return _pcb; }
tcp_pcb * pcb() {
return _pcb;
}
protected:
bool _connect(ip_addr_t addr, uint16_t port);
tcp_pcb * _pcb;
int8_t _closed_slot;
@@ -188,6 +202,7 @@ class AsyncClient {
class AsyncServer {
public:
AsyncServer(IPAddress addr, uint16_t port);
AsyncServer(IPv6Address addr, uint16_t port);
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void * arg);
@@ -203,7 +218,10 @@ class AsyncServer {
protected:
uint16_t _port;
bool _bind4 = false;
bool _bind6 = false;
IPAddress _addr;
IPv6Address _addr6;
bool _noDelay;
tcp_pcb * _pcb;
AcConnectHandler _connect_cb;

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.1.2b1"
#define EMSESP_APP_VERSION "3.1.2b2"

View File

@@ -73,6 +73,20 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
EMSESP::system_.ethernet_connected(false);
break;
case SYSTEM_EVENT_STA_CONNECTED:
WiFi.enableIpV6();
break;
case SYSTEM_EVENT_ETH_CONNECTED:
// ETH.enableIpV6(); // TODO this crashes
break;
case SYSTEM_EVENT_GOT_IP6:
#ifndef EMSESP_STANDALONE
EMSESP::logger().info(F("WiFi Connected with IP=%s, hostname=%s"), WiFi.localIPv6().toString().c_str(), WiFi.getHostname());
#endif
break;
default:
break;
}