Merge branch 'feature/transport_tcp_connection_errors' into 'master'

tcp_transport/esp_tls: Use common TCP transport to reduce code duplication

Closes IDFGH-4405

See merge request espressif/esp-idf!12136
This commit is contained in:
David Čermák 2021-02-16 13:32:47 +00:00
commit e615d10b4f
27 changed files with 855 additions and 654 deletions

View File

@ -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)

View File

@ -45,6 +45,7 @@ static const char *TAG = "esp-tls";
#define _esp_tls_read esp_mbedtls_read
#define _esp_tls_write esp_mbedtls_write
#define _esp_tls_conn_delete esp_mbedtls_conn_delete
#define _esp_tls_net_init esp_mbedtls_net_init
#ifdef CONFIG_ESP_TLS_SERVER
#define _esp_tls_server_session_create esp_mbedtls_server_session_create
#define _esp_tls_server_session_delete esp_mbedtls_server_session_delete
@ -60,6 +61,7 @@ static const char *TAG = "esp-tls";
#define _esp_tls_read esp_wolfssl_read
#define _esp_tls_write esp_wolfssl_write
#define _esp_tls_conn_delete esp_wolfssl_conn_delete
#define _esp_tls_net_init esp_wolfssl_net_init
#ifdef CONFIG_ESP_TLS_SERVER
#define _esp_tls_server_session_create esp_wolfssl_server_session_create
#define _esp_tls_server_session_delete esp_wolfssl_server_session_delete
@ -126,15 +128,14 @@ esp_tls_t *esp_tls_init(void)
free(tls);
return NULL;
}
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
tls->server_fd.fd = -1;
#endif
_esp_tls_net_init(tls);
tls->sockfd = -1;
return tls;
}
static esp_err_t resolve_host_name(const char *host, size_t hostlen, struct addrinfo **address_info)
static esp_err_t esp_tls_hostname_to_fd(const char *host, size_t hostlen, int port, struct sockaddr_storage *address, int* fd)
{
struct addrinfo *address_info;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
@ -146,12 +147,40 @@ static esp_err_t resolve_host_name(const char *host, size_t hostlen, struct addr
}
ESP_LOGD(TAG, "host:%s: strlen %lu", use_host, (unsigned long)hostlen);
if (getaddrinfo(use_host, NULL, &hints, address_info)) {
ESP_LOGE(TAG, "couldn't get hostname for :%s:", use_host);
int res = getaddrinfo(use_host, NULL, &hints, &address_info);
if (res != 0 || address_info == NULL) {
ESP_LOGE(TAG, "couldn't get hostname for :%s: "
"getaddrinfo() returns %d, addrinfo=%p", use_host, res, address_info);
free(use_host);
return ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME;
}
free(use_host);
*fd = socket(address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
if (*fd < 0) {
ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
freeaddrinfo(address_info);
return ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET;
}
if (address_info->ai_family == AF_INET) {
struct sockaddr_in *p = (struct sockaddr_in *)address_info->ai_addr;
p->sin_port = htons(port);
ESP_LOGD(TAG, "[sock=%d] Resolved IPv4 address: %s", *fd, ipaddr_ntoa((const ip_addr_t*)&p->sin_addr.s_addr));
memcpy(address, p, sizeof(struct sockaddr ));
} else if (address_info->ai_family == AF_INET6) {
struct sockaddr_in6 *p = (struct sockaddr_in6 *)address_info->ai_addr;
p->sin6_port = htons(port);
p->sin6_family = AF_INET6;
ESP_LOGD(TAG, "[sock=%d] Resolved IPv6 address: %s", *fd, ip6addr_ntoa((const ip6_addr_t*)&p->sin6_addr));
memcpy(address, p, sizeof(struct sockaddr_in6 ));
} else {
ESP_LOGE(TAG, "Unsupported protocol family %d", address_info->ai_family);
close(*fd);
freeaddrinfo(address_info);
return ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY;
}
freeaddrinfo(address_info);
return ESP_OK;
}
@ -161,106 +190,153 @@ static void ms_to_timeval(int timeout_ms, struct timeval *tv)
tv->tv_usec = (timeout_ms % 1000) * 1000;
}
static int esp_tls_tcp_enable_keep_alive(int fd, tls_keep_alive_cfg_t *cfg)
static esp_err_t esp_tls_set_socket_options(int fd, const esp_tls_cfg_t *cfg)
{
int keep_alive_enable = 1;
int keep_alive_idle = cfg->keep_alive_idle;
int keep_alive_interval = cfg->keep_alive_interval;
int keep_alive_count = cfg->keep_alive_count;
if (cfg && cfg->timeout_ms >= 0) {
struct timeval tv;
ms_to_timeval(cfg->timeout_ms, &tv);
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt SO_RCVTIMEO");
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt SO_SNDTIMEO");
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
if (cfg->keep_alive_cfg && cfg->keep_alive_cfg->keep_alive_enable) {
int keep_alive_enable = 1;
int keep_alive_idle = cfg->keep_alive_cfg->keep_alive_idle;
int keep_alive_interval = cfg->keep_alive_cfg->keep_alive_interval;
int keep_alive_count = cfg->keep_alive_cfg->keep_alive_count;
ESP_LOGD(TAG, "Enable TCP keep alive. idle: %d, interval: %d, count: %d", keep_alive_idle, keep_alive_interval, keep_alive_count);
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt SO_KEEPALIVE");
return -1;
ESP_LOGD(TAG, "Enable TCP keep alive. idle: %d, interval: %d, count: %d", keep_alive_idle, keep_alive_interval, keep_alive_count);
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt SO_KEEPALIVE");
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPIDLE");
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPINTVL");
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPCNT");
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
}
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_idle, sizeof(keep_alive_idle)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPIDLE");
return -1;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPINTVL");
return -1;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPCNT");
return -1;
return ESP_OK;
}
static esp_err_t esp_tls_set_socket_non_blocking(int fd, bool non_blocking)
{
int flags;
if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", fd, strerror(errno));
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
return 0;
if (non_blocking) {
flags |= O_NONBLOCK;
} else {
flags &= ~O_NONBLOCK;
}
if (fcntl(fd, F_SETFL, flags) < 0) {
ESP_LOGE(TAG, "[sock=%d] set blocking/nonblocking error: %s", fd, strerror(errno));
return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
}
return ESP_OK;
}
static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *sockfd, const esp_tls_t *tls, const esp_tls_cfg_t *cfg)
{
esp_err_t ret;
struct addrinfo *addrinfo;
if ((ret = resolve_host_name(host, hostlen, &addrinfo)) != ESP_OK) {
struct sockaddr_storage address;
int fd;
esp_err_t ret = esp_tls_hostname_to_fd(host, hostlen, port, &address, &fd);
if (ret != ESP_OK) {
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno);
return ret;
}
int fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
if (fd < 0) {
ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno);
ret = ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET;
goto err_freeaddr;
// Set timeout options and keep-alive options if configured
ret = esp_tls_set_socket_options(fd, cfg);
if (ret != ESP_OK) {
goto err;
}
void *addr_ptr;
if (addrinfo->ai_family == AF_INET) {
struct sockaddr_in *p = (struct sockaddr_in *)addrinfo->ai_addr;
p->sin_port = htons(port);
addr_ptr = p;
} else if (addrinfo->ai_family == AF_INET6) {
struct sockaddr_in6 *p = (struct sockaddr_in6 *)addrinfo->ai_addr;
p->sin6_port = htons(port);
p->sin6_family = AF_INET6;
addr_ptr = p;
} else {
ESP_LOGE(TAG, "Unsupported protocol family %d", addrinfo->ai_family);
ret = ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY;
goto err_freesocket;
// Set to non block before connecting to better control connection timeout
ret = esp_tls_set_socket_non_blocking(fd, true);
if (ret != ESP_OK) {
goto err;
}
if (cfg) {
if (cfg->timeout_ms >= 0) {
struct timeval tv;
ms_to_timeval(cfg->timeout_ms, &tv);
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
if (cfg->keep_alive_cfg && cfg->keep_alive_cfg->keep_alive_enable) {
if (esp_tls_tcp_enable_keep_alive(fd, cfg->keep_alive_cfg) < 0) {
ESP_LOGE(TAG, "Error setting keep-alive");
goto err_freesocket;
ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST;
ESP_LOGD(TAG, "[sock=%d] Connecting to server. HOST: %s, Port: %d", fd, host, port);
if (connect(fd, (struct sockaddr *)&address, sizeof(struct sockaddr)) < 0) {
if (errno == EINPROGRESS) {
fd_set fdset;
struct timeval tv = { .tv_usec = 0, .tv_sec = 10 }; // Default connection timeout is 10 s
if (cfg && cfg->non_block) {
// Non-blocking mode -> just return successfully at this stage
*sockfd = fd;
return ESP_OK;
}
if ( cfg && cfg->timeout_ms > 0 ) {
ms_to_timeval(cfg->timeout_ms, &tv);
}
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
int res = select(fd+1, NULL, &fdset, NULL, &tv);
if (res < 0) {
ESP_LOGE(TAG, "[sock=%d] select() error: %s", fd, strerror(errno));
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno);
goto err;
}
else if (res == 0) {
ESP_LOGE(TAG, "[sock=%d] select() timeout", fd);
ret = ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT;
goto err;
} else {
int sockerr;
socklen_t len = (socklen_t)sizeof(int);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
ESP_LOGE(TAG, "[sock=%d] getsockopt() error: %s", fd, strerror(errno));
ret = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
goto err;
}
else if (sockerr) {
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, sockerr);
ESP_LOGE(TAG, "[sock=%d] delayed connect error: %s", fd, strerror(sockerr));
goto err;
}
}
}
if (cfg->non_block) {
int flags = fcntl(fd, F_GETFL, 0);
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
if (ret < 0) {
ESP_LOGE(TAG, "Failed to configure the socket as non-blocking (errno %d)", errno);
goto err_freesocket;
}
} else {
ESP_LOGE(TAG, "[sock=%d] connect() error: %s", fd, strerror(errno));
goto err;
}
}
ret = connect(fd, addr_ptr, addrinfo->ai_addrlen);
if (ret < 0 && !(errno == EINPROGRESS && cfg && cfg->non_block)) {
ESP_LOGE(TAG, "Failed to connnect to host (errno %d)", errno);
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno);
ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST;
goto err_freesocket;
if (cfg && cfg->non_block == false) {
// reset back to blocking mode (unless non_block configured)
ret = esp_tls_set_socket_non_blocking(fd, false);
if (ret != ESP_OK) {
goto err;
}
}
*sockfd = fd;
freeaddrinfo(addrinfo);
return ESP_OK;
err_freesocket:
err:
close(fd);
err_freeaddr:
freeaddrinfo(addrinfo);
return ret;
}
@ -276,23 +352,21 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c
switch (tls->conn_state) {
case ESP_TLS_INIT:
tls->sockfd = -1;
if (cfg != NULL) {
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
mbedtls_net_init(&tls->server_fd);
#endif
if (cfg != NULL && cfg->is_plain_tcp == false) {
_esp_tls_net_init(tls);
tls->is_tls = true;
}
if ((esp_ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, tls, cfg)) != ESP_OK) {
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, esp_ret);
return -1;
}
if (!cfg) {
if (tls->is_tls == false) {
tls->read = tcp_read;
tls->write = tcp_write;
ESP_LOGD(TAG, "non-tls connection established");
return 1;
}
if (cfg->non_block) {
if (cfg && cfg->non_block) {
FD_ZERO(&tls->rset);
FD_SET(tls->sockfd, &tls->rset);
tls->wset = tls->rset;
@ -300,7 +374,7 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c
tls->conn_state = ESP_TLS_CONNECTING;
/* falls through */
case ESP_TLS_CONNECTING:
if (cfg->non_block) {
if (cfg && cfg->non_block) {
ESP_LOGD(TAG, "connecting...");
struct timeval tv;
ms_to_timeval(cfg->timeout_ms, &tv);

View File

@ -18,6 +18,7 @@
#include <sys/socket.h>
#include <fcntl.h>
#include "esp_err.h"
#include "esp_tls_errors.h"
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
@ -36,71 +37,6 @@
extern "C" {
#endif
#define ESP_ERR_ESP_TLS_BASE 0x8000 /*!< Starting number of ESP-TLS error codes */
#define ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME (ESP_ERR_ESP_TLS_BASE + 0x01) /*!< Error if hostname couldn't be resolved upon tls connection */
#define ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET (ESP_ERR_ESP_TLS_BASE + 0x02) /*!< Failed to create socket */
#define ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY (ESP_ERR_ESP_TLS_BASE + 0x03) /*!< Unsupported protocol family */
#define ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST (ESP_ERR_ESP_TLS_BASE + 0x04) /*!< Failed to connect to host */
#define ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x05) /*!< failed to set socket option */
#define ESP_ERR_MBEDTLS_CERT_PARTLY_OK (ESP_ERR_ESP_TLS_BASE + 0x06) /*!< mbedtls parse certificates was partly successful */
#define ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED (ESP_ERR_ESP_TLS_BASE + 0x07) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x08) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x09) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0A) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0B) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0C) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0D) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */
#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */
#define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */
#define ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT (ESP_ERR_ESP_TLS_BASE + 0x12) /*!< new connection in esp_tls_low_level_conn connection timeouted */
#define ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x13) /*!< wolfSSL api returned error */
#define ESP_ERR_WOLFSSL_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x14) /*!< wolfSSL api returned error */
#define ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x15) /*!< wolfSSL api returned error */
#define ESP_ERR_WOLFSSL_KEY_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x16) /*!< wolfSSL api returned error */
#define ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x17) /*!< wolfSSL api returned failed */
#define ESP_ERR_WOLFSSL_CTX_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x18) /*!< wolfSSL api returned failed */
#define ESP_ERR_WOLFSSL_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x19) /*!< wolfSSL api returned failed */
#define ESP_ERR_WOLFSSL_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1A) /*!< wolfSSL api returned failed */
#define ESP_ERR_ESP_TLS_SE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1B) /*< esp-tls use Secure Element returned failed */
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
#define ESP_TLS_ERR_SSL_WANT_READ MBEDTLS_ERR_SSL_WANT_READ
#define ESP_TLS_ERR_SSL_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE
#define ESP_TLS_ERR_SSL_TIMEOUT MBEDTLS_ERR_SSL_TIMEOUT
#elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */
#define ESP_TLS_ERR_SSL_WANT_READ WOLFSSL_ERROR_WANT_READ
#define ESP_TLS_ERR_SSL_WANT_WRITE WOLFSSL_ERROR_WANT_WRITE
#define ESP_TLS_ERR_SSL_TIMEOUT WOLFSSL_CBIO_ERR_TIMEOUT
#endif /*CONFIG_ESP_TLS_USING_WOLFSSL */
/**
* Definition of different types/sources of error codes reported
* from different components
*/
typedef enum {
ESP_TLS_ERR_TYPE_UNKNOWN = 0,
ESP_TLS_ERR_TYPE_SYSTEM, /*!< System error -- errno */
ESP_TLS_ERR_TYPE_MBEDTLS, /*!< Error code from mbedTLS library */
ESP_TLS_ERR_TYPE_MBEDTLS_CERT_FLAGS, /*!< Certificate flags defined in mbedTLS */
ESP_TLS_ERR_TYPE_ESP, /*!< ESP-IDF error type -- esp_err_t */
ESP_TLS_ERR_TYPE_WOLFSSL, /*!< Error code from wolfSSL library */
ESP_TLS_ERR_TYPE_WOLFSSL_CERT_FLAGS, /*!< Certificate flags defined in wolfSSL */
ESP_TLS_ERR_TYPE_MAX, /*!< Last err type -- invalid entry */
} esp_tls_error_type_t;
typedef struct esp_tls_last_error* esp_tls_error_handle_t;
/**
* @brief Error structure containing relevant errors in case tls error occurred
*/
typedef struct esp_tls_last_error {
esp_err_t last_error; /*!< error code (based on ESP_ERR_ESP_TLS_BASE) of the last occurred error */
int esp_tls_error_code; /*!< esp_tls error code from last esp_tls failed api */
int esp_tls_flags; /*!< last certification verification flags */
} esp_tls_last_error_t;
/**
* @brief ESP-TLS Connection State
*/
@ -234,6 +170,8 @@ typedef struct esp_tls_cfg {
bundle for server verification, must be enabled in menuconfig */
void *ds_data; /*!< Pointer for digital signature peripheral context */
bool is_plain_tcp; /*!< Use non-TLS connection: When set to true, the esp-tls uses
plain TCP transport rather then TLS/SSL connection */
} esp_tls_cfg_t;
#ifdef CONFIG_ESP_TLS_SERVER

View File

@ -0,0 +1,100 @@
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_TLS_ERRORS_H_
#define _ESP_TLS_ERRORS_H_
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_ERR_ESP_TLS_BASE 0x8000 /*!< Starting number of ESP-TLS error codes */
#define ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME (ESP_ERR_ESP_TLS_BASE + 0x01) /*!< Error if hostname couldn't be resolved upon tls connection */
#define ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET (ESP_ERR_ESP_TLS_BASE + 0x02) /*!< Failed to create socket */
#define ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY (ESP_ERR_ESP_TLS_BASE + 0x03) /*!< Unsupported protocol family */
#define ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST (ESP_ERR_ESP_TLS_BASE + 0x04) /*!< Failed to connect to host */
#define ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x05) /*!< failed to set/get socket option */
#define ESP_ERR_MBEDTLS_CERT_PARTLY_OK (ESP_ERR_ESP_TLS_BASE + 0x06) /*!< mbedtls parse certificates was partly successful */
#define ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED (ESP_ERR_ESP_TLS_BASE + 0x07) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x08) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x09) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0A) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0B) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0C) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0D) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */
#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */
#define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */
#define ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT (ESP_ERR_ESP_TLS_BASE + 0x12) /*!< new connection in esp_tls_low_level_conn connection timeouted */
#define ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x13) /*!< wolfSSL api returned error */
#define ESP_ERR_WOLFSSL_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x14) /*!< wolfSSL api returned error */
#define ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x15) /*!< wolfSSL api returned error */
#define ESP_ERR_WOLFSSL_KEY_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x16) /*!< wolfSSL api returned error */
#define ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x17) /*!< wolfSSL api returned failed */
#define ESP_ERR_WOLFSSL_CTX_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x18) /*!< wolfSSL api returned failed */
#define ESP_ERR_WOLFSSL_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x19) /*!< wolfSSL api returned failed */
#define ESP_ERR_WOLFSSL_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1A) /*!< wolfSSL api returned failed */
#define ESP_ERR_ESP_TLS_SE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1B) /*< esp-tls use Secure Element returned failed */
#define ESP_ERR_ESP_TLS_TCP_CLOSED_FIN (ESP_ERR_ESP_TLS_BASE + 0x1C) /*< esp-tls's TPC transport connection has benn closed (in a clean way) */
/**
* Definition of errors reported from IO API (potentially non-blocking) in case of error:
* - esp_tls_conn_read()
* - esp_tls_conn_write()
*/
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
#define ESP_TLS_ERR_SSL_WANT_READ MBEDTLS_ERR_SSL_WANT_READ
#define ESP_TLS_ERR_SSL_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE
#define ESP_TLS_ERR_SSL_TIMEOUT MBEDTLS_ERR_SSL_TIMEOUT
#elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */
#define ESP_TLS_ERR_SSL_WANT_READ -0x6900
#define ESP_TLS_ERR_SSL_WANT_WRITE -0x6880
#define ESP_TLS_ERR_SSL_TIMEOUT WOLFSSL_CBIO_ERR_TIMEOUT
#endif /*CONFIG_ESP_TLS_USING_WOLFSSL */
/**
* Definition of different types/sources of error codes reported
* from different components
*/
typedef enum {
ESP_TLS_ERR_TYPE_UNKNOWN = 0,
ESP_TLS_ERR_TYPE_SYSTEM, /*!< System error -- errno */
ESP_TLS_ERR_TYPE_MBEDTLS, /*!< Error code from mbedTLS library */
ESP_TLS_ERR_TYPE_MBEDTLS_CERT_FLAGS, /*!< Certificate flags defined in mbedTLS */
ESP_TLS_ERR_TYPE_ESP, /*!< ESP-IDF error type -- esp_err_t */
ESP_TLS_ERR_TYPE_WOLFSSL, /*!< Error code from wolfSSL library */
ESP_TLS_ERR_TYPE_WOLFSSL_CERT_FLAGS, /*!< Certificate flags defined in wolfSSL */
ESP_TLS_ERR_TYPE_MAX, /*!< Last err type -- invalid entry */
} esp_tls_error_type_t;
typedef struct esp_tls_last_error* esp_tls_error_handle_t;
/**
* @brief Error structure containing relevant errors in case tls error occurred
*/
typedef struct esp_tls_last_error {
esp_err_t last_error; /*!< error code (based on ESP_ERR_ESP_TLS_BASE) of the last occurred error */
int esp_tls_error_code; /*!< esp_tls error code from last esp_tls failed api */
int esp_tls_flags; /*!< last certification verification flags */
} esp_tls_last_error_t;
#ifdef __cplusplus
}
#endif
#endif //_ESP_TLS_ERRORS_H_

View File

@ -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;

View File

@ -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

View File

@ -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
/**

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -1,8 +1,7 @@
idf_component_register(SRCS "transport.c"
"transport_ssl.c"
"transport_tcp.c"
"transport_ws.c"
"transport_utils.c"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "private_include"
REQUIRES lwip esp-tls)
REQUIRES esp-tls)

View File

@ -20,6 +20,11 @@
typedef int (*get_socket_func)(esp_transport_handle_t t);
typedef struct esp_foundation_transport {
struct esp_transport_error_storage *error_handle; /*!< Pointer to the transport error container */
struct transport_esp_tls *transport_esp_tls; /*!< Pointer to the base transport which uses esp-tls */
} esp_foundation_transport_t;
/**
* Transport layer structure, which will provide functions, basic properties for transport types
*/
@ -37,13 +42,35 @@ struct esp_transport_item_t {
connect_async_func _connect_async; /*!< non-blocking connect function of this transport */
payload_transfer_func _parent_transfer; /*!< Function returning underlying transport layer */
get_socket_func _get_socket; /*!< Function returning the transport's socket */
struct esp_transport_error_s* error_handle; /*!< Error handle (based on esp-tls error handle)
* extended with transport's specific errors */
esp_transport_keep_alive_t *keep_alive_cfg; /*!< TCP keep-alive config */
struct esp_foundation_transport *base; /*!< Foundation transport pointer available from each transport */
STAILQ_ENTRY(esp_transport_item_t) next;
};
/**
* @brief Internal error types for TCP connection issues not covered in socket's errno
*/
enum tcp_transport_errors {
ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT,
ERR_TCP_TRANSPORT_CANNOT_RESOLVE_HOSTNAME,
ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN,
ERR_TCP_TRANSPORT_CONNECTION_FAILED,
ERR_TCP_TRANSPORT_SETOPT_FAILED,
};
/**
* @brief Captures internal tcp connection error
*
* This is internally translated to esp-tls return codes of esp_err_t type, since the esp-tls
* will be used as TCP transport layer
*
* @param[in] t The transport handle
* @param[in] error Internal tcp-transport's error
*
*/
void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_errors error);
/**
* @brief Returns underlying socket for the supplied transport handle
*
@ -63,4 +90,29 @@ int esp_transport_get_socket(esp_transport_handle_t t);
*/
void esp_transport_capture_errno(esp_transport_handle_t t, int sock_errno);
/**
* @brief Creates esp-tls transport used in the foundation transport
*
* @return transport esp-tls handle
*/
struct transport_esp_tls* esp_transport_esp_tls_create(void);
/**
* @brief Destroys esp-tls transport used in the foundation transport
*
* @param[in] transport esp-tls handle
*/
void esp_transport_esp_tls_destroy(struct transport_esp_tls* transport_esp_tls);
/**
* @brief Sets error to common transport handle
*
* Note: This function copies the supplied error handle object to tcp_transport's internal
* error handle object
*
* @param[in] A transport handle
*
*/
void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_handle_t error_handle);
#endif //_ESP_TRANSPORT_INTERNAL_H_

View File

@ -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_ */

View File

@ -14,6 +14,9 @@
#define TCP_CONNECT_DONE (1)
#define TCP_LISTENER_DONE (2)
#define TCP_ACCEPTOR_DONE (4)
#define TCP_LISTENER_ACCEPTED (8)
#define TCP_LISTENER_READY (16)
struct tcp_connect_task_params {
int timeout_ms;
@ -21,8 +24,12 @@ struct tcp_connect_task_params {
EventGroupHandle_t tcp_connect_done;
int ret;
int listen_sock;
int accepted_sock;
int last_connect_sock;
bool tcp_listener_failed;
esp_transport_handle_t transport_under_test;
bool accept_connection;
bool consume_sock_backlog;
};
/**
@ -51,8 +58,12 @@ static void connect_once(struct tcp_connect_task_params *params)
}
/**
* @brief creates a listener (without and acceptor) and connect to as many times as possible
* to prepare an endpoint which would make the client block but not complete TCP handshake
* @brief creates a listener (and an acceptor if configured)
*
* if consume_sock_backlog set: connect as many times as possible to prepare an endpoint which
* would make the client block but not complete TCP handshake
*
* if accept_connection set: waiting normally for connection creating an acceptor to mimic tcp-transport endpoint
*/
static void localhost_listener(void *pvParameters)
{
@ -63,6 +74,9 @@ static void localhost_listener(void *pvParameters)
.sin_port = htons(params->port) };
// Create listener socket and bind it to ANY address
params->listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
int opt = 1;
setsockopt(params->listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (params->listen_sock < 0) {
ESP_LOGE(TAG, "Unable to create socket");
params->tcp_listener_failed = true;
@ -83,11 +97,27 @@ static void localhost_listener(void *pvParameters)
goto failed;
}
// Ideally we would set backlog to 0, but since this is an implementation specific recommendation parameter,
// we recursively create sockets and try to connect to this listener in order to consume the backlog. After
// the backlog is consumed, the last connection blocks (waiting for accept), but at that point we are sure
// that any other connection would also block
connect_once(params);
// Listener is ready at this point
xEventGroupSetBits(params->tcp_connect_done, TCP_LISTENER_READY);
if (params->consume_sock_backlog) {
// Ideally we would set backlog to 0, but since this is an implementation specific recommendation parameter,
// we recursively create sockets and try to connect to this listener in order to consume the backlog. After
// the backlog is consumed, the last connection blocks (waiting for accept), but at that point we are sure
// that any other connection would also block
connect_once(params);
} else if (params->accept_connection) {
struct sockaddr_storage source_addr;
socklen_t addr_len = sizeof(source_addr);
params->accepted_sock = accept(params->listen_sock, (struct sockaddr *)&source_addr, &addr_len);
if (params->accepted_sock < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
goto failed;
}
xEventGroupSetBits(params->tcp_connect_done, TCP_LISTENER_ACCEPTED); // Mark the socket as accepted
// ...and wait for the "acceptor" tests to finish
xEventGroupWaitBits(params->tcp_connect_done, TCP_ACCEPTOR_DONE, true, true, params->timeout_ms * 10);
}
failed:
xEventGroupSetBits(params->tcp_connect_done, TCP_LISTENER_DONE);
@ -98,14 +128,12 @@ static void tcp_connect_task(void *pvParameters)
{
struct tcp_connect_task_params *params = pvParameters;
esp_transport_list_handle_t transport_list = esp_transport_list_init();
esp_transport_handle_t tcp = esp_transport_tcp_init();
esp_transport_list_add(transport_list, tcp, "tcp");
params->ret = esp_transport_connect(tcp, "localhost", params->port, params->timeout_ms);
params->ret = esp_transport_connect(params->transport_under_test, "localhost", params->port, params->timeout_ms);
if (params->accept_connection) {
// If we test the accepted connection, need to wait until the test completes
xEventGroupWaitBits(params->tcp_connect_done, TCP_ACCEPTOR_DONE, true, true, params->timeout_ms * 10);
}
xEventGroupSetBits(params->tcp_connect_done, TCP_CONNECT_DONE);
esp_transport_close(tcp);
esp_transport_list_destroy(transport_list);
vTaskSuspend(NULL);
}
@ -132,7 +160,7 @@ TEST_CASE("tcp_transport: using ws transport separately", "[tcp_transport][leaks
TEST_ASSERT_EQUAL(ESP_OK, esp_transport_destroy(tcp));
}
TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]")
static void transport_connection_timeout_test(esp_transport_handle_t transport_under_test)
{
// This case simulates connection timeout running tcp connect asynchronously with other socket connection
// consuming entire socket listener backlog.
@ -142,7 +170,9 @@ TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]")
struct tcp_connect_task_params params = { .tcp_connect_done = xEventGroupCreate(),
.timeout_ms = 200,
.port = 80 };
.port = 80,
.consume_sock_backlog = true,
.transport_under_test = transport_under_test };
TickType_t max_wait = pdMS_TO_TICKS(params.timeout_ms * 10);
TaskHandle_t localhost_listener_task_handle = NULL;
TaskHandle_t tcp_connect_task_handle = NULL;
@ -160,7 +190,7 @@ TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]")
EventBits_t bits = xEventGroupWaitBits(params.tcp_connect_done, TCP_CONNECT_DONE, true, true, max_wait);
TickType_t end = xTaskGetTickCount();
TEST_ASSERT_EQUAL(TCP_CONNECT_DONE, bits); // Connection has finished
TEST_ASSERT_EQUAL(TCP_CONNECT_DONE, TCP_CONNECT_DONE & bits); // Connection has finished
TEST_ASSERT_EQUAL(-1, params.ret); // Connection failed with -1
// Test connection attempt took expected timeout value
@ -177,3 +207,226 @@ TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]")
test_utils_task_delete(localhost_listener_task_handle);
test_utils_task_delete(tcp_connect_task_handle);
}
TEST_CASE("tcp_transport: connect timeout", "[tcp_transport]")
{
// Init the transport under test
esp_transport_list_handle_t transport_list = esp_transport_list_init();
esp_transport_handle_t tcp = esp_transport_tcp_init();
esp_transport_list_add(transport_list, tcp, "tcp");
transport_connection_timeout_test(tcp);
esp_transport_close(tcp);
esp_transport_list_destroy(transport_list);
}
TEST_CASE("ssl_transport: connect timeout", "[tcp_transport]")
{
// Init the transport under test
esp_transport_list_handle_t transport_list = esp_transport_list_init();
esp_transport_handle_t tcp = esp_transport_tcp_init();
esp_transport_list_add(transport_list, tcp, "tcp");
esp_transport_handle_t ssl = esp_transport_ssl_init();
esp_transport_list_add(transport_list, ssl, "ssl");
transport_connection_timeout_test(ssl);
esp_transport_close(tcp);
esp_transport_close(ssl);
esp_transport_list_destroy(transport_list);
}
TEST_CASE("transport: init and deinit multiple transport items", "[tcp_transport][leaks=0]")
{
esp_transport_list_handle_t transport_list = esp_transport_list_init();
esp_transport_handle_t tcp = esp_transport_tcp_init();
esp_transport_list_add(transport_list, tcp, "tcp");
esp_transport_handle_t ssl = esp_transport_ssl_init();
esp_transport_list_add(transport_list, ssl, "ssl");
esp_transport_handle_t ws = esp_transport_ws_init(tcp);
esp_transport_list_add(transport_list, ws, "ws");
esp_transport_handle_t wss = esp_transport_ws_init(ssl);
esp_transport_list_add(transport_list, wss, "wss");
TEST_ASSERT_EQUAL(ESP_OK, esp_transport_list_destroy(transport_list));
}
// This is a private API of the tcp transport, but needed for socket operation tests
int esp_transport_get_socket(esp_transport_handle_t t);
// Structures and types for passing socket options
enum expected_sock_option_types {
SOCK_OPT_TYPE_BOOL,
SOCK_OPT_TYPE_INT,
};
struct expected_sock_option {
int level;
int optname;
int optval;
enum expected_sock_option_types opttype;
};
static void socket_operation_test(esp_transport_handle_t transport_under_test,
const struct expected_sock_option expected_opts[], size_t sock_options_len)
{
struct tcp_connect_task_params params = { .tcp_connect_done = xEventGroupCreate(),
.timeout_ms = 200,
.port = 80,
.accept_connection = true,
.transport_under_test = transport_under_test };
TickType_t max_wait = pdMS_TO_TICKS(params.timeout_ms * 10);
TaskHandle_t localhost_listener_task_handle = NULL;
TaskHandle_t tcp_connect_task_handle = NULL;
test_case_uses_tcpip();
// Create a listener and wait for it to be ready
xTaskCreatePinnedToCore(localhost_listener, "localhost_listener", 4096, (void*)&params, 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*)&params, 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<sock_options_len; ++i) {
int value = -1;
socklen_t optlen = (socklen_t)sizeof(value);
TEST_ASSERT_EQUAL(getsockopt(sock, expected_opts[i].level, expected_opts[i].optname,
(void*)&value, &optlen), 0);
if (expected_opts[i].opttype == SOCK_OPT_TYPE_BOOL) {
TEST_ASSERT_EQUAL((bool)value, (bool) expected_opts[i].optval);
} else if (expected_opts[i].opttype == SOCK_OPT_TYPE_INT) {
TEST_ASSERT_EQUAL(value, expected_opts[i].optval);
} else {
TEST_FAIL_MESSAGE("Unsupported socket option type");
}
}
close(sock); // close the tcp_transport's socket so we don't have to wait for connection timeout
xEventGroupSetBits(params.tcp_connect_done, TCP_ACCEPTOR_DONE);
xEventGroupWaitBits(params.tcp_connect_done, TCP_CONNECT_DONE, true, true, max_wait);
// Closing the listener and acceptor sockets
close(params.listen_sock);
close(params.accepted_sock);
// Cleanup
TEST_ASSERT_EQUAL(false, params.tcp_listener_failed);
vEventGroupDelete(params.tcp_connect_done);
test_utils_task_delete(localhost_listener_task_handle);
test_utils_task_delete(tcp_connect_task_handle);
}
static void tcp_transport_keepalive_test(esp_transport_handle_t transport_under_test, esp_transport_keep_alive_t *config)
{
static struct expected_sock_option expected_opts[4] = {
{ .level = SOL_SOCKET, .optname = SO_KEEPALIVE, .optval = 1, .opttype = SOCK_OPT_TYPE_BOOL },
{ .level = IPPROTO_TCP },
{ .level = IPPROTO_TCP },
{ .level = IPPROTO_TCP }
};
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));
}
TEST_CASE("tcp_transport: Keep alive test", "[tcp_transport]")
{
// Init the transport under test
esp_transport_list_handle_t transport_list = esp_transport_list_init();
esp_transport_handle_t tcp = esp_transport_tcp_init();
esp_transport_list_add(transport_list, tcp, "tcp");
// Perform the test
esp_transport_keep_alive_t keep_alive_cfg = {
.keep_alive_interval = 5,
.keep_alive_idle = 4,
.keep_alive_enable = true,
.keep_alive_count = 3 };
esp_transport_tcp_set_keep_alive(tcp, &keep_alive_cfg);
tcp_transport_keepalive_test(tcp, &keep_alive_cfg);
// Cleanup
esp_transport_close(tcp);
esp_transport_list_destroy(transport_list);
}
TEST_CASE("ssl_transport: Keep alive test", "[tcp_transport]")
{
// Init the transport under test
esp_transport_list_handle_t transport_list = esp_transport_list_init();
esp_transport_handle_t ssl = esp_transport_ssl_init();
esp_transport_list_add(transport_list, ssl, "ssl");
esp_tls_init_global_ca_store();
esp_transport_ssl_enable_global_ca_store(ssl);
// Perform the test
esp_transport_keep_alive_t keep_alive_cfg = {
.keep_alive_interval = 2,
.keep_alive_idle = 3,
.keep_alive_enable = true,
.keep_alive_count = 4 };
esp_transport_ssl_set_keep_alive(ssl, &keep_alive_cfg);
tcp_transport_keepalive_test(ssl, &keep_alive_cfg);
// Cleanup
esp_transport_close(ssl);
esp_transport_list_destroy(transport_list);
}
TEST_CASE("ws_transport: Keep alive test", "[tcp_transport]")
{
// Init the transport under test
esp_transport_list_handle_t transport_list = esp_transport_list_init();
esp_transport_handle_t ssl = esp_transport_ssl_init();
esp_transport_list_add(transport_list, ssl, "ssl");
esp_tls_init_global_ca_store();
esp_transport_ssl_enable_global_ca_store(ssl);
esp_transport_handle_t ws = esp_transport_ws_init(ssl);
esp_transport_list_add(transport_list, ws, "wss");
// Perform the test
esp_transport_keep_alive_t keep_alive_cfg = {
.keep_alive_interval = 1,
.keep_alive_idle = 2,
.keep_alive_enable = true,
.keep_alive_count = 3 };
esp_transport_tcp_set_keep_alive(ssl, &keep_alive_cfg);
tcp_transport_keepalive_test(ws, &keep_alive_cfg);
// Cleanup
esp_transport_close(ssl);
esp_transport_list_destroy(transport_list);
}
// Note: This functionality is tested and kept only for compatibility reasons with IDF <= 4.x
// It is strongly encouraged to use transport within lists only
TEST_CASE("ssl_transport: Check that parameters (keepalive) are set independently on the list", "[tcp_transport]")
{
// Init the transport under test
esp_transport_handle_t ssl = esp_transport_ssl_init();
esp_tls_init_global_ca_store();
esp_transport_ssl_enable_global_ca_store(ssl);
// Perform the test
esp_transport_keep_alive_t keep_alive_cfg = {
.keep_alive_interval = 2,
.keep_alive_idle = 4,
.keep_alive_enable = true,
.keep_alive_count = 3 };
esp_transport_ssl_set_keep_alive(ssl, &keep_alive_cfg);
tcp_transport_keepalive_test(ssl, &keep_alive_cfg);
// Cleanup
esp_transport_close(ssl);
esp_transport_destroy(ssl);
}

