summaryrefslogtreecommitdiff
path: root/ext/socket
diff options
context:
space:
mode:
authorKJ Tsanaktsidis <kj@kjtsanaktsidis.id.au>2023-12-07 19:55:15 +1100
committerGitHub <noreply@github.com>2023-12-07 17:55:15 +0900
commitd2ba8ea54a4089959afdeecdd963e3c4ff391748 (patch)
tree1ec2a22efb57f62660f63dddef48795f3816890a /ext/socket
parentc6eb355e04b2f9ffe9e78fcec259c901b3905cc9 (diff)
Set AI_ADDRCONFIG when making getaddrinfo(3) calls for outgoing conns (#7295)
When making an outgoing TCP or UDP connection, set AI_ADDRCONFIG in the hints we send to getaddrinfo(3) (if supported). This will prompt the resolver to _NOT_ issue A or AAAA queries if the system does not actually have an IPv4 or IPv6 address (respectively). This makes outgoing connections marginally more efficient on non-dual-stack systems, since we don't have to try connecting to an address which can't possibly work. More importantly, however, this works around a race condition present in some older versions of glibc on aarch64 where it could accidently send the two outgoing DNS queries with the same DNS txnid, and get confused when receiving the responses. This manifests as outgoing connections sometimes taking 5 seconds (the DNS timeout before retry) to be made. Fixes #19144
Diffstat (limited to 'ext/socket')
-rw-r--r--ext/socket/extconf.rb2
-rw-r--r--ext/socket/ipsocket.c11
-rw-r--r--ext/socket/udpsocket.c9
3 files changed, 19 insertions, 3 deletions
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index 1ca52da366..544bed5298 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -607,6 +607,8 @@ You can try --enable-wide-getaddrinfo.
EOS
end
+ have_const('AI_ADDRCONFIG', headers)
+
case with_config("lookup-order-hack", "UNSPEC")
when "INET"
$defs << "-DLOOKUP_ORDER_HACK_INET"
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c
index 0c13620258..0a693655b4 100644
--- a/ext/socket/ipsocket.c
+++ b/ext/socket/ipsocket.c
@@ -54,15 +54,22 @@ init_inetsock_internal(VALUE v)
VALUE connect_timeout = arg->connect_timeout;
struct timeval tv_storage;
struct timeval *tv = NULL;
+ int remote_addrinfo_hints = 0;
if (!NIL_P(connect_timeout)) {
tv_storage = rb_time_interval(connect_timeout);
tv = &tv_storage;
}
+ if (type == INET_SERVER) {
+ remote_addrinfo_hints |= AI_PASSIVE;
+ }
+#ifdef HAVE_CONST_AI_ADDRCONFIG
+ remote_addrinfo_hints |= AI_ADDRCONFIG;
+#endif
+
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
- family, SOCK_STREAM,
- (type == INET_SERVER) ? AI_PASSIVE : 0);
+ family, SOCK_STREAM, remote_addrinfo_hints);
/*
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index 5224e48a96..cf3eb6ab9a 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -88,9 +88,16 @@ udp_connect(VALUE sock, VALUE host, VALUE port)
{
struct udp_arg arg;
VALUE ret;
+ int addrinfo_hints = 0;
GetOpenFile(sock, arg.fptr);
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
+
+#ifdef HAVE_CONST_AI_ADDRCONFIG
+ addrinfo_hints |= AI_ADDRCONFIG;
+#endif
+
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM,
+ addrinfo_hints);
ret = rb_ensure(udp_connect_internal, (VALUE)&arg,
rsock_freeaddrinfo, (VALUE)arg.res);
if (!ret) rsock_sys_fail_host_port("connect(2)", host, port);