Module: Net::DNS::MDNSSD

Defined in:
lib/net/dns/mdns-sd.rb

Overview

DNS-SD over mDNS

An implementation of DNS Service-Discovery (DNS-SD) using Net::DNS::MDNS.

DNS-SD is described in draft-cheshire-dnsext-dns-sd.txt, see www.dns-sd.org for more information. It is most often seen as part of Apple’s OS X, but is widely useful.

These APIs accept and return a set of arguments which are documented once, here, for convenience.

  • type: DNS-SD classifies services into types using a naming convention. That convention is <_service>.<_protocol>. The underscores (“_”) serve to differentiate from normal DNS names. Protocol is always one of “_tcp” or “_udp”. The service is a short name, see the list at www.dns-sd.org/ServiceTypes.html. A common service is “http”, the type of which would be “_http._tcp”.

  • domain: Services operate in a domain, theoretically. In current practice, that domain is always “local”.

  • name: Service lookup with #browse results in a name of a service of that type. That name is associated with a target (a host name), port, priority, and weight, as well as series of key to value mappings, specific to the service. In practice, priority and weight are widely ignored.

  • fullname: The concatention of the service name (optionally), type, and domain results in a single dot-seperated domain name - the “fullname”. See Util.parse_name for more information about the format.

  • text_record: Service information in the form of key/value pairs. See Util.parse_strings for more information about the format.

  • flags: should return flags, similar to DNSSD, but for now we just return the TTL of the DNS message. A TTL of zero means a deregistration of the record.

Services are advertised and resolved over specific network interfaces. Currently, Net::DNS::MDNS supports only a single default interface, and the interface will always be nil.

Defined Under Namespace

Modules: Util Classes: BrowseReply, RegisterReply, ResolveReply

Class Method Summary collapse

Class Method Details

.browse(type, domain = '.local', *ignored) ⇒ Object

Lookup a service by type and domain.

Yields a BrowseReply as services are found, in a background thread, not the caller’s thread!

Returns a MDNS::BackgroundQuery, call MDNS::BackgroundQuery#stop when you have found all the replies you are interested in.



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/net/dns/mdns-sd.rb', line 74

def self.browse(type, domain = '.local', *ignored) # :yield: BrowseReply
  dnsname = DNS::Name.create(type)
  dnsname << DNS::Name.create(domain)
  dnsname.absolute = true

  q = MDNS::BackgroundQuery.new(dnsname, IN::PTR) do |q, answers|
    answers.each do |an|
      yield BrowseReply.new( an )
    end
  end
  q
end

.register(name, type, domain, port, txt = {}, *ignored) {|RegisterReply.new(name, type, domain)| ... } ⇒ Object

Register a service instance on the local host.

txt is a Hash of String keys to String values.

Because the service name may already be in use on the network, a different name may be registered than that requested. Because of this, if a block is supplied, a RegisterReply will be yielded so that the actual service name registered may be seen.

Returns a MDNS::Service, call MDNS::Service#stop when you no longer want to advertise the service.

NOTE - The service name should be unique on the network, MDNSSD doesn’t currently attempt to ensure this. This will be fixed in an upcoming release.

Yields:



168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/net/dns/mdns-sd.rb', line 168

def self.register(name, type, domain, port, txt = {}, *ignored) # :yields: RegisterReply
  dnsname = DNS::Name.create(name)
  dnsname << DNS::Name.create(type)
  dnsname << DNS::Name.create(domain)
  dnsname.absolute = true

  s = MDNS::Service.new(name, type, port, txt) do |s|
    s.domain = domain
  end

  yield RegisterReply.new(name, type, domain) if block_given?

  s
end

.resolve(name, type, domain = '.local', *ignored) ⇒ Object

Resolve a service instance by name, type and domain.

Yields a ResolveReply as service instances are found, in a background thread, not the caller’s thread!

Returns a MDNS::BackgroundQuery, call MDNS::BackgroundQuery#stop when you have found all the replies you are interested in.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/net/dns/mdns-sd.rb', line 110

def self.resolve(name, type, domain = '.local', *ignored) # :yield: ResolveReply
  dnsname = DNS::Name.create(name)
  dnsname << DNS::Name.create(type)
  dnsname << DNS::Name.create(domain)
  dnsname.absolute = true

  rrs = {}

  q = MDNS::BackgroundQuery.new(dnsname, IN::ANY) do |q, answers|
    _rrs = {}
    answers.each do |an|
      if an.name == dnsname
        _rrs[an.type] = an
      end
    end
    # We queried for ANY, but don't yield unless we got a SRV or TXT.
    if( _rrs[IN::SRV] || _rrs[IN::TXT] )
      rrs.update _rrs

      ansrv, antxt = rrs[IN::SRV], rrs[IN::TXT]

#           puts "ansrv->#{ansrv}"
#           puts "antxt->#{antxt}"

      # Even though we got an SRV or TXT, we can't yield until we have both.
      if ansrv && antxt
        yield ResolveReply.new( ansrv, antxt )
      end
    end
  end
  q
end