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