curl / Mailing Lists / curl-library / Single Mail
Buy commercial curl support from WolfSSL. We help you work out your issues, debug your libcurl applications, use the API, port to new platforms, add new features and more. With a team lead by the curl founder himself.

RE: Connection takes too long in dual-stack if IPv6 starting family is not available or blocked and has multiple addresses.

From: Daniel Stenberg via curl-library <curl-library_at_cool.haxx.se>
Date: Mon, 7 Jun 2021 13:36:00 +0200 (CEST)

On Fri, 4 Jun 2021, Dmitry Karpov wrote:

(I've put the CC back to the libcurl list to allow everyone to participate)

> Initially, I also had the same idea to use happy eyeballs timeout to cover
> cases of connection socket errors, but with host resolutions having multiple
> IPv6 addresses, it was really a waste of time to try next addresses of the
> failed family knowing that they would definitely fail. I think that in the
> current state, when Curl tries family addresses sequentially, happy eyeball
> timeout should be applied only for "good" connections that don't issue
> socket errors, and socket errors should be probably treated as a "family
> failure".

Hm, what if we also consider the first *error* on IPv6 as a signal to kick off
the IPv4 connect in addition to the timeout? See updated patch below.

> If Curl tried parallel connections for all addresses inside the family
> instead of doing it sequentially, then the idea to apply happy eyeballs
> timeout to the socket errors would work very well. Parallel connections
> would allow to fail the family much faster if something was wrong with it,
> and this would also be beneficial because the client would get the fastest
> connection inside the family - which is nice.

Yes, and I'm not against trying this out - this idea has been mentioned before
in HTTP implementor "circles". I would however imagine that it would need to
be capped at some value because some names will return MANY addresses so this
could be rather excessive, which could become a problem for apps who fire up
many transfers at once.

--- patch proposal v2

diff --git a/lib/connect.c b/lib/connect.c
index d9317f378..76e9d50dd 100644
--- a/lib/connect.c
+++ b/lib/connect.c
_at__at_ -931,18 +931,10 _at__at_ CURLcode Curl_is_connected(struct Curl_easy *data,
           conn->timeoutms_per_addr[i]) {
          infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
                "ms connect time, move on!\n", conn->timeoutms_per_addr[i]);
          error = ETIMEDOUT;
        }
-
- /* 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(data, conn, sockindex, 1);
- }
      }
      else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
        if(verifyconnect(conn->tempsock[i], &error)) {
          /* we are connected with TCP, awesome! */

_at__at_ -1002,10 +994,20 _at__at_ CURLcode Curl_is_connected(struct Curl_easy *data,
             conn->tempsock[other] == CURL_SOCKET_BAD)
            /* the last attempt failed and no other sockets remain open */
            result = status;
        }
      }
+
+ if(!rc || error) {
+ /* should we try another protocol family? */
+ if(i == 0 && !conn->bits.parallel_connect &&
+ (error || (Curl_timediff(now, conn->connecttime) >=
+ data->set.happy_eyeballs_timeout))) {
+ conn->bits.parallel_connect = TRUE; /* starting now */
+ trynextip(data, conn, sockindex, 1);
+ }
+ }
    }

    if(result &&
       (conn->tempsock[0] == CURL_SOCKET_BAD) &&
       (conn->tempsock[1] == CURL_SOCKET_BAD)) {


-- 
  / daniel.haxx.se
-------------------------------------------------------------------
Unsubscribe: https://cool.haxx.se/list/listinfo/curl-library
Etiquette:   https://curl.se/mail/etiquette.html
Received on 2021-06-07