cf-socket: disable TCP SYN retransmissions for localhost on Windows

Suggested-by: Marcel Jamin
URL: https://curl.se/mail/lib-2026-08/0002.html
URL: https://daniel.haxx.se/blog/2024/08/14/slow-tcp-connect-on-windows/

Closes #22494
This commit is contained in:
Daniel Stenberg 2026-08-05 14:56:40 +02:00
parent 9ea48811fe
commit abcb5349e3
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
2 changed files with 58 additions and 5 deletions

View file

@ -81,7 +81,9 @@
#include "curlx/version_win32.h"
#include "curlx/strerr.h"
#include "curlx/strparse.h"
#ifdef _WIN32
#include <mstcpip.h> /* for TCP_INITIAL_RTO_PARAMETERS */
#endif
/* retrieves ip address and port from a sockaddr structure. note it calls
* curlx_inet_ntop which sets errno on fail, not SOCKERRNO.
@ -1141,6 +1143,51 @@ static int cf_socktype(int x)
return x;
}
#ifdef _WIN32
/* Offered by mingw-w64 v10+, MS SDK 8.0/~VS2012+ */
#ifndef SIO_TCP_INITIAL_RTO
#define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR, 17)
#define TCP_INITIAL_RTO_DEFAULT_RTT 0
/* !checksrc! disable TYPEDEFSTRUCT 1 */
typedef struct _TCP_INITIAL_RTO_PARAMETERS {
USHORT Rtt;
UCHAR MaxSynRetransmissions;
} TCP_INITIAL_RTO_PARAMETERS;
#endif
#ifndef TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS
#define TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS 0xFE /* -2 */
#endif
static bool targets_localhost(struct cf_socket_ctx *ctx)
{
return (((ctx->addr.family == AF_INET) &&
!strcmp(ctx->ip.remote_ip, "127.0.0.1")) ||
((ctx->addr.family == AF_INET6) &&
!strcmp(ctx->ip.remote_ip, "::1")));
}
/* disable TCP SYN retransmissions for localhost connection on Windows to
detect problems faster */
static void tcplocalhost(struct Curl_cfilter *cf,
curl_socket_t sockfd)
{
if(targets_localhost(cf->ctx)) {
TCP_INITIAL_RTO_PARAMETERS rto;
DWORD bytes = 0;
memset(&rto, 0, sizeof(rto));
rto.Rtt = TCP_INITIAL_RTO_DEFAULT_RTT;
rto.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS;
(void)WSAIoctl(sockfd, SIO_TCP_INITIAL_RTO, &rto, sizeof(rto),
NULL, 0, &bytes, NULL, NULL);
}
}
#else
#define tcplocalhost(x, y)
#endif
static CURLcode cf_socket_open(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@ -1214,11 +1261,15 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
is_tcp = (ctx->addr.family == AF_INET) &&
cf_socktype(ctx->addr.socktype) == SOCK_STREAM;
#endif
if(is_tcp && data->set.tcp_nodelay)
tcpnodelay(cf, data, ctx->sock);
if(is_tcp) {
if(data->set.tcp_nodelay)
tcpnodelay(cf, data, ctx->sock);
if(is_tcp && data->set.tcp_keepalive)
tcpkeepalive(cf, data, ctx->sock);
if(data->set.tcp_keepalive)
tcpkeepalive(cf, data, ctx->sock);
tcplocalhost(cf, ctx->sock);
}
if(data->set.fsockopt) {
/* activate callback for setting socket options */