From 5b1ef41e83a70da3107aa792b73103de39305d5a Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 14 Oct 2019 12:45:57 +0200 Subject: [PATCH 1/5] Create fork for esphome --- README.md | 4 +++- library.json | 6 +++--- library.properties | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 983aabd9..f12573a6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# AsyncTCP +# AsyncTCP [![Build Status](https://travis-ci.org/me-no-dev/AsyncTCP.svg?branch=master)](https://travis-ci.org/me-no-dev/AsyncTCP) ![](https://github.com/me-no-dev/AsyncTCP/workflows/Async%20TCP%20CI/badge.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2f7e4d1df8b446d192cbfec6dc174d2d)](https://www.codacy.com/manual/me-no-dev/AsyncTCP?utm_source=github.com&utm_medium=referral&utm_content=me-no-dev/AsyncTCP&utm_campaign=Badge_Grade) +A fork of the [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) library by [@me-no-dev](https://github.com/me-no-dev) for [ESPHome](https://esphome.io). + ### Async TCP Library for ESP32 Arduino [![Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer](https://badges.gitter.im/me-no-dev/ESPAsyncWebServer.svg)](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) diff --git a/library.json b/library.json index 89f90e4e..5041b7c6 100644 --- a/library.json +++ b/library.json @@ -1,5 +1,5 @@ { - "name":"AsyncTCP", + "name":"AsyncTCP-esphome", "description":"Asynchronous TCP Library for ESP32", "keywords":"async,tcp", "authors": @@ -10,7 +10,7 @@ "repository": { "type": "git", - "url": "https://github.com/me-no-dev/AsyncTCP.git" + "url": "https://github.com/OttoWinter/AsyncTCP.git" }, "version": "1.1.1", "license": "LGPL-3.0", @@ -18,5 +18,5 @@ "platforms": "espressif32", "build": { "libCompatMode": 2 - } + } } diff --git a/library.properties b/library.properties index eb4e26e9..38f03d4b 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ -name=AsyncTCP +name=AsyncTCP-esphome version=1.1.1 author=Me-No-Dev maintainer=Me-No-Dev sentence=Async TCP Library for ESP32 paragraph=Async TCP Library for ESP32 category=Other -url=https://github.com/me-no-dev/AsyncTCP +url=https://github.com/OttoWinter/AsyncTCP architectures=* From c18b7cafcc86b03166f7025584e16c62bff9adbe Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 14 Oct 2019 12:46:51 +0200 Subject: [PATCH 2/5] Create fallback xTaskCreateUniversal function --- src/AsyncTCP.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 9071eadd..b1b47cdd 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -210,12 +210,32 @@ static void _stop_async_task(){ } } */ + +static bool customTaskCreateUniversal( + TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + const BaseType_t xCoreID) { +#ifndef CONFIG_FREERTOS_UNICORE + if(xCoreID >= 0 && xCoreID < 2) { + return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID); + } else { +#endif + return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask); +#ifndef CONFIG_FREERTOS_UNICORE + } +#endif +} + static bool _start_async_task(){ if(!_init_async_event_queue()){ return false; } if(!_async_service_task_handle){ - xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); + customTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); if(!_async_service_task_handle){ return false; } From cfecaa3a1ce00052e00335da30b21266781849ec Mon Sep 17 00:00:00 2001 From: Otto winter Date: Thu, 8 Apr 2021 15:34:35 +0200 Subject: [PATCH 3/5] Bump version to 1.2.0 --- library.json | 2 +- library.properties | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 library.properties diff --git a/library.json b/library.json index 5041b7c6..3acca7be 100644 --- a/library.json +++ b/library.json @@ -12,7 +12,7 @@ "type": "git", "url": "https://github.com/OttoWinter/AsyncTCP.git" }, - "version": "1.1.1", + "version": "1.2.0", "license": "LGPL-3.0", "frameworks": "arduino", "platforms": "espressif32", diff --git a/library.properties b/library.properties deleted file mode 100644 index 38f03d4b..00000000 --- a/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=AsyncTCP-esphome -version=1.1.1 -author=Me-No-Dev -maintainer=Me-No-Dev -sentence=Async TCP Library for ESP32 -paragraph=Async TCP Library for ESP32 -category=Other -url=https://github.com/OttoWinter/AsyncTCP -architectures=* From 030b7476164e58c355cb3a47d44b8cc3d82e0ec5 Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Sun, 11 Apr 2021 19:09:21 +0200 Subject: [PATCH 4/5] Fix race condition causing 'ack timeout 4' disconnects (#4) The AsyncClient::send() methods sets a boolean to true after pushing data over the TCP socket successfully using tcp_output(). It also sets a timestamp to remember at what time the data was sent. The AsyncClient::_sent() callback method reacts to ACKs coming from the connected client. This method sets the boolean to false. In the AsyncClient::_poll() method, a check is done to see if the boolean is true ("I'm waiting for an ACK") and if the time at which the data was sent is too long ago (5000 ms). If this is the case, a connection issue with the connected client is assumed and the connection is forcibly closed by the server. The race condition is when these operations get mixed up, because of multithreading behavior. The _sent() method can be called during the execution of the send() method: 1. send() sends out data using tcp_output() 2. _sent() is called because an ACK is processed, sets boolean to false 3. send() continues and sets boolean to true + timestamp to "now" After this, the data exchange with the client was successful. Data were sent and the ACK was seen. However, the boolean ended up as true, making the _poll() method think that an ACK is still to be expected. As a result, 5000 ms later, the connection is dropped. This commit fixes the code by first registering that an ACK is expected, before calling tcp_output(). This way, there is no race condition when the ACK is processed right after that call. Additionally, I changed the boolean to an integer counter value. The server might send multiple messages to the client, resulting in multiple expected ACKs. A boolean does not cover this situation. Co-authored-by: Maurice Makaay --- src/AsyncTCP.cpp | 21 +++++++++++---------- src/AsyncTCP.h | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index c305a701..471e8fcf 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -575,7 +575,7 @@ AsyncClient::AsyncClient(tcp_pcb* pcb) , _pb_cb_arg(0) , _timeout_cb(0) , _timeout_cb_arg(0) -, _pcb_busy(false) +, _pcb_busy(0) , _pcb_sent_at(0) , _ack_pcb(true) , _rx_last_packet(0) @@ -783,13 +783,14 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { } bool AsyncClient::send(){ - int8_t err = ERR_OK; - err = _tcp_output(_pcb, _closed_slot); - if(err == ERR_OK){ - _pcb_busy = true; - _pcb_sent_at = millis(); + auto pcb_sent_at_backup = _pcb_sent_at; + _pcb_sent_at = millis(); + _pcb_busy++; + if (_tcp_output(_pcb, _closed_slot) == ERR_OK) { return true; } + _pcb_sent_at = pcb_sent_at_backup; + _pcb_busy--; return false; } @@ -869,7 +870,7 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ _pcb = reinterpret_cast(pcb); if(_pcb){ _rx_last_packet = millis(); - _pcb_busy = false; + _pcb_busy = 0; // tcp_recv(_pcb, &_tcp_recv); // tcp_sent(_pcb, &_tcp_sent); // tcp_poll(_pcb, &_tcp_poll, 1); @@ -932,7 +933,7 @@ int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) { int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { _rx_last_packet = millis(); //log_i("%u", len); - _pcb_busy = false; + _pcb_busy--; if(_sent_cb) { _sent_cb(_sent_cb_arg, this, len, (millis() - _pcb_sent_at)); } @@ -977,8 +978,8 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ uint32_t now = millis(); // ACK Timeout - if(_pcb_busy && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout){ - _pcb_busy = false; + if(_pcb_busy > 0 && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout){ + _pcb_busy = 0; log_w("ack timeout %d", pcb->state); if(_timeout_cb) _timeout_cb(_timeout_cb_arg, this, (now - _pcb_sent_at)); diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index ac87deda..fcd511bb 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -160,7 +160,7 @@ class AsyncClient { AcConnectHandler _poll_cb; void* _poll_cb_arg; - bool _pcb_busy; + uint32_t _pcb_busy; uint32_t _pcb_sent_at; bool _ack_pcb; uint32_t _rx_ack_len; From f278522a5961086e3bb798557cb89d6094f82d5c Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sun, 11 Apr 2021 19:09:48 +0200 Subject: [PATCH 5/5] Bump version to 1.2.1 --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index 3acca7be..c5e1f447 100644 --- a/library.json +++ b/library.json @@ -12,7 +12,7 @@ "type": "git", "url": "https://github.com/OttoWinter/AsyncTCP.git" }, - "version": "1.2.0", + "version": "1.2.1", "license": "LGPL-3.0", "frameworks": "arduino", "platforms": "espressif32",