From 391d7bf271529e72d8bace030a863e187777d46d Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 22 Jan 2021 21:00:22 +0100 Subject: [PATCH 01/14] tcp_transport: Add TCP transport connection errors Transport's error_handle is used to capture different types of errors including esp_err_t from esp-tls and socket/system errors. This change adds the following error codes for TCP transport: * connection closed by a FIN flag (clean closure from server) * DNS resolution problem * connection timeout These errors are already defined in esp-tls component and since this component will be used in the future for both TCP and SSL transport, we currently report these issues in transport::error_handle::esp_tls_last_error of standard esp error type (esp_err_t) Closes https://github.com/espressif/esp-mqtt/issues/182 --- components/esp-tls/esp_tls.h | 66 +------------ components/esp-tls/esp_tls_errors.h | 96 +++++++++++++++++++ .../private_include/esp_transport_internal.h | 23 +++++ components/tcp_transport/transport.c | 23 +++++ components/tcp_transport/transport_ssl.c | 4 + components/tcp_transport/transport_tcp.c | 15 ++- 6 files changed, 161 insertions(+), 66 deletions(-) create mode 100644 components/esp-tls/esp_tls_errors.h diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index a3ab33b3d4..b2fb0c1cdd 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 */ diff --git a/components/esp-tls/esp_tls_errors.h b/components/esp-tls/esp_tls_errors.h new file mode 100644 index 0000000000..3b39b56209 --- /dev/null +++ b/components/esp-tls/esp_tls_errors.h @@ -0,0 +1,96 @@ +// 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 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) */ + +#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_TCP_CONNECTION, /*!< Errors related to TCP layer, extending errno */ + 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/tcp_transport/private_include/esp_transport_internal.h b/components/tcp_transport/private_include/esp_transport_internal.h index 21fda1a4ea..56a26ba076 100644 --- a/components/tcp_transport/private_include/esp_transport_internal.h +++ b/components/tcp_transport/private_include/esp_transport_internal.h @@ -44,6 +44,29 @@ struct esp_transport_item_t { STAILQ_ENTRY(esp_transport_item_t) next; }; +/** + * @brief Internal error types for TCP connection issues not covered in socket's errno + */ +enum tcp_transport_errors { + ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT, + ERR_TCP_TRANSPORT_CANNOT_RESOLVE_HOSTNAME, + ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN, + ERR_TCP_TRANSPORT_CONNECTION_FAILED, + ERR_TCP_TRANSPORT_SETOPT_FAILED, +}; + +/** + * @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 * diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index f9b2b38a2c..f35212d2a9 100644 --- a/components/tcp_transport/transport.c +++ b/components/tcp_transport/transport.c @@ -23,6 +23,7 @@ #include "esp_transport.h" #include "esp_transport_internal.h" #include "esp_transport_utils.h" +#include "esp_tls_errors.h" static const char *TAG = "TRANSPORT"; @@ -298,6 +299,28 @@ int esp_transport_get_errno(esp_transport_handle_t t) return -1; } +void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_errors error) +{ + 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) { diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 9e3854d7c2..1d698ca909 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -166,6 +166,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; diff --git a/components/tcp_transport/transport_tcp.c b/components/tcp_transport/transport_tcp.c index d61626f4f1..4d498e69ad 100644 --- a/components/tcp_transport/transport_tcp.c +++ b/components/tcp_transport/transport_tcp.c @@ -26,6 +26,7 @@ #include "esp_transport_utils.h" #include "esp_transport.h" #include "esp_transport_internal.h" +#include "esp_tls_errors.h" static const char *TAG = "TRANS_TCP"; @@ -33,6 +34,7 @@ typedef struct { int sock; } transport_tcp_t; + static int resolve_dns(const char *host, struct sockaddr_in *ip) { const struct addrinfo hints = { @@ -91,6 +93,7 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int //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) { + capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_CANNOT_RESOLVE_HOSTNAME); return -1; } } @@ -120,10 +123,12 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int 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)); + capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); 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)); + capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); goto error; } @@ -146,7 +151,7 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int } else if (res == 0) { ESP_LOGE(TAG, "[sock=%d] select() timeout", tcp->sock); - esp_transport_capture_errno(t, EINPROGRESS); // errno=EINPROGRESS indicates connection timeout + capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT); goto error; } else { int sockerr; @@ -154,11 +159,13 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, 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)); + capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); goto error; } else if (sockerr) { esp_transport_capture_errno(t, sockerr); ESP_LOGE(TAG, "[sock=%d] delayed connect error: %s", tcp->sock, strerror(sockerr)); + capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_CONNECTION_FAILED); goto error; } } @@ -170,10 +177,12 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int // 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)); + capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); 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)); + capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); goto error; } return tcp->sock; @@ -202,6 +211,10 @@ static int tcp_read(esp_transport_handle_t t, char *buffer, int len, int timeout } int read_len = read(tcp->sock, buffer, len); if (read_len == 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); + } return -1; } return read_len; From 2c28ffffeef96dac0a96feabe3e26f81308f762e Mon Sep 17 00:00:00 2001 From: David Cermak Date: Sat, 23 Jan 2021 09:46:06 +0100 Subject: [PATCH 02/14] tcp_transport/esp_tls: Use common TCP transport to reduce code duplication For high level review of the changes. --- components/esp-tls/esp_tls.c | 4 +- components/esp-tls/esp_tls.h | 1 + components/tcp_transport/CMakeLists.txt | 1 - .../private_include/esp_transport_internal.h | 5 + components/tcp_transport/transport.c | 7 +- components/tcp_transport/transport_ssl.c | 89 +++-- components/tcp_transport/transport_tcp.c | 323 ------------------ 7 files changed, 74 insertions(+), 356 deletions(-) delete mode 100644 components/tcp_transport/transport_tcp.c diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 80cbf417be..c2a6ad64f9 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -276,7 +276,7 @@ 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) { + if (cfg != NULL && cfg->is_plain_tcp == false) { #ifdef CONFIG_ESP_TLS_USING_MBEDTLS mbedtls_net_init(&tls->server_fd); #endif @@ -286,7 +286,7 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c 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"); diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index b2fb0c1cdd..f3e36a22b5 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -170,6 +170,7 @@ 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; } esp_tls_cfg_t; #ifdef CONFIG_ESP_TLS_SERVER diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index db4afb8752..ad03b74a68 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -1,6 +1,5 @@ idf_component_register(SRCS "transport.c" "transport_ssl.c" - "transport_tcp.c" "transport_ws.c" "transport_utils.c" INCLUDE_DIRS "include" diff --git a/components/tcp_transport/private_include/esp_transport_internal.h b/components/tcp_transport/private_include/esp_transport_internal.h index 56a26ba076..761efeef29 100644 --- a/components/tcp_transport/private_include/esp_transport_internal.h +++ b/components/tcp_transport/private_include/esp_transport_internal.h @@ -20,6 +20,8 @@ typedef int (*get_socket_func)(esp_transport_handle_t t); +struct transport_esp_tls; + /** * Transport layer structure, which will provide functions, basic properties for transport types */ @@ -40,6 +42,7 @@ struct esp_transport_item_t { 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 transport_esp_tls *foundation_transport; STAILQ_ENTRY(esp_transport_item_t) next; }; @@ -86,4 +89,6 @@ int esp_transport_get_socket(esp_transport_handle_t t); */ void esp_transport_capture_errno(esp_transport_handle_t t, int sock_errno); +struct transport_esp_tls* esp_transport_init_foundation(void); + #endif //_ESP_TRANSPORT_INTERNAL_H_ diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index f35212d2a9..f6ae753279 100644 --- a/components/tcp_transport/transport.c +++ b/components/tcp_transport/transport.c @@ -23,7 +23,6 @@ #include "esp_transport.h" #include "esp_transport_internal.h" #include "esp_transport_utils.h" -#include "esp_tls_errors.h" static const char *TAG = "TRANSPORT"; @@ -43,12 +42,15 @@ 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 transport_esp_tls *foundation_transport; } esp_transport_internal_t; static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_handle_t t) @@ -65,6 +67,7 @@ esp_transport_list_handle_t esp_transport_list_init(void) ESP_TRANSPORT_MEM_CHECK(TAG, transport, return NULL); STAILQ_INIT(&transport->list); transport->error_handle = calloc(1, sizeof(struct esp_transport_error_s)); + transport->foundation_transport = esp_transport_init_foundation(); return transport; } @@ -79,6 +82,7 @@ esp_err_t esp_transport_list_add(esp_transport_list_handle_t h, esp_transport_ha 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->foundation_transport = h->foundation_transport; return ESP_OK; } @@ -103,6 +107,7 @@ esp_err_t esp_transport_list_destroy(esp_transport_list_handle_t h) { esp_transport_list_clean(h); free(h->error_handle); + free(h->foundation_transport); // TODO: make it destroy foundation free(h); return ESP_OK; } diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 1d698ca909..96034c76e3 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -37,7 +37,7 @@ 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; @@ -48,7 +48,7 @@ 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) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_ssl_t *ssl = t->foundation_transport; if (ssl->conn_state == TRANS_SSL_INIT) { ssl->cfg.timeout_ms = timeout_ms; ssl->cfg.non_block = true; @@ -67,7 +67,7 @@ static int ssl_connect_async(esp_transport_handle_t t, const char *host, int por static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_ssl_t *ssl = t->foundation_transport; ssl->cfg.timeout_ms = timeout_ms; ssl->ssl_initialized = true; @@ -83,9 +83,29 @@ static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int return 0; } +static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms) +{ + transport_ssl_t *ssl = t->foundation_transport; + + ssl->cfg.timeout_ms = timeout_ms; + ssl->cfg.is_plain_tcp = true; + ssl->ssl_initialized = true; + ssl->tls = esp_tls_init(); + if (esp_tls_conn_new_sync(host, strlen(host), port, &ssl->cfg, ssl->tls) <= 0) { + ESP_LOGE(TAG, "Failed to open a new connection"); + esp_transport_set_errors(t, ssl->tls->error_handle); + esp_tls_conn_destroy(ssl->tls); + ssl->tls = NULL; + return -1; + } + + return 0; +} + + static int ssl_poll_read(esp_transport_handle_t t, int timeout_ms) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_ssl_t *ssl = t->foundation_transport; int ret = -1; int remain = 0; struct timeval timeout; @@ -114,7 +134,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_ssl_t *ssl = t->foundation_transport; int ret = -1; struct timeval timeout; fd_set writeset; @@ -138,7 +158,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_ssl_t *ssl = t->foundation_transport; 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 +175,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_ssl_t *ssl = t->foundation_transport; if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) { return poll; @@ -178,7 +198,7 @@ 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); + transport_ssl_t *ssl = t->foundation_transport; if (ssl->ssl_initialized) { ret = esp_tls_conn_destroy(ssl->tls); ssl->conn_state = TRANS_SSL_INIT; @@ -189,7 +209,7 @@ 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); + transport_ssl_t *ssl = t->foundation_transport; esp_transport_close(t); free(ssl); return 0; @@ -197,7 +217,7 @@ static int ssl_destroy(esp_transport_handle_t t) void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.use_global_ca_store = true; } @@ -205,7 +225,7 @@ void esp_transport_ssl_enable_global_ca_store(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) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.psk_hint_key = psk_hint_key; } @@ -213,7 +233,7 @@ void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint 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); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.cacert_pem_buf = (void *)data; ssl->cfg.cacert_pem_bytes = len + 1; @@ -222,7 +242,7 @@ void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, 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); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.cacert_buf = (void *)data; ssl->cfg.cacert_bytes = len; @@ -231,7 +251,7 @@ void esp_transport_ssl_set_cert_data_der(esp_transport_handle_t t, const char *d 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); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.clientcert_pem_buf = (void *)data; ssl->cfg.clientcert_pem_bytes = len + 1; @@ -240,7 +260,7 @@ void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char 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); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.clientcert_buf = (void *)data; ssl->cfg.clientcert_bytes = len; @@ -249,7 +269,7 @@ void esp_transport_ssl_set_client_cert_data_der(esp_transport_handle_t t, const 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); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.clientkey_pem_buf = (void *)data; ssl->cfg.clientkey_pem_bytes = len + 1; @@ -258,7 +278,7 @@ void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char 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); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.clientkey_password = (void *)password; ssl->cfg.clientkey_password_len = password_len; @@ -267,7 +287,7 @@ void esp_transport_ssl_set_client_key_password(esp_transport_handle_t t, const c 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); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.clientkey_buf = (void *)data; ssl->cfg.clientkey_bytes = len; @@ -276,7 +296,7 @@ void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const c 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); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.alpn_protos = alpn_protos; } @@ -284,7 +304,7 @@ void esp_transport_ssl_set_alpn_protocol(esp_transport_handle_t t, const char ** void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.skip_common_name = true; } @@ -292,7 +312,7 @@ void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t) void esp_transport_ssl_use_secure_element(esp_transport_handle_t t) { - transport_ssl_t *ssl = esp_transport_get_context_data(t); + transport_ssl_t *ssl = t->foundation_transport; if (t && ssl) { ssl->cfg.use_secure_element = true; } @@ -311,8 +331,8 @@ static int ssl_get_socket(esp_transport_handle_t t) 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) { + transport_ssl_t *ssl = t->foundation_transport; + if (t && ssl) { // TODO: check t NULL first! ssl->cfg.ds_data = ds_data; } } @@ -328,14 +348,25 @@ void esp_transport_ssl_set_keep_alive(esp_transport_handle_t t, esp_transport_ke 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_context_data(t, NULL); 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_init_foundation(void) +{ + transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t)); + return ssl; +} + +esp_transport_handle_t esp_transport_tcp_init(void) +{ + esp_transport_handle_t t = esp_transport_init(); + esp_transport_set_context_data(t, NULL); + 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, ssl_connect_async); // TODO: tcp_connect_async() + t->_get_socket = ssl_get_socket; + return t; +} diff --git a/components/tcp_transport/transport_tcp.c b/components/tcp_transport/transport_tcp.c deleted file mode 100644 index 4d498e69ad..0000000000 --- a/components/tcp_transport/transport_tcp.c +++ /dev/null @@ -1,323 +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" -#include "esp_tls_errors.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) { - capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_CANNOT_RESOLVE_HOSTNAME); - 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)); - capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); - 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)); - capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); - 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); - capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_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)); - capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); - goto error; - } - else if (sockerr) { - esp_transport_capture_errno(t, sockerr); - ESP_LOGE(TAG, "[sock=%d] delayed connect error: %s", tcp->sock, strerror(sockerr)); - capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_CONNECTION_FAILED); - 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)); - capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); - 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)); - capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_SETOPT_FAILED); - 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) { - 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); - } - 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; -} From 6b318fe583ddd1a396608d687219a39f30484371 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 25 Jan 2021 09:45:38 +0100 Subject: [PATCH 03/14] esp_tls: Updated connection method to use non-blocking connect For better control over connection timeouts To be in line with former tcp_transport, as esp-tls is not used for plain tcp transports --- components/esp-tls/esp_tls.c | 118 +++++++++--- components/esp-tls/esp_tls.h | 3 +- components/esp-tls/esp_tls_errors.h | 2 +- .../private_include/esp_transport_internal.h | 34 +++- .../esp_transport_ssl_internal.h | 30 --- components/tcp_transport/transport.c | 58 ++++-- components/tcp_transport/transport_ssl.c | 175 ++++++++---------- 7 files changed, 244 insertions(+), 176 deletions(-) delete mode 100644 components/tcp_transport/private_include/esp_transport_ssl_internal.h diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index c2a6ad64f9..cc3af34c1a 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -146,8 +146,10 @@ 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; } @@ -209,9 +211,11 @@ static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *s if (addrinfo->ai_family == AF_INET) { struct sockaddr_in *p = (struct sockaddr_in *)addrinfo->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)); addr_ptr = p; } else if (addrinfo->ai_family == AF_INET6) { struct sockaddr_in6 *p = (struct sockaddr_in6 *)addrinfo->ai_addr; + ESP_LOGD(TAG, "[sock=%d] Resolved IPv6 address: %s", fd, ip6addr_ntoa((const ip6_addr_t*)&p->sin6_addr)); p->sin6_port = htons(port); p->sin6_family = AF_INET6; addr_ptr = p; @@ -221,37 +225,95 @@ static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *s goto err_freesocket; } - 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; - } - } - } - 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); + if (cfg && 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 = 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; + // Set socket to 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)); goto err_freesocket; } + if (fcntl(fd, F_SETFL, flags |= O_NONBLOCK) < 0) { + ESP_LOGE(TAG, "[sock=%d] set nonblocking error: %s", fd, strerror(errno)); + goto err_freesocket; + } + + ESP_LOGD(TAG, "[sock=%d] Connecting to server. HOST: %s, Port: %d", fd, host, port); + + if (connect(fd, (struct sockaddr *)(addr_ptr), 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; + freeaddrinfo(addrinfo); + 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_freesocket; + } + else if (res == 0) { + ESP_LOGE(TAG, "[sock=%d] select() timeout", fd); + ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; + goto err_freesocket; + } 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_freesocket; + } + 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)); + ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; + goto err_freesocket; + } + } + } else { + ESP_LOGE(TAG, "[sock=%d] connect() error: %s", fd, strerror(errno)); + goto err_freesocket; + } + } + + if (cfg && cfg->non_block == false) { + // Reset socket to blocking (unless non-blocking option set) + if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) { + ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", fd, strerror(errno)); + ret = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + goto err_freesocket; + } + if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0) { + ESP_LOGE(TAG, "[sock=%d] reset blocking error: %s", fd, strerror(errno)); + ret = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; + goto err_freesocket; + } + } *sockfd = fd; freeaddrinfo(addrinfo); @@ -292,7 +354,7 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c 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 +362,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 f3e36a22b5..981379435c 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -170,7 +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; + 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 index 3b39b56209..a24fb7f7f1 100644 --- a/components/esp-tls/esp_tls_errors.h +++ b/components/esp-tls/esp_tls_errors.h @@ -26,7 +26,7 @@ extern "C" { #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_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 */ diff --git a/components/tcp_transport/private_include/esp_transport_internal.h b/components/tcp_transport/private_include/esp_transport_internal.h index 761efeef29..ea9c64b4a8 100644 --- a/components/tcp_transport/private_include/esp_transport_internal.h +++ b/components/tcp_transport/private_include/esp_transport_internal.h @@ -20,7 +20,10 @@ typedef int (*get_socket_func)(esp_transport_handle_t t); -struct transport_esp_tls; +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 @@ -39,10 +42,8 @@ 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 transport_esp_tls *foundation_transport; + struct esp_foundation_transport *base; /*!< Foundation transport pointer available from each transport */ STAILQ_ENTRY(esp_transport_item_t) next; }; @@ -89,6 +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); -struct transport_esp_tls* esp_transport_init_foundation(void); +/** + * @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/transport.c b/components/tcp_transport/transport.c index f6ae753279..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 */ @@ -49,10 +49,32 @@ struct transport_esp_tls; */ 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 transport_esp_tls *foundation_transport; + 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) { /* @@ -66,8 +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->foundation_transport = esp_transport_init_foundation(); + transport->base = esp_transport_init_foundation_transport(); + ESP_TRANSPORT_MEM_CHECK(TAG, transport->base, + free(transport); + return NULL); return transport; } @@ -81,8 +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->foundation_transport = h->foundation_transport; + t->base = h->base; return ESP_OK; } @@ -106,8 +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); - free(h->foundation_transport); // TODO: make it destroy foundation + esp_transport_destroy_foundation_transport(h->base); free(h); return ESP_OK; } @@ -289,16 +311,16 @@ 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; @@ -328,19 +350,19 @@ void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_er 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 96034c76e3..f503aa74d4 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -15,19 +15,15 @@ #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"; +static const char *TAG = "TRANSPORT_BASE"; typedef enum { TRANS_SSL_INIT = 0, @@ -42,15 +38,16 @@ typedef struct transport_esp_tls { esp_tls_cfg_t cfg; bool ssl_initialized; transport_ssl_conn_state_t conn_state; -} transport_ssl_t; +} transport_esp_tls_t; 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 = t->foundation_transport; + transport_esp_tls_t *ssl = t->base->transport_esp_tls; 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 +62,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 = t->foundation_transport; + 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 = t->base->transport_esp_tls; 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,33 +88,22 @@ static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int ssl->tls = NULL; return -1; } - return 0; } -static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms) +static inline int ssl_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms) { - transport_ssl_t *ssl = t->foundation_transport; - - ssl->cfg.timeout_ms = timeout_ms; - ssl->cfg.is_plain_tcp = true; - ssl->ssl_initialized = true; - ssl->tls = esp_tls_init(); - if (esp_tls_conn_new_sync(host, strlen(host), port, &ssl->cfg, ssl->tls) <= 0) { - ESP_LOGE(TAG, "Failed to open a new connection"); - esp_transport_set_errors(t, ssl->tls->error_handle); - esp_tls_conn_destroy(ssl->tls); - ssl->tls = NULL; - return -1; - } - - return 0; + 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 = t->foundation_transport; + transport_esp_tls_t *ssl = t->base->transport_esp_tls; int ret = -1; int remain = 0; struct timeval timeout; @@ -134,7 +132,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 = t->foundation_transport; + transport_esp_tls_t *ssl = t->base->transport_esp_tls; int ret = -1; struct timeval timeout; fd_set writeset; @@ -158,7 +156,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 = t->foundation_transport; + transport_esp_tls_t *ssl = t->base->transport_esp_tls; 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); @@ -175,7 +173,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 = t->foundation_transport; + transport_esp_tls_t *ssl = t->base->transport_esp_tls; if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) { return poll; @@ -198,8 +196,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 = t->foundation_transport; - if (ssl->ssl_initialized) { + if (t && t->base && t->base->transport_esp_tls && t->base->transport_esp_tls->ssl_initialized) { + transport_esp_tls_t *ssl = t->base->transport_esp_tls; ret = esp_tls_conn_destroy(ssl->tls); ssl->conn_state = TRANS_SSL_INIT; ssl->ssl_initialized = false; @@ -209,139 +207,120 @@ static int ssl_close(esp_transport_handle_t t) static int ssl_destroy(esp_transport_handle_t t) { - transport_ssl_t *ssl = t->foundation_transport; esp_transport_close(t); - free(ssl); return 0; } void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t) { - transport_ssl_t *ssl = t->foundation_transport; - if (t && ssl) { - ssl->cfg.use_global_ca_store = true; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->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 = t->foundation_transport; - if (t && ssl) { - ssl->cfg.psk_hint_key = psk_hint_key; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->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 = t->foundation_transport; - if (t && ssl) { - ssl->cfg.cacert_pem_buf = (void *)data; - ssl->cfg.cacert_pem_bytes = len + 1; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.cacert_pem_buf = (void *)data; + t->base->transport_esp_tls->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 = t->foundation_transport; - if (t && ssl) { - ssl->cfg.cacert_buf = (void *)data; - ssl->cfg.cacert_bytes = len; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.cacert_buf = (void *)data; + t->base->transport_esp_tls->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 = t->foundation_transport; - if (t && ssl) { - ssl->cfg.clientcert_pem_buf = (void *)data; - ssl->cfg.clientcert_pem_bytes = len + 1; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.clientcert_pem_buf = (void *)data; + t->base->transport_esp_tls->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 = t->foundation_transport; - if (t && ssl) { - ssl->cfg.clientcert_buf = (void *)data; - ssl->cfg.clientcert_bytes = len; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.clientcert_buf = (void *)data; + t->base->transport_esp_tls->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 = t->foundation_transport; - if (t && ssl) { - ssl->cfg.clientkey_pem_buf = (void *)data; - ssl->cfg.clientkey_pem_bytes = len + 1; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.clientkey_pem_buf = (void *)data; + t->base->transport_esp_tls->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 = t->foundation_transport; - if (t && ssl) { - ssl->cfg.clientkey_password = (void *)password; - ssl->cfg.clientkey_password_len = password_len; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.clientkey_password = (void *)password; + t->base->transport_esp_tls->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 = t->foundation_transport; - if (t && ssl) { - ssl->cfg.clientkey_buf = (void *)data; - ssl->cfg.clientkey_bytes = len; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.clientkey_buf = (void *)data; + t->base->transport_esp_tls->cfg.clientkey_bytes = len; } } void esp_transport_ssl_set_alpn_protocol(esp_transport_handle_t t, const char **alpn_protos) { - transport_ssl_t *ssl = t->foundation_transport; - if (t && ssl) { - ssl->cfg.alpn_protos = alpn_protos; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.alpn_protos = alpn_protos; } } void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t) { - transport_ssl_t *ssl = t->foundation_transport; - if (t && ssl) { - ssl->cfg.skip_common_name = true; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.skip_common_name = true; } } void esp_transport_ssl_use_secure_element(esp_transport_handle_t t) { - transport_ssl_t *ssl = t->foundation_transport; - if (t && ssl) { - ssl->cfg.use_secure_element = true; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->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; - } + if (t && t->base && t->base->transport_esp_tls && t->base->transport_esp_tls->tls) { + return t->base->transport_esp_tls->tls->sockfd; } return -1; } void esp_transport_ssl_set_ds_data(esp_transport_handle_t t, void *ds_data) { - transport_ssl_t *ssl = t->foundation_transport; - if (t && ssl) { // TODO: check t NULL first! - ssl->cfg.ds_data = ds_data; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->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; + if (t && t->base && t->base->transport_esp_tls) { + t->base->transport_esp_tls->cfg.keep_alive_cfg = (tls_keep_alive_cfg_t *) keep_alive_cfg; } } @@ -355,10 +334,15 @@ esp_transport_handle_t esp_transport_ssl_init(void) return t; } -struct transport_esp_tls* esp_transport_init_foundation(void) +struct transport_esp_tls* esp_transport_esp_tls_create(void) { - transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t)); - return ssl; + 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) @@ -366,7 +350,12 @@ esp_transport_handle_t esp_transport_tcp_init(void) esp_transport_handle_t t = esp_transport_init(); esp_transport_set_context_data(t, NULL); 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, ssl_connect_async); // TODO: tcp_connect_async() + 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); +} From b4d792446c324934fd75e36219254547a54e738c Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 1 Feb 2021 16:15:50 +0100 Subject: [PATCH 04/14] examples/mqtt: Use common transport for setting log severity --- examples/protocols/mqtt/ssl/main/app_main.c | 3 +-- examples/protocols/mqtt/ssl_ds/main/app_main.c | 3 +-- examples/protocols/mqtt/ssl_mutual_auth/main/app_main.c | 3 +-- examples/protocols/mqtt/ssl_psk/main/app_main.c | 3 +-- examples/protocols/mqtt/tcp/main/app_main.c | 4 ++-- examples/protocols/mqtt/ws/main/app_main.c | 3 +-- examples/protocols/mqtt/wss/main/app_main.c | 3 +-- .../mqtt/publish_connect_test/main/publish_connect_test.c | 3 +-- tools/test_apps/protocols/openssl/main/main.c | 3 +-- 9 files changed, 10 insertions(+), 18 deletions(-) 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/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); From 4e394bcbce68a90d1970bed99c3dabfde3260771 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 1 Feb 2021 19:21:56 +0100 Subject: [PATCH 05/14] esp-tls: Extend error types with TCP clean close error --- components/esp_common/src/esp_err_to_name.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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 From 0e97517a1c0f6dace1c46d7ec50f6bd81f6b0d0f Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 1 Feb 2021 20:05:47 +0100 Subject: [PATCH 06/14] tcp_transport: Add unit test to exercise tcp/ssl transport init --- .../tcp_transport/test/test_transport.c | 245 ++++++++++++++++-- 1 file changed, 228 insertions(+), 17 deletions(-) diff --git a/components/tcp_transport/test/test_transport.c b/components/tcp_transport/test/test_transport.c index 8a52577b7c..dc82672302 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,184 @@ 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; i Date: Tue, 2 Feb 2021 10:38:34 +0100 Subject: [PATCH 07/14] websockets: Set keepalive options after adding transport to the list To be in line with other code and mainly to support base/foundation transport used by both tcp and ssl transport layers --- components/esp_websocket_client/esp_websocket_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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); From 41146d674f27d70b7d3c32cc5b243b4631c1c5e0 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 3 Feb 2021 17:30:45 +0100 Subject: [PATCH 08/14] ci: Update pppos client test regex with esp-tls transport layer --- examples/protocols/pppos_client/example_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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') From 1fa0db8d444f066cce5fadcfb3111e222fb5361f Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 4 Feb 2021 10:18:56 +0100 Subject: [PATCH 09/14] tcp_transport: Allow for using transport independently from list For compatibility reasons, support also transports separately if the transport is used before attaching to parent list. In this case we create an internal context which is independent on the foundation transport and used preferably --- .../tcp_transport/test/test_transport.c | 78 +++++++--- components/tcp_transport/transport_ssl.c | 143 ++++++++++-------- 2 files changed, 141 insertions(+), 80 deletions(-) diff --git a/components/tcp_transport/test/test_transport.c b/components/tcp_transport/test/test_transport.c index dc82672302..0395c0b6be 100644 --- a/components/tcp_transport/test/test_transport.c +++ b/components/tcp_transport/test/test_transport.c @@ -190,7 +190,7 @@ static void transport_connection_timeout_test(esp_transport_handle_t transport_u 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, 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 @@ -316,24 +316,21 @@ static void socket_operation_test(esp_transport_handle_t transport_under_test, test_utils_task_delete(tcp_connect_task_handle); } -static void tcp_transport_keepalive_test(esp_transport_handle_t transport_under_test) +static void tcp_transport_keepalive_test(esp_transport_handle_t transport_under_test, esp_transport_keep_alive_t *config) { - static const int KEEP_ALIVE_INTERVAL = 1; - static const int KEEP_ALIVE_IDLE = 2; - static const int KEEP_ALIVE_COUNT = 3; - - static const struct expected_sock_option expected_opts[] = { + static struct expected_sock_option expected_opts[4] = { { .level = SOL_SOCKET, .optname = SO_KEEPALIVE, .optval = 1, .opttype = SOCK_OPT_TYPE_BOOL }, - { .level = IPPROTO_TCP, .optname = TCP_KEEPIDLE, .optval = KEEP_ALIVE_IDLE, .opttype = SOCK_OPT_TYPE_INT }, - { .level = IPPROTO_TCP, .optname = TCP_KEEPINTVL, .optval = KEEP_ALIVE_INTERVAL, .opttype = SOCK_OPT_TYPE_INT }, - { .level = IPPROTO_TCP, .optname = TCP_KEEPCNT, .optval = KEEP_ALIVE_COUNT, .opttype = SOCK_OPT_TYPE_INT }, + { .level = IPPROTO_TCP }, + { .level = IPPROTO_TCP }, + { .level = IPPROTO_TCP } }; - esp_transport_keep_alive_t keep_alive_cfg = { .keep_alive_interval = KEEP_ALIVE_INTERVAL, - .keep_alive_idle = KEEP_ALIVE_IDLE, - .keep_alive_enable = true, - .keep_alive_count = KEEP_ALIVE_COUNT }; - esp_transport_tcp_set_keep_alive(transport_under_test, &keep_alive_cfg); + expected_opts[1].optname = TCP_KEEPIDLE; + expected_opts[1].optval = config->keep_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)); } @@ -346,7 +343,14 @@ TEST_CASE("tcp_transport: Keep alive test", "[tcp_transport]") esp_transport_list_add(transport_list, tcp, "tcp"); // Perform the test - tcp_transport_keepalive_test(tcp); + 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); @@ -363,7 +367,14 @@ TEST_CASE("ssl_transport: Keep alive test", "[tcp_transport]") esp_transport_ssl_enable_global_ca_store(ssl); // Perform the test - tcp_transport_keepalive_test(ssl); + 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); @@ -382,9 +393,40 @@ TEST_CASE("ws_transport: Keep alive test", "[tcp_transport]") esp_transport_list_add(transport_list, ws, "wss"); // Perform the test - tcp_transport_keepalive_test(ws); + 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_ssl.c b/components/tcp_transport/transport_ssl.c index f503aa74d4..fd2795a4bd 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -23,6 +23,10 @@ #include "esp_transport_utils.h" #include "esp_transport_internal.h" +#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 { @@ -40,11 +44,30 @@ typedef struct transport_esp_tls { transport_ssl_conn_state_t conn_state; } 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 esp_tls_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms, bool is_plain_tcp) { - transport_esp_tls_t *ssl = t->base->transport_esp_tls; + 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; @@ -74,7 +97,7 @@ static inline int tcp_connect_async(esp_transport_handle_t t, const char *host, 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 = t->base->transport_esp_tls; + transport_esp_tls_t *ssl = ssl_get_context_data(t); ssl->cfg.timeout_ms = timeout_ms; ssl->cfg.is_plain_tcp = is_plain_tcp; @@ -103,7 +126,7 @@ static inline int tcp_connect(esp_transport_handle_t t, const char *host, int po static int ssl_poll_read(esp_transport_handle_t t, int timeout_ms) { - transport_esp_tls_t *ssl = t->base->transport_esp_tls; + transport_esp_tls_t *ssl = ssl_get_context_data(t); int ret = -1; int remain = 0; struct timeval timeout; @@ -132,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_esp_tls_t *ssl = t->base->transport_esp_tls; + transport_esp_tls_t *ssl = ssl_get_context_data(t); int ret = -1; struct timeval timeout; fd_set writeset; @@ -156,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_esp_tls_t *ssl = t->base->transport_esp_tls; + 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); @@ -173,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_esp_tls_t *ssl = t->base->transport_esp_tls; + transport_esp_tls_t *ssl = ssl_get_context_data(t); if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) { return poll; @@ -196,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; - if (t && t->base && t->base->transport_esp_tls && t->base->transport_esp_tls->ssl_initialized) { - transport_esp_tls_t *ssl = t->base->transport_esp_tls; + 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; @@ -207,127 +230,124 @@ static int ssl_close(esp_transport_handle_t t) static int ssl_destroy(esp_transport_handle_t t) { - esp_transport_close(t); + 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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->cfg.cacert_pem_buf = (void *)data; - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->cfg.cacert_buf = (void *)data; - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->cfg.clientcert_pem_buf = (void *)data; - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->cfg.clientcert_buf = (void *)data; - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->cfg.clientkey_pem_buf = (void *)data; - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->cfg.clientkey_password = (void *)password; - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->cfg.clientkey_buf = (void *)data; - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->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 && t->base && t->base->transport_esp_tls && t->base->transport_esp_tls->tls) { - return t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->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) { - if (t && t->base && t->base->transport_esp_tls) { - t->base->transport_esp_tls->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(); - esp_transport_set_context_data(t, NULL); 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; @@ -348,7 +368,6 @@ void esp_transport_esp_tls_destroy(struct transport_esp_tls* transport_esp_tls) esp_transport_handle_t esp_transport_tcp_init(void) { esp_transport_handle_t t = esp_transport_init(); - esp_transport_set_context_data(t, NULL); 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; From 2d25252746c251299f021d1d2c3db7f8eaca80ee Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 4 Feb 2021 16:50:56 +0100 Subject: [PATCH 10/14] esp-tls: Rework tcp_connect() to use more subroutines Refactored the esp_tcp_connect() functionality to break it down to * dns-resolution + socket creation * set configured socket options * set/reset non-block mode * the actual connection in non-blocking mode --- components/esp-tls/esp_tls.c | 210 +++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 98 deletions(-) diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index cc3af34c1a..ac27acee76 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -133,8 +133,9 @@ esp_tls_t *esp_tls_init(void) 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,14 +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); - int res = getaddrinfo(use_host, NULL, &hints, address_info); - if (res != 0 || *address_info == NULL) { + 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); + "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; } @@ -163,95 +190,93 @@ 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); - ESP_LOGD(TAG, "[sock=%d] Resolved IPv4 address: %s", fd, ipaddr_ntoa((const ip_addr_t*)&p->sin_addr.s_addr)); - addr_ptr = p; - } else if (addrinfo->ai_family == AF_INET6) { - struct sockaddr_in6 *p = (struct sockaddr_in6 *)addrinfo->ai_addr; - ESP_LOGD(TAG, "[sock=%d] Resolved IPv6 address: %s", fd, ip6addr_ntoa((const ip6_addr_t*)&p->sin6_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; - } - - if (cfg && 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; - } - } - } - - // Set socket to 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)); - goto err_freesocket; - } - if (fcntl(fd, F_SETFL, flags |= O_NONBLOCK) < 0) { - ESP_LOGE(TAG, "[sock=%d] set nonblocking error: %s", fd, strerror(errno)); - 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; } + 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 *)(addr_ptr), sizeof(struct sockaddr)) < 0) { + 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 @@ -259,7 +284,6 @@ static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *s if (cfg && cfg->non_block) { // Non-blocking mode -> just return successfully at this stage *sockfd = fd; - freeaddrinfo(addrinfo); return ESP_OK; } @@ -273,12 +297,12 @@ static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *s 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_freesocket; + goto err; } else if (res == 0) { ESP_LOGE(TAG, "[sock=%d] select() timeout", fd); - ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; - goto err_freesocket; + ret = ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT; + goto err; } else { int sockerr; socklen_t len = (socklen_t)sizeof(int); @@ -286,43 +310,33 @@ static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *s 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_freesocket; + 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)); - ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; - goto err_freesocket; + goto err; } } } else { ESP_LOGE(TAG, "[sock=%d] connect() error: %s", fd, strerror(errno)); - goto err_freesocket; + goto err; } } if (cfg && cfg->non_block == false) { - // Reset socket to blocking (unless non-blocking option set) - if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) { - ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", fd, strerror(errno)); - ret = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; - goto err_freesocket; - } - if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0) { - ESP_LOGE(TAG, "[sock=%d] reset blocking error: %s", fd, strerror(errno)); - ret = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED; - goto err_freesocket; + // 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; } From 4375f888faecb32776ded4eaa56b3187c4cc2a56 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 10 Feb 2021 12:23:58 +0100 Subject: [PATCH 11/14] esp-tls: Fix wolfssl error codes for WANT_READ/WANT_WRITE wolfSSL error codes are mostly positive numbers, but esp-tls potentially non-block API (read/write) returns ssize_t, i.e. bytes read/written if >0, errorcode otherwise. To comply with this API we have to conditionate the wolfssl return codes to negative numbers, preferably the same codes as mbedTLS codes. --- components/esp-tls/esp_tls_errors.h | 10 ++++++--- components/esp-tls/esp_tls_wolfssl.c | 31 +++++++++++++++++++++------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/components/esp-tls/esp_tls_errors.h b/components/esp-tls/esp_tls_errors.h index a24fb7f7f1..bb281b0dae 100644 --- a/components/esp-tls/esp_tls_errors.h +++ b/components/esp-tls/esp_tls_errors.h @@ -52,13 +52,18 @@ extern "C" { #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 WOLFSSL_ERROR_WANT_READ -#define ESP_TLS_ERR_SSL_WANT_WRITE WOLFSSL_ERROR_WANT_WRITE +#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 */ @@ -74,7 +79,6 @@ typedef enum { 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_TCP_CONNECTION, /*!< Errors related to TCP layer, extending errno */ ESP_TLS_ERR_TYPE_MAX, /*!< Last err type -- invalid entry */ } esp_tls_error_type_t; 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; From 5cfa545d0849d191c2389f5c1af3b7bd04a97f38 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 10 Feb 2021 13:25:09 +0100 Subject: [PATCH 12/14] esp-tls: Added _esp_tls_net_init to init fd for both mbedtls/wolfssl --- components/esp-tls/esp_tls.c | 10 ++++------ components/esp-tls/private_include/esp_tls_mbedtls.h | 8 ++++++++ components/esp-tls/private_include/esp_tls_wolfssl.h | 7 +++++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index ac27acee76..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,9 +128,7 @@ 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; } @@ -353,9 +353,7 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c case ESP_TLS_INIT: tls->sockfd = -1; if (cfg != NULL && cfg->is_plain_tcp == false) { -#ifdef CONFIG_ESP_TLS_USING_MBEDTLS - mbedtls_net_init(&tls->server_fd); -#endif + _esp_tls_net_init(tls); tls->is_tls = true; } if ((esp_ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, tls, cfg)) != ESP_OK) { 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 /** From eb772e152c2bf034f6414c47b9f47ddecf9808d9 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Sat, 13 Feb 2021 12:00:13 +0100 Subject: [PATCH 13/14] esp_tls: Fix unresolved lwip symbol when complex dependency tree --- components/esp-tls/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) 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) From 1921ae89733ab55ad1e888742ef6dee917124411 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 15 Feb 2021 08:43:56 +0100 Subject: [PATCH 14/14] tcp_transport: Reduce lwip dependecy for tcp_transport/http_client --- components/esp_http_client/CMakeLists.txt | 2 +- components/tcp_transport/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index ad03b74a68..b2108a764c 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -4,4 +4,4 @@ idf_component_register(SRCS "transport.c" "transport_utils.c" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "private_include" - REQUIRES lwip esp-tls) + REQUIRES esp-tls)