diff --git a/.github/scripts/typos.toml b/.github/scripts/typos.toml index 3192a2987c..880664361d 100644 --- a/.github/scripts/typos.toml +++ b/.github/scripts/typos.toml @@ -14,6 +14,8 @@ extend-ignore-identifiers-re = [ "^(clen|req_clen|smtp_perform_helo|smtp_state_helo_resp|Tru64|_stati64)$", "(_ccontains|_controllen|O_WRONLY|secur32)", "proxys", # this should be limited to tests/http/*. Short for secure proxy. + "rto", # (TCP) retransmission timeout + "RTO" ] extend-ignore-re = [ diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 9c65963ce3..54df7cc2a3 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -81,7 +81,9 @@ #include "curlx/version_win32.h" #include "curlx/strerr.h" #include "curlx/strparse.h" - +#ifdef _WIN32 +#include /* 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 */