Skip to content
This repository was archived by the owner on Sep 6, 2022. It is now read-only.

Commit 6f37967

Browse files
author
Maurice Makaay
committed
Better fix for "ack timeout 4" client disconnects.
After my first attempt at fixing the client disconnects (OttoWinter#4) got merged into AsyncTCP, it turned out that there was regression for some devices: the connection stability actually went down instead of up. After a lot of debugging and discussion with @glmnet (some of the results can be found in the above pull request discussion), we came up with an improved fix for the disconnect issues. **Changed:** The code that checks for ACK timeouts has been simplified in such way, that only two timestamps are now used to determine if an ACK timeout has happened: the time of the last sent packet (this was already recorded), and the time of the last received ACK from the client (this has been added). Using these timestamps, there is no more need for a separate field to keep track if we are waiting for an ACK or not (`_pcb_busy`). Therefore, this field was completely removed from the code. While I was at it, I renamed a few variables to make the code easier to read and more consistent. **Results:** I connected Home Assistant plus 8 OTA loggers at the same time, using very verbose logging output. This normally was an easy way to trigger the disconnect errors. It turned out, this solution runs as solid for me, as when disabling the ACK timeout checks completely (using `AsyncClient::setAckTimeout(0)`).
1 parent f278522 commit 6f37967

File tree

2 files changed

+23
-24
lines changed

2 files changed

+23
-24
lines changed

src/AsyncTCP.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -575,11 +575,10 @@ AsyncClient::AsyncClient(tcp_pcb* pcb)
575575
, _pb_cb_arg(0)
576576
, _timeout_cb(0)
577577
, _timeout_cb_arg(0)
578-
, _pcb_busy(0)
579-
, _pcb_sent_at(0)
580578
, _ack_pcb(true)
581-
, _rx_last_packet(0)
582-
, _rx_since_timeout(0)
579+
, _tx_last_packet(0)
580+
, _rx_timeout(0)
581+
, _rx_last_ack(0)
583582
, _ack_timeout(ASYNC_MAX_ACK_TIME)
584583
, _connect_port(0)
585584
, prev(NULL)
@@ -783,14 +782,12 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) {
783782
}
784783

785784
bool AsyncClient::send(){
786-
auto pcb_sent_at_backup = _pcb_sent_at;
787-
_pcb_sent_at = millis();
788-
_pcb_busy++;
785+
auto backup = _tx_last_packet;
786+
_tx_last_packet = millis();
789787
if (_tcp_output(_pcb, _closed_slot) == ERR_OK) {
790788
return true;
791789
}
792-
_pcb_sent_at = pcb_sent_at_backup;
793-
_pcb_busy--;
790+
_tx_last_packet = backup;
794791
return false;
795792
}
796793

@@ -870,7 +867,6 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){
870867
_pcb = reinterpret_cast<tcp_pcb*>(pcb);
871868
if(_pcb){
872869
_rx_last_packet = millis();
873-
_pcb_busy = 0;
874870
// tcp_recv(_pcb, &_tcp_recv);
875871
// tcp_sent(_pcb, &_tcp_sent);
876872
// tcp_poll(_pcb, &_tcp_poll, 1);
@@ -932,10 +928,10 @@ int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) {
932928

933929
int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) {
934930
_rx_last_packet = millis();
931+
_rx_last_ack = millis();
935932
//log_i("%u", len);
936-
_pcb_busy--;
937933
if(_sent_cb) {
938-
_sent_cb(_sent_cb_arg, this, len, (millis() - _pcb_sent_at));
934+
_sent_cb(_sent_cb_arg, this, len, (millis() - _tx_last_packet));
939935
}
940936
return ERR_OK;
941937
}
@@ -978,15 +974,18 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){
978974
uint32_t now = millis();
979975

980976
// ACK Timeout
981-
if(_pcb_busy > 0 && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout){
982-
_pcb_busy = 0;
983-
log_w("ack timeout %d", pcb->state);
984-
if(_timeout_cb)
985-
_timeout_cb(_timeout_cb_arg, this, (now - _pcb_sent_at));
986-
return ERR_OK;
977+
if(_ack_timeout){
978+
uint32_t one_day = 86400000;
979+
bool last_tx_is_after_last_ack = (_rx_last_ack - _tx_last_packet + one_day) < one_day;
980+
if(last_tx_is_after_last_ack && (now - _tx_last_packet) >= _ack_timeout) {
981+
log_w("ack timeout %d", pcb->state);
982+
if(_timeout_cb)
983+
_timeout_cb(_timeout_cb_arg, this, (now - _tx_last_packet));
984+
return ERR_OK;
985+
}
987986
}
988987
// RX Timeout
989-
if(_rx_since_timeout && (now - _rx_last_packet) >= (_rx_since_timeout * 1000)){
988+
if(_rx_timeout && (now - _rx_last_packet) >= (_rx_timeout * 1000)) {
990989
log_w("rx timeout %d", pcb->state);
991990
_close();
992991
return ERR_OK;
@@ -1045,11 +1044,11 @@ size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) {
10451044
}
10461045

10471046
void AsyncClient::setRxTimeout(uint32_t timeout){
1048-
_rx_since_timeout = timeout;
1047+
_rx_timeout = timeout;
10491048
}
10501049

10511050
uint32_t AsyncClient::getRxTimeout(){
1052-
return _rx_since_timeout;
1051+
return _rx_timeout;
10531052
}
10541053

10551054
uint32_t AsyncClient::getAckTimeout(){

src/AsyncTCP.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,12 @@ class AsyncClient {
160160
AcConnectHandler _poll_cb;
161161
void* _poll_cb_arg;
162162

163-
uint32_t _pcb_busy;
164-
uint32_t _pcb_sent_at;
165163
bool _ack_pcb;
164+
uint32_t _tx_last_packet;
166165
uint32_t _rx_ack_len;
167166
uint32_t _rx_last_packet;
168-
uint32_t _rx_since_timeout;
167+
uint32_t _rx_timeout;
168+
uint32_t _rx_last_ack;
169169
uint32_t _ack_timeout;
170170
uint16_t _connect_port;
171171

0 commit comments

Comments
 (0)