2
0
mirror of https://github.com/curl/curl.git synced 2025-04-12 16:20:35 +08:00

tcpkeepalive: add CURLOPT_TCP_KEEPCNT and --keepalive-cnt

Closes 
This commit is contained in:
Andy Pan 2024-06-05 11:30:16 +08:00 committed by Daniel Stenberg
parent 02ff5d53a8
commit b77d627d24
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
25 changed files with 210 additions and 20 deletions

@ -142,6 +142,7 @@ DPAGES = \
ipv6.md \
json.md \
junk-session-cookies.md \
keepalive-cnt.md \
keepalive-time.md \
key-type.md \
key.md \

@ -0,0 +1,27 @@
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Long: keepalive-cnt
Arg: <integer>
Help: Maximum number of keepalive probes
Added: 8.9.0
Category: connection
Multi: single
See-also:
- keepalive-time
- no-keepalive
Example:
- --keepalive-cnt 3 $URL
---
# `--keepalive-cnt`
Set the maximum number of keepalive probes TCP should send but get no response
before dropping the connection. This option is usually used in conjunction
with --keepalive-time.
This option is supported on Linux, *BSD/macOS, Windows \>=10.0.16299, Solaris
11.4, and recent AIX, HP-UX and more. This option has no effect if
--no-keepalive is used.
If unspecified, the option defaults to 9.

@ -9,6 +9,7 @@ Category: connection
Multi: single
See-also:
- no-keepalive
- keepalive-cnt
- max-time
Example:
- --keepalive-time 20 $URL
@ -22,7 +23,8 @@ operating systems offering the `TCP_KEEPIDLE` and `TCP_KEEPINTVL` socket
options (meaning Linux, *BSD/macOS, Windows, Solaris, and recent AIX, HP-UX and more).
Keepalive is used by the TCP stack to detect broken networks on idle connections.
The number of missed keepalive probes before declaring the connection down is OS
dependent and is commonly 8 (*BSD/macOS/AIX), 9 (Linux/AIX) or 5/10 (Windows).
This option has no effect if --no-keepalive is used.
dependent and is commonly 8 (*BSD/macOS/AIX), 9 (Linux/AIX) or 5/10 (Windows), and
this number can be changed by specifying the curl option `keepalive-cnt`.
Note that this option has no effect if --no-keepalive is used.
If unspecified, the option defaults to 60 seconds.

@ -8,6 +8,7 @@ Added: 7.18.0
Multi: boolean
See-also:
- keepalive-time
- keepalive-cnt
Example:
- --no-keepalive $URL
---

@ -44,6 +44,9 @@ int main(void)
/* interval time between keep-alive probes: 60 seconds */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
/* maximum number of keep-alive probes: 3 */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);
curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/");
res = curl_easy_perform(curl);

@ -417,6 +417,10 @@ Idle time before sending keep-alive. See CURLOPT_TCP_KEEPIDLE(3)
Interval between keep-alive probes. See CURLOPT_TCP_KEEPINTVL(3)
## CURLOPT_TCP_KEEPCNT
Maximum number of keep-alive probes. See CURLOPT_TCP_KEEPCNT(3)
## CURLOPT_UNIX_SOCKET_PATH
Path to a Unix domain socket. See CURLOPT_UNIX_SOCKET_PATH(3)

@ -9,8 +9,9 @@ See-also:
- CURLOPT_MAX_RECV_SPEED_LARGE (3)
- CURLOPT_TCP_KEEPIDLE (3)
- CURLOPT_TCP_KEEPINTVL (3)
- CURLOPT_TCP_KEEPCNT (3)
Protocol:
- All
- TCP
---
# NAME
@ -29,9 +30,9 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPALIVE, long probe);
Pass a long. If set to 1, TCP keepalive probes are used. The delay and
frequency of these probes can be controlled by the
CURLOPT_TCP_KEEPIDLE(3) and CURLOPT_TCP_KEEPINTVL(3) options,
provided the operating system supports them. Set to 0 (default behavior) to
disable keepalive probes
CURLOPT_TCP_KEEPIDLE(3), CURLOPT_TCP_KEEPINTVL(3), and CURLOPT_TCP_KEEPCNT(3)
options, provided the operating system supports them. Set to 0 (default behavior)
to disable keepalive probes.
# DEFAULT
@ -55,6 +56,9 @@ int main(void)
/* interval time between keep-alive probes: 60 seconds */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
/* maximum number of keep-alive probes: 3 */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);
curl_easy_perform(curl);
}
}

