dnssd 1.2 → 1.3
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.
- data.tar.gz.sig +0 -0
- data/.autotest +14 -0
- data/History.txt +22 -3
- data/Manifest.txt +15 -0
- data/README.txt +27 -3
- data/Rakefile +5 -4
- data/ext/dnssd/dnssd.c +4 -0
- data/ext/dnssd/dnssd.h +13 -18
- data/ext/dnssd/errors.c +9 -3
- data/ext/dnssd/extconf.rb +51 -44
- data/ext/dnssd/flags.c +68 -14
- data/ext/dnssd/record.c +218 -0
- data/ext/dnssd/service.c +341 -121
- data/lib/dnssd.rb +46 -11
- data/lib/dnssd/record.rb +97 -0
- data/lib/dnssd/reply.rb +39 -92
- data/lib/dnssd/reply/addr_info.rb +47 -0
- data/lib/dnssd/reply/browse.rb +52 -0
- data/lib/dnssd/reply/domain.rb +22 -0
- data/lib/dnssd/reply/query_record.rb +183 -0
- data/lib/dnssd/reply/register.rb +37 -0
- data/lib/dnssd/reply/resolve.rb +105 -0
- data/lib/dnssd/service.rb +123 -16
- data/lib/dnssd/text_record.rb +28 -19
- data/sample/browse.rb +24 -6
- data/sample/enumerate_domains.rb +7 -1
- data/sample/getaddrinfo.rb +28 -0
- data/sample/growl.rb +2 -0
- data/sample/query_record.rb +15 -0
- data/sample/register.rb +19 -20
- data/sample/resolve.rb +31 -7
- data/sample/resolve_ichat.rb +5 -6
- data/sample/server.rb +2 -0
- data/sample/socket.rb +4 -0
- data/test/test_dnssd.rb +6 -4
- data/test/test_dnssd_flags.rb +1 -15
- data/test/test_dnssd_record.rb +92 -0
- data/test/test_dnssd_reply.rb +13 -79
- data/test/test_dnssd_reply_browse.rb +28 -0
- data/test/test_dnssd_reply_query_record.rb +92 -0
- data/test/test_dnssd_reply_resolve.rb +47 -0
- data/test/test_dnssd_service.rb +12 -0
- data/test/test_dnssd_text_record.rb +3 -3
- metadata +32 -11
- metadata.gz.sig +0 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
##
|
2
|
+
# Returned by DNSSD::Service#enumerate_domains
|
3
|
+
|
4
|
+
class DNSSD::Reply::Domain < DNSSD::Reply
|
5
|
+
|
6
|
+
##
|
7
|
+
# A domain for registration or browsing
|
8
|
+
|
9
|
+
attr_reader :domain
|
10
|
+
|
11
|
+
##
|
12
|
+
# Creates a new Browse, called internally by
|
13
|
+
# DNSSD::Service#enumerate_domains
|
14
|
+
|
15
|
+
def initialize(service, flags, interface, domain)
|
16
|
+
super service, flags, interface
|
17
|
+
|
18
|
+
@domain = domain
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
##
|
4
|
+
# Created by DNSSD::Service#query_record
|
5
|
+
|
6
|
+
class DNSSD::Reply::QueryRecord < DNSSD::Reply
|
7
|
+
|
8
|
+
##
|
9
|
+
# A domain for registration or browsing
|
10
|
+
|
11
|
+
attr_reader :domain
|
12
|
+
|
13
|
+
##
|
14
|
+
# The service name
|
15
|
+
|
16
|
+
attr_reader :name
|
17
|
+
|
18
|
+
##
|
19
|
+
# DNS Record data
|
20
|
+
|
21
|
+
attr_reader :record
|
22
|
+
|
23
|
+
##
|
24
|
+
# DNS Record class (only IN is supported)
|
25
|
+
|
26
|
+
attr_reader :record_class
|
27
|
+
|
28
|
+
##
|
29
|
+
# DNS Record type
|
30
|
+
|
31
|
+
attr_reader :record_type
|
32
|
+
|
33
|
+
##
|
34
|
+
# Time-to-live for this record. See #expired?
|
35
|
+
|
36
|
+
attr_reader :ttl
|
37
|
+
|
38
|
+
##
|
39
|
+
# The service type
|
40
|
+
|
41
|
+
attr_reader :type
|
42
|
+
|
43
|
+
##
|
44
|
+
# Creates a new QueryRecord, called internally by
|
45
|
+
# DNSSD::Service#query_record
|
46
|
+
|
47
|
+
def initialize(service, flags, interface, fullname, record_type,
|
48
|
+
record_class, record, ttl)
|
49
|
+
super service, flags, interface
|
50
|
+
|
51
|
+
set_fullname fullname
|
52
|
+
|
53
|
+
@record_type = record_type
|
54
|
+
@record_class = record_class
|
55
|
+
@record = record
|
56
|
+
|
57
|
+
@created = Time.now
|
58
|
+
@ttl = ttl
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Converts a RFC 1035 character-string into a ruby String
|
63
|
+
|
64
|
+
def character_string_to_string(character_string)
|
65
|
+
length = character_string.slice 0
|
66
|
+
length = length.ord unless Numeric === length
|
67
|
+
string = character_string.slice 1, length
|
68
|
+
|
69
|
+
if string.length != length then
|
70
|
+
raise TypeError,
|
71
|
+
"invalid character string, expected #{length} got #{string.length} in #{@record.inspect}"
|
72
|
+
end
|
73
|
+
|
74
|
+
string
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Converts a RFC 1035 domain-name into a ruby String
|
79
|
+
|
80
|
+
def domain_name_to_string(domain_name)
|
81
|
+
return '.' if domain_name == "\0"
|
82
|
+
|
83
|
+
domain_name = domain_name.dup
|
84
|
+
string = []
|
85
|
+
|
86
|
+
until domain_name.empty? do
|
87
|
+
string << character_string_to_string(domain_name)
|
88
|
+
domain_name.slice! 0, string.last.length + 1
|
89
|
+
end
|
90
|
+
|
91
|
+
string << nil unless string.last.empty?
|
92
|
+
|
93
|
+
string.join('.')
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Has this QueryRecord passed its TTL?
|
98
|
+
|
99
|
+
def expired?
|
100
|
+
Time.now > @created + ttl
|
101
|
+
end
|
102
|
+
|
103
|
+
def inspect # :nodoc:
|
104
|
+
"#<%s:0x%x %s %s %s %p interface: %s flags: %p>" % [
|
105
|
+
self.class, object_id,
|
106
|
+
fullname, record_class_name, record_type_name, record,
|
107
|
+
interface_name, @flags
|
108
|
+
]
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Name of this record's record_class
|
113
|
+
|
114
|
+
def record_class_name
|
115
|
+
return "unknown #{@record_class}" unless @record_class == DNSSD::Record::IN
|
116
|
+
'IN' # Only IN is supported
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Decodes output for #record, returning the raw record if it can't be
|
121
|
+
# decoded. Handles:
|
122
|
+
#
|
123
|
+
# A AAAA CNAME MX NS PTR SOA SRV TXT
|
124
|
+
|
125
|
+
def record_data
|
126
|
+
return @record unless @record_class == DNSSD::Record::IN
|
127
|
+
|
128
|
+
case @record_type
|
129
|
+
when DNSSD::Record::A,
|
130
|
+
DNSSD::Record::AAAA then
|
131
|
+
IPAddr.new_ntoh @record
|
132
|
+
when DNSSD::Record::CNAME,
|
133
|
+
DNSSD::Record::NS,
|
134
|
+
DNSSD::Record::PTR then
|
135
|
+
domain_name_to_string @record
|
136
|
+
when DNSSD::Record::MX then
|
137
|
+
mx = @record.unpack 'nZ*'
|
138
|
+
mx[-1] = domain_name_to_string mx.last
|
139
|
+
mx
|
140
|
+
when DNSSD::Record::SOA then
|
141
|
+
soa = @record.unpack 'Z*Z*NNNNN'
|
142
|
+
soa[0] = domain_name_to_string soa[0]
|
143
|
+
soa[1] = domain_name_to_string soa[1]
|
144
|
+
soa
|
145
|
+
when DNSSD::Record::SRV then
|
146
|
+
srv = @record.unpack 'nnnZ*'
|
147
|
+
srv[-1] = domain_name_to_string srv.last
|
148
|
+
srv
|
149
|
+
when DNSSD::Record::TXT then
|
150
|
+
record = @record.dup
|
151
|
+
txt = []
|
152
|
+
|
153
|
+
until record.empty? do
|
154
|
+
txt << character_string_to_string(record)
|
155
|
+
record.slice! 0, txt.last.length + 1
|
156
|
+
end
|
157
|
+
|
158
|
+
txt
|
159
|
+
else
|
160
|
+
@record
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Name of this record's record_type
|
166
|
+
|
167
|
+
def record_type_name
|
168
|
+
return "unknown #{@record_type} for record class (#{@record_class})" unless
|
169
|
+
@record_class == DNSSD::Record::IN
|
170
|
+
DNSSD::Record::VALUE_TO_NAME[@record_type]
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Outputs this record in a BIND-like DNS format
|
175
|
+
|
176
|
+
def to_s
|
177
|
+
"%s %d %s %s %p" % [
|
178
|
+
fullname, ttl, record_class_name, record_type_name, record_data
|
179
|
+
]
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
##
|
2
|
+
# Returned by DNSSD::Service#register
|
3
|
+
|
4
|
+
class DNSSD::Reply::Register < DNSSD::Reply
|
5
|
+
|
6
|
+
##
|
7
|
+
# A domain for registration or browsing
|
8
|
+
|
9
|
+
attr_reader :domain
|
10
|
+
|
11
|
+
##
|
12
|
+
# The service name
|
13
|
+
|
14
|
+
attr_reader :name
|
15
|
+
|
16
|
+
##
|
17
|
+
# The service type
|
18
|
+
|
19
|
+
attr_reader :type
|
20
|
+
|
21
|
+
##
|
22
|
+
# Creates a Register, called internally by DNSSD::Service#register
|
23
|
+
|
24
|
+
def initialize(service, flags, name, type, domain)
|
25
|
+
super service, flags, nil
|
26
|
+
|
27
|
+
set_names name, type, domain
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect # :nodoc:
|
31
|
+
"#<%s:0x%x %p flags: %p>" % [
|
32
|
+
self.class, object_id, fullname, @flags
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,105 @@
|
|
1
|
+
##
|
2
|
+
# Created by DNSSD::Service#resolve
|
3
|
+
|
4
|
+
class DNSSD::Reply::Resolve < DNSSD::Reply
|
5
|
+
|
6
|
+
##
|
7
|
+
# A domain for registration or browsing
|
8
|
+
|
9
|
+
attr_reader :domain
|
10
|
+
|
11
|
+
##
|
12
|
+
# The service name
|
13
|
+
|
14
|
+
attr_reader :name
|
15
|
+
|
16
|
+
##
|
17
|
+
# The port for this service
|
18
|
+
|
19
|
+
attr_reader :port
|
20
|
+
|
21
|
+
##
|
22
|
+
# The hostname of the host provide the service
|
23
|
+
|
24
|
+
attr_reader :target
|
25
|
+
|
26
|
+
##
|
27
|
+
# The service's primary text record
|
28
|
+
|
29
|
+
attr_reader :text_record
|
30
|
+
|
31
|
+
##
|
32
|
+
# The service type
|
33
|
+
|
34
|
+
attr_reader :type
|
35
|
+
|
36
|
+
##
|
37
|
+
# Creates a new Resolve, called internally by DNSSD::Service#resolve
|
38
|
+
|
39
|
+
def initialize(service, flags, interface, fullname, target, port,
|
40
|
+
text_record)
|
41
|
+
super service, flags, interface
|
42
|
+
|
43
|
+
set_fullname fullname
|
44
|
+
|
45
|
+
@target = target
|
46
|
+
@port = port
|
47
|
+
@text_record = DNSSD::TextRecord.new text_record
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Connects to this Reply. If #target and #port are missing, DNSSD.resolve
|
52
|
+
# is automatically called.
|
53
|
+
#
|
54
|
+
# +family+ can be used to select a particular address family (IPv6 vs IPv4).
|
55
|
+
#
|
56
|
+
# +addrinfo_flags+ are passed to DNSSD::Service#getaddrinfo as flags.
|
57
|
+
|
58
|
+
def connect(family = Socket::AF_UNSPEC, addrinfo_flags = 0)
|
59
|
+
addrinfo_protocol = case family
|
60
|
+
when Socket::AF_INET then DNSSD::Service::IPv4
|
61
|
+
when Socket::AF_INET6 then DNSSD::Service::IPv6
|
62
|
+
when Socket::AF_UNSPEC then 0
|
63
|
+
else raise ArgumentError, "invalid family #{family}"
|
64
|
+
end
|
65
|
+
|
66
|
+
addresses = []
|
67
|
+
|
68
|
+
service = DNSSD::Service.new
|
69
|
+
|
70
|
+
begin
|
71
|
+
service.getaddrinfo target, addrinfo_protocol, addrinfo_flags,
|
72
|
+
@interface do |addrinfo|
|
73
|
+
address = addrinfo.address
|
74
|
+
|
75
|
+
begin
|
76
|
+
socket = nil
|
77
|
+
|
78
|
+
case protocol
|
79
|
+
when 'tcp' then
|
80
|
+
socket = TCPSocket.new address, port
|
81
|
+
when 'udp' then
|
82
|
+
socket = UDPSocket.new
|
83
|
+
socket.connect address, port
|
84
|
+
end
|
85
|
+
|
86
|
+
return socket
|
87
|
+
rescue
|
88
|
+
next if addrinfo.flags.more_coming?
|
89
|
+
raise
|
90
|
+
end
|
91
|
+
end
|
92
|
+
ensure
|
93
|
+
service.stop
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def inspect # :nodoc:
|
98
|
+
"#<%s:0x%x %s at %s:%d text_record: %p interface: %s flags: %p>" % [
|
99
|
+
self.class, object_id,
|
100
|
+
fullname, @target, @port, @text_record, interface_name, @flags
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
data/lib/dnssd/service.rb
CHANGED
@@ -8,6 +8,11 @@ require 'thread'
|
|
8
8
|
|
9
9
|
class DNSSD::Service
|
10
10
|
|
11
|
+
# :stopdoc:
|
12
|
+
IPv4 = 1 unless const_defined? :IPv4
|
13
|
+
IPv6 = 2 unless const_defined? :IPv6
|
14
|
+
# :startdoc:
|
15
|
+
|
11
16
|
##
|
12
17
|
# Creates a new DNSSD::Service
|
13
18
|
|
@@ -15,6 +20,22 @@ class DNSSD::Service
|
|
15
20
|
@replies = []
|
16
21
|
@continue = true
|
17
22
|
@thread = nil
|
23
|
+
@type = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Adds an extra DNS record of +type+ containing +data+. +ttl+ is in
|
28
|
+
# seconds, use 0 for the default value. +flags+ are currently ignored.
|
29
|
+
#
|
30
|
+
# Must be called on a service only after #register.
|
31
|
+
#
|
32
|
+
# Returns the added DNSSD::Record
|
33
|
+
|
34
|
+
def add_record(type, data, ttl = 0, flags = 0)
|
35
|
+
raise TypeError, 'must be called after register' unless @type == :register
|
36
|
+
@records ||= []
|
37
|
+
|
38
|
+
_add_record flags.to_i, type, data, ttl
|
18
39
|
end
|
19
40
|
|
20
41
|
##
|
@@ -37,7 +58,9 @@ class DNSSD::Service
|
|
37
58
|
|
38
59
|
raise DNSSD::Error, 'service in progress' if started?
|
39
60
|
|
40
|
-
|
61
|
+
@type = :browse
|
62
|
+
|
63
|
+
_browse flags.to_i, interface, type, domain
|
41
64
|
|
42
65
|
process(&block)
|
43
66
|
end
|
@@ -60,11 +83,9 @@ class DNSSD::Service
|
|
60
83
|
#
|
61
84
|
# available_domains = []
|
62
85
|
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
# end
|
67
|
-
# rescue TimeoutError
|
86
|
+
# service.enumerate_domains! do |r|
|
87
|
+
# available_domains << r.domain
|
88
|
+
# break unless r.flags.more_coming?
|
68
89
|
# end
|
69
90
|
#
|
70
91
|
# p available_domains
|
@@ -77,15 +98,61 @@ class DNSSD::Service
|
|
77
98
|
|
78
99
|
_enumerate_domains flags.to_i, interface
|
79
100
|
|
101
|
+
@type = :enumerate_domains
|
102
|
+
|
80
103
|
process(&block)
|
81
104
|
end
|
82
|
-
|
105
|
+
|
106
|
+
##
|
107
|
+
# Retrieve address information for +host+ on +protocol+
|
108
|
+
#
|
109
|
+
# addresses = []
|
110
|
+
# service.getaddrinfo reply.target do |addrinfo|
|
111
|
+
# addresses << addrinfo.address
|
112
|
+
# break unless addrinfo.flags.more_coming?
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# When using DNSSD on top of the Avahi compatibilty shim you'll need to
|
116
|
+
# setup your /etc/nsswitch.conf correctly. See
|
117
|
+
# http://avahi.org/wiki/AvahiAndUnicastDotLocal for details
|
118
|
+
|
119
|
+
def getaddrinfo(host, protocol = nil, flags = 0,
|
120
|
+
interface = DNSSD::InterfaceAny, &block)
|
121
|
+
interface = DNSSD.interface_index interface unless Integer === interface
|
122
|
+
|
123
|
+
if respond_to? :_getaddrinfo then
|
124
|
+
raise DNSSD::Error, 'service in progress' if started?
|
125
|
+
|
126
|
+
_getaddrinfo flags.to_i, interface, protocol, host
|
127
|
+
|
128
|
+
@type = :getaddrinfo
|
129
|
+
|
130
|
+
process(&block)
|
131
|
+
else
|
132
|
+
family = case protocol
|
133
|
+
when IPv4 then Socket::AF_INET
|
134
|
+
when IPv6 then Socket::AF_INET6
|
135
|
+
else protocol
|
136
|
+
end
|
137
|
+
|
138
|
+
addrinfo = Socket.getaddrinfo host, nil, family
|
139
|
+
|
140
|
+
addrinfo.each do |_, _, host, ip, _|
|
141
|
+
sockaddr = Socket.pack_sockaddr_in 0, ip
|
142
|
+
@replies << DNSSD::Reply::AddrInfo.new(self, 0, 0, host, sockaddr, 0)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
83
147
|
def inspect # :nodoc:
|
84
148
|
stopped = stopped? ? 'stopped' : 'running'
|
85
149
|
"#<%s:0x%x %s>" % [self.class, object_id, stopped]
|
86
150
|
end
|
87
151
|
|
88
|
-
|
152
|
+
##
|
153
|
+
# Yields results from the mDNS daemon, blocking until data is available.
|
154
|
+
|
155
|
+
def process # :yields: DNSSD::Result
|
89
156
|
@thread = Thread.current
|
90
157
|
|
91
158
|
while @continue do
|
@@ -95,14 +162,45 @@ class DNSSD::Service
|
|
95
162
|
|
96
163
|
@thread = nil
|
97
164
|
|
165
|
+
self
|
166
|
+
rescue DNSSD::ServiceNotRunningError
|
167
|
+
# raised when we jump out of DNSServiceProcess() while it's waiting for a
|
168
|
+
# response
|
98
169
|
self
|
99
170
|
end
|
100
171
|
|
172
|
+
##
|
173
|
+
# Retrieves an arbitrary DNS record
|
174
|
+
#
|
175
|
+
# +fullname+ is the full name of the resource record. +record_type+ is the
|
176
|
+
# type of the resource record (see DNSSD::Resource).
|
177
|
+
#
|
178
|
+
# +flags+ may be either DNSSD::Flags::ForceMulticast or
|
179
|
+
# DNSSD::Flags::LongLivedQuery
|
180
|
+
#
|
181
|
+
# service.query_record "hostname._afpovertcp._tcp.local",
|
182
|
+
# DNSService::Record::SRV do |record|
|
183
|
+
# p record
|
184
|
+
# end
|
185
|
+
|
186
|
+
def query_record(fullname, record_type, record_class = DNSSD::Record::IN,
|
187
|
+
flags = 0, interface = DNSSD::InterfaceAny, &block)
|
188
|
+
interface = DNSSD.interface_index interface unless Integer === interface
|
189
|
+
|
190
|
+
raise DNSSD::Error, 'service in progress' if started?
|
191
|
+
|
192
|
+
_query_record flags.to_i, interface, fullname, record_type, record_class
|
193
|
+
|
194
|
+
@type = :query_record
|
195
|
+
|
196
|
+
process(&block)
|
197
|
+
end
|
198
|
+
|
101
199
|
##
|
102
200
|
# Register a service. A DNSSD::Reply object is passed to the optional block
|
103
201
|
# when the registration completes.
|
104
202
|
#
|
105
|
-
#
|
203
|
+
# service.register "My Files", "_http._tcp", nil, 8080 do |r|
|
106
204
|
# puts "successfully registered: #{r.inspect}"
|
107
205
|
# end
|
108
206
|
|
@@ -110,14 +208,16 @@ class DNSSD::Service
|
|
110
208
|
flags = 0, interface = DNSSD::InterfaceAny, &block)
|
111
209
|
check_domain domain
|
112
210
|
interface = DNSSD.interface_index interface unless Integer === interface
|
211
|
+
text_record = text_record.encode if text_record
|
113
212
|
|
114
213
|
raise DNSSD::Error, 'service in progress' if started?
|
115
214
|
|
116
|
-
_register name, type, domain, host, port,
|
215
|
+
_register flags.to_i, interface, name, type, domain, host, port,
|
216
|
+
text_record, &block
|
117
217
|
|
118
|
-
|
218
|
+
@type = :register
|
119
219
|
|
120
|
-
process(&block)
|
220
|
+
process(&block) if block
|
121
221
|
end
|
122
222
|
|
123
223
|
##
|
@@ -135,11 +235,9 @@ class DNSSD::Service
|
|
135
235
|
# The returned service can be used to control when to stop resolving the
|
136
236
|
# service (see DNSSD::Service#stop).
|
137
237
|
#
|
138
|
-
#
|
238
|
+
# service.resolve "foo bar", "_http._tcp", "local" do |r|
|
139
239
|
# p r
|
140
240
|
# end
|
141
|
-
# sleep 2
|
142
|
-
# s.stop
|
143
241
|
|
144
242
|
def resolve(name, type = name.type, domain = name.domain, flags = 0,
|
145
243
|
interface = DNSSD::InterfaceAny, &block)
|
@@ -149,10 +247,19 @@ class DNSSD::Service
|
|
149
247
|
|
150
248
|
raise DNSSD::Error, 'service in progress' if started?
|
151
249
|
|
152
|
-
_resolve
|
250
|
+
_resolve flags.to_i, interface, name, type, domain
|
251
|
+
|
252
|
+
@type = :resolve
|
153
253
|
|
154
254
|
process(&block)
|
155
255
|
end
|
156
256
|
|
257
|
+
##
|
258
|
+
# Returns true if the service has been started.
|
259
|
+
|
260
|
+
def started?
|
261
|
+
not stopped?
|
262
|
+
end
|
263
|
+
|
157
264
|
end
|
158
265
|
|