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 <shubham.kulkarni@espressif.com>
This commit is contained in:
Laukik Hase 2022-03-07 10:59:54 +05:30
parent 01d014c42d
commit cc7c67ad4e
No known key found for this signature in database
GPG Key ID: 11C571361F51A199
5 changed files with 105 additions and 36 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}