chore: import local project into Gitea

This commit is contained in:
2026-05-20 10:03:16 -07:00
commit 7bd88d29b5
4043 changed files with 1056916 additions and 0 deletions

View File

@@ -0,0 +1,355 @@
/*
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
*/
#if !defined(_RPAsyncTCP_LOGLEVEL_)
#define _RPAsyncTCP_LOGLEVEL_ 1
#endif
#include "AsyncPrinter.h"
#include "debug.h"
/////////////////////////////////////////////////////////
AsyncPrinter::AsyncPrinter()
: _client(NULL)
, _data_cb(NULL)
, _data_arg(NULL)
, _close_cb(NULL)
, _close_arg(NULL)
, _tx_buffer(NULL)
, _tx_buffer_size(TCP_MSS)
, next(NULL)
{}
/////////////////////////////////////////////////////////
AsyncPrinter::AsyncPrinter(AsyncClient *client, size_t txBufLen)
: _client(client)
, _data_cb(NULL)
, _data_arg(NULL)
, _close_cb(NULL)
, _close_arg(NULL)
, _tx_buffer(NULL)
, _tx_buffer_size(txBufLen)
, next(NULL)
{
_attachCallbacks();
_tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size);
if (_tx_buffer == NULL)
{
panic(); //What should we do?
}
}
/////////////////////////////////////////////////////////
AsyncPrinter::~AsyncPrinter()
{
_on_close();
}
/////////////////////////////////////////////////////////
void AsyncPrinter::onData(ApDataHandler cb, void *arg)
{
_data_cb = cb;
_data_arg = arg;
}
/////////////////////////////////////////////////////////
void AsyncPrinter::onClose(ApCloseHandler cb, void *arg)
{
_close_cb = cb;
_close_arg = arg;
}
/////////////////////////////////////////////////////////
int AsyncPrinter::connect(IPAddress ip, uint16_t port)
{
if (_client != NULL && connected())
return 0;
_client = new (std::nothrow) AsyncClient();
if (_client == NULL)
{
panic();
}
_client->onConnect([](void *obj, AsyncClient * c)
{
((AsyncPrinter*)(obj))->_onConnect(c);
}, this);
if (_client->connect(ip, port))
{
while (_client && _client->state() < 4)
delay(1);
return connected();
}
return 0;
}
/////////////////////////////////////////////////////////
int AsyncPrinter::connect(const char *host, uint16_t port)
{
if (_client != NULL && connected())
return 0;
_client = new (std::nothrow) AsyncClient();
if (_client == NULL)
{
panic();
}
_client->onConnect([](void *obj, AsyncClient * c)
{
((AsyncPrinter*)(obj))->_onConnect(c);
}, this);
if (_client->connect(host, port))
{
while (_client && _client->state() < 4)
delay(1);
return connected();
}
return 0;
}
/////////////////////////////////////////////////////////
void AsyncPrinter::_onConnect(AsyncClient *c)
{
RPAsyncTCP_UNUSED(c);
if (_tx_buffer != NULL)
{
cbuf *b = _tx_buffer;
_tx_buffer = NULL;
delete b;
}
_tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size);
if (_tx_buffer)
{
panic();
}
_attachCallbacks();
}
/////////////////////////////////////////////////////////
AsyncPrinter::operator bool()
{
return connected();
}
/////////////////////////////////////////////////////////
AsyncPrinter & AsyncPrinter::operator=(const AsyncPrinter &other)
{
if (_client != NULL)
{
_client->close(true);
_client = NULL;
}
_tx_buffer_size = other._tx_buffer_size;
if (_tx_buffer != NULL)
{
cbuf *b = _tx_buffer;
_tx_buffer = NULL;
delete b;
}
_tx_buffer = new (std::nothrow) cbuf(other._tx_buffer_size);
if (_tx_buffer == NULL)
{
panic();
}
_client = other._client;
_attachCallbacks();
return *this;
}
/////////////////////////////////////////////////////////
size_t AsyncPrinter::write(uint8_t data)
{
return write(&data, 1);
}
/////////////////////////////////////////////////////////
size_t AsyncPrinter::write(const uint8_t *data, size_t len)
{
if (_tx_buffer == NULL || !connected())
return 0;
size_t toWrite = 0;
size_t toSend = len;
while (_tx_buffer->room() < toSend)
{
toWrite = _tx_buffer->room();
_tx_buffer->write((const char*)data, toWrite);
while (connected() && !_client->canSend())
delay(0);
if (!connected())
return 0; // or len - toSend;
_sendBuffer();
toSend -= toWrite;
}
_tx_buffer->write((const char*)(data + (len - toSend)), toSend);
while (connected() && !_client->canSend())
delay(0);
if (!connected())
return 0; // or len - toSend;
_sendBuffer();
return len;
}
/////////////////////////////////////////////////////////
bool AsyncPrinter::connected()
{
return (_client != NULL && _client->connected());
}
/////////////////////////////////////////////////////////
void AsyncPrinter::close()
{
if (_client != NULL)
_client->close(true);
}
/////////////////////////////////////////////////////////
size_t AsyncPrinter::_sendBuffer()
{
size_t available = _tx_buffer->available();
if (!connected() || !_client->canSend() || available == 0)
return 0;
size_t sendable = _client->space();
if (sendable < available)
available = sendable;
char *out = new (std::nothrow) char[available];
if (out == NULL)
{
panic(); // Connection should be aborted instead
}
_tx_buffer->read(out, available);
size_t sent = _client->write(out, available);
delete out;
return sent;
}
/////////////////////////////////////////////////////////
void AsyncPrinter::_onData(void *data, size_t len)
{
if (_data_cb)
_data_cb(_data_arg, this, (uint8_t*)data, len);
}
/////////////////////////////////////////////////////////
void AsyncPrinter::_on_close()
{
if (_client != NULL)
{
_client = NULL;
}
if (_tx_buffer != NULL)
{
cbuf *b = _tx_buffer;
_tx_buffer = NULL;
delete b;
}
if (_close_cb)
_close_cb(_close_arg, this);
}
/////////////////////////////////////////////////////////
void AsyncPrinter::_attachCallbacks()
{
_client->onPoll([](void *obj, AsyncClient * c)
{
RPAsyncTCP_UNUSED(c);
((AsyncPrinter*)(obj))->_sendBuffer();
}, this);
_client->onAck([](void *obj, AsyncClient * c, size_t len, uint32_t time)
{
RPAsyncTCP_UNUSED(c);
RPAsyncTCP_UNUSED(len);
RPAsyncTCP_UNUSED(time);
((AsyncPrinter*)(obj))->_sendBuffer();
}, this);
_client->onDisconnect([](void *obj, AsyncClient * c)
{
((AsyncPrinter*)(obj))->_on_close(); delete c;
}, this);
_client->onData([](void *obj, AsyncClient * c, void *data, size_t len)
{
RPAsyncTCP_UNUSED(c);
((AsyncPrinter*)(obj))->_onData(data, len);
}, this);
}
/////////////////////////////////////////////////////////

View File

@@ -0,0 +1,77 @@
/*
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 ASYNCPRINTER_H_
#define ASYNCPRINTER_H_
#include "Arduino.h"
#include "RPAsyncTCP.h"
#include "cbuf.h"
class AsyncPrinter;
typedef std::function<void(void*, AsyncPrinter*, uint8_t*, size_t)> ApDataHandler;
typedef std::function<void(void*, AsyncPrinter*)> ApCloseHandler;
/////////////////////////////////////////////////////////
class AsyncPrinter: public Print
{
private:
AsyncClient *_client;
ApDataHandler _data_cb;
void *_data_arg;
ApCloseHandler _close_cb;
void *_close_arg;
cbuf *_tx_buffer;
size_t _tx_buffer_size;
void _onConnect(AsyncClient *c);
public:
AsyncPrinter *next;
AsyncPrinter();
AsyncPrinter(AsyncClient *client, size_t txBufLen = TCP_MSS);
virtual ~AsyncPrinter();
int connect(IPAddress ip, uint16_t port);
int connect(const char *host, uint16_t port);
void onData(ApDataHandler cb, void *arg);
void onClose(ApCloseHandler cb, void *arg);
operator bool();
AsyncPrinter & operator=(const AsyncPrinter &other);
size_t write(uint8_t data);
size_t write(const uint8_t *data, size_t len);
bool connected();
void close();
size_t _sendBuffer();
void _onData(void *data, size_t len);
void _on_close();
void _attachCallbacks();
};
#endif /* ASYNCPRINTER_H_ */

View File

