Hi All,

Working with IPv6-enabled dual-stack libcurl, I noticed that for some Linux 
kernel configurations, it takes ~15-30ms more for dual-stack libcurl to 
establish IPv4 connections than for IPv4 single-stack libcurl.
After looking into this issue, it turned out that the regression was caused by 
Curl_ipv6works() function enabled in IPv6-on builds.

This function is called on every multi handle initialization and it uses 
successful IPv6 socket creation call as an indicator that IPv6 actually works 
on the system.
And in some cases, it takes ~15-30ms for IPv6 socket creation to fail, thus 
creating IPv4 connection delay.

I propose to define a global callback which libcurl client application can use 
to tell libcurl whether IPv6 works on the system or not - thus allowing to 
eliminate delays caused by failed IPv6 socket creations.
And client app can set this callback in a special flavor of 
curl_global_init_xxx() function (i.e. curl_global_init_ipv6()) similar to 
curl_global_init_mem().

So, the prototype may look like:

/*
* callback function for checking if IPv6 is enabled on the system or
* for the application.
*
*/
typedef enum {
  CURLIPV6_NO = 0, /* ipv6 is disabled and shouldn't be used. */
  CURLIPV6_YES,    /* ipv6 is enabled and can be used. */
  CURLIPV6_AUTO    /* use default libcurl mechanism to detect if IPv6 works */
} CURLipv6;

typedef CURLipv6(*curl_ipv6works_callback)();

/*
* NAME curl_global_init_ipv6()
*
* DESCRIPTION
*
* curl_global_init() or curl_global_init_ipv6() should be invoked exactly once
* for each application that uses libcurl.  This function can be used to
* initialize libcurl and set user defined callback checking if IPv6 works
* on the system.
* Users can implement IPv6 checking routines to tell libcurl if it can use
* IPv6 in its transfers.
*/

CURL_EXTERN CURLcode curl_global_init_ipv6(long flags,
  curl_ipv6works_callback ipv6_works_cb);

This approach is flexible enough to allow clients to specify special conditions 
where they know when they do or don't want to use IPv6 with conditions where 
they want to rely on libcurl default mechanism.

Example:
CURLipv6 check_ipv6() {
    if (client_disables_ipv6)   // We know that IPv6 doesn't work here.
       return CURLipv6::CURLIPV6_NO;

    // Use default check when we are not sure if IPv6 works or not.
    return CURLipv6::CURLIPV6_AUTO;
}

// Init libcurl  with "IPv6 works" callback.
curl_global_init_ipv6(CURL_GLOBAL_ALL, check_ipv6);

I am also attaching a patch file implementing this approach in libcurl.

Thanks,
Dmitry Karpov

Attachment: curl_global_init_ipv6-global-function.patch
Description: curl_global_init_ipv6-global-function.patch

-- 
Unsubscribe: https://lists.haxx.se/listinfo/curl-library
Etiquette:   https://curl.se/mail/etiquette.html

Reply via email to