class Excon::Socket

def connect

def connect
  @socket = nil
  exception = nil
  if @data[:proxy]
    family = @data[:proxy][:family] || ::Socket::Constants::AF_UNSPEC
    args = [@data[:proxy][:host], @data[:proxy][:port], family, ::Socket::Constants::SOCK_STREAM]
  else
    family = @data[:family] || ::Socket::Constants::AF_UNSPEC
    args = [@data[:host], @data[:port], family, ::Socket::Constants::SOCK_STREAM]
  end
  if RUBY_VERSION >= '1.9.2' && defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
    args << nil << nil << false # no reverse lookup
  end
  addrinfo = ::Socket.getaddrinfo(*args)
  addrinfo.each do |_, port, _, ip, a_family, s_type|
    @remote_ip = ip
    # nonblocking connect
    begin
      sockaddr = ::Socket.sockaddr_in(port, ip)
      socket = ::Socket.new(a_family, s_type, 0)
      if @data[:reuseaddr]
        socket.setsockopt(::Socket::Constants::SOL_SOCKET, ::Socket::Constants::SO_REUSEADDR, true)
        if defined?(::Socket::Constants::SO_REUSEPORT)
          socket.setsockopt(::Socket::Constants::SOL_SOCKET, ::Socket::Constants::SO_REUSEPORT, true)
        end
      end
      begin
        Timeout.timeout(@data[:connect_timeout]) do
          if @nonblock
            socket.connect_nonblock(sockaddr)
          else
            socket.connect(sockaddr)
          end
        end
      rescue Timeout::Error
        raise Excon::Errors::Timeout.new('connect timeout reached')
      end
      @socket = socket
      break
    rescue Errno::EINPROGRESS
      unless IO.select(nil, [socket], nil, @data[:connect_timeout])
        raise(Excon::Errors::Timeout.new("connect timeout reached"))
      end
      begin
        socket.connect_nonblock(sockaddr)
        @socket = socket
        break
      rescue Errno::EISCONN
        @socket = socket
        break
      rescue SystemCallError => exception
        socket.close rescue nil
        next
      end
    rescue SystemCallError => exception
      socket.close rescue nil if socket
      next
    end
  end
  unless @socket
    # this will be our last encountered exception
    raise exception
  end
  if @data[:tcp_nodelay]
    @socket.setsockopt(::Socket::IPPROTO_TCP,
                       ::Socket::TCP_NODELAY,
                       true)
  end
end