@@ -0,0 +1,127 @@
#ifndef _DEBUG_PRINT_MACROS_H
#define _DEBUG_PRINT_MACROS_H
// Some customizable print macros to suite the debug needs de jour.
// Debug macros
// #include <pgmspace.h>
// https://stackoverflow.com/questions/8487986/file-macro-shows-full-path
// This value is resolved at compile time.
#define _FILENAME_ strrchr("/" __FILE__, '/')
/////////////////////////////////////////////////////////
#if defined(DEBUG_ESP_PORT) && !defined(DEBUG_TIME_STAMP_FMT)
#define DEBUG_TIME_STAMP_FMT "%06u.%03u "
struct _DEBUG_TIME_STAMP
{
unsigned dec;
unsigned whole;
};
inline struct _DEBUG_TIME_STAMP debugTimeStamp()
{
struct _DEBUG_TIME_STAMP st;
unsigned now = millis() % 1000000000;
st.dec = now % 1000;
st.whole = now / 1000;
return st;
}
#endif
/////////////////////////////////////////////////////////
#if defined(DEBUG_ESP_PORT) && !defined(DEBUG_GENERIC)
#define DEBUG_GENERIC( module, format, ... ) \
do { \
struct _DEBUG_TIME_STAMP st = debugTimeStamp(); \
DEBUG_ESP_PORT.printf( DEBUG_TIME_STAMP_FMT module " " format, st.whole, st.dec, ##__VA_ARGS__ ); \
} while(false)
#endif
/////////////////////////////////////////////////////////
#if defined(DEBUG_ESP_PORT) && !defined(DEBUG_GENERIC_P)
#define DEBUG_GENERIC_P( module, format, ... ) \
do { \
struct _DEBUG_TIME_STAMP st = debugTimeStamp(); \
DEBUG_ESP_PORT.printf_P(PSTR( DEBUG_TIME_STAMP_FMT module " " format ), st.whole, st.dec, ##__VA_ARGS__ ); \
} while(false)
#endif
/////////////////////////////////////////////////////////
#if defined(DEBUG_GENERIC) && !defined(ASSERT_GENERIC)
#define ASSERT_GENERIC( a, module ) \
do { \
if ( !(a) ) { \
DEBUG_GENERIC( module, "%s:%s:%u: ASSERT("#a") failed!\n", __FILE__, __func__, __LINE__); \
DEBUG_ESP_PORT.flush(); \
} \
} while(false)
#endif
/////////////////////////////////////////////////////////
#if defined(DEBUG_GENERIC_P) && !defined(ASSERT_GENERIC_P)
#define ASSERT_GENERIC_P( a, module ) \
do { \
if ( !(a) ) { \
DEBUG_GENERIC_P( module, "%s:%s:%u: ASSERT("#a") failed!\n", __FILE__, __func__, __LINE__); \
DEBUG_ESP_PORT.flush(); \
} \
} while(false)
#endif
/////////////////////////////////////////////////////////
#ifndef DEBUG_GENERIC
#define DEBUG_GENERIC(...) do { (void)0;} while(false)
#endif
/////////////////////////////////////////////////////////
#ifndef DEBUG_GENERIC_P
#define DEBUG_GENERIC_P(...) do { (void)0;} while(false)
#endif
/////////////////////////////////////////////////////////
#ifndef ASSERT_GENERIC
#define ASSERT_GENERIC(...) do { (void)0;} while(false)
#endif
/////////////////////////////////////////////////////////
#ifndef ASSERT_GENERIC_P
#define ASSERT_GENERIC_P(...) do { (void)0;} while(false)
#endif
/////////////////////////////////////////////////////////
#ifndef DEBUG_ESP_PRINTF
#define DEBUG_ESP_PRINTF( format, ...) DEBUG_GENERIC_P("[%s]", format, &_FILENAME_[1], ##__VA_ARGS__)
#endif
/////////////////////////////////////////////////////////
#if defined(DEBUG_ESP_ASYNC_TCP) && !defined(ASYNC_TCP_DEBUG)
#define ASYNC_TCP_DEBUG( format, ...) DEBUG_GENERIC_P("[ASYNC_TCP]", format, ##__VA_ARGS__)
#endif
/////////////////////////////////////////////////////////
#ifndef ASYNC_TCP_ASSERT
#define ASYNC_TCP_ASSERT( a ) ASSERT_GENERIC_P( (a), "[ASYNC_TCP]")
#endif
/////////////////////////////////////////////////////////
#if defined(DEBUG_ESP_TCP_SSL) && !defined(TCP_SSL_DEBUG)
#define TCP_SSL_DEBUG( format, ...) DEBUG_GENERIC_P("[TCP_SSL]", format, ##__VA_ARGS__)
#endif
/////////////////////////////////////////////////////////
#endif //_DEBUG_PRINT_MACROS_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,417 @@
#ifndef RPAsyncTCP_H_
#define RPAsyncTCP_H_
#include "Arduino.h"
#include <WiFi.h>
#if ASYNC_TCP_SSL_ENABLED
#undef ASYNC_TCP_SSL_ENABLED
#define ASYNC_TCP_SSL_ENABLED false
#warning ASYNC_TCP_SSL_ENABLED is not ready yet. Disable it
#endif
#define DEBUG_ESP_ASYNC_TCP true
#include "RPAsyncTCP_Debug.h"
#include <async_config.h>
#include "IPAddress.h"
#include <functional>
#include <memory>
extern "C"
{
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/tcp.h"
#include "lwip/pbuf.h"
};
#ifndef RPAsyncTCP_UNUSED
#define RPAsyncTCP_UNUSED(x) (void)(x)
#endif
/////////////////////////////////////////////////
class AsyncClient;
class AsyncServer;
class ACErrorTracker;
#define ASYNC_MAX_ACK_TIME 5000
#define ASYNC_WRITE_FLAG_COPY 0x01 //to allocate new buffer to hold the data while sending
#define ASYNC_WRITE_FLAG_MORE 0x02 //not send PSH flag. More data to be sent before the application should react.
/////////////////////////////////////////////////
struct tcp_pcb;
#if ASYNC_TCP_SSL_ENABLED
struct SSL_;
typedef struct SSL_ SSL;
struct SSL_CTX_;
typedef struct SSL_CTX_ SSL_CTX;
#endif
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*, err_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;
typedef std::function<void(void*, size_t event)> AsNotifyHandler;
enum error_events
{
EE_OK = 0,
EE_ABORTED, // Callback or foreground aborted connections
EE_ERROR_CB, // Stack initiated aborts via error Callbacks.
EE_CONNECTED_CB,
EE_RECV_CB,
EE_ACCEPT_CB,
EE_MAX
};
/////////////////////////////////////////////////
// DEBUG_MORE is for gathering more information on which CBs close events are
// occuring and count.
// #define DEBUG_MORE 1
class ACErrorTracker
{
private:
AsyncClient *_client;
err_t _close_error;
int _errored;
#if DEBUG_ESP_ASYNC_TCP
size_t _connectionId;
#endif
#ifdef DEBUG_MORE
AsNotifyHandler _error_event_cb;
void* _error_event_cb_arg;
#endif
protected:
friend class AsyncClient;
friend class AsyncServer;
#ifdef DEBUG_MORE
void onErrorEvent(AsNotifyHandler cb, void *arg);
#endif
#if DEBUG_ESP_ASYNC_TCP
void setConnectionId(size_t id)
{
_connectionId = id;
}
size_t getConnectionId()
{
return _connectionId;
}
#endif
void setCloseError(err_t e);
void setErrored(size_t errorEvent);
err_t getCallbackCloseError();
void clearClient()
{
if (_client) _client = NULL;
}
public:
err_t getCloseError() const
{
return _close_error;
}
bool hasClient() const
{
return (_client != NULL);
}
ACErrorTracker(AsyncClient *c);
~ACErrorTracker() {}
};
/////////////////////////////////////////////////
class AsyncClient
{
protected:
friend class AsyncTCPbuffer;
friend class AsyncServer;
tcp_pcb* _pcb;
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;
#if ASYNC_TCP_SSL_ENABLED
bool _pcb_secure;
bool _handshake_done;
#endif
uint32_t _pcb_sent_at;
bool _close_pcb;
bool _ack_pcb;
uint32_t _tx_unacked_len;
uint32_t _tx_acked_len;
uint32_t _tx_unsent_len;
uint32_t _rx_ack_len;
uint32_t _rx_last_packet;
uint32_t _rx_since_timeout;
uint32_t _ack_timeout;
uint16_t _connect_port;
u8_t _recv_pbuf_flags;
std::shared_ptr<ACErrorTracker> _errorTracker;
void _close();
void _connected(std::shared_ptr<ACErrorTracker>& closeAbort, void* pcb, err_t err);
void _error(err_t err);
#if ASYNC_TCP_SSL_ENABLED
void _ssl_error(int8_t err);
#endif
void _poll(std::shared_ptr<ACErrorTracker>& closeAbort, tcp_pcb* pcb);
void _sent(std::shared_ptr<ACErrorTracker>& closeAbort, tcp_pcb* pcb, uint16_t len);
#if LWIP_VERSION_MAJOR == 1
void _dns_found(struct ip_addr *ipaddr);
#else
void _dns_found(ip_addr_t *p);
#endif
static err_t _s_poll(void *arg, struct tcp_pcb *tpcb);
static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err);
static void _s_error(void *arg, err_t err);
static err_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len);
static err_t _s_connected(void* arg, void* tpcb, err_t err);
#if LWIP_VERSION_MAJOR == 1
static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg);
#else
static void _s_dns_found(const char *name, ip_addr_t *p, void *arg);
#endif
#if ASYNC_TCP_SSL_ENABLED
static void _s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len);
static void _s_handshake(void *arg, struct tcp_pcb *tcp, SSL *ssl);
static void _s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err);
#endif
std::shared_ptr<ACErrorTracker> getACErrorTracker() const
{
return _errorTracker;
};
void setCloseError(err_t e) const
{
_errorTracker->setCloseError(e);
}
public:
AsyncClient* prev;
AsyncClient* next;
#if ASYNC_TCP_SSL_ENABLED
AsyncClient(tcp_pcb* pcb = 0, SSL_CTX * ssl_ctx = NULL);
#else
AsyncClient(tcp_pcb* pcb = 0);
#endif
~AsyncClient();
AsyncClient & operator=(const AsyncClient &other);
AsyncClient & operator+=(const AsyncClient &other);
bool operator==(const AsyncClient &other) const;
bool operator!=(const AsyncClient &other) const
{
return !(*this == other);
}
#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);
#else
bool connect(IPAddress ip, uint16_t port);
bool connect(const char* host, uint16_t port);
#endif
void close(bool now = false);
void stop();
void abort();
bool free();
bool canSend() const;//ack is not pending
size_t space() const;
size_t add(const char* data, size_t size, uint8_t apiflags = 0); //add for sending
bool send();//send all data added with the method above
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
}
bool isRecvPush()
{
return !!(_recv_pbuf_flags & PBUF_FLAG_PUSH);
}
#if DEBUG_ESP_ASYNC_TCP
size_t getConnectionId() const
{
return _errorTracker->getConnectionId();
}
#endif
#if ASYNC_TCP_SSL_ENABLED
SSL *getSSL();
#endif
size_t write(const char* data);
size_t write(const char* data, size_t size, uint8_t apiflags = 0); //only when canSend() == true
uint8_t state() const;
bool connecting() const;
bool connected() const;
bool disconnecting() const;
bool disconnected() const;
bool freeable() const;//disconnected or disconnecting
uint16_t getMss() const;
uint32_t getRxTimeout() const;
void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds
uint32_t getAckTimeout() const;
void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds
void setNoDelay(bool nodelay);
bool getNoDelay() const;
uint32_t getRemoteAddress() const;
uint16_t getRemotePort() const;
uint32_t getLocalAddress() const;
uint16_t getLocalPort() const;
IPAddress remoteIP() const;
uint16_t remotePort() const;
IPAddress localIP() const;
uint16_t localPort() const;
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);
const char * errorToString(err_t error) const;
const char * stateToString() const;
void _recv(std::shared_ptr<ACErrorTracker>& closeAbort, tcp_pcb* pcb, pbuf* pb, err_t err);
err_t getCloseError() const
{
return _errorTracker->getCloseError();
}
};
/////////////////////////////////////////////////
#if ASYNC_TCP_SSL_ENABLED
typedef std::function<int(void* arg, const char *filename, uint8_t **buf)> AcSSlFileHandler;
struct pending_pcb;
#endif
/////////////////////////////////////////////////
class AsyncServer
{
protected:
uint16_t _port;
IPAddress _addr;
bool _noDelay;
tcp_pcb* _pcb;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
#if ASYNC_TCP_SSL_ENABLED
struct pending_pcb * _pending;
SSL_CTX * _ssl_ctx;
AcSSlFileHandler _file_cb;
void* _file_cb_arg;
#endif
#ifdef DEBUG_MORE
int _event_count[EE_MAX];
#endif
public:
AsyncServer(IPAddress addr, uint16_t port);
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void* arg);
#if ASYNC_TCP_SSL_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);
bool getNoDelay() const;
uint8_t status() const;
#ifdef DEBUG_MORE
int getEventCount(size_t ee) const
{
return _event_count[ee];
}
#endif
protected:
err_t _accept(tcp_pcb* newpcb, err_t err);
static err_t _s_accept(void *arg, tcp_pcb* newpcb, err_t err);
#ifdef DEBUG_MORE
int incEventCount(size_t ee)
{
return ++_event_count[ee];
}
#endif
#if ASYNC_TCP_SSL_ENABLED
int _cert(const char *filename, uint8_t **buf);
err_t _poll(tcp_pcb* pcb);
err_t _recv(tcp_pcb *pcb, struct pbuf *pb, err_t err);
static int _s_cert(void *arg, const char *filename, uint8_t **buf);
static err_t _s_poll(void *arg, struct tcp_pcb *tpcb);
static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err);
#endif
};
/////////////////////////////////////////////////
#endif /* RPAsyncTCP_H_ */

