Class: Resolv::DNS
- Inherits:
-
Object
- Object
- Resolv::DNS
- Defined in:
- lib/resolv-srv.rb
Overview
A monkey patch for Resolv::DNS that provides a mostly RFC-compliant method for resolving SRV records.
Instance Method Summary collapse
-
#each_srv_resource(service, protocol, domain) { ... } ⇒ Object
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.
Instance Method Details
#each_srv_resource(service, protocol, domain) { ... } ⇒ Object
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.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# 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 |