View File

@ -31,7 +31,7 @@ static const char *TAG = "TRANSPORT";
* * esp-tls last error storage
* * sock-errno
*/
struct esp_transport_error_s {
struct esp_transport_error_storage {
struct esp_tls_last_error esp_tls_err_h_base; /*!< esp-tls last error container */
// additional fields
int sock_errno; /*!< last socket error captured for this transport */
@ -42,14 +42,39 @@ struct esp_transport_error_s {
*/
STAILQ_HEAD(esp_transport_list_t, esp_transport_item_t);
struct transport_esp_tls;
/**
* Internal transport structure holding list of transports and other data common to all transports
*/
typedef struct esp_transport_internal {
struct esp_transport_list_t list; /*!< List of transports */
struct esp_transport_error_s* error_handle; /*!< Pointer to the transport error container */
struct esp_foundation_transport *base; /*!< Base transport pointer shared for each list item */
} esp_transport_internal_t;
static esp_foundation_transport_t * esp_transport_init_foundation_transport(void)
{
esp_foundation_transport_t *foundation = calloc(1, sizeof(esp_foundation_transport_t));
ESP_TRANSPORT_MEM_CHECK(TAG, foundation, return NULL);
foundation->error_handle = calloc(1, sizeof(struct esp_transport_error_storage));
ESP_TRANSPORT_MEM_CHECK(TAG, foundation->error_handle,
free(foundation);
return NULL);
foundation->transport_esp_tls = esp_transport_esp_tls_create();
ESP_TRANSPORT_MEM_CHECK(TAG, foundation->transport_esp_tls,
free(foundation->error_handle);
free(foundation);
return NULL);
return foundation;
}
static void esp_transport_destroy_foundation_transport(esp_foundation_transport_t *foundation)
{
esp_transport_esp_tls_destroy(foundation->transport_esp_tls);
free(foundation->error_handle);
free(foundation);
}
static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_handle_t t)
{
/*
@ -63,7 +88,10 @@ esp_transport_list_handle_t esp_transport_list_init(void)
esp_transport_list_handle_t transport = calloc(1, sizeof(esp_transport_internal_t));
ESP_TRANSPORT_MEM_CHECK(TAG, transport, return NULL);
STAILQ_INIT(&transport->list);
transport->error_handle = calloc(1, sizeof(struct esp_transport_error_s));
transport->base = esp_transport_init_foundation_transport();
ESP_TRANSPORT_MEM_CHECK(TAG, transport->base,
free(transport);
return NULL);
return transport;
}
@ -77,7 +105,7 @@ esp_err_t esp_transport_list_add(esp_transport_list_handle_t h, esp_transport_ha
strcpy(t->scheme, scheme);
STAILQ_INSERT_TAIL(&h->list, t, next);
// Each transport in a list to share the same error tracker
t->error_handle = h->error_handle;
t->base = h->base;
return ESP_OK;
}
@ -101,7 +129,7 @@ esp_transport_handle_t esp_transport_list_get_transport(esp_transport_list_handl
esp_err_t esp_transport_list_destroy(esp_transport_list_handle_t h)
{
esp_transport_list_clean(h);
free(h->error_handle);
esp_transport_destroy_foundation_transport(h->base);
free(h);
return ESP_OK;
}
@ -283,36 +311,58 @@ esp_err_t esp_transport_set_parent_transport_func(esp_transport_handle_t t, payl
esp_tls_error_handle_t esp_transport_get_error_handle(esp_transport_handle_t t)
{
if (t) {
return &t->error_handle->esp_tls_err_h_base;
return &t->base->error_handle->esp_tls_err_h_base;
}
return NULL;
}
int esp_transport_get_errno(esp_transport_handle_t t)
{
if (t && t->error_handle) {
int actual_errno = t->error_handle->sock_errno;
t->error_handle->sock_errno = 0;
if (t && t->base && t->base->error_handle) {
int actual_errno = t->base->error_handle->sock_errno;
t->base->error_handle->sock_errno = 0;
return actual_errno;
}
return -1;
}
void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_errors error)
{
esp_tls_last_error_t *err_handle = esp_transport_get_error_handle(t);
switch (error) {
case ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT:
err_handle->last_error = ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT;
break;
case ERR_TCP_TRANSPORT_CANNOT_RESOLVE_HOSTNAME:
err_handle->last_error = ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME;
break;
case ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN:
err_handle->last_error = ESP_ERR_ESP_TLS_TCP_CLOSED_FIN;
break;
case ERR_TCP_TRANSPORT_CONNECTION_FAILED:
err_handle->last_error = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST;
break;
case ERR_TCP_TRANSPORT_SETOPT_FAILED:
err_handle->last_error = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
break;
}
}
void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_handle_t error_handle)
{
if (t && t->error_handle) {
memcpy(&t->error_handle->esp_tls_err_h_base, error_handle, sizeof(esp_tls_last_error_t));
if (t && t->base && t->base->error_handle) {
memcpy(&t->base->error_handle->esp_tls_err_h_base, error_handle, sizeof(esp_tls_last_error_t));
int sock_error;
if (esp_tls_get_and_clear_error_type(error_handle, ESP_TLS_ERR_TYPE_SYSTEM, &sock_error) == ESP_OK) {
t->error_handle->sock_errno = sock_error;
t->base->error_handle->sock_errno = sock_error;
}
}
}
void esp_transport_capture_errno(esp_transport_handle_t t, int sock_errno)
{
if (t && t->error_handle) {
t->error_handle->sock_errno = sock_errno;
if (t && t->base && t->base->error_handle) {
t->base->error_handle->sock_errno = sock_errno;
}
}

View File

@ -15,19 +15,19 @@
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_tls.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_transport.h"
#include "esp_transport_ssl.h"
#include "esp_transport_utils.h"
#include "esp_transport_ssl_internal.h"
#include "esp_transport_internal.h"
static const char *TAG = "TRANS_SSL";
#define GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t) \
transport_esp_tls_t *ssl = ssl_get_context_data(t); \
if (!ssl) { return; }
static const char *TAG = "TRANSPORT_BASE";
typedef enum {
TRANS_SSL_INIT = 0,
@ -37,20 +37,40 @@ typedef enum {
/**
* mbedtls specific transport data
*/
typedef struct {
typedef struct transport_esp_tls {
esp_tls_t *tls;
esp_tls_cfg_t cfg;
bool ssl_initialized;
transport_ssl_conn_state_t conn_state;
} transport_ssl_t;
} transport_esp_tls_t;
static inline struct transport_esp_tls * ssl_get_context_data(esp_transport_handle_t t)
{
if (!t) {
return NULL;
}
if (t->data) { // Prefer internal ssl context (independent from the list)
return (transport_esp_tls_t*)t->data;
}
if (t->base && t->base->transport_esp_tls) { // Next one is the lists inherent context
t->data = t->base->transport_esp_tls; // Optimize: if we have base context, use it as internal
return t->base->transport_esp_tls;
}
// If we don't have a valid context, let's to create one
transport_esp_tls_t *ssl = esp_transport_esp_tls_create();
ESP_TRANSPORT_MEM_CHECK(TAG, ssl, return NULL)
t->data = ssl;
return ssl;
}
static int ssl_close(esp_transport_handle_t t);
static int ssl_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
static int esp_tls_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms, bool is_plain_tcp)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
transport_esp_tls_t *ssl = ssl_get_context_data(t);
if (ssl->conn_state == TRANS_SSL_INIT) {
ssl->cfg.timeout_ms = timeout_ms;
ssl->cfg.is_plain_tcp = is_plain_tcp;
ssl->cfg.non_block = true;
ssl->ssl_initialized = true;
ssl->tls = esp_tls_init();
@ -65,11 +85,23 @@ static int ssl_connect_async(esp_transport_handle_t t, const char *host, int por
return 0;
}
static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
static inline int ssl_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
return esp_tls_connect_async(t, host, port, timeout_ms, false);
}
static inline int tcp_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
{
return esp_tls_connect_async(t, host, port, timeout_ms, true);
}
static int esp_tls_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms, bool is_plain_tcp)
{
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ssl->cfg.timeout_ms = timeout_ms;
ssl->cfg.is_plain_tcp = is_plain_tcp;
ssl->ssl_initialized = true;
ssl->tls = esp_tls_init();
if (esp_tls_conn_new_sync(host, strlen(host), port, &ssl->cfg, ssl->tls) <= 0) {
@ -79,13 +111,22 @@ static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int
ssl->tls = NULL;
return -1;
}
return 0;
}
static inline int ssl_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
{
return esp_tls_connect(t, host, port, timeout_ms, false);
}
static inline int tcp_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
{
return esp_tls_connect(t, host, port, timeout_ms, true);
}
static int ssl_poll_read(esp_transport_handle_t t, int timeout_ms)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
transport_esp_tls_t *ssl = ssl_get_context_data(t);
int ret = -1;
int remain = 0;
struct timeval timeout;
@ -114,7 +155,7 @@ static int ssl_poll_read(esp_transport_handle_t t, int timeout_ms)
static int ssl_poll_write(esp_transport_handle_t t, int timeout_ms)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
transport_esp_tls_t *ssl = ssl_get_context_data(t);
int ret = -1;
struct timeval timeout;
fd_set writeset;
@ -138,7 +179,7 @@ static int ssl_poll_write(esp_transport_handle_t t, int timeout_ms)
static int ssl_write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms)
{
int poll, ret;
transport_ssl_t *ssl = esp_transport_get_context_data(t);
transport_esp_tls_t *ssl = ssl_get_context_data(t);
if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) {
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->tls->sockfd, timeout_ms);
@ -155,7 +196,7 @@ static int ssl_write(esp_transport_handle_t t, const char *buffer, int len, int
static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms)
{
int poll, ret;
transport_ssl_t *ssl = esp_transport_get_context_data(t);
transport_esp_tls_t *ssl = ssl_get_context_data(t);
if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) {
return poll;
@ -166,6 +207,10 @@ static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout
esp_transport_set_errors(t, ssl->tls->error_handle);
}
if (ret == 0) {
if (poll > 0) {
// no error, socket reads 0 while previously detected as readable -> connection has been closed cleanly
capture_tcp_transport_error(t, ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN);
}
ret = -1;
}
return ret;
@ -174,8 +219,8 @@ static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout
static int ssl_close(esp_transport_handle_t t)
{
int ret = -1;
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (ssl->ssl_initialized) {
transport_esp_tls_t *ssl = ssl_get_context_data(t);
if (ssl && ssl->ssl_initialized) {
ret = esp_tls_conn_destroy(ssl->tls);
ssl->conn_state = TRANS_SSL_INIT;
ssl->ssl_initialized = false;
@ -185,153 +230,151 @@ static int ssl_close(esp_transport_handle_t t)
static int ssl_destroy(esp_transport_handle_t t)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
esp_transport_close(t);
free(ssl);
transport_esp_tls_t *ssl = ssl_get_context_data(t);
if (ssl) {
esp_transport_close(t);
if (t->base && t->base->transport_esp_tls &&
t->data == t->base->transport_esp_tls) {
// if internal ssl the same as the foundation transport,
// just zero out, it will be freed on list destroy
t->data = NULL;
}
esp_transport_esp_tls_destroy(t->data); // okay to pass NULL
}
return 0;
}
void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.use_global_ca_store = true;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.use_global_ca_store = true;
}
void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.psk_hint_key = psk_hint_key;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.psk_hint_key = psk_hint_key;
}
void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.cacert_pem_buf = (void *)data;
ssl->cfg.cacert_pem_bytes = len + 1;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.cacert_pem_buf = (void *)data;
ssl->cfg.cacert_pem_bytes = len + 1;
}
void esp_transport_ssl_set_cert_data_der(esp_transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.cacert_buf = (void *)data;
ssl->cfg.cacert_bytes = len;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.cacert_buf = (void *)data;
ssl->cfg.cacert_bytes = len;
}
void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.clientcert_pem_buf = (void *)data;
ssl->cfg.clientcert_pem_bytes = len + 1;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.clientcert_pem_buf = (void *)data;
ssl->cfg.clientcert_pem_bytes = len + 1;
}
void esp_transport_ssl_set_client_cert_data_der(esp_transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.clientcert_buf = (void *)data;
ssl->cfg.clientcert_bytes = len;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.clientcert_buf = (void *)data;
ssl->cfg.clientcert_bytes = len;
}
void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.clientkey_pem_buf = (void *)data;
ssl->cfg.clientkey_pem_bytes = len + 1;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.clientkey_pem_buf = (void *)data;
ssl->cfg.clientkey_pem_bytes = len + 1;
}
void esp_transport_ssl_set_client_key_password(esp_transport_handle_t t, const char *password, int password_len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.clientkey_password = (void *)password;
ssl->cfg.clientkey_password_len = password_len;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.clientkey_password = (void *)password;
ssl->cfg.clientkey_password_len = password_len;
}
void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.clientkey_buf = (void *)data;
ssl->cfg.clientkey_bytes = len;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.clientkey_buf = (void *)data;
ssl->cfg.clientkey_bytes = len;
}
void esp_transport_ssl_set_alpn_protocol(esp_transport_handle_t t, const char **alpn_protos)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.alpn_protos = alpn_protos;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.alpn_protos = alpn_protos;
}
void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.skip_common_name = true;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.skip_common_name = true;
}
void esp_transport_ssl_use_secure_element(esp_transport_handle_t t)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.use_secure_element = true;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.use_secure_element = true;
}
static int ssl_get_socket(esp_transport_handle_t t)
{
if (t) {
transport_ssl_t *ssl = t->data;
if (ssl && ssl->tls) {
return ssl->tls->sockfd;
}
transport_esp_tls_t *ssl = ssl_get_context_data(t);
if (ssl && ssl->tls) {
return ssl->tls->sockfd;
}
return -1;
}
void esp_transport_ssl_set_ds_data(esp_transport_handle_t t, void *ds_data)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.ds_data = ds_data;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.ds_data = ds_data;
}
void esp_transport_ssl_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.keep_alive_cfg = (tls_keep_alive_cfg_t *)keep_alive_cfg;
}
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
ssl->cfg.keep_alive_cfg = (tls_keep_alive_cfg_t *) keep_alive_cfg;
}
esp_transport_handle_t esp_transport_ssl_init(void)
{
esp_transport_handle_t t = esp_transport_init();
transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t));
ESP_TRANSPORT_MEM_CHECK(TAG, ssl, {
esp_transport_destroy(t);
return NULL;
});
esp_transport_set_context_data(t, ssl);
esp_transport_set_func(t, ssl_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy);
esp_transport_set_async_connect_func(t, ssl_connect_async);
t->_get_socket = ssl_get_socket;
return t;
}
struct transport_esp_tls* esp_transport_esp_tls_create(void)
{
transport_esp_tls_t *transport_esp_tls = calloc(1, sizeof(transport_esp_tls_t));
return transport_esp_tls;
}
void esp_transport_esp_tls_destroy(struct transport_esp_tls* transport_esp_tls)
{
free(transport_esp_tls);
}
esp_transport_handle_t esp_transport_tcp_init(void)
{
esp_transport_handle_t t = esp_transport_init();
esp_transport_set_func(t, tcp_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy);
esp_transport_set_async_connect_func(t, tcp_connect_async);
t->_get_socket = ssl_get_socket;
return t;
}
void esp_transport_tcp_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg)
{
return esp_transport_ssl_set_keep_alive(t, keep_alive_cfg);
}

