class Excon::Socket

def connect

def connect
  @socket = nil
  exception = nil
  hostname = @data[:hostname]
  port = @port
  family = @data[:family]
  if @data[:proxy]
    hostname = @data[:proxy][:hostname]
    port = @data[:proxy][:port]
    family = @data[:proxy][:family]
  end
  resolver = @data[:resolv_resolver] || Resolv::DefaultResolver
  # Deprecated
  if @data[:dns_timeouts]
    Excon.display_warning('dns_timeouts is deprecated, use resolv_resolver instead.')
    dns_resolver = Resolv::DNS.new
    dns_resolver.timeouts = @data[:dns_timeouts]
    resolver = Resolv.new([Resolv::Hosts.new, dns_resolver])
  end
  resolver.each_address(hostname) do |ip|
    # already succeeded on previous addrinfo
    if @socket
      break
    end
    @remote_ip = ip
    @data[:remote_ip] = ip
    # nonblocking connect
    begin
      sockaddr = ::Socket.sockaddr_in(port, ip)
      addrinfo = Addrinfo.getaddrinfo(ip, port, family, :STREAM).first
      socket = ::Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol)
      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
      if @nonblock
        socket.connect_nonblock(sockaddr)
      else
        socket.connect(sockaddr)
      end
      @socket = socket
    rescue *CONNECT_RETRY_EXCEPTION_CLASSES
      select_with_timeout(socket, :connect_write)
      begin
        socket.connect_nonblock(sockaddr)
        @socket = socket
      rescue Errno::EISCONN
        @socket = socket
      rescue SystemCallError => exception
        socket.close rescue nil
      end
    rescue SystemCallError => exception
      socket.close rescue nil if socket
    end
  end
  exception ||= Resolv::ResolvError.new("no address for #{hostname}")
  # this will be our last encountered exception
  fail exception unless @socket
  if @data[:tcp_nodelay]
    @socket.setsockopt(::Socket::IPPROTO_TCP,
                       ::Socket::TCP_NODELAY,
                       true)
  end
  if @data[:keepalive]
    if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| ::Socket.const_defined? c}
      @socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true)
      @socket.setsockopt(::Socket::SOL_TCP, ::Socket::TCP_KEEPIDLE, @data[:keepalive][:time])
      @socket.setsockopt(::Socket::SOL_TCP, ::Socket::TCP_KEEPINTVL, @data[:keepalive][:intvl])
      @socket.setsockopt(::Socket::SOL_TCP, ::Socket::TCP_KEEPCNT, @data[:keepalive][:probes])
    else
      Excon.display_warning('Excon::Socket keepalive was set, but is not supported by Ruby version.')
    end
  end
end