cURL / Mailing Lists / curl-library / Single Mail

curl-library

[PATCH 1/2] add library support for tuning TCP_KEEPALIVE

From: Dave Reisner <d_at_falconindy.com>
Date: Tue, 24 Jan 2012 00:41:27 -0500

This adds three new options to control the behavior of TCP keepalives:

- CURLOPT_TCP_KEEPALIVE: enable/disable probes
- CURLOPT_TCP_KEEPIDLE: idle time before sending first probe
- CURLOPT_TCP_KEEPINTVL: delay between successive probes

While not all operating systems support the TCP_KEEPIDLE and
TCP_KEEPINTVL knobs, the library will still allow these options to be
set by clients, silently ignoring the values.

---
Playing the role of the optimist and labelling this work for 7.24.1. This is
mostly the result of a conversation I had with Daniel regarding usage of
keepalives to thwart control connections to FTP servers being killed off by
firewalls. The code is more or less copied from the front end tool, with all
the bells and whistles added to wire it up for accessibility via
curl_easy_setopt.
 docs/libcurl/curl_easy_setopt.3  |   18 ++++++++++++++++++
 docs/libcurl/symbols-in-versions |    3 +++
 include/curl/curl.h              |    7 +++++++
 lib/connect.c                    |   32 ++++++++++++++++++++++++++++++++
 lib/url.c                        |   20 ++++++++++++++++++++
 lib/urldata.h                    |    4 ++++
 6 files changed, 84 insertions(+), 0 deletions(-)
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index 1a20cb9..0a4fef3 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -915,6 +915,24 @@ overdone.
 .IP CURLOPT_ADDRESS_SCOPE
 Pass a long specifying the scope_id value to use when connecting to IPv6
 link-local or site-local addresses. (Added in 7.19.0)
+
+.IP CURLOPT_TCP_KEEPALIVE
+Pass a long. If set to 1, TCP keepalive probes will be sent. The delay and
+frequency of these probes can be controlled by the \fICURLOPT_TCP_KEEPIDLE\fP
+and \fICURLOPT_TCP_KEEPINTVL\fP options, provided the operating system supports
+them. Set to 0 (default behavior) to disable keepalive probes (Added in
+7.24.1).
+
+.IP CURLOPT_TCP_KEEPIDLE
+Pass a long. Sets the delay, in seconds, that the operating system will wait
+while the connection is idle before sending keepalive probes. Not all operating
+systems support this option. (Added in 7.24.1)
+
+.IP CURLOPT_TCP_KEEPINTVL
+Pass a long. Sets the interval, in seconds, that the operating system will wait
+between sending keepalive probes. Not all operating systems support this
+option. (Added in 7.24.1)
+
 .SH NAMES and PASSWORDS OPTIONS (Authentication)
 .IP CURLOPT_NETRC
 This parameter controls the preference of libcurl between using user names and
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index 73d50a2..a9f8a9d 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -486,6 +486,9 @@ CURLOPT_SSL_SESSIONID_CACHE     7.16.0
 CURLOPT_SSL_VERIFYHOST          7.8.1
 CURLOPT_SSL_VERIFYPEER          7.4.2
 CURLOPT_STDERR                  7.1
+CURLOPT_TCP_KEEPALIVE           7.24.1
+CURLOPT_TCP_KEEPIDLE            7.24.1
+CURLOPT_TCP_KEEPINTVL           7.24.1
 CURLOPT_TCP_NODELAY             7.11.2
 CURLOPT_TELNETOPTIONS           7.7
 CURLOPT_TFTP_BLKSIZE            7.19.4
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 59a5c79..2a9957e 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1499,6 +1499,13 @@ typedef enum {
      of miliseconds. */
   CINIT(ACCEPTTIMEOUT_MS, LONG, 212),
 
+  /* Set TCP keepalive */
+  CINIT(TCP_KEEPALIVE, LONG, 213),
+
+  /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */
+  CINIT(TCP_KEEPIDLE, LONG, 214),
+  CINIT(TCP_KEEPINTVL, LONG, 215),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
diff --git a/lib/connect.c b/lib/connect.c
index f76ec0e..f882db5 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -91,6 +91,35 @@
 
 static bool verifyconnect(curl_socket_t sockfd, int *error);
 
+static void
+tcpkeepalive(struct SessionHandle *data,
+             int sockfd)
+{
+  int optval = data->set.tcp_keepalive;
+
+  /* don't abort operation if any setsockopt fails, just log to debug */
+  if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+        (void *)&optval, sizeof(optval)) < 0) {
+    infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
+  }
+  else {
+#ifdef TCP_KEEPIDLE
+    optval = data->set.tcp_keepidle;
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
+          (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
+    }
+#endif
+#ifdef TCP_KEEPINTVL
+    optval = data->set.tcp_keepintvl;
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
+          (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
+    }
+#endif
+  }
+}
+
 static CURLcode
 singleipconnect(struct connectdata *conn,
                 const Curl_addrinfo *ai, /* start connecting to this */
@@ -874,6 +903,9 @@ singleipconnect(struct connectdata *conn,
 
   Curl_sndbufset(sockfd);
 
+  if(data->set.tcp_keepalive)
+    tcpkeepalive(data, sockfd);
+
   if(data->set.fsockopt) {
     /* activate callback for setting socket options */
     error = data->set.fsockopt(data->set.sockopt_client,
diff --git a/lib/url.c b/lib/url.c
index 466748b..9d66e76 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -742,6 +742,13 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
   set->chunk_bgn      = ZERO_NULL;
   set->chunk_end      = ZERO_NULL;
 
+  /* tcp keepalives are disabled by default, but provide reasonable values for
+   * the interval and idle times.
+   */
+  set->tcp_keepalive = 0;
+  set->tcp_keepintvl = 60;
+  set->tcp_keepidle = 60;
+
   return res;
 }
 
@@ -805,6 +812,7 @@ CURLcode Curl_open(struct SessionHandle **curl)
        multi stack. */
   }
 
+
   if(res) {
     Curl_resolver_cleanup(data->state.resolver);
     if(data->state.headerbuff)
@@ -2539,6 +2547,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     result = Curl_set_dns_servers(data, va_arg(param, char *));
     break;
 
+  case CURLOPT_TCP_KEEPALIVE:
+    data->set.tcp_keepalive = (0 != va_arg(param, long))?TRUE:FALSE;
+    break;
+
+  case CURLOPT_TCP_KEEPIDLE:
+    data->set.tcp_keepidle = va_arg(param, long);
+    break;
+
+  case CURLOPT_TCP_KEEPINTVL:
+    data->set.tcp_keepintvl = va_arg(param, long);
+    break;
+
   default:
     /* unknown tag and its companion, just ignore: */
     result = CURLE_UNKNOWN_OPTION;
diff --git a/lib/urldata.h b/lib/urldata.h
index adabf5b..a959bc7 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1539,6 +1539,10 @@ struct UserDefined {
 
   long gssapi_delegation; /* GSSAPI credential delegation, see the
                              documentation of CURLOPT_GSSAPI_DELEGATION */
+
+  bool tcp_keepalive;    /* use TCP keepalives */
+  long tcp_keepidle;     /* seconds in idle before sending keepalive probe */
+  long tcp_keepintvl;    /* seconds between TCP keepalive probes */
 };
 
 struct Names {
-- 
1.7.8.4
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2012-01-24