dnssd 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,7 +13,7 @@ module DNSSD
13
13
  ##
14
14
  # The version of DNSSD you're using.
15
15
 
16
- VERSION = '2.0.1'
16
+ VERSION = '3.0.0'
17
17
 
18
18
  ##
19
19
  # Registers +socket+ with DNSSD as +name+. If +service+ is omitted it is
@@ -32,7 +32,7 @@ module DNSSD
32
32
 
33
33
  raise ArgumentError, 'socket not bound' if port == 0
34
34
 
35
- service ||= DNSSD.getservbyport port
35
+ service ||= Socket.getservbyport port
36
36
 
37
37
  proto = case socket
38
38
  when TCPSocket then 'tcp'
@@ -65,38 +65,29 @@ module DNSSD
65
65
  ##
66
66
  # Asynchronous version of DNSSD::Service#browse
67
67
 
68
- def self.browse(type, domain = nil, flags = 0,
69
- interface = DNSSD::InterfaceAny, &block)
70
- service = DNSSD::Service.new
71
-
72
- Thread.start do
73
- run(service, :browse, type, domain, flags, interface, &block)
74
- end
75
-
68
+ def self.browse type, domain = nil, flags = 0, interface = DNSSD::InterfaceAny
69
+ service = DNSSD::Service.browse type, domain, flags, interface
70
+ service.async_each { |r| yield r }
76
71
  service
77
72
  end
78
73
 
79
74
  ##
80
75
  # Synchronous version of DNSSD::Service#browse
81
76
 
82
- def self.browse!(type, domain = nil, flags = 0,
83
- interface = DNSSD::InterfaceAny, &block)
84
- service = DNSSD::Service.new
85
-
86
- run(service, :browse, type, domain, flags, interface, &block)
77
+ def self.browse! type, domain = nil, flags = 0, interface = DNSSD::InterfaceAny
78
+ service = DNSSD::Service.browse type, domain, flags, interface
79
+ service.each { |r| yield r }
80
+ ensure
81
+ service.stop
87
82
  end
88
83
 
89
84
  ##
90
85
  # Asynchronous version of DNSSD::Service#enumerate_domains
91
86
 
92
- def self.enumerate_domains(flags = DNSSD::Flags::BrowseDomains,
93
- interface = DNSSD::InterfaceAny, &block)
94
- service = DNSSD::Service.new
95
-
96
- Thread.start do
97
- run(service, :enumerate_domains, flags, interface, &block)
98
- end
99
-
87
+ def self.enumerate_domains flags = DNSSD::Flags::BrowseDomains,
88
+ interface = DNSSD::InterfaceAny
89
+ service = DNSSD::Service.enumerate_domains flags, interface
90
+ service.async_each { |r| yield r }
100
91
  service
101
92
  end
102
93
 
@@ -105,27 +96,21 @@ module DNSSD
105
96
 
106
97
  def self.enumerate_domains!(flags = DNSSD::Flags::BrowseDomains,
107
98
  interface = DNSSD::InterfaceAny, &block)
108
- service = DNSSD::Service.new
109
-
110
- run(service, :enumerate_domains, flags, interface, &block)
99
+ service = DNSSD::Service.enumerate_domains flags, interface
100
+ service.each { |r| yield r }
101
+ ensure
102
+ service.stop
111
103
  end
112
104
 
113
105
  ##
114
106
  # Asynchronous version of DNSSD::Service#register
115
107
 
116
108
  def self.register(name, type, domain, port, text_record = nil, flags = 0,
117
- interface = DNSSD::InterfaceAny, &block)
118
- service = DNSSD::Service.new
119
-
120
- if block_given? then
121
- Thread.start do
122
- run(service, :register, name, type, domain, port, nil, text_record,
123
- flags, interface, &block)
124
- end
125
- else
126
- service.register name, type, domain, port, nil, text_record, flags,
127
- interface
128
- end
109
+ interface = DNSSD::InterfaceAny)
110
+ service = DNSSD::Service.register name, type, domain, port, nil,
111
+ text_record, flags, interface
112
+
113
+ service.async_each { |r| yield r } if block_given?
129
114
 
