Bläddra i källkod

Modify esp-tls and tcp_transport to support keep alive for tcp and ssl connection

yuanjm 5 år sedan
förälder
incheckning
f946e296a2

+ 34 - 0
components/esp-tls/esp_tls.c

@@ -148,6 +148,34 @@ static void ms_to_timeval(int timeout_ms, struct timeval *tv)
     tv->tv_usec = (timeout_ms % 1000) * 1000;
 }
 
+static int esp_tls_tcp_enable_keep_alive(int fd, tls_keep_alive_cfg_t *cfg)
+{
+    int keep_alive_enable = 1;
+    int keep_alive_idle = cfg->keep_alive_idle;
+    int keep_alive_interval = cfg->keep_alive_interval;
+    int keep_alive_count = cfg->keep_alive_count;
+
+    ESP_LOGD(TAG, "Enable TCP keep alive. idle: %d, interval: %d, count: %d", keep_alive_idle, keep_alive_interval, keep_alive_count);
+    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) {
+        ESP_LOGE(TAG, "Fail to setsockopt SO_KEEPALIVE");
+        return -1;
+    }
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_idle, sizeof(keep_alive_idle)) != 0) {
+        ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPIDLE");
+        return -1;
+    }
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) != 0) {
+        ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPINTVL");
+        return -1;
+    }
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) != 0) {
+        ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPCNT");
+        return -1;
+    }
+
+    return 0;
+}
+
 static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *sockfd, const esp_tls_t *tls, const esp_tls_cfg_t *cfg)
 {
     esp_err_t ret;
@@ -186,6 +214,12 @@ static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *s
             ms_to_timeval(cfg->timeout_ms, &tv);
             setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
             setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+            if (cfg->keep_alive_cfg && cfg->keep_alive_cfg->keep_alive_enable) {
+                if (esp_tls_tcp_enable_keep_alive(fd, cfg->keep_alive_cfg) < 0) {
+                    ESP_LOGE(TAG, "Error setting keep-alive");
+                    goto err_freesocket;
+                }
+            }
         }
         if (cfg->non_block) {
             int flags = fcntl(fd, F_GETFL, 0);

+ 11 - 1
components/esp-tls/esp_tls.h

@@ -101,6 +101,16 @@ typedef struct psk_key_hint {
     const char* hint;                       /*!< hint in PSK authentication mode in string format */
 } psk_hint_key_t;
 
+/**
+ *  @brief Keep alive parameters structure
+ */
+typedef struct tls_keep_alive_cfg {
+    bool keep_alive_enable;               /*!< Enable keep-alive timeout */
+    int keep_alive_idle;                  /*!< Keep-alive idle time (second) */
+    int keep_alive_interval;              /*!< Keep-alive interval time (second) */
+    int keep_alive_count;                 /*!< Keep-alive packet retry send count */
+} tls_keep_alive_cfg_t;
+
 /**
  * @brief      ESP-TLS configuration parameters 
  * 
@@ -188,7 +198,7 @@ typedef struct esp_tls_cfg {
     const psk_hint_key_t* psk_hint_key;     /*!< Pointer to PSK hint and key. if not NULL (and certificates are NULL)
                                                  then PSK authentication is enabled with configured setup.
                                                  Important note: the pointer must be valid for connection */
-
+    tls_keep_alive_cfg_t *keep_alive_cfg;   /*!< Enable TCP keep-alive timeout for SSL connection */
 } esp_tls_cfg_t;
 
 #ifdef CONFIG_ESP_TLS_SERVER

+ 25 - 1
components/tcp_transport/include/esp_transport.h

@@ -16,11 +16,21 @@
 #define _ESP_TRANSPORT_H_
 
 #include <esp_err.h>
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/**
+*  @brief Keep alive parameters structure
+*/
+typedef struct esp_transport_keepalive {
+    bool            keep_alive_enable;      /*!< Enable keep-alive timeout */
+    int             keep_alive_idle;        /*!< Keep-alive idle time (second) */
+    int             keep_alive_interval;    /*!< Keep-alive interval time (second) */
+    int             keep_alive_count;       /*!< Keep-alive packet retry send count */
+} esp_transport_keep_alive_t;
 
 typedef struct esp_transport_internal* esp_transport_list_handle_t;
 typedef struct esp_transport_item_t* esp_transport_handle_t;
@@ -313,8 +323,22 @@ esp_err_t esp_transport_set_parent_transport_func(esp_transport_handle_t t, payl
   */
 esp_tls_error_handle_t esp_transport_get_error_handle(esp_transport_handle_t t);
 
+/**
+ * @brief      Set keep-alive configuration
+ *
+ * @param[in]  t               The transport handle
+ * @param[in]  keep_alive_cfg  The keep-alive config
+ */
+void esp_transport_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg);
 
-
+/**
+ * @brief      Get keep-alive config of this transport
+ *
+ * @param[in]  t        The transport handle
+ *
+ * @return     The keep-alive configuration
+ */
+void *esp_transport_get_keep_alive(esp_transport_handle_t t);
 #ifdef __cplusplus
 }
 #endif

+ 7 - 0
components/tcp_transport/include/esp_transport_ssl.h

@@ -146,6 +146,13 @@ void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t);
  */
 void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key);
 
