Skip to content

Commit eb31640

Browse files
committed
fix(websocket): Handling timeouts/errors in from tcp_transport
1 parent 34b6681 commit eb31640

File tree

1 file changed

+58
-3
lines changed

1 file changed

+58
-3
lines changed

components/esp_websocket_client/esp_websocket_client.c

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,15 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
972972
esp_websocket_free_buf(client, false);
973973
esp_tls_error_handle_t error_handle = esp_transport_get_error_handle(client->transport);
974974
if (error_handle) {
975+
// Check for specific transport error codes
976+
if (error_handle->last_error == ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT) {
977+
ESP_LOGV(TAG, "Transport layer reported timeout during read");
978+
return ESP_OK; // Treat timeout as OK, not an error
979+
} else if (error_handle->last_error == ESP_ERR_ESP_TLS_TCP_CLOSED_FIN) {
980+
ESP_LOGD(TAG, "Connection closed by peer (FIN)");
981+
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT);
982+
return ESP_FAIL;
983+
}
975984
esp_websocket_client_error(client, "esp_transport_read() failed with %d, transport_error=%s, tls_error_code=%i, tls_flags=%i, errno=%d",
976985
rlen, esp_err_to_name(error_handle->last_error), error_handle->esp_tls_error_code,
977986
error_handle->esp_tls_flags, errno);
@@ -984,10 +993,50 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
984993
client->last_fin = esp_transport_ws_get_fin_flag(client->transport);
985994
client->last_opcode = esp_transport_ws_get_read_opcode(client->transport);
986995

987-
if (rlen == 0 && client->last_opcode == WS_TRANSPORT_OPCODES_NONE) {
988-
ESP_LOGV(TAG, "esp_transport_read timeouts");
996+
// Enhanced timeout detection: Use transport layer error codes to distinguish timeout from valid empty message
997+
if (rlen == 0) {
998+
// Check transport layer error codes to determine if this is a timeout
999+
esp_tls_error_handle_t error_handle = esp_transport_get_error_handle(client->transport);
1000+
bool is_timeout = false;
1001+
1002+
if (error_handle) {
1003+
// Check for specific transport error codes that indicate timeout
1004+
if (error_handle->last_error == ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT) {
1005+
is_timeout = true;
1006+
ESP_LOGV(TAG, "Transport layer reported timeout (ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT)");
1007+
}
1008+
}
1009+
1010+
// Fallback: Check WebSocket frame state for timeout indicators
1011+
if (!is_timeout) {
1012+
// Condition 1: No opcode set (transport layer indicates no frame received)
1013+
if (client->last_opcode == WS_TRANSPORT_OPCODES_NONE) {
1014+
is_timeout = true;
1015+
ESP_LOGV(TAG, "No opcode set, treating as timeout");
1016+
}
1017+
// Condition 2: Check if we're in a fragmented message state but got no data
1018+
else if (client->payload_offset > 0 && client->payload_len > 0 && client->payload_offset < client->payload_len) {
1019+
// We're expecting more data for a fragmented message but got nothing
1020+
is_timeout = true;
1021+
ESP_LOGV(TAG, "Fragmented message timeout (offset=%d, payload_len=%d)",
1022+
client->payload_offset, client->payload_len);
1023+
}
1024+
}
1025+
1026+
if (is_timeout) {
1027+
ESP_LOGV(TAG, "esp_transport_read timeout detected (rlen=%d, opcode=%d, payload_len=%d, offset=%d)",
1028+
rlen, client->last_opcode, client->payload_len, client->payload_offset);
1029+
esp_websocket_free_buf(client, false);
1030+
return ESP_OK;
1031+
}
1032+
}
1033+
1034+
// Additional validation: Check for invalid opcodes that might indicate corruption
1035+
if (rlen > 0 && client->last_opcode > 0xF) {
1036+
ESP_LOGW(TAG, "Received invalid WebSocket opcode: %d (max valid is 15)", client->last_opcode);
9891037
esp_websocket_free_buf(client, false);
990-
return ESP_OK;
1038+
esp_websocket_client_error(client, "Invalid WebSocket opcode received: %d", client->last_opcode);
1039+
return ESP_FAIL;
9911040
}
9921041

9931042
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DATA, client->rx_buffer, rlen);
@@ -1015,6 +1064,12 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
10151064
} else if (client->last_opcode == WS_TRANSPORT_OPCODES_CLOSE) {
10161065
ESP_LOGD(TAG, "Received close frame");
10171066
client->state = WEBSOCKET_STATE_CLOSING;
1067+
} else if (client->last_opcode > 0xF) {
1068+
// Invalid opcode detected - this indicates potential state corruption
1069+
ESP_LOGW(TAG, "Invalid opcode %d detected, resetting client state", client->last_opcode);
1070+
esp_websocket_free_buf(client, false);
1071+
esp_websocket_client_error(client, "Invalid WebSocket opcode %d - potential state corruption", client->last_opcode);
1072+
return ESP_FAIL;
10181073
}
10191074
esp_websocket_free_buf(client, false);
10201075
return ESP_OK;

0 commit comments

Comments
 (0)