diff --git a/docs/cmdline-opts/Makefile.inc b/docs/cmdline-opts/Makefile.inc index 9891f3717..778149ca3 100644 --- a/docs/cmdline-opts/Makefile.inc +++ b/docs/cmdline-opts/Makefile.inc @@ -12,7 +12,9 @@ DPAGES = abstract-unix-socket.d anyauth.d append.d basic.d cacert.d capath.d cer form.d form-string.d ftp-account.d ftp-alternative-to-user.d \ ftp-create-dirs.d ftp-method.d ftp-pasv.d ftp-port.d ftp-pret.d \ ftp-skip-pasv-ip.d ftp-ssl-ccc.d ftp-ssl-ccc-mode.d ftp-ssl-control.d \ - get.d globoff.d head.d header.d help.d hostpubmd5.d http1.0.d \ + get.d globoff.d \ + happy-eyeballs-timeout-ms.d \ + head.d header.d help.d hostpubmd5.d http1.0.d \ http1.1.d http2.d http2-prior-knowledge.d ignore-content-length.d \ include.d insecure.d interface.d ipv4.d ipv6.d junk-session-cookies.d \ keepalive-time.d key.d key-type.d krb.d libcurl.d limit-rate.d \ diff --git a/docs/cmdline-opts/happy-eyeballs-timeout-ms.d b/docs/cmdline-opts/happy-eyeballs-timeout-ms.d new file mode 100644 index 000000000..ec9a8c228 --- /dev/null +++ b/docs/cmdline-opts/happy-eyeballs-timeout-ms.d @@ -0,0 +1,17 @@ +Long: happy-eyeballs-timeout-ms +Arg: +Help: How long to wait in milliseconds for IPv6 before trying IPv4 +Added: 7.59.0 +--- +Happy eyeballs is an algorithm that attempts to connect to both IPv4 and IPv6 +addresses for dual-stack hosts, preferring IPv6 first for the number of +milliseconds. If the IPv6 address cannot be connected to within that time then +a connection attempt is made to the IPv4 address in parallel. The first +connection to be established is the one that is used. + +The range of suggested useful values is limited. Happy Eyeballs RFC 6555 says +"It is RECOMMENDED that connection attempts be paced 150-250 ms apart to +balance human factors against network load." libcurl currently defaults to +200 ms. Firefox and Chrome currently default to 300 ms. + +If this option is used several times, the last one will be used. diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 0249e6bbc..72ef2886a 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -577,6 +577,8 @@ Mode for creating new remote directories. See \fICURLOPT_NEW_DIRECTORY_PERMS(3)\ .SH TELNET OPTIONS .IP CURLOPT_TELNETOPTIONS TELNET options. See \fICURLOPT_TELNETOPTIONS(3)\fP +.IP CURLOPT_HAPPY_EYEBALLS_TIMEOUT +Timeout for happy eyeballs. See \fICURLOPT_HAPPY_EYEBALLS_TIMEOUT(3)\fP .SH RETURN VALUE \fICURLE_OK\fP (zero) means that the option was set properly, non-zero means an error occurred as \fI\fP defines. See the \fIlibcurl-errors(3)\fP diff --git a/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT.3 b/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT.3 new file mode 100644 index 000000000..d4fa1505b --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT.3 @@ -0,0 +1,59 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_HAPPY_EYEBALLS_TIMEOUT 3 "1 Feb 2018" "libcurl 7.59.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_HAPPY_EYEBALLS_TIMEOUT \- head start for ipv6 for happy eyeballs +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HAPPY_EYEBALLS_TIMEOUT, long timeout); +.SH DESCRIPTION +Happy eyeballs is an algorithm that attempts to connect to both IPv4 and IPv6 +addresses for dual-stack hosts, preferring IPv6 first for \fItimeout\fP +milliseconds. If the IPv6 address cannot be connected to within that time then +a connection attempt is made to the IPv4 address in parallel. The first +connection to be established is the one that is used. + +The range of suggested useful values for \fItimeout\fP is limited. Happy +Eyeballs RFC 6555 says "It is RECOMMENDED that connection attempts be paced +150-250 ms apart to balance human factors against network load." libcurl +currently defaults to 200 ms. Firefox and Chrome currently default to 300 ms. +.SH DEFAULT +CURL_HET_DEFAULT (currently defined as 200L) +.SH EXAMPLE +.nf +CURL *curl = curl_easy_init(); +if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT, 300L); + + curl_easy_perform(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); +} +.fi +.SH AVAILABILITY +Added in 7.59.0 +.SH RETURN VALUE +Returns CURLE_OK diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc index 22a54c399..d0597500a 100644 --- a/docs/libcurl/opts/Makefile.inc +++ b/docs/libcurl/opts/Makefile.inc @@ -136,6 +136,7 @@ man_MANS = \ CURLOPT_FTP_USE_EPSV.3 \ CURLOPT_FTP_USE_PRET.3 \ CURLOPT_GSSAPI_DELEGATION.3 \ + CURLOPT_HAPPY_EYEBALLS_TIMEOUT.3 \ CURLOPT_HEADER.3 \ CURLOPT_HEADERDATA.3 \ CURLOPT_HEADERFUNCTION.3 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index ac3dadee3..44f111b05 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -403,6 +403,7 @@ CURLOPT_FTP_USE_EPRT 7.10.5 CURLOPT_FTP_USE_EPSV 7.9.2 CURLOPT_FTP_USE_PRET 7.20.0 CURLOPT_GSSAPI_DELEGATION 7.22.0 +CURLOPT_HAPPY_EYEBALLS_TIMEOUT 7.59.0 CURLOPT_HEADER 7.1 CURLOPT_HEADERDATA 7.10 CURLOPT_HEADERFUNCTION 7.7.2 @@ -741,6 +742,7 @@ CURL_GLOBAL_DEFAULT 7.8 CURL_GLOBAL_NOTHING 7.8 CURL_GLOBAL_SSL 7.8 CURL_GLOBAL_WIN32 7.8.1 +CURL_HET_DEFAULT 7.59.0 CURL_HTTPPOST_BUFFER 7.46.0 CURL_HTTPPOST_CALLBACK 7.46.0 CURL_HTTPPOST_FILENAME 7.46.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index 7cab0a16c..a592a0e4d 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -791,6 +791,11 @@ typedef enum { SSL backends where such behavior is present. */ #define CURLSSLOPT_NO_REVOKE (1<<1) +/* The default connection attempt delay in milliseconds for happy eyeballs. + CURLOPT_HAPPY_EYEBALLS_TIMEOUT.3 and happy-eyeballs-timeout-ms.d document + this value, keep them in sync. */ +#define CURL_HET_DEFAULT 200L + #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ @@ -1825,6 +1830,9 @@ typedef enum { seconds since 1 Jan 1970. */ CINIT(TIMEVALUE_LARGE, OFF_T, 270), + /* Head start in milliseconds to give happy eyeballs. */ + CINIT(HAPPY_EYEBALLS_TIMEOUT, LONG, 271), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/connect.c b/lib/connect.c index c3add43cc..1a27ae135 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -783,7 +783,8 @@ CURLcode Curl_is_connected(struct connectdata *conn, /* should we try another protocol family? */ if(i == 0 && conn->tempaddr[1] == NULL && - Curl_timediff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) { + (Curl_timediff(now, conn->connecttime) >= + data->set.happy_eyeballs_timeout)) { trynextip(conn, sockindex, 1); } } @@ -1206,7 +1207,8 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ } data->info.numconnects++; /* to track the number of connections made */ - Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS); + Curl_expire(conn->data, data->set.happy_eyeballs_timeout, + EXPIRE_HAPPY_EYEBALLS); return CURLE_OK; } diff --git a/lib/connect.h b/lib/connect.h index 4c038874e..193dc6397 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -41,8 +41,6 @@ timediff_t Curl_timeleft(struct Curl_easy *data, bool duringconnect); #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ -#define HAPPY_EYEBALLS_TIMEOUT 200 /* milliseconds to wait between - IPv4/IPv6 connection attempts */ /* * Used to extract socket and connectdata struct for the most recent diff --git a/lib/setopt.c b/lib/setopt.c index 69f98a64d..f03e6d5fa 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2533,6 +2533,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, case CURLOPT_SSH_COMPRESSION: data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE; break; + case CURLOPT_HAPPY_EYEBALLS_TIMEOUT: + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.happy_eyeballs_timeout = arg; + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; diff --git a/lib/url.c b/lib/url.c index 74813e874..90afd03a6 100644 --- a/lib/url.c +++ b/lib/url.c @@ -527,6 +527,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->expect_100_timeout = 1000L; /* Wait for a second by default. */ set->sep_headers = TRUE; /* separated header lists by default */ set->buffer_size = READBUFFER_SIZE; + set->happy_eyeballs_timeout = CURL_HET_DEFAULT; Curl_http2_init_userset(set); return result; diff --git a/lib/urldata.h b/lib/urldata.h index 6c594fe8d..35014c232 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1520,6 +1520,7 @@ struct UserDefined { long timeout; /* in milliseconds, 0 means no timeout */ long connecttimeout; /* in milliseconds, 0 means no timeout */ long accepttimeout; /* in milliseconds, 0 means no timeout */ + long happy_eyeballs_timeout; /* in milliseconds, 0 is a valid value */ long server_response_timeout; /* in milliseconds, 0 means no timeout */ long tftp_blksize; /* in bytes, 0 means use default */ bool tftp_no_options; /* do not send TFTP options requests */ diff --git a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in index 03603e290..1b2996894 100644 --- a/packages/OS400/curl.inc.in +++ b/packages/OS400/curl.inc.in @@ -1322,6 +1322,10 @@ d c 00268 d CURLOPT_MIMEPOST... d c 10269 + d CURLOPT_TIMEVALUE_LARGE... + d c 30270 + d CURLOPT_HAPPY_EYEBALLS_TIMEOUT... + d c 00271 * /if not defined(CURL_NO_OLDIES) d CURLOPT_FILE c 10001 diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index d77488166..81e16c1c8 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -42,6 +42,7 @@ void config_init(struct OperationConfig* config) config->proto_redir_present = FALSE; config->proto_default = NULL; config->tcp_nodelay = TRUE; /* enabled by default */ + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT; } static void free_config_fields(struct OperationConfig *config) diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 0f316775d..743ce725d 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -250,6 +250,8 @@ struct OperationConfig { curl_error synthetic_error; /* if non-zero, it overrides any libcurl error */ bool ssh_compression; /* enable/disable SSH compression */ + long happy_eyeballs_timeout_ms; /* happy eyeballs timeout in milliseconds. + 0 is valid. default: CURL_HET_DEFAULT. */ struct GlobalConfig *global; struct OperationConfig *prev; struct OperationConfig *next; /* Always last in the struct */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 46e7dd3cd..c6b1a0d6f 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -190,6 +190,7 @@ static const struct LongShort aliases[]= { {"$X", "tls-max", ARG_STRING}, {"$Y", "suppress-connect-headers", ARG_BOOL}, {"$Z", "compressed-ssh", ARG_BOOL}, + {"$~", "happy-eyeballs-timeout-ms", ARG_STRING}, {"0", "http1.0", ARG_NONE}, {"01", "http1.1", ARG_NONE}, {"02", "http2", ARG_NONE}, @@ -1111,6 +1112,12 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ case 'Z': /* --compressed-ssh */ config->ssh_compression = toggle; break; + case '~': /* --happy-eyeballs-timeout-ms */ + err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg); + if(err) + return err; + /* 0 is a valid value for this timeout */ + break; } break; case '#': /* --progress-bar */ diff --git a/src/tool_help.c b/src/tool_help.c index 751b43aca..9796b7e87 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -160,6 +160,8 @@ static const struct helptxt helptext[] = { "Put the post data in the URL and use GET"}, {"-g, --globoff", "Disable URL sequences and ranges using {} and []"}, + {" --happy-eyeballs-timeout-ms", + "How long to wait in milliseconds for IPv6 before trying IPv4"}, {"-I, --head", "Show document info only"}, {"-H, --header
", diff --git a/src/tool_operate.c b/src/tool_operate.c index f326a0d0c..c8e9c6901 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1440,6 +1440,11 @@ static CURLcode operate_do(struct GlobalConfig *global, if(config->tftp_no_options) my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L); + /* new in 7.59.0 */ + if(config->happy_eyeballs_timeout_ms != CURL_HET_DEFAULT) + my_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT, + config->happy_eyeballs_timeout_ms); + /* initialize retry vars for loop below */ retry_sleep_default = (config->retry_delay) ? config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */