diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index 36569cfd51..839161e4bf 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -24,3 +24,8 @@ if(CONFIG_ESP_TLS_USE_SE) idf_component_get_property(cryptoauthlib esp-cryptoauthlib COMPONENT_LIB) target_link_libraries(${COMPONENT_LIB} PUBLIC ${cryptoauthlib}) endif() + +# Increase link multiplicity to get some lwip symbols correctly resolved by the linker +# due to cyclic dependencies present in IDF for lwip/esp_netif/mbedtls +idf_component_get_property(lwip lwip COMPONENT_LIB) +set_property(TARGET ${lwip} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 5) diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 80cbf417be..9eb1502c18 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -45,6 +45,7 @@ static const char *TAG = "esp-tls"; #define _esp_tls_read esp_mbedtls_read #define _esp_tls_write esp_mbedtls_write #define _esp_tls_conn_delete esp_mbedtls_conn_delete +#define _esp_tls_net_init esp_mbedtls_net_init #ifdef CONFIG_ESP_TLS_SERVER #define _esp_tls_server_session_create esp_mbedtls_server_session_create #define _esp_tls_server_session_delete esp_mbedtls_server_session_delete @@ -60,6 +61,7 @@ static const char *TAG = "esp-tls"; #define _esp_tls_read esp_wolfssl_read #define _esp_tls_write esp_wolfssl_write #define _esp_tls_conn_delete esp_wolfssl_conn_delete +#define _esp_tls_net_init esp_wolfssl_net_init #ifdef CONFIG_ESP_TLS_SERVER #define _esp_tls_server_session_create esp_wolfssl_server_session_create #define _esp_tls_server_session_delete esp_wolfssl_server_session_delete @@ -126,15 +128,14 @@ esp_tls_t *esp_tls_init(void) free(tls); return NULL; } -#ifdef CONFIG_ESP_TLS_USING_MBEDTLS - tls->server_fd.fd = -1; -#endif + _esp_tls_net_init(tls); tls->sockfd = -1; return tls; } -static esp_err_t resolve_host_name(const char *host, size_t hostlen, struct addrinfo **address_info) +static esp_err_t esp_tls_hostname_to_fd(const char *host, size_t hostlen, int port, struct sockaddr_storage *address, int* fd) { + struct addrinfo *address_info; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; @@ -146,12 +147,40 @@ static esp_err_t resolve_host_name(const char *host, size_t hostlen, struct addr } ESP_LOGD(TAG, "host:%s: strlen %lu", use_host, (unsigned long)hostlen); - if (getaddrinfo(use_host, NULL, &hints, address_info)) { - ESP_LOGE(TAG, "couldn't get hostname for :%s:", use_host); + int res = getaddrinfo(use_host, NULL, &hints, &address_info); + if (res != 0 || address_info == NULL) { + ESP_LOGE(TAG, "couldn't get hostname for :%s: " + "getaddrinfo() returns %d, addrinfo=%p", use_host, res, address_info); free(use_host); return ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME; } free(use_host); + *fd = socket(address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol); + if (*fd < 0) { + ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol); + freeaddrinfo(address_info); + return ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET; + } + + if (address_info->ai_family == AF_INET) { + struct sockaddr_in *p = (struct sockaddr_in *)address_info->ai_addr; + p->sin_port = htons(port); + ESP_LOGD(TAG, "[sock=%d] Resolved IPv4 address: %s", *fd, ipaddr_ntoa((const ip_addr_t*)&p->sin_addr.s_addr)); + memcpy(address, p, sizeof(struct sockaddr )); + } else if (address_info->ai_family == AF_INET6) { + struct sockaddr_in6 *p = (struct sockaddr_in6 *)address_info->ai_addr; + p->sin6_port = htons(port); + p->sin6_family = AF_INET6; + ESP_LOGD(TAG, "[sock=%d] Resolved IPv6 address: %s", *fd, ip6addr_ntoa((const ip6_addr_t*)&p->sin6_addr)); + memcpy(address, p, sizeof(struct sockaddr_in6 )); + } else { + ESP_LOGE(TAG, "Unsupported protocol family %d", address_info->ai_family); + close(*fd); + freeaddrinfo(address_info); + return ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY; + } + + freeaddrinfo(address_info); return ESP_OK; } @@ -161,106 +190,153 @@ 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) +static esp_err_t esp_tls_set_socket_options(int fd, const esp_tls_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; + if (cfg && cfg->timeout_ms >= 0) { + struct timeval tv; + ms_to_timeval(cfg->timeout_ms, &tv); + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) { + ESP_LOGE(TAG, "Fail to setsockopt SO_RCVTIMEO"); + return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + } + if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) { + ESP_LOGE(TAG, "Fail to setsockopt SO_SNDTIMEO"); + return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + } + if (cfg->keep_alive_cfg && cfg->keep_alive_cfg->keep_alive_enable) { + int keep_alive_enable = 1; + int keep_alive_idle = cfg->keep_alive_cfg->keep_alive_idle; + int keep_alive_interval = cfg->keep_alive_cfg->keep_alive_interval; + int keep_alive_count = cfg->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; + 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 ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + } + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) { + ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPIDLE"); + return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + } + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) != 0) { + ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPINTVL"); + return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + } + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) != 0) { + ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPCNT"); + return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + } + } } - 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 ESP_OK; +} + +static esp_err_t esp_tls_set_socket_non_blocking(int fd, bool non_blocking) +{ + int flags; + if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) { + ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", fd, strerror(errno)); + return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; } - return 0; + if (non_blocking) { + flags |= O_NONBLOCK; + } else { + flags &= ~O_NONBLOCK; + } + + if (fcntl(fd, F_SETFL, flags) < 0) { + ESP_LOGE(TAG, "[sock=%d] set blocking/nonblocking error: %s", fd, strerror(errno)); + return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + } + return ESP_OK; } 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; - struct addrinfo *addrinfo; - if ((ret = resolve_host_name(host, hostlen, &addrinfo)) != ESP_OK) { + struct sockaddr_storage address; + int fd; + esp_err_t ret = esp_tls_hostname_to_fd(host, hostlen, port, &address, &fd); + if (ret != ESP_OK) { + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno); return ret; } - int fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); - if (fd < 0) { - ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); - ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno); - ret = ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET; - goto err_freeaddr; + // Set timeout options and keep-alive options if configured + ret = esp_tls_set_socket_options(fd, cfg); + if (ret != ESP_OK) { + goto err; } - void *addr_ptr; - if (addrinfo->ai_family == AF_INET) { - struct sockaddr_in *p = (struct sockaddr_in *)addrinfo->ai_addr; - p->sin_port = htons(port); - addr_ptr = p; - } else if (addrinfo->ai_family == AF_INET6) { - struct sockaddr_in6 *p = (struct sockaddr_in6 *)addrinfo->ai_addr; - p->sin6_port = htons(port); - p->sin6_family = AF_INET6; - addr_ptr = p; - } else { - ESP_LOGE(TAG, "Unsupported protocol family %d", addrinfo->ai_family); - ret = ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY; - goto err_freesocket; + // Set to non block before connecting to better control connection timeout + ret = esp_tls_set_socket_non_blocking(fd, true); + if (ret != ESP_OK) { + goto err; } - if (cfg) { - if (cfg->timeout_ms >= 0) { - struct timeval tv; - 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; + ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; + ESP_LOGD(TAG, "[sock=%d] Connecting to server. HOST: %s, Port: %d", fd, host, port); + if (connect(fd, (struct sockaddr *)&address, sizeof(struct sockaddr)) < 0) { + if (errno == EINPROGRESS) { + fd_set fdset; + struct timeval tv = { .tv_usec = 0, .tv_sec = 10 }; // Default connection timeout is 10 s + + if (cfg && cfg->non_block) { + // Non-blocking mode -> just return successfully at this stage + *sockfd = fd; + return ESP_OK; + } + + if ( cfg && cfg->timeout_ms > 0 ) { + ms_to_timeval(cfg->timeout_ms, &tv); + } + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + + int res = select(fd+1, NULL, &fdset, NULL, &tv); + if (res < 0) { + ESP_LOGE(TAG, "[sock=%d] select() error: %s", fd, strerror(errno)); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno); + goto err; + } + else if (res == 0) { + ESP_LOGE(TAG, "[sock=%d] select() timeout", fd); + ret = ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT; + goto err; + } else { + int sockerr; + socklen_t len = (socklen_t)sizeof(int); + + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) { + ESP_LOGE(TAG, "[sock=%d] getsockopt() error: %s", fd, strerror(errno)); + ret = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + goto err; + } + else if (sockerr) { + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, sockerr); + ESP_LOGE(TAG, "[sock=%d] delayed connect error: %s", fd, strerror(sockerr)); + goto err; } } - } - if (cfg->non_block) { - int flags = fcntl(fd, F_GETFL, 0); - ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - if (ret < 0) { - ESP_LOGE(TAG, "Failed to configure the socket as non-blocking (errno %d)", errno); - goto err_freesocket; - } + } else { + ESP_LOGE(TAG, "[sock=%d] connect() error: %s", fd, strerror(errno)); + goto err; } } - ret = connect(fd, addr_ptr, addrinfo->ai_addrlen); - if (ret < 0 && !(errno == EINPROGRESS && cfg && cfg->non_block)) { - - ESP_LOGE(TAG, "Failed to connnect to host (errno %d)", errno); - ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno); - ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; - goto err_freesocket; + if (cfg && cfg->non_block == false) { + // reset back to blocking mode (unless non_block configured) + ret = esp_tls_set_socket_non_blocking(fd, false); + if (ret != ESP_OK) { + goto err; + } } *sockfd = fd; - freeaddrinfo(addrinfo); return ESP_OK; -err_freesocket: +err: close(fd); -err_freeaddr: - freeaddrinfo(addrinfo); return ret; } @@ -276,23 +352,21 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c switch (tls->conn_state) { case ESP_TLS_INIT: tls->sockfd = -1; - if (cfg != NULL) { -#ifdef CONFIG_ESP_TLS_USING_MBEDTLS - mbedtls_net_init(&tls->server_fd); -#endif + if (cfg != NULL && cfg->is_plain_tcp == false) { + _esp_tls_net_init(tls); tls->is_tls = true; } if ((esp_ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, tls, cfg)) != ESP_OK) { ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, esp_ret); return -1; } - if (!cfg) { + if (tls->is_tls == false) { tls->read = tcp_read; tls->write = tcp_write; ESP_LOGD(TAG, "non-tls connection established"); return 1; } - if (cfg->non_block) { + if (cfg && cfg->non_block) { FD_ZERO(&tls->rset); FD_SET(tls->sockfd, &tls->rset); tls->wset = tls->rset; @@ -300,7 +374,7 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c tls->conn_state = ESP_TLS_CONNECTING; /* falls through */ case ESP_TLS_CONNECTING: - if (cfg->non_block) { + if (cfg && cfg->non_block) { ESP_LOGD(TAG, "connecting..."); struct timeval tv; ms_to_timeval(cfg->timeout_ms, &tv); diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index a3ab33b3d4..981379435c 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -18,6 +18,7 @@ #include #include #include "esp_err.h" +#include "esp_tls_errors.h" #ifdef CONFIG_ESP_TLS_USING_MBEDTLS #include "mbedtls/platform.h" #include "mbedtls/net_sockets.h" @@ -36,71 +37,6 @@ extern "C" { #endif -#define ESP_ERR_ESP_TLS_BASE 0x8000 /*!< Starting number of ESP-TLS error codes */ -#define ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME (ESP_ERR_ESP_TLS_BASE + 0x01) /*!< Error if hostname couldn't be resolved upon tls connection */ -#define ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET (ESP_ERR_ESP_TLS_BASE + 0x02) /*!< Failed to create socket */ -#define ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY (ESP_ERR_ESP_TLS_BASE + 0x03) /*!< Unsupported protocol family */ -#define ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST (ESP_ERR_ESP_TLS_BASE + 0x04) /*!< Failed to connect to host */ -#define ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x05) /*!< failed to set socket option */ -#define ESP_ERR_MBEDTLS_CERT_PARTLY_OK (ESP_ERR_ESP_TLS_BASE + 0x06) /*!< mbedtls parse certificates was partly successful */ -#define ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED (ESP_ERR_ESP_TLS_BASE + 0x07) /*!< mbedtls api returned error */ -#define ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x08) /*!< mbedtls api returned error */ -#define ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x09) /*!< mbedtls api returned error */ -#define ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0A) /*!< mbedtls api returned error */ -#define ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0B) /*!< mbedtls api returned error */ -#define ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0C) /*!< mbedtls api returned error */ -#define ESP_ERR_MBEDTLS_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0D) /*!< mbedtls api returned error */ -#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */ -#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */ -#define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */ -#define ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT (ESP_ERR_ESP_TLS_BASE + 0x12) /*!< new connection in esp_tls_low_level_conn connection timeouted */ -#define ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x13) /*!< wolfSSL api returned error */ -#define ESP_ERR_WOLFSSL_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x14) /*!< wolfSSL api returned error */ -#define ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x15) /*!< wolfSSL api returned error */ -#define ESP_ERR_WOLFSSL_KEY_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x16) /*!< wolfSSL api returned error */ -#define ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x17) /*!< wolfSSL api returned failed */ -#define ESP_ERR_WOLFSSL_CTX_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x18) /*!< wolfSSL api returned failed */ -#define ESP_ERR_WOLFSSL_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x19) /*!< wolfSSL api returned failed */ -#define ESP_ERR_WOLFSSL_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1A) /*!< wolfSSL api returned failed */ - -#define ESP_ERR_ESP_TLS_SE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1B) /*< esp-tls use Secure Element returned failed */ -#ifdef CONFIG_ESP_TLS_USING_MBEDTLS -#define ESP_TLS_ERR_SSL_WANT_READ MBEDTLS_ERR_SSL_WANT_READ -#define ESP_TLS_ERR_SSL_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE -#define ESP_TLS_ERR_SSL_TIMEOUT MBEDTLS_ERR_SSL_TIMEOUT -#elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */ -#define ESP_TLS_ERR_SSL_WANT_READ WOLFSSL_ERROR_WANT_READ -#define ESP_TLS_ERR_SSL_WANT_WRITE WOLFSSL_ERROR_WANT_WRITE -#define ESP_TLS_ERR_SSL_TIMEOUT WOLFSSL_CBIO_ERR_TIMEOUT -#endif /*CONFIG_ESP_TLS_USING_WOLFSSL */ - -/** -* Definition of different types/sources of error codes reported -* from different components -*/ -typedef enum { - ESP_TLS_ERR_TYPE_UNKNOWN = 0, - ESP_TLS_ERR_TYPE_SYSTEM, /*!< System error -- errno */ - ESP_TLS_ERR_TYPE_MBEDTLS, /*!< Error code from mbedTLS library */ - ESP_TLS_ERR_TYPE_MBEDTLS_CERT_FLAGS, /*!< Certificate flags defined in mbedTLS */ - ESP_TLS_ERR_TYPE_ESP, /*!< ESP-IDF error type -- esp_err_t */ - ESP_TLS_ERR_TYPE_WOLFSSL, /*!< Error code from wolfSSL library */ - ESP_TLS_ERR_TYPE_WOLFSSL_CERT_FLAGS, /*!< Certificate flags defined in wolfSSL */ - ESP_TLS_ERR_TYPE_MAX, /*!< Last err type -- invalid entry */ -} esp_tls_error_type_t; - -typedef struct esp_tls_last_error* esp_tls_error_handle_t; - -/** -* @brief Error structure containing relevant errors in case tls error occurred -*/ -typedef struct esp_tls_last_error { - esp_err_t last_error; /*!< error code (based on ESP_ERR_ESP_TLS_BASE) of the last occurred error */ - int esp_tls_error_code; /*!< esp_tls error code from last esp_tls failed api */ - int esp_tls_flags; /*!< last certification verification flags */ -} esp_tls_last_error_t; - /** * @brief ESP-TLS Connection State */ @@ -234,6 +170,8 @@ typedef struct esp_tls_cfg { bundle for server verification, must be enabled in menuconfig */ void *ds_data; /*!< Pointer for digital signature peripheral context */ + bool is_plain_tcp; /*!< Use non-TLS connection: When set to true, the esp-tls uses + plain TCP transport rather then TLS/SSL connection */ } esp_tls_cfg_t; #ifdef CONFIG_ESP_TLS_SERVER diff --git a/components/esp-tls/esp_tls_errors.h b/components/esp-tls/esp_tls_errors.h new file mode 100644 index 0000000000..bb281b0dae --- /dev/null +++ b/components/esp-tls/esp_tls_errors.h @@ -0,0 +1,100 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_TLS_ERRORS_H_ +#define _ESP_TLS_ERRORS_H_ + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_ERR_ESP_TLS_BASE 0x8000 /*!< Starting number of ESP-TLS error codes */ +#define ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME (ESP_ERR_ESP_TLS_BASE + 0x01) /*!< Error if hostname couldn't be resolved upon tls connection */ +#define ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET (ESP_ERR_ESP_TLS_BASE + 0x02) /*!< Failed to create socket */ +#define ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY (ESP_ERR_ESP_TLS_BASE + 0x03) /*!< Unsupported protocol family */ +#define ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST (ESP_ERR_ESP_TLS_BASE + 0x04) /*!< Failed to connect to host */ +#define ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x05) /*!< failed to set/get socket option */ +#define ESP_ERR_MBEDTLS_CERT_PARTLY_OK (ESP_ERR_ESP_TLS_BASE + 0x06) /*!< mbedtls parse certificates was partly successful */ +#define ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED (ESP_ERR_ESP_TLS_BASE + 0x07) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x08) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x09) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0A) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0B) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0C) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0D) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */ +#define ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT (ESP_ERR_ESP_TLS_BASE + 0x12) /*!< new connection in esp_tls_low_level_conn connection timeouted */ +#define ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x13) /*!< wolfSSL api returned error */ +#define ESP_ERR_WOLFSSL_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x14) /*!< wolfSSL api returned error */ +#define ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x15) /*!< wolfSSL api returned error */ +#define ESP_ERR_WOLFSSL_KEY_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x16) /*!< wolfSSL api returned error */ +#define ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x17) /*!< wolfSSL api returned failed */ +#define ESP_ERR_WOLFSSL_CTX_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x18) /*!< wolfSSL api returned failed */ +#define ESP_ERR_WOLFSSL_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x19) /*!< wolfSSL api returned failed */ +#define ESP_ERR_WOLFSSL_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1A) /*!< wolfSSL api returned failed */ + +#define ESP_ERR_ESP_TLS_SE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1B) /*< esp-tls use Secure Element returned failed */ +#define ESP_ERR_ESP_TLS_TCP_CLOSED_FIN (ESP_ERR_ESP_TLS_BASE + 0x1C) /*< esp-tls's TPC transport connection has benn closed (in a clean way) */ + +/** +* Definition of errors reported from IO API (potentially non-blocking) in case of error: +* - esp_tls_conn_read() +* - esp_tls_conn_write() +*/ +#ifdef CONFIG_ESP_TLS_USING_MBEDTLS +#define ESP_TLS_ERR_SSL_WANT_READ MBEDTLS_ERR_SSL_WANT_READ +#define ESP_TLS_ERR_SSL_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE +#define ESP_TLS_ERR_SSL_TIMEOUT MBEDTLS_ERR_SSL_TIMEOUT +#elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */ +#define ESP_TLS_ERR_SSL_WANT_READ -0x6900 +#define ESP_TLS_ERR_SSL_WANT_WRITE -0x6880 +#define ESP_TLS_ERR_SSL_TIMEOUT WOLFSSL_CBIO_ERR_TIMEOUT +#endif /*CONFIG_ESP_TLS_USING_WOLFSSL */ + +/** +* Definition of different types/sources of error codes reported +* from different components +*/ +typedef enum { + ESP_TLS_ERR_TYPE_UNKNOWN = 0, + ESP_TLS_ERR_TYPE_SYSTEM, /*!< System error -- errno */ + ESP_TLS_ERR_TYPE_MBEDTLS, /*!< Error code from mbedTLS library */ + ESP_TLS_ERR_TYPE_MBEDTLS_CERT_FLAGS, /*!< Certificate flags defined in mbedTLS */ + ESP_TLS_ERR_TYPE_ESP, /*!< ESP-IDF error type -- esp_err_t */ + ESP_TLS_ERR_TYPE_WOLFSSL, /*!< Error code from wolfSSL library */ + ESP_TLS_ERR_TYPE_WOLFSSL_CERT_FLAGS, /*!< Certificate flags defined in wolfSSL */ + ESP_TLS_ERR_TYPE_MAX, /*!< Last err type -- invalid entry */ +} esp_tls_error_type_t; + +typedef struct esp_tls_last_error* esp_tls_error_handle_t; + +/** +* @brief Error structure containing relevant errors in case tls error occurred +*/ +typedef struct esp_tls_last_error { + esp_err_t last_error; /*!< error code (based on ESP_ERR_ESP_TLS_BASE) of the last occurred error */ + int esp_tls_error_code; /*!< esp_tls error code from last esp_tls failed api */ + int esp_tls_flags; /*!< last certification verification flags */ +} esp_tls_last_error_t; + +#ifdef __cplusplus +} +#endif + +#endif //_ESP_TLS_ERRORS_H_ diff --git a/components/esp-tls/esp_tls_wolfssl.c b/components/esp-tls/esp_tls_wolfssl.c index 9faab69119..b249fba3bc 100644 --- a/components/esp-tls/esp_tls_wolfssl.c +++ b/components/esp-tls/esp_tls_wolfssl.c @@ -62,6 +62,20 @@ typedef enum x509_file_type { FILE_TYPE_SELF_KEY, /* Private key in the self cert-key pair */ } x509_file_type_t; +/* Error type conversion utility so that esp-tls read/write API to return negative number on error */ +static inline ssize_t esp_tls_convert_wolfssl_err_to_ssize(int wolfssl_error) +{ + switch (wolfssl_error) { + case WOLFSSL_ERROR_WANT_READ: + return ESP_TLS_ERR_SSL_WANT_READ; + case WOLFSSL_ERROR_WANT_WRITE: + return ESP_TLS_ERR_SSL_WANT_WRITE; + default: + // Make sure we return a negative number + return wolfssl_error>0 ? -wolfssl_error: wolfssl_error; + } +} + /* Checks whether the certificate provided is in pem format or not */ static esp_err_t esp_load_wolfssl_verify_buffer(esp_tls_t *tls, const unsigned char *cert_buf, unsigned int cert_len, x509_file_type_t type, int *err_ret) { @@ -332,9 +346,9 @@ int esp_wolfssl_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg) return 1; } else { int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret); - if (err != ESP_TLS_ERR_SSL_WANT_READ && err != ESP_TLS_ERR_SSL_WANT_WRITE) { - ESP_LOGE(TAG, "wolfSSL_connect returned -0x%x", -ret); - ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, -ret); + if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) { + ESP_LOGE(TAG, "wolfSSL_connect returned %d, error code: 0x%x", ret, err); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, -err); ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED); if (cfg->cacert_buf != NULL || cfg->use_global_ca_store == true) { /* This is to check whether handshake failed due to invalid certificate*/ @@ -359,10 +373,11 @@ ssize_t esp_wolfssl_read(esp_tls_t *tls, char *data, size_t datalen) return 0; } - if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE) { + if (ret != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) { ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, -ret); ESP_LOGE(TAG, "read error :%d:", ret); } + return esp_tls_convert_wolfssl_err_to_ssize(ret); } return ret; } @@ -372,12 +387,13 @@ ssize_t esp_wolfssl_write(esp_tls_t *tls, const char *data, size_t datalen) ssize_t ret = wolfSSL_write( (WOLFSSL *)tls->priv_ssl, (unsigned char *) data, datalen); if (ret < 0) { ret = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret); - if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE) { + if (ret != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) { ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, -ret); ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, ESP_ERR_WOLFSSL_SSL_WRITE_FAILED); ESP_LOGE(TAG, "write error :%d:", ret); } + return esp_tls_convert_wolfssl_err_to_ssize(ret); } return ret; } @@ -447,11 +463,12 @@ int esp_wolfssl_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp tls->write = esp_wolfssl_write; int ret; while ((ret = wolfSSL_accept((WOLFSSL *)tls->priv_ssl)) != WOLFSSL_SUCCESS) { - if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE) { + ret = wolfSSL_get_error((WOLFSSL *)tls->priv_ssl, ret); + if (ret != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) { ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, -ret); ESP_LOGE(TAG, "wolfSSL_handshake_server returned %d", ret); tls->conn_state = ESP_TLS_FAIL; - return ret; + return -1; } } return 0; diff --git a/components/esp-tls/private_include/esp_tls_mbedtls.h b/components/esp-tls/private_include/esp_tls_mbedtls.h index 362a71fd64..7440f0c3c7 100644 --- a/components/esp-tls/private_include/esp_tls_mbedtls.h +++ b/components/esp-tls/private_include/esp_tls_mbedtls.h @@ -55,6 +55,14 @@ ssize_t esp_mbedtls_get_bytes_avail(esp_tls_t *tls); */ esp_err_t esp_create_mbedtls_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls); +/** + * mbedTLS function for Initializing socket wrappers + */ +static inline void esp_mbedtls_net_init(esp_tls_t *tls) +{ + mbedtls_net_init(&tls->server_fd); +} + #ifdef CONFIG_ESP_TLS_SERVER /** * Internal Callback for set_server_config diff --git a/components/esp-tls/private_include/esp_tls_wolfssl.h b/components/esp-tls/private_include/esp_tls_wolfssl.h index a04ad796cc..f29e9332f8 100644 --- a/components/esp-tls/private_include/esp_tls_wolfssl.h +++ b/components/esp-tls/private_include/esp_tls_wolfssl.h @@ -71,6 +71,13 @@ void esp_wolfssl_free_global_ca_store(void); */ esp_err_t esp_wolfssl_init_global_ca_store(void); +/** + * wolfSSL function for Initializing socket wrappers (no-operation for wolfSSL) + */ +static inline void esp_wolfssl_net_init(esp_tls_t *tls) +{ +} + #ifdef CONFIG_ESP_TLS_SERVER /** diff --git a/components/esp_common/src/esp_err_to_name.c b/components/esp_common/src/esp_err_to_name.c index 59963fa78c..14037c6725 100644 --- a/components/esp_common/src/esp_err_to_name.c +++ b/components/esp_common/src/esp_err_to_name.c @@ -50,8 +50,8 @@ #if __has_include("esp_supplicant/esp_wps.h") #include "esp_supplicant/esp_wps.h" #endif -#if __has_include("esp_tls.h") -#include "esp_tls.h" +#if __has_include("esp_tls_errors.h") +#include "esp_tls_errors.h" #endif #if __has_include("esp_wifi.h") #include "esp_wifi.h" @@ -588,7 +588,7 @@ static const esp_err_msg_t esp_err_msg_table[] = { # ifdef ESP_ERR_HTTP_EAGAIN ERR_TBL_IT(ESP_ERR_HTTP_EAGAIN), /* 28679 0x7007 Mapping of errno EAGAIN to esp_err_t */ # endif - // components/esp-tls/esp_tls.h + // components/esp-tls/esp_tls_errors.h # ifdef ESP_ERR_ESP_TLS_BASE ERR_TBL_IT(ESP_ERR_ESP_TLS_BASE), /* 32768 0x8000 Starting number of ESP-TLS error codes */ # endif @@ -606,7 +606,7 @@ static const esp_err_msg_t esp_err_msg_table[] = { ERR_TBL_IT(ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST), /* 32772 0x8004 Failed to connect to host */ # endif # ifdef ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED - ERR_TBL_IT(ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED), /* 32773 0x8005 failed to set socket option */ + ERR_TBL_IT(ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED), /* 32773 0x8005 failed to set/get socket option */ # endif # ifdef ESP_ERR_MBEDTLS_CERT_PARTLY_OK ERR_TBL_IT(ESP_ERR_MBEDTLS_CERT_PARTLY_OK), /* 32774 0x8006 mbedtls parse certificates was partly successful */ @@ -674,6 +674,9 @@ static const esp_err_msg_t esp_err_msg_table[] = { # endif # ifdef ESP_ERR_ESP_TLS_SE_FAILED ERR_TBL_IT(ESP_ERR_ESP_TLS_SE_FAILED), /* 32795 0x801b */ +# endif +# ifdef ESP_ERR_ESP_TLS_TCP_CLOSED_FIN + ERR_TBL_IT(ESP_ERR_ESP_TLS_TCP_CLOSED_FIN), /* 32796 0x801c */ # endif // components/esp_https_ota/include/esp_https_ota.h # ifdef ESP_ERR_HTTPS_OTA_BASE diff --git a/components/esp_http_client/CMakeLists.txt b/components/esp_http_client/CMakeLists.txt index 4020133229..f499fe82d7 100644 --- a/components/esp_http_client/CMakeLists.txt +++ b/components/esp_http_client/CMakeLists.txt @@ -5,4 +5,4 @@ idf_component_register(SRCS "esp_http_client.c" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "lib/include" REQUIRES nghttp - PRIV_REQUIRES lwip esp-tls tcp_transport) + PRIV_REQUIRES tcp_transport) diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c index 167a9d4b07..055a237722 100644 --- a/components/esp_websocket_client/esp_websocket_client.c +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -329,8 +329,8 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie ESP_WS_CLIENT_MEM_CHECK(TAG, tcp, goto _websocket_init_fail); esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT); - esp_transport_tcp_set_keep_alive(tcp, &client->keep_alive_cfg); esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup + esp_transport_tcp_set_keep_alive(tcp, &client->keep_alive_cfg); esp_transport_handle_t ws = esp_transport_ws_init(tcp); @@ -347,6 +347,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie ESP_WS_CLIENT_MEM_CHECK(TAG, ssl, goto _websocket_init_fail); esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT); + esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup if (config->use_global_ca_store == true) { esp_transport_ssl_enable_global_ca_store(ssl); } else if (config->cert_pem) { @@ -374,7 +375,6 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie esp_transport_ssl_skip_common_name_check(ssl); } esp_transport_ssl_set_keep_alive(ssl, &client->keep_alive_cfg); - esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup esp_transport_handle_t wss = esp_transport_ws_init(ssl); ESP_WS_CLIENT_MEM_CHECK(TAG, wss, goto _websocket_init_fail); diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index db4afb8752..b2108a764c 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -1,8 +1,7 @@ idf_component_register(SRCS "transport.c" "transport_ssl.c" - "transport_tcp.c" "transport_ws.c" "transport_utils.c" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "private_include" - REQUIRES lwip esp-tls) + REQUIRES esp-tls) diff --git a/components/tcp_transport/private_include/esp_transport_internal.h b/components/tcp_transport/private_include/esp_transport_internal.h index 21fda1a4ea..ea9c64b4a8 100644 --- a/components/tcp_transport/private_include/esp_transport_internal.h +++ b/components/tcp_transport/private_include/esp_transport_internal.h @@ -20,6 +20,11 @@ typedef int (*get_socket_func)(esp_transport_handle_t t); +typedef struct esp_foundation_transport { + struct esp_transport_error_storage *error_handle; /*!< Pointer to the transport error container */ + struct transport_esp_tls *transport_esp_tls; /*!< Pointer to the base transport which uses esp-tls */ +} esp_foundation_transport_t; + /** * Transport layer structure, which will provide functions, basic properties for transport types */ @@ -37,13 +42,35 @@ 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 */ get_socket_func _get_socket; /*!< Function returning the transport's socket */ - struct esp_transport_error_s* error_handle; /*!< Error handle (based on esp-tls error handle) - * extended with transport's specific errors */ esp_transport_keep_alive_t *keep_alive_cfg; /*!< TCP keep-alive config */ + struct esp_foundation_transport *base; /*!< Foundation transport pointer available from each transport */ 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, +}; + +/** + * @brief Captures internal tcp connection error + * + * This is internally translated to esp-tls return codes of esp_err_t type, since the esp-tls + * will be used as TCP transport layer + * + * @param[in] t The transport handle + * @param[in] error Internal tcp-transport's error + * + */ +void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_errors error); + /** * @brief Returns underlying socket for the supplied transport handle * @@ -63,4 +90,29 @@ int esp_transport_get_socket(esp_transport_handle_t t); */ void esp_transport_capture_errno(esp_transport_handle_t t, int sock_errno); +/** + * @brief Creates esp-tls transport used in the foundation transport + * + * @return transport esp-tls handle + */ +struct transport_esp_tls* esp_transport_esp_tls_create(void); + +/** + * @brief Destroys esp-tls transport used in the foundation transport + * + * @param[in] transport esp-tls handle + */ +void esp_transport_esp_tls_destroy(struct transport_esp_tls* transport_esp_tls); + +/** + * @brief Sets error to common transport handle + * + * Note: This function copies the supplied error handle object to tcp_transport's internal + * error handle object + * + * @param[in] A transport handle + * + */ +void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_handle_t error_handle); + #endif //_ESP_TRANSPORT_INTERNAL_H_ diff --git a/components/tcp_transport/private_include/esp_transport_ssl_internal.h b/components/tcp_transport/private_include/esp_transport_ssl_internal.h deleted file mode 100644 index 07b8c39435..0000000000 --- a/components/tcp_transport/private_include/esp_transport_ssl_internal.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef _ESP_TRANSPORT_SSL_INTERNAL_H_ -#define _ESP_TRANSPORT_SSL_INTERNAL_H_ - -/** - * @brief Sets error to common transport handle - * - * Note: This function copies the supplied error handle object to tcp_transport's internal - * error handle object - * - * @param[in] A transport handle - * - */ -void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_handle_t error_handle); - - -#endif /* _ESP_TRANSPORT_SSL_INTERNAL_H_ */ diff --git a/components/tcp_transport/test/test_transport.c b/components/tcp_transport/test/test_transport.c index 8a52577b7c..0395c0b6be 100644 --- a/components/tcp_transport/test/test_transport.c +++ b/components/tcp_transport/test/test_transport.c @@ -14,6 +14,9 @@ #define TCP_CONNECT_DONE (1) #define TCP_LISTENER_DONE (2) +#define TCP_ACCEPTOR_DONE (4) +#define TCP_LISTENER_ACCEPTED (8) +#define TCP_LISTENER_READY (16) struct tcp_connect_task_params { int timeout_ms; @@ -21,8 +24,12 @@ struct tcp_connect_task_params { EventGroupHandle_t tcp_connect_done; int ret; int listen_sock; + int accepted_sock; int last_connect_sock; bool tcp_listener_failed; + esp_transport_handle_t transport_under_test; + bool accept_connection; + bool consume_sock_backlog; }; /** @@ -51,8 +58,12 @@ static void connect_once(struct tcp_connect_task_params *params) } /** - * @brief creates a listener (without and acceptor) and connect to as many times as possible - * to prepare an endpoint which would make the client block but not complete TCP handshake + * @brief creates a listener (and an acceptor if configured) + * + * if consume_sock_backlog set: connect as many times as possible to prepare an endpoint which + * would make the client block but not complete TCP handshake + * + * if accept_connection set: waiting normally for connection creating an acceptor to mimic tcp-transport endpoint */ static void localhost_listener(void *pvParameters) { @@ -63,6 +74,9 @@ static void localhost_listener(void *pvParameters) .sin_port = htons(params->port) }; // Create listener socket and bind it to ANY address params->listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + int opt = 1; + setsockopt(params->listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + if (params->listen_sock < 0) { ESP_LOGE(TAG, "Unable to create socket"); params->tcp_listener_failed = true; @@ -83,11 +97,27 @@ static void localhost_listener(void *pvParameters) goto failed; } - // Ideally we would set backlog to 0, but since this is an implementation specific recommendation parameter, - // we recursively create sockets and try to connect to this listener in order to consume the backlog. After - // the backlog is consumed, the last connection blocks (waiting for accept), but at that point we are sure - // that any other connection would also block - connect_once(params); + // Listener is ready at this point + xEventGroupSetBits(params->tcp_connect_done, TCP_LISTENER_READY); + + if (params->consume_sock_backlog) { + // Ideally we would set backlog to 0, but since this is an implementation specific recommendation parameter, + // we recursively create sockets and try to connect to this listener in order to consume the backlog. After + // the backlog is consumed, the last connection blocks (waiting for accept), but at that point we are sure + // that any other connection would also block + connect_once(params); + } else if (params->accept_connection) { + struct sockaddr_storage source_addr; + socklen_t addr_len = sizeof(source_addr); + params->accepted_sock = accept(params->listen_sock, (struct sockaddr *)&source_addr, &addr_len); + if (params->accepted_sock < 0) { + ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno); + goto failed; + } + xEventGroupSetBits(params->tcp_connect_done, TCP_LISTENER_ACCEPTED); // Mark the socket as accepted + // ...and wait for the "acceptor" tests to finish + xEventGroupWaitBits(params->tcp_connect_done, TCP_ACCEPTOR_DONE, true, true, params->timeout_ms * 10); + } failed: xEventGroupSetBits(params->tcp_connect_done, TCP_LISTENER_DONE); @@ -98,14 +128,12 @@ static void tcp_connect_task(void *pvParameters) { struct tcp_connect_task_params *params = pvParameters; - esp_transport_list_handle_t transport_list = esp_transport_list_init(); - esp_transport_handle_t tcp = esp_transport_tcp_init(); - esp_transport_list_add(transport_list, tcp, "tcp"); - - params->ret = esp_transport_connect(tcp, "localhost", params->port, params->timeout_ms); + params->ret = esp_transport_connect(params->transport_under_test, "localhost", params->port, params->timeout_ms); + if (params->accept_connection) { + // If we test the accepted connection, need to wait until the test completes + xEventGroupWaitBits(params->tcp_connect_done, TCP_ACCEPTOR_DONE, true, true, params->timeout_ms * 10); + } xEventGroupSetBits(params->tcp_connect_done, TCP_CONNECT_DONE); - esp_transport_close(tcp); - esp_transport_list_destroy(transport_list); vTaskSuspend(NULL); } @@ -132,7 +160,7 @@ TEST_CASE("tcp_transport: using ws transport separately", "[tcp_transport][leaks TEST_ASSERT_EQUAL(ESP_OK, esp_transport_destroy(tcp)); } -TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]") +static void transport_connection_timeout_test(esp_transport_handle_t transport_under_test) { // This case simulates connection timeout running tcp connect asynchronously with other socket connection // consuming entire socket listener backlog. @@ -142,7 +170,9 @@ TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]") struct tcp_connect_task_params params = { .tcp_connect_done = xEventGroupCreate(), .timeout_ms = 200, - .port = 80 }; + .port = 80, + .consume_sock_backlog = true, + .transport_under_test = transport_under_test }; TickType_t max_wait = pdMS_TO_TICKS(params.timeout_ms * 10); TaskHandle_t localhost_listener_task_handle = NULL; TaskHandle_t tcp_connect_task_handle = NULL; @@ -160,7 +190,7 @@ TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]") EventBits_t bits = xEventGroupWaitBits(params.tcp_connect_done, TCP_CONNECT_DONE, true, true, max_wait); TickType_t end = xTaskGetTickCount(); - TEST_ASSERT_EQUAL(TCP_CONNECT_DONE, bits); // Connection has finished + TEST_ASSERT_EQUAL(TCP_CONNECT_DONE, TCP_CONNECT_DONE & bits); // Connection has finished TEST_ASSERT_EQUAL(-1, params.ret); // Connection failed with -1 // Test connection attempt took expected timeout value @@ -177,3 +207,226 @@ TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]") test_utils_task_delete(localhost_listener_task_handle); test_utils_task_delete(tcp_connect_task_handle); } + +TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]") +{ + // Init the transport under test + esp_transport_list_handle_t transport_list = esp_transport_list_init(); + esp_transport_handle_t tcp = esp_transport_tcp_init(); + esp_transport_list_add(transport_list, tcp, "tcp"); + + transport_connection_timeout_test(tcp); + esp_transport_close(tcp); + esp_transport_list_destroy(transport_list); +} + +TEST_CASE("ssl_transport: connect timeout", "[tcp_transport]") +{ + // Init the transport under test + esp_transport_list_handle_t transport_list = esp_transport_list_init(); + esp_transport_handle_t tcp = esp_transport_tcp_init(); + esp_transport_list_add(transport_list, tcp, "tcp"); + esp_transport_handle_t ssl = esp_transport_ssl_init(); + esp_transport_list_add(transport_list, ssl, "ssl"); + + transport_connection_timeout_test(ssl); + esp_transport_close(tcp); + esp_transport_close(ssl); + esp_transport_list_destroy(transport_list); +} + +TEST_CASE("transport: init and deinit multiple transport items", "[tcp_transport][leaks=0]") +{ + esp_transport_list_handle_t transport_list = esp_transport_list_init(); + esp_transport_handle_t tcp = esp_transport_tcp_init(); + esp_transport_list_add(transport_list, tcp, "tcp"); + esp_transport_handle_t ssl = esp_transport_ssl_init(); + esp_transport_list_add(transport_list, ssl, "ssl"); + esp_transport_handle_t ws = esp_transport_ws_init(tcp); + esp_transport_list_add(transport_list, ws, "ws"); + esp_transport_handle_t wss = esp_transport_ws_init(ssl); + esp_transport_list_add(transport_list, wss, "wss"); + TEST_ASSERT_EQUAL(ESP_OK, esp_transport_list_destroy(transport_list)); +} + +// This is a private API of the tcp transport, but needed for socket operation tests +int esp_transport_get_socket(esp_transport_handle_t t); + +// Structures and types for passing socket options +enum expected_sock_option_types { + SOCK_OPT_TYPE_BOOL, + SOCK_OPT_TYPE_INT, +}; + +struct expected_sock_option { + int level; + int optname; + int optval; + enum expected_sock_option_types opttype; +}; + +static void socket_operation_test(esp_transport_handle_t transport_under_test, + const struct expected_sock_option expected_opts[], size_t sock_options_len) +{ + struct tcp_connect_task_params params = { .tcp_connect_done = xEventGroupCreate(), + .timeout_ms = 200, + .port = 80, + .accept_connection = true, + .transport_under_test = transport_under_test }; + TickType_t max_wait = pdMS_TO_TICKS(params.timeout_ms * 10); + TaskHandle_t localhost_listener_task_handle = NULL; + TaskHandle_t tcp_connect_task_handle = NULL; + + test_case_uses_tcpip(); + + // Create a listener and wait for it to be ready + xTaskCreatePinnedToCore(localhost_listener, "localhost_listener", 4096, (void*)¶ms, 5, &localhost_listener_task_handle, 0); + xEventGroupWaitBits(params.tcp_connect_done, TCP_LISTENER_READY, true, true, max_wait); + // Perform tcp-connect in a separate task + xTaskCreatePinnedToCore(tcp_connect_task, "tcp_connect_task", 4096, (void*)¶ms, 6, &tcp_connect_task_handle, 0); + + // Wait till the connection gets accepted to get the client's socket + xEventGroupWaitBits(params.tcp_connect_done, TCP_LISTENER_ACCEPTED, true, true, max_wait); + int sock = esp_transport_get_socket(params.transport_under_test); + for (int i=0; ikeep_alive_idle; + expected_opts[2].optname = TCP_KEEPINTVL; + expected_opts[2].optval = config->keep_alive_interval; + expected_opts[3].optname = TCP_KEEPCNT; + expected_opts[3].optval = config->keep_alive_count; + + socket_operation_test(transport_under_test, expected_opts, sizeof(expected_opts)/sizeof(struct expected_sock_option)); +} + +TEST_CASE("tcp_transport: Keep alive test", "[tcp_transport]") +{ + // Init the transport under test + esp_transport_list_handle_t transport_list = esp_transport_list_init(); + esp_transport_handle_t tcp = esp_transport_tcp_init(); + esp_transport_list_add(transport_list, tcp, "tcp"); + + // Perform the test + esp_transport_keep_alive_t keep_alive_cfg = { + .keep_alive_interval = 5, + .keep_alive_idle = 4, + .keep_alive_enable = true, + .keep_alive_count = 3 }; + esp_transport_tcp_set_keep_alive(tcp, &keep_alive_cfg); + + tcp_transport_keepalive_test(tcp, &keep_alive_cfg); + + // Cleanup + esp_transport_close(tcp); + esp_transport_list_destroy(transport_list); +} + +TEST_CASE("ssl_transport: Keep alive test", "[tcp_transport]") +{ + // Init the transport under test + esp_transport_list_handle_t transport_list = esp_transport_list_init(); + esp_transport_handle_t ssl = esp_transport_ssl_init(); + esp_transport_list_add(transport_list, ssl, "ssl"); + esp_tls_init_global_ca_store(); + esp_transport_ssl_enable_global_ca_store(ssl); + + // Perform the test + esp_transport_keep_alive_t keep_alive_cfg = { + .keep_alive_interval = 2, + .keep_alive_idle = 3, + .keep_alive_enable = true, + .keep_alive_count = 4 }; + esp_transport_ssl_set_keep_alive(ssl, &keep_alive_cfg); + + tcp_transport_keepalive_test(ssl, &keep_alive_cfg); + + // Cleanup + esp_transport_close(ssl); + esp_transport_list_destroy(transport_list); +} + +TEST_CASE("ws_transport: Keep alive test", "[tcp_transport]") +{ + // Init the transport under test + esp_transport_list_handle_t transport_list = esp_transport_list_init(); + esp_transport_handle_t ssl = esp_transport_ssl_init(); + esp_transport_list_add(transport_list, ssl, "ssl"); + esp_tls_init_global_ca_store(); + esp_transport_ssl_enable_global_ca_store(ssl); + esp_transport_handle_t ws = esp_transport_ws_init(ssl); + esp_transport_list_add(transport_list, ws, "wss"); + + // Perform the test + esp_transport_keep_alive_t keep_alive_cfg = { + .keep_alive_interval = 1, + .keep_alive_idle = 2, + .keep_alive_enable = true, + .keep_alive_count = 3 }; + esp_transport_tcp_set_keep_alive(ssl, &keep_alive_cfg); + + tcp_transport_keepalive_test(ws, &keep_alive_cfg); + + // Cleanup + esp_transport_close(ssl); + esp_transport_list_destroy(transport_list); +} + +// Note: This functionality is tested and kept only for compatibility reasons with IDF <= 4.x +// It is strongly encouraged to use transport within lists only +TEST_CASE("ssl_transport: Check that parameters (keepalive) are set independently on the list", "[tcp_transport]") +{ + // Init the transport under test + esp_transport_handle_t ssl = esp_transport_ssl_init(); + esp_tls_init_global_ca_store(); + esp_transport_ssl_enable_global_ca_store(ssl); + + // Perform the test + esp_transport_keep_alive_t keep_alive_cfg = { + .keep_alive_interval = 2, + .keep_alive_idle = 4, + .keep_alive_enable = true, + .keep_alive_count = 3 }; + esp_transport_ssl_set_keep_alive(ssl, &keep_alive_cfg); + + tcp_transport_keepalive_test(ssl, &keep_alive_cfg); + + // Cleanup + esp_transport_close(ssl); + esp_transport_destroy(ssl); +} diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index f9b2b38a2c..8de4f9d355 100644 --- a/components/tcp_transport/transport.c +++ b/components/tcp_transport/transport.c @@ -31,7 +31,7 @@ static const char *TAG = "TRANSPORT"; * * esp-tls last error storage * * sock-errno */ -struct esp_transport_error_s { +struct esp_transport_error_storage { struct esp_tls_last_error esp_tls_err_h_base; /*!< esp-tls last error container */ // additional fields int sock_errno; /*!< last socket error captured for this transport */ @@ -42,14 +42,39 @@ struct esp_transport_error_s { */ STAILQ_HEAD(esp_transport_list_t, esp_transport_item_t); +struct transport_esp_tls; + /** * Internal transport structure holding list of transports and other data common to all transports */ typedef struct esp_transport_internal { struct esp_transport_list_t list; /*!< List of transports */ - struct esp_transport_error_s* error_handle; /*!< Pointer to the transport error container */ + struct esp_foundation_transport *base; /*!< Base transport pointer shared for each list item */ } esp_transport_internal_t; +static esp_foundation_transport_t * esp_transport_init_foundation_transport(void) +{ + esp_foundation_transport_t *foundation = calloc(1, sizeof(esp_foundation_transport_t)); + ESP_TRANSPORT_MEM_CHECK(TAG, foundation, return NULL); + foundation->error_handle = calloc(1, sizeof(struct esp_transport_error_storage)); + ESP_TRANSPORT_MEM_CHECK(TAG, foundation->error_handle, + free(foundation); + return NULL); + foundation->transport_esp_tls = esp_transport_esp_tls_create(); + ESP_TRANSPORT_MEM_CHECK(TAG, foundation->transport_esp_tls, + free(foundation->error_handle); + free(foundation); + return NULL); + return foundation; +} + +static void esp_transport_destroy_foundation_transport(esp_foundation_transport_t *foundation) +{ + esp_transport_esp_tls_destroy(foundation->transport_esp_tls); + free(foundation->error_handle); + free(foundation); +} + static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_handle_t t) { /* @@ -63,7 +88,10 @@ esp_transport_list_handle_t esp_transport_list_init(void) esp_transport_list_handle_t transport = calloc(1, sizeof(esp_transport_internal_t)); ESP_TRANSPORT_MEM_CHECK(TAG, transport, return NULL); STAILQ_INIT(&transport->list); - transport->error_handle = calloc(1, sizeof(struct esp_transport_error_s)); + transport->base = esp_transport_init_foundation_transport(); + ESP_TRANSPORT_MEM_CHECK(TAG, transport->base, + free(transport); + return NULL); return transport; } @@ -77,7 +105,7 @@ esp_err_t esp_transport_list_add(esp_transport_list_handle_t h, esp_transport_ha strcpy(t->scheme, scheme); STAILQ_INSERT_TAIL(&h->list, t, next); // Each transport in a list to share the same error tracker - t->error_handle = h->error_handle; + t->base = h->base; return ESP_OK; } @@ -101,7 +129,7 @@ esp_transport_handle_t esp_transport_list_get_transport(esp_transport_list_handl esp_err_t esp_transport_list_destroy(esp_transport_list_handle_t h) { esp_transport_list_clean(h); - free(h->error_handle); + esp_transport_destroy_foundation_transport(h->base); free(h); return ESP_OK; } @@ -283,36 +311,58 @@ 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) { if (t) { - return &t->error_handle->esp_tls_err_h_base; + return &t->base->error_handle->esp_tls_err_h_base; } return NULL; } int esp_transport_get_errno(esp_transport_handle_t t) { - if (t && t->error_handle) { - int actual_errno = t->error_handle->sock_errno; - t->error_handle->sock_errno = 0; + if (t && t->base && t->base->error_handle) { + int actual_errno = t->base->error_handle->sock_errno; + t->base->error_handle->sock_errno = 0; return actual_errno; } return -1; } +void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_errors 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_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; + } +} + void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_handle_t error_handle) { - if (t && t->error_handle) { - memcpy(&t->error_handle->esp_tls_err_h_base, error_handle, sizeof(esp_tls_last_error_t)); + if (t && t->base && t->base->error_handle) { + memcpy(&t->base->error_handle->esp_tls_err_h_base, error_handle, sizeof(esp_tls_last_error_t)); int sock_error; if (esp_tls_get_and_clear_error_type(error_handle, ESP_TLS_ERR_TYPE_SYSTEM, &sock_error) == ESP_OK) { - t->error_handle->sock_errno = sock_error; + t->base->error_handle->sock_errno = sock_error; } } } void esp_transport_capture_errno(esp_transport_handle_t t, int sock_errno) { - if (t && t->error_handle) { - t->error_handle->sock_errno = sock_errno; + if (t && t->base && t->base->error_handle) { + t->base->error_handle->sock_errno = sock_errno; } } diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 9e3854d7c2..fd2795a4bd 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -15,19 +15,19 @@ #include #include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" #include "esp_tls.h" #include "esp_log.h" -#include "esp_system.h" #include "esp_transport.h" #include "esp_transport_ssl.h" #include "esp_transport_utils.h" -#include "esp_transport_ssl_internal.h" #include "esp_transport_internal.h" -static const char *TAG = "TRANS_SSL"; +#define GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t) \ + transport_esp_tls_t *ssl = ssl_get_context_data(t); \ + if (!ssl) { return; } + +static const char *TAG = "TRANSPORT_BASE"; typedef enum { TRANS_SSL_INIT = 0, @@ -37,20 +37,40 @@ typedef enum { /** * mbedtls specific transport data */ -typedef struct { +typedef struct transport_esp_tls { esp_tls_t *tls; esp_tls_cfg_t cfg; bool ssl_initialized; transport_ssl_conn_state_t conn_state; -} transport_ssl_t; +} transport_esp_tls_t; + +static inline struct transport_esp_tls * ssl_get_context_data(esp_transport_handle_t t) +{ + if (!t) { + return NULL; + } + if (t->data) { // Prefer internal ssl context (independent from the list) + return (transport_esp_tls_t*)t->data; + } + if (t->base && t->base->transport_esp_tls) { // Next one is the lists inherent context + t->data = t->base->transport_esp_tls; // Optimize: if we have base context, use it as internal + return t->base->transport_esp_tls; + } + // If we don't have a valid context, let's to create one + transport_esp_tls_t *ssl = esp_transport_esp_tls_create(); + ESP_TRANSPORT_MEM_CHECK(TAG, ssl, return NULL) + t->data = ssl; + return ssl; +} static int ssl_close(esp_transport_handle_t t); -static int ssl_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms) +static int esp_tls_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms, bool is_plain_tcp) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_esp_tls_t *ssl = ssl_get_context_data(t); if (ssl->conn_state == TRANS_SSL_INIT) { ssl->cfg.timeout_ms = timeout_ms; + ssl->cfg.is_plain_tcp = is_plain_tcp; ssl->cfg.non_block = true; ssl->ssl_initialized = true; ssl->tls = esp_tls_init(); @@ -65,11 +85,23 @@ static int ssl_connect_async(esp_transport_handle_t t, const char *host, int por return 0; } -static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms) +static inline int ssl_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + return esp_tls_connect_async(t, host, port, timeout_ms, false); +} + +static inline int tcp_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms) +{ + return esp_tls_connect_async(t, host, port, timeout_ms, true); +} + +static int esp_tls_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms, bool is_plain_tcp) +{ + transport_esp_tls_t *ssl = ssl_get_context_data(t); ssl->cfg.timeout_ms = timeout_ms; + ssl->cfg.is_plain_tcp = is_plain_tcp; + ssl->ssl_initialized = true; ssl->tls = esp_tls_init(); if (esp_tls_conn_new_sync(host, strlen(host), port, &ssl->cfg, ssl->tls) <= 0) { @@ -79,13 +111,22 @@ static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int ssl->tls = NULL; return -1; } - return 0; } +static inline int ssl_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms) +{ + return esp_tls_connect(t, host, port, timeout_ms, false); +} + +static inline int tcp_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms) +{ + return esp_tls_connect(t, host, port, timeout_ms, true); +} + static int ssl_poll_read(esp_transport_handle_t t, int timeout_ms) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_esp_tls_t *ssl = ssl_get_context_data(t); int ret = -1; int remain = 0; struct timeval timeout; @@ -114,7 +155,7 @@ static int ssl_poll_read(esp_transport_handle_t t, int timeout_ms) static int ssl_poll_write(esp_transport_handle_t t, int timeout_ms) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_esp_tls_t *ssl = ssl_get_context_data(t); int ret = -1; struct timeval timeout; fd_set writeset; @@ -138,7 +179,7 @@ static int ssl_poll_write(esp_transport_handle_t t, int timeout_ms) static int ssl_write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms) { int poll, ret; - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_esp_tls_t *ssl = ssl_get_context_data(t); if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) { ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->tls->sockfd, timeout_ms); @@ -155,7 +196,7 @@ static int ssl_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, ret; - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_esp_tls_t *ssl = ssl_get_context_data(t); if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) { return poll; @@ -166,6 +207,10 @@ static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout esp_transport_set_errors(t, ssl->tls->error_handle); } 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; } return ret; @@ -174,8 +219,8 @@ static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout static int ssl_close(esp_transport_handle_t t) { int ret = -1; - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (ssl->ssl_initialized) { + transport_esp_tls_t *ssl = ssl_get_context_data(t); + if (ssl && ssl->ssl_initialized) { ret = esp_tls_conn_destroy(ssl->tls); ssl->conn_state = TRANS_SSL_INIT; ssl->ssl_initialized = false; @@ -185,153 +230,151 @@ static int ssl_close(esp_transport_handle_t t) static int ssl_destroy(esp_transport_handle_t t) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - esp_transport_close(t); - free(ssl); + transport_esp_tls_t *ssl = ssl_get_context_data(t); + if (ssl) { + esp_transport_close(t); + if (t->base && t->base->transport_esp_tls && + t->data == t->base->transport_esp_tls) { + // if internal ssl the same as the foundation transport, + // just zero out, it will be freed on list destroy + t->data = NULL; + } + esp_transport_esp_tls_destroy(t->data); // okay to pass NULL + } return 0; } + void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.use_global_ca_store = true; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.use_global_ca_store = true; } void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.psk_hint_key = psk_hint_key; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.psk_hint_key = psk_hint_key; } void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.cacert_pem_buf = (void *)data; - ssl->cfg.cacert_pem_bytes = len + 1; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.cacert_pem_buf = (void *)data; + ssl->cfg.cacert_pem_bytes = len + 1; } void esp_transport_ssl_set_cert_data_der(esp_transport_handle_t t, const char *data, int len) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.cacert_buf = (void *)data; - ssl->cfg.cacert_bytes = len; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.cacert_buf = (void *)data; + ssl->cfg.cacert_bytes = len; } void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char *data, int len) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.clientcert_pem_buf = (void *)data; - ssl->cfg.clientcert_pem_bytes = len + 1; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.clientcert_pem_buf = (void *)data; + ssl->cfg.clientcert_pem_bytes = len + 1; } void esp_transport_ssl_set_client_cert_data_der(esp_transport_handle_t t, const char *data, int len) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.clientcert_buf = (void *)data; - ssl->cfg.clientcert_bytes = len; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.clientcert_buf = (void *)data; + ssl->cfg.clientcert_bytes = len; } void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char *data, int len) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.clientkey_pem_buf = (void *)data; - ssl->cfg.clientkey_pem_bytes = len + 1; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.clientkey_pem_buf = (void *)data; + ssl->cfg.clientkey_pem_bytes = len + 1; } void esp_transport_ssl_set_client_key_password(esp_transport_handle_t t, const char *password, int password_len) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.clientkey_password = (void *)password; - ssl->cfg.clientkey_password_len = password_len; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.clientkey_password = (void *)password; + ssl->cfg.clientkey_password_len = password_len; } void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const char *data, int len) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.clientkey_buf = (void *)data; - ssl->cfg.clientkey_bytes = len; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.clientkey_buf = (void *)data; + ssl->cfg.clientkey_bytes = len; } void esp_transport_ssl_set_alpn_protocol(esp_transport_handle_t t, const char **alpn_protos) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.alpn_protos = alpn_protos; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.alpn_protos = alpn_protos; } void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.skip_common_name = true; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.skip_common_name = true; } void esp_transport_ssl_use_secure_element(esp_transport_handle_t t) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.use_secure_element = true; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.use_secure_element = true; } static int ssl_get_socket(esp_transport_handle_t t) { - if (t) { - transport_ssl_t *ssl = t->data; - if (ssl && ssl->tls) { - return ssl->tls->sockfd; - } + transport_esp_tls_t *ssl = ssl_get_context_data(t); + if (ssl && ssl->tls) { + return ssl->tls->sockfd; } return -1; } void esp_transport_ssl_set_ds_data(esp_transport_handle_t t, void *ds_data) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); - if (t && ssl) { - ssl->cfg.ds_data = ds_data; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + ssl->cfg.ds_data = ds_data; } 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; - } + GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t); + 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(); - transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t)); - ESP_TRANSPORT_MEM_CHECK(TAG, ssl, { - esp_transport_destroy(t); - return NULL; - }); - esp_transport_set_context_data(t, ssl); esp_transport_set_func(t, ssl_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy); esp_transport_set_async_connect_func(t, ssl_connect_async); t->_get_socket = ssl_get_socket; return t; } + +struct transport_esp_tls* esp_transport_esp_tls_create(void) +{ + transport_esp_tls_t *transport_esp_tls = calloc(1, sizeof(transport_esp_tls_t)); + return transport_esp_tls; +} + +void esp_transport_esp_tls_destroy(struct transport_esp_tls* transport_esp_tls) +{ + free(transport_esp_tls); +} + +esp_transport_handle_t esp_transport_tcp_init(void) +{ + esp_transport_handle_t t = esp_transport_init(); + esp_transport_set_func(t, tcp_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy); + esp_transport_set_async_connect_func(t, tcp_connect_async); + t->_get_socket = ssl_get_socket; + return t; +} + +void esp_transport_tcp_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg) +{ + return esp_transport_ssl_set_keep_alive(t, keep_alive_cfg); +} diff --git a/components/tcp_transport/transport_tcp.c b/components/tcp_transport/transport_tcp.c deleted file mode 100644 index d61626f4f1..0000000000 --- a/components/tcp_transport/transport_tcp.c +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "lwip/sockets.h" -#include "lwip/dns.h" -#include "lwip/netdb.h" - -#include "esp_log.h" -#include "esp_system.h" -#include "esp_err.h" - -#include "esp_transport_utils.h" -#include "esp_transport.h" -#include "esp_transport_internal.h" - -static const char *TAG = "TRANS_TCP"; - -typedef struct { - int sock; -} transport_tcp_t; - -static int resolve_dns(const char *host, struct sockaddr_in *ip) -{ - const struct addrinfo hints = { - .ai_family = AF_INET, - .ai_socktype = SOCK_STREAM, - }; - struct addrinfo *res; - - int err = getaddrinfo(host, NULL, &hints, &res); - if(err != 0 || res == NULL) { - ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res); - return ESP_FAIL; - } - ip->sin_family = AF_INET; - memcpy(&ip->sin_addr, &((struct sockaddr_in *)(res->ai_addr))->sin_addr, sizeof(ip->sin_addr)); - freeaddrinfo(res); - 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); - - bzero(&remote_ip, sizeof(struct sockaddr_in)); - - //if stream_host is not ip address, resolve it AF_INET,servername,&serveraddr.sin_addr - if (inet_pton(AF_INET, host, &remote_ip.sin_addr) != 1) { - if (resolve_dns(host, &remote_ip) < 0) { - return -1; - } - } - - tcp->sock = socket(PF_INET, SOCK_STREAM, 0); - - if (tcp->sock < 0) { - ESP_LOGE(TAG, "Error create socket"); - return -1; - } - - remote_ip.sin_family = AF_INET; - remote_ip.sin_port = htons(port); - - esp_transport_utils_ms_to_timeval(timeout_ms, &tv); // if timeout=-1, tv is unchanged, 0, i.e. waits forever - - 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 (t->keep_alive_cfg && t->keep_alive_cfg->keep_alive_enable) { - if (tcp_enable_keep_alive(tcp->sock, t->keep_alive_cfg) < 0) { - ESP_LOGE(TAG, "Error to set tcp [socket=%d] keep-alive", tcp->sock); - goto error; - } - } - // Set socket to non-blocking - int flags; - if ((flags = fcntl(tcp->sock, F_GETFL, NULL)) < 0) { - ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", tcp->sock, strerror(errno)); - goto error; - } - if (fcntl(tcp->sock, F_SETFL, flags |= O_NONBLOCK) < 0) { - ESP_LOGE(TAG, "[sock=%d] set nonblocking error: %s", tcp->sock, strerror(errno)); - goto error; - } - - 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) { - if (errno == EINPROGRESS) { - fd_set fdset; - - esp_transport_utils_ms_to_timeval(timeout_ms, &tv); - FD_ZERO(&fdset); - FD_SET(tcp->sock, &fdset); - - int res = select(tcp->sock+1, NULL, &fdset, NULL, &tv); - if (res < 0) { - ESP_LOGE(TAG, "[sock=%d] select() error: %s", tcp->sock, strerror(errno)); - esp_transport_capture_errno(t, errno); - goto error; - } - else if (res == 0) { - ESP_LOGE(TAG, "[sock=%d] select() timeout", tcp->sock); - esp_transport_capture_errno(t, EINPROGRESS); // errno=EINPROGRESS indicates connection timeout - goto error; - } else { - int sockerr; - socklen_t len = (socklen_t)sizeof(int); - - if (getsockopt(tcp->sock, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) { - ESP_LOGE(TAG, "[sock=%d] getsockopt() error: %s", tcp->sock, strerror(errno)); - goto error; - } - else if (sockerr) { - esp_transport_capture_errno(t, sockerr); - ESP_LOGE(TAG, "[sock=%d] delayed connect error: %s", tcp->sock, strerror(sockerr)); - goto error; - } - } - } else { - ESP_LOGE(TAG, "[sock=%d] connect() error: %s", tcp->sock, strerror(errno)); - goto error; - } - } - // Reset socket to blocking - if ((flags = fcntl(tcp->sock, F_GETFL, NULL)) < 0) { - ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", tcp->sock, strerror(errno)); - goto error; - } - if (fcntl(tcp->sock, F_SETFL, flags & ~O_NONBLOCK) < 0) { - ESP_LOGE(TAG, "[sock=%d] reset blocking error: %s", tcp->sock, strerror(errno)); - goto error; - } - return tcp->sock; -error: - close(tcp->sock); - tcp->sock = -1; - return -1; -} - -static int tcp_write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms) -{ - int poll; - transport_tcp_t *tcp = esp_transport_get_context_data(t); - if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) { - return poll; - } - return write(tcp->sock, buffer, len); -} - -static int tcp_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms) -{ - transport_tcp_t *tcp = esp_transport_get_context_data(t); - int poll = -1; - if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) { - return poll; - } - int read_len = read(tcp->sock, buffer, len); - if (read_len == 0) { - return -1; - } - return read_len; -} - -static int tcp_poll_read(esp_transport_handle_t t, int timeout_ms) -{ - transport_tcp_t *tcp = esp_transport_get_context_data(t); - int ret = -1; - struct timeval timeout; - fd_set readset; - fd_set errset; - FD_ZERO(&readset); - FD_ZERO(&errset); - FD_SET(tcp->sock, &readset); - FD_SET(tcp->sock, &errset); - - ret = select(tcp->sock + 1, &readset, NULL, &errset, esp_transport_utils_ms_to_timeval(timeout_ms, &timeout)); - if (ret > 0 && FD_ISSET(tcp->sock, &errset)) { - int sock_errno = 0; - uint32_t optlen = sizeof(sock_errno); - getsockopt(tcp->sock, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen); - esp_transport_capture_errno(t, sock_errno); - ESP_LOGE(TAG, "tcp_poll_read select error %d, errno = %s, fd = %d", sock_errno, strerror(sock_errno), tcp->sock); - ret = -1; - } - return ret; -} - -static int tcp_poll_write(esp_transport_handle_t t, int timeout_ms) -{ - transport_tcp_t *tcp = esp_transport_get_context_data(t); - int ret = -1; - struct timeval timeout; - fd_set writeset; - fd_set errset; - FD_ZERO(&writeset); - FD_ZERO(&errset); - FD_SET(tcp->sock, &writeset); - FD_SET(tcp->sock, &errset); - - ret = select(tcp->sock + 1, NULL, &writeset, &errset, esp_transport_utils_ms_to_timeval(timeout_ms, &timeout)); - if (ret > 0 && FD_ISSET(tcp->sock, &errset)) { - int sock_errno = 0; - uint32_t optlen = sizeof(sock_errno); - getsockopt(tcp->sock, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen); - esp_transport_capture_errno(t, sock_errno); - ESP_LOGE(TAG, "tcp_poll_write select error %d, errno = %s, fd = %d", sock_errno, strerror(sock_errno), tcp->sock); - ret = -1; - } - return ret; -} - -static int tcp_close(esp_transport_handle_t t) -{ - transport_tcp_t *tcp = esp_transport_get_context_data(t); - int ret = -1; - if (tcp->sock >= 0) { - ret = close(tcp->sock); - tcp->sock = -1; - } - return ret; -} - -static esp_err_t tcp_destroy(esp_transport_handle_t t) -{ - transport_tcp_t *tcp = esp_transport_get_context_data(t); - esp_transport_close(t); - free(tcp); - return 0; -} - -static int tcp_get_socket(esp_transport_handle_t t) -{ - if (t) { - transport_tcp_t *tcp = t->data; - if (tcp) { - return tcp->sock; - } - } - return -1; -} - -void esp_transport_tcp_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; - } -} - -esp_transport_handle_t esp_transport_tcp_init(void) -{ - esp_transport_handle_t t = esp_transport_init(); - transport_tcp_t *tcp = calloc(1, sizeof(transport_tcp_t)); - ESP_TRANSPORT_MEM_CHECK(TAG, tcp, { - esp_transport_destroy(t); - return NULL; - }); - - tcp->sock = -1; - esp_transport_set_func(t, tcp_connect, tcp_read, tcp_write, tcp_close, tcp_poll_read, tcp_poll_write, tcp_destroy); - esp_transport_set_context_data(t, tcp); - t->_get_socket = tcp_get_socket; - - return t; -} diff --git a/examples/protocols/mqtt/ssl/main/app_main.c b/examples/protocols/mqtt/ssl/main/app_main.c index 0f4d26ac74..3e8775d1b2 100644 --- a/examples/protocols/mqtt/ssl/main/app_main.c +++ b/examples/protocols/mqtt/ssl/main/app_main.c @@ -144,8 +144,7 @@ void app_main(void) esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); diff --git a/examples/protocols/mqtt/ssl_ds/main/app_main.c b/examples/protocols/mqtt/ssl_ds/main/app_main.c index ca288f8bb4..502dce4ac9 100644 --- a/examples/protocols/mqtt/ssl_ds/main/app_main.c +++ b/examples/protocols/mqtt/ssl_ds/main/app_main.c @@ -194,8 +194,7 @@ void app_main(void) esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); diff --git a/examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c b/examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c index a5add84e85..48ad78d5cc 100644 --- a/examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c +++ b/examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c @@ -133,8 +133,7 @@ void app_main(void) esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); diff --git a/examples/protocols/mqtt/ssl_psk/main/app_main.c b/examples/protocols/mqtt/ssl_psk/main/app_main.c index 3ca754c255..cbb4526824 100644 --- a/examples/protocols/mqtt/ssl_psk/main/app_main.c +++ b/examples/protocols/mqtt/ssl_psk/main/app_main.c @@ -121,8 +121,7 @@ void app_main(void) esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); diff --git a/examples/protocols/mqtt/tcp/main/app_main.c b/examples/protocols/mqtt/tcp/main/app_main.c index 3f63ce462e..48b1c475b0 100644 --- a/examples/protocols/mqtt/tcp/main/app_main.c +++ b/examples/protocols/mqtt/tcp/main/app_main.c @@ -152,8 +152,8 @@ void app_main(void) esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); + esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); diff --git a/examples/protocols/mqtt/ws/main/app_main.c b/examples/protocols/mqtt/ws/main/app_main.c index 09a81b56bf..32410e85a8 100644 --- a/examples/protocols/mqtt/ws/main/app_main.c +++ b/examples/protocols/mqtt/ws/main/app_main.c @@ -125,8 +125,7 @@ void app_main(void) esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT_WS", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); diff --git a/examples/protocols/mqtt/wss/main/app_main.c b/examples/protocols/mqtt/wss/main/app_main.c index 3c56890025..d0495e2bb9 100644 --- a/examples/protocols/mqtt/wss/main/app_main.c +++ b/examples/protocols/mqtt/wss/main/app_main.c @@ -117,8 +117,7 @@ void app_main(void) esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); diff --git a/examples/protocols/pppos_client/example_test.py b/examples/protocols/pppos_client/example_test.py index d332830fb6..5fe1111a52 100644 --- a/examples/protocols/pppos_client/example_test.py +++ b/examples/protocols/pppos_client/example_test.py @@ -94,7 +94,7 @@ def test_examples_pppos_client(env, extra_data): 'pppos_example: GOT ip event!!!', 'pppos_example: MQTT other event id: 7', # There are no fake DNS server and MQTT server set up so the example fails at this point - 'TRANS_TCP: DNS lookup failed err=202 res=0x0', + 'esp-tls: couldn\'t get hostname', 'MQTT_CLIENT: Error transport connect', 'pppos_example: MQTT_EVENT_ERROR', 'pppos_example: MQTT_EVENT_DISCONNECTED') diff --git a/tools/test_apps/protocols/mqtt/publish_connect_test/main/publish_connect_test.c b/tools/test_apps/protocols/mqtt/publish_connect_test/main/publish_connect_test.c index a7a250471e..a112834231 100644 --- a/tools/test_apps/protocols/mqtt/publish_connect_test/main/publish_connect_test.c +++ b/tools/test_apps/protocols/mqtt/publish_connect_test/main/publish_connect_test.c @@ -46,8 +46,7 @@ void app_main(void) esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); diff --git a/tools/test_apps/protocols/openssl/main/main.c b/tools/test_apps/protocols/openssl/main/main.c index 5af4559b2b..c7d7218dae 100644 --- a/tools/test_apps/protocols/openssl/main/main.c +++ b/tools/test_apps/protocols/openssl/main/main.c @@ -44,8 +44,7 @@ void app_main(void) esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("OPENSSL_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE); esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);