From 0c7204e934b8abda433026f9ec9800c5380a657d Mon Sep 17 00:00:00 2001 From: boarchuz <46267286+boarchuz@users.noreply.github.com> Date: Wed, 17 Jul 2019 18:59:07 +1000 Subject: [PATCH] tcp_transport: Implement connect timeout Merges https://github.com/espressif/esp-idf/pull/3791 Closes https://github.com/espressif/esp-idf/issues/5004 --- components/tcp_transport/transport_tcp.c | 58 +++++++++++++++++++++--- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/components/tcp_transport/transport_tcp.c b/components/tcp_transport/transport_tcp.c index 975d0e8740..6e68991a31 100644 --- a/components/tcp_transport/transport_tcp.c +++ b/components/tcp_transport/transport_tcp.c @@ -81,14 +81,60 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int setsockopt(tcp->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(tcp->sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - 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) { - close(tcp->sock); - tcp->sock = -1; - return -1; + // Set socket to non-blocking + int flags; + if ((flags = fcntl(tcp->sock, F_GETFL, NULL)) < 0 || 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)); + goto error; + } + else if (res == 0) { + ESP_LOGE(TAG, "[sock=%d] select() timeout", tcp->sock); + 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_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 || 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)