mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
IPv6 support by MichaelDvP - #83
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.1.2b1"
|
||||
#define EMSESP_APP_VERSION "3.1.2b2"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user