lib/socketry/resolver/system.rb
# frozen_string_literal: true
require "timeout"
module Socketry
module Resolver
# System DNS resolver backed by the POSIX getaddrinfo(3) function
module System
module_function
# Resolve a domain name using IPSocket.getaddress. This uses getaddrinfo(3)
# on POSIX operating systems.
#
# @param hostname [String] name of the host whose IP address we'd like to obtain
# @return [IPAddr] resolved IP address
# @raise [Socketry::Resolver::Error] an error occurred resolving the domain name
# @raise [Socketry::TimeoutError] a timeout occured before the name could be resolved
# @raise [Socketry::AddressError] the name was resolved to an unsupported address
def resolve(hostname, timeout: nil)
raise TypeError, "expected String, got #{hostname.class}" unless hostname.is_a?(String)
begin
case timeout
when Integer, Float
# NOTE: ::Timeout is not thread safe. For thread safety, use Socketry::Resolver::Resolv
result = ::Timeout.timeout(timeout) { IPSocket.getaddress(hostname) }
when NilClass
result = IPSocket.getaddress(hostname)
else raise TypeError, "expected Numeric, got #{timeout.class}"
end
rescue ::SocketError => ex
raise Socketry::Resolver::Error, ex.message, ex.backtrace
rescue ::Timeout::Error => ex
raise Socketry::TimeoutError, ex.message, ex.backtrace
end
begin
IPAddr.new(result)
rescue IPAddr::InvalidAddressError => ex
raise Socketry::AddressError, ex.message, ex.backtrace
end
end
end
# Use Socketry::Resolver::System as the default resolver
DEFAULT_RESOLVER = System
end
end