Просмотр исходного кода

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>

Laukik Hase 3 лет назад
Родитель
Сommit
cc7c67ad4e

+ 20 - 0
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

+ 30 - 1
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

+ 1 - 13
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

+ 25 - 10
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;
+}

+ 29 - 12
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;
 }