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 @@
{"type": "library", "name": "AsyncTCP", "version": "3.4.9", "spec": {"owner": "esp32async", "id": 18273, "name": "AsyncTCP", "requirements": null, "uri": null}}

View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@@ -0,0 +1,55 @@
![https://avatars.githubusercontent.com/u/195753706?s=96&v=4](https://avatars.githubusercontent.com/u/195753706?s=96&v=4)
# AsyncTCP
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
[![Continuous Integration](https://github.com/ESP32Async/AsyncTCP/actions/workflows/ci.yml/badge.svg)](https://github.com/ESP32Async/AsyncTCP/actions/workflows/ci.yml)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/ESP32Async/library/AsyncTCP.svg)](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

View File

@@ -0,0 +1,169 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
/*
This example demonstrates how to send data to a remote server asynchronously.
Run on the remote computer: nc -l -p 1234
You should see in the logs:
Connected!
Will send 5760 bytes...
Acked 1436 bytes in 19 ms
Will send 1436 bytes...
Acked 1436 bytes in 2 ms
Will send 996 bytes...
Waiting for acks...
Acked 1436 bytes in 1 ms
Acked 1436 bytes in 5 ms
Acked 1452 bytes in 17 ms
Acked 996 bytes in 28 ms
Buffer received - next send in 2 sec
Will send 5760 bytes...
Acked 1436 bytes in 14 ms
Will send 1436 bytes...
Acked 1436 bytes in 2 ms
Acked 1436 bytes in 0 ms
Acked 1452 bytes in 1 ms
Will send 996 bytes...
Waiting for acks...
Acked 1436 bytes in 3 ms
Acked 996 bytes in 18 ms
Buffer received - next send in 2 sec
And in the remote terminal 3072 characters sent [......... ...........] and so on.
*/
#include <Arduino.h>
#include <AsyncTCP.h>
#include <StreamString.h>
#include <WiFi.h>
#include <assert.h>
#include <functional>
#include <string>
#define WIFI_SSID "IoT"
#define WIFI_PASSWORD ""
#define REMOTE_IP "192.168.125.116"
#define REMOTE_PORT 1234
#define BUFFER_SIZE 8 * 1024
static char buffer[BUFFER_SIZE] = {0};
static size_t bufferPos = 0;
// 0 == disconnected
// 1 == connecting
// 2 == connected
static uint8_t state = 0;
// number of bytes waiting for a ack
static size_t waitingAck = 0;
static AsyncClient client;
void setup() {
Serial.begin(115200);
while (!Serial) {
continue;
}
// connect to WiFi
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
Serial.println("Connected to WiFi!");
Serial.println(WiFi.localIP());
// fill buffer
buffer[0] = '[';
for (size_t i = 1; i < BUFFER_SIZE - 1; i++) {
buffer[i] = '.';
}
buffer[BUFFER_SIZE - 1] = ']';
// register a callback when the client disconnects
client.onDisconnect([](void *arg, AsyncClient *client) {
Serial.printf("Disconnected.\n");
state = 0;
});
// register a callback when an error occurs
client.onError([](void *arg, AsyncClient *client, int8_t error) {
Serial.printf("Error: %s\n", client->errorToString(error));
});
// register a callback when data arrives, to accumulate it
client.onData([](void *arg, AsyncClient *client, void *data, size_t len) {
Serial.printf("Received %u bytes...\n", len);
Serial.write((uint8_t *)data, len);
});
// register a callback when we are connected
client.onConnect([](void *arg, AsyncClient *client) {
Serial.printf("Connected!\n");
state = 2;
});
client.onAck([](void *arg, AsyncClient *client, size_t len, uint32_t time) {
Serial.printf("Acked %u bytes in %" PRIu32 " ms\n", len, time);
assert(waitingAck >= len);
waitingAck -= len;
});
client.setRxTimeout(20000);
client.setNoDelay(true);
}
void loop() {
switch (state) {
case 0:
{
Serial.printf("Connecting...\n");
if (!client.connect(REMOTE_IP, REMOTE_PORT)) {
Serial.printf("Failed to connect!\n");
delay(1000); // to not flood logs
} else {
state = 1;
}
break;
}
case 1:
{
Serial.printf("Still connecting...\n");
delay(500); // to not flood logs
break;
}
case 2:
{
// fill PCB space until we can
size_t willSend;
while (bufferPos < BUFFER_SIZE && (willSend = client.write(buffer + bufferPos, BUFFER_SIZE - bufferPos))) {
Serial.printf("Will send %u bytes...\n", willSend);
bufferPos += willSend;
waitingAck += willSend;
}
// we have sent the whole buffer ?
if (bufferPos >= BUFFER_SIZE) {
// wait for acks, or send again after 2 sec
if (waitingAck) {
Serial.printf("Waiting for acks...\n");
delay(100);
} else {
Serial.printf("Buffer received - next send in 2 sec\n");
delay(2000);
bufferPos = 0;
}
}
break;
}
default: break;
}
}

View File

@@ -0,0 +1,87 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
#include <Arduino.h>
#include <AsyncTCP.h>
#include <WiFi.h>
// Run a server at the root of the project with:
// > python3 -m http.server 3333
// Now you can open a browser and test it works by visiting http://192.168.125.122:3333/ or http://192.168.125.122:3333/README.md
#define HOST "192.168.125.122"
#define PORT 3333
// WiFi SSID to connect to
#define WIFI_SSID "IoT"
// 16 slots on esp32 (CONFIG_LWIP_MAX_ACTIVE_TCP)
#define MAX_CLIENTS CONFIG_LWIP_MAX_ACTIVE_TCP
// #define MAX_CLIENTS 1
size_t permits = MAX_CLIENTS;
void makeRequest() {
if (!permits) {
return;
}
Serial.printf("** permits: %d\n", permits);
AsyncClient *client = new AsyncClient;
client->onError([](void *arg, AsyncClient *client, int8_t error) {
Serial.printf("** error occurred %s \n", client->errorToString(error));
client->close(true);
delete client;
});
client->onConnect([](void *arg, AsyncClient *client) {
permits--;
Serial.printf("** client has been connected: %" PRIu16 "\n", client->localPort());
client->onDisconnect([](void *arg, AsyncClient *client) {
Serial.printf("** client has been disconnected: %" PRIu16 "\n", client->localPort());
client->close(true);
delete client;
permits++;
makeRequest();
});
client->onData([](void *arg, AsyncClient *client, void *data, size_t len) {
Serial.printf("** data received by client: %" PRIu16 ": len=%u\n", client->localPort(), len);
});
client->write("GET /README.md HTTP/1.1\r\nHost: " HOST "\r\nUser-Agent: ESP\r\nConnection: close\r\n\r\n");
});
if (client->connect(HOST, PORT)) {
} else {
Serial.println("** connection failed");
}
}
void setup() {
Serial.begin(115200);
while (!Serial) {
continue;
}
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("** connected to WiFi");
Serial.println(WiFi.localIP());
for (size_t i = 0; i < MAX_CLIENTS; i++) {
makeRequest();
}
}
void loop() {
delay(1000);
Serial.printf("** free heap: %" PRIu32 "\n", ESP.getFreeHeap());
}

View File

@@ -0,0 +1,107 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
#include <Arduino.h>
#include <AsyncTCP.h>
#include <StreamString.h>
#include <WiFi.h>
#include <functional>
#include <string>
#define WIFI_SSID "IoT"
#define WIFI_PASSWORD ""
void fetchAsync(const char *host, std::function<void(const StreamString *)> onDone) {
Serial.printf("[%s] Fetching: http://%s...\n", host, host);
// buffer where we will accumulate the received data
StreamString *content = new StreamString();
// reserve enough space to avoid reallocations
content->reserve(32 * 1024);
// create a new client
AsyncClient *client = new AsyncClient();
// register a callback when the client disconnects
client->onDisconnect([content, host, onDone](void *arg, AsyncClient *client) {
Serial.printf("[%s] Disconnected.\n", host);
onDone(content);
delete client;
delete content;
});
// register a callback when an error occurs
client->onError([host, onDone](void *arg, AsyncClient *client, int8_t error) {
Serial.printf("[%s] Error: %s\n", host, client->errorToString(error));
});
// register a callback when data arrives, to accumulate it
client->onData([host, content](void *arg, AsyncClient *client, void *data, size_t len) {
Serial.printf("[%s] Received %u bytes...\n", host, len);
content->write((const uint8_t *)data, len);
});
// register a callback when we are connected
client->onConnect([host](void *arg, AsyncClient *client) {
Serial.printf("[%s] Connected!\n", host);
// send request
client->write("GET / HTTP/1.1\r\n");
client->write("Host: ");
client->write(host);
client->write("\r\n");
client->write("User-Agent: ESP32\r\n");
client->write("Connection: close\r\n");
client->write("\r\n");
});
Serial.printf("[%s] Connecting...\n", host);
if (!client->connect(host, 80)) {
Serial.printf("[%s] Failed to connect!\n", host);
delete client;
delete content;
onDone(nullptr);
}
}
void setup() {
Serial.begin(115200);
while (!Serial) {
continue;
}
// connect to WiFi
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
Serial.println("Connected to WiFi!");
Serial.println(WiFi.localIP());
// fetch asynchronously 2 websites:
// equivalent to curl -v --raw http://www.time.org/
fetchAsync("www.time.org", [](const StreamString *content) {
if (content) {
Serial.printf("[www.time.org] Fetched website:\n%s\n", content->c_str());
} else {
Serial.println("[www.time.org] Failed to fetch website!");
}
});
// equivalent to curl -v --raw http://www.google.com/
fetchAsync("www.google.com", [](const StreamString *content) {
if (content) {
Serial.printf("[www.google.com] Fetched website:\n%s\n", content->c_str());
} else {
Serial.println("[www.google.com] Failed to fetch website!");
}
});
}
void loop() {
delay(100);
}

View File

@@ -0,0 +1,31 @@
{
"name": "AsyncTCP",
"version": "3.4.9",
"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"
]
}
}

View File

@@ -0,0 +1,11 @@
name=Async TCP
includes=AsyncTCP.h
version=3.4.9
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

View File

@@ -0,0 +1,335 @@
// 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
#ifdef ARDUINO
#include "IPAddress.h"
#if __has_include(<IPv6Address.h>)
#include "IPv6Address.h"
#endif
#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 <FreeRTOS.h>
#include <semphr.h>
}
#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;
class AsyncTCP_detail;
class AsyncClient {
public:
AsyncClient(tcp_pcb *pcb = 0);
~AsyncClient();
// Noncopyable
AsyncClient(const AsyncClient &) = delete;
AsyncClient &operator=(const AsyncClient &) = delete;
// Nonmovable
AsyncClient(AsyncClient &&) = delete;
AsyncClient &operator=(AsyncClient &&) = delete;
bool operator==(const AsyncClient &other) const;
bool operator!=(const AsyncClient &other) const {
return !(*this == other);
}
bool connect(ip_addr_t addr, uint16_t port);
#ifdef ARDUINO
bool connect(const IPAddress &ip, uint16_t port);
#if __has_include(<IPv6Address.h>)
bool connect(const IPv6Address &ip, uint16_t port);
#endif
#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() const;
// TCP buffer space available
size_t space() const;
/**
* @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() const;
bool connecting() const;
bool connected() const;
bool disconnecting() const;
bool disconnected() const;
// disconnected or disconnecting
bool freeable() const;
uint16_t getMss() const;
uint32_t getRxTimeout() const;
// no RX data timeout for the connection in seconds
void setRxTimeout(uint32_t timeout);
uint32_t getAckTimeout() const;
// no ACK timeout for the last sent packet in milliseconds
void setAckTimeout(uint32_t timeout);
void setNoDelay(bool nodelay) const;
bool getNoDelay();
void setKeepAlive(uint32_t ms, uint8_t cnt);
uint32_t getRemoteAddress() const;
uint16_t getRemotePort() const;
uint16_t remotePort() const {
return getRemotePort();
}
uint32_t getLocalAddress() const;
uint16_t getLocalPort() const;
uint16_t localPort() const {
return getLocalPort();
}
ip4_addr_t getRemoteAddress4() const;
ip4_addr_t getLocalAddress4() const;
#if LWIP_IPV6
ip6_addr_t getRemoteAddress6() const;
ip6_addr_t getLocalAddress6() const;
#ifdef ARDUINO
#if __has_include(<IPv6Address.h>)
IPv6Address remoteIP6() const;
IPv6Address localIP6() const;
#else
IPAddress remoteIP6() const;
IPAddress localIP6() const;
#endif
#endif
#endif
#ifdef ARDUINO
IPAddress remoteIP() const;
IPAddress localIP() const;
#endif
// 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() const;
int8_t _recv(tcp_pcb *pcb, pbuf *pb, int8_t err);
tcp_pcb *pcb() {
return _pcb;
}
protected:
friend class AsyncTCP_detail;
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 _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();
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(ip_addr_t *ipaddr);
};
class AsyncServer {
public:
AsyncServer(ip_addr_t addr, uint16_t port);
#ifdef ARDUINO
AsyncServer(IPAddress addr, uint16_t port);
#if __has_include(<IPv6Address.h>)
AsyncServer(IPv6Address addr, uint16_t port);
#endif
#endif
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void *arg);
void begin();
void end();
void setNoDelay(bool nodelay);
bool getNoDelay() const;
uint8_t status() const;
protected:
friend class AsyncTCP_detail;
uint16_t _port;
ip_addr_t _addr;
bool _noDelay;
tcp_pcb *_pcb;
AcConnectHandler _connect_cb;
void *_connect_cb_arg;
int8_t _accept(tcp_pcb *newpcb, int8_t err);
int8_t _accepted(AsyncClient *client);
};
#endif /* ASYNCTCP_H_ */

View File

@@ -0,0 +1,66 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
#pragma once
#ifdef CONFIG_ASYNC_TCP_LOG_CUSTOM
// The user must provide the following macros in AsyncTCPLoggingCustom.h:
// async_tcp_log_e, async_tcp_log_w, async_tcp_log_i, async_tcp_log_d, async_tcp_log_v
#include <AsyncTCPLoggingCustom.h>
#elif defined(CONFIG_ASYNC_TCP_DEBUG)
// Local Debug logging
#include <HardwareSerial.h>
#define async_tcp_log_e(format, ...) Serial.printf("E async_tcp %s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#define async_tcp_log_w(format, ...) Serial.printf("W async_tcp %s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#define async_tcp_log_i(format, ...) Serial.printf("I async_tcp %s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#define async_tcp_log_d(format, ...) Serial.printf("D async_tcp %s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#define async_tcp_log_v(format, ...) Serial.printf("V async_tcp %s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
// Framework-based logging
/**
* LibreTiny specific configurations
*/
#if defined(LIBRETINY)
#include <Arduino.h>
#define async_tcp_log_e(format, ...) log_e(format, ##__VA_ARGS__)
#define async_tcp_log_w(format, ...) log_w(format, ##__VA_ARGS__)
#define async_tcp_log_i(format, ...) log_i(format, ##__VA_ARGS__)
#define async_tcp_log_d(format, ...) log_d(format, ##__VA_ARGS__)
#define async_tcp_log_v(format, ...) log_v(format, ##__VA_ARGS__)
/**
* Arduino specific configurations
*/
#elif defined(ARDUINO)
#if defined(USE_ESP_IDF_LOG)
#include <esp_log.h>
#define async_tcp_log_e(format, ...) ESP_LOGE("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define async_tcp_log_w(format, ...) ESP_LOGW("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define async_tcp_log_i(format, ...) ESP_LOGI("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define async_tcp_log_d(format, ...) ESP_LOGD("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define async_tcp_log_v(format, ...) ESP_LOGV("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#include <esp32-hal-log.h>
#define async_tcp_log_e(format, ...) log_e(format, ##__VA_ARGS__)
#define async_tcp_log_w(format, ...) log_w(format, ##__VA_ARGS__)
#define async_tcp_log_i(format, ...) log_i(format, ##__VA_ARGS__)
#define async_tcp_log_d(format, ...) log_d(format, ##__VA_ARGS__)
#define async_tcp_log_v(format, ...) log_v(format, ##__VA_ARGS__)
#endif // USE_ESP_IDF_LOG
/**
* ESP-IDF specific configurations
*/
#else
#include <esp_log.h>
#define async_tcp_log_e(format, ...) ESP_LOGE("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define async_tcp_log_w(format, ...) ESP_LOGW("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define async_tcp_log_i(format, ...) ESP_LOGI("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define async_tcp_log_d(format, ...) ESP_LOGD("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define async_tcp_log_v(format, ...) ESP_LOGV("async_tcp", "%s() %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif // !LIBRETINY && !ARDUINO
#endif // CONFIG_ASYNC_TCP_LOG_CUSTOM

View File

@@ -0,0 +1,134 @@
// Simple intrusive list class
#pragma once
template<typename T> class SimpleIntrusiveList {
static_assert(std::is_same<decltype(std::declval<T>().next), T *>::value, "Template type must have public 'T* next' member");
public:
typedef T value_type;
typedef value_type *value_ptr_type;
typedef value_ptr_type *value_ptr_ptr_type;
// Static utility methods
static size_t list_size(value_ptr_type chain) {
size_t count = 0;
for (auto c = chain; c != nullptr; c = c->next) {
++count;
}
return count;
}
static void delete_list(value_ptr_type chain) {
while (chain) {
auto t = chain;
chain = chain->next;
delete t;
}
}
public:
// Object methods
SimpleIntrusiveList() : _head(nullptr), _tail(&_head) {}
~SimpleIntrusiveList() {
clear();
}
// Noncopyable, nonmovable
SimpleIntrusiveList(const SimpleIntrusiveList<T> &) = delete;
SimpleIntrusiveList(SimpleIntrusiveList<T> &&) = delete;
SimpleIntrusiveList<T> &operator=(const SimpleIntrusiveList<T> &) = delete;
SimpleIntrusiveList<T> &operator=(SimpleIntrusiveList<T> &&) = delete;
inline void push_back(value_ptr_type obj) {
if (obj) {
*_tail = obj;
_tail = &obj->next;
++_size;
}
}
inline void push_front(value_ptr_type obj) {
if (obj) {
if (_head == nullptr) {
_tail = &obj->next;
}
obj->next = _head;
_head = obj;
++_size;
}
}
inline value_ptr_type pop_front() {
auto rv = _head;
if (_head) {
if (_tail == &_head->next) {
_tail = &_head;
}
_head = _head->next;
--_size;
}
return rv;
}
inline void clear() {
// Assumes all elements were allocated with "new"
delete_list(_head);
_head = nullptr;
_tail = &_head;
_size = 0;
}
inline size_t size() const {
return _size;
}
template<typename function_type> inline value_ptr_type remove_if(const function_type &condition) {
value_ptr_type removed = nullptr;
value_ptr_ptr_type current_ptr = &_head;
while (*current_ptr != nullptr) {
value_ptr_type current = *current_ptr;
if (condition(*current)) {
// Remove this item from the list by moving the next item in
*current_ptr = current->next;
// If we were the last item, reset tail
if (current->next == nullptr) {
_tail = current_ptr;
}
--_size;
// Prepend this item to the removed list
current->next = removed;
removed = current;
// do not advance current_ptr
} else {
// advance current_ptr
current_ptr = &(*current_ptr)->next;
}
}
// Return the removed entries
return removed;
}
inline value_ptr_type begin() const {
return _head;
}
bool validate_tail() const {
if (_head == nullptr) {
return (_tail == &_head);
}
auto p = _head;
while (p->next != nullptr) {
p = p->next;
}
return _tail == &p->next;
}
private:
// Data members
value_ptr_type _head;
value_ptr_ptr_type _tail;
size_t _size;
}; // class simple_intrusive_list

View File

@@ -0,0 +1,40 @@
// 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 4
/** Patch version number (x.x.X) */
#define ASYNCTCP_VERSION_PATCH 9
/**
* 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