View File

@ -1,310 +0,0 @@
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_transport_utils.h"
#include "esp_transport.h"
#include "esp_transport_internal.h"
static const char *TAG = "TRANS_TCP";
typedef struct {
int sock;
} transport_tcp_t;
static int resolve_dns(const char *host, struct sockaddr_in *ip)
{
const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res;
int err = getaddrinfo(host, NULL, &hints, &res);
if(err != 0 || res == NULL) {
ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
return ESP_FAIL;
}
ip->sin_family = AF_INET;
memcpy(&ip->sin_addr, &((struct sockaddr_in *)(res->ai_addr))->sin_addr, sizeof(ip->sin_addr));
freeaddrinfo(res);
return ESP_OK;
}
static int tcp_enable_keep_alive(int fd, esp_transport_keep_alive_t *keep_alive_cfg)
{
int keep_alive_enable = 1;
int keep_alive_idle = keep_alive_cfg->keep_alive_idle;
int keep_alive_interval = keep_alive_cfg->keep_alive_interval;
int keep_alive_count = keep_alive_cfg->keep_alive_count;
ESP_LOGD(TAG, "Enable TCP keep alive. idle: %d, interval: %d, count: %d", keep_alive_idle, keep_alive_interval, keep_alive_count);
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt SO_KEEPALIVE");
return -1;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_idle, sizeof(keep_alive_idle)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPIDLE");
return -1;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPINTVL");
return -1;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPCNT");
return -1;
}
return 0;
}
static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
{
struct sockaddr_in remote_ip;
struct timeval tv = { 0 };
transport_tcp_t *tcp = esp_transport_get_context_data(t);
bzero(&remote_ip, sizeof(struct sockaddr_in));
//if stream_host is not ip address, resolve it AF_INET,servername,&serveraddr.sin_addr
if (inet_pton(AF_INET, host, &remote_ip.sin_addr) != 1) {
if (resolve_dns(host, &remote_ip) < 0) {
return -1;
}
}
tcp->sock = socket(PF_INET, SOCK_STREAM, 0);
if (tcp->sock < 0) {
ESP_LOGE(TAG, "Error create socket");
return -1;
}
remote_ip.sin_family = AF_INET;
remote_ip.sin_port = htons(port);
esp_transport_utils_ms_to_timeval(timeout_ms, &tv); // if timeout=-1, tv is unchanged, 0, i.e. waits forever
setsockopt(tcp->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
setsockopt(tcp->sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
// Set socket keep-alive option
if (t->keep_alive_cfg && t->keep_alive_cfg->keep_alive_enable) {
if (tcp_enable_keep_alive(tcp->sock, t->keep_alive_cfg) < 0) {
ESP_LOGE(TAG, "Error to set tcp [socket=%d] keep-alive", tcp->sock);
goto error;
}
}
// Set socket to non-blocking
int flags;
if ((flags = fcntl(tcp->sock, F_GETFL, NULL)) < 0) {
ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", tcp->sock, strerror(errno));
goto error;
}
if (fcntl(tcp->sock, F_SETFL, flags |= O_NONBLOCK) < 0) {
ESP_LOGE(TAG, "[sock=%d] set nonblocking error: %s", tcp->sock, strerror(errno));
goto error;
}
ESP_LOGD(TAG, "[sock=%d] Connecting to server. IP: %s, Port: %d",
tcp->sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port);
if (connect(tcp->sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) < 0) {
if (errno == EINPROGRESS) {
fd_set fdset;
esp_transport_utils_ms_to_timeval(timeout_ms, &tv);
FD_ZERO(&fdset);
FD_SET(tcp->sock, &fdset);
int res = select(tcp->sock+1, NULL, &fdset, NULL, &tv);
if (res < 0) {
ESP_LOGE(TAG, "[sock=%d] select() error: %s", tcp->sock, strerror(errno));
esp_transport_capture_errno(t, errno);
goto error;
}
else if (res == 0) {
ESP_LOGE(TAG, "[sock=%d] select() timeout", tcp->sock);
esp_transport_capture_errno(t, EINPROGRESS); // errno=EINPROGRESS indicates connection timeout
goto error;
} else {
int sockerr;
socklen_t len = (socklen_t)sizeof(int);
if (getsockopt(tcp->sock, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
ESP_LOGE(TAG, "[sock=%d] getsockopt() error: %s", tcp->sock, strerror(errno));
goto error;
}
else if (sockerr) {
esp_transport_capture_errno(t, sockerr);
ESP_LOGE(TAG, "[sock=%d] delayed connect error: %s", tcp->sock, strerror(sockerr));
goto error;
}
}
} else {
ESP_LOGE(TAG, "[sock=%d] connect() error: %s", tcp->sock, strerror(errno));
goto error;
}
}
// Reset socket to blocking
if ((flags = fcntl(tcp->sock, F_GETFL, NULL)) < 0) {
ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", tcp->sock, strerror(errno));
goto error;
}
if (fcntl(tcp->sock, F_SETFL, flags & ~O_NONBLOCK) < 0) {
ESP_LOGE(TAG, "[sock=%d] reset blocking error: %s", tcp->sock, strerror(errno));
goto error;
}
return tcp->sock;
error:
close(tcp->sock);
tcp->sock = -1;
return -1;
}
static int tcp_write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms)
{
int poll;
transport_tcp_t *tcp = esp_transport_get_context_data(t);
if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) {
return poll;
}
return write(tcp->sock, buffer, len);
}
static int tcp_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms)
{
transport_tcp_t *tcp = esp_transport_get_context_data(t);
int poll = -1;
if ((poll = esp_transport_poll_read(t, timeout_ms)) <= 0) {
return poll;
}
int read_len = read(tcp->sock, buffer, len);
if (read_len == 0) {
return -1;
}
return read_len;
}
static int tcp_poll_read(esp_transport_handle_t t, int timeout_ms)
{
transport_tcp_t *tcp = esp_transport_get_context_data(t);
int ret = -1;
struct timeval timeout;
fd_set readset;
fd_set errset;
FD_ZERO(&readset);
FD_ZERO(&errset);
FD_SET(tcp->sock, &readset);
FD_SET(tcp->sock, &errset);
ret = select(tcp->sock + 1, &readset, NULL, &errset, esp_transport_utils_ms_to_timeval(timeout_ms, &timeout));
if (ret > 0 && FD_ISSET(tcp->sock, &errset)) {
int sock_errno = 0;
uint32_t optlen = sizeof(sock_errno);
getsockopt(tcp->sock, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
esp_transport_capture_errno(t, sock_errno);
ESP_LOGE(TAG, "tcp_poll_read select error %d, errno = %s, fd = %d", sock_errno, strerror(sock_errno), tcp->sock);
ret = -1;
}
return ret;
}
static int tcp_poll_write(esp_transport_handle_t t, int timeout_ms)
{
transport_tcp_t *tcp = esp_transport_get_context_data(t);
int ret = -1;
struct timeval timeout;
fd_set writeset;
fd_set errset;
FD_ZERO(&writeset);
FD_ZERO(&errset);
FD_SET(tcp->sock, &writeset);
FD_SET(tcp->sock, &errset);
ret = select(tcp->sock + 1, NULL, &writeset, &errset, esp_transport_utils_ms_to_timeval(timeout_ms, &timeout));
if (ret > 0 && FD_ISSET(tcp->sock, &errset)) {
int sock_errno = 0;
uint32_t optlen = sizeof(sock_errno);
getsockopt(tcp->sock, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
esp_transport_capture_errno(t, sock_errno);
ESP_LOGE(TAG, "tcp_poll_write select error %d, errno = %s, fd = %d", sock_errno, strerror(sock_errno), tcp->sock);
ret = -1;
}
return ret;
}
static int tcp_close(esp_transport_handle_t t)
{
transport_tcp_t *tcp = esp_transport_get_context_data(t);
int ret = -1;
if (tcp->sock >= 0) {
ret = close(tcp->sock);
tcp->sock = -1;
}
return ret;
}
static esp_err_t tcp_destroy(esp_transport_handle_t t)
{
transport_tcp_t *tcp = esp_transport_get_context_data(t);
esp_transport_close(t);
free(tcp);
return 0;
}
static int tcp_get_socket(esp_transport_handle_t t)
{
if (t) {
transport_tcp_t *tcp = t->data;
if (tcp) {
return tcp->sock;
}
}
return -1;
}
void esp_transport_tcp_set_keep_alive(esp_transport_handle_t t, esp_transport_keep_alive_t *keep_alive_cfg)
{
if (t && keep_alive_cfg) {
t->keep_alive_cfg = keep_alive_cfg;
}
}
esp_transport_handle_t esp_transport_tcp_init(void)
{
esp_transport_handle_t t = esp_transport_init();
transport_tcp_t *tcp = calloc(1, sizeof(transport_tcp_t));
ESP_TRANSPORT_MEM_CHECK(TAG, tcp, {
esp_transport_destroy(t);
return NULL;
});
tcp->sock = -1;
esp_transport_set_func(t, tcp_connect, tcp_read, tcp_write, tcp_close, tcp_poll_read, tcp_poll_write, tcp_destroy);
esp_transport_set_context_data(t, tcp);
t->_get_socket = tcp_get_socket;
return t;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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')

View File

@ -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);

View File

@ -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);