zeroconf 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39d1c369a77bb16908b77e600e166c264662ec1fc624de8aee2f62fc752e3aae
4
- data.tar.gz: 6f58a84ef9926d9e900182390249b6b029312332a7376cc1f1229b182812bb59
3
+ metadata.gz: 7f58175fb721fb08fa2a5abb36b0b2165d9b38592bb7ff66bd3a3f4c303ed2f9
4
+ data.tar.gz: afd32fb72b31c90e84aaea02db2f81e603b872f8f81c1f6f147d15c13ce3713e
5
5
  SHA512:
6
- metadata.gz: 5a515ce4490d93f37439bec362b84a6bb99c4d42098892f8250d9059537984c9ac6f0c90e9cbf005374f0fdb9abd0a78cb4fd2f7b54e87e05f8acce6eee892cb
7
- data.tar.gz: be3a38c8bfab29934aca1d2d1100fa4fdda4aa7bfc8c31fe095a461337cffc67b44ac1d982c2faf8f6131891c9eee1a9d444932fa5899b353b0f12e9b8968210
6
+ metadata.gz: 2e4faed4b18775a5fec2faf0b4064556356699b049c6ca1d6d2d4c03b685cd8702e3ba8591d098799d3ec6ee54efdb9aee1f0e5ea68578b92c1df7ea8fbbba7b
7
+ data.tar.gz: 210e338f7d21bbe98df962e4785e0716e2364e538fb44c1029217465fca0fe6ea2f414986d4bb7ce0f3588efd5bfbbd8caeb140ef5f1028b5e75b58648de57e6
data/README.md CHANGED
@@ -108,12 +108,14 @@ to run an HTTP server and simultaneously advertise the server:
108
108
 
