diff options
| author | Misaki Shioi <31817032+shioimm@users.noreply.github.com> | 2025-12-17 11:11:39 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-17 11:11:39 +0900 |
| commit | 74a365310cfd150af6b45920d84920d17d6b3946 (patch) | |
| tree | a7d3e4224b486af5214464580bd54f2e205d934c /ext | |
| parent | f483484fc610589a6faf828a77fd76f15fb4ebb3 (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.c | 41 | ||||
| -rw-r--r-- | ext/socket/lib/socket.rb | 19 |
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 |