View File

@@ -0,0 +1,65 @@
#pragma once
#ifndef RPAsyncTCP_DEBUG_H
#define RPAsyncTCP_DEBUG_H
#ifdef RPAsyncTCP_DEBUG_PORT
#define DBG_PORT_ATCP RPAsyncTCP_DEBUG_PORT
#else
#define DBG_PORT_ATCP Serial
#endif
// Change _RPAsyncTCP_LOGLEVEL_ to set tracing and logging verbosity
// 0: DISABLED: no logging
// 1: ERROR: errors
// 2: WARN: errors and warnings
// 3: INFO: errors, warnings and informational (default)
// 4: DEBUG: errors, warnings, informational and debug
#ifndef _RPAsyncTCP_LOGLEVEL_
#define _RPAsyncTCP_LOGLEVEL_ 1
#endif
/////////////////////////////////////////////////////////
#define ATCP_PRINT_MARK ATCP_PRINT("[ATCP] ")
#define ATCP_PRINT_SP DBG_PORT_ATCP.print(" ")
#define ATCP_PRINT DBG_PORT_ATCP.print
#define ATCP_PRINTLN DBG_PORT_ATCP.println
/////////////////////////////////////////////////////////
#define ATCP_LOGERROR(x) if(_RPAsyncTCP_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINTLN(x); }
#define ATCP_LOGERROR0(x) if(_RPAsyncTCP_LOGLEVEL_>0) { ATCP_PRINT(x); }
#define ATCP_LOGERROR1(x,y) if(_RPAsyncTCP_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINTLN(y); }
#define ATCP_LOGERROR2(x,y,z) if(_RPAsyncTCP_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINTLN(z); }
#define ATCP_LOGERROR3(x,y,z,w) if(_RPAsyncTCP_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINTLN(w); }
/////////////////////////////////////////////////////////
#define ATCP_LOGWARN(x) if(_RPAsyncTCP_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINTLN(x); }
#define ATCP_LOGWARN0(x) if(_RPAsyncTCP_LOGLEVEL_>1) { ATCP_PRINT(x); }
#define ATCP_LOGWARN1(x,y) if(_RPAsyncTCP_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINTLN(y); }
#define ATCP_LOGWARN2(x,y,z) if(_RPAsyncTCP_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINTLN(z); }
#define ATCP_LOGWARN3(x,y,z,w) if(_RPAsyncTCP_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINTLN(w); }
/////////////////////////////////////////////////////////
#define ATCP_LOGINFO(x) if(_RPAsyncTCP_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINTLN(x); }
#define ATCP_LOGINFO0(x) if(_RPAsyncTCP_LOGLEVEL_>2) { ATCP_PRINT(x); }
#define ATCP_LOGINFO1(x,y) if(_RPAsyncTCP_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINTLN(y); }
#define ATCP_LOGINFO2(x,y,z) if(_RPAsyncTCP_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINTLN(z); }
#define ATCP_LOGINFO3(x,y,z,w) if(_RPAsyncTCP_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINTLN(w); }
/////////////////////////////////////////////////////////
#define ATCP_LOGDEBUG(x) if(_RPAsyncTCP_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINTLN(x); }
#define ATCP_LOGDEBUG0(x) if(_RPAsyncTCP_LOGLEVEL_>3) { ATCP_PRINT(x); }
#define ATCP_LOGDEBUG1(x,y) if(_RPAsyncTCP_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINTLN(y); }
#define ATCP_LOGDEBUG2(x,y,z) if(_RPAsyncTCP_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINTLN(z); }
#define ATCP_LOGDEBUG3(x,y,z,w) if(_RPAsyncTCP_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINTLN(w); }
/////////////////////////////////////////////////////////
#endif //RPAsyncTCP_DEBUG_H

View File

@@ -0,0 +1,721 @@
#include <Arduino.h>
#include "debug.h"
#if !defined(_RPAsyncTCP_LOGLEVEL_)
#define _RPAsyncTCP_LOGLEVEL_ 1
#endif
#include "RPAsyncTCP_buffer.h"
/////////////////////////////////////////////////////////
AsyncTCPbuffer::AsyncTCPbuffer(AsyncClient* client)
{
if (client == NULL)
{
ATCP_LOGDEBUG("client is null!!!");
panic();
}
_client = client;
_TXbufferWrite = new (std::nothrow) cbuf(TCP_MSS);
_TXbufferRead = _TXbufferWrite;
_RXbuffer = new (std::nothrow) cbuf(100);
_RXmode = ATB_RX_MODE_FREE;
_rxSize = 0;
_rxTerminator = 0x00;
_rxReadBytesPtr = NULL;
_rxReadStringPtr = NULL;
_cbDisconnect = NULL;
_cbRX = NULL;
_cbDone = NULL;
_attachCallbacks();
}
/////////////////////////////////////////////////////////
AsyncTCPbuffer::~AsyncTCPbuffer()
{
if (_client)
{
_client->close();
}
if (_RXbuffer)
{
delete _RXbuffer;
_RXbuffer = NULL;
}
if (_TXbufferWrite)
{
// will be deleted in _TXbufferRead chain
_TXbufferWrite = NULL;
}
if (_TXbufferRead)
{
cbuf * next = _TXbufferRead->next;
delete _TXbufferRead;
while (next != NULL)
{
_TXbufferRead = next;
next = _TXbufferRead->next;
delete _TXbufferRead;
}
_TXbufferRead = NULL;
}
}
/////////////////////////////////////////////////////////
size_t AsyncTCPbuffer::write(String & data)
{
return write(data.c_str(), data.length());
}
/////////////////////////////////////////////////////////
size_t AsyncTCPbuffer::write(uint8_t data)
{
return write(&data, 1);
}
/////////////////////////////////////////////////////////
size_t AsyncTCPbuffer::write(const char* data)
{
return write((const uint8_t *) data, strlen(data));
}
/////////////////////////////////////////////////////////
size_t AsyncTCPbuffer::write(const char *data, size_t len)
{
return write((const uint8_t *) data, len);
}
/////////////////////////////////////////////////////////
/**
write data in to buffer and try to send the data
@param data
@param len
@return
*/
size_t AsyncTCPbuffer::write(const uint8_t *data, size_t len)
{
if (_TXbufferWrite == NULL || _client == NULL || !_client->connected() || data == NULL || len == 0)
{
return 0;
}
size_t bytesLeft = len;
while (bytesLeft)
{
size_t w = _TXbufferWrite->write((const char*) data, bytesLeft);
bytesLeft -= w;
data += w;
_sendBuffer();
// add new buffer since we have more data
if (_TXbufferWrite->full() && bytesLeft > 0)
{
/*
// to less ram!!!
if(ESP.getFreeHeap() < 4096) {
ATCP_LOGDEBUG("run out of Heap can not send all Data!");
return (len - bytesLeft);
}
*/
cbuf * next = new (std::nothrow) cbuf(TCP_MSS);
if (next == NULL)
{
ATCP_LOGDEBUG("run out of Heap!");
panic();
}
else
{
ATCP_LOGDEBUG("new cbuf");
}
// add new buffer to chain (current cbuf)
_TXbufferWrite->next = next;
// move ptr for next data
_TXbufferWrite = next;
}
}
return len;
}
/////////////////////////////////////////////////////////
/**
wait until all data has send out
*/
void AsyncTCPbuffer::flush()
{
while (!_TXbufferWrite->empty())
{
while (connected() && !_client->canSend())
{
delay(0);
}
if (!connected())
return;
_sendBuffer();
}
}
/////////////////////////////////////////////////////////
void AsyncTCPbuffer::noCallback()
{
_RXmode = ATB_RX_MODE_NONE;
}
/////////////////////////////////////////////////////////
void AsyncTCPbuffer::readStringUntil(char terminator, String * str, AsyncTCPbufferDoneCb done)
{
if (_client == NULL)
{
return;
}
ATCP_LOGDEBUG1("readStringUntil terminator:", terminator);
_RXmode = ATB_RX_MODE_NONE;
_cbDone = done;
_rxReadStringPtr = str;
_rxTerminator = terminator;
_rxSize = 0;
_RXmode = ATB_RX_MODE_TERMINATOR_STRING;
}
/////////////////////////////////////////////////////////
/*
void AsyncTCPbuffer::readBytesUntil(char terminator, char *buffer, size_t length, AsyncTCPbufferDoneCb done)
{
_RXmode = ATB_RX_MODE_NONE;
_cbDone = done;
_rxReadBytesPtr = (uint8_t *) buffer;
_rxTerminator = terminator;
_rxSize = length;
_RXmode = ATB_RX_MODE_TERMINATOR;
_handleRxBuffer(NULL, 0);
}
void AsyncTCPbuffer::readBytesUntil(char terminator, uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done)
{
readBytesUntil(terminator, (char *) buffer, length, done);
}
*/
/////////////////////////////////////////////////////////
void AsyncTCPbuffer::readBytes(char *buffer, size_t length, AsyncTCPbufferDoneCb done)
{
if (_client == NULL)
{
return;
}
ATCP_LOGDEBUG1("readBytes length:", length);
_RXmode = ATB_RX_MODE_NONE;
_cbDone = done;
_rxReadBytesPtr = (uint8_t *) buffer;
_rxSize = length;
_RXmode = ATB_RX_MODE_READ_BYTES;
}
/////////////////////////////////////////////////////////
void AsyncTCPbuffer::readBytes(uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done)
{
readBytes((char *) buffer, length, done);
}
/////////////////////////////////////////////////////////
void AsyncTCPbuffer::onData(AsyncTCPbufferDataCb cb)
{
if (_client == NULL)
{
return;
}
ATCP_LOGDEBUG("onData");
_RXmode = ATB_RX_MODE_NONE;
_cbDone = NULL;
_cbRX = cb;
_RXmode = ATB_RX_MODE_FREE;
}
/////////////////////////////////////////////////////////
void AsyncTCPbuffer::onDisconnect(AsyncTCPbufferDisconnectCb cb)
{
_cbDisconnect = cb;
}
/////////////////////////////////////////////////////////
IPAddress AsyncTCPbuffer::remoteIP()
{
if (!_client)
{
return IPAddress(0, 0, 0, 0);
}
return _client->remoteIP();
}
/////////////////////////////////////////////////////////
uint16_t AsyncTCPbuffer::remotePort()
{
if (!_client)
{
return 0;
}
return _client->remotePort();
}
/////////////////////////////////////////////////////////
bool AsyncTCPbuffer::connected()
{
if (!_client)
{
return false;
}
return _client->connected();
}
/////////////////////////////////////////////////////////
void AsyncTCPbuffer::stop()
{
if (!_client)
{
return;
}
_client->stop();
_client = NULL;
if (_cbDone)
{
switch (_RXmode)
{
case ATB_RX_MODE_READ_BYTES:
case ATB_RX_MODE_TERMINATOR:
case ATB_RX_MODE_TERMINATOR_STRING:
_RXmode = ATB_RX_MODE_NONE;
_cbDone(false, NULL);
break;
default:
break;
}
}
_RXmode = ATB_RX_MODE_NONE;
}
/////////////////////////////////////////////////////////
void AsyncTCPbuffer::close()
{
stop();
}
/////////////////////////////////////////////////////////
/**
attachCallbacks to AsyncClient class
*/
void AsyncTCPbuffer::_attachCallbacks()
{
if (!_client)
{
return;
}
ATCP_LOGDEBUG("attachCallbacks");
_client->onPoll([](void *obj, AsyncClient * c)
{
RPAsyncTCP_UNUSED(c);
AsyncTCPbuffer* b = ((AsyncTCPbuffer*)(obj));
if ((b->_TXbufferRead != NULL) && !b->_TXbufferRead->empty())
{
b->_sendBuffer();
}
// if(!b->_RXbuffer->empty()) {
// b->_handleRxBuffer(NULL, 0);
// }
}, this);
_client->onAck([](void *obj, AsyncClient * c, size_t len, uint32_t time)
{
RPAsyncTCP_UNUSED(c);
RPAsyncTCP_UNUSED(len);
RPAsyncTCP_UNUSED(time);
ATCP_LOGDEBUG("onAck");
((AsyncTCPbuffer*)(obj))->_sendBuffer();
}, this);
_client->onDisconnect([](void *obj, AsyncClient * c)
{
ATCP_LOGDEBUG("onDisconnect");
AsyncTCPbuffer* b = ((AsyncTCPbuffer*)(obj));
b->_client = NULL;
bool del = true;
if (b->_cbDisconnect)
{
del = b->_cbDisconnect(b);
}
delete c;
if (del)
{
delete b;
}
}, this);
_client->onData([](void *obj, AsyncClient * c, void *buf, size_t len)
{
RPAsyncTCP_UNUSED(c);
AsyncTCPbuffer* b = ((AsyncTCPbuffer*)(obj));
b->_rxData((uint8_t *)buf, len);
}, this);
_client->onTimeout([](void *obj, AsyncClient * c, uint32_t time)
{
RPAsyncTCP_UNUSED(obj);
RPAsyncTCP_UNUSED(time);
ATCP_LOGDEBUG("onTimeout");
c->close();
}, this);
ATCP_LOGDEBUG("attachCallbacks Done.");
}
/////////////////////////////////////////////////////////
/**
send TX buffer if possible
*/
void AsyncTCPbuffer::_sendBuffer()
{
//ATCP_LOGDEBUG("_sendBuffer...");
size_t available = _TXbufferRead->available();
if (available == 0 || _client == NULL || !_client->connected() || !_client->canSend())
{
return;
}
while (connected() && (_client->space() > 0) && (_TXbufferRead->available() > 0) && _client->canSend())
{
available = _TXbufferRead->available();
if (available > _client->space())
{
available = _client->space();
}
char *out = new (std::nothrow) char[available];
if (out == NULL)
{
ATCP_LOGDEBUG("to less heap, try later.");
return;
}
// read data from buffer
_TXbufferRead->peek(out, available);
// send data
size_t send = _client->write((const char*) out, available);
if (send != available)
{
ATCP_LOGDEBUG3("_sendBuffer write failed send:", send, ", available:", available);
if (!connected())
{
ATCP_LOGDEBUG("incomplete transfer, connection lost.");
}
}
// remove really send data from buffer
_TXbufferRead->remove(send);
// if buffer is empty and there is a other buffer in chain delete the empty one
if (_TXbufferRead->available() == 0 && _TXbufferRead->next != NULL)
{
cbuf * old = _TXbufferRead;
_TXbufferRead = _TXbufferRead->next;
delete old;
ATCP_LOGDEBUG("delete cbuf");
}
delete[] out;
}
}
/////////////////////////////////////////////////////////
/**
called on incoming data
@param buf
@param len
*/
void AsyncTCPbuffer::_rxData(uint8_t *buf, size_t len)
{
if (!_client || !_client->connected())
{
ATCP_LOGDEBUG("not connected!");
return;
}
if (!_RXbuffer)
{
ATCP_LOGDEBUG("_rxData no _RXbuffer!");
return;
}
ATCP_LOGDEBUG3("_rxData len:", len, ", RXmode:", _RXmode);
size_t handled = 0;
if (_RXmode != ATB_RX_MODE_NONE)
{
handled = _handleRxBuffer((uint8_t *) buf, len);
buf += handled;
len -= handled;
// handle as much as possible before using the buffer
if (_RXbuffer->empty())
{
while (_RXmode != ATB_RX_MODE_NONE && handled != 0 && len > 0)
{
handled = _handleRxBuffer(buf, len);
buf += handled;
len -= handled;
}
}
}
if (len > 0)
{
if (_RXbuffer->room() < len)
{
// to less space
ATCP_LOGDEBUG("_rxData buffer full try resize");
_RXbuffer->resizeAdd((len + _RXbuffer->room()));
if (_RXbuffer->room() < len)
{
ATCP_LOGDEBUG1("_rxData buffer to full can only handle:", _RXbuffer->room());
}
}
_RXbuffer->write((const char *) (buf), len);
}
if (!_RXbuffer->empty() && _RXmode != ATB_RX_MODE_NONE)
{
// handle as much as possible data in buffer
handled = _handleRxBuffer(NULL, 0);
while (_RXmode != ATB_RX_MODE_NONE && handled != 0)
{
handled = _handleRxBuffer(NULL, 0);
}
}
// clean up ram
if (_RXbuffer->empty() && _RXbuffer->room() != 100)
{
_RXbuffer->resize(100);
}
}
/////////////////////////////////////////////////////////
size_t AsyncTCPbuffer::_handleRxBuffer(uint8_t *buf, size_t len)
{
if (!_client || !_client->connected() || _RXbuffer == NULL)
{
return 0;
}
ATCP_LOGDEBUG3("_handleRxBuffer len:", len, ", RXmode:", _RXmode);
size_t BufferAvailable = _RXbuffer->available();
size_t r = 0;
if (_RXmode == ATB_RX_MODE_NONE)
{
return 0;
}
else if (_RXmode == ATB_RX_MODE_FREE)
{
if (_cbRX == NULL)
{
return 0;
}
if (BufferAvailable > 0)
{
uint8_t * b = new (std::nothrow) uint8_t[BufferAvailable];
if (b == NULL)
{
panic(); //TODO: What action should this be ?
}
_RXbuffer->peek((char *) b, BufferAvailable);
r = _cbRX(b, BufferAvailable);
_RXbuffer->remove(r);
}
if (r == BufferAvailable && buf && (len > 0))
{
return _cbRX(buf, len);
}
else
{
return 0;
}
}
else if (_RXmode == ATB_RX_MODE_READ_BYTES)
{
if (_rxReadBytesPtr == NULL || _cbDone == NULL)
{
return 0;
}
size_t newReadCount = 0;
if (BufferAvailable)
{
r = _RXbuffer->read((char *) _rxReadBytesPtr, _rxSize);
_rxSize -= r;
_rxReadBytesPtr += r;
}
if (_RXbuffer->empty() && (len > 0) && buf)
{
r = len;
if (r > _rxSize)
{
r = _rxSize;
}
memcpy(_rxReadBytesPtr, buf, r);
_rxReadBytesPtr += r;
_rxSize -= r;
newReadCount += r;
}
if (_rxSize == 0)
{
_RXmode = ATB_RX_MODE_NONE;
_cbDone(true, NULL);
}
// add left over bytes to Buffer
return newReadCount;
}
else if (_RXmode == ATB_RX_MODE_TERMINATOR)
{
// TODO implement read terminator non string
}
else if (_RXmode == ATB_RX_MODE_TERMINATOR_STRING)
{
if (_rxReadStringPtr == NULL || _cbDone == NULL)
{
return 0;
}
// handle Buffer
if (BufferAvailable > 0)
{
while (!_RXbuffer->empty())
{
char c = _RXbuffer->read();
if (c == _rxTerminator || c == 0x00)
{
_RXmode = ATB_RX_MODE_NONE;
_cbDone(true, _rxReadStringPtr);
return 0;
}
else
{
(*_rxReadStringPtr) += c;
}
}
}
if (_RXbuffer->empty() && (len > 0) && buf)
{
size_t newReadCount = 0;
while (newReadCount < len)
{
char c = (char) * buf;
buf++;
newReadCount++;
if (c == _rxTerminator || c == 0x00)
{
_RXmode = ATB_RX_MODE_NONE;
_cbDone(true, _rxReadStringPtr);
return newReadCount;
}
else
{
(*_rxReadStringPtr) += c;
}
}
return newReadCount;
}
}
return 0;
}

View File

@@ -0,0 +1,93 @@
#ifndef RPAsyncTCP_BUFFER_H_
#define RPAsyncTCP_BUFFER_H_
#ifndef DEBUG_ASYNC_TCP
#define DEBUG_ASYNC_TCP(...)
#endif
#include <Arduino.h>
#include <cbuf.h>
#include "RPAsyncTCP.h"
typedef enum
{
ATB_RX_MODE_NONE,
ATB_RX_MODE_FREE,
ATB_RX_MODE_READ_BYTES,
ATB_RX_MODE_TERMINATOR,
ATB_RX_MODE_TERMINATOR_STRING
} atbRxMode_t;
/////////////////////////////////////////////////////////
class AsyncTCPbuffer: public Print
{
public:
typedef std::function<size_t(uint8_t * payload, size_t length)> AsyncTCPbufferDataCb;
typedef std::function<void(bool ok, void * ret)> AsyncTCPbufferDoneCb;
typedef std::function<bool(AsyncTCPbuffer * obj)> AsyncTCPbufferDisconnectCb;
AsyncTCPbuffer(AsyncClient* c);
virtual ~AsyncTCPbuffer();
size_t write(String & data);
size_t write(uint8_t data);
size_t write(const char* data);
size_t write(const char *data, size_t len);
size_t write(const uint8_t *data, size_t len);
void flush();
void noCallback();
void readStringUntil(char terminator, String * str, AsyncTCPbufferDoneCb done);
// TODO implement read terminator non string
//void readBytesUntil(char terminator, char *buffer, size_t length, AsyncTCPbufferDoneCb done);
//void readBytesUntil(char terminator, uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done);
void readBytes(char *buffer, size_t length, AsyncTCPbufferDoneCb done);
void readBytes(uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done);
// TODO implement
// void setTimeout(size_t timeout);
void onData(AsyncTCPbufferDataCb cb);
void onDisconnect(AsyncTCPbufferDisconnectCb cb);
IPAddress remoteIP();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
bool connected();
void stop();
void close();
protected:
AsyncClient* _client;
cbuf * _TXbufferRead;
cbuf * _TXbufferWrite;
cbuf * _RXbuffer;
atbRxMode_t _RXmode;
size_t _rxSize;
char _rxTerminator;
uint8_t * _rxReadBytesPtr;
String * _rxReadStringPtr;
AsyncTCPbufferDataCb _cbRX;
AsyncTCPbufferDoneCb _cbDone;
AsyncTCPbufferDisconnectCb _cbDisconnect;
void _attachCallbacks();
void _sendBuffer();
void _on_close();
void _rxData(uint8_t *buf, size_t len);
size_t _handleRxBuffer(uint8_t *buf, size_t len);
};
#endif /* RPAsyncTCP_BUFFER_H_ */

View File

@@ -0,0 +1,615 @@
#if !defined(_RPAsyncTCP_LOGLEVEL_)
#define _RPAsyncTCP_LOGLEVEL_ 1
#endif
#include "Arduino.h"
#include "SyncClient.h"
#include "RPAsyncTCP.h"
#include "cbuf.h"
#define DEBUG_ESP_SYNC_CLIENT
/////////////////////////////////////////////////////////
#if defined(DEBUG_ESP_SYNC_CLIENT) && !defined(SYNC_CLIENT_DEBUG)
#define SYNC_CLIENT_DEBUG( format, ...) DEBUG_GENERIC_P("[SYNC_CLIENT]", format, ##__VA_ARGS__)
#endif
/////////////////////////////////////////////////////////
#ifndef SYNC_CLIENT_DEBUG
#define SYNC_CLIENT_DEBUG(...) do { (void)0;} while(false)
#endif
/////////////////////////////////////////////////////////
/*
Without LWIP_NETIF_TX_SINGLE_PBUF, all tcp_writes default to "no copy".
Referenced data must be preserved and free-ed from the specified tcp_sent()
callback. Alternative, tcp_writes need to use the TCP_WRITE_FLAG_COPY
attribute.
*/
static_assert(LWIP_NETIF_TX_SINGLE_PBUF, "Required, tcp_write() must always copy.");
/////////////////////////////////////////////////////////
SyncClient::SyncClient(size_t txBufLen)
: _client(NULL)
, _tx_buffer(NULL)
, _tx_buffer_size(txBufLen)
, _rx_buffer(NULL)
, _ref(NULL)
{
ref();
}
/////////////////////////////////////////////////////////
SyncClient::SyncClient(AsyncClient *client, size_t txBufLen)
: _client(client)
, _tx_buffer(new (std::nothrow) cbuf(txBufLen))
, _tx_buffer_size(txBufLen)
, _rx_buffer(NULL)
, _ref(NULL)
{
if (ref() > 0 && _client != NULL)
_attachCallbacks();
}
/////////////////////////////////////////////////////////
SyncClient::~SyncClient()
{
if (0 == unref())
_release();
}
/////////////////////////////////////////////////////////
void SyncClient::_release()
{
if (_client != NULL)
{
_client->onData(NULL, NULL);
_client->onAck(NULL, NULL);
_client->onPoll(NULL, NULL);
_client->abort();
_client = NULL;
}
if (_tx_buffer != NULL)
{
cbuf *b = _tx_buffer;
_tx_buffer = NULL;
delete b;
}
while (_rx_buffer != NULL)
{
cbuf *b = _rx_buffer;
_rx_buffer = _rx_buffer->next;
delete b;
}
}
/////////////////////////////////////////////////////////
int SyncClient::ref()
{
if (_ref == NULL)
{
_ref = new (std::nothrow) int;
if (_ref != NULL)
*_ref = 0;
else
return -1;
}
return (++*_ref);
}
/////////////////////////////////////////////////////////
int SyncClient::unref()
{
int count = -1;
if (_ref != NULL)
{
count = --*_ref;
if (0 == count)
{
delete _ref;
_ref = NULL;
}
}
return count;
}
/////////////////////////////////////////////////////////
#if ASYNC_TCP_SSL_ENABLED
int SyncClient::_connect(const IPAddress& ip, uint16_t port, bool secure)
#else
int SyncClient::_connect(const IPAddress& ip, uint16_t port)
#endif
{
if (connected())
return 0;
if (_client != NULL)
delete _client;
_client = new (std::nothrow) AsyncClient();
if (_client == NULL)
return 0;
_client->onConnect([](void *obj, AsyncClient * c)
{
((SyncClient*)(obj))->_onConnect(c);
}, this);
_attachCallbacks_Disconnect();
#if ASYNC_TCP_SSL_ENABLED
if (_client->connect(ip, port, secure))
#else
if (_client->connect(ip, port))
#endif
{
while (_client != NULL && !_client->connected() && !_client->disconnecting())
delay(1);
return connected();
}
return 0;
}
/////////////////////////////////////////////////////////
#if ASYNC_TCP_SSL_ENABLED
int SyncClient::connect(const char *host, uint16_t port, bool secure)
#else
int SyncClient::connect(const char *host, uint16_t port)
#endif
{
if (connected())
return 0;
if (_client != NULL)
delete _client;
_client = new (std::nothrow) AsyncClient();
if (_client == NULL)
return 0;
_client->onConnect([](void *obj, AsyncClient * c)
{
((SyncClient*)(obj))->_onConnect(c);
}, this);
_attachCallbacks_Disconnect();
#if ASYNC_TCP_SSL_ENABLED
if (_client->connect(host, port, secure))
#else
if (_client->connect(host, port))
#endif
{
while (_client != NULL && !_client->connected() && !_client->disconnecting())
delay(1);
return connected();
}
return 0;
}
/////////////////////////////////////////////////////////
//#define SYNCCLIENT_NEW_OPERATOR_EQUAL
#ifdef SYNCCLIENT_NEW_OPERATOR_EQUAL
/*
New behavior for operator=
Allow for the object to be placed on a queue and transfered to a new container
with buffers still in tact. Avoiding receive data drops. Transfers rx and tx
buffers. Supports return by value.
Note, this is optional, the old behavior is the default.
*/
SyncClient & SyncClient::operator=(const SyncClient &other)
{
int *rhsref = other._ref;
++*rhsref; // Just in case the left and right side are the same object with different containers
if (0 == unref())
_release();
_ref = other._ref;
ref();
--*rhsref;
// Why do I not test _tx_buffer for != NULL and free?
// I allow for the lh target container, to be a copy of an active
// connection. Thus we are just reusing the container.
// The above unref() handles releaseing the previous client of the container.
_tx_buffer_size = other._tx_buffer_size;
_tx_buffer = other._tx_buffer;
_client = other._client;
if (_client != NULL && _tx_buffer == NULL)
_tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size);
_rx_buffer = other._rx_buffer;
if (_client)
_attachCallbacks();
return *this;
}
/////////////////////////////////////////////////////////
#else // ! SYNCCLIENT_NEW_OPERATOR_EQUAL
// This is the origianl logic with null checks
SyncClient & SyncClient::operator=(const SyncClient &other)
{
if (_client != NULL)
{
_client->abort();
_client->free();
_client = NULL;
}
_tx_buffer_size = other._tx_buffer_size;
if (_tx_buffer != NULL)
{
cbuf *b = _tx_buffer;
_tx_buffer = NULL;
delete b;
}
while (_rx_buffer != NULL)
{
cbuf *b = _rx_buffer;
_rx_buffer = b->next;
delete b;
}
if (other._client != NULL)
_tx_buffer = new (std::nothrow) cbuf(other._tx_buffer_size);
_client = other._client;
if (_client)
_attachCallbacks();
return *this;
}
#endif
/////////////////////////////////////////////////////////
void SyncClient::setTimeout(uint32_t seconds)
{
if (_client != NULL)
_client->setRxTimeout(seconds);
}
/////////////////////////////////////////////////////////
uint8_t SyncClient::status()
{
if (_client == NULL)
return 0;
return _client->state();
}
/////////////////////////////////////////////////////////
uint8_t SyncClient::connected()
{
return (_client != NULL && _client->connected());
}
/////////////////////////////////////////////////////////
bool SyncClient::stop(unsigned int maxWaitMs)
{
RPAsyncTCP_UNUSED(maxWaitMs);
if (_client != NULL)
_client->close(true);
return true;
}
/////////////////////////////////////////////////////////
size_t SyncClient::_sendBuffer()
{
if (_client == NULL || _tx_buffer == NULL)
return 0;
size_t available = _tx_buffer->available();
if ( !connected() || !_client->canSend() || (available == 0) )
return 0;
size_t sendable = _client->space();
if (sendable < available)
available = sendable;
char *out = new (std::nothrow) char[available];
if (out == NULL)
return 0;
_tx_buffer->read(out, available);
size_t sent = _client->write(out, available);
delete[] out;
return sent;
}
/////////////////////////////////////////////////////////
void SyncClient::_onData(void *data, size_t len)
{
_client->ackLater();
cbuf *b = new (std::nothrow) cbuf(len + 1);
if (b != NULL)
{
b->write((const char *)data, len);
if (_rx_buffer == NULL)
_rx_buffer = b;
else
{
cbuf *p = _rx_buffer;
while (p->next != NULL)
p = p->next;
p->next = b;
}
}
else
{
// We ran out of memory. This fail causes lost receive data.
// The connection should be closed in a manner that conveys something
// bad/abnormal has happened to the connection. Hence, we abort the
// connection to avoid possible data corruption.
// Note, callbacks maybe called.
_client->abort();
}
}
/////////////////////////////////////////////////////////
void SyncClient::_onDisconnect()
{
if (_client != NULL)
{
_client = NULL;
}
if (_tx_buffer != NULL)
{
cbuf *b = _tx_buffer;
_tx_buffer = NULL;
delete b;
}
}
/////////////////////////////////////////////////////////
void SyncClient::_onConnect(AsyncClient *c)
{
_client = c;
if (_tx_buffer != NULL)
{
cbuf *b = _tx_buffer;
_tx_buffer = NULL;
delete b;
}
_tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size);
_attachCallbacks_AfterConnected();
}
/////////////////////////////////////////////////////////
void SyncClient::_attachCallbacks()
{
_attachCallbacks_Disconnect();
_attachCallbacks_AfterConnected();
}
/////////////////////////////////////////////////////////
void SyncClient::_attachCallbacks_AfterConnected()
{
_client->onAck([](void *obj, AsyncClient * c, size_t len, uint32_t time)
{
RPAsyncTCP_UNUSED(c);
RPAsyncTCP_UNUSED(len);
RPAsyncTCP_UNUSED(time);
((SyncClient*)(obj))->_sendBuffer();
}, this);
_client->onData([](void *obj, AsyncClient * c, void *data, size_t len)
{ RPAsyncTCP_UNUSED(c);
((SyncClient*)(obj))->_onData(data, len);
}, this);
_client->onTimeout([](void *obj, AsyncClient * c, uint32_t time)
{
RPAsyncTCP_UNUSED(obj);
RPAsyncTCP_UNUSED(time);
c->close();
}, this);
}
/////////////////////////////////////////////////////////
void SyncClient::_attachCallbacks_Disconnect()
{
_client->onDisconnect([](void *obj, AsyncClient * c)
{
((SyncClient*)(obj))->_onDisconnect();
delete c;
}, this);
}
/////////////////////////////////////////////////////////
size_t SyncClient::write(uint8_t data)
{
return write(&data, 1);
}
/////////////////////////////////////////////////////////
size_t SyncClient::write(const uint8_t *data, size_t len)
{
if (_tx_buffer == NULL || !connected())
{
return 0;
}
size_t toWrite = 0;
size_t toSend = len;
while (_tx_buffer->room() < toSend)
{
toWrite = _tx_buffer->room();
_tx_buffer->write((const char*)data, toWrite);
while (connected() && !_client->canSend())
delay(0);
if (!connected())
return 0;
_sendBuffer();
toSend -= toWrite;
}
_tx_buffer->write((const char*)(data + (len - toSend)), toSend);
if (connected() && _client->canSend())
_sendBuffer();
return len;
}
/////////////////////////////////////////////////////////
int SyncClient::available()
{
if (_rx_buffer == NULL)
return 0;
size_t a = 0;
cbuf *b = _rx_buffer;
while (b != NULL)
{
a += b->available();
b = b->next;
}
return a;
}
/////////////////////////////////////////////////////////
int SyncClient::peek()
{
if (_rx_buffer == NULL)
return -1;
return _rx_buffer->peek();
}
/////////////////////////////////////////////////////////
int SyncClient::read(uint8_t *data, size_t len)
{
if (_rx_buffer == NULL)
return -1;
size_t readSoFar = 0;
while (_rx_buffer != NULL && (len - readSoFar) >= _rx_buffer->available())
{
cbuf *b = _rx_buffer;
_rx_buffer = _rx_buffer->next;
size_t toRead = b->available();
readSoFar += b->read((char*)(data + readSoFar), toRead);
if (connected())
{
_client->ack(b->size() - 1);
}
delete b;
}
if (_rx_buffer != NULL && readSoFar < len)
{
readSoFar += _rx_buffer->read((char*)(data + readSoFar), (len - readSoFar));
}
return readSoFar;
}
/////////////////////////////////////////////////////////
int SyncClient::read()
{
uint8_t res = 0;
if (read(&res, 1) != 1)
return -1;
return res;
}
/////////////////////////////////////////////////////////
bool SyncClient::flush(unsigned int maxWaitMs)
{
RPAsyncTCP_UNUSED(maxWaitMs);
if (_tx_buffer == NULL || !connected())
return false;
if (_tx_buffer->available())
{
while (connected() && !_client->canSend())
delay(0);
if (_client == NULL || _tx_buffer == NULL)
return false;
_sendBuffer();
}
return true;
}
/////////////////////////////////////////////////////////

