mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-06 03:50:13 +02:00
Revert the AsyncTCP library change with AsyncTCPsock
This commit is contained in:
parent
dda8afce1e
commit
8b83f54087
23 changed files with 2106 additions and 2304 deletions
|
@ -4,10 +4,10 @@
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include "../../include.h"
|
#include "../../include.h"
|
||||||
#include "../../lib/ESP32Async-AsyncTCP/src/AsyncTCP.h"
|
|
||||||
#include "../../lib/ESP32Async-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
|
#include "../../lib/ESP32Async-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
|
||||||
#include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h"
|
#include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h"
|
||||||
#include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h"
|
#include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h"
|
||||||
|
#include "../../lib/mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||||
|
|
||||||
extern const char* version_number; // The current software version, shown on webserver
|
extern const char* version_number; // The current software version, shown on webserver
|
||||||
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
set(COMPONENT_SRCDIRS
|
|
||||||
"src"
|
|
||||||
)
|
|
||||||
|
|
||||||
set(COMPONENT_ADD_INCLUDEDIRS
|
|
||||||
"src"
|
|
||||||
)
|
|
||||||
|
|
||||||
set(COMPONENT_REQUIRES
|
|
||||||
"arduino-esp32"
|
|
||||||
)
|
|
||||||
|
|
||||||
register_component()
|
|
||||||
|
|
||||||
target_compile_options(${COMPONENT_TARGET} PRIVATE -fno-rtti)
|
|
|
@ -1,129 +0,0 @@
|
||||||
|
|
||||||
# Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
We as members, contributors, and leaders pledge to make participation in our
|
|
||||||
community a harassment-free experience for everyone, regardless of age, body
|
|
||||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
||||||
identity and expression, level of experience, education, socioeconomic status,
|
|
||||||
nationality, personal appearance, race, religion, or sexual identity
|
|
||||||
and orientation.
|
|
||||||
|
|
||||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
||||||
diverse, inclusive, and healthy community.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to a positive environment for our
|
|
||||||
community include:
|
|
||||||
|
|
||||||
* Demonstrating empathy and kindness toward other people
|
|
||||||
* Being respectful of differing opinions, viewpoints, and experiences
|
|
||||||
* Giving and gracefully accepting constructive feedback
|
|
||||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
||||||
and learning from the experience
|
|
||||||
* Focusing on what is best not just for us as individuals, but for the
|
|
||||||
overall community
|
|
||||||
|
|
||||||
Examples of unacceptable behavior include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery, and sexual attention or
|
|
||||||
advances of any kind
|
|
||||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or email
|
|
||||||
address, without their explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
|
||||||
professional setting
|
|
||||||
|
|
||||||
## Enforcement Responsibilities
|
|
||||||
|
|
||||||
Community leaders are responsible for clarifying and enforcing our standards of
|
|
||||||
acceptable behavior and will take appropriate and fair corrective action in
|
|
||||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
||||||
or harmful.
|
|
||||||
|
|
||||||
Community leaders have the right and responsibility to remove, edit, or reject
|
|
||||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
||||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
||||||
decisions when appropriate.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies within all community spaces, and also applies when
|
|
||||||
an individual is officially representing the community in public spaces.
|
|
||||||
Examples of representing our community include using an official e-mail address,
|
|
||||||
posting via an official social media account, or acting as an appointed
|
|
||||||
representative at an online or offline event.
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
||||||
reported to the community leaders responsible for enforcement at
|
|
||||||
https://sidweb.nl/cms3/en/contact.
|
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
|
||||||
reporter of any incident.
|
|
||||||
|
|
||||||
## Enforcement Guidelines
|
|
||||||
|
|
||||||
Community leaders will follow these Community Impact Guidelines in determining
|
|
||||||
the consequences for any action they deem in violation of this Code of Conduct:
|
|
||||||
|
|
||||||
### 1. Correction
|
|
||||||
|
|
||||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
|
||||||
unprofessional or unwelcome in the community.
|
|
||||||
|
|
||||||
**Consequence**: A private, written warning from community leaders, providing
|
|
||||||
clarity around the nature of the violation and an explanation of why the
|
|
||||||
behavior was inappropriate. A public apology may be requested.
|
|
||||||
|
|
||||||
### 2. Warning
|
|
||||||
|
|
||||||
**Community Impact**: A violation through a single incident or series
|
|
||||||
of actions.
|
|
||||||
|
|
||||||
**Consequence**: A warning with consequences for continued behavior. No
|
|
||||||
interaction with the people involved, including unsolicited interaction with
|
|
||||||
those enforcing the Code of Conduct, for a specified period of time. This
|
|
||||||
includes avoiding interactions in community spaces as well as external channels
|
|
||||||
like social media. Violating these terms may lead to a temporary or
|
|
||||||
permanent ban.
|
|
||||||
|
|
||||||
### 3. Temporary Ban
|
|
||||||
|
|
||||||
**Community Impact**: A serious violation of community standards, including
|
|
||||||
sustained inappropriate behavior.
|
|
||||||
|
|
||||||
**Consequence**: A temporary ban from any sort of interaction or public
|
|
||||||
communication with the community for a specified period of time. No public or
|
|
||||||
private interaction with the people involved, including unsolicited interaction
|
|
||||||
with those enforcing the Code of Conduct, is allowed during this period.
|
|
||||||
Violating these terms may lead to a permanent ban.
|
|
||||||
|
|
||||||
### 4. Permanent Ban
|
|
||||||
|
|
||||||
**Community Impact**: Demonstrating a pattern of violation of community
|
|
||||||
standards, including sustained inappropriate behavior, harassment of an
|
|
||||||
individual, or aggression toward or disparagement of classes of individuals.
|
|
||||||
|
|
||||||
**Consequence**: A permanent ban from any sort of public interaction within
|
|
||||||
the community.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
||||||
version 2.0, available at
|
|
||||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
|
||||||
|
|
||||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
|
||||||
enforcement ladder](https://github.com/mozilla/diversity).
|
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see the FAQ at
|
|
||||||
https://www.contributor-covenant.org/faq. Translations are available at
|
|
||||||
https://www.contributor-covenant.org/translations.
|
|
|
@ -1,55 +0,0 @@
|
||||||

|
|
||||||
|
|
||||||
# AsyncTCP
|
|
||||||
|
|
||||||
[](https://opensource.org/license/lgpl-3-0/)
|
|
||||||
[](https://github.com/ESP32Async/AsyncTCP/actions/workflows/ci.yml)
|
|
||||||
[](https://registry.platformio.org/libraries/ESP32Async/AsyncTCP)
|
|
||||||
|
|
||||||
Discord Server: [https://discord.gg/X7zpGdyUcY](https://discord.gg/X7zpGdyUcY)
|
|
||||||
|
|
||||||
## Async TCP Library for ESP32 Arduino
|
|
||||||
|
|
||||||
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/ESP32Async/ESPAsyncWebServer)
|
|
||||||
|
|
||||||
## How to install
|
|
||||||
|
|
||||||
The library can be downloaded from the releases page at [https://github.com/ESP32Async/AsyncTCP/releases](https://github.com/ESP32Async/AsyncTCP/releases).
|
|
||||||
|
|
||||||
It is also deployed in these registries:
|
|
||||||
|
|
||||||
- Arduino Library Registry: [https://github.com/arduino/library-registry](https://github.com/arduino/library-registry)
|
|
||||||
|
|
||||||
- ESP Component Registry [https://components.espressif.com/components/esp32async/asynctcp/](https://components.espressif.com/components/esp32async/asynctcp/)
|
|
||||||
|
|
||||||
- PlatformIO Registry: [https://registry.platformio.org/libraries/esp32async/AsyncTCP](https://registry.platformio.org/libraries/esp32async/AsyncTCP)
|
|
||||||
|
|
||||||
- Use: `lib_deps=ESP32Async/AsyncTCP` to point to latest version
|
|
||||||
- Use: `lib_deps=ESP32Async/AsyncTCP @ ^<x.y.z>` to point to latest version with the same major version
|
|
||||||
- Use: `lib_deps=ESP32Async/AsyncTCP @ <x.y.z>` to always point to the same version (reproductible build)
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
## Important recommendations
|
|
||||||
|
|
||||||
Most of the crashes are caused by improper configuration of the library for the project.
|
|
||||||
Here are some recommendations to avoid them.
|
|
||||||
|
|
||||||
I personally use the following configuration in my projects:
|
|
||||||
|
|
||||||
```c++
|
|
||||||
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 // (keep default)
|
|
||||||
-D CONFIG_ASYNC_TCP_PRIORITY=10 // (keep default)
|
|
||||||
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 // (keep default)
|
|
||||||
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1 // force async_tcp task to be on same core as the app (default is core 0)
|
|
||||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=4096 // reduce the stack size (default is 16K)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Compatibility
|
|
||||||
|
|
||||||
- ESP32
|
|
||||||
- Arduino Core 2.x and 3.x
|
|
|
@ -1,3 +0,0 @@
|
||||||
COMPONENT_ADD_INCLUDEDIRS := src
|
|
||||||
COMPONENT_SRCDIRS := src
|
|
||||||
CXXFLAGS += -fno-rtti
|
|
|
@ -1,31 +0,0 @@
|
||||||
{
|
|
||||||
"name": "AsyncTCP",
|
|
||||||
"version": "3.3.6",
|
|
||||||
"description": "Asynchronous TCP Library for ESP32",
|
|
||||||
"keywords": "async,tcp",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/ESP32Async/AsyncTCP.git"
|
|
||||||
},
|
|
||||||
"authors":
|
|
||||||
{
|
|
||||||
"name": "ESP32Async",
|
|
||||||
"maintainer": true
|
|
||||||
},
|
|
||||||
"license": "LGPL-3.0",
|
|
||||||
"frameworks": "arduino",
|
|
||||||
"platforms": [
|
|
||||||
"espressif32",
|
|
||||||
"libretiny"
|
|
||||||
],
|
|
||||||
"export": {
|
|
||||||
"include": [
|
|
||||||
"examples",
|
|
||||||
"src",
|
|
||||||
"library.json",
|
|
||||||
"library.properties",
|
|
||||||
"LICENSE",
|
|
||||||
"README.md"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
name=Async TCP
|
|
||||||
includes=AsyncTCP.h
|
|
||||||
version=3.3.6
|
|
||||||
author=ESP32Async
|
|
||||||
maintainer=ESP32Async
|
|
||||||
sentence=Async TCP Library for ESP32
|
|
||||||
paragraph=Async TCP Library for ESP32
|
|
||||||
category=Other
|
|
||||||
url=https://github.com/ESP32Async/AsyncTCP.git
|
|
||||||
architectures=*
|
|
||||||
license=LGPL-3.0
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,335 +0,0 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
|
||||||
|
|
||||||
#ifndef ASYNCTCP_H_
|
|
||||||
#define ASYNCTCP_H_
|
|
||||||
|
|
||||||
#include "AsyncTCPVersion.h"
|
|
||||||
#define ASYNCTCP_FORK_ESP32Async
|
|
||||||
|
|
||||||
#include "IPAddress.h"
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
#include "IPv6Address.h"
|
|
||||||
#endif
|
|
||||||
#include "lwip/ip6_addr.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#ifndef LIBRETINY
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
extern "C" {
|
|
||||||
#include "freertos/semphr.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
extern "C" {
|
|
||||||
#include <lwip/pbuf.h>
|
|
||||||
#include <semphr.h>
|
|
||||||
}
|
|
||||||
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 // any available core
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// If core is not defined, then we are running in Arduino or PIO
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
|
|
||||||
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 // any available core
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// guard AsyncTCP task with watchdog
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_USE_WDT
|
|
||||||
#define CONFIG_ASYNC_TCP_USE_WDT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_STACK_SIZE
|
|
||||||
#define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_PRIORITY
|
|
||||||
#define CONFIG_ASYNC_TCP_PRIORITY 10
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_QUEUE_SIZE
|
|
||||||
#define CONFIG_ASYNC_TCP_QUEUE_SIZE 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_ASYNC_TCP_MAX_ACK_TIME
|
|
||||||
#define CONFIG_ASYNC_TCP_MAX_ACK_TIME 5000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class AsyncClient;
|
|
||||||
|
|
||||||
#define ASYNC_WRITE_FLAG_COPY 0x01 // will allocate new buffer to hold the data while sending (else will hold reference to the data given)
|
|
||||||
#define ASYNC_WRITE_FLAG_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(const IPAddress &ip, uint16_t port);
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
bool connect(const IPv6Address &ip, uint16_t port);
|
|
||||||
#endif
|
|
||||||
bool connect(const char *host, uint16_t port);
|
|
||||||
/**
|
|
||||||
* @brief close connection
|
|
||||||
*
|
|
||||||
* @param now - ignored
|
|
||||||
*/
|
|
||||||
void close(bool now = false);
|
|
||||||
// same as close()
|
|
||||||
void stop() {
|
|
||||||
close(false);
|
|
||||||
};
|
|
||||||
int8_t abort();
|
|
||||||
bool free();
|
|
||||||
|
|
||||||
// ack is not pending
|
|
||||||
bool canSend();
|
|
||||||
// TCP buffer space available
|
|
||||||
size_t space();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief add data to be send (but do not send yet)
|
|
||||||
* @note add() would call lwip's tcp_write()
|
|
||||||
By default apiflags=ASYNC_WRITE_FLAG_COPY
|
|
||||||
You could try to use apiflags with this flag unset to pass data by reference and avoid copy to socket buffer,
|
|
||||||
but looks like it does not work for Arduino's lwip in ESP32/IDF at least
|
|
||||||
it is enforced in https://github.com/espressif/esp-lwip/blob/0606eed9d8b98a797514fdf6eabb4daf1c8c8cd9/src/core/tcp_out.c#L422C5-L422C30
|
|
||||||
if LWIP_NETIF_TX_SINGLE_PBUF is set, and it is set indeed in IDF
|
|
||||||
https://github.com/espressif/esp-idf/blob/a0f798cfc4bbd624aab52b2c194d219e242d80c1/components/lwip/port/include/lwipopts.h#L744
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* @param size
|
|
||||||
* @param apiflags
|
|
||||||
* @return size_t amount of data that has been copied
|
|
||||||
*/
|
|
||||||
size_t add(const char *data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief send data previously add()'ed
|
|
||||||
*
|
|
||||||
* @return true on success
|
|
||||||
* @return false on error
|
|
||||||
*/
|
|
||||||
bool send();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief add and enqueue data for sending
|
|
||||||
* @note it is same as add() + send()
|
|
||||||
* @note only make sense when canSend() == true
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* @param size
|
|
||||||
* @param apiflags
|
|
||||||
* @return size_t
|
|
||||||
*/
|
|
||||||
size_t write(const char *data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief add and enqueue data for sending
|
|
||||||
* @note treats data as null-terminated string
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* @return size_t
|
|
||||||
*/
|
|
||||||
size_t write(const char *data) {
|
|
||||||
return data == NULL ? 0 : write(data, strlen(data));
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t state();
|
|
||||||
bool connecting();
|
|
||||||
bool connected();
|
|
||||||
bool disconnecting();
|
|
||||||
bool disconnected();
|
|
||||||
|
|
||||||
// disconnected or disconnecting
|
|
||||||
bool freeable();
|
|
||||||
|
|
||||||
uint16_t getMss();
|
|
||||||
|
|
||||||
uint32_t getRxTimeout();
|
|
||||||
// no RX data timeout for the connection in seconds
|
|
||||||
void setRxTimeout(uint32_t timeout);
|
|
||||||
|
|
||||||
uint32_t getAckTimeout();
|
|
||||||
// no ACK timeout for the last sent packet in milliseconds
|
|
||||||
void setAckTimeout(uint32_t timeout);
|
|
||||||
|
|
||||||
void setNoDelay(bool nodelay);
|
|
||||||
bool getNoDelay();
|
|
||||||
|
|
||||||
void setKeepAlive(uint32_t ms, uint8_t cnt);
|
|
||||||
|
|
||||||
uint32_t getRemoteAddress();
|
|
||||||
uint16_t getRemotePort();
|
|
||||||
uint32_t getLocalAddress();
|
|
||||||
uint16_t getLocalPort();
|
|
||||||
#if LWIP_IPV6
|
|
||||||
ip6_addr_t getRemoteAddress6();
|
|
||||||
ip6_addr_t getLocalAddress6();
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
IPv6Address remoteIP6();
|
|
||||||
IPv6Address localIP6();
|
|
||||||
#else
|
|
||||||
IPAddress remoteIP6();
|
|
||||||
IPAddress localIP6();
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// compatibility
|
|
||||||
IPAddress remoteIP();
|
|
||||||
uint16_t remotePort();
|
|
||||||
IPAddress localIP();
|
|
||||||
uint16_t localPort();
|
|
||||||
|
|
||||||
// set callback - on successful connect
|
|
||||||
void onConnect(AcConnectHandler cb, void *arg = 0);
|
|
||||||
// set callback - disconnected
|
|
||||||
void onDisconnect(AcConnectHandler cb, void *arg = 0);
|
|
||||||
// set callback - ack received
|
|
||||||
void onAck(AcAckHandler cb, void *arg = 0);
|
|
||||||
// set callback - unsuccessful connect or error
|
|
||||||
void onError(AcErrorHandler cb, void *arg = 0);
|
|
||||||
// set callback - data received (called if onPacket is not used)
|
|
||||||
void onData(AcDataHandler cb, void *arg = 0);
|
|
||||||
// set callback - data received
|
|
||||||
// !!! You MUST call ackPacket() or free the pbuf yourself to prevent memory leaks
|
|
||||||
void onPacket(AcPacketHandler cb, void *arg = 0);
|
|
||||||
// set callback - ack timeout
|
|
||||||
void onTimeout(AcTimeoutHandler cb, void *arg = 0);
|
|
||||||
// set callback - every 125ms when connected
|
|
||||||
void onPoll(AcConnectHandler cb, void *arg = 0);
|
|
||||||
|
|
||||||
// ack pbuf from onPacket
|
|
||||||
void ackPacket(struct pbuf *pb);
|
|
||||||
// ack data that you have not acked using the method below
|
|
||||||
size_t ack(size_t len);
|
|
||||||
// will not ack the current packet. Call from onData
|
|
||||||
void ackLater() {
|
|
||||||
_ack_pcb = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *errorToString(int8_t error);
|
|
||||||
const char *stateToString();
|
|
||||||
|
|
||||||
// internal callbacks - Do NOT call any of the functions below in user code!
|
|
||||||
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, struct tcp_pcb *tpcb, int8_t err);
|
|
||||||
static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg);
|
|
||||||
static void _tcp_error(void *arg, int8_t err);
|
|
||||||
|
|
||||||
int8_t _recv(tcp_pcb *pcb, pbuf *pb, int8_t err);
|
|
||||||
tcp_pcb *pcb() {
|
|
||||||
return _pcb;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
friend class AsyncServer;
|
|
||||||
|
|
||||||
bool _connect(ip_addr_t addr, uint16_t port);
|
|
||||||
|
|
||||||
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 _ack_pcb;
|
|
||||||
uint32_t _tx_last_packet;
|
|
||||||
uint32_t _rx_ack_len;
|
|
||||||
uint32_t _rx_last_packet;
|
|
||||||
uint32_t _rx_timeout;
|
|
||||||
uint32_t _rx_last_ack;
|
|
||||||
uint32_t _ack_timeout;
|
|
||||||
uint16_t _connect_port;
|
|
||||||
|
|
||||||
int8_t _close();
|
|
||||||
void _free_closed_slot();
|
|
||||||
bool _allocate_closed_slot();
|
|
||||||
int8_t _connected(tcp_pcb *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);
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
AsyncServer(IPv6Address addr, uint16_t port);
|
|
||||||
#endif
|
|
||||||
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;
|
|
||||||
bool _bind4 = false;
|
|
||||||
bool _bind6 = false;
|
|
||||||
IPAddress _addr;
|
|
||||||
#if ESP_IDF_VERSION_MAJOR < 5
|
|
||||||
IPv6Address _addr6;
|
|
||||||
#endif
|
|
||||||
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_ */
|
|
|
@ -1,40 +0,0 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Major version number (X.x.x) */
|
|
||||||
#define ASYNCTCP_VERSION_MAJOR 3
|
|
||||||
/** Minor version number (x.X.x) */
|
|
||||||
#define ASYNCTCP_VERSION_MINOR 3
|
|
||||||
/** Patch version number (x.x.X) */
|
|
||||||
#define ASYNCTCP_VERSION_PATCH 6
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Macro to convert version number into an integer
|
|
||||||
*
|
|
||||||
* To be used in comparisons, such as ASYNCTCP_VERSION >= ASYNCTCP_VERSION_VAL(2, 0, 0)
|
|
||||||
*/
|
|
||||||
#define ASYNCTCP_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Current version, as an integer
|
|
||||||
*
|
|
||||||
* To be used in comparisons, such as ASYNCTCP_VERSION_NUM >= ASYNCTCP_VERSION_VAL(2, 0, 0)
|
|
||||||
*/
|
|
||||||
#define ASYNCTCP_VERSION_NUM ASYNCTCP_VERSION_VAL(ASYNCTCP_VERSION_MAJOR, ASYNCTCP_VERSION_MINOR, ASYNCTCP_VERSION_PATCH)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Current version, as string
|
|
||||||
*/
|
|
||||||
#define df2xstr(s) #s
|
|
||||||
#define df2str(s) df2xstr(s)
|
|
||||||
#define ASYNCTCP_VERSION df2str(ASYNCTCP_VERSION_MAJOR) "." df2str(ASYNCTCP_VERSION_MINOR) "." df2str(ASYNCTCP_VERSION_PATCH)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#include "../../ESP32Async-AsyncTCP/src/AsyncTCP.h"
|
#include "../../mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#ifndef SSE_MAX_QUEUED_MESSAGES
|
#ifndef SSE_MAX_QUEUED_MESSAGES
|
||||||
#define SSE_MAX_QUEUED_MESSAGES 32
|
#define SSE_MAX_QUEUED_MESSAGES 32
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#include "../../ESP32Async-AsyncTCP/src/AsyncTCP.h"
|
#include "../../mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#ifndef WS_MAX_QUEUED_MESSAGES
|
#ifndef WS_MAX_QUEUED_MESSAGES
|
||||||
#define WS_MAX_QUEUED_MESSAGES 32
|
#define WS_MAX_QUEUED_MESSAGES 32
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#include "../../ESP32Async-AsyncTCP/src/AsyncTCP.h"
|
#include "../../mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
|
|
|
@ -64,7 +64,7 @@ _____ _ _ ___ _____ _
|
||||||
#include "Update.h"
|
#include "Update.h"
|
||||||
#include "StreamString.h"
|
#include "StreamString.h"
|
||||||
#if ELEGANTOTA_USE_ASYNC_WEBSERVER == 1
|
#if ELEGANTOTA_USE_ASYNC_WEBSERVER == 1
|
||||||
#include "../../ESP32Async-AsyncTCP/src/AsyncTCP.h"
|
#include "../../mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
|
||||||
#include "../../ESP32Async-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
|
#include "../../ESP32Async-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
|
||||||
#define ELEGANTOTA_WEBSERVER AsyncWebServer
|
#define ELEGANTOTA_WEBSERVER AsyncWebServer
|
||||||
#else
|
#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
|
Loading…
Add table
Add a link
Reference in a new issue