mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 09:49:32 +02:00
Replace AsyncTCP with AsyncTCPsock library
This commit is contained in:
parent
1613b52d5f
commit
73eccb64ec
19 changed files with 2106 additions and 1658 deletions
|
@ -6,8 +6,8 @@
|
|||
#include "../../include.h"
|
||||
#include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h"
|
||||
#include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h"
|
||||
#include "../../lib/mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||
#include "../../lib/mathieucarbou-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
|
||||
#include "../../lib/me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
extern const char* version_number; // The current software version, shown on webserver
|
||||
|
|
|
@ -64,7 +64,7 @@ _____ _ _ ___ _____ _
|
|||
#include "Update.h"
|
||||
#include "StreamString.h"
|
||||
#if ELEGANTOTA_USE_ASYNC_WEBSERVER == 1
|
||||
#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||
#include "../../mathieucarbou-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
|
||||
#define ELEGANTOTA_WEBSERVER AsyncWebServer
|
||||
#else
|
||||
|
|
22
Software/src/lib/mathieucarbou-AsyncTCPSock/library.json
Normal file
22
Software/src/lib/mathieucarbou-AsyncTCPSock/library.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name":"AsyncTCPSock",
|
||||
"description":"Reimplementation of an Asynchronous TCP Library for ESP32, using BSD Sockets",
|
||||
"keywords":"async,tcp",
|
||||
"authors":
|
||||
{
|
||||
"name": "Alex Villacís Lasso",
|
||||
"maintainer": true
|
||||
},
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/yubox-node-org/AsyncTCPSock.git"
|
||||
},
|
||||
"version": "1.0.2-dev",
|
||||
"license": "LGPL-3.0",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "espressif32",
|
||||
"build": {
|
||||
"libCompatMode": 2
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
name=AsyncTCPSock
|
||||
version=1.0.2-dev
|
||||
author=avillacis
|
||||
maintainer=avillacis
|
||||
sentence=Reimplemented Async TCP Library for ESP32 using BSD Sockets
|
||||
paragraph=This is a reimplementation of AsyncTCP (Async TCP Library for ESP32) by Me No Dev, using high-level BSD Sockets instead of the low-level packet API and a message queue.
|
||||
category=Other
|
||||
url=https://github.com/yubox-node-org/AsyncTCPSock
|
||||
architectures=*
|
1301
Software/src/lib/mathieucarbou-AsyncTCPSock/src/AsyncTCP.cpp
Normal file
1301
Software/src/lib/mathieucarbou-AsyncTCPSock/src/AsyncTCP.cpp
Normal file
File diff suppressed because it is too large
Load diff
321
Software/src/lib/mathieucarbou-AsyncTCPSock/src/AsyncTCP.h
Normal file
321
Software/src/lib/mathieucarbou-AsyncTCPSock/src/AsyncTCP.h
Normal file
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
Reimplementation of an asynchronous TCP library for Espressif MCUs, using
|
||||
BSD sockets.
|
||||
|
||||
Copyright (c) 2020 Alex Villacís Lasso.
|
||||
|
||||
Original AsyncTCP API Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ASYNCTCP_H_
|
||||
#define ASYNCTCP_H_
|
||||
|
||||
#include "../../../system_settings.h"
|
||||
#include "../../../devboard/hal/hal.h"
|
||||
|
||||
#include "IPAddress.h"
|
||||
#include "sdkconfig.h"
|
||||
#include <functional>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
#include <ssl_client.h>
|
||||
#include "AsyncTCP_TLS_Context.h"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
}
|
||||
|
||||
#define ASYNCTCP_VERSION "1.0.2-dev"
|
||||
#define ASYNCTCP_VERSION_MAJOR 1
|
||||
#define ASYNCTCP_VERSION_MINOR 2
|
||||
#define ASYNCTCP_VERSION_REVISION 2
|
||||
#define ASYNCTCP_FORK_mathieucarbou
|
||||
|
||||
//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 WIFI_CORE
|
||||
#define CONFIG_ASYNC_TCP_USE_WDT 0 //if enabled, adds between 33us and 200us per event
|
||||
#endif
|
||||
#ifndef CONFIG_ASYNC_TCP_STACK_SIZE
|
||||
#define CONFIG_ASYNC_TCP_STACK_SIZE 16384 // 8192 * 2
|
||||
#endif
|
||||
#ifndef CONFIG_ASYNC_TCP_STACK
|
||||
#define CONFIG_ASYNC_TCP_STACK CONFIG_ASYNC_TCP_STACK_SIZE
|
||||
#endif
|
||||
#ifndef CONFIG_ASYNC_TCP_PRIORITY
|
||||
#define CONFIG_ASYNC_TCP_PRIORITY 3
|
||||
#endif
|
||||
#ifndef CONFIG_ASYNC_TCP_TASK_PRIORITY
|
||||
#define CONFIG_ASYNC_TCP_TASK_PRIORITY TASK_CONNECTIVITY_PRIO
|
||||
#endif
|
||||
#ifndef CONFIG_ASYNC_TCP_TASK_NAME
|
||||
#define CONFIG_ASYNC_TCP_TASK_NAME "asyncTcpSock"
|
||||
#endif
|
||||
|
||||
class AsyncClient;
|
||||
|
||||
#ifndef CONFIG_ASYNC_TCP_MAX_ACK_TIME
|
||||
#define CONFIG_ASYNC_TCP_MAX_ACK_TIME 5000
|
||||
#endif
|
||||
#ifndef ASYNC_MAX_ACK_TIME
|
||||
#define ASYNC_MAX_ACK_TIME CONFIG_ASYNC_TCP_MAX_ACK_TIME
|
||||
#endif
|
||||
#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 SSL_HANDSHAKE_TIMEOUT 5000 // timeout to complete SSL handshake
|
||||
|
||||
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
|
||||
|
||||
virtual bool _pendingWrite(void) { return false; } // Test if there is data pending to be written
|
||||
virtual bool _isServer(void) { return false; } // Will a read from this socket result in one more client?
|
||||
|
||||
public:
|
||||
AsyncSocketBase(void);
|
||||
virtual ~AsyncSocketBase();
|
||||
|
||||
friend void _asynctcpsock_task(void *);
|
||||
};
|
||||
|
||||
class AsyncClient : public AsyncSocketBase
|
||||
{
|
||||
public:
|
||||
AsyncClient(int sockfd = -1);
|
||||
~AsyncClient();
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
bool connect(IPAddress ip, uint16_t port, bool secure = false);
|
||||
bool connect(const char* host, uint16_t port, bool secure = false);
|
||||
void setRootCa(const char* rootca, const size_t len);
|
||||
void setClientCert(const char* cli_cert, const size_t len);
|
||||
void setClientKey(const char* cli_key, const size_t len);
|
||||
void setPsk(const char* psk_ident, const char* psk);
|
||||
#else
|
||||
bool connect(IPAddress ip, uint16_t port);
|
||||
bool connect(const char* host, uint16_t port);
|
||||
#endif // ASYNC_TCP_SSL_ENABLED
|
||||
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();
|
||||
|
||||
protected:
|
||||
bool _sockIsWriteable(void);
|
||||
void _sockIsReadable(void);
|
||||
void _sockPoll(void);
|
||||
void _sockDelayedConnect(void);
|
||||
bool _pendingWrite(void);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
size_t _root_ca_len;
|
||||
char* _root_ca;
|
||||
size_t _cli_cert_len;
|
||||
char* _cli_cert;
|
||||
size_t _cli_key_len;
|
||||
char* _cli_key;
|
||||
bool _secure;
|
||||
bool _handshake_done;
|
||||
const char* _psk_ident;
|
||||
const char* _psk;
|
||||
|
||||
String _hostname;
|
||||
AsyncTCP_TLS_Context * _sslctx;
|
||||
#endif // ASYNC_TCP_SSL_ENABLED
|
||||
|
||||
// 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
|
||||
uint32_t written_at; // Timestamp at which this data buffer was completely written
|
||||
int write_errno; // If != 0, errno value while writing this buffer
|
||||
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;
|
||||
|
||||
// Internal struct used to implement sent buffer notification
|
||||
typedef struct {
|
||||
uint32_t length;
|
||||
uint32_t delay;
|
||||
} notify_writebuf;
|
||||
|
||||
// Queue of buffers to write to socket
|
||||
SemaphoreHandle_t _write_mutex;
|
||||
std::deque<queued_writebuf> _writeQueue;
|
||||
bool _ack_timeout_signaled = false;
|
||||
|
||||
// Remaining space willing to queue for writing
|
||||
uint32_t _writeSpaceRemaining;
|
||||
|
||||
// Simulation of connection state
|
||||
uint8_t _conn_state;
|
||||
|
||||
void _error(int8_t err);
|
||||
void _close(void);
|
||||
void _removeAllCallbacks(void);
|
||||
bool _flushWriteQueue(void);
|
||||
void _clearWriteQueue(void);
|
||||
void _collectNotifyWrittenBuffers(std::deque<notify_writebuf> &, int &);
|
||||
void _notifyWrittenBuffers(std::deque<notify_writebuf> &, int);
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
int _runSSLHandshakeLoop(void);
|
||||
#endif
|
||||
|
||||
friend void _tcpsock_dns_found(const char * name, struct ip_addr * ipaddr, void * arg);
|
||||
};
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
typedef std::function<int(void* arg, const char *filename, uint8_t **buf)> AcSSlFileHandler;
|
||||
#endif
|
||||
|
||||
class AsyncServer : public AsyncSocketBase
|
||||
{
|
||||
public:
|
||||
AsyncServer(IPAddress addr, uint16_t port);
|
||||
AsyncServer(uint16_t port);
|
||||
~AsyncServer();
|
||||
void onClient(AcConnectHandler cb, void* arg);
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
// Dummy, so it compiles with ESP Async WebServer library enabled.
|
||||
void onSslFileRequest(AcSSlFileHandler cb, void* arg) {};
|
||||
void beginSecure(const char *cert, const char *private_key_file, const char *password) {};
|
||||
#endif
|
||||
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);
|
||||
|
||||
// Mark this class as a server
|
||||
bool _isServer(void) { return true; }
|
||||
};
|
||||
|
||||
|
||||
#endif /* ASYNCTCP_H_ */
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef ASYNCTCP_SSL_H_
|
||||
#define ASYNCTCP_SSL_H_
|
||||
|
||||
#include "AsyncTCP_SSL.hpp"
|
||||
|
||||
#endif /* ASYNCTCP_SSL_H_ */
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef ASYNCTCP_SSL_HPP
|
||||
#define ASYNCTCP_SSL_HPP
|
||||
|
||||
#ifdef ASYNC_TCP_SSL_ENABLED
|
||||
|
||||
#include <AsyncTCP.h>
|
||||
|
||||
#define AsyncSSLClient AsyncClient
|
||||
#define AsyncSSLServer AsyncServer
|
||||
|
||||
#define ASYNC_TCP_SSL_VERSION "AsyncTCPSock SSL shim v0.0.1"
|
||||
|
||||
#else
|
||||
#error Compatibility shim requires ASYNC_TCP_SSL_ENABLED to be defined!
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,346 @@
|
|||
#include <Arduino.h>
|
||||
#include <esp32-hal-log.h>
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/sys.h>
|
||||
#include <lwip/netdb.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/oid.h>
|
||||
|
||||
|
||||
#include "AsyncTCP_TLS_Context.h"
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
#if !defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) && !defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
|
||||
# warning "Please configure IDF framework to include mbedTLS -> Enable pre-shared-key ciphersuites and activate at least one cipher"
|
||||
#else
|
||||
|
||||
static const char *pers = "esp32-tls";
|
||||
|
||||
static int _handle_error(int err, const char * function, int line)
|
||||
{
|
||||
if(err == -30848){
|
||||
return err;
|
||||
}
|
||||
#ifdef MBEDTLS_ERROR_C
|
||||
char error_buf[100];
|
||||
mbedtls_strerror(err, error_buf, 100);
|
||||
log_e("[%s():%d]: (%d) %s", function, line, err, error_buf);
|
||||
#else
|
||||
log_e("[%s():%d]: code %d", function, line, err);
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
#define handle_error(e) _handle_error(e, __FUNCTION__, __LINE__)
|
||||
|
||||
AsyncTCP_TLS_Context::AsyncTCP_TLS_Context(void)
|
||||
{
|
||||
mbedtls_ssl_init(&ssl_ctx);
|
||||
mbedtls_ssl_config_init(&ssl_conf);
|
||||
mbedtls_ctr_drbg_init(&drbg_ctx);
|
||||
_socket = -1;
|
||||
_have_ca_cert = false;
|
||||
_have_client_cert = false;
|
||||
_have_client_key = false;
|
||||
handshake_timeout = 120000;
|
||||
}
|
||||
|
||||
int AsyncTCP_TLS_Context::startSSLClientInsecure(int sck, const char * host_or_ip)
|
||||
{
|
||||
return _startSSLClient(sck, host_or_ip,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
NULL, NULL,
|
||||
true);
|
||||
}
|
||||
|
||||
int AsyncTCP_TLS_Context::startSSLClient(int sck, const char * host_or_ip,
|
||||
const char *pskIdent, const char *psKey)
|
||||
{
|
||||
return _startSSLClient(sck, host_or_ip,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
pskIdent, psKey,
|
||||
false);
|
||||
}
|
||||
|
||||
int AsyncTCP_TLS_Context::startSSLClient(int sck, const char * host_or_ip,
|
||||
const char *rootCABuff,
|
||||
const char *cli_cert,
|
||||
const char *cli_key)
|
||||
{
|
||||
return startSSLClient(sck, host_or_ip,
|
||||
(const unsigned char *)rootCABuff, (rootCABuff != NULL) ? strlen(rootCABuff) + 1 : 0,
|
||||
(const unsigned char *)cli_cert, (cli_cert != NULL) ? strlen(cli_cert) + 1 : 0,
|
||||
(const unsigned char *)cli_key, (cli_key != NULL) ? strlen(cli_key) + 1 : 0);
|
||||
}
|
||||
|
||||
int AsyncTCP_TLS_Context::startSSLClient(int sck, const char * host_or_ip,
|
||||
const unsigned char *rootCABuff, const size_t rootCABuff_len,
|
||||
const unsigned char *cli_cert, const size_t cli_cert_len,
|
||||
const unsigned char *cli_key, const size_t cli_key_len)
|
||||
{
|
||||
return _startSSLClient(sck, host_or_ip,
|
||||
rootCABuff, rootCABuff_len,
|
||||
cli_cert, cli_cert_len,
|
||||
cli_key, cli_key_len,
|
||||
NULL, NULL,
|
||||
false);
|
||||
}
|
||||
|
||||
int AsyncTCP_TLS_Context::_startSSLClient(int sck, const char * host_or_ip,
|
||||
const unsigned char *rootCABuff, const size_t rootCABuff_len,
|
||||
const unsigned char *cli_cert, const size_t cli_cert_len,
|
||||
const unsigned char *cli_key, const size_t cli_key_len,
|
||||
const char *pskIdent, const char *psKey,
|
||||
bool insecure)
|
||||
{
|
||||
int ret;
|
||||
int enable = 1;
|
||||
|
||||
// The insecure flag will skip server certificate validation. Otherwise some
|
||||
// certificate is required.
|
||||
if (rootCABuff == NULL && pskIdent == NULL && psKey == NULL && !insecure) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define ROE(x,msg) { if (((x)<0)) { log_e("LWIP Socket config of " msg " failed."); return -1; }}
|
||||
// ROE(lwip_setsockopt(sck, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)),"SO_RCVTIMEO");
|
||||
// ROE(lwip_setsockopt(sck, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)),"SO_SNDTIMEO");
|
||||
|
||||
ROE(lwip_setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)),"TCP_NODELAY");
|
||||
ROE(lwip_setsockopt(sck, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),"SO_KEEPALIVE");
|
||||
|
||||
log_v("Seeding the random number generator");
|
||||
mbedtls_entropy_init(&entropy_ctx);
|
||||
|
||||
ret = mbedtls_ctr_drbg_seed(&drbg_ctx, mbedtls_entropy_func,
|
||||
&entropy_ctx, (const unsigned char *) pers, strlen(pers));
|
||||
if (ret < 0) {
|
||||
return handle_error(ret);
|
||||
}
|
||||
|
||||
log_v("Setting up the SSL/TLS structure...");
|
||||
|
||||
if ((ret = mbedtls_ssl_config_defaults(&ssl_conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
return handle_error(ret);
|
||||
}
|
||||
|
||||
if (insecure) {
|
||||
mbedtls_ssl_conf_authmode(&ssl_conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
log_i("WARNING: Skipping SSL Verification. INSECURE!");
|
||||
} else if (rootCABuff != NULL) {
|
||||
log_v("Loading CA cert");
|
||||
mbedtls_x509_crt_init(&ca_cert);
|
||||
mbedtls_ssl_conf_authmode(&ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
ret = mbedtls_x509_crt_parse(&ca_cert, rootCABuff, rootCABuff_len);
|
||||
_have_ca_cert = true;
|
||||
mbedtls_ssl_conf_ca_chain(&ssl_conf, &ca_cert, NULL);
|
||||
if (ret < 0) {
|
||||
// free the ca_cert in the case parse failed, otherwise, the old ca_cert still in the heap memory, that lead to "out of memory" crash.
|
||||
_deleteHandshakeCerts();
|
||||
return handle_error(ret);
|
||||
}
|
||||
} else if (pskIdent != NULL && psKey != NULL) {
|
||||
log_v("Setting up PSK");
|
||||
// convert PSK from hex to binary
|
||||
if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2*MBEDTLS_PSK_MAX_LEN) {
|
||||
log_e("pre-shared key not valid hex or too long");
|
||||
return -1;
|
||||
}
|
||||
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
|
||||
size_t psk_len = strlen(psKey)/2;
|
||||
for (int j=0; j<strlen(psKey); j+= 2) {
|
||||
char c = psKey[j];
|
||||
if (c >= '0' && c <= '9') c -= '0';
|
||||
else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
|
||||
else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
|
||||
else return -1;
|
||||
psk[j/2] = c<<4;
|
||||
c = psKey[j+1];
|
||||
if (c >= '0' && c <= '9') c -= '0';
|
||||
else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
|
||||
else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
|
||||
else return -1;
|
||||
psk[j/2] |= c;
|
||||
}
|
||||
// set mbedtls config
|
||||
ret = mbedtls_ssl_conf_psk(&ssl_conf, psk, psk_len,
|
||||
(const unsigned char *)pskIdent, strlen(pskIdent));
|
||||
if (ret != 0) {
|
||||
log_e("mbedtls_ssl_conf_psk returned %d", ret);
|
||||
return handle_error(ret);
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!insecure && cli_cert != NULL && cli_key != NULL) {
|
||||
mbedtls_x509_crt_init(&client_cert);
|
||||
mbedtls_pk_init(&client_key);
|
||||
|
||||
log_v("Loading CRT cert");
|
||||
|
||||
ret = mbedtls_x509_crt_parse(&client_cert, cli_cert, cli_cert_len);
|
||||
_have_client_cert = true;
|
||||
if (ret < 0) {
|
||||
// free the client_cert in the case parse failed, otherwise, the old client_cert still in the heap memory, that lead to "out of memory" crash.
|
||||
_deleteHandshakeCerts();
|
||||
return handle_error(ret);
|
||||
}
|
||||
|
||||
log_v("Loading private key");
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x03000000
|
||||
ret = mbedtls_pk_parse_key(&client_key, cli_key, cli_key_len, NULL, 0);
|
||||
#else
|
||||
ret = mbedtls_pk_parse_key(&client_key, cli_key, cli_key_len, NULL, 0, mbedtls_ctr_drbg_random, &drbg_ctx);
|
||||
#endif
|
||||
_have_client_key = true;
|
||||
|
||||
if (ret != 0) {
|
||||
_deleteHandshakeCerts();
|
||||
return handle_error(ret);
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_own_cert(&ssl_conf, &client_cert, &client_key);
|
||||
}
|
||||
|
||||
log_v("Setting hostname for TLS session...");
|
||||
|
||||
// Hostname set here should match CN in server certificate
|
||||
if ((ret = mbedtls_ssl_set_hostname(&ssl_ctx, host_or_ip)) != 0){
|
||||
_deleteHandshakeCerts();
|
||||
return handle_error(ret);
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_rng(&ssl_conf, mbedtls_ctr_drbg_random, &drbg_ctx);
|
||||
|
||||
if ((ret = mbedtls_ssl_setup(&ssl_ctx, &ssl_conf)) != 0) {
|
||||
_deleteHandshakeCerts();
|
||||
return handle_error(ret);
|
||||
}
|
||||
|
||||
_socket = sck;
|
||||
mbedtls_ssl_set_bio(&ssl_ctx, &_socket, mbedtls_net_send, mbedtls_net_recv, NULL );
|
||||
handshake_start_time = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AsyncTCP_TLS_Context::runSSLHandshake(void)
|
||||
{
|
||||
int ret, flags;
|
||||
if (_socket < 0) return -1;
|
||||
|
||||
if (handshake_start_time == 0) handshake_start_time = millis();
|
||||
ret = mbedtls_ssl_handshake(&ssl_ctx);
|
||||
if (ret != 0) {
|
||||
// Something happened before SSL handshake could be completed
|
||||
|
||||
// Negotiation error, other than socket not readable/writable when required
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
return handle_error(ret);
|
||||
}
|
||||
|
||||
// Handshake is taking too long
|
||||
if ((millis()-handshake_start_time) > handshake_timeout)
|
||||
return -1;
|
||||
|
||||
// Either MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Handshake completed, validate remote side if required...
|
||||
|
||||
if (_have_client_cert && _have_client_key) {
|
||||
log_d("Protocol is %s Ciphersuite is %s", mbedtls_ssl_get_version(&ssl_ctx), mbedtls_ssl_get_ciphersuite(&ssl_ctx));
|
||||
if ((ret = mbedtls_ssl_get_record_expansion(&ssl_ctx)) >= 0) {
|
||||
log_d("Record expansion is %d", ret);
|
||||
} else {
|
||||
log_w("Record expansion is unknown (compression)");
|
||||
}
|
||||
}
|
||||
|
||||
log_v("Verifying peer X.509 certificate...");
|
||||
|
||||
if ((flags = mbedtls_ssl_get_verify_result(&ssl_ctx)) != 0) {
|
||||
char buf[512];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
|
||||
log_e("Failed to verify peer certificate! verification info: %s", buf);
|
||||
_deleteHandshakeCerts();
|
||||
return handle_error(ret);
|
||||
} else {
|
||||
log_v("Certificate verified.");
|
||||
}
|
||||
|
||||
_deleteHandshakeCerts();
|
||||
|
||||
log_v("Free internal heap after TLS %u", ESP.getFreeHeap());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AsyncTCP_TLS_Context::write(const uint8_t *data, size_t len)
|
||||
{
|
||||
if (_socket < 0) return -1;
|
||||
|
||||
log_v("Writing packet, %d bytes unencrypted...", len);
|
||||
int ret = mbedtls_ssl_write(&ssl_ctx, data, len);
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0) {
|
||||
log_v("Handling error %d", ret); //for low level debug
|
||||
return handle_error(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AsyncTCP_TLS_Context::read(uint8_t * data, size_t len)
|
||||
{
|
||||
int ret = mbedtls_ssl_read(&ssl_ctx, data, len);
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0) {
|
||||
log_v("Handling error %d", ret); //for low level debug
|
||||
return handle_error(ret);
|
||||
}
|
||||
if (ret > 0) log_v("Read packet, %d out of %d requested bytes...", ret, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AsyncTCP_TLS_Context::_deleteHandshakeCerts(void)
|
||||
{
|
||||
if (_have_ca_cert) {
|
||||
log_v("Cleaning CA certificate.");
|
||||
mbedtls_x509_crt_free(&ca_cert);
|
||||
_have_ca_cert = false;
|
||||
}
|
||||
if (_have_client_cert) {
|
||||
log_v("Cleaning client certificate.");
|
||||
mbedtls_x509_crt_free(&client_cert);
|
||||
_have_client_cert = false;
|
||||
}
|
||||
if (_have_client_key) {
|
||||
log_v("Cleaning client certificate key.");
|
||||
mbedtls_pk_free(&client_key);
|
||||
_have_client_key = false;
|
||||
}
|
||||
}
|
||||
|
||||
AsyncTCP_TLS_Context::~AsyncTCP_TLS_Context()
|
||||
{
|
||||
_deleteHandshakeCerts();
|
||||
|
||||
log_v("Cleaning SSL connection.");
|
||||
|
||||
mbedtls_ssl_free(&ssl_ctx);
|
||||
mbedtls_ssl_config_free(&ssl_conf);
|
||||
mbedtls_ctr_drbg_free(&drbg_ctx);
|
||||
mbedtls_entropy_free(&entropy_ctx); // <-- Is this OK to free if mbedtls_entropy_init() has not been called on it?
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // ASYNC_TCP_SSL_ENABLED
|
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
|
||||
#include "mbedtls/version.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x03000000
|
||||
#include "mbedtls/net.h"
|
||||
#else
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#endif
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
|
||||
#define ASYNCTCP_TLS_CAN_RETRY(r) (((r) == MBEDTLS_ERR_SSL_WANT_READ) || ((r) == MBEDTLS_ERR_SSL_WANT_WRITE))
|
||||
#define ASYNCTCP_TLS_EOF(r) (((r) == MBEDTLS_ERR_SSL_CONN_EOF) || ((r) == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY))
|
||||
|
||||
class AsyncTCP_TLS_Context
|
||||
{
|
||||
private:
|
||||
// These fields must persist for the life of the encrypted connection, destroyed on
|
||||
// object destructor.
|
||||
mbedtls_ssl_context ssl_ctx;
|
||||
mbedtls_ssl_config ssl_conf;
|
||||
mbedtls_ctr_drbg_context drbg_ctx;
|
||||
mbedtls_entropy_context entropy_ctx;
|
||||
|
||||
// These allocate memory during handshake but must be freed on either success or failure
|
||||
mbedtls_x509_crt ca_cert;
|
||||
mbedtls_x509_crt client_cert;
|
||||
mbedtls_pk_context client_key;
|
||||
bool _have_ca_cert;
|
||||
bool _have_client_cert;
|
||||
bool _have_client_key;
|
||||
|
||||
unsigned long handshake_timeout;
|
||||
unsigned long handshake_start_time;
|
||||
|
||||
int _socket;
|
||||
|
||||
int _startSSLClient(int sck, const char * host_or_ip,
|
||||
const unsigned char *rootCABuff, const size_t rootCABuff_len,
|
||||
const unsigned char *cli_cert, const size_t cli_cert_len,
|
||||
const unsigned char *cli_key, const size_t cli_key_len,
|
||||
const char *pskIdent, const char *psKey,
|
||||
bool insecure);
|
||||
|
||||
// Delete certificates used in handshake
|
||||
void _deleteHandshakeCerts(void);
|
||||
public:
|
||||
AsyncTCP_TLS_Context(void);
|
||||
virtual ~AsyncTCP_TLS_Context();
|
||||
|
||||
int startSSLClientInsecure(int sck, const char * host_or_ip);
|
||||
|
||||
int startSSLClient(int sck, const char * host_or_ip,
|
||||
const char *pskIdent, const char *psKey);
|
||||
|
||||
int startSSLClient(int sck, const char * host_or_ip,
|
||||
const char *rootCABuff,
|
||||
const char *cli_cert,
|
||||
const char *cli_key);
|
||||
|
||||
int startSSLClient(int sck, const char * host_or_ip,
|
||||
const unsigned char *rootCABuff, const size_t rootCABuff_len,
|
||||
const unsigned char *cli_cert, const size_t cli_cert_len,
|
||||
const unsigned char *cli_key, const size_t cli_key_len);
|
||||
|
||||
int runSSLHandshake(void);
|
||||
|
||||
int write(const uint8_t *data, size_t len);
|
||||
|
||||
int read(uint8_t * data, size_t len);
|
||||
};
|
||||
|
||||
#endif // ASYNC_TCP_SSL_ENABLED
|
|
@ -23,7 +23,7 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
|
||||
#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||
#include <mutex>
|
||||
#ifndef SSE_MAX_QUEUED_MESSAGES
|
||||
#define SSE_MAX_QUEUED_MESSAGES 32
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#define ASYNCWEBSOCKET_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||
#include <mutex>
|
||||
#ifndef WS_MAX_QUEUED_MESSAGES
|
||||
#define WS_MAX_QUEUED_MESSAGES 32
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <vector>
|
||||
|
||||
#ifdef ESP32
|
||||
#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||
#include <WiFi.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
This is commit ca8ac5f from https://github.com/me-no-dev/AsyncTCP
|
||||
|
||||
# AsyncTCP
|
||||
[](https://travis-ci.org/me-no-dev/AsyncTCP)  [](https://www.codacy.com/manual/me-no-dev/AsyncTCP?utm_source=github.com&utm_medium=referral&utm_content=me-no-dev/AsyncTCP&utm_campaign=Badge_Grade)
|
||||
|
||||
### Async TCP Library for ESP32 Arduino
|
||||
|
||||
[](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs.
|
||||
|
||||
This library is the base for [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer)
|
||||
|
||||
## AsyncClient and AsyncServer
|
||||
The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use.
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"name":"AsyncTCP",
|
||||
"description":"Asynchronous TCP Library for ESP32",
|
||||
"keywords":"async,tcp",
|
||||
"authors":
|
||||
{
|
||||
"name": "Hristo Gochkov",
|
||||
"maintainer": true
|
||||
},
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/me-no-dev/AsyncTCP.git"
|
||||
},
|
||||
"version": "1.1.1",
|
||||
"license": "LGPL-3.0",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "espressif32",
|
||||
"build": {
|
||||
"libCompatMode": 2
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
name=AsyncTCP
|
||||
version=1.1.1
|
||||
author=Me-No-Dev
|
||||
maintainer=Me-No-Dev
|
||||
sentence=Async TCP Library for ESP32
|
||||
paragraph=Async TCP Library for ESP32
|
||||
category=Other
|
||||
url=https://github.com/me-no-dev/AsyncTCP
|
||||
architectures=*
|
File diff suppressed because it is too large
Load diff
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
Asynchronous TCP library for Espressif MCUs
|
||||
|
||||
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ASYNCTCP_H_
|
||||
#define ASYNCTCP_H_
|
||||
|
||||
#include "IPAddress.h"
|
||||
#include "sdkconfig.h"
|
||||
#include <functional>
|
||||
extern "C" {
|
||||
#include "freertos/semphr.h"
|
||||
#include "lwip/pbuf.h"
|
||||
}
|
||||
|
||||
#include "../../../system_settings.h"
|
||||
#include "../../../devboard/hal/hal.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 WIFI_CORE //any available core
|
||||
#define CONFIG_ASYNC_TCP_USE_WDT 0 //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;
|
||||
|
||||
struct tcp_pcb;
|
||||
struct ip_addr;
|
||||
|
||||
class AsyncClient {
|
||||
public:
|
||||
AsyncClient(tcp_pcb* pcb = 0);
|
||||
~AsyncClient();
|
||||
|
||||
AsyncClient & operator=(const AsyncClient &other);
|
||||
AsyncClient & operator+=(const AsyncClient &other);
|
||||
|
||||
bool operator==(const AsyncClient &other);
|
||||
|
||||
bool operator!=(const AsyncClient &other) {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool connect(IPAddress ip, uint16_t port);
|
||||
bool connect(const char* host, uint16_t port);
|
||||
void close(bool now = false);
|
||||
void stop();
|
||||
int8_t abort();
|
||||
bool free();
|
||||
|
||||
bool canSend();//ack is not pending
|
||||
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
|
||||
bool send();//send all data added with the method above
|
||||
|
||||
//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();
|
||||
bool connecting();
|
||||
bool connected();
|
||||
bool disconnecting();
|
||||
bool disconnected();
|
||||
bool freeable();//disconnected or disconnecting
|
||||
|
||||
uint16_t getMss();
|
||||
|
||||
uint32_t getRxTimeout();
|
||||
void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds
|
||||
|
||||
uint32_t getAckTimeout();
|
||||
void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds
|
||||
|
||||
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 (called if onPacket is not used)
|
||||
void onPacket(AcPacketHandler 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
|
||||
|
||||
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
|
||||
|
||||
const char * errorToString(int8_t error);
|
||||
const char * stateToString();
|
||||
|
||||
//Do not use any of the functions below!
|
||||
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_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 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 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; }
|
||||
|
||||
protected:
|
||||
tcp_pcb* _pcb;
|
||||
int8_t _closed_slot;
|
||||
|
||||
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;
|
||||
AcPacketHandler _pb_cb;
|
||||
void* _pb_cb_arg;
|
||||
AcTimeoutHandler _timeout_cb;
|
||||
void* _timeout_cb_arg;
|
||||
AcConnectHandler _poll_cb;
|
||||
void* _poll_cb_arg;
|
||||
|
||||
bool _pcb_busy;
|
||||
uint32_t _pcb_sent_at;
|
||||
bool _ack_pcb;
|
||||
uint32_t _rx_ack_len;
|
||||
uint32_t _rx_last_packet;
|
||||
uint32_t _rx_since_timeout;
|
||||
uint32_t _ack_timeout;
|
||||
uint16_t _connect_port;
|
||||
|
||||
int8_t _close();
|
||||
void _free_closed_slot();
|
||||
void _allocate_closed_slot();
|
||||
int8_t _connected(void* pcb, int8_t err);
|
||||
void _error(int8_t err);
|
||||
int8_t _poll(tcp_pcb* pcb);
|
||||
int8_t _sent(tcp_pcb* pcb, uint16_t len);
|
||||
int8_t _fin(tcp_pcb* pcb, int8_t err);
|
||||
int8_t _lwip_fin(tcp_pcb* pcb, int8_t err);
|
||||
void _dns_found(struct ip_addr *ipaddr);
|
||||
|
||||
public:
|
||||
AsyncClient* prev;
|
||||
AsyncClient* next;
|
||||
};
|
||||
|
||||
class AsyncServer {
|
||||
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);
|
||||
bool getNoDelay();
|
||||
uint8_t status();
|
||||
|
||||
//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_accepted(void *arg, AsyncClient* client);
|
||||
|
||||
protected:
|
||||
uint16_t _port;
|
||||
IPAddress _addr;
|
||||
bool _noDelay;
|
||||
tcp_pcb* _pcb;
|
||||
AcConnectHandler _connect_cb;
|
||||
void* _connect_cb_arg;
|
||||
|
||||
int8_t _accept(tcp_pcb* newpcb, int8_t err);
|
||||
int8_t _accepted(AsyncClient* client);
|
||||
};
|
||||
|
||||
|
||||
#endif /* ASYNCTCP_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue