diff options
author | Daniel Stenberg <daniel@haxx.se> | 2020-06-15 16:17:55 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2020-06-18 00:20:42 +0200 |
commit | dc90f510657875a95d8f82def2c1e79c7284c9dc (patch) | |
tree | 432a53fd7aec4d10e9b7ba79b872cb626c9c143c /lib/connect.c | |
parent | 325866fd6fdd80fa582dce5a1acb4a88ce51f5c1 (diff) | |
download | curl-dc90f510657875a95d8f82def2c1e79c7284c9dc.tar.gz |
connect: improve happy eyeballs handling
For QUIC but also for regular TCP when the second family runs out of IPs
with a failure while the first family is still trying to connect.
Separated the timeout handling for IPv4 and IPv6 connections when they
both have a number of addresses to iterate over.
Diffstat (limited to 'lib/connect.c')
-rw-r--r-- | lib/connect.c | 79 |
1 files changed, 40 insertions, 39 deletions
diff --git a/lib/connect.c b/lib/connect.c index 46c285537..29293f087 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -560,7 +560,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) to the correct family */ static struct Curl_addrinfo *ainext(struct connectdata *conn, int tempindex, - bool next) /* use current or next entry */ + bool next) /* use next entry? */ { struct Curl_addrinfo *ai = conn->tempaddr[tempindex]; if(ai && next) @@ -571,7 +571,7 @@ static struct Curl_addrinfo *ainext(struct connectdata *conn, return ai; } -/* Used within the multi interface. Try next IP address, return TRUE if no +/* Used within the multi interface. Try next IP address, returns error if no more address exists or error */ static CURLcode trynextip(struct connectdata *conn, int sockindex, @@ -823,8 +823,8 @@ CURLcode Curl_is_connected(struct connectdata *conn, timediff_t allow; int error = 0; struct curltime now; - int rc; - int i; + int rc = 0; + unsigned int i; DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); @@ -859,49 +859,42 @@ CURLcode Curl_is_connected(struct connectdata *conn, const int other = i ^ 1; if(conn->tempsock[i] == CURL_SOCKET_BAD) continue; - + error = 0; #ifdef ENABLE_QUIC if(conn->transport == TRNSPRT_QUIC) { result = Curl_quic_is_connected(conn, i, connected); - if(result) { - error = SOCKERRNO; - goto error; - } - if(*connected) { + if(!result && *connected) { /* use this socket from now on */ conn->sock[sockindex] = conn->tempsock[i]; conn->ip_addr = conn->tempaddr[i]; conn->tempsock[i] = CURL_SOCKET_BAD; post_SOCKS(conn, sockindex, connected); connkeep(conn, "HTTP/3 default"); - return result; - } - /* should we try another protocol family? */ - if(i == 0 && !conn->bits.parallel_connect && - (Curl_timediff(now, conn->connecttime) >= - data->set.happy_eyeballs_timeout)) { - conn->bits.parallel_connect = TRUE; /* starting now */ - trynextip(conn, sockindex, 1); + return CURLE_OK; } - continue; + if(result) + error = SOCKERRNO; } + else #endif - + { #ifdef mpeix - /* Call this function once now, and ignore the results. We do this to - "clear" the error state on the socket so that we can later read it - reliably. This is reported necessary on the MPE/iX operating system. */ - (void)verifyconnect(conn->tempsock[i], NULL); + /* Call this function once now, and ignore the results. We do this to + "clear" the error state on the socket so that we can later read it + reliably. This is reported necessary on the MPE/iX operating + system. */ + (void)verifyconnect(conn->tempsock[i], NULL); #endif - /* check socket for connect */ - rc = SOCKET_WRITABLE(conn->tempsock[i], 0); + /* check socket for connect */ + rc = SOCKET_WRITABLE(conn->tempsock[i], 0); + } if(rc == 0) { /* no connection yet */ - error = 0; - if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) { + if(Curl_timediff(now, conn->connecttime) >= + conn->timeoutms_per_addr[i]) { infof(data, "After %" CURL_FORMAT_TIMEDIFF_T - "ms connect time, move on!\n", conn->timeoutms_per_addr); + "ms connect time, move on!\n", conn->timeoutms_per_addr[i]); error = ETIMEDOUT; } @@ -946,9 +939,6 @@ CURLcode Curl_is_connected(struct connectdata *conn, else if(rc & CURL_CSELECT_ERR) (void)verifyconnect(conn->tempsock[i], &error); -#ifdef ENABLE_QUIC - error: -#endif /* * The connection failed here, we should attempt to connect to the "next * address" for the given host. But first remember the latest error. @@ -968,7 +958,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, Curl_strerror(error, buffer, sizeof(buffer))); #endif - conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? + conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ? allow : allow / 2; ainext(conn, i, TRUE); status = trynextip(conn, sockindex, i); @@ -980,13 +970,15 @@ CURLcode Curl_is_connected(struct connectdata *conn, } } - if(result) { + if(result && + (conn->tempsock[0] == CURL_SOCKET_BAD) && + (conn->tempsock[1] == CURL_SOCKET_BAD)) { /* no more addresses to try */ const char *hostname; char buffer[STRERROR_LEN]; - /* if the first address family runs out of addresses to try before - the happy eyeball timeout, go ahead and try the next family now */ + /* if the first address family runs out of addresses to try before the + happy eyeball timeout, go ahead and try the next family now */ result = trynextip(conn, sockindex, 1); if(!result) return result; @@ -1007,6 +999,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, hostname, conn->port, Curl_strerror(error, buffer, sizeof(buffer))); + Curl_quic_disconnect(conn, 0); + Curl_quic_disconnect(conn, 1); + #ifdef WSAETIMEDOUT if(WSAETIMEDOUT == data->state.os_errno) result = CURLE_OPERATION_TIMEDOUT; @@ -1015,6 +1010,8 @@ CURLcode Curl_is_connected(struct connectdata *conn, result = CURLE_OPERATION_TIMEDOUT; #endif } + else + result = CURLE_OK; /* still trying */ return result; } @@ -1206,8 +1203,10 @@ static CURLcode singleipconnect(struct connectdata *conn, (void)curlx_nonblock(sockfd, TRUE); conn->connecttime = Curl_now(); - if(conn->num_addr > 1) - Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME); + if(conn->num_addr > 1) { + Curl_expire(data, conn->timeoutms_per_addr[0], EXPIRE_DNS_PER_NAME); + Curl_expire(data, conn->timeoutms_per_addr[1], EXPIRE_DNS_PER_NAME2); + } /* Connect TCP and QUIC sockets */ if(!isconnected && (conn->transport != TRNSPRT_UDP)) { @@ -1330,8 +1329,10 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ conn->tempsock[0] = conn->tempsock[1] = CURL_SOCKET_BAD; /* Max time for the next connection attempt */ - conn->timeoutms_per_addr = + conn->timeoutms_per_addr[0] = conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2; + conn->timeoutms_per_addr[1] = + conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2; conn->tempfamily[0] = conn->tempaddr[0]? conn->tempaddr[0]->ai_family:0; |