From 0049385850daebfe2222c8f0526b896ffaeacdd9 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 22 May 2020 20:34:20 +0800 Subject: [PATCH] websocket: add configurable timeout for PONG not received Closes IDF-1744 --- .../esp_websocket_client.c | 30 +++++++++++++++++++ .../include/esp_websocket_client.h | 5 +++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index 0e959971f7..565fad3101 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -39,6 +39,7 @@ static const char *TAG = "WEBSOCKET_CLIENT"; #define WEBSOCKET_NETWORK_TIMEOUT_MS (10*1000) #define WEBSOCKET_PING_TIMEOUT_MS (10*1000) #define WEBSOCKET_EVENT_QUEUE_SIZE (1) +#define WEBSOCKET_PINGPONG_TIMEOUT_SEC (120) #define ESP_WS_CLIENT_MEM_CHECK(TAG, a, action) if (!(a)) { \ ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \ @@ -65,6 +66,7 @@ typedef struct { char *subprotocol; char *user_agent; char *headers; + int pingpong_timeout_sec; } websocket_config_storage_t; typedef enum { @@ -84,9 +86,11 @@ struct esp_websocket_client { uint64_t keepalive_tick_ms; uint64_t reconnect_tick_ms; uint64_t ping_tick_ms; + uint64_t pingpong_tick_ms; int wait_timeout_ms; int auto_reconnect; bool run; + bool wait_for_pong_resp; EventGroupHandle_t status_bits; xSemaphoreHandle lock; char *rx_buffer; @@ -206,6 +210,13 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c cfg->auto_reconnect = false; } + if (config->disable_pingpong_discon){ + cfg->pingpong_timeout_sec = 0; + } else if (config->pingpong_timeout_sec) { + cfg->pingpong_timeout_sec = config->pingpong_timeout_sec; + } else { + cfg->pingpong_timeout_sec = WEBSOCKET_PINGPONG_TIMEOUT_SEC; + } return ESP_OK; } @@ -335,6 +346,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie client->keepalive_tick_ms = _tick_get_ms(); client->reconnect_tick_ms = _tick_get_ms(); client->ping_tick_ms = _tick_get_ms(); + client->wait_for_pong_resp = false; int buffer_size = config->buffer_size; if (buffer_size <= 0) { @@ -474,6 +486,9 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client) esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG | WS_TRANSPORT_OPCODES_FIN, data, client->payload_len, client->config->network_timeout_ms); } + else if (client->last_opcode == WS_TRANSPORT_OPCODES_PONG) { + client->wait_for_pong_resp = false; + } return ESP_OK; } @@ -522,6 +537,7 @@ static void esp_websocket_client_task(void *pv) ESP_LOGD(TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port); client->state = WEBSOCKET_STATE_CONNECTED; + client->wait_for_pong_resp = false; esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CONNECTED, NULL, 0); break; @@ -530,7 +546,21 @@ static void esp_websocket_client_task(void *pv) client->ping_tick_ms = _tick_get_ms(); ESP_LOGD(TAG, "Sending PING..."); esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING | WS_TRANSPORT_OPCODES_FIN, NULL, 0, client->config->network_timeout_ms); + + if (!client->wait_for_pong_resp && client->config->pingpong_timeout_sec) { + client->pingpong_tick_ms = _tick_get_ms(); + client->wait_for_pong_resp = true; + } } + + if ( _tick_get_ms() - client->pingpong_tick_ms > client->config->pingpong_timeout_sec*1000 ) { + if (client->wait_for_pong_resp) { + ESP_LOGE(TAG, "Error, no PONG received for more than %d seconds after PING", client->config->pingpong_timeout_sec); + esp_websocket_client_abort_connection(client); + break; + } + } + if (read_select == 0) { ESP_LOGV(TAG, "Read poll timeout: skipping esp_transport_read()..."); break; diff --git a/components/esp_websocket_client/include/esp_websocket_client.h b/components/esp_websocket_client/include/esp_websocket_client.h index ae8cc8a4b5..5a0e52e0aa 100644 --- a/components/esp_websocket_client/include/esp_websocket_client.h +++ b/components/esp_websocket_client/include/esp_websocket_client.h @@ -85,6 +85,9 @@ typedef struct { char *subprotocol; /*!< Websocket subprotocol */ char *user_agent; /*!< Websocket user-agent */ char *headers; /*!< Websocket additional headers */ + int pingpong_timeout_sec; /*!< Period before connection is aborted due to no PONGs received */ + bool disable_pingpong_discon; /*!< Disable auto-disconnect due to no PONG received within pingpong_timeout_sec */ + } esp_websocket_client_config_t; /** @@ -185,7 +188,7 @@ int esp_websocket_client_send_bin(esp_websocket_client_handle_t client, const ch int esp_websocket_client_send_text(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout); /** - * @brief Check the WebSocket connection status + * @brief Check the WebSocket client connection state * * @param[in] client The client handle *