Skip to content

Commit

Permalink
add library support for tuning TCP_KEEPALIVE
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
falconindy authored and bagder committed Feb 9, 2012
1 parent ea05540 commit 705f0f7
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 0 deletions.
18 changes: 18 additions & 0 deletions docs/libcurl/curl_easy_setopt.3
Expand Up @@ -915,6 +915,24 @@ overdone.
.IP CURLOPT_ADDRESS_SCOPE .IP CURLOPT_ADDRESS_SCOPE
Pass a long specifying the scope_id value to use when connecting to IPv6 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) 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) .SH NAMES and PASSWORDS OPTIONS (Authentication)
.IP CURLOPT_NETRC .IP CURLOPT_NETRC
This parameter controls the preference of libcurl between using user names and This parameter controls the preference of libcurl between using user names and
Expand Down
3 changes: 3 additions & 0 deletions docs/libcurl/symbols-in-versions
Expand Up @@ -486,6 +486,9 @@ CURLOPT_SSL_SESSIONID_CACHE 7.16.0
CURLOPT_SSL_VERIFYHOST 7.8.1 CURLOPT_SSL_VERIFYHOST 7.8.1
CURLOPT_SSL_VERIFYPEER 7.4.2 CURLOPT_SSL_VERIFYPEER 7.4.2
CURLOPT_STDERR 7.1 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_TCP_NODELAY 7.11.2
CURLOPT_TELNETOPTIONS 7.7 CURLOPT_TELNETOPTIONS 7.7
CURLOPT_TFTP_BLKSIZE 7.19.4 CURLOPT_TFTP_BLKSIZE 7.19.4
Expand Down
7 changes: 7 additions & 0 deletions include/curl/curl.h
Expand Up @@ -1499,6 +1499,13 @@ typedef enum {
of miliseconds. */ of miliseconds. */
CINIT(ACCEPTTIMEOUT_MS, LONG, 212), 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 */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;


Expand Down
32 changes: 32 additions & 0 deletions lib/connect.c
Expand Up @@ -91,6 +91,35 @@


static bool verifyconnect(curl_socket_t sockfd, int *error); static bool verifyconnect(curl_socket_t sockfd, int *error);


static void
tcpkeepalive(struct SessionHandle *data,
int sockfd)
{
int optval = data->set.tcp_keepalive;

/* only set IDLE and INTVL if setting KEEPALIVE is successful */
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 static CURLcode
singleipconnect(struct connectdata *conn, singleipconnect(struct connectdata *conn,
const Curl_addrinfo *ai, /* start connecting to this */ const Curl_addrinfo *ai, /* start connecting to this */
Expand Down Expand Up @@ -876,6 +905,9 @@ singleipconnect(struct connectdata *conn,


Curl_sndbufset(sockfd); Curl_sndbufset(sockfd);


if(data->set.tcp_keepalive)
tcpkeepalive(data, sockfd);

if(data->set.fsockopt) { if(data->set.fsockopt) {
/* activate callback for setting socket options */ /* activate callback for setting socket options */
error = data->set.fsockopt(data->set.sockopt_client, error = data->set.fsockopt(data->set.sockopt_client,
Expand Down
18 changes: 18 additions & 0 deletions lib/url.c
Expand Up @@ -748,6 +748,13 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
set->chunk_bgn = ZERO_NULL; set->chunk_bgn = ZERO_NULL;
set->chunk_end = 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; return res;
} }


Expand Down Expand Up @@ -811,6 +818,7 @@ CURLcode Curl_open(struct SessionHandle **curl)
multi stack. */ multi stack. */
} }



if(res) { if(res) {
Curl_resolver_cleanup(data->state.resolver); Curl_resolver_cleanup(data->state.resolver);
if(data->state.headerbuff) if(data->state.headerbuff)
Expand Down Expand Up @@ -2545,6 +2553,16 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
result = Curl_set_dns_servers(data, va_arg(param, char *)); result = Curl_set_dns_servers(data, va_arg(param, char *));
break; 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: default:
/* unknown tag and its companion, just ignore: */ /* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION; result = CURLE_UNKNOWN_OPTION;
Expand Down
4 changes: 4 additions & 0 deletions lib/urldata.h
Expand Up @@ -1539,6 +1539,10 @@ struct UserDefined {


long gssapi_delegation; /* GSSAPI credential delegation, see the long gssapi_delegation; /* GSSAPI credential delegation, see the
documentation of CURLOPT_GSSAPI_DELEGATION */ 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 { struct Names {
Expand Down

0 comments on commit 705f0f7

Please sign in to comment.