class Resolv::DNS
A monkey patch for Resolv::DNS
that provides a mostly RFC-compliant method for resolving SRV records.
Public Instance Methods
each_srv_resource(service, protocol, domain) { |selected| ... }
click to toggle source
Iterates over SRV resources for service operating over protocol within domain, first in order of priority and then randomly within a priority in proportion to weight.
NOTE: The algorithm used causes resources with weight 0 to be selected before resources with higher weights slightly more often than they would be if strict RFC compliance were enforced.
@param service [String] The service type, such as ldap
or http
. @param protocol [String] The protocol for connections, such as tcp
or
+udp+.
@param domain [String] The DNS
domain in which to search for records.
@yield Resolv::DNS::Resource::IN::SRV
# File lib/resolv-srv.rb, line 22 def each_srv_resource(service, protocol, domain) if service.nil? || service.empty? || service.index('.') raise ArgumentError, "Invalid service name: #{service.inspect}" end if protocol.nil? || protocol.empty? || protocol.index('.') raise ArgumentError, "Invalid protocol name: #{protocol.inspect}" end name = "_#{service}._#{protocol}.#{domain}" # Fetch the resources. getresources(name, Resolv::DNS::Resource::IN::SRV). # Group and sort them by priority. sort_by!(&:priority).chunk(&:priority).sort. # Iterate over the lists of resources at each priority level. each do |priority, available| # NOTE: # All weight processing is shifted to be 1-based rather than 0-based. # Because of the way selection is handled, this avoids needing to shuffle # or sort the array elements by weight while ensuring that resources with # weight 0 avoid ALWAYS being selected last. The trade-off is that # resources with weight 0 may be selected before other resources slightly # more often than otherwise. # Tracks the total weight of all resources remaining in the available # list. total_weight = available.inject(0) { |sum, e| sum + e.weight + 1 } until available.empty? # Randomly select from the available list such that the probability of # selecting a resource is proportional to the resource's weight. selector = Integer(rand * total_weight) + 1 selected_idx = available.find_index do |e| selector -= e.weight + 1 selector <= 0 end selected = available.delete_at(selected_idx) # Account for the removal of a resource from the available list. total_weight -= selected.weight + 1 yield(selected) end end end