Initial commit

This commit is contained in:
Alex Villacís Lasso
2020-12-19 17:28:53 -05:00
commit 5f24debb27
2 changed files with 1112 additions and 0 deletions

204
src/AsyncTCP.h Normal file
View File

@@ -0,0 +1,204 @@
#ifndef ASYNCTCP_H_
#define ASYNCTCP_H_
#include "IPAddress.h"
#include "sdkconfig.h"
#include <functional>
#include <deque>
#include <list>
extern "C" {
#include "lwip/err.h"
#include "lwip/sockets.h"
}
//If core is not defined, then we are running in Arduino or PIO
#ifndef CONFIG_ASYNC_TCP_RUNNING_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
#endif
class AsyncClient;
#define ASYNC_MAX_ACK_TIME 5000
#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.
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*, int8_t error)> AcErrorHandler;
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*, uint32_t time)> AcTimeoutHandler;
class AsyncSocketBase
{
private:
static std::list<AsyncSocketBase *> & _getSocketBaseList(void);
protected:
int _socket = -1;
bool _selected = false;
bool _isdnsfinished = false;
uint32_t _sock_lastactivity = 0;
virtual void _sockIsReadable(void) {} // Action to take on readable socket
virtual bool _sockIsWriteable(void) { return false; } // Action to take on writable socket
virtual void _sockPoll(void) {} // Action to take on idle socket activity poll
virtual void _sockDelayedConnect(void) {} // Action to take on DNS-resolve finished
public:
AsyncSocketBase(void);
virtual ~AsyncSocketBase();
friend void _asynctcpsock_task(void *);
};
class AsyncClient : public AsyncSocketBase
{
public:
AsyncClient(int sockfd = -1);
~AsyncClient();
bool connect(IPAddress ip, uint16_t port);
bool connect(const char* host, uint16_t port);
void close(bool now = false);
int8_t abort();
bool free();
bool canSend() { return space() > 0; }
size_t space();
size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending
bool send();
//write equals add()+send()
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
uint8_t state() { return _conn_state; }
bool connected();
bool freeable();//disconnected or disconnecting
uint32_t getAckTimeout();
void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds
uint32_t getRxTimeout();
void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds
void setNoDelay(bool nodelay);
bool getNoDelay();
uint32_t getRemoteAddress();
uint16_t getRemotePort();
uint32_t getLocalAddress();
uint16_t getLocalPort();
//compatibility
IPAddress remoteIP();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected
void onAck(AcAckHandler cb, void* arg = 0); //ack received
void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error
void onData(AcDataHandler cb, void* arg = 0); //data received
void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout
void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected
// The following functions are just for API compatibility and do nothing
size_t ack(size_t len) { return len; }
void ackLater() {}
const char * errorToString(int8_t error);
// const char * stateToString();
private:
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
AcConnectHandler _discard_cb;
void* _discard_cb_arg;
AcAckHandler _sent_cb;
void* _sent_cb_arg;
AcErrorHandler _error_cb;
void* _error_cb_arg;
AcDataHandler _recv_cb;
void* _recv_cb_arg;
AcTimeoutHandler _timeout_cb;
void* _timeout_cb_arg;
AcConnectHandler _poll_cb;
void* _poll_cb_arg;
// Simulation of connection state
uint8_t _conn_state;
uint32_t _rx_last_packet;
uint32_t _rx_since_timeout;
uint32_t _ack_timeout;
// Used on asynchronous DNS resolving scenario - I do not want to connect()
// from the LWIP thread itself.
struct ip_addr _connect_addr;
uint16_t _connect_port = 0;
//const char * _connect_dnsname = NULL;
// The following private struct represents a buffer enqueued with the add()
// method. Each of these buffers are flushed whenever the socket becomes
// writable
typedef struct {
uint8_t * data; // Pointer to data queued for write
uint32_t length; // Length of data queued for write
uint32_t written; // Length of data written to socket so far
uint32_t queued_at;// Timestamp at which this data buffer was queued
bool owned; // If true, we malloc'ed the data and should be freed after completely written.
// If false, app owns the memory and should ensure it remains valid until acked
} queued_writebuf;
// Queue of buffers to write to socket
std::deque<queued_writebuf> _writeQueue;
bool _ack_timeout_signaled = false;
// Remaining space willing to queue for writing
uint32_t _writeSpaceRemaining;
void _error(int8_t err);
void _close(void);
bool _sockIsWriteable(void);
void _sockIsReadable(void);
void _sockPoll(void);
void _sockDelayedConnect(void);
void _clearWriteQueue(void);
friend void _tcpsock_dns_found(const char * name, struct ip_addr * ipaddr, void * arg);
};
class AsyncServer : public AsyncSocketBase
{
public:
AsyncServer(IPAddress addr, uint16_t port);
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void* arg);
void begin();
void end();
void setNoDelay(bool nodelay) { _noDelay = nodelay; }
bool getNoDelay() { return _noDelay; }
uint8_t status();
protected:
uint16_t _port;
IPAddress _addr;
bool _noDelay;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
// Listening socket is readable on incoming connection
void _sockIsReadable(void);
};
#endif /* ASYNCTCP_H_ */