From f946e296a23db136c5fe50e25e4fbe6eda32e9bd Mon Sep 17 00:00:00 2001 From: yuanjm Date: Wed, 6 Jan 2021 16:58:39 +0800 Subject: [PATCH] Modify esp-tls and tcp_transport to support keep alive for tcp and ssl connection --- components/esp-tls/esp_tls.c | 34 ++++++++++++++ components/esp-tls/esp_tls.h | 12 ++++- .../tcp_transport/include/esp_transport.h | 26 ++++++++++- .../tcp_transport/include/esp_transport_ssl.h | 7 +++ .../tcp_transport/include/esp_transport_tcp.h | 8 ++++ components/tcp_transport/transport.c | 19 +++++++- components/tcp_transport/transport_ssl.c | 8 ++++ components/tcp_transport/transport_tcp.c | 44 ++++++++++++++++++- 8 files changed, 153 insertions(+), 5 deletions(-) diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 0ae9384135..b3da42b4e8 100644 --- a/components/esp-tls/esp_tls.c +++ b/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); diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index fd7625a559..311fdff645 100644 --- a/components/esp-tls/esp_tls.h +++ b/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 diff --git a/components/tcp_transport/include/esp_transport.h b/components/tcp_transport/include/esp_transport.h index 4841725d0f..70874a2eeb 100644 --- a/components/tcp_transport/include/esp_transport.h +++ b/components/tcp_transport/include/esp_transport.h @@ -16,11 +16,21 @@ #define _ESP_TRANSPORT_H_ #include +#include #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 diff --git a/components/tcp_transport/include/esp_transport_ssl.h b/components/tcp_transport/include/esp_transport_ssl.h index 9ce0b19c31..c044cea020 100644 --- a/components/tcp_transport/include/esp_transport_ssl.h +++ b/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 diff --git a/components/tcp_transport/include/esp_transport_tcp.h b/components/tcp_transport/include/esp_transport_tcp.h index 7a283fe9d5..65ed8eb30b 100644 --- a/components/tcp_transport/include/esp_transport_tcp.h +++ b/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 * diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index d5bc57bb48..0dbad08f6b 100644 --- a/components/tcp_transport/transport.c +++ b/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)); } -} \ No newline at end of file +} + +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; +} diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index f51dc0acdb..1b19fd5fca 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/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(); diff --git a/components/tcp_transport/transport_tcp.c b/components/tcp_transport/transport_tcp.c index d94f483e5c..c8ccf3e6d0 100644 --- a/components/tcp_transport/transport_tcp.c +++ b/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();