From 2c28ffffeef96dac0a96feabe3e26f81308f762e Mon Sep 17 00:00:00 2001 From: David Cermak Date: Sat, 23 Jan 2021 09:46:06 +0100 Subject: [PATCH] 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 80cbf417bed0..c2a6ad64f948 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 b2fb0c1cdda0..f3e36a22b582 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 db4afb8752ea..ad03b74a6834 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 56a26ba0762c..761efeef29db 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 f35212d2a9f6..f6ae7532796d 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 1d698ca909fa..96034c76e3ab 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 4d498e69ad27..000000000000 --- 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; -}