From cc7c67ad4e0054ee503d88e9532cd0efe816f242 Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Mon, 7 Mar 2022 10:59:54 +0530 Subject: [PATCH] tcp_transport: Fix error propogation - Made tcp_transport_errors codes public to indicate TCP connection issues not covered in socket's errno - Added API to translate tcp_transport_error codes to esp_err_t codes for TCP Transport Co-authored-by: Shubham Kulkarni --- components/esp_common/src/esp_err_to_name.c | 20 +++++++++ .../tcp_transport/include/esp_transport.h | 31 +++++++++++++- .../private_include/esp_transport_internal.h | 14 +------ components/tcp_transport/transport.c | 35 +++++++++++----- components/tcp_transport/transport_ssl.c | 41 +++++++++++++------ 5 files changed, 105 insertions(+), 36 deletions(-) diff --git a/components/esp_common/src/esp_err_to_name.c b/components/esp_common/src/esp_err_to_name.c index b38638f76e..10151ac2c6 100644 --- a/components/esp_common/src/esp_err_to_name.c +++ b/components/esp_common/src/esp_err_to_name.c @@ -53,6 +53,9 @@ #if __has_include("esp_tls_errors.h") #include "esp_tls_errors.h" #endif +#if __has_include("esp_transport.h") +#include "esp_transport.h" +#endif #if __has_include("esp_wifi.h") #include "esp_wifi.h" #endif @@ -796,6 +799,23 @@ static const esp_err_msg_t esp_err_msg_table[] = { # endif # ifdef ESP_ERR_MEMPROT_AREA_INVALID ERR_TBL_IT(ESP_ERR_MEMPROT_AREA_INVALID), /* 53255 0xd007 */ +# endif + // components/tcp_transport/include/esp_transport.h +# ifdef ESP_ERR_TCP_TRANSPORT_BASE + ERR_TBL_IT(ESP_ERR_TCP_TRANSPORT_BASE), /* 57344 0xe000 Starting number of TCP Transport error codes */ +# endif +# ifdef ESP_ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT + ERR_TBL_IT(ESP_ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT), /* 57345 0xe001 Connection has timed out */ +# endif +# ifdef ESP_ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN + ERR_TBL_IT(ESP_ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN), /* 57346 0xe002 Read FIN from peer and the connection + has closed (in a clean way) */ +# endif +# ifdef ESP_ERR_TCP_TRANSPORT_CONNECTION_FAILED + ERR_TBL_IT(ESP_ERR_TCP_TRANSPORT_CONNECTION_FAILED), /* 57347 0xe003 Failed to connect to the peer */ +# endif +# ifdef ESP_ERR_TCP_TRANSPORT_NO_MEM + ERR_TBL_IT(ESP_ERR_TCP_TRANSPORT_NO_MEM), /* 57348 0xe004 Memory allocation failed */ # endif }; #endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP diff --git a/components/tcp_transport/include/esp_transport.h b/components/tcp_transport/include/esp_transport.h index e165ea11c0..bc1490df06 100644 --- a/components/tcp_transport/include/esp_transport.h +++ b/components/tcp_transport/include/esp_transport.h @@ -37,6 +37,22 @@ typedef esp_transport_handle_t (*payload_transfer_func)(esp_transport_handle_t); typedef struct esp_tls_last_error* esp_tls_error_handle_t; +/** + * @brief Error types for TCP connection issues not covered in socket's errno + */ +enum esp_tcp_transport_err_t { + ERR_TCP_TRANSPORT_NO_MEM = -3, + ERR_TCP_TRANSPORT_CONNECTION_FAILED = -2, + ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN = -1, + ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT = 0, +}; + +#define ESP_ERR_TCP_TRANSPORT_BASE (0xe000) /*!< Starting number of TCP Transport error codes */ +#define ESP_ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT (ESP_ERR_TCP_TRANSPORT_BASE + 1) /*!< Connection has timed out */ +#define ESP_ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN (ESP_ERR_TCP_TRANSPORT_BASE + 2) /*!< Read FIN from peer and the connection has closed (in a clean way) */ +#define ESP_ERR_TCP_TRANSPORT_CONNECTION_FAILED (ESP_ERR_TCP_TRANSPORT_BASE + 3) /*!< Failed to connect to the peer */ +#define ESP_ERR_TCP_TRANSPORT_NO_MEM (ESP_ERR_TCP_TRANSPORT_BASE + 4) /*!< Memory allocation failed */ + /** * @brief Create transport list * @@ -169,7 +185,11 @@ int esp_transport_connect_async(esp_transport_handle_t t, const char *host, int * * @return * - Number of bytes was read - * - (-1) if there are any errors, should check errno + * - 0 Read timed-out + * - (<0) For other errors + * + * @note: Please refer to the enum `esp_tcp_transport_err_t` for all the possible return values + * */ int esp_transport_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms); @@ -334,6 +354,15 @@ esp_tls_error_handle_t esp_transport_get_error_handle(esp_transport_handle_t t); */ int esp_transport_get_errno(esp_transport_handle_t t); +/** + * @brief Translates the TCP transport error codes to esp_err_t error codes + * + * @param[in] error TCP Transport specific error code + * + * @return Corresponding esp_err_t based error code + */ +esp_err_t esp_transport_translate_error(enum esp_tcp_transport_err_t error); + #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/private_include/esp_transport_internal.h b/components/tcp_transport/private_include/esp_transport_internal.h index 616086e76d..64a52fd38f 100644 --- a/components/tcp_transport/private_include/esp_transport_internal.h +++ b/components/tcp_transport/private_include/esp_transport_internal.h @@ -45,18 +45,6 @@ struct esp_transport_item_t { STAILQ_ENTRY(esp_transport_item_t) next; }; -/** - * @brief Internal error types for TCP connection issues not covered in socket's errno - */ -enum tcp_transport_errors { - ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT, - ERR_TCP_TRANSPORT_CANNOT_RESOLVE_HOSTNAME, - ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN, - ERR_TCP_TRANSPORT_CONNECTION_FAILED, - ERR_TCP_TRANSPORT_SETOPT_FAILED, - ERR_TCP_TRANSPORT_NO_MEM, -}; - /** * @brief Captures internal tcp connection error * @@ -67,7 +55,7 @@ enum tcp_transport_errors { * @param[in] error Internal tcp-transport's error * */ -void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_errors error); +void capture_tcp_transport_error(esp_transport_handle_t t, enum esp_tcp_transport_err_t error); /** * @brief Returns underlying socket for the supplied transport handle diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index 902786cf0d..4fa4fa9c36 100644 --- a/components/tcp_transport/transport.c +++ b/components/tcp_transport/transport.c @@ -318,25 +318,19 @@ int esp_transport_get_errno(esp_transport_handle_t t) return -1; } -void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_errors error) +void capture_tcp_transport_error(esp_transport_handle_t t, enum esp_tcp_transport_err_t error) { esp_tls_last_error_t *err_handle = esp_transport_get_error_handle(t); switch (error) { - case ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT: - err_handle->last_error = ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT; - break; - case ERR_TCP_TRANSPORT_CANNOT_RESOLVE_HOSTNAME: - err_handle->last_error = ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME; - break; case ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN: err_handle->last_error = ESP_ERR_ESP_TLS_TCP_CLOSED_FIN; break; + case ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT: + err_handle->last_error = ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT; + break; case ERR_TCP_TRANSPORT_CONNECTION_FAILED: err_handle->last_error = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; break; - case ERR_TCP_TRANSPORT_SETOPT_FAILED: - err_handle->last_error = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; - break; case ERR_TCP_TRANSPORT_NO_MEM: err_handle->last_error = ESP_ERR_NO_MEM; break; @@ -368,3 +362,24 @@ int esp_transport_get_socket(esp_transport_handle_t t) } return -1; } + +esp_err_t esp_transport_translate_error(enum esp_tcp_transport_err_t error) +{ + esp_err_t err = ESP_FAIL; + switch (error) { + case ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN: + err = ESP_ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN; + break; + case ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT: + err = ESP_ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT; + break; + case ERR_TCP_TRANSPORT_CONNECTION_FAILED: + err = ESP_ERR_TCP_TRANSPORT_CONNECTION_FAILED; + break; + case ERR_TCP_TRANSPORT_NO_MEM: + err = ESP_ERR_TCP_TRANSPORT_NO_MEM; + break; + } + + return err; +} diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 5794263b03..507fae3871 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -174,6 +174,8 @@ static int base_poll_read(esp_transport_handle_t t, int timeout_ms) esp_transport_capture_errno(t, sock_errno); ESP_LOGE(TAG, "poll_read select error %d, errno = %s, fd = %d", sock_errno, strerror(sock_errno), ssl->sockfd); ret = -1; + } else if (ret == 0) { + ESP_LOGD(TAG, "poll_read: select - Timeout before any socket was ready!"); } return ret; } @@ -197,6 +199,8 @@ static int base_poll_write(esp_transport_handle_t t, int timeout_ms) esp_transport_capture_errno(t, sock_errno); ESP_LOGE(TAG, "poll_write select error %d, errno = %s, fd = %d", sock_errno, strerror(sock_errno), ssl->sockfd); ret = -1; + } else if (ret == 0) { + ESP_LOGD(TAG, "poll_write: select - Timeout before any socket was ready!"); } return ret; } @@ -242,51 +246,64 @@ static int tcp_write(esp_transport_handle_t t, const char *buffer, int len, int static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms) { - int poll; transport_esp_tls_t *ssl = ssl_get_context_data(t); - if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) { - return poll; + int poll = esp_transport_poll_read(t, timeout_ms); + if (poll == -1) { + return ERR_TCP_TRANSPORT_CONNECTION_FAILED; } + if (poll == 0) { + return ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT; + } + int ret = esp_tls_conn_read(ssl->tls, (unsigned char *)buffer, len); if (ret < 0) { ESP_LOGE(TAG, "esp_tls_conn_read error, errno=%s", strerror(errno)); + if (ret == ESP_TLS_ERR_SSL_WANT_READ || ret == ESP_TLS_ERR_SSL_TIMEOUT) { + ret = ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT; + } + esp_tls_error_handle_t esp_tls_error_handle; if (esp_tls_get_error_handle(ssl->tls, &esp_tls_error_handle) == ESP_OK) { esp_transport_set_errors(t, esp_tls_error_handle); } else { ESP_LOGE(TAG, "Error in obtaining the error handle"); } - } - if (ret == 0) { + } else if (ret == 0) { if (poll > 0) { // no error, socket reads 0 while previously detected as readable -> connection has been closed cleanly capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN); } - ret = -1; + ret = ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN; } return ret; } static int tcp_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms) { - int poll; transport_esp_tls_t *ssl = ssl_get_context_data(t); - if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) { - return poll; + int poll = esp_transport_poll_read(t, timeout_ms); + if (poll == -1) { + return ERR_TCP_TRANSPORT_CONNECTION_FAILED; } + if (poll == 0) { + return ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT; + } + int ret = recv(ssl->sockfd, (unsigned char *)buffer, len, 0); if (ret < 0) { ESP_LOGE(TAG, "tcp_read error, errno=%s", strerror(errno)); esp_transport_capture_errno(t, errno); - } - if (ret == 0) { + if (errno == EAGAIN) { + ret = ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT; + } + } else if (ret == 0) { if (poll > 0) { // no error, socket reads 0 while previously detected as readable -> connection has been closed cleanly capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN); } - ret = -1; + ret = ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN; } return ret; }