dnssd 2.0.1 → 3.0.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 +4 -4
- data/README.txt +2 -2
- data/Rakefile +6 -1
- data/ext/dnssd/dnssd.c +0 -33
- data/ext/dnssd/dnssd.h +0 -6
- data/ext/dnssd/extconf.rb +0 -8
- data/ext/dnssd/service.c +103 -136
- data/lib/dnssd.rb +35 -71
- data/lib/dnssd/reply/browse.rb +6 -3
- data/lib/dnssd/reply/query_record.rb +0 -2
- data/lib/dnssd/reply/register.rb +5 -0
- data/lib/dnssd/reply/resolve.rb +4 -3
- data/lib/dnssd/service.rb +95 -102
- data/lib/dnssd/text_record.rb +26 -23
- data/test/test_dnssd.rb +65 -26
- data/test/test_dnssd_flags.rb +2 -3
- data/test/test_dnssd_record.rb +10 -6
- data/test/test_dnssd_reply.rb +2 -3
- data/test/test_dnssd_reply_browse.rb +15 -9
- data/test/test_dnssd_reply_query_record.rb +2 -3
- data/test/test_dnssd_reply_resolve.rb +6 -4
- data/test/test_dnssd_service.rb +175 -7
- data/test/test_dnssd_text_record.rb +2 -3
- metadata +8 -8
data/lib/dnssd/text_record.rb
CHANGED
@@ -4,6 +4,31 @@ require 'delegate'
|
|
4
4
|
# DNSSD::TextRecord is a Hash delegate that can encode its contents for DNSSD.
|
5
5
|
|
6
6
|
class DNSSD::TextRecord < DelegateClass(Hash)
|
7
|
+
def self.decode text_record
|
8
|
+
record = {}
|
9
|
+
|
10
|
+
tr = text_record.unpack 'C*'
|
11
|
+
|
12
|
+
until tr.empty? do
|
13
|
+
size = tr.shift
|
14
|
+
|
15
|
+
next if size.zero?
|
16
|
+
|
17
|
+
raise ArgumentError, 'ran out of data in text record' if tr.length < size
|
18
|
+
|
19
|
+
entry = tr.shift(size).pack('C*')
|
20
|
+
|
21
|
+
raise ArgumentError, 'key not found' unless entry =~ /^[^=]/
|
22
|
+
|
23
|
+
key, value = entry.split '=', 2
|
24
|
+
|
25
|
+
next unless key
|
26
|
+
|
27
|
+
record[key] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
new record
|
31
|
+
end
|
7
32
|
|
8
33
|
##
|
9
34
|
# Creates a new TextRecord decoding an encoded +text_record+ if given or
|
@@ -30,29 +55,7 @@ class DNSSD::TextRecord < DelegateClass(Hash)
|
|
30
55
|
# Decodes +text_record+ and returns a Hash
|
31
56
|
|
32
57
|
def decode(text_record)
|
33
|
-
|
34
|
-
|
35
|
-
tr = text_record.unpack 'C*'
|
36
|
-
|
37
|
-
until tr.empty? do
|
38
|
-
size = tr.shift
|
39
|
-
|
40
|
-
next if size.zero?
|
41
|
-
|
42
|
-
raise ArgumentError, 'ran out of data in text record' if tr.length < size
|
43
|
-
|
44
|
-
entry = tr.shift(size).pack('C*')
|
45
|
-
|
46
|
-
raise ArgumentError, 'key not found' unless entry =~ /^[^=]/
|
47
|
-
|
48
|
-
key, value = entry.split '=', 2
|
49
|
-
|
50
|
-
next unless key
|
51
|
-
|
52
|
-
record[key] = value
|
53
|
-
end
|
54
|
-
|
55
|
-
record
|
58
|
+
self.class.decode text_record
|
56
59
|
end
|
57
60
|
|
58
61
|
##
|
data/test/test_dnssd.rb
CHANGED
@@ -1,60 +1,101 @@
|
|
1
|
-
require '
|
2
|
-
require 'dnssd'
|
3
|
-
require 'socket'
|
4
|
-
|
5
|
-
class TestDNSSD < MiniTest::Unit::TestCase
|
1
|
+
require 'helper'
|
6
2
|
|
3
|
+
class TestDNSSD < DNSSD::Test
|
7
4
|
def setup
|
8
5
|
@abort = Thread.abort_on_exception
|
9
6
|
Thread.abort_on_exception = true
|
10
7
|
|
11
|
-
|
8
|
+
begin
|
9
|
+
@port = Socket.getservbyname 'blackjack'
|
10
|
+
rescue
|
11
|
+
@port = 1025
|
12
|
+
end
|
12
13
|
end
|
13
14
|
|
14
15
|
def teardown
|
15
16
|
Thread.abort_on_exception = @abort
|
16
17
|
end
|
17
18
|
|
19
|
+
def test_synchronous_register
|
20
|
+
reply = DNSSD.register! name, "_http._tcp", nil, 8080 do |r|
|
21
|
+
break r
|
22
|
+
end
|
23
|
+
assert reply
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_synchronous_enumerate
|
27
|
+
Timeout.timeout(2, Minitest::Skip) do
|
28
|
+
reply = DNSSD.enumerate_domains! do |r|
|
29
|
+
break r
|
30
|
+
end
|
31
|
+
assert reply
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_asynchronous_enumerate
|
36
|
+
latch = Latch.new
|
37
|
+
reply = DNSSD.enumerate_domains do |r|
|
38
|
+
latch.await
|
39
|
+
end
|
40
|
+
latch.release
|
41
|
+
assert reply
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_synchronous_browse
|
45
|
+
register = DNSSD::Service.register name, "_http._tcp", nil, 8080
|
46
|
+
thing = nil
|
47
|
+
DNSSD.browse!('_http._tcp') do |r|
|
48
|
+
thing = true
|
49
|
+
break
|
50
|
+
end
|
51
|
+
assert thing
|
52
|
+
register.stop
|
53
|
+
end
|
54
|
+
|
18
55
|
def test_class_announce_tcp_server
|
19
|
-
t =
|
20
|
-
|
56
|
+
t = nil
|
57
|
+
latch = Latch.new
|
58
|
+
|
59
|
+
browse = DNSSD.browse '_blackjack._tcp' do |reply|
|
21
60
|
next unless 'blackjack tcp server' == reply.name
|
22
|
-
t
|
61
|
+
t = reply
|
62
|
+
latch.release
|
23
63
|
end
|
24
64
|
|
25
65
|
s = TCPServer.new 'localhost', @port
|
26
66
|
|
27
|
-
|
67
|
+
stub Socket, :getservbyport, 'blackjack' do
|
68
|
+
DNSSD.announce s, 'blackjack tcp server'
|
69
|
+
end
|
28
70
|
|
29
|
-
|
71
|
+
latch.await
|
30
72
|
|
31
|
-
assert_equal 'blackjack tcp server', t
|
73
|
+
assert_equal 'blackjack tcp server', t.name
|
32
74
|
ensure
|
75
|
+
browse.stop
|
33
76
|
s.close
|
34
77
|
end
|
35
78
|
|
36
79
|
def test_class_announce_tcp_server_service
|
37
|
-
t =
|
80
|
+
t = nil
|
81
|
+
latch = Latch.new
|
38
82
|
|
39
|
-
DNSSD.resolve 'blackjack resolve', '_blackjack._tcp', 'local.' do |reply|
|
40
|
-
t
|
83
|
+
rs = DNSSD.resolve 'blackjack resolve', '_blackjack._tcp', 'local.' do |reply|
|
84
|
+
t = reply
|
85
|
+
latch.release
|
41
86
|
end
|
42
87
|
|
43
88
|
s = TCPServer.new 'localhost', @port + 1
|
44
89
|
|
45
90
|
DNSSD.announce s, 'blackjack resolve', 'blackjack'
|
46
91
|
|
47
|
-
|
92
|
+
latch.await
|
48
93
|
|
49
|
-
assert_equal 'blackjack resolve', t
|
50
|
-
assert_equal @port + 1, t
|
94
|
+
assert_equal 'blackjack resolve', t.name
|
95
|
+
assert_equal @port + 1, t.port
|
51
96
|
ensure
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
def test_class_getservbyport
|
56
|
-
assert_equal 'blackjack', DNSSD.getservbyport(1025),
|
57
|
-
"Your /etc/services is out of date, sorry!"
|
97
|
+
rs.stop
|
98
|
+
s.close if s
|
58
99
|
end
|
59
100
|
|
60
101
|
def test_class_interface_index
|
@@ -69,6 +110,4 @@ class TestDNSSD < MiniTest::Unit::TestCase
|
|
69
110
|
|
70
111
|
assert_match %r%^lo0?$%, DNSSD.interface_name(index)
|
71
112
|
end
|
72
|
-
|
73
113
|
end
|
74
|
-
|
data/test/test_dnssd_flags.rb
CHANGED
data/test/test_dnssd_record.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
require '
|
2
|
-
require 'dnssd'
|
1
|
+
require 'helper'
|
3
2
|
|
4
|
-
class TestDNSSDRecord <
|
3
|
+
class TestDNSSDRecord < DNSSD::Test
|
5
4
|
|
6
5
|
def setup
|
7
6
|
@fullname = 'blackjack._blackjack._tcp.test.'
|
8
7
|
@IN = DNSSD::Record::IN
|
9
|
-
@ipv4 = "\300\000\002\001"
|
10
|
-
@ipv6 = " \001\r\270\000\000\000\000\000\000\000\000\000\000\000\001"
|
11
|
-
@nowhere = "\007nowhere\007example\000"
|
8
|
+
@ipv4 = "\300\000\002\001".force_encoding("ascii-8bit")
|
9
|
+
@ipv6 = " \001\r\270\000\000\000\000\000\000\000\000\000\000\000\001".force_encoding("ascii-8bit")
|
10
|
+
@nowhere = "\007nowhere\007example\000".force_encoding("ascii-8bit")
|
12
11
|
|
13
12
|
@R = DNSSD::Record
|
14
13
|
end
|
@@ -28,6 +27,11 @@ class TestDNSSDRecord < MiniTest::Unit::TestCase
|
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
30
|
+
def test_idk
|
31
|
+
a_variable = IPAddr.new '2001:db8::1'
|
32
|
+
assert_equal @ipv6, a_variable.hton
|
33
|
+
end
|
34
|
+
|
31
35
|
def test_class_to_data_AAAA
|
32
36
|
assert_equal @ipv6, @R.to_data(DNSSD::Record::AAAA, '2001:db8::1')
|
33
37
|
assert_equal @ipv6,
|
data/test/test_dnssd_reply.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
|
-
require '
|
2
|
-
require 'dnssd'
|
1
|
+
require 'helper'
|
3
2
|
|
4
|
-
class TestDNSSDReplyBrowse <
|
3
|
+
class TestDNSSDReplyBrowse < DNSSD::Test
|
5
4
|
|
6
5
|
def test_connect
|
7
6
|
reply = DNSSD::Reply::Browse.new nil, 0, 0, 'blackjack no port',
|
8
7
|
'_blackjack._tcp', 'local'
|
9
8
|
|
10
|
-
port = Socket
|
9
|
+
port = stub Socket, :getservbyname, 1025 do
|
10
|
+
Socket.getservbyname('blackjack')
|
11
|
+
end
|
12
|
+
|
11
13
|
server = TCPServer.new nil, port
|
12
14
|
Thread.start do server.accept end
|
13
15
|
|
14
|
-
|
16
|
+
stub Socket, :getservbyport, "blackjack" do
|
17
|
+
DNSSD.announce server, 'blackjack no port'
|
18
|
+
end
|
15
19
|
|
16
20
|
socket = reply.connect
|
17
21
|
|
@@ -29,14 +33,18 @@ class TestDNSSDReplyBrowse < MiniTest::Unit::TestCase
|
|
29
33
|
'_blackjack._tcp', 'local'
|
30
34
|
|
31
35
|
|
32
|
-
port = Socket
|
36
|
+
port = stub Socket, :getservbyname, 1025 do
|
37
|
+
Socket.getservbyname 'blackjack'
|
38
|
+
end
|
33
39
|
server = TCPServer.new nil, port
|
34
40
|
Thread.start do server.accept end
|
35
41
|
|
36
42
|
name = "\u00E9"
|
37
43
|
name.encode! Encoding::ISO_8859_1
|
38
44
|
|
39
|
-
|
45
|
+
stub Socket, :getservbyport, 'blackjack' do
|
46
|
+
DNSSD.announce server, name
|
47
|
+
end
|
40
48
|
|
41
49
|
socket = reply.connect
|
42
50
|
|
@@ -46,6 +54,4 @@ class TestDNSSDReplyBrowse < MiniTest::Unit::TestCase
|
|
46
54
|
socket.close if socket
|
47
55
|
server.close if server
|
48
56
|
end
|
49
|
-
|
50
57
|
end
|
51
|
-
|
@@ -1,11 +1,13 @@
|
|
1
|
-
require '
|
2
|
-
require 'dnssd'
|
1
|
+
require 'helper'
|
3
2
|
|
4
|
-
class TestDNSSDReplyResolve <
|
3
|
+
class TestDNSSDReplyResolve < DNSSD::Test
|
5
4
|
|
6
5
|
def setup
|
7
|
-
@port = Socket
|
6
|
+
@port = stub Socket, :getservbyname, 1025 do
|
7
|
+
Socket.getservbyname 'blackjack'
|
8
|
+
end
|
8
9
|
@interface = DNSSD::InterfaceAny
|
10
|
+
super
|
9
11
|
end
|
10
12
|
|
11
13
|
def test_connect_tcp
|
data/test/test_dnssd_service.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'dnssd'
|
1
|
+
require 'helper'
|
3
2
|
|
4
|
-
class TestDNSSDService <
|
3
|
+
class TestDNSSDService < DNSSD::Test
|
5
4
|
|
6
5
|
def test_class_get_property
|
7
6
|
skip 'DNSSD::Service::get_property not defined' unless
|
@@ -12,11 +11,10 @@ class TestDNSSDService < MiniTest::Unit::TestCase
|
|
12
11
|
end
|
13
12
|
|
14
13
|
def test_class_getaddrinfo
|
15
|
-
service = DNSSD::Service.new
|
16
|
-
|
17
14
|
addresses = []
|
15
|
+
service = DNSSD::Service.getaddrinfo 'localhost'
|
18
16
|
|
19
|
-
service.
|
17
|
+
service.each do |addrinfo|
|
20
18
|
addresses << addrinfo.address
|
21
19
|
break unless addrinfo.flags.more_coming?
|
22
20
|
end
|
@@ -24,5 +22,175 @@ class TestDNSSDService < MiniTest::Unit::TestCase
|
|
24
22
|
assert addresses.index('127.0.0.1')
|
25
23
|
end
|
26
24
|
|
27
|
-
|
25
|
+
def test_enumerate
|
26
|
+
service = DNSSD::Service.enumerate_domains
|
27
|
+
|
28
|
+
begin
|
29
|
+
Timeout.timeout(2) do
|
30
|
+
service.each do |reply|
|
31
|
+
# I *think* there will be a local. on every machine??
|
32
|
+
break if reply.domain == 'local.'
|
33
|
+
end
|
34
|
+
assert true
|
35
|
+
end
|
36
|
+
rescue Timeout::Error
|
37
|
+
skip "couldn't find any domains to enumerate"
|
38
|
+
end
|
39
|
+
ensure
|
40
|
+
service.stop
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_async_register_browse
|
44
|
+
registered = Latch.new
|
45
|
+
found = Latch.new
|
46
|
+
name = SecureRandom.hex
|
47
|
+
|
48
|
+
register = DNSSD::Service.register name, "_http._tcp", nil, 8080
|
49
|
+
register.async_each do |reply|
|
50
|
+
if reply.domain == "local."
|
51
|
+
registered.release
|
52
|
+
found.await
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
registered.await
|
57
|
+
|
58
|
+
browse = DNSSD::Service.browse '_http._tcp'
|
59
|
+
browse.async_each do |r|
|
60
|
+
if r.name == name && r.domain == "local."
|
61
|
+
found.release
|
62
|
+
assert_equal name, r.name
|
63
|
+
assert_equal "_http._tcp", r.type
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
register.stop
|
68
|
+
browse.stop
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_register_browse
|
72
|
+
registered = Latch.new
|
73
|
+
found = Latch.new
|
74
|
+
name = SecureRandom.hex
|
75
|
+
|
76
|
+
broadcast = Thread.new do
|
77
|
+
service = DNSSD::Service.register name, "_http._tcp", nil, 8080
|
78
|
+
service.each do |reply|
|
79
|
+
if reply.domain == "local."
|
80
|
+
registered.release
|
81
|
+
found.await
|
82
|
+
service.stop
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
find = Thread.new do
|
88
|
+
registered.await
|
89
|
+
service = DNSSD::Service.browse '_http._tcp'
|
90
|
+
service.each do |r|
|
91
|
+
if r.name == name && r.domain == "local."
|
92
|
+
found.release
|
93
|
+
service.stop
|
94
|
+
assert_equal name, r.name
|
95
|
+
assert_equal "_http._tcp", r.type
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
28
99
|
|
100
|
+
found.await
|
101
|
+
broadcast.join
|
102
|
+
find.join
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_resolve
|
106
|
+
done = Latch.new
|
107
|
+
name = SecureRandom.hex
|
108
|
+
|
109
|
+
broadcast = Thread.new do
|
110
|
+
txt = DNSSD::TextRecord.new 'foo' => 'bar'
|
111
|
+
service = DNSSD::Service.register name, "_http._tcp", nil, 8080, nil, txt
|
112
|
+
done.await
|
113
|
+
service.stop
|
114
|
+
end
|
115
|
+
|
116
|
+
service = DNSSD::Service.browse '_http._tcp'
|
117
|
+
reply = service.each.find do |r|
|
118
|
+
r.name == name && r.domain == "local."
|
119
|
+
end
|
120
|
+
|
121
|
+
resolver = DNSSD::Service.resolve reply.name, reply.type, reply.domain
|
122
|
+
text = resolver.each.find(&:text_record).text_record
|
123
|
+
assert_equal 'bar', text['foo']
|
124
|
+
|
125
|
+
done.release
|
126
|
+
broadcast.join
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_query_record
|
130
|
+
done = Latch.new
|
131
|
+
name = SecureRandom.hex
|
132
|
+
|
133
|
+
broadcast = Thread.new do
|
134
|
+
txt = DNSSD::TextRecord.new 'foo' => 'bar'
|
135
|
+
service = DNSSD::Service.register name, "_http._tcp", nil, 8080, nil, txt
|
136
|
+
done.await
|
137
|
+
service.stop
|
138
|
+
end
|
139
|
+
|
140
|
+
service = DNSSD::Service.browse '_http._tcp'
|
141
|
+
reply = service.each.find do |r|
|
142
|
+
r.name == name && r.domain == "local."
|
143
|
+
end
|
144
|
+
service.stop
|
145
|
+
|
146
|
+
service = DNSSD::Service.query_record reply.fullname, DNSSD::Record::SRV
|
147
|
+
assert service.each.first
|
148
|
+
service.stop
|
149
|
+
|
150
|
+
done.release
|
151
|
+
broadcast.join
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_add_record
|
155
|
+
skip "not supported" if RbConfig::CONFIG['target_os'] =~ /linux/
|
156
|
+
done = Latch.new
|
157
|
+
registered = Latch.new
|
158
|
+
broadcast = Thread.new do
|
159
|
+
txt = DNSSD::TextRecord.new 'bar' => 'baz'
|
160
|
+
service = DNSSD::Service.register name, "_http._tcp", nil, 8080
|
161
|
+
service.add_record(DNSSD::Record::TXT, txt.encode)
|
162
|
+
registered.release
|
163
|
+
done.await
|
164
|
+
end
|
165
|
+
|
166
|
+
registered.await
|
167
|
+
service = DNSSD::Service.browse '_http._tcp'
|
168
|
+
reply = service.each.find { |r|
|
169
|
+
r.name == name && r.domain == "local."
|
170
|
+
}
|
171
|
+
|
172
|
+
query = DNSSD::Service.query_record reply.fullname, DNSSD::Record::TXT
|
173
|
+
r = query.each.find do |response|
|
174
|
+
!response.flags.more_coming?
|
175
|
+
end
|
176
|
+
record = DNSSD::TextRecord.decode r.record
|
177
|
+
done.release
|
178
|
+
assert_equal 'baz', record['bar']
|
179
|
+
broadcast.join
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_stop
|
183
|
+
service = DNSSD::Service.browse '_http._tcp'
|
184
|
+
assert_predicate service, :started?
|
185
|
+
service.stop
|
186
|
+
refute_predicate service, :started?
|
187
|
+
|
188
|
+
assert_raises(DNSSD::Error) { service.each { } }
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_stop_twice
|
192
|
+
service = DNSSD::Service.browse '_http._tcp'
|
193
|
+
service.stop
|
194
|
+
assert_raises(DNSSD::Error) { service.stop }
|
195
|
+
end
|
196
|
+
end
|