summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorMisaki Shioi <31817032+shioimm@users.noreply.github.com>2025-12-17 11:11:39 +0900
committerGitHub <noreply@github.com>2025-12-17 11:11:39 +0900
commit74a365310cfd150af6b45920d84920d17d6b3946 (patch)
treea7d3e4224b486af5214464580bd54f2e205d934c /ext
parentf483484fc610589a6faf828a77fd76f15fb4ebb3 (diff)
Fix: Recalculate the timeout duration considering `open_timeout` (#15596)
This change updates the behavior so that, when there is only a single destination and `open_timeout` is specified, the remaining `open_timeout` duration is used as the connection timeout.
Diffstat (limited to 'ext')
-rw-r--r--ext/socket/ipsocket.c41
-rw-r--r--ext/socket/lib/socket.rb19
2 files changed, 46 insertions, 14 deletions
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c
index a95f5767d2..ba1b81b3ad 100644
--- a/ext/socket/ipsocket.c
+++ b/ext/socket/ipsocket.c
@@ -606,6 +606,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
struct timeval user_specified_open_timeout_storage;
struct timeval *user_specified_open_timeout_at = NULL;
struct timespec now = current_clocktime_ts();
+ VALUE starts_at = current_clocktime();
if (!NIL_P(open_timeout)) {
struct timeval open_timeout_tv = rb_time_interval(open_timeout);
@@ -619,7 +620,14 @@ init_fast_fallback_inetsock_internal(VALUE v)
arg->getaddrinfo_shared = NULL;
int family = arg->families[0];
- unsigned int t = NIL_P(resolv_timeout) ? 0 : rsock_value_timeout_to_msec(resolv_timeout);
+ unsigned int t;
+ if (!NIL_P(open_timeout)) {
+ t = rsock_value_timeout_to_msec(open_timeout);
+ } else if (!NIL_P(open_timeout)) {
+ t = rsock_value_timeout_to_msec(resolv_timeout);
+ } else {
+ t = 0;
+ }
arg->remote.res = rsock_addrinfo(
arg->remote.host,
@@ -833,14 +841,22 @@ init_fast_fallback_inetsock_internal(VALUE v)
status = connect(fd, remote_ai->ai_addr, remote_ai->ai_addrlen);
last_family = remote_ai->ai_family;
} else {
- if (!NIL_P(connect_timeout)) {
- user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
- user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ VALUE timeout = Qnil;
+
+ if (!NIL_P(open_timeout)) {
+ VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
+ timeout = rb_funcall(open_timeout, '-', 1, elapsed);
+ }
+ if (NIL_P(timeout)) {
+ if (!NIL_P(connect_timeout)) {
+ user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
+ user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ }
+ timeout =
+ (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
+ Qnil : tv_to_seconds(user_specified_connect_timeout_at);
}
- VALUE timeout =
- (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
- Qnil : tv_to_seconds(user_specified_connect_timeout_at);
io = arg->io = rsock_init_sock(arg->self, fd);
status = rsock_connect(io, remote_ai->ai_addr, remote_ai->ai_addrlen, 0, timeout);
}
@@ -1305,13 +1321,22 @@ rsock_init_inetsock(
* Maybe also accept a local address
*/
if (!NIL_P(local_host) || !NIL_P(local_serv)) {
+ unsigned int t;
+ if (!NIL_P(open_timeout)) {
+ t = rsock_value_timeout_to_msec(open_timeout);
+ } else if (!NIL_P(open_timeout)) {
+ t = rsock_value_timeout_to_msec(resolv_timeout);
+ } else {
+ t = 0;
+ }
+
local_res = rsock_addrinfo(
local_host,
local_serv,
AF_UNSPEC,
SOCK_STREAM,
0,
- 0
+ t
);
struct addrinfo *tmp_p = local_res->ai;
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index f47b5bc1d1..49fb3fcc6d 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -685,7 +685,7 @@ class Socket < BasicSocket
# :stopdoc:
def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil)
if local_host || local_port
- local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: resolv_timeout)
+ local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: open_timeout || resolv_timeout)
resolving_family_names = local_addrinfos.map { |lai| ADDRESS_FAMILIES.key(lai.afamily) }.uniq
else
local_addrinfos = []
@@ -698,6 +698,7 @@ class Socket < BasicSocket
is_windows_environment ||= (RUBY_PLATFORM =~ /mswin|mingw|cygwin/)
now = current_clock_time
+ starts_at = now
resolution_delay_expires_at = nil
connection_attempt_delay_expires_at = nil
user_specified_connect_timeout_at = nil
@@ -707,7 +708,7 @@ class Socket < BasicSocket
if resolving_family_names.size == 1
family_name = resolving_family_names.first
- addrinfos = Addrinfo.getaddrinfo(host, port, ADDRESS_FAMILIES[:family_name], :STREAM, timeout: resolv_timeout)
+ addrinfos = Addrinfo.getaddrinfo(host, port, ADDRESS_FAMILIES[:family_name], :STREAM, timeout: open_timeout || resolv_timeout)
resolution_store.add_resolved(family_name, addrinfos)
hostname_resolution_result = nil
hostname_resolution_notifier = nil
@@ -724,7 +725,6 @@ class Socket < BasicSocket
thread
}
)
-
user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY
end
@@ -758,9 +758,16 @@ class Socket < BasicSocket
socket.bind(local_addrinfo) if local_addrinfo
result = socket.connect_nonblock(addrinfo, exception: false)
else
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
result = socket = local_addrinfo ?
- addrinfo.connect_from(local_addrinfo, timeout: connect_timeout) :
- addrinfo.connect(timeout: connect_timeout)
+ addrinfo.connect_from(local_addrinfo, timeout:) :
+ addrinfo.connect(timeout:)
end
if result == :wait_writable
@@ -934,7 +941,7 @@ class Socket < BasicSocket
local_addr_list = nil
if local_host != nil || local_port != nil
- local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
+ local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil, timeout: open_timeout || resolv_timeout)
end
timeout = open_timeout ? open_timeout : resolv_timeout