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