[pacman-dev] [PATCH 1/2] add library support for tuning TCP_KEEPALIVE
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
Use the new library CURLOPT_TCP_KEEPALIVE rather than disabling this via the sockopt callback. If --keepalive-time is used, apply the value to CURLOPT_TCP_KEEPIDLE and CURLOPT_TCP_KEEPINTVL. --- The matching changes for the front end to use the new options from the previous patch. docs/curl.1 | 3 +- src/Makefile.inc | 2 - src/tool_cb_skt.c | 97 ---------------------------------------------------- src/tool_cb_skt.h | 35 ------------------- src/tool_operate.c | 12 ++++-- 5 files changed, 10 insertions(+), 139 deletions(-) delete mode 100644 src/tool_cb_skt.c delete mode 100644 src/tool_cb_skt.h diff --git a/docs/curl.1 b/docs/curl.1 index e92cf51..5bc8f0d 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -711,7 +711,8 @@ currently effective on operating systems offering the TCP_KEEPIDLE and TCP_KEEPINTVL socket options (meaning Linux, recent AIX, HP-UX and more). This option has no effect if \fI--no-keepalive\fP is used. (Added in 7.18.0) -If this option is used multiple times, the last occurrence sets the amount. +If this option is used multiple times, the last occurrence sets the amount. If +unspecified, the option defaults to 60 seconds. .IP "--key <key>" (SSL/SSH) Private key file name. Allows you to provide your private key in this separate file. diff --git a/src/Makefile.inc b/src/Makefile.inc index 1660bc4..a43ac51 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -22,7 +22,6 @@ CURL_CFILES = hugehelp.c \ tool_cb_prg.c \ tool_cb_rea.c \ tool_cb_see.c \ - tool_cb_skt.c \ tool_cb_wrt.c \ tool_cfgable.c \ tool_convert.c \ @@ -62,7 +61,6 @@ CURL_HFILES = hugehelp.h setup.h config-win32.h config-mac.h \ tool_cb_prg.h \ tool_cb_rea.h \ tool_cb_see.h \ - tool_cb_skt.h \ tool_cb_wrt.h \ tool_cfgable.h \ tool_convert.h \ diff --git a/src/tool_cb_skt.c b/src/tool_cb_skt.c deleted file mode 100644 index 156c110..0000000 --- a/src/tool_cb_skt.c +++ /dev/null @@ -1,97 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "setup.h" - -#include <curl/curl.h> - -#ifdef HAVE_SYS_SOCKET_H -# include <sys/socket.h> -#endif - -#define ENABLE_CURLX_PRINTF -/* use our own printf() functions */ -#include "curlx.h" - -#include "tool_cfgable.h" -#include "tool_msgs.h" -#include "tool_cb_skt.h" - -#include "memdebug.h" /* keep this as LAST include */ - -/* -** callback for CURLOPT_SOCKOPTFUNCTION -*/ - -int tool_sockopt_cb(void *userdata, curl_socket_t curlfd, curlsocktype purpose) -{ - struct Configurable *config = userdata; - - int onoff = 1; /* this callback is only used if we ask for keepalives on the - connection */ - -#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL) - int keepidle = (int)config->alivetime; -#endif - - switch(purpose) { - case CURLSOCKTYPE_IPCXN: - if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff, - sizeof(onoff)) < 0) { - /* don't abort operation, just issue a warning */ - SET_SOCKERRNO(0); - warnf(config, "Could not set SO_KEEPALIVE!\n"); - return 0; - } - else { - if(config->alivetime) { -#ifdef TCP_KEEPIDLE - if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle, - sizeof(keepidle)) < 0) { - /* don't abort operation, just issue a warning */ - SET_SOCKERRNO(0); - warnf(config, "Could not set TCP_KEEPIDLE!\n"); - return 0; - } -#endif -#ifdef TCP_KEEPINTVL - if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle, - sizeof(keepidle)) < 0) { - /* don't abort operation, just issue a warning */ - SET_SOCKERRNO(0); - warnf(config, "Could not set TCP_KEEPINTVL!\n"); - return 0; - } -#endif -#if !defined(TCP_KEEPIDLE) || !defined(TCP_KEEPINTVL) - warnf(config, "Keep-alive functionality somewhat crippled due to " - "missing support in your operating system!\n"); -#endif - } - } - break; - default: - break; - } - - return 0; -} - diff --git a/src/tool_cb_skt.h b/src/tool_cb_skt.h deleted file mode 100644 index 11bd0c4..0000000 --- a/src/tool_cb_skt.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef HEADER_CURL_TOOL_CB_SKT_H -#define HEADER_CURL_TOOL_CB_SKT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "setup.h" - -/* -** callback for CURLOPT_SOCKOPTFUNCTION -*/ - -int tool_sockopt_cb(void *userdata, - curl_socket_t curlfd, - curlsocktype purpose); - -#endif /* HEADER_CURL_TOOL_CB_SKT_H */ - diff --git a/src/tool_operate.c b/src/tool_operate.c index a6f6f0b..e093560 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -54,7 +54,6 @@ #include "tool_cb_prg.h" #include "tool_cb_rea.h" #include "tool_cb_see.h" -#include "tool_cb_skt.h" #include "tool_cb_wrt.h" #include "tool_dirhie.h" #include "tool_doswin.h" @@ -1147,8 +1146,13 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) /* curl 7.17.1 */ if(!config->nokeepalive) { - my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, tool_sockopt_cb); - my_setopt(curl, CURLOPT_SOCKOPTDATA, config); + my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); + if(config->alivetime != 0) { + my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime); + my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime); + } + } else { + my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L); } /* curl 7.20.0 */ -- 1.7.8.4
participants (1)
-
Dave Reisner