fix(tcp): recover stalled TCP client connects
This commit is contained in:
+56
-9
@@ -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++;
|
||||
}
|
||||
if (dropped > 0u && ctx->pcb != NULL) {
|
||||
tcp_recved(ctx->pcb, 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 (acked > 0u && ctx->pcb != NULL) {
|
||||
tcp_recved(ctx->pcb, acked);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -16,6 +16,7 @@ extern "C" {
|
||||
#define TCP_CLIENT_INSTANCE_COUNT 2u
|
||||
#define TCP_CLIENT_RX_BUFFER_SIZE 480u
|
||||
#define TCP_CLIENT_RECONNECT_DELAY_MS 3000u
|
||||
#define TCP_CLIENT_CONNECT_TIMEOUT_MS 10000u
|
||||
|
||||
typedef enum {
|
||||
TCP_CLIENT_STATE_IDLE = 0,
|
||||
@@ -39,6 +40,7 @@ typedef struct {
|
||||
uint32_t rx_bytes;
|
||||
uint32_t tx_bytes;
|
||||
uint32_t reconnect_count;
|
||||
uint32_t connect_timeout_count;
|
||||
uint32_t errors;
|
||||
} tcp_client_status_t;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user