From a15d069a19867b9c508ccfca5702f36448e829e8 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 12 Oct 2013 22:29:40 +0000 Subject: http: enable keepalive on TCP sockets This is a follow up to commit e47a8583 (enable SO_KEEPALIVE for connected TCP sockets, 2011-12-06). Sockets may never receive notification of some link errors, causing "git fetch" or similar processes to hang forever. Enabling keepalive messages allows hung processes to error out after a few minutes/hours depending on the keepalive settings of the system. I noticed this problem with some non-interactive cronjobs getting hung when talking to HTTP servers. Signed-off-by: Eric Wong Signed-off-by: Jonathan Nieder --- http.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'http.c') diff --git a/http.c b/http.c index b2ae8de16d..a2c1819e22 100644 --- a/http.c +++ b/http.c @@ -233,6 +233,24 @@ static int has_cert_password(void) return 0; } +/* curl 7.25.0 has CURLOPT_TCP_KEEPALIVE, too, but we support older curl */ +static int sockopt_callback(void *client, curl_socket_t fd, curlsocktype type) +{ + int ka = 1; + int rc; + socklen_t len = (socklen_t)sizeof(ka); + + if (type != CURLSOCKTYPE_IPCXN) + return 0; + + rc = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&ka, len); + if (rc < 0) + warning("unable to set SO_KEEPALIVE on socket %s", + strerror(errno)); + + return 0; /* CURL_SOCKOPT_OK only exists since curl 7.21.5 */ +} + static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); @@ -298,6 +316,10 @@ static CURL *get_curl_handle(void) if (curl_http_proxy) curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy); +#if LIBCURL_VERSION_NUM >= 0x071000 + curl_easy_setopt(result, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); +#endif + return result; } -- cgit v1.2.3 From 47ce115370cba8ebfced696f9997e718c465435d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 14 Oct 2013 20:06:14 -0400 Subject: http: use curl's tcp keepalive if available Commit a15d069 taught git to use curl's SOCKOPTFUNCTION hook to turn on TCP keepalives. However, modern versions of curl have a TCP_KEEPALIVE option, which can do this for us. As an added bonus, the curl code knows how to turn on keepalive for a much wider variety of platforms. The only downside to using this option is that not everybody has a new enough curl. Let's split our keepalive options into three conditionals: 1. With curl 7.25.0 and newer, we rely on curl to do it right. 2. With older curl that still knows SOCKOPTFUNCTION, we use the code from a15d069. 3. Otherwise, we are out of luck, and the call is a no-op. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- http.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index a2c1819e22..6359526196 100644 --- a/http.c +++ b/http.c @@ -233,7 +233,13 @@ static int has_cert_password(void) return 0; } -/* curl 7.25.0 has CURLOPT_TCP_KEEPALIVE, too, but we support older curl */ +#if LIBCURL_VERSION_NUM >= 0x071900 +static void set_curl_keepalive(CURL *c) +{ + curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1); +} + +#elif LIBCURL_VERSION_NUM >= 0x071000 static int sockopt_callback(void *client, curl_socket_t fd, curlsocktype type) { int ka = 1; @@ -251,6 +257,18 @@ static int sockopt_callback(void *client, curl_socket_t fd, curlsocktype type) return 0; /* CURL_SOCKOPT_OK only exists since curl 7.21.5 */ } +static void set_curl_keepalive(CURL *c) +{ + curl_easy_setopt(c, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); +} + +#else +static void set_curl_keepalive(CURL *c) +{ + /* not supported on older curl versions */ +} +#endif + static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); @@ -316,9 +334,7 @@ static CURL *get_curl_handle(void) if (curl_http_proxy) curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy); -#if LIBCURL_VERSION_NUM >= 0x071000 - curl_easy_setopt(result, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); -#endif + set_curl_keepalive(result); return result; } -- cgit v1.2.3