View File

@@ -0,0 +1,125 @@
#ifndef SYNCCLIENT_H_
#define SYNCCLIENT_H_
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#include "Client.h"
// Needed for Arduino core releases prior to 2.5.0, because of changes
// made to accommodate Arduino core 2.5.0
// CONST was 1st defined in Core 2.5.0 in IPAddress.h
#ifndef CONST
#define CONST
#endif
#include <async_config.h>
class cbuf;
class AsyncClient;
/////////////////////////////////////////////////////////
class SyncClient: public Client
{
private:
AsyncClient *_client;
cbuf *_tx_buffer;
size_t _tx_buffer_size;
cbuf *_rx_buffer;
int *_ref;
size_t _sendBuffer();
void _onData(void *data, size_t len);
void _onConnect(AsyncClient *c);
void _onDisconnect();
void _attachCallbacks();
void _attachCallbacks_Disconnect();
void _attachCallbacks_AfterConnected();
void _release();
public:
SyncClient(size_t txBufLen = TCP_MSS);
SyncClient(AsyncClient *client, size_t txBufLen = TCP_MSS);
virtual ~SyncClient();
int ref();
int unref();
operator bool()
{
return connected();
}
SyncClient & operator=(const SyncClient &other);
#if ASYNC_TCP_SSL_ENABLED
int _connect(const IPAddress& ip, uint16_t port, bool secure);
int connect(CONST IPAddress& ip, uint16_t port, bool secure)
{
return _connect(ip, port, secure);
}
int connect(IPAddress ip, uint16_t port, bool secure)
{
return _connect(reinterpret_cast<const IPAddress&>(ip), port, secure);
}
int connect(const char *host, uint16_t port, bool secure);
int connect(CONST IPAddress& ip, uint16_t port)
{
return _connect(ip, port, false);
}
int connect(IPAddress ip, uint16_t port)
{
return _connect(reinterpret_cast<const IPAddress&>(ip), port, false);
}
int connect(const char *host, uint16_t port)
{
return connect(host, port, false);
}
#else
int _connect(const IPAddress& ip, uint16_t port);
int connect(CONST IPAddress& ip, uint16_t port)
{
return _connect(ip, port);
}
int connect(IPAddress ip, uint16_t port)
{
return _connect(reinterpret_cast<const IPAddress&>(ip), port);
}
int connect(const char *host, uint16_t port);
#endif
void setTimeout(uint32_t seconds);
uint8_t status();
uint8_t connected();
bool stop(unsigned int maxWaitMs);
bool flush(unsigned int maxWaitMs);
void stop()
{
(void)stop(0);
}
void flush()
{
(void)flush(0);
}
size_t write(uint8_t data);
size_t write(const uint8_t *data, size_t len);
int available();
int peek();
int read();
int read(uint8_t *data, size_t len);
};
#endif /* SYNCCLIENT_H_ */

View File

@@ -0,0 +1,12 @@
#ifndef _RP2040W_ASYNC_CONFIG_H_
#define _RP2040W_ASYNC_CONFIG_H_
#ifndef TCP_MSS
// May have been definded as a -DTCP_MSS option on the compile line or not.
// Arduino core 2.3.0 or earlier does not do the -DTCP_MSS option.
// Later versions may set this option with info from board.txt.
// However, Core 2.4.0 and up board.txt does not define TCP_MSS for lwIP v1.4
#define TCP_MSS MBED_CONF_LWIP_TCP_MSS //(1460)
#endif
#endif // _RP2040W_ASYNC_CONFIG_H_

View File

@@ -0,0 +1,109 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _C_TYPES_H_
#define _C_TYPES_H_
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <sys/cdefs.h>
typedef signed char sint8_t;
typedef signed short sint16_t;
typedef signed long sint32_t;
typedef signed long long sint64_t;
typedef unsigned long long u_int64_t;
typedef float real32_t;
typedef double real64_t;
typedef unsigned char uint8;
typedef unsigned char u8;
typedef signed char sint8;
typedef signed char int8;
typedef signed char s8;
typedef unsigned short uint16;
typedef unsigned short u16;
typedef signed short sint16;
typedef signed short s16;
typedef unsigned int uint32;
typedef unsigned int u_int;
typedef unsigned int u32;
typedef signed int sint32;
typedef signed int s32;
typedef int int32;
typedef signed long long sint64;
typedef unsigned long long uint64;
typedef unsigned long long u64;
typedef float real32;
typedef double real64;
#define __le16 u16
#define LOCAL static
#ifndef NULL
#define NULL (void *)0
#endif /* NULL */
/* probably should not put STATUS here */
typedef enum
{
OK = 0,
FAIL,
PENDING,
BUSY,
CANCEL,
} STATUS;
#define BIT(nr) (1UL << (nr))
#define REG_SET_BIT(_r, _b) (*(volatile uint32_t*)(_r) |= (_b))
#define REG_CLR_BIT(_r, _b) (*(volatile uint32_t*)(_r) &= ~(_b))
#define DMEM_ATTR __attribute__((section(".bss")))
#define SHMEM_ATTR
#ifdef ICACHE_FLASH
#define __ICACHE_STRINGIZE_NX(A) #A
#define __ICACHE_STRINGIZE(A) __ICACHE_STRINGIZE_NX(A)
#define ICACHE_FLASH_ATTR __attribute__((section("\".irom0.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\"")))
#define ICACHE_RAM_ATTR __attribute__((section("\".iram.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\"")))
#else
#define ICACHE_FLASH_ATTR
#define ICACHE_RAM_ATTR
#endif /* ICACHE_FLASH */
// counterpart https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp8266-compat.h
#define IRAM_ATTR ICACHE_RAM_ATTR
#define STORE_ATTR __attribute__((aligned(4)))
#ifndef __cplusplus
#define BOOL bool
#define TRUE true
#define FALSE false
#endif /* !__cplusplus */
#endif /* _C_TYPES_H_ */

View File

@@ -0,0 +1,221 @@
/*
cbuf.cpp - Circular buffer implementation
Copyright (c) 2014 Ivan Grokhotkov. 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
*/
#include "cbuf.h"
#include "c_types.h"
cbuf::cbuf(size_t size) :
next(NULL), _size(size), _buf(new char[size]), _bufend(_buf + size), _begin(_buf), _end(_begin)
{
}
cbuf::~cbuf()
{
delete[] _buf;
}
size_t cbuf::resizeAdd(size_t addSize)
{
return resize(_size + addSize);
}
size_t cbuf::resize(size_t newSize)
{
size_t bytes_available = available();
// not lose any data
// if data can be lost use remove or flush before resize
if ((newSize <= bytes_available) || (newSize == _size))
{
return _size;
}
char *newbuf = new char[newSize];
char *oldbuf = _buf;
if (!newbuf)
{
return _size;
}
if (_buf)
{
read(newbuf, bytes_available);
memset((newbuf + bytes_available), 0x00, (newSize - bytes_available));
}
_begin = newbuf;
_end = newbuf + bytes_available;
_bufend = newbuf + newSize;
_size = newSize;
_buf = newbuf;
delete[] oldbuf;
return _size;
}
size_t ICACHE_RAM_ATTR cbuf::available() const
{
if (_end >= _begin)
{
return _end - _begin;
}
return _size - (_begin - _end);
}
size_t cbuf::size()
{
return _size;
}
size_t cbuf::room() const
{
if (_end >= _begin)
{
return _size - (_end - _begin) - 1;
}
return _begin - _end - 1;
}
int cbuf::peek()
{
if (empty())
return -1;
return static_cast<int>(*_begin);
}
size_t cbuf::peek(char *dst, size_t size)
{
size_t bytes_available = available();
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
size_t size_read = size_to_read;
char * begin = _begin;
if (_end < _begin && size_to_read > (size_t) (_bufend - _begin))
{
size_t top_size = _bufend - _begin;
memcpy(dst, _begin, top_size);
begin = _buf;
size_to_read -= top_size;
dst += top_size;
}
memcpy(dst, begin, size_to_read);
return size_read;
}
int ICACHE_RAM_ATTR cbuf::read()
{
if (empty())
return -1;
char result = *_begin;
_begin = wrap_if_bufend(_begin + 1);
return static_cast<int>(result);
}
size_t cbuf::read(char* dst, size_t size)
{
size_t bytes_available = available();
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
size_t size_read = size_to_read;
if (_end < _begin && size_to_read > (size_t) (_bufend - _begin))
{
size_t top_size = _bufend - _begin;
memcpy(dst, _begin, top_size);
_begin = _buf;
size_to_read -= top_size;
dst += top_size;
}
memcpy(dst, _begin, size_to_read);
_begin = wrap_if_bufend(_begin + size_to_read);
return size_read;
}
size_t ICACHE_RAM_ATTR cbuf::write(char c)
{
if (full())
return 0;
*_end = c;
_end = wrap_if_bufend(_end + 1);
return 1;
}
size_t cbuf::write(const char* src, size_t size)
{
size_t bytes_available = room();
size_t size_to_write = (size < bytes_available) ? size : bytes_available;
size_t size_written = size_to_write;
if (_end >= _begin && size_to_write > (size_t) (_bufend - _end))
{
size_t top_size = _bufend - _end;
memcpy(_end, src, top_size);
_end = _buf;
size_to_write -= top_size;
src += top_size;
}
memcpy(_end, src, size_to_write);
_end = wrap_if_bufend(_end + size_to_write);
return size_written;
}
void cbuf::flush()
{
_begin = _buf;
_end = _buf;
}
size_t cbuf::remove(size_t size)
{
size_t bytes_available = available();
if (size >= bytes_available)
{
flush();
return 0;
}
size_t size_to_remove = (size < bytes_available) ? size : bytes_available;
if (_end < _begin && size_to_remove > (size_t) (_bufend - _begin))
{
size_t top_size = _bufend - _begin;
_begin = _buf;
size_to_remove -= top_size;
}
_begin = wrap_if_bufend(_begin + size_to_remove);
return available();
}