+/**
+ * @brief      Set keep-alive status in current ssl context
+ *
+ * @param[in]  t               ssl transport
+ * @param[in]  keep_alive_cfg  The handle for keep-alive configuration
+ */
+void esp_transport_ssl_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg);
 #ifdef __cplusplus
 }
 #endif

+ 8 - 0
components/tcp_transport/include/esp_transport_tcp.h

@@ -21,6 +21,14 @@
 extern "C" {
 #endif
 
+/**
+ * @brief      Set TCP keep-alive configuration
+ *
+ * @param[in]  t               The transport handle
+ * @param[in]  keep_alive_cfg  The keep-alive config
+ */
+void esp_transport_tcp_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg);
+
 /**
  * @brief      Create TCP transport, the transport handle must be release esp_transport_destroy callback
  *

+ 17 - 2
components/tcp_transport/transport.c

@@ -44,7 +44,7 @@ struct esp_transport_item_t {
     connect_async_func _connect_async;      /*!< non-blocking connect function of this transport */
     payload_transfer_func  _parent_transfer;        /*!< Function returning underlying transport layer */
     esp_tls_error_handle_t     error_handle;            /*!< Pointer to esp-tls error handle */
-
+    esp_transport_keep_alive_t *keep_alive_cfg;    /*!< TCP keep-alive config */
     STAILQ_ENTRY(esp_transport_item_t) next;
 };
 
@@ -305,4 +305,19 @@ void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_hand
     if (t)  {
         memcpy(t->error_handle, error_handle, sizeof(esp_tls_last_error_t));
     }
-}
+}
+
+void esp_transport_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg)
+{
+    if (t && keep_alive_cfg) {
+        t->keep_alive_cfg = keep_alive_cfg;
+    }
+}
+
+void *esp_transport_get_keep_alive(esp_transport_handle_t t)
+{
+    if (t) {
+        return t->keep_alive_cfg;
+    }
+    return NULL;
+}

+ 8 - 0
components/tcp_transport/transport_ssl.c

@@ -282,6 +282,14 @@ void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t)
     }
 }
 
+void esp_transport_ssl_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg)
+{
+    transport_ssl_t *ssl = esp_transport_get_context_data(t);
+    if (t && ssl) {
+        ssl->cfg.keep_alive_cfg = (tls_keep_alive_cfg_t *)keep_alive_cfg;
+    }
+}
+
 esp_transport_handle_t esp_transport_ssl_init(void)
 {
     esp_transport_handle_t t = esp_transport_init();

+ 43 - 1
components/tcp_transport/transport_tcp.c

@@ -51,11 +51,40 @@ static int resolve_dns(const char *host, struct sockaddr_in *ip)
     return ESP_OK;
 }
 
+static int tcp_enable_keep_alive(int fd, esp_transport_keep_alive_t *keep_alive_cfg)
+{
+    int keep_alive_enable = 1;
+    int keep_alive_idle = keep_alive_cfg->keep_alive_idle;
+    int keep_alive_interval = keep_alive_cfg->keep_alive_interval;
+    int keep_alive_count = keep_alive_cfg->keep_alive_count;
+
+    ESP_LOGD(TAG, "Enable TCP keep alive. idle: %d, interval: %d, count: %d", keep_alive_idle, keep_alive_interval, keep_alive_count);
+    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) {
+        ESP_LOGE(TAG, "Fail to setsockopt SO_KEEPALIVE");
+        return -1;
+    }
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_idle, sizeof(keep_alive_idle)) != 0) {
+        ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPIDLE");
+        return -1;
+    }
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) != 0) {
+        ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPINTVL");
+        return -1;
+    }
+    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) != 0) {
+        ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPCNT");
+        return -1;
+    }
+
+    return 0;
+}
+
 static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
 {
     struct sockaddr_in remote_ip;
     struct timeval tv = { 0 };
     transport_tcp_t *tcp = esp_transport_get_context_data(t);
+    esp_transport_keep_alive_t *keep_alive_cfg = esp_transport_get_keep_alive(t);
 
     bzero(&remote_ip, sizeof(struct sockaddr_in));
 
@@ -80,7 +109,15 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int
 
     setsockopt(tcp->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
     setsockopt(tcp->sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
-
+    // Set socket keep-alive option
+    if (keep_alive_cfg && keep_alive_cfg->keep_alive_enable) {
+        if (tcp_enable_keep_alive(tcp->sock, keep_alive_cfg) < 0) {
+            ESP_LOGE(TAG, "Error to set tcp [socket=%d] keep-alive", tcp->sock);
+            close(tcp->sock);
+            tcp->sock = -1;
+            return -1;
+        }
+    }
     ESP_LOGD(TAG, "[sock=%d],connecting to server IP:%s,Port:%d...",
              tcp->sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port);
     if (connect(tcp->sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 0) {
@@ -180,6 +217,11 @@ static esp_err_t tcp_destroy(esp_transport_handle_t t)
     return 0;
 }
 
+void esp_transport_tcp_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg)
+{
+    esp_transport_set_keep_alive(t, keep_alive_cfg);
+}
+
 esp_transport_handle_t esp_transport_tcp_init(void)
 {
     esp_transport_handle_t t = esp_transport_init();