Project

General

Profile

Actions

Bug #21803

open

`Addrinfo#connect_internal` should raise `IO::TimeoutError` on user-specified timeouts

Bug #21803: `Addrinfo#connect_internal` should raise `IO::TimeoutError` on user-specified timeouts

Added by shioimm (Misaki Shioi) about 3 hours ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:124357]

Description

Background & Proposal

Addrinfo#connect_internal is a core internal method that is called by both
Addrinfo#connect and Addrinfo#connect_from.
It receives a user-specified timeout value from these methods and currently raises
Errno::ETIMEDOUT when that timeout expires.

https://github.com/ruby/ruby/blame/1c07158203f00d020841f2400002f6e9b62d1318/ext/socket/lib/socket.rb#L65

  def connect_internal(local_addrinfo, timeout=nil) # :yields: socket
    sock = Socket.new(self.pfamily, self.socktype, self.protocol)
    begin
      sock.ipv6only! if self.ipv6?
      sock.bind local_addrinfo if local_addrinfo
      if timeout
        case sock.connect_nonblock(self, exception: false)
        when 0 # success or EISCONN, other errors raise
          break
        when :wait_writable
          sock.wait_writable(timeout) or
            raise Errno::ETIMEDOUT, "user specified timeout for #{self.ip_address}:#{self.ip_port}"
        end while true
      else
        sock.connect(self)
      end

However, this timeout is not caused by a system call returning Errno::ETIMEDOUT.
It is a Ruby-level timeout triggered by explicitly waiting with a user-specified
timeout value.
This distinction was discussed in another issue:
Introduce general IO#timeout and IO#timeout= for blocking operations)

After that discussion, Support IO#timeout for rsock_connect introduced a change so that rsock_connect() raises IO::TimeoutError
when a user-specified timeout expires.

In addition, TCPSocket.new and Socket.tcp were updated to align with this behavior, so that they raise IO::TimeoutError when a user-specified timeout occurs:
Socket.tcp and TCPSocket.new raise IO::TimeoutError with user specified timeout

However, the implementation of Socket.tcp still partially relies on
Addrinfo#connect_internal, specifically in cases where a synchronous connection
attempt is made to a single destination.
As a result, depending on the execution path, a user-specified timeout may raise
either IO::TimeoutError or Errno::ETIMEDOUT.
This inconsistency is undesirable. Therefore, I propose that Addrinfo#connect_internal should raise IO::TimeoutError (instead of Errno::ETIMEDOUT) when a user-specified timeout expires, to make the behavior consistent across the socket APIs.

No data to display

Actions

Also available in: PDF Atom