@ -0,0 +1,73 @@
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_KEEPCNT
Section: 3
Source: libcurl
See-also:
- CURLOPT_TCP_KEEPALIVE (3)
- CURLOPT_TCP_KEEPIDLE (3)
- CURLOPT_TCP_KEEPINTVL (3)
Protocol:
- TCP
---
# NAME
CURLOPT_TCP_KEEPCNT - Maximum number of TCP keep-alive probes
# SYNOPSIS
~~~c
#include <curl/curl.h>
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPCNT, long cnt);
~~~
# DESCRIPTION
Pass a long. Sets the number of probes to send before dropping
the connection. Not all operating systems support this option.
(Added in 8.9.0)
The maximum value this option accepts is INT_MAX or whatever your
system allows.
Any larger value is capped to this amount.
# DEFAULT
9
# EXAMPLE
~~~c
int main(void)
{
CURL *curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
/* enable TCP keep-alive for this transfer */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
/* set keep-alive idle time to 120 seconds */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
/* interval time between keep-alive probes: 60 seconds */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
/* maximum number of keep-alive probes: 3 */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);
curl_easy_perform(curl);
}
}
~~~
# AVAILABILITY
Added in v8.9.0
# RETURN VALUE
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.

@ -7,8 +7,9 @@ Source: libcurl
See-also:
- CURLOPT_TCP_KEEPALIVE (3)
- CURLOPT_TCP_KEEPINTVL (3)
- CURLOPT_TCP_KEEPCNT (3)
Protocol:
- All
- TCP
---
# NAME
@ -54,6 +55,9 @@ int main(void)
/* interval time between keep-alive probes: 60 seconds */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
/* maximum number of keep-alive probes: 3 */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);
curl_easy_perform(curl);
}
}

@ -7,8 +7,9 @@ Source: libcurl
See-also:
- CURLOPT_TCP_KEEPALIVE (3)
- CURLOPT_TCP_KEEPIDLE (3)
- CURLOPT_TCP_KEEPCNT (3)
Protocol:
- All
- TCP
---
# NAME
@ -53,6 +54,9 @@ int main(void)
/* interval time between keep-alive probes: 60 seconds */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
/* maximum number of keep-alive probes: 3 */
curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);
curl_easy_perform(curl);
}
}

@ -9,7 +9,7 @@ See-also:
- CURLOPT_SOCKOPTFUNCTION (3)
- CURLOPT_TCP_KEEPALIVE (3)
Protocol:
- All
- TCP
---
# NAME

@ -384,6 +384,7 @@ man_MANS = \
CURLOPT_TCP_KEEPALIVE.3 \
CURLOPT_TCP_KEEPIDLE.3 \
CURLOPT_TCP_KEEPINTVL.3 \
CURLOPT_TCP_KEEPCNT.3 \
CURLOPT_TCP_NODELAY.3 \
CURLOPT_TELNETOPTIONS.3 \
CURLOPT_TFTP_BLKSIZE.3 \

@ -864,6 +864,7 @@ CURLOPT_TCP_FASTOPEN 7.49.0
CURLOPT_TCP_KEEPALIVE 7.25.0
CURLOPT_TCP_KEEPIDLE 7.25.0
CURLOPT_TCP_KEEPINTVL 7.25.0
CURLOPT_TCP_KEEPCNT 8.9.0
CURLOPT_TCP_NODELAY 7.11.2
CURLOPT_TELNETOPTIONS 7.7
CURLOPT_TFTP_BLKSIZE 7.19.4

@ -107,6 +107,7 @@
--ipv6 (-6) 7.10.8
--json 7.82.0
--junk-session-cookies (-j) 7.9.7
--keepalive-cnt 8.9.0
--keepalive-time 7.18.0
--key 7.9.3
--key-type 7.9.3

@ -2218,9 +2218,12 @@ typedef enum {
/* millisecond version */
CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),
/* set ECH configuration */
/* set ECH configuration */
CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 325),
/* maximum number of keepalive probes (Linux, *BSD, macOS, etc.) */
CURLOPT(CURLOPT_TCP_KEEPCNT, CURLOPTTYPE_LONG, 326),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

@ -145,8 +145,9 @@ static void nosigpipe(struct Curl_easy *data,
#if defined(USE_WINSOCK) || \
(defined(__sun) && !defined(TCP_KEEPIDLE)) || \
(defined(__DragonFly__) && __DragonFly_version < 500702)
/* Solaris < 11.4, DragonFlyBSD < 500702 and Windows
(defined(__DragonFly__) && __DragonFly_version < 500702) || \
(defined(_WIN32) && !defined(TCP_KEEPIDLE))
/* Solaris < 11.4, DragonFlyBSD < 500702 and Windows < 10.0.16299
* use millisecond units. */
#define KEEPALIVE_FACTOR(x) (x *= 1000)
#else
@ -177,7 +178,33 @@ tcpkeepalive(struct Curl_easy *data,
sockfd, SOCKERRNO);
}
else {
#if defined(SIO_KEEPALIVE_VALS)
#if defined(SIO_KEEPALIVE_VALS) /* Windows */
/* Windows 10, version 1709 (10.0.16299) and later versions */
#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
optval = curlx_sltosi(data->set.tcp_keepidle);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
(const char *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPIDLE on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
optval = curlx_sltosi(data->set.tcp_keepintvl);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
(const char *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPINTVL on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
optval = curlx_sltosi(data->set.tcp_keepcnt);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
(const char *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPCNT on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
#else /* Windows < 10.0.16299 */
struct tcp_keepalive vals;
DWORD dummy;
vals.onoff = 1;
@ -193,7 +220,8 @@ tcpkeepalive(struct Curl_easy *data,
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
#else
#endif
#else /* !Windows */
#ifdef TCP_KEEPIDLE
optval = curlx_sltosi(data->set.tcp_keepidle);
KEEPALIVE_FACTOR(optval);
@ -238,14 +266,15 @@ tcpkeepalive(struct Curl_easy *data,
/* TCP_KEEPALIVE_ABORT_THRESHOLD should equal to
* TCP_KEEPCNT * TCP_KEEPINTVL on other platforms.
* The default value of TCP_KEEPCNT is 9 on Linux,
* 8 on *BSD/macOS, 5 or 10 on Windows. We choose
* 9 for Solaris <11.4 because there is no default
* value for TCP_KEEPCNT on Solaris 11.4.
* 8 on *BSD/macOS, 5 or 10 on Windows. We use the
* default config for Solaris <11.4 because there is
* no default value for TCP_KEEPCNT on Solaris 11.4.
*
* Note that the consequent probes will not be sent
* at equal intervals on Solaris, but will be sent
* using the exponential backoff algorithm. */
optval = 9 * curlx_sltosi(data->set.tcp_keepintvl);
optval = curlx_sltosi(data->set.tcp_keepcnt) *
curlx_sltosi(data->set.tcp_keepintvl);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
(void *)&optval, sizeof(optval)) < 0) {
@ -254,6 +283,15 @@ tcpkeepalive(struct Curl_easy *data,
sockfd, SOCKERRNO);
}
#endif
#ifdef TCP_KEEPCNT
optval = curlx_sltosi(data->set.tcp_keepcnt);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
(void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPCNT on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
#endif
#endif
}
}

@ -328,6 +328,7 @@ struct curl_easyoption Curl_easyopts[] = {
CURLOT_LONG, 0},
{"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0},
{"TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE, CURLOT_LONG, 0},
{"TCP_KEEPCNT", CURLOPT_TCP_KEEPCNT, CURLOT_LONG, 0},
{"TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE, CURLOT_LONG, 0},
{"TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL, CURLOT_LONG, 0},
{"TCP_NODELAY", CURLOPT_TCP_NODELAY, CURLOT_LONG, 0},
@ -376,6 +377,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
return ((CURLOPT_LASTENTRY%10000) != (325 + 1));
return ((CURLOPT_LASTENTRY%10000) != (326 + 1));
}
#endif

@ -2960,6 +2960,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = INT_MAX;
data->set.tcp_keepintvl = (int)arg;
break;
case CURLOPT_TCP_KEEPCNT:
arg = va_arg(param, long);
if(arg < 0)
return CURLE_BAD_FUNCTION_ARGUMENT;
else if(arg > INT_MAX)
arg = INT_MAX;
data->set.tcp_keepcnt = (int)arg;
break;
case CURLOPT_TCP_FASTOPEN:
#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \
defined(TCP_FASTOPEN_CONNECT)

@ -467,6 +467,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->tcp_keepalive = FALSE;
set->tcp_keepintvl = 60;
set->tcp_keepidle = 60;
set->tcp_keepcnt = 9;
set->tcp_fastopen = FALSE;
set->tcp_nodelay = TRUE;
set->ssl_enable_alpn = TRUE;

@ -1733,6 +1733,7 @@ struct UserDefined {
int tcp_keepidle; /* seconds in idle before sending keepalive probe */
int tcp_keepintvl; /* seconds between TCP keepalive probes */
int tcp_keepcnt; /* maximum number of keepalive probes */
long expect_100_timeout; /* in milliseconds */
#if defined(USE_HTTP2) || defined(USE_HTTP3)

@ -249,7 +249,8 @@ struct OperationConfig {
bool post302;
bool post303;
bool nokeepalive; /* for keepalive needs */
long alivetime;
long alivetime; /* keepalive-time */
long alivecnt; /* keepalive-cnt */
bool content_disposition; /* use Content-disposition filename */
int default_node_flags; /* default flags to search for each 'node', which

@ -179,6 +179,7 @@ typedef enum {
C_JSON,
C_JUNK_SESSION_COOKIES,
C_KEEPALIVE,
C_KEEPALIVE_CNT,
C_KEEPALIVE_TIME,
C_KEY,
C_KEY_TYPE,
@ -465,6 +466,7 @@ static const struct LongShort aliases[]= {
{"json", ARG_STRG, ' ', C_JSON},
{"junk-session-cookies", ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES},
{"keepalive", ARG_BOOL, ' ', C_KEEPALIVE},
{"keepalive-cnt", ARG_STRG, ' ', C_KEEPALIVE_CNT},
{"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME},
{"key", ARG_FILE, ' ', C_KEY},
{"key-type", ARG_STRG, ' ', C_KEY_TYPE},
@ -1826,6 +1828,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
case C_KEEPALIVE_TIME: /* --keepalive-time */
err = str2unum(&config->alivetime, nextarg);
break;
case C_KEEPALIVE_CNT: /* --keepalive-cnt */
err = str2unum(&config->alivecnt, nextarg);
break;
case C_POST301: /* --post301 */
config->post301 = toggle;
break;

@ -324,6 +324,9 @@ const struct helptxt helptext[] = {
{"-j, --junk-session-cookies",
"Ignore session cookies read from file",
CURLHELP_HTTP},
{" --keepalive-cnt <integer>",
"Maximum number of keepalive probes",
CURLHELP_CONNECTION},
{" --keepalive-time <seconds>",
"Interval time for keepalive probes",
CURLHELP_CONNECTION},

@ -2111,6 +2111,8 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
}
if(config->alivecnt)
my_setopt(curl, CURLOPT_TCP_KEEPCNT, config->alivecnt);
}
else
my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);

@ -241,6 +241,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 1L);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 1L);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 1L);
/* Enable uploading. */
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");