mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* lib/resolv.rb: Add one-shot multicast DNS support.
[ruby-core:53387] [Feature #8089] by Eric Hodel. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40160 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
4c1e97226f
commit
9791353555
3 changed files with 118 additions and 2 deletions
|
@ -1,3 +1,8 @@
|
|||
Sat Apr 6 23:31:38 2013 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* lib/resolv.rb: Add one-shot multicast DNS support.
|
||||
[ruby-core:53387] [Feature #8089] by Eric Hodel.
|
||||
|
||||
Sat Apr 6 22:12:01 2013 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* lib/resolv.rb (Resolv::DNS.fetch_resource): New method to obtain
|
||||
|
|
1
NEWS
1
NEWS
|
@ -49,6 +49,7 @@ with all sufficient information, see the ChangeLog file.
|
|||
* Resolv
|
||||
* New methods:
|
||||
* Resolv::DNS.fetch_resource
|
||||
* One-shot multicast DNS support
|
||||
|
||||
* Rinda::RingServer, Rinda::RingFinger
|
||||
* Rinda now supports multicast sockets. See Rinda::RingServer and
|
||||
|
|
114
lib/resolv.rb
114
lib/resolv.rb
|
@ -665,7 +665,12 @@ class Resolv
|
|||
def request(sender, tout)
|
||||
start = Time.now
|
||||
timelimit = start + tout
|
||||
sender.send
|
||||
begin
|
||||
sender.send
|
||||
rescue Errno::EHOSTUNREACH
|
||||
# multi-homed IPv6 may generate this
|
||||
raise ResolvTimeout
|
||||
end
|
||||
while true
|
||||
before_select = Time.now
|
||||
timeout = timelimit - before_select
|
||||
|
@ -691,7 +696,7 @@ class Resolv
|
|||
rescue DecodeError
|
||||
next # broken DNS message ignored
|
||||
end
|
||||
if s = @senders[[from,msg.id]]
|
||||
if s = sender_for(from, msg)
|
||||
break
|
||||
else
|
||||
# unexpected DNS message ignored
|
||||
|
@ -700,6 +705,10 @@ class Resolv
|
|||
return msg, s.data
|
||||
end
|
||||
|
||||
def sender_for(addr, msg)
|
||||
@senders[[addr,msg.id]]
|
||||
end
|
||||
|
||||
def close
|
||||
socks = @socks
|
||||
@socks = nil
|
||||
|
@ -820,6 +829,22 @@ class Resolv
|
|||
end
|
||||
end
|
||||
|
||||
class MDNSOneShot < UnconnectedUDP # :nodoc:
|
||||
def sender(msg, data, host, port=Port)
|
||||
service = [host, port]
|
||||
id = DNS.allocate_request_id(host, port)
|
||||
request = msg.encode
|
||||
request[0,2] = [id].pack('n')
|
||||
sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
|
||||
return @senders[id] =
|
||||
UnconnectedUDP::Sender.new(request, data, sock, host, port)
|
||||
end
|
||||
|
||||
def sender_for(addr, msg)
|
||||
@senders[msg.id]
|
||||
end
|
||||
end
|
||||
|
||||
class TCP < Requester # :nodoc:
|
||||
def initialize(host, port=Port)
|
||||
super()
|
||||
|
@ -2387,11 +2412,96 @@ class Resolv
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Resolv::MDNS is a one-shot Multicast DNS (mDNS) resolver. It blindly
|
||||
# makes queries to the mDNS addresses without understanding anything about
|
||||
# multicast ports.
|
||||
#
|
||||
# Information taken form the following places:
|
||||
#
|
||||
# * RFC 6762
|
||||
|
||||
class MDNS < DNS
|
||||
|
||||
##
|
||||
# Default mDNS Port
|
||||
|
||||
Port = 5353
|
||||
|
||||
##
|
||||
# Default IPv4 mDNS address
|
||||
|
||||
AddressV4 = '224.0.0.251'
|
||||
|
||||
##
|
||||
# Default IPv6 mDNS address
|
||||
|
||||
AddressV6 = 'ff02::fb'
|
||||
|
||||
##
|
||||
# Default mDNS addresses
|
||||
|
||||
Addresses = [
|
||||
[AddressV4, Port],
|
||||
[AddressV6, Port],
|
||||
]
|
||||
|
||||
##
|
||||
# Creates a new one-shot Multicast DNS (mDNS) resolver.
|
||||
#
|
||||
# +config_info+ can be:
|
||||
#
|
||||
# nil::
|
||||
# Uses the default mDNS addresses
|
||||
#
|
||||
# Hash::
|
||||
# Must contain :nameserver or :nameserver_port like
|
||||
# Resolv::DNS#initialize.
|
||||
|
||||
def initialize(config_info=nil)
|
||||
if config_info then
|
||||
super({ nameserver_port: Addresses }.merge(config_info))
|
||||
else
|
||||
super(nameserver_port: Addresses)
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Iterates over all IP addresses for +name+ retrieved from the mDNS
|
||||
# resolver, provided name ends with "local". If the name does not end in
|
||||
# "local" no records will be returned.
|
||||
#
|
||||
# +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will
|
||||
# be a Resolv::IPv4 or Resolv::IPv6
|
||||
|
||||
def each_address(name)
|
||||
name = Resolv::DNS::Name.create(name)
|
||||
|
||||
return unless name.to_a.last == 'local'
|
||||
|
||||
super(name)
|
||||
end
|
||||
|
||||
def make_udp_requester # :nodoc:
|
||||
nameserver_port = @config.nameserver_port
|
||||
Requester::MDNSOneShot.new(*nameserver_port)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
##
|
||||
# Default resolver to use for Resolv class methods.
|
||||
|
||||
DefaultResolver = self.new
|
||||
|
||||
##
|
||||
# Replaces the resolvers in the default resolver with +new_resolvers+. This
|
||||
# allows resolvers to be changed for resolv-replace.
|
||||
|
||||
def DefaultResolver.replace_resolvers new_resolvers
|
||||
@resolvers = new_resolvers
|
||||
end
|
||||
|
||||
##
|
||||
# Address Regexp to use for matching IP addresses.
|
||||
|
||||
|
|
Loading…
Reference in a new issue