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

File diff suppressed because it is too large Load Diff

View File

@@ -23,17 +23,20 @@
#define ASYNCTCP_H_ #define ASYNCTCP_H_
#include "IPAddress.h" #include "IPAddress.h"
#include "IPv6Address.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include <functional> #include <functional>
extern "C" { extern "C" {
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "lwip/pbuf.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 //If core is not defined, then we are running in Arduino or PIO
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE #ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core #define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core
#define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event #define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event
#endif #endif
class AsyncClient; class AsyncClient;
@@ -42,127 +45,138 @@ class AsyncClient;
#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given) #define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given)
#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react. #define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react.
typedef std::function<void(void*, AsyncClient*)> AcConnectHandler; typedef std::function<void(void *, AsyncClient *)> AcConnectHandler;
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)> AcAckHandler; typedef std::function<void(void *, AsyncClient *, size_t len, uint32_t time)> AcAckHandler;
typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler; typedef std::function<void(void *, AsyncClient *, int8_t error)> AcErrorHandler;
typedef std::function<void(void*, AsyncClient*, void *data, size_t len)> AcDataHandler; typedef std::function<void(void *, AsyncClient *, void * data, size_t len)> AcDataHandler;
typedef std::function<void(void*, AsyncClient*, struct pbuf *pb)> AcPacketHandler; typedef std::function<void(void *, AsyncClient *, struct pbuf * pb)> AcPacketHandler;
typedef std::function<void(void*, AsyncClient*, uint32_t time)> AcTimeoutHandler; typedef std::function<void(void *, AsyncClient *, uint32_t time)> AcTimeoutHandler;
struct tcp_pcb; struct tcp_pcb;
struct ip_addr; struct ip_addr;
class AsyncClient { class AsyncClient {
public: public:
AsyncClient(tcp_pcb* pcb = 0); AsyncClient(tcp_pcb * pcb = 0);
~AsyncClient(); ~AsyncClient();
AsyncClient & operator=(const AsyncClient &other); AsyncClient & operator=(const AsyncClient & other);
AsyncClient & operator+=(const AsyncClient &other); AsyncClient & operator+=(const AsyncClient & other);
bool operator==(const AsyncClient &other); bool operator==(const AsyncClient & other);
bool operator!=(const AsyncClient &other) { bool operator!=(const AsyncClient & other) {
return !(*this == other); return !(*this == other);
} }
bool connect(IPAddress ip, uint16_t port); bool connect(IPAddress ip, uint16_t port);
bool connect(const char* host, uint16_t port); bool connect(IPv6Address ip, uint16_t port);
void close(bool now = false); bool connect(const char * host, uint16_t port);
void stop(); void close(bool now = false);
void stop();
int8_t abort(); int8_t abort();
bool free(); bool free();
bool canSend();//ack is not pending bool canSend(); //ack is not pending
size_t space();//space available in the TCP window size_t space(); //space available in the TCP window
size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending size_t add(const char * data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //add for sending
bool send();//send all data added with the method above bool send(); //send all data added with the method above
//write equals add()+send() //write equals add()+send()
size_t write(const char* data); size_t write(const char * data);
size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true size_t write(const char * data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //only when canSend() == true
uint8_t state(); uint8_t state();
bool connecting(); bool connecting();
bool connected(); bool connected();
bool disconnecting(); bool disconnecting();
bool disconnected(); bool disconnected();
bool freeable();//disconnected or disconnecting bool freeable(); //disconnected or disconnecting
uint16_t getMss(); uint16_t getMss();
uint32_t getRxTimeout(); uint32_t getRxTimeout();
void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds void setRxTimeout(uint32_t timeout); //no RX data timeout for the connection in seconds
uint32_t getAckTimeout(); uint32_t getAckTimeout();
void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds void setAckTimeout(uint32_t timeout); //no ACK timeout for the last sent packet in milliseconds
void setNoDelay(bool nodelay); void setNoDelay(bool nodelay);
bool getNoDelay(); bool getNoDelay();
uint32_t getRemoteAddress(); uint32_t getRemoteAddress();
uint16_t getRemotePort(); ip6_addr_t getRemoteAddress6();
uint32_t getLocalAddress(); uint16_t getRemotePort();
uint16_t getLocalPort(); uint32_t getLocalAddress();
ip6_addr_t getLocalAddress6();
uint16_t getLocalPort();
//compatibility //compatibility
IPAddress remoteIP(); IPAddress remoteIP();
uint16_t remotePort(); IPv6Address remoteIP6();
IPAddress localIP(); uint16_t remotePort();
uint16_t localPort(); IPAddress localIP();
IPv6Address localIP6();
uint16_t localPort();
void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect void onConnect(AcConnectHandler cb, void * arg = 0); //on successful connect
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected void onDisconnect(AcConnectHandler cb, void * arg = 0); //disconnected
void onAck(AcAckHandler cb, void* arg = 0); //ack received void onAck(AcAckHandler cb, void * arg = 0); //ack received
void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error void onError(AcErrorHandler cb, void * arg = 0); //unsuccessful connect or error
void onData(AcDataHandler cb, void* arg = 0); //data received (called if onPacket is not used) void onData(AcDataHandler cb, void * arg = 0); //data received (called if onPacket is not used)
void onPacket(AcPacketHandler cb, void* arg = 0); //data received void onPacket(AcPacketHandler cb, void * arg = 0); //data received
void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout void onTimeout(AcTimeoutHandler cb, void * arg = 0); //ack timeout
void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected void onPoll(AcConnectHandler cb, void * arg = 0); //every 125ms when connected
void ackPacket(struct pbuf * pb);//ack pbuf from onPacket 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 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 * errorToString(int8_t error);
const char * stateToString(); const char * stateToString();
//Do not use any of the functions below! //Do not use any of the functions below!
static int8_t _s_poll(void *arg, struct tcp_pcb *tpcb); static int8_t _s_poll(void * arg, struct tcp_pcb * tpcb);
static int8_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, int8_t err); static int8_t _s_recv(void * arg, struct tcp_pcb * tpcb, struct pbuf * pb, int8_t err);
static int8_t _s_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); static int8_t _s_fin(void * arg, struct tcp_pcb * tpcb, int8_t err);
static int8_t _s_lwip_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); static int8_t _s_lwip_fin(void * arg, struct tcp_pcb * tpcb, int8_t err);
static void _s_error(void *arg, int8_t err); static void _s_error(void * arg, int8_t err);
static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); static int8_t _s_sent(void * arg, struct tcp_pcb * tpcb, uint16_t len);
static int8_t _s_connected(void* arg, void* tpcb, int8_t err); static int8_t _s_connected(void * arg, void * tpcb, int8_t err);
static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); 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); int8_t _recv(tcp_pcb * pcb, pbuf * pb, int8_t err);
tcp_pcb * pcb(){ return _pcb; } tcp_pcb * pcb() {
return _pcb;
}
protected: protected:
tcp_pcb* _pcb; bool _connect(ip_addr_t addr, uint16_t port);
int8_t _closed_slot;
tcp_pcb * _pcb;
int8_t _closed_slot;
AcConnectHandler _connect_cb; AcConnectHandler _connect_cb;
void* _connect_cb_arg; void * _connect_cb_arg;
AcConnectHandler _discard_cb; AcConnectHandler _discard_cb;
void* _discard_cb_arg; void * _discard_cb_arg;
AcAckHandler _sent_cb; AcAckHandler _sent_cb;
void* _sent_cb_arg; void * _sent_cb_arg;
AcErrorHandler _error_cb; AcErrorHandler _error_cb;
void* _error_cb_arg; void * _error_cb_arg;
AcDataHandler _recv_cb; AcDataHandler _recv_cb;
void* _recv_cb_arg; void * _recv_cb_arg;
AcPacketHandler _pb_cb; AcPacketHandler _pb_cb;
void* _pb_cb_arg; void * _pb_cb_arg;
AcTimeoutHandler _timeout_cb; AcTimeoutHandler _timeout_cb;
void* _timeout_cb_arg; void * _timeout_cb_arg;
AcConnectHandler _poll_cb; AcConnectHandler _poll_cb;
void* _poll_cb_arg; void * _poll_cb_arg;
bool _pcb_busy; bool _pcb_busy;
uint32_t _pcb_sent_at; uint32_t _pcb_sent_at;
bool _ack_pcb; bool _ack_pcb;
uint32_t _rx_ack_len; uint32_t _rx_ack_len;
uint32_t _rx_last_packet; uint32_t _rx_last_packet;
uint32_t _rx_since_timeout; uint32_t _rx_since_timeout;
@@ -170,47 +184,51 @@ class AsyncClient {
uint16_t _connect_port; uint16_t _connect_port;
int8_t _close(); int8_t _close();
void _free_closed_slot(); void _free_closed_slot();
void _allocate_closed_slot(); void _allocate_closed_slot();
int8_t _connected(void* pcb, int8_t err); int8_t _connected(void * pcb, int8_t err);
void _error(int8_t err); void _error(int8_t err);
int8_t _poll(tcp_pcb* pcb); int8_t _poll(tcp_pcb * pcb);
int8_t _sent(tcp_pcb* pcb, uint16_t len); int8_t _sent(tcp_pcb * pcb, uint16_t len);
int8_t _fin(tcp_pcb* pcb, int8_t err); int8_t _fin(tcp_pcb * pcb, int8_t err);
int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); int8_t _lwip_fin(tcp_pcb * pcb, int8_t err);
void _dns_found(struct ip_addr *ipaddr); void _dns_found(struct ip_addr * ipaddr);
public: public:
AsyncClient* prev; AsyncClient * prev;
AsyncClient* next; AsyncClient * next;
}; };
class AsyncServer { class AsyncServer {
public: public:
AsyncServer(IPAddress addr, uint16_t port); AsyncServer(IPAddress addr, uint16_t port);
AsyncServer(IPv6Address addr, uint16_t port);
AsyncServer(uint16_t port); AsyncServer(uint16_t port);
~AsyncServer(); ~AsyncServer();
void onClient(AcConnectHandler cb, void* arg); void onClient(AcConnectHandler cb, void * arg);
void begin(); void begin();
void end(); void end();
void setNoDelay(bool nodelay); void setNoDelay(bool nodelay);
bool getNoDelay(); bool getNoDelay();
uint8_t status(); uint8_t status();
//Do not use any of the functions below! //Do not use any of the functions below!
static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); static int8_t _s_accept(void * arg, tcp_pcb * newpcb, int8_t err);
static int8_t _s_accepted(void *arg, AsyncClient* client); static int8_t _s_accepted(void * arg, AsyncClient * client);
protected: protected:
uint16_t _port; uint16_t _port;
IPAddress _addr; bool _bind4 = false;
bool _noDelay; bool _bind6 = false;
tcp_pcb* _pcb; IPAddress _addr;
IPv6Address _addr6;
bool _noDelay;
tcp_pcb * _pcb;
AcConnectHandler _connect_cb; AcConnectHandler _connect_cb;
void* _connect_cb_arg; void * _connect_cb_arg;
int8_t _accept(tcp_pcb* newpcb, int8_t err); int8_t _accept(tcp_pcb * newpcb, int8_t err);
int8_t _accepted(AsyncClient* client); int8_t _accepted(AsyncClient * client);
}; };

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); EMSESP::system_.ethernet_connected(false);
break; 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: default:
break; break;
} }