Skip to content

Commit eb79b1c

Browse files
committed
fix(websocket): Treat write timeouts as partial success (not fatal errors)
1 parent eb31640 commit eb79b1c

File tree

1 file changed

+52
-6
lines changed

1 file changed

+52
-6
lines changed

components/esp_websocket_client/esp_websocket_client.c

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,13 @@ static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle
243243
static esp_err_t esp_websocket_client_abort_connection(esp_websocket_client_handle_t client, esp_websocket_error_type_t error_type)
244244
{
245245
ESP_WS_CLIENT_STATE_CHECK(TAG, client, return ESP_FAIL);
246+
247+
// Prevent double connection close - check if already closing or closed
248+
if (client->state == WEBSOCKET_STATE_CLOSING || client->state == WEBSOCKET_STATE_UNKNOW) {
249+
ESP_LOGV(TAG, "Connection already closing/closed, skipping abort");
250+
return ESP_OK;
251+
}
252+
246253
esp_transport_close(client->transport);
247254

248255
if (!client->config->auto_reconnect) {
@@ -654,19 +661,58 @@ static int esp_websocket_client_send_with_exact_opcode(esp_websocket_client_hand
654661
// send with ws specific way and specific opcode
655662
wlen = esp_transport_ws_send_raw(client->transport, opcode, (char *)client->tx_buffer, need_write,
656663
(timeout == portMAX_DELAY) ? -1 : timeout * portTICK_PERIOD_MS);
657-
if (wlen < 0 || (wlen == 0 && need_write != 0)) {
664+
if (wlen < 0) {
665+
// Handle negative return values (actual errors)
658666
ret = wlen;
659667
esp_websocket_free_buf(client, true);
660668
esp_tls_error_handle_t error_handle = esp_transport_get_error_handle(client->transport);
661669
if (error_handle) {
662-
esp_websocket_client_error(client, "esp_transport_write() returned %d, transport_error=%s, tls_error_code=%i, tls_flags=%i, errno=%d",
663-
ret, esp_err_to_name(error_handle->last_error), error_handle->esp_tls_error_code,
664-
error_handle->esp_tls_flags, errno);
670+
// Check for specific transport error codes
671+
if (error_handle->last_error == ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT) {
672+
ESP_LOGV(TAG, "Transport layer reported timeout during write");
673+
// Treat timeout as partial success, don't abort connection
674+
ret = 0; // Return 0 to indicate no bytes written but not an error
675+
} else if (error_handle->last_error == ESP_ERR_ESP_TLS_TCP_CLOSED_FIN) {
676+
ESP_LOGD(TAG, "Connection closed by peer during write (FIN)");
677+
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT);
678+
} else {
679+
esp_websocket_client_error(client, "esp_transport_write() failed with %d, transport_error=%s, tls_error_code=%i, tls_flags=%i, errno=%d",
680+
ret, esp_err_to_name(error_handle->last_error), error_handle->esp_tls_error_code,
681+
error_handle->esp_tls_flags, errno);
682+
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT);
683+
}
665684
} else {
666-
esp_websocket_client_error(client, "esp_transport_write() returned %d, errno=%d", ret, errno);
685+
esp_websocket_client_error(client, "esp_transport_write() failed with %d, errno=%d", ret, errno);
686+
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT);
667687
}
668-
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT);
669688
goto unlock_and_return;
689+
} else if (wlen == 0 && need_write != 0) {
690+
// Handle zero return value - could be timeout or connection issue
691+
esp_tls_error_handle_t error_handle = esp_transport_get_error_handle(client->transport);
692+
bool is_timeout = false;
693+
694+
if (error_handle) {
695+
// Check for specific transport error codes that indicate timeout
696+
if (error_handle->last_error == ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT) {
697+
is_timeout = true;
698+
ESP_LOGV(TAG, "Transport layer reported timeout during write (wlen=0)");
699+
}
700+
}
701+
702+
if (is_timeout) {
703+
// Timeout during write - treat as partial success, don't abort connection
704+
ESP_LOGV(TAG, "Write timeout detected, treating as partial success");
705+
ret = 0; // Return 0 to indicate no bytes written but not an error
706+
esp_websocket_free_buf(client, true);
707+
goto unlock_and_return;
708+
} else {
709+
// Not a timeout - likely connection issue, abort connection
710+
ret = -1;
711+
esp_websocket_free_buf(client, true);
712+
esp_websocket_client_error(client, "esp_transport_write() returned 0 with no timeout, connection may be broken");
713+
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT);
714+
goto unlock_and_return;
715+
}
670716
}
671717
opcode = 0;
672718
widx += wlen;

0 commit comments

Comments
 (0)