130
115
  service
131
116
  end
@@ -135,53 +120,32 @@ module DNSSD
135
120
 
136
121
  def self.register!(name, type, domain, port, text_record = nil, flags = 0,
137
122
  interface = DNSSD::InterfaceAny, &block)
138
- service = DNSSD::Service.new
139
-
140
- if block_given? then
141
- run(service, :register, name, type, domain, port, nil, text_record, flags,
142
- interface, &block)
143
- else
144
- service.register name, type, domain, port, nil, text_record, flags,
145
- interface
146
- end
123
+ service = DNSSD::Service.register name, type, domain, port, nil,
124
+ text_record, flags, interface
147
125
 
148
- service
126
+ service.each { |r| yield r } if block_given?
127
+ ensure
128
+ service.stop
149
129
  end
150
130
 
151
131
  ##
152
132
  # Asynchronous version of DNSSD::Service#resolve
153
133
 
154
- def self.resolve(*args, &block)
155
- service = DNSSD::Service.new
156
-
157
- Thread.start do
158
- run(service, :resolve, *args, &block)
159
- end
160
-
134
+ def self.resolve(*args)
135
+ service = DNSSD::Service.resolve(*args)
136
+ service.async_each { |r| yield r }
161
137
  service
162
138
  end
163
139
 
164
140
  ##
165
141
  # Synchronous version of DNSSD::Service#resolve
166
142
 
167
- def self.resolve!(*args, &block)
168
- service = DNSSD::Service.new
169
-
170
- run(service, :resolve, *args, &block)
171
- end
172
-
173
- ##
174
- # Dispatches +args+ and +block+ to +method+ on +service+ and ensures
175
- # +service+ is shut down after use.
176
-
177
- def self.run(service, method, *args, &block)
178
- service.send(method, *args, &block)
179
-
180
- service
143
+ def self.resolve!(*args)
144
+ service = DNSSD::Service.resolve(*args)
145
+ service.each { |r| yield r }
181
146
  ensure
182
- service.stop unless service.stopped?
147
+ service.stop if service
183
148
  end
184
-
185
149
  end
186
150
 
187
151
  require 'socket'
@@ -34,7 +34,7 @@ class DNSSD::Reply::Browse < DNSSD::Reply
34
34
  def connect(family = Socket::AF_UNSPEC, addrinfo_flags = 0)
35
35
  value = nil
36
36
 
37
- DNSSD.resolve! self do |reply|
37
+ DNSSD.resolve! name, type, domain do |reply|
38
38
  value = reply
39
39
  break
40
40
  end
@@ -42,11 +42,14 @@ class DNSSD::Reply::Browse < DNSSD::Reply
42
42
  value.connect family, addrinfo_flags
43
43
  end
44
44
 
45
+ def resolve
46
+ service = DNSSD::Service.resolve name, type, domain
47
+ service.first
48
+ end
49
+
45
50
  def inspect # :nodoc:
46
51
  "#<%s:0x%x %p interface: %s flags: %p>" % [
47
52
  self.class, object_id, fullname, interface_name, @flags
48
53
  ]
49
54
  end
50
-
51
55
  end
52
-
@@ -178,6 +178,4 @@ class DNSSD::Reply::QueryRecord < DNSSD::Reply
178
178
  fullname, ttl, record_class_name, record_type_name, record_data
179
179
  ]
180
180
  end
181
-
182
181
  end
183
-
@@ -27,6 +27,11 @@ class DNSSD::Reply::Register < DNSSD::Reply
27
27
  set_names name, type, domain
28
28
  end
29
29
 
30
+ def resolve
31
+ service = DNSSD::Service.resolve name, type, domain
32
+ service.first
33
+ end
34
+
30
35
  def inspect # :nodoc:
31
36
  "#<%s:0x%x %p flags: %p>" % [
32
37
  self.class, object_id, fullname, @flags
@@ -63,10 +63,10 @@ class DNSSD::Reply::Resolve < DNSSD::Reply
63
63
  else raise ArgumentError, "invalid family #{family}"
64
64
  end
65
65
 
66
- service = DNSSD::Service.new
66
+ service = DNSSD::Service.getaddrinfo target, addrinfo_protocol,
67
+ addrinfo_flags, @interface
67
68
 
68
- service.getaddrinfo target, addrinfo_protocol, addrinfo_flags,
69
- @interface do |addrinfo|
69
+ service.each do |addrinfo|
70
70
  address = addrinfo.address
71
71
 
72
72
  begin
@@ -80,6 +80,7 @@ class DNSSD::Reply::Resolve < DNSSD::Reply
80
80
  socket.connect address, port
81
81
  end
82
82
 
83
+ service.stop
83
84
  return socket
84
85
  rescue
85
86
  next if addrinfo.flags.more_coming?
@@ -8,35 +8,42 @@ require 'thread'
8
8
  # DNSSD::Service provides the raw DNS-SD functions via the +_+ variants.
9
9
 
10
10
  class DNSSD::Service
11
+ include Enumerable
11
12
 
12
13
  # :stopdoc:
13
14
  IPv4 = 1 unless const_defined? :IPv4
14
15
  IPv6 = 2 unless const_defined? :IPv6
15
16
  # :startdoc:
16
17
 
18
+ class << self; private :new; end
19
+
17
20
  ##
18
21
  # Creates a new DNSSD::Service
19
22
 
20
23
  def initialize
21
- @replies = []
24
+ @replies = []
22
25
  @continue = true
23
- @thread = nil
24
- @type = nil
26
+ @thread = nil
27
+ @lock = Mutex.new
25
28
  end
26
29
 
27
- ##
28
- # Adds an extra DNS record of +type+ containing +data+. +ttl+ is in
29
- # seconds, use 0 for the default value. +flags+ are currently ignored.
30
- #
31
- # Must be called on a service only after #register.
32
- #
33
- # Returns the added DNSSD::Record
30
+ class Register < ::DNSSD::Service
31
+ def initialize
32
+ super
33
+ @records = []
34
+ end
34
35
 
35
- def add_record(type, data, ttl = 0, flags = 0)
36
- raise TypeError, 'must be called after register' unless @type == :register
37
- @records ||= []
36
+ ##
37
+ # Adds an extra DNS record of +type+ containing +data+. +ttl+ is in
38
+ # seconds, use 0 for the default value. +flags+ are currently ignored.
39
+ #
40
+ # Must be called on a service only after #register.
41
+ #
42
+ # Returns the added DNSSD::Record
38
43
 
39
- _add_record flags.to_i, type, data, ttl
44
+ def add_record type, data, ttl = 0, flags = 0
45
+ @records << _add_record(flags.to_i, type, data, ttl)
46
+ end
40
47
  end
41
48
 
42
49
  ##
@@ -52,56 +59,77 @@ class DNSSD::Service
52
59
  # rescue Timeout::Error
53
60
  # end
54
61
 
55
- def browse(type, domain = nil, flags = 0, interface = DNSSD::InterfaceAny,
56
- &block)
62
+ def self.browse type, domain = nil, flags = 0, interface = DNSSD::InterfaceAny
57
63
  check_domain domain
58
64
  interface = DNSSD.interface_index interface unless Integer === interface
59
65
 
60
- raise DNSSD::Error, 'service in progress' if started?
66
+ _browse flags.to_i, interface, type, domain
67
+ end
61
68
 
62
- @type = :browse
69
+ def each timeout = :never
70
+ raise DNSSD::Error, 'already stopped' unless @continue
63
71
 
64
- _browse flags.to_i, interface, type, domain
72
+ return enum_for __method__, timeout unless block_given?
73
+
74
+ io = IO.new ref_sock_fd
75
+ rd = [io]
76
+
77
+ start_at = clock_time
78
+
79
+ while @continue
80
+ break unless timeout == :never || clock_time - start_at < timeout
65
81
 
66
- process(&block)
82
+ if IO.select rd, nil, nil, 1
83
+ begin
84
+ process_result
85
+ rescue DNSSD::UnknownError
86
+ end
87
+ @replies.each { |r| yield r }
88
+ @replies.clear
89
+ end
90
+ end
91
+ end
92
+
93
+ def async_each timeout = :never
94
+ @lock.synchronize do
95
+ raise DNSSD::Error, 'already stopped' unless @continue
96
+ @thread = Thread.new { each(timeout) { |r| yield r } }
97
+ end
98
+ end
99
+
100
+ def push record
101
+ @replies << record
67
102
  end
68
103
 
69
104
  ##
70
105
  # Raises an ArgumentError if +domain+ is too long including NULL terminator
71
106
  # and trailing '.'
72
107
 
73
- def check_domain(domain)
108
+ def self.check_domain(domain)
74
109
  return unless domain
75
110
  raise ArgumentError, 'domain name string is too long' if
76
111
  domain.length >= MAX_DOMAIN_NAME - 1
77
112
  end
78
113
 
114
+
79
115
  ##
80
116
  # Enumerate domains available for browsing and registration.
81
117
  #
82
118
  # For each domain found a DNSSD::Reply object is passed to block with
83
119
  # #domain set to the enumerated domain.
84
120
  #
85
- # available_domains = []
86
- #
87
- # service.enumerate_domains! do |r|
88
- # available_domains << r.domain
121
+ # service = DNSSD::Service.enumerate_domains
122
+ #
123
+ # service.each do |r|
124
+ # p r.domain
89
125
  # break unless r.flags.more_coming?
90
126
  # end
91
- #
92
- # p available_domains
93
127
 
94
- def enumerate_domains(flags = DNSSD::Flags::BrowseDomains,
128
+ def self.enumerate_domains(flags = DNSSD::Flags::BrowseDomains,
95
129
  interface = DNSSD::InterfaceAny, &block)
96
130
  interface = DNSSD.interface_index interface unless Integer === interface
97
131
 
98
- raise DNSSD::Error, 'service in progress' if started?
99
-
100
132
  _enumerate_domains flags.to_i, interface
101
-
102
- @type = :enumerate_domains
103
-
104
- process(&block)
105
133
  end
106
134
 
107
135
  ##
@@ -117,18 +145,12 @@ class DNSSD::Service
117
145
  # setup your /etc/nsswitch.conf correctly. See
118
146
  # http://avahi.org/wiki/AvahiAndUnicastDotLocal for details
119
147
 
120
- def getaddrinfo(host, protocol = 0, flags = 0,
148
+ def self.getaddrinfo(host, protocol = 0, flags = 0,
121
149
  interface = DNSSD::InterfaceAny, &block)
122
150
  interface = DNSSD.interface_index interface unless Integer === interface
123
151
 
124
- if respond_to? :_getaddrinfo then
125
- raise DNSSD::Error, 'service in progress' if started?
126
-
152
+ if respond_to? :_getaddrinfo, true then
127
153
  _getaddrinfo flags.to_i, interface, protocol, host
128
-
129
- @type = :getaddrinfo
130
-
131
- process(&block)
132
154
  else
133
155
  family = case protocol
134
156
  when IPv4 then Socket::AF_INET
@@ -138,43 +160,15 @@ class DNSSD::Service
138
160
 
139
161
  addrinfo = Socket.getaddrinfo host, nil, family
140
162
 
141
- addrinfo.each do |_, _, a_host, ip, _|
163
+ list = addrinfo.map do |_, _, a_host, ip, _|
142
164
  sockaddr = Socket.pack_sockaddr_in 0, ip
143
- @replies << DNSSD::Reply::AddrInfo.new(self, 0, 0, a_host, sockaddr, 0)
165
+ DNSSD::Reply::AddrInfo.new(self, 0, 0, a_host, sockaddr, 0)
144
166
  end
167
+ def list.stop; end
168
+ list
145
169
  end
146
170
  end
147
171
 
148
- def inspect # :nodoc:
149
- stopped = stopped? ? 'stopped' : 'running'
150
- "#<%s:0x%x %s>" % [self.class, object_id, stopped]
151
- end
152
-
153
- ##
154
- # Yields results from the mDNS daemon, blocking until data is available.
155
- # Use break or return when you wish to stop receiving results.
156
- #
157
- # The service is automatically stopped after calling this method.
158
-
159
- def process # :yields: DNSSD::Result
160
- @thread = Thread.current
161
-
162
- while @continue do
163
- _process if @replies.empty?
164
- yield @replies.shift until @replies.empty?
165
- end
166
-
167
- @thread = nil
168
-
169
- self
170
- rescue DNSSD::ServiceNotRunningError
171
- # raised when we jump out of DNSServiceProcess() while it's waiting for a
172
- # response
173
- self
174
- ensure
175
- stop unless stopped?
176
- end
177
-
178
172
  ##
179
173
  # Retrieves an arbitrary DNS record
180
174
  #
@@ -189,17 +183,11 @@ class DNSSD::Service
189
183
  # p record
190
184
  # end
191
185
 
192
- def query_record(fullname, record_type, record_class = DNSSD::Record::IN,
193
- flags = 0, interface = DNSSD::InterfaceAny, &block)
186
+ def self.query_record(fullname, record_type, record_class = DNSSD::Record::IN,
187
+ flags = 0, interface = DNSSD::InterfaceAny)
194
188
  interface = DNSSD.interface_index interface unless Integer === interface
195
189
 
196
- raise DNSSD::Error, 'service in progress' if started?
197
-
198
190
  _query_record flags.to_i, interface, fullname, record_type, record_class
199
-
200
- @type = :query_record
201
-
202
- process(&block)
203
191
  end
204
192
 
205
193
  ##
@@ -210,20 +198,13 @@ class DNSSD::Service
210
198
  # puts "successfully registered: #{r.inspect}"
211
199
  # end
212
200
 
213
- def register(name, type, domain, port, host = nil, text_record = nil,
214
- flags = 0, interface = DNSSD::InterfaceAny, &block)
201
+ def self.register(name, type, domain, port, host = nil, text_record = nil,
202
+ flags = 0, interface = DNSSD::InterfaceAny)
215
203
  check_domain domain
216
204
  interface = DNSSD.interface_index interface unless Integer === interface
217
205
  text_record = text_record.encode if text_record
218
206
 
219
- raise DNSSD::Error, 'service in progress' if started?
220
-
221
- _register flags.to_i, interface, name, type, domain, host, port,
222
- text_record, &block
223
-
224
- @type = :register
225
-
226
- process(&block) if block
207
+ _register flags.to_i, interface, name, type, domain, host, port, text_record
227
208
  end
228
209
 
229
210
  ##
@@ -242,27 +223,39 @@ class DNSSD::Service
242
223
  # p r
243
224
  # end
244
225
 
245
- def resolve(name, type = name.type, domain = name.domain, flags = 0,
246
- interface = DNSSD::InterfaceAny, &block)
226
+ def self.resolve(name, type = name.type, domain = name.domain, flags = 0,
227
+ interface = DNSSD::InterfaceAny)
247
228
  name = name.name if DNSSD::Reply === name
248
229
  check_domain domain
249
230
  interface = DNSSD.interface_index interface unless Integer === interface
250
231
 
251
- raise DNSSD::Error, 'service in progress' if started?
252
-
253
232
  _resolve flags.to_i, interface, name, type, domain
254
-
255
- @type = :resolve
256
-
257
- process(&block)
258
233
  end
259
234
 
260
235
  ##
261
236
  # Returns true if the service has been started.
262
237
 
263
238
  def started?
264
- not stopped?
239
+ @continue
265
240
  end
266
241
 
267
- end
242
+ def stop
243
+ raise DNSSD::Error, 'service is already stopped' unless started?
244
+ @continue = false
245
+ @thread.join if @thread
246
+ _stop
247
+ self
248
+ end
268
249
 
250
+ private
251
+
252
+ if defined? Process::CLOCK_MONOTONIC
253
+ def clock_time
254
+ Process.clock_gettime Process::CLOCK_MONOTONIC
255
+ end
256
+ else
257
+ def clock_time
258
+ Time.now
259
+ end
260
+ end
261
+ end