fix(tcp): recover stalled TCP client connects

This commit is contained in:
2026-05-12 03:31:39 +08:00
parent d36f6b4bee
commit e203db13ca
2 changed files with 57 additions and 8 deletions
+55 -8
View File
@@ -20,6 +20,7 @@ typedef struct {
struct pbuf *hold_pbuf;
uint16_t hold_offset;
uint32_t next_retry_ms;
uint32_t connect_start_ms;
uint8_t index;
tcp_client_instance_config_t config;
tcp_client_status_t status;
@@ -37,6 +38,11 @@ static uint16_t ring_used(uint16_t head, uint16_t tail, uint16_t size)
return (head >= tail) ? (uint16_t)(head - tail) : (uint16_t)(size - tail + head);
}
static bool tick_reached(uint32_t now, uint32_t deadline)
{
return ((int32_t)(now - deadline) >= 0);
}
static void tcp_client_reset_rx_state(tcp_client_ctx_t *ctx)
{
if (ctx == NULL) {
@@ -51,6 +57,31 @@ static void tcp_client_reset_rx_state(tcp_client_ctx_t *ctx)
ctx->rx_tail = 0u;
}
static void tcp_client_abort_connect_timeout(tcp_client_ctx_t *ctx, uint32_t now)
{
if (ctx == NULL) {
return;
}
if (ctx->pcb != NULL) {
tcp_arg(ctx->pcb, NULL);
tcp_recv(ctx->pcb, NULL);
tcp_sent(ctx->pcb, NULL);
tcp_err(ctx->pcb, NULL);
tcp_client_reset_rx_state(ctx);
tcp_abort(ctx->pcb);
ctx->pcb = NULL;
} else {
tcp_client_reset_rx_state(ctx);
}
ctx->connect_start_ms = 0u;
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->status.errors++;
ctx->status.connect_timeout_count++;
ctx->next_retry_ms = now + ctx->config.reconnect_interval_ms;
}
static void tcp_client_fill_ring_from_pbuf(tcp_client_ctx_t *ctx)
{
struct pbuf *q;
@@ -111,6 +142,7 @@ static err_t tcp_client_on_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p,
tcp_err(pcb, NULL);
tcp_abort(pcb);
ctx->pcb = NULL;
ctx->connect_start_ms = 0u;
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
return ERR_ABRT;
@@ -147,6 +179,7 @@ static void tcp_client_on_err(void *arg, err_t err)
}
tcp_client_reset_rx_state(ctx);
ctx->pcb = NULL;
ctx->connect_start_ms = 0u;
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->status.errors++;
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
@@ -162,6 +195,7 @@ static err_t tcp_client_on_connected(void *arg, struct tcp_pcb *pcb, err_t err)
}
if (err != ERR_OK) {
ctx->pcb = NULL;
ctx->connect_start_ms = 0u;
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->status.errors++;
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
@@ -169,6 +203,7 @@ static err_t tcp_client_on_connected(void *arg, struct tcp_pcb *pcb, err_t err)
}
ctx->pcb = pcb;
ctx->connect_start_ms = 0u;
ctx->status.state = TCP_CLIENT_STATE_CONNECTED;
tcp_nagle_disable(pcb);
tcp_arg(pcb, ctx);
@@ -228,6 +263,7 @@ int tcp_client_connect(uint8_t instance)
if (err != ERR_OK) {
tcp_abort(pcb);
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->connect_start_ms = 0u;
ctx->status.errors++;
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
return -1;
@@ -241,6 +277,7 @@ int tcp_client_connect(uint8_t instance)
ctx->config.remote_ip[3]);
ctx->status.state = TCP_CLIENT_STATE_CONNECTING;
ctx->connect_start_ms = HAL_GetTick();
tcp_arg(pcb, ctx);
tcp_err(pcb, tcp_client_on_err);
err = tcp_connect(pcb, &remote_addr, ctx->config.remote_port, tcp_client_on_connected);
@@ -248,6 +285,7 @@ int tcp_client_connect(uint8_t instance)
tcp_err(pcb, NULL);
tcp_abort(pcb);
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->connect_start_ms = 0u;
ctx->status.errors++;
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
return -1;
@@ -274,6 +312,7 @@ int tcp_client_disconnect(uint8_t instance)
tcp_abort(ctx->pcb);
ctx->pcb = NULL;
}
ctx->connect_start_ms = 0u;
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
tcp_client_reset_rx_state(ctx);
return 0;
@@ -368,21 +407,26 @@ uint16_t tcp_client_peek(uint8_t instance, uint8_t *data, uint16_t max_len)
void tcp_client_drop(uint8_t instance, uint16_t len)
{
tcp_client_ctx_t *ctx;
uint16_t dropped = 0u;
uint16_t acked = 0u;
if (instance >= TCP_CLIENT_INSTANCE_COUNT || len == 0u) {
return;
}
ctx = &g_clients[instance];
while (dropped < len && ctx->rx_tail != ctx->rx_head) {
ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % TCP_CLIENT_RX_BUFFER_SIZE);
dropped++;
while (acked < len) {
tcp_client_fill_ring_from_pbuf(ctx);
if (ctx->rx_tail == ctx->rx_head) {
break;
}
while (acked < len && ctx->rx_tail != ctx->rx_head) {
ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % TCP_CLIENT_RX_BUFFER_SIZE);
acked++;
}
}
if (dropped > 0u && ctx->pcb != NULL) {
tcp_recved(ctx->pcb, dropped);
if (acked > 0u && ctx->pcb != NULL) {
tcp_recved(ctx->pcb, acked);
}
tcp_client_fill_ring_from_pbuf(ctx);
}
bool tcp_client_is_connected(uint8_t instance)
@@ -410,9 +454,12 @@ void tcp_client_poll(void)
continue;
}
if ((ctx->pcb != NULL) && (ctx->status.state == TCP_CLIENT_STATE_CONNECTING)) {
if ((uint32_t)(now - ctx->connect_start_ms) >= TCP_CLIENT_CONNECT_TIMEOUT_MS) {
tcp_client_abort_connect_timeout(ctx, now);
}
continue;
}
if (now >= ctx->next_retry_ms) {
if (tick_reached(now, ctx->next_retry_ms)) {
ctx->status.reconnect_count++;
ctx->next_retry_ms = now + ctx->config.reconnect_interval_ms;
(void)tcp_client_connect(i);