class Redis::Connection::TCPSocket

def self.connect(host, port, timeout)

def self.connect(host, port, timeout)
  Timeout.timeout(timeout) do
    sock = new(host, port)
    sock
  end
rescue Timeout::Error
  raise TimeoutError
end

def self.connect(host, port, timeout)

def self.connect(host, port, timeout)
  # Don't pass AI_ADDRCONFIG as flag to getaddrinfo(3)
  #
  # From the man page for getaddrinfo(3):
  #
  #   If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4
  #   addresses are returned in the list pointed to by res only if the
  #   local system has at least one IPv4 address configured, and IPv6
  #   addresses are returned only if the local system has at least one
  #   IPv6 address configured. The loopback address is not considered
  #   for this case as valid as a configured address.
  #
  # We do want the IPv6 loopback address to be returned if applicable,
  # even if it is the only configured IPv6 address on the machine.
  # Also see: https://github.com/redis/redis-rb/pull/394.
  addrinfo = ::Socket.getaddrinfo(host, nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM)
  # From the man page for getaddrinfo(3):
  #
  #   Normally, the application should try using the addresses in the
  #   order in which they are returned. The sorting function used
  #   within getaddrinfo() is defined in RFC 3484 [...].
  #
  addrinfo.each_with_index do |ai, i|
    begin
      return connect_addrinfo(ai, port, timeout)
    rescue SystemCallError
      # Raise if this was our last attempt.
      raise if addrinfo.length == i + 1
    end
  end
end

def self.connect_addrinfo(addrinfo, port, timeout)

def self.connect_addrinfo(addrinfo, port, timeout)
  sock = new(::Socket.const_get(addrinfo[0]), Socket::SOCK_STREAM, 0)
  sockaddr = ::Socket.pack_sockaddr_in(port, addrinfo[3])
  begin
    sock.connect_nonblock(sockaddr)
  rescue Errno::EINPROGRESS
    raise TimeoutError unless sock.wait_writable(timeout)
    begin
      sock.connect_nonblock(sockaddr)
    rescue Errno::EISCONN
    end
  end
  sock
end