View File

@@ -0,0 +1,78 @@
/*
cbuf.h - Circular buffer implementation
Copyright (c) 2014 Ivan Grokhotkov. 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 __cbuf_h
#define __cbuf_h
#include <stddef.h>
#include <stdint.h>
#include <string.h>
class cbuf
{
public:
cbuf(size_t size);
~cbuf();
size_t resizeAdd(size_t addSize);
size_t resize(size_t newSize);
size_t available() const;
size_t size();
size_t room() const;
inline bool empty() const
{
return _begin == _end;
}
inline bool full() const
{
return wrap_if_bufend(_end + 1) == _begin;
}
int peek();
size_t peek(char *dst, size_t size);
int read();
size_t read(char* dst, size_t size);
size_t write(char c);
size_t write(const char* src, size_t size);
void flush();
size_t remove(size_t size);
cbuf *next;
private:
inline char* wrap_if_bufend(char* ptr) const
{
return (ptr == _bufend) ? _buf : ptr;
}
size_t _size;
char* _buf;
const char* _bufend;
char* _begin;
char* _end;
};
#endif//__cbuf_h

View File

@@ -0,0 +1,4 @@
void panic()
{
}

View File

@@ -0,0 +1,6 @@
#ifndef DEBUG_H_
#define DEBUG_H_
void panic();
#endif

View File

@@ -0,0 +1,802 @@
#if !defined(_RPAsyncTCP_LOGLEVEL_)
#define _RPAsyncTCP_LOGLEVEL_ 1
#endif
#include <async_config.h>
#if ASYNC_TCP_SSL_ENABLED
#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "lwip/inet.h"
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include <tcp_axtls.h>
uint8_t * default_private_key = NULL;
uint16_t default_private_key_len = 0;
uint8_t * default_certificate = NULL;
uint16_t default_certificate_len = 0;
static uint8_t _tcp_ssl_has_client = 0;
/////////////////////////////////////////////////////////
SSL_CTX * tcp_ssl_new_server_ctx(const char *cert, const char *private_key_file, const char *password)
{
uint32_t options = SSL_CONNECT_IN_PARTS;
SSL_CTX *ssl_ctx;
if (private_key_file)
{
options |= SSL_NO_DEFAULT_KEY;
}
if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_SVR_SESS)) == NULL)
{
TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: failed to allocate context\n");
return NULL;
}
if (private_key_file)
{
int obj_type = SSL_OBJ_RSA_KEY;
if (strstr(private_key_file, ".p8"))
obj_type = SSL_OBJ_PKCS8;
else if (strstr(private_key_file, ".p12"))
obj_type = SSL_OBJ_PKCS12;
if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password))
{
TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: load private key '%s' failed\n", private_key_file);
return NULL;
}
}
if (cert)
{
if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert, NULL))
{
TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: load certificate '%s' failed\n", cert);
return NULL;
}
}
return ssl_ctx;
}
/////////////////////////////////////////////////////////
struct tcp_ssl_pcb
{
struct tcp_pcb *tcp;
int fd;
SSL_CTX* ssl_ctx;
SSL *ssl;
uint8_t type;
int handshake;
void * arg;
tcp_ssl_data_cb_t on_data;
tcp_ssl_handshake_cb_t on_handshake;
tcp_ssl_error_cb_t on_error;
int last_wr;
struct pbuf *tcp_pbuf;
int pbuf_offset;
struct tcp_ssl_pcb * next;
};
typedef struct tcp_ssl_pcb tcp_ssl_t;
static tcp_ssl_t * tcp_ssl_array = NULL;
static int tcp_ssl_next_fd = 0;
/////////////////////////////////////////////////////////
uint8_t tcp_ssl_has_client()
{
return _tcp_ssl_has_client;
}
/////////////////////////////////////////////////////////
tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp)
{
if (tcp_ssl_next_fd < 0)
{
tcp_ssl_next_fd = 0;//overflow
}
tcp_ssl_t * new_item = (tcp_ssl_t*)malloc(sizeof(tcp_ssl_t));
if (!new_item)
{
TCP_SSL_DEBUG("tcp_ssl_new: failed to allocate tcp_ssl\n");
return NULL;
}
new_item->tcp = tcp;
new_item->handshake = SSL_NOT_OK;
new_item->arg = NULL;
new_item->on_data = NULL;
new_item->on_handshake = NULL;
new_item->on_error = NULL;
new_item->tcp_pbuf = NULL;
new_item->pbuf_offset = 0;
new_item->next = NULL;
new_item->ssl_ctx = NULL;
new_item->ssl = NULL;
new_item->type = TCP_SSL_TYPE_CLIENT;
new_item->fd = tcp_ssl_next_fd++;
if (tcp_ssl_array == NULL)
{
tcp_ssl_array = new_item;
}
else
{
tcp_ssl_t * item = tcp_ssl_array;
while (item->next != NULL)
item = item->next;
item->next = new_item;
}
TCP_SSL_DEBUG("tcp_ssl_new: %d\n", new_item->fd);
return new_item;
}
/////////////////////////////////////////////////////////
tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp)
{
if (tcp == NULL)
{
return NULL;
}
tcp_ssl_t * item = tcp_ssl_array;
while (item && item->tcp != tcp)
{
item = item->next;
}
return item;
}
/////////////////////////////////////////////////////////
int tcp_ssl_new_client(struct tcp_pcb *tcp)
{
SSL_CTX* ssl_ctx;
tcp_ssl_t * tcp_ssl;
if (tcp == NULL)
{
return -1;
}
if (tcp_ssl_get(tcp) != NULL)
{
TCP_SSL_DEBUG("tcp_ssl_new_client: tcp_ssl already exists\n");
return -1;
}
ssl_ctx = ssl_ctx_new(SSL_CONNECT_IN_PARTS | SSL_SERVER_VERIFY_LATER, 1);
if (ssl_ctx == NULL)
{
TCP_SSL_DEBUG("tcp_ssl_new_client: failed to allocate ssl context\n");
return -1;
}
tcp_ssl = tcp_ssl_new(tcp);
if (tcp_ssl == NULL)
{
ssl_ctx_free(ssl_ctx);
return -1;
}
tcp_ssl->ssl_ctx = ssl_ctx;
tcp_ssl->ssl = ssl_client_new(ssl_ctx, tcp_ssl->fd, NULL, 0, NULL);
if (tcp_ssl->ssl == NULL)
{
TCP_SSL_DEBUG("tcp_ssl_new_client: failed to allocate ssl\n");
tcp_ssl_free(tcp);
return -1;
}
return tcp_ssl->fd;
}
/////////////////////////////////////////////////////////
int tcp_ssl_new_server(struct tcp_pcb *tcp, SSL_CTX* ssl_ctx)
{
tcp_ssl_t * tcp_ssl;
if (tcp == NULL)
{
return -1;
}
if (ssl_ctx == NULL)
{
return -1;
}
if (tcp_ssl_get(tcp) != NULL)
{
TCP_SSL_DEBUG("tcp_ssl_new_server: tcp_ssl already exists\n");
return -1;
}
tcp_ssl = tcp_ssl_new(tcp);
if (tcp_ssl == NULL)
{
return -1;
}
tcp_ssl->type = TCP_SSL_TYPE_SERVER;
tcp_ssl->ssl_ctx = ssl_ctx;
_tcp_ssl_has_client = 1;
tcp_ssl->ssl = ssl_server_new(ssl_ctx, tcp_ssl->fd);
if (tcp_ssl->ssl == NULL)
{
TCP_SSL_DEBUG("tcp_ssl_new_server: failed to allocate ssl\n");
tcp_ssl_free(tcp);
return -1;
}
return tcp_ssl->fd;
}
/////////////////////////////////////////////////////////
int tcp_ssl_free(struct tcp_pcb *tcp)
{
if (tcp == NULL)
{
return -1;
}
tcp_ssl_t * item = tcp_ssl_array;
if (item->tcp == tcp)
{
tcp_ssl_array = tcp_ssl_array->next;
if (item->tcp_pbuf != NULL)
{
pbuf_free(item->tcp_pbuf);
}
TCP_SSL_DEBUG("tcp_ssl_free: %d\n", item->fd);
if (item->ssl)
ssl_free(item->ssl);
if (item->type == TCP_SSL_TYPE_CLIENT && item->ssl_ctx)
ssl_ctx_free(item->ssl_ctx);
if (item->type == TCP_SSL_TYPE_SERVER)
_tcp_ssl_has_client = 0;
free(item);
return 0;
}
while (item->next && item->next->tcp != tcp)
item = item->next;
if (item->next == NULL)
{
return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found
}
tcp_ssl_t * i = item->next;
item->next = i->next;
if (i->tcp_pbuf != NULL)
{
pbuf_free(i->tcp_pbuf);
}
TCP_SSL_DEBUG("tcp_ssl_free: %d\n", i->fd);
if (i->ssl)
ssl_free(i->ssl);
if (i->type == TCP_SSL_TYPE_CLIENT && i->ssl_ctx)
ssl_ctx_free(i->ssl_ctx);
if (i->type == TCP_SSL_TYPE_SERVER)
_tcp_ssl_has_client = 0;
free(i);
return 0;
}
/////////////////////////////////////////////////////////
#ifdef AXTLS_2_0_0_SNDBUF
int tcp_ssl_sndbuf(struct tcp_pcb *tcp)
{
int expected;
int available;
int result = -1;
if (tcp == NULL)
{
return result;
}
tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp);
if (!tcp_ssl)
{
TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_ssl is NULL\n");
return result;
}
available = tcp_sndbuf(tcp);
if (!available)
{
TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_sndbuf is zero\n");
return 0;
}
result = available;
while ((expected = ssl_calculate_write_length(tcp_ssl->ssl, result)) > available)
{
result -= (expected - available) + 4;
}
if (expected > 0)
{
//TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_sndbuf is %d from %d\n", result, available);
return result;
}
return 0;
}
#endif // AXTLS_2_0_0_SNDBUF
/////////////////////////////////////////////////////////
int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len)
{
if (tcp == NULL)
{
return -1;
}
tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp);
if (!tcp_ssl)
{
TCP_SSL_DEBUG("tcp_ssl_write: tcp_ssl is NULL\n");
return 0;
}
tcp_ssl->last_wr = 0;
#ifdef AXTLS_2_0_0_SNDBUF
int expected_len = ssl_calculate_write_length(tcp_ssl->ssl, len);
int available_len = tcp_sndbuf(tcp);
if (expected_len < 0 || expected_len > available_len)
{
TCP_SSL_DEBUG("tcp_ssl_write: data will not fit! %u < %d(%u)\r\n", available_len, expected_len, len);
return -1;
}
#endif // AXTLS_2_0_0_SNDBUF
int rc = ssl_write(tcp_ssl->ssl, data, len);
//TCP_SSL_DEBUG("tcp_ssl_write: %u -> %d (%d)\r\n", len, tcp_ssl->last_wr, rc);
if (rc < 0)
{
if (rc != SSL_CLOSE_NOTIFY)
{
TCP_SSL_DEBUG("tcp_ssl_write error: %d\r\n", rc);
}
return rc;
}
return tcp_ssl->last_wr;
}
/////////////////////////////////////////////////////////
/**
Reads data from the SSL over TCP stream. Returns decrypted data.
@param tcp_pcb *tcp - pointer to the raw tcp object
@param pbuf *p - pointer to the buffer with the TCP packet data
@return int
0 - when everything is fine but there are no symbols to process yet
< 0 - when there is an error
> 0 - the length of the clear text characters that were read
*/
int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p)
{
if (tcp == NULL)
{
return -1;
}
tcp_ssl_t* fd_data = NULL;
int read_bytes = 0;
int total_bytes = 0;
uint8_t *read_buf;
fd_data = tcp_ssl_get(tcp);
if (fd_data == NULL)
{
TCP_SSL_DEBUG("tcp_ssl_read: tcp_ssl is NULL\n");
return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;
}
if (p == NULL)
{
TCP_SSL_DEBUG("tcp_ssl_read:p == NULL\n");
return ERR_TCP_SSL_INVALID_DATA;
}
//TCP_SSL_DEBUG("READY TO READ SOME DATA\n");
fd_data->tcp_pbuf = p;
fd_data->pbuf_offset = 0;
do
{
read_bytes = ssl_read(fd_data->ssl, &read_buf);
//TCP_SSL_DEBUG("tcp_ssl_ssl_read: %d\n", read_bytes);
if (read_bytes < SSL_OK)
{
if (read_bytes != SSL_CLOSE_NOTIFY)
{
TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes);
}
total_bytes = read_bytes;
break;
}
else if (read_bytes > 0)
{
if (fd_data->on_data)
{
fd_data->on_data(fd_data->arg, tcp, read_buf, read_bytes);
}
total_bytes += read_bytes;
}
else
{
if (fd_data->handshake != SSL_OK)
{
fd_data->handshake = ssl_handshake_status(fd_data->ssl);
if (fd_data->handshake == SSL_OK)
{
//TCP_SSL_DEBUG("tcp_ssl_read: handshake OK\n");
if (fd_data->on_handshake)
fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data->ssl);
}
else if (fd_data->handshake != SSL_NOT_OK)
{
TCP_SSL_DEBUG("tcp_ssl_read: handshake error: %d\n", fd_data->handshake);
if (fd_data->on_error)
fd_data->on_error(fd_data->arg, fd_data->tcp, fd_data->handshake);
return fd_data->handshake;
}
}
}
} while (p->tot_len - fd_data->pbuf_offset > 0);
tcp_recved(tcp, p->tot_len);
fd_data->tcp_pbuf = NULL;
pbuf_free(p);
return total_bytes;
}
/////////////////////////////////////////////////////////
SSL * tcp_ssl_get_ssl(struct tcp_pcb *tcp)
{
tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp);
if (tcp_ssl)
{
return tcp_ssl->ssl;
}
return NULL;
}
/////////////////////////////////////////////////////////
bool tcp_ssl_has(struct tcp_pcb *tcp)
{
return tcp_ssl_get(tcp) != NULL;
}
/////////////////////////////////////////////////////////
int tcp_ssl_is_server(struct tcp_pcb *tcp)
{
tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp);
if (tcp_ssl)
{
return tcp_ssl->type;
}
return -1;
}
/////////////////////////////////////////////////////////
void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg)
{
tcp_ssl_t * item = tcp_ssl_get(tcp);
if (item)
{
item->arg = arg;
}
}
/////////////////////////////////////////////////////////
void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg)
{
tcp_ssl_t * item = tcp_ssl_get(tcp);
if (item)
{
item->on_data = arg;
}
}
/////////////////////////////////////////////////////////
void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg)
{
tcp_ssl_t * item = tcp_ssl_get(tcp);
if (item)
{
item->on_handshake = arg;
}
}
/////////////////////////////////////////////////////////
void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg)
{
tcp_ssl_t * item = tcp_ssl_get(tcp);
if (item)
{
item->on_error = arg;
}
}
/////////////////////////////////////////////////////////
static tcp_ssl_file_cb_t _tcp_ssl_file_cb = NULL;
static void * _tcp_ssl_file_arg = NULL;
/////////////////////////////////////////////////////////
void tcp_ssl_file(tcp_ssl_file_cb_t cb, void * arg)
{
_tcp_ssl_file_cb = cb;
_tcp_ssl_file_arg = arg;
}
/////////////////////////////////////////////////////////
int ax_get_file(const char *filename, uint8_t **buf)
{
//TCP_SSL_DEBUG("ax_get_file: %s\n", filename);
if (_tcp_ssl_file_cb)
{
return _tcp_ssl_file_cb(_tcp_ssl_file_arg, filename, buf);
}
*buf = 0;
return 0;
}
/////////////////////////////////////////////////////////
tcp_ssl_t* tcp_ssl_get_by_fd(int fd)
{
tcp_ssl_t * item = tcp_ssl_array;
while (item && item->fd != fd)
{
item = item->next;
}
return item;
}
/////////////////////////////////////////////////////////
/*
The LWIP tcp raw version of the SOCKET_WRITE(A, B, C)
*/
int ax_port_write(int fd, uint8_t *data, uint16_t len)
{
tcp_ssl_t *fd_data = NULL;
int tcp_len = 0;
err_t err = ERR_OK;
//TCP_SSL_DEBUG("ax_port_write: %d, %d\n", fd, len);
fd_data = tcp_ssl_get_by_fd(fd);
if (fd_data == NULL)
{
//TCP_SSL_DEBUG("ax_port_write: tcp_ssl[%d] is NULL\n", fd);
return ERR_MEM;
}
if (data == NULL || len == 0)
{
return 0;
}
if (tcp_sndbuf(fd_data->tcp) < len)
{
tcp_len = tcp_sndbuf(fd_data->tcp);
if (tcp_len == 0)
{
TCP_SSL_DEBUG("ax_port_write: tcp_sndbuf is zero: %d\n", len);
return ERR_MEM;
}
}
else
{
tcp_len = len;
}
if (tcp_len > 2 * fd_data->tcp->mss)
{
tcp_len = 2 * fd_data->tcp->mss;
}
err = tcp_write(fd_data->tcp, data, tcp_len, TCP_WRITE_FLAG_COPY);
if (err < ERR_OK)
{
if (err == ERR_MEM)
{
TCP_SSL_DEBUG("ax_port_write: No memory %d (%d)\n", tcp_len, len);
return err;
}
TCP_SSL_DEBUG("ax_port_write: tcp_write error: %d\n", err);
return err;
}
else if (err == ERR_OK)
{
//TCP_SSL_DEBUG("ax_port_write: tcp_output: %d / %d\n", tcp_len, len);
err = tcp_output(fd_data->tcp);
if (err != ERR_OK)
{
TCP_SSL_DEBUG("ax_port_write: tcp_output err: %d\n", err);
return err;
}
}
fd_data->last_wr += tcp_len;
return tcp_len;
}
/////////////////////////////////////////////////////////
/*
The LWIP tcp raw version of the SOCKET_READ(A, B, C)
*/
int ax_port_read(int fd, uint8_t *data, int len)
{
tcp_ssl_t *fd_data = NULL;
uint8_t *read_buf = NULL;
uint8_t *pread_buf = NULL;
u16_t recv_len = 0;
//TCP_SSL_DEBUG("ax_port_read: %d, %d\n", fd, len);
fd_data = tcp_ssl_get_by_fd(fd);
if (fd_data == NULL)
{
TCP_SSL_DEBUG("ax_port_read: tcp_ssl[%d] is NULL\n", fd);
return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;
}
if (fd_data->tcp_pbuf == NULL || fd_data->tcp_pbuf->tot_len == 0)
{
return 0;
}
read_buf = (uint8_t*) calloc(fd_data->tcp_pbuf->len + 1, sizeof(uint8_t));
pread_buf = read_buf;
if (pread_buf != NULL)
{
recv_len = pbuf_copy_partial(fd_data->tcp_pbuf, read_buf, len, fd_data->pbuf_offset);
fd_data->pbuf_offset += recv_len;
}
if (recv_len != 0)
{
memcpy(data, read_buf, recv_len);
}
if (len < recv_len)
{
TCP_SSL_DEBUG("ax_port_read: got %d bytes more than expected\n", recv_len - len);
}
free(pread_buf);
pread_buf = NULL;
return recv_len;
}
/////////////////////////////////////////////////////////
void ax_wdt_feed() {}
/////////////////////////////////////////////////////////
#endif // ASYNC_TCP_SSL_ENABLED

View File

@@ -0,0 +1,73 @@
#ifndef LWIPR_COMPAT_H
#define LWIPR_COMPAT_H
#include <async_config.h>
#if ASYNC_TCP_SSL_ENABLED
#include "lwipopts.h"
/*
All those functions will run only if LWIP tcp raw mode is used
*/
#if LWIP_RAW==1
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "include/ssl.h"
#define ERR_TCP_SSL_INVALID_SSL -101
#define ERR_TCP_SSL_INVALID_TCP -102
#define ERR_TCP_SSL_INVALID_CLIENTFD -103
#define ERR_TCP_SSL_INVALID_CLIENTFD_DATA -104
#define ERR_TCP_SSL_INVALID_DATA -105
#define TCP_SSL_TYPE_CLIENT 0
#define TCP_SSL_TYPE_SERVER 1
#define tcp_ssl_ssl_write(A, B, C) tcp_ssl_write(A, B, C)
#define tcp_ssl_ssl_read(A, B) tcp_ssl_read(A, B)
typedef void (* tcp_ssl_data_cb_t)(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len);
typedef void (* tcp_ssl_handshake_cb_t)(void *arg, struct tcp_pcb *tcp, SSL *ssl);
typedef void (* tcp_ssl_error_cb_t)(void *arg, struct tcp_pcb *tcp, int8_t error);
typedef int (* tcp_ssl_file_cb_t)(void *arg, const char *filename, uint8_t **buf);
uint8_t tcp_ssl_has_client();
int tcp_ssl_new_client(struct tcp_pcb *tcp);
SSL_CTX * tcp_ssl_new_server_ctx(const char *cert, const char *private_key_file, const char *password);
int tcp_ssl_new_server(struct tcp_pcb *tcp, SSL_CTX* ssl_ctx);
int tcp_ssl_is_server(struct tcp_pcb *tcp);
int tcp_ssl_free(struct tcp_pcb *tcp);
int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p);
#ifdef AXTLS_2_0_0_SNDBUF
int tcp_ssl_sndbuf(struct tcp_pcb *tcp);
#endif
int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len);
void tcp_ssl_file(tcp_ssl_file_cb_t cb, void * arg);
void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg);
void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg);
void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg);
void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg);
SSL * tcp_ssl_get_ssl(struct tcp_pcb *tcp);
bool tcp_ssl_has(struct tcp_pcb *tcp);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_RAW==1 */
#endif /* ASYNC_TCP_SSL_ENABLED */
#endif /* LWIPR_COMPAT_H */