109
109
  ```ruby
110
110
  require "zeroconf"
111
- require 'webrick'
111
+ require "webrick"
112
112
 
113
113
  port = 8080
114
114
  host = "test-hostname"
115
115
 
116
- Thread.new { ZeroConf.service "_http._tcp.local.", port, host }
116
+ Ractor.new(port, host) { |port, host|
117
+ ZeroConf.service "_http._tcp.local.", port, host
118
+ }
117
119
 
118
120
  server = WEBrick::HTTPServer.new(:Port => port,
119
121
  :SSLEnable => false,
@@ -14,7 +14,7 @@ module ZeroConf
14
14
  end
15
15
 
16
16
  def run timeout: 3
17
- sockets = open_interfaces interfaces.map(&:addr), Resolv::MDNS::Port
17
+ sockets = open_interfaces interfaces.map(&:addr), 0
18
18
 
19
19
  query = get_query
20
20
  sockets.each { |socket| multicast_send(socket, query.encode) }
@@ -7,15 +7,24 @@ module ZeroConf
7
7
  include Utils
8
8
 
9
9
  attr_reader :service, :service_port, :hostname, :service_interfaces,
10
- :service_name, :qualified_host, :text
10
+ :service_name, :qualified_host, :text, :abort_on_malformed_requests
11
11
 
12
- def initialize service, service_port, hostname = Socket.gethostname, service_interfaces: ZeroConf.service_interfaces, text: [""]
12
+ def initialize service, service_port, hostname = Socket.gethostname, service_interfaces: ZeroConf.service_interfaces, instance_name: nil, text: [""], abort_on_malformed_requests: false, started_callback: nil
13
13
  @service = service
14
14
  @service_port = service_port
15
- @hostname = hostname
15
+
16
+ @hostname = strip_dot_local(hostname) # We re-add .local anyway, later on
16
17
  @service_interfaces = service_interfaces
17
- @service_name = "#{hostname}.#{service}"
18
- @qualified_host = "#{hostname}.local."
18
+ @abort_on_malformed_requests = abort_on_malformed_requests
19
+
20
+ instance_name ||= @hostname
21
+ if instance_name.include?(".")
22
+ raise ArgumentError, "instance_name must not contain dots (is #{instance_name.inspect})"
23
+ end
24
+
25
+ @service_name = "#{instance_name}.#{@service}"
26
+ @qualified_host = "#{@hostname}.local."
27
+ @started_callback = started_callback
19
28
  @text = text
20
29
  @started = false
21
30
  @rd, @wr = IO.pipe
@@ -88,6 +97,7 @@ module ZeroConf
88
97
  end
89
98
 
90
99
  def stop
100
+ return unless @started
91
101
  @wr.write "x"
92
102
  @wr.close
93
103
  @started = false
@@ -104,16 +114,27 @@ module ZeroConf
104
114
  multicast_send(sock, msg.encode)
105
115
 
106
116
  @started = true
117
+ @started_callback&.call
107
118
 
108
119
  loop do
109
120
  readers, = IO.select(sockets, [], [])
110
121
  next unless readers
111
122
 
112
123
  readers.each do |reader|
113
- return if reader == @rd
124
+ if reader == @rd
125
+ @rd.close
126
+ return
127
+ end
114
128
 
115
129
  buf, from = reader.recvfrom 2048
116
- msg = Resolv::DNS::Message.decode(buf)
130
+ msg = begin
131
+ Resolv::DNS::Message.decode(buf)
132
+ rescue Resolv::DNS::DecodeError
133
+ next unless abort_on_malformed_requests
134
+ @rd.close
135
+ stop
136
+ raise
137
+ end
117
138
 
118
139
  has_flags = (buf.getbyte(3) << 8 | buf.getbyte(2)) != 0
119
140
 
@@ -122,9 +143,7 @@ module ZeroConf
122
143
 
123
144
  break unless class_type == 1 || class_type == 255
124
145
 
125
- legacy = from[1] != Resolv::MDNS::Port
126
- unicast = legacy || type::ClassValue & PTR::MDNS_UNICAST_RESPONSE > 0
127
- reply_id = legacy ? msg.id : 0
146
+ unicast = type::ClassValue & PTR::MDNS_UNICAST_RESPONSE > 0
128
147
 
129
148
  qn = name.to_s + "."
130
149
 
@@ -133,25 +152,25 @@ module ZeroConf
133
152
  break if has_flags
134
153
 
135
154
  if unicast
136
- dnssd_unicast_answer(id: reply_id, legacy: legacy)
155
+ dnssd_unicast_answer
137
156
  else
138
157
  dnssd_multicast_answer
139
158
  end
140
159
  when service
141
160
  if unicast
142
- service_unicast_answer(id: reply_id, legacy: legacy)
161
+ service_unicast_answer
143
162
  else
144
163
  service_multicast_answer
145
164
  end
146
165
  when service_name
147
166
  if unicast
148
- service_instance_unicast_answer(id: reply_id, legacy: legacy)
167
+ service_instance_unicast_answer
149
168
  else
150
169
  service_instance_multicast_answer
151
170
  end
152
171
  when qualified_host
153
172
  if unicast
154
- name_answer_unicast(id: reply_id, legacy: legacy)
173
+ name_answer_unicast
155
174
  else
156
175
  name_answer_multicast
157
176
  end
@@ -178,11 +197,10 @@ module ZeroConf
178
197
 
179
198
  private
180
199
 
181
- def service_instance_unicast_answer(id:, legacy:)
200
+ def service_instance_unicast_answer
182
201
  msg = Resolv::DNS::Message.new(0)
183
202
  msg.qr = 1
184
203
  msg.aa = 1
185
- msg.id = id
186
204
 
187
205
  service_interfaces.each do |iface|
188
206
  if iface.addr.ipv4?
@@ -202,16 +220,15 @@ module ZeroConf
202
220
  Resolv::DNS::Resource::IN::TXT.new(*@text)
203
221
  end
204
222
  msg.add_answer service_name, 10, Resolv::DNS::Resource::IN::SRV.new(0, 0, service_port, qualified_host)
205
- msg.add_question service_name, legacy ? Resolv::DNS::Resource::IN::SRV : MDNS::Announce::IN::SRV
223
+ msg.add_question service_name, MDNS::Announce::IN::SRV
206
224
 
207
225
  msg
208
226
  end
209
227
 
210
- def service_unicast_answer(id:, legacy:)
228
+ def service_unicast_answer
211
229
  msg = Resolv::DNS::Message.new(0)
212
230
  msg.qr = 1
213
231
  msg.aa = 1
214
- msg.id = id
215
232
 
216
233
  msg.add_additional service_name, 10, Resolv::DNS::Resource::IN::SRV.new(0, 0, service_port, qualified_host)
217
234
 
@@ -237,21 +254,20 @@ module ZeroConf
237
254
  10,
238
255
  Resolv::DNS::Resource::IN::PTR.new(Resolv::DNS::Name.create(service_name))
239
256
 
240
- msg.add_question service, legacy ? Resolv::DNS::Resource::IN::PTR : PTR
257
+ msg.add_question service, PTR
241
258
 
242
259
  msg
243
260
  end
244
261
 
245
- def dnssd_unicast_answer(id:, legacy:)
262
+ def dnssd_unicast_answer
246
263
  msg = Resolv::DNS::Message.new(0)
247
264
  msg.qr = 1
248
265
  msg.aa = 1
249
- msg.id = id
250
266
 
251
267
  msg.add_answer DISCOVERY_NAME, 10,
252
268
  Resolv::DNS::Resource::IN::PTR.new(Resolv::DNS::Name.create(service))
253
269
 
254
- msg.add_question DISCOVERY_NAME, legacy ? Resolv::DNS::Resource::IN::PTR : PTR
270
+ msg.add_question DISCOVERY_NAME, PTR
255
271
  msg
256
272
  end
257
273
 
@@ -325,11 +341,10 @@ module ZeroConf
325
341
  msg
326
342
  end
327
343
 
328
- def name_answer_unicast(id:, legacy:)
344
+ def name_answer_unicast
329
345
  msg = Resolv::DNS::Message.new(0)
330
346
  msg.qr = 1
331
347
  msg.aa = 1
332
- msg.id = id
333
348
 
334
349
  first = true
335
350
 
@@ -358,7 +373,7 @@ module ZeroConf
358
373
  end
359
374
  end
360
375
 
361
- msg.add_question qualified_host, legacy ? Resolv::DNS::Resource::IN::A : MDNS::Announce::IN::A
376
+ msg.add_question qualified_host, MDNS::Announce::IN::A
362
377
 
363
378
  if @text
364
379
  msg.add_additional service_name,
@@ -4,7 +4,6 @@ require "socket"
4
4
  require "ipaddr"
5
5
  require "fcntl"
6
6
  require "resolv"
7
- require "rbconfig"
8
7
 
9
8
  module ZeroConf
10
9
  MDNS_CACHE_FLUSH = 0x8000
@@ -58,7 +57,7 @@ module ZeroConf
58
57
  def open_ipv4 saddr, port
59
58
  sock = UDPSocket.new Socket::AF_INET
60
59
  sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
61
- sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, true) unless RbConfig::CONFIG["host_os"].include?("linux")
60
+ sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, true)
62
61
  sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, true)
63
62
  sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_LOOP, true)
64
63
  sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP,
@@ -70,8 +69,8 @@ module ZeroConf
70
69
  sock
71
70
  end
72
71
 
73
- BROADCAST_V4 = Addrinfo.new Socket.sockaddr_in(Resolv::MDNS::Port, Resolv::MDNS::AddressV4)
74
- BROADCAST_V6 = Addrinfo.new Socket.sockaddr_in(Resolv::MDNS::Port, Resolv::MDNS::AddressV6)
72
+ BROADCAST_V4 = Addrinfo.new(Socket.sockaddr_in(Resolv::MDNS::Port, Resolv::MDNS::AddressV4)).freeze
73
+ BROADCAST_V6 = Addrinfo.new(Socket.sockaddr_in(Resolv::MDNS::Port, Resolv::MDNS::AddressV6)).freeze
75
74
 
76
75
  def multicast_send sock, query
77
76
  dest = if sock.local_address.ipv4?
@@ -95,10 +94,14 @@ module ZeroConf
95
94
  sock.send(data, 0, Addrinfo.new(to))
96
95
  end
97
96
 
97
+ def strip_dot_local(from_string)
98
+ from_string.to_s.gsub(/\.local\.?$/, "")
99
+ end
100
+
98
101
  def open_ipv6 saddr, port
99
102
  sock = UDPSocket.new Socket::AF_INET6
100
103
  sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
101
- sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, true) unless RbConfig::CONFIG["host_os"].include?("linux")
104
+ sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, true)
102
105
  sock.setsockopt(Socket::IPPROTO_IPV6, Socket::IPV6_MULTICAST_HOPS, true)
103
106
  sock.setsockopt(Socket::IPPROTO_IPV6, Socket::IPV6_MULTICAST_LOOP, true)
104
107
 
@@ -1,3 +1,3 @@
1
1
  module ZeroConf
2
- VERSION = "1.0.1"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/zeroconf.rb CHANGED
@@ -67,8 +67,8 @@ module ZeroConf
67
67
  resolver.run(timeout:, &blk)
68
68
  end
69
69
 
70
- def self.service service, service_port, hostname = Socket.gethostname, service_interfaces: self.service_interfaces, text: [""]
71
- s = Service.new(service, service_port, hostname, service_interfaces:, text:)
70
+ def self.service ...
71
+ s = Service.new(...)
72
72
  s.start
73
73
  end
74
74
 
data/test/client_test.rb CHANGED
@@ -10,9 +10,10 @@ module ZeroConf
10
10
  end
11
11
 
12
12
  def test_resolve
13
- s = make_server iface, "coolhostname"
13
+ latch = Queue.new
14
+ s = make_server iface, "coolhostname", started_callback: -> { latch << :start }
14
15
  runner = Thread.new { s.start }
15
- Thread.pass until s.started?
16
+ latch.pop
16
17
  found = nil
17
18
 
18
19
  name = "coolhostname.local"
@@ -33,9 +34,10 @@ module ZeroConf
33
34
  end
34
35
 
35
36
  def test_resolve_returns_early
36
- s = make_server iface, "coolhostname"
37
+ latch = Queue.new
38
+ s = make_server iface, "coolhostname", started_callback: -> { latch << :start }
37
39
  runner = Thread.new { s.start }
38
- Thread.pass until s.started?
40
+ latch.pop
39
41
  found = nil
40
42
 
41
43
  name = "coolhostname.local"
@@ -57,9 +59,10 @@ module ZeroConf
57
59
  end
58
60
 
59
61
  def test_discover_works
60
- s = make_server iface
62
+ latch = Queue.new
63
+ s = make_server iface, started_callback: -> { latch << :start }
61
64
  runner = Thread.new { s.start }
62
- Thread.pass until s.started?
65
+ latch.pop
63
66
  found = nil
64
67
 
65
68
  took = time_it do
@@ -78,9 +81,10 @@ module ZeroConf
78
81
  end
79
82
 
80
83
  def test_discover_return_early
81
- s = make_server iface
84
+ latch = Queue.new
85
+ s = make_server iface, started_callback: -> { latch << :start }
82
86
  runner = Thread.new { s.start }
83
- Thread.pass until s.started?
87
+ latch.pop
84
88
  found = nil
85
89
 
86
90
  took = time_it do
@@ -99,9 +103,10 @@ module ZeroConf
99
103
  end
100
104
 
101
105
  def test_browse
102
- s = make_server iface
106
+ latch = Queue.new
107
+ s = make_server iface, started_callback: -> { latch << :start }
103
108
  runner = Thread.new { s.start }
104
- Thread.pass until s.started?
109
+ latch.pop
105
110
  found = nil
106
111
 
107
112
  took = time_it do
@@ -121,9 +126,10 @@ module ZeroConf
121
126
  end
122
127
 
123
128
  def test_browse_returns_early
124
- s = make_server iface
129
+ latch = Queue.new
130
+ s = make_server iface, started_callback: -> { latch << :start }
125
131
  runner = Thread.new { s.start }
126
- Thread.pass until s.started?
132
+ latch.pop
127
133
  found = nil
128
134
 
129
135
  took = time_it do
data/test/helper.rb CHANGED
@@ -39,16 +39,18 @@ module ZeroConf
39
39
  Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
40
40
  end
41
41
 
42
- def make_server iface, host = HOST_NAME
42
+ def make_server iface, host = HOST_NAME, **opts
43
43
  Service.new SERVICE + ".",
44
44
  42424,
45
45
  host,
46
- service_interfaces: [iface], text: ["test=1", "other=value"]
46
+ service_interfaces: [iface], text: ["test=1", "other=value"],
47
+ **opts
47
48
  end
48
49
 
49
- def make_listener rd, q
50
+ def make_listener rd, q, started_callback: nil
50
51
  Thread.new do
51
52
  sock = open_ipv4 Addrinfo.new(Socket.sockaddr_in(Resolv::MDNS::Port, Socket::INADDR_ANY)), Resolv::MDNS::Port
53
+ started_callback&.call
52
54
  Thread.current[:started] = true
53
55
  loop do
54
56
  readers, = IO.select([sock, rd])
data/test/service_test.rb CHANGED
@@ -26,44 +26,45 @@ module ZeroConf
26
26
  assert_equal [""], s.text
27
27
  end
28
28
 
29
- def test_unicast_service_instance_answer
30
- s = make_server iface
31
- runner = Thread.new { s.start }
32
- Thread.pass until s.started?
33
-
34
- query = Resolv::DNS::Message.new 10
35
- query.add_question "tc-lan-adapter._test-mdns._tcp.local.", SRV
36
-
37
- sock = open_ipv4 iface.addr, Resolv::MDNS::Port
38
- multicast_send sock, query.encode
39
- res = Resolv::DNS::Message.decode read_with_timeout(sock).first
40
- s.stop
41
- runner.join
29
+ def test_raises_when_creating_a_service_with_dot_in_the_name
30
+ assert_raises ArgumentError do
31
+ Service.new "_test-mdns._tcp.local.", 42424,
32
+ "some.subdomain.workstation"
33
+ end
42
34
 
43
- expected = Resolv::DNS::Message.new(0)
44
- expected.qr = 1
45
- expected.aa = 1
35
+ assert_raises ArgumentError do
36
+ Service.new "_test-mdns._tcp.local.", 42424,
37
+ "ruby-mdns", instance_name: "ruby.test"
38
+ end
39
+ end
46
40
 
47
- expected.add_additional s.qualified_host,
48
- 10,
49
- Resolv::DNS::Resource::IN::A.new(iface.addr.ip_address)
41
+ def test_sets_correct_service_name_from_instance_name
42
+ s = Service.new "_test-mdns._tcp.local.", 42424,
43
+ "my-rb-service", instance_name: "My RB service"
44
+ assert_equal "my-rb-service.local.", s.qualified_host
45
+ assert_equal "My RB service._test-mdns._tcp.local.", s.service_name
46
+ end
50
47
 
51
- expected.add_additional s.service_name,
52
- 10,
53
- Resolv::DNS::Resource::IN::TXT.new(*s.text)
54
- expected.add_answer s.service_name, 10, Resolv::DNS::Resource::IN::SRV.new(0, 0, s.service_port, s.qualified_host)
55
- expected.add_question s.service_name, MDNS::Announce::IN::SRV
48
+ def test_removes_dot_local_tld_from_passed_hostname
49
+ s = Service.new "_test-mdns._tcp.local.", 42424,
50
+ "ThisMac.local"
51
+ assert_equal "ThisMac.local.", s.qualified_host
52
+ assert_equal "ThisMac._test-mdns._tcp.local.", s.service_name
56
53
 
57
- assert_equal expected, res
54
+ s = Service.new "_test-mdns._tcp.local.", 42424,
55
+ "ThisMac.local."
56
+ assert_equal "ThisMac.local.", s.qualified_host
57
+ assert_equal "ThisMac._test-mdns._tcp.local.", s.service_name
58
58
  end
59
59
 
60
- def test_legacy_unicast_service_instance_answer
61
- s = make_server iface
60
+ def test_unicast_service_instance_answer
61
+ latch = Queue.new
62
+ s = make_server iface, started_callback: -> { latch << :start }
62
63
  runner = Thread.new { s.start }
63
- Thread.pass until s.started?
64
+ latch.pop
64
65
 
65
- query = Resolv::DNS::Message.new 10
66
- query.add_question "tc-lan-adapter._test-mdns._tcp.local.", Resolv::DNS::Resource::IN::SRV
66
+ query = Resolv::DNS::Message.new 0
67
+ query.add_question "tc-lan-adapter._test-mdns._tcp.local.", SRV
67
68
 
68
69
  sock = open_ipv4 iface.addr, 0
69
70
  multicast_send sock, query.encode
@@ -71,7 +72,7 @@ module ZeroConf
71
72
  s.stop
72
73
  runner.join
73
74
 
74
- expected = Resolv::DNS::Message.new(10)
75
+ expected = Resolv::DNS::Message.new(0)
75
76
  expected.qr = 1
76
77
  expected.aa = 1
77
78
 
@@ -83,7 +84,7 @@ module ZeroConf
83
84
  10,
84
85
  Resolv::DNS::Resource::IN::TXT.new(*s.text)
85
86
  expected.add_answer s.service_name, 10, Resolv::DNS::Resource::IN::SRV.new(0, 0, s.service_port, s.qualified_host)
86
- expected.add_question s.service_name, Resolv::DNS::Resource::IN::SRV
87
+ expected.add_question s.service_name, MDNS::Announce::IN::SRV
87
88
 
88
89
  assert_equal expected, res
89
90
  end
@@ -93,13 +94,14 @@ module ZeroConf
93
94
  rd, wr = IO.pipe
94
95
 
95
96
  listen = make_listener rd, q
96
- s = make_server iface
97
+ latch = Queue.new
98
+ s = make_server iface, started_callback: -> { latch << :start }
97
99
  server = Thread.new { s.start }
98
- Thread.pass until s.started?
100
+ latch.pop
99
101
 
100
- query = Resolv::DNS::Message.new 10
102
+ query = Resolv::DNS::Message.new 0
101
103
  query.add_question "_services._dns-sd._udp.local.", Resolv::DNS::Resource::IN::PTR
102
- sock = open_ipv4 iface.addr, Resolv::MDNS::Port
104
+ sock = open_ipv4 iface.addr, 0
103
105
  multicast_send sock, query.encode
104
106
 
105
107
  while res = q.pop
@@ -196,14 +198,15 @@ module ZeroConf
196
198
  end
197
199
 
198
200
  def test_dnssd_unicast_answer
199
- s = make_server iface
201
+ latch = Queue.new
202
+ s = make_server iface, started_callback: -> { latch << :start }
200
203
  runner = Thread.new { s.start }
201
- Thread.pass until s.started?
204
+ latch.pop
202
205
 
203
- query = Resolv::DNS::Message.new 10
206
+ query = Resolv::DNS::Message.new 0
204
207
  query.add_question "_services._dns-sd._udp.local.", PTR
205
208
 
206
- sock = open_ipv4 iface.addr, Resolv::MDNS::Port
209
+ sock = open_ipv4 iface.addr, 0
207
210
  multicast_send sock, query.encode
208
211
 
209
212
  res = nil
@@ -230,53 +233,20 @@ module ZeroConf
230
233
  assert_equal expected, res
231
234
  end
232
235
 
233
- def test_dnssd_legacy_unicast_answer
234
- s = make_server iface
235
- runner = Thread.new { s.start }
236
- Thread.pass until s.started?
237
-
238
- query = Resolv::DNS::Message.new 10
239
- query.add_question "_services._dns-sd._udp.local.", Resolv::DNS::Resource::IN::PTR
240
-
241
- sock = open_ipv4 iface.addr, 0
242
- multicast_send sock, query.encode
243
-
244
- res = nil
245
- loop do
246
- buf, from = read_with_timeout sock
247
- res = Resolv::DNS::Message.decode buf
248
- if from.last == iface.addr.ip_address
249
- break if res.answer.find { |name, ttl, data| data.name.to_s == SERVICE }
250
- end
251
- end
252
-
253
- s.stop
254
- runner.join
255
-
256
- expected = Resolv::DNS::Message.new(10)
257
- expected.qr = 1
258
- expected.aa = 1
259
-
260
- expected.add_answer DISCOVERY_NAME, 10,
261
- Resolv::DNS::Resource::IN::PTR.new(Resolv::DNS::Name.create(s.service))
262
-
263
- expected.add_question DISCOVERY_NAME, Resolv::DNS::Resource::IN::PTR
264
-
265
- assert_equal expected, res
266
- end
267
-
268
236
  def test_service_multicast_answer
269
237
  q = Thread::Queue.new
270
238
  rd, wr = IO.pipe
271
239
 
272
- listen = make_listener rd, q
273
- s = make_server iface
240
+ latch = Queue.new
241
+ listen = make_listener rd, q, started_callback: -> { latch << :start }
242
+ s = make_server iface, started_callback: -> { latch << :start }
274
243
  server = Thread.new { s.start }
275
- Thread.pass until s.started? && listen[:started]
244
+ latch.pop
245
+ latch.pop
276
246
 
277
- query = Resolv::DNS::Message.new 10
247
+ query = Resolv::DNS::Message.new 0
278
248
  query.add_question "_test-mdns._tcp.local.", Resolv::DNS::Resource::IN::PTR
279
- sock = open_ipv4 iface.addr, Resolv::MDNS::Port
249
+ sock = open_ipv4 iface.addr, 0
280
250
  multicast_send sock, query.encode
281
251
 
282
252
  service = Resolv::DNS::Name.create s.service
@@ -316,14 +286,15 @@ module ZeroConf
316
286
  end
317
287
 
318
288
  def test_service_unicast_answer
319
- s = make_server iface
289
+ latch = Queue.new
290
+ s = make_server iface, started_callback: -> { latch << :start }
320
291
  runner = Thread.new { s.start }
321
- Thread.pass until s.started?
292
+ latch.pop
322
293
 
323
- query = Resolv::DNS::Message.new 10
294
+ query = Resolv::DNS::Message.new 0
324
295
  query.add_question "_test-mdns._tcp.local.", PTR
325
296
 
326
- sock = open_ipv4 iface.addr, Resolv::MDNS::Port
297
+ sock = open_ipv4 iface.addr, 0
327
298
  multicast_send sock, query.encode
328
299
  res = Resolv::DNS::Message.decode read_with_timeout(sock).first
329
300
  s.stop
@@ -349,53 +320,20 @@ module ZeroConf
349
320
  assert_equal expected, res
350
321
  end
351
322
 
352
- def test_service_legacy_unicast_answer
353
- s = make_server iface
354
- runner = Thread.new { s.start }
355
- Thread.pass until s.started?
356
-
357
- query = Resolv::DNS::Message.new 10
358
- query.add_question "_test-mdns._tcp.local.", PTR
359
-
360
- sock = open_ipv4 iface.addr, 0
361
- multicast_send sock, query.encode
362
- res = Resolv::DNS::Message.decode read_with_timeout(sock).first
363
- s.stop
364
- runner.join
365
-
366
- expected = Resolv::DNS::Message.new(10)
367
- expected.qr = 1
368
- expected.aa = 1
369
-
370
- expected.add_additional s.service_name, 10, Resolv::DNS::Resource::IN::SRV.new(0, 0, s.service_port, s.qualified_host)
371
- expected.add_additional s.qualified_host,
372
- 10,
373
- Resolv::DNS::Resource::IN::A.new(iface.addr.ip_address)
374
-
375
- expected.add_additional s.service_name,
376
- 10,
377
- Resolv::DNS::Resource::IN::TXT.new(*s.text)
378
- expected.add_answer s.service,
379
- 10,
380
- Resolv::DNS::Resource::IN::PTR.new(Resolv::DNS::Name.create(s.service_name))
381
- expected.add_question s.service, Resolv::DNS::Resource::IN::PTR
382
-
383
- assert_equal expected, res
384
- end
385
-
386
-
387
323
  def test_multicast_service_instance_answer
388
324
  q = Queue.new
389
325
  rd, wr = IO.pipe
390
326
 
391
- listen = make_listener rd, q
392
- s = make_server iface
327
+ latch = Queue.new
328
+ listen = make_listener rd, q, started_callback: -> { latch << :start }
329
+ s = make_server iface, started_callback: -> { latch << :start }
393
330
  server = Thread.new { s.start }
394
- Thread.pass until s.started?
331
+ latch.pop
332
+ latch.pop
395
333
 
396
- query = Resolv::DNS::Message.new 10
334
+ query = Resolv::DNS::Message.new 0
397
335
  query.add_question "tc-lan-adapter._test-mdns._tcp.local.", Resolv::DNS::Resource::IN::PTR
398
- sock = open_ipv4 iface.addr, Resolv::MDNS::Port
336
+ sock = open_ipv4 iface.addr, 0
399
337
  multicast_send sock, query.encode
400
338
 
401
339
  service_name = Resolv::DNS::Name.create s.service_name
@@ -430,14 +368,15 @@ module ZeroConf
430
368
  end
431
369
 
432
370
  def test_unicast_name_lookup
433
- s = make_server iface
371
+ latch = Queue.new
372
+ s = make_server iface, started_callback: -> { latch << :start }
434
373
  runner = Thread.new { s.start }
435
- Thread.pass until s.started?
374
+ latch.pop
436
375
 
437
- query = Resolv::DNS::Message.new 10
376
+ query = Resolv::DNS::Message.new 0
438
377
  query.add_question "tc-lan-adapter.local.", A
439
378
 
440
- sock = open_ipv4 iface.addr, Resolv::MDNS::Port
379
+ sock = open_ipv4 iface.addr, 0
441
380
  multicast_send sock, query.encode
442
381
  res = Resolv::DNS::Message.decode read_with_timeout(sock).first
443
382
  s.stop
@@ -459,48 +398,20 @@ module ZeroConf
459
398
  assert_equal expected, res
460
399
  end
461
400
 
462
- def test_legacy_unicast_name_lookup
463
- s = make_server iface
464
- runner = Thread.new { s.start }
465
- Thread.pass until s.started?
466
-
467
- query = Resolv::DNS::Message.new 10
468
- query.add_question "tc-lan-adapter.local.", Resolv::DNS::Resource::IN::A
469
-
470
- sock = open_ipv4 iface.addr, 0
471
- multicast_send sock, query.encode
472
- res = Resolv::DNS::Message.decode read_with_timeout(sock).first
473
- s.stop
474
- runner.join
475
-
476
- expected = Resolv::DNS::Message.new(10)
477
- expected.qr = 1
478
- expected.aa = 1
479
-
480
- expected.add_answer s.qualified_host, 10, Resolv::DNS::Resource::IN::A.new(iface.addr.ip_address)
481
-
482
- expected.add_additional s.service_name,
483
- 10,
484
- Resolv::DNS::Resource::IN::TXT.new(*s.text)
485
-
486
- expected.add_question s.qualified_host,
487
- Resolv::DNS::Resource::IN::A
488
-
489
- assert_equal expected, res
490
- end
491
-
492
401
  def test_multicast_name
493
402
  q = Queue.new
494
403
  rd, wr = IO.pipe
495
404
 
496
- listen = make_listener rd, q
497
- s = make_server iface
405
+ latch = Queue.new
406
+ listen = make_listener rd, q, started_callback: -> { latch << :start }
407
+ s = make_server iface, started_callback: -> { latch << :start }
498
408
  server = Thread.new { s.start }
499
- Thread.pass until s.started?
409
+ latch.pop
410
+ latch.pop
500
411
 
501
- query = Resolv::DNS::Message.new 10
412
+ query = Resolv::DNS::Message.new 0
502
413
  query.add_question "tc-lan-adapter.local.", Resolv::DNS::Resource::IN::A
503
- sock = open_ipv4 iface.addr, Resolv::MDNS::Port
414
+ sock = open_ipv4 iface.addr, 0
504
415
  multicast_send sock, query.encode
505
416
 
506
417
  host = Resolv::DNS::Name.create s.qualified_host
@@ -529,6 +440,21 @@ module ZeroConf
529
440
  assert_equal expected, res
530
441
  end
531
442
 
443
+ def test_raise_on_malformed_requests
444
+ latch = Queue.new
445
+ s = make_server iface, abort_on_malformed_requests: true, started_callback: -> { latch << :start }
446
+ runner = Thread.new {
447
+ assert_raises do
448
+ s.start
449
+ end
450
+ }
451
+ latch.pop
452
+
453
+ sock = open_ipv4 iface.addr, Resolv::MDNS::Port
454
+ multicast_send sock, "not a valid DNS message"
455
+ runner.join
456
+ end
457
+
532
458
  def read_with_timeout sock
533
459
  return unless sock.wait_readable(3)
534
460
  sock.recvfrom(2048)
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zeroconf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Patterson
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-08-15 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: resolv
@@ -80,7 +79,6 @@ homepage: https://github.com/tenderlove/zeroconf
80
79
  licenses:
81
80
  - Apache-2.0
82
81
  metadata: {}
83
- post_install_message:
84
82
  rdoc_options: []
85
83
  require_paths:
86
84
  - lib
@@ -95,8 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
93
  - !ruby/object:Gem::Version
96
94
  version: '0'
97
95
  requirements: []
98
- rubygems_version: 3.5.11
99
- signing_key:
96
+ rubygems_version: 3.7.0.dev
100
97
  specification_version: 4
101
98
  summary: Multicast DNS client and server
102
99
  test_files: