]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tcpkeepalive: add CURLOPT_TCP_KEEPCNT and --keepalive-cnt
authorAndy Pan <i@andypan.me>
Wed, 5 Jun 2024 03:30:16 +0000 (11:30 +0800)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 12 Jun 2024 07:31:17 +0000 (09:31 +0200)
Closes #13885

25 files changed:
docs/cmdline-opts/Makefile.inc
docs/cmdline-opts/keepalive-cnt.md [new file with mode: 0644]
docs/cmdline-opts/keepalive-time.md
docs/cmdline-opts/no-keepalive.md
docs/examples/keepalive.c
docs/libcurl/curl_easy_setopt.md
docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md
docs/libcurl/opts/CURLOPT_TCP_KEEPCNT.md [new file with mode: 0644]
docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md
docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md
docs/libcurl/opts/CURLOPT_TCP_NODELAY.md
docs/libcurl/opts/Makefile.inc
docs/libcurl/symbols-in-versions
docs/options-in-versions
include/curl/curl.h
lib/cf-socket.c
lib/easyoptions.c
lib/setopt.c
lib/url.c
lib/urldata.h
src/tool_cfgable.h
src/tool_getparam.c
src/tool_listhelp.c
src/tool_operate.c
tests/http/clients/upload-pausing.c

index 087e05c7cf809afe334e59338f6772930c9e81a1..d69635e4950966646024e1066f06236ae00e3f79 100644 (file)
@@ -142,6 +142,7 @@ DPAGES = \
   ipv6.md \
   json.md \
   junk-session-cookies.md \
+  keepalive-cnt.md \
   keepalive-time.md \
   key-type.md \
   key.md \
diff --git a/docs/cmdline-opts/keepalive-cnt.md b/docs/cmdline-opts/keepalive-cnt.md
new file mode 100644 (file)
index 0000000..0846db3
--- /dev/null
@@ -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.
index 7116bcdd919e577d87b0fba4d1b105b86ee70ac6..5fd7ab4b8c1a8e54cf3cda338f42c0908a7cf3bd 100644 (file)
@@ -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.
index 1829e8c4e44888e845a3eaa5a473be9cc3252fa5..2c2115fe092bc613f69557abe95e9fc4ded73e35 100644 (file)
@@ -8,6 +8,7 @@ Added: 7.18.0
 Multi: boolean
 See-also:
   - keepalive-time
+  - keepalive-cnt
 Example:
   - --no-keepalive $URL
 ---
index 1c876bb1f52c8eb5609b4afd6299ae4d39f2c618..e06d7ff37b7bba8897bab783feb758b8ac274afd 100644 (file)
@@ -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);
index b80d0b6640efb9cc9971b6cd0c90e7cafe69b3c3..e571b60cc3a2d74ca9917321d651546f53296394 100644 (file)
@@ -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)
index e9e80ac6a5d231065cddc6ba38e0e65bdfee826b..1efc6f6b79e3851b55e5bb0f45ed9f846bc2b946 100644 (file)
@@ -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);
   }
 }
diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPCNT.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPCNT.md
new file mode 100644 (file)
index 0000000..b4ba5b3
--- /dev/null
@@ -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.
index 5f8841747d859cd87219a932ce36ea5027db4733..00c24274024a354892e91939e75df838046138e1 100644 (file)
@@ -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);
   }
 }
index 405b6ec8287168940a4a826f3a69bd5c8fed8dc2..7752b34282694d948311d5e80b16ca1a67f6423e 100644 (file)
@@ -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);
   }
 }
index a5b15abbf1cb92ddbfc96200b05058a126cde614..c4c83ae54a525fa8bf2ba8a13105f6c57b0a1823 100644 (file)
@@ -9,7 +9,7 @@ See-also:
   - CURLOPT_SOCKOPTFUNCTION (3)
   - CURLOPT_TCP_KEEPALIVE (3)
 Protocol:
-  - All
+  - TCP
 ---
 
 # NAME
index bf5ea7645faac53f65a10e9de226ea8f47e352e0..f09c5863d39be6f55f2a5c5461f57b06a85c93b8 100644 (file)
@@ -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                        \
index 90ffa378b22b818710cf2a3e428506eaf8c9436c..ebf2cee2931edb71f46a4c4e5438b5444c7f4c85 100644 (file)
@@ -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
index 15f5a54dfb767e56e9046247c0edc19611d2d3ee..e329f87230a1ecc5b9a420724e5b79ee1cd78c0a 100644 (file)
 --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
index 2e57cd8446a24233223a4d924cc9a17aa1c6dcb4..45e5f4840c743ca3f1131dc4297d56962a1a4d3e 100644 (file)
@@ -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;
 
index c6d002ad0262b5e4f736b8bee64c5e24c05f37e7..f608fbe0bad2f70e2a2ca54ef5878655ab5896b1 100644 (file)
@@ -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
   }
 }
index c79d136707e4d41c23f0b90a094bdba450bdcef8..81091c405aaa5a6f4ae30ba72e091f3a1d59a3d7 100644 (file)
@@ -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
index 744479582925c0b07e365cc8e90b6a44ecead67a..188ecb27569ed0feddaa1c54a1f27fee18941276 100644 (file)
@@ -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)
index 02df5bd489ce11c82e6913ee5220d35603d2ffaa..d3dcfd38d12cbfc236e6300127a077a7a4803e58 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -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;
index 8408565186cdb50efb32367ee75094f10ce1278e..e7ce95b41c6990ab9e25566fd58f6378e1e8ee4c 100644 (file)
@@ -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)
index f0e904531a2e8f8f2515dc30b05d1b7a9a9e20ff..439f5dd510da115a57227a450e95960dd026b8d2 100644 (file)
@@ -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
index 869b8be0dae0a1e84bc8b118c3e4d386f20ba194..e0d754cf123cdca4d5ecd2d63f86b35d82c68f8a 100644 (file)
@@ -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;
index 27f49f8fa8627f1115022e0db8220d0771e22e3d..d49f0c15e79511a1e5158e866ce505e159c88b9a 100644 (file)
@@ -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},
index 6471ae4f05502ef0bb2bbf802aff37c3c04cf44c..e760e052d95a91266f15447a34859419f98cd9c9 100644 (file)
@@ -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);
index 8247e4fd9efbef1b6992684c8e0b7798ee517b76..24e4701bd2084acf9522345fe1a93de8cbafbca6 100644 (file)
@@ -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");