dnssd 1.0 → 1.1.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.
- data/.autotest +15 -0
- data/History.txt +12 -0
- data/Manifest.txt +17 -3
- data/Rakefile +3 -0
- data/ext/dnssd/dnssd.c +8 -128
- data/ext/dnssd/dnssd.h +0 -27
- data/ext/dnssd/errors.c +105 -0
- data/ext/dnssd/extconf.rb +12 -7
- data/ext/dnssd/flags.c +124 -0
- data/ext/dnssd/{dnssd_service.c → service.c} +350 -248
- data/lib/dnssd.rb +4 -1
- data/lib/dnssd/flags.rb +104 -0
- data/lib/dnssd/reply.rb +87 -0
- data/lib/dnssd/service.rb +15 -0
- data/lib/dnssd/text_record.rb +69 -0
- data/sample/browse.rb +11 -0
- data/sample/growl.rb +14 -0
- data/sample/highlevel_api.rb +30 -0
- data/sample/register.rb +30 -0
- data/sample/resolve.rb +13 -0
- data/sample/resolve_ichat.rb +36 -0
- data/test/test_dnssd_reply.rb +64 -0
- data/test/test_dnssd_text_record.rb +83 -0
- metadata +23 -28
- data.tar.gz.sig +0 -0
- data/ext/dnssd/dnssd_structs.c +0 -397
- data/ext/dnssd/dnssd_tr.c +0 -248
- metadata.gz.sig +0 -0
@@ -1,11 +1,3 @@
|
|
1
|
-
/*
|
2
|
-
* Ruby Rendezvous Binding
|
3
|
-
*
|
4
|
-
* Copyright (c) 2004 Chad Fowler, Charles Mills, Rich Kilmer
|
5
|
-
* Licenced under the same terms as Ruby.
|
6
|
-
* This software has absolutely no warranty.
|
7
|
-
*/
|
8
|
-
|
9
1
|
#include "dnssd.h"
|
10
2
|
#include <assert.h>
|
11
3
|
|
@@ -14,14 +6,24 @@
|
|
14
6
|
#define DNSSD_API
|
15
7
|
#endif
|
16
8
|
|
9
|
+
static VALUE cDNSSDReply;
|
17
10
|
static VALUE cDNSSDService;
|
11
|
+
static VALUE cDNSSDTextRecord;
|
12
|
+
|
18
13
|
static ID dnssd_id_call;
|
19
|
-
static ID
|
14
|
+
static ID dnssd_id_encode;
|
20
15
|
static ID dnssd_id_to_i;
|
16
|
+
static ID dnssd_id_to_str;
|
17
|
+
|
21
18
|
static ID dnssd_iv_block;
|
22
|
-
static ID
|
19
|
+
static ID dnssd_iv_domain;
|
20
|
+
static ID dnssd_iv_interface;
|
21
|
+
static ID dnssd_iv_port;
|
23
22
|
static ID dnssd_iv_result;
|
24
23
|
static ID dnssd_iv_service;
|
24
|
+
static ID dnssd_iv_target;
|
25
|
+
static ID dnssd_iv_text_record;
|
26
|
+
static ID dnssd_iv_thread;
|
25
27
|
|
26
28
|
#define IsDNSSDService(obj) (rb_obj_is_kind_of(obj,cDNSSDService)==Qtrue)
|
27
29
|
#define GetDNSSDService(obj, var) \
|
@@ -32,10 +34,131 @@ dnssd_to_flags(VALUE obj) {
|
|
32
34
|
return (DNSServiceFlags)NUM2ULONG(rb_funcall(obj, dnssd_id_to_i, 0));
|
33
35
|
}
|
34
36
|
|
35
|
-
|
37
|
+
static VALUE
|
38
|
+
create_fullname(const char *name, const char *regtype,
|
39
|
+
const char *domain) {
|
40
|
+
char buffer[kDNSServiceMaxDomainName];
|
41
|
+
|
42
|
+
if (DNSServiceConstructFullName(buffer, name, regtype, domain)) {
|
43
|
+
static const char msg[] = "could not construct full service name";
|
44
|
+
rb_raise(rb_eArgError, msg);
|
45
|
+
}
|
46
|
+
|
47
|
+
buffer[kDNSServiceMaxDomainName - 1] = '\000'; /* just in case */
|
48
|
+
return rb_str_new2(buffer);
|
49
|
+
}
|
50
|
+
|
51
|
+
/*
|
52
|
+
* call-seq:
|
53
|
+
* DNSSD::Service.fullname(name, type, domain) => String
|
54
|
+
*
|
55
|
+
* Concatenate a three-part domain name like DNSSD::Reply#fullname into a
|
56
|
+
* properly-escaped full domain name.
|
57
|
+
*
|
58
|
+
* Any dots or slashes in the +name+ must NOT be escaped.
|
59
|
+
*
|
60
|
+
* +name+ may be +nil+ (to construct a PTR record name, e.g.
|
61
|
+
* "_ftp._tcp.apple.com").
|
62
|
+
*
|
63
|
+
* The +type+ is the service type followed by the protocol, separated by a dot
|
64
|
+
* (e.g. "_ftp._tcp").
|
65
|
+
*
|
66
|
+
* The +domain+ is the domain name, e.g. "apple.com". Any literal dots or
|
67
|
+
* backslashes must be escaped.
|
68
|
+
*
|
69
|
+
* Raises ArgumentError if the full service name cannot be
|
70
|
+
* constructed from the arguments.
|
71
|
+
*/
|
72
|
+
|
73
|
+
static VALUE
|
74
|
+
dnssd_service_s_fullname(VALUE klass, VALUE name, VALUE type, VALUE domain) {
|
75
|
+
return create_fullname(StringValueCStr(name), StringValueCStr(type),
|
76
|
+
StringValueCStr(domain));
|
77
|
+
}
|
78
|
+
|
79
|
+
static VALUE
|
80
|
+
text_record_new(VALUE text_record) {
|
81
|
+
return rb_funcall(cDNSSDTextRecord, rb_intern("new"), 1, text_record);
|
82
|
+
}
|
83
|
+
|
84
|
+
static VALUE
|
85
|
+
reply_new(VALUE service, DNSServiceFlags flags) {
|
86
|
+
return rb_funcall(cDNSSDReply, rb_intern("from_service"), 2, service,
|
87
|
+
UINT2NUM(flags));
|
88
|
+
}
|
89
|
+
|
90
|
+
static void
|
91
|
+
reply_set_interface(VALUE self, uint32_t interface) {
|
92
|
+
VALUE if_value;
|
93
|
+
char buffer[IF_NAMESIZE];
|
94
|
+
|
95
|
+
if (if_indextoname(interface, buffer)) {
|
96
|
+
if_value = rb_str_new2(buffer);
|
97
|
+
} else {
|
98
|
+
if_value = ULONG2NUM(interface);
|
99
|
+
}
|
100
|
+
|
101
|
+
rb_ivar_set(self, dnssd_iv_interface, if_value);
|
102
|
+
}
|
103
|
+
|
104
|
+
static VALUE
|
105
|
+
reply_from_browse(VALUE service, DNSServiceFlags flags,
|
106
|
+
uint32_t interface, const char *name, const char *regtype,
|
107
|
+
const char *domain) {
|
108
|
+
VALUE self = reply_new(service, flags);
|
109
|
+
reply_set_interface(self, interface);
|
110
|
+
rb_funcall(self, rb_intern("set_names"), 3, rb_str_new2(name),
|
111
|
+
rb_str_new2(regtype), rb_str_new2(domain));
|
112
|
+
return self;
|
113
|
+
}
|
114
|
+
|
115
|
+
static VALUE
|
116
|
+
reply_from_domain_enum(VALUE service, DNSServiceFlags flags,
|
117
|
+
uint32_t interface, const char *domain) {
|
118
|
+
VALUE self = reply_new(service, flags);
|
119
|
+
reply_set_interface(self, interface);
|
120
|
+
rb_ivar_set(self, dnssd_iv_domain, rb_str_new2(domain));
|
121
|
+
return self;
|
122
|
+
}
|
123
|
+
|
124
|
+
static VALUE
|
125
|
+
reply_from_register(VALUE service, DNSServiceFlags flags,
|
126
|
+
const char *name, const char *regtype, const char *domain) {
|
127
|
+
VALUE self = reply_new(service, flags);
|
128
|
+
rb_funcall(self, rb_intern("set_names"), 3, rb_str_new2(name),
|
129
|
+
rb_str_new2(regtype), rb_str_new2(domain));
|
130
|
+
/* HACK */
|
131
|
+
/* See HACK in dnssd_service.c */
|
132
|
+
rb_ivar_set(self, dnssd_iv_interface,
|
133
|
+
rb_ivar_get(service, dnssd_iv_interface));
|
134
|
+
rb_ivar_set(self, dnssd_iv_port, rb_ivar_get(service, dnssd_iv_port));
|
135
|
+
rb_ivar_set(self, dnssd_iv_text_record,
|
136
|
+
rb_ivar_get(service, dnssd_iv_text_record));
|
137
|
+
/********/
|
138
|
+
return self;
|
139
|
+
}
|
140
|
+
|
141
|
+
static VALUE
|
142
|
+
reply_from_resolve(VALUE service, DNSServiceFlags flags, uint32_t
|
143
|
+
interface, const char *fullname, const char *host_target, uint16_t
|
144
|
+
opaqueport, uint16_t txt_len, const char *txt_rec) {
|
145
|
+
uint16_t port = ntohs(opaqueport);
|
146
|
+
VALUE self = reply_new(service, flags);
|
147
|
+
|
148
|
+
reply_set_interface(self, interface);
|
149
|
+
rb_funcall(self, rb_intern("set_fullname"), 1, rb_str_new2(fullname));
|
150
|
+
rb_ivar_set(self, dnssd_iv_target, rb_str_new2(host_target));
|
151
|
+
rb_ivar_set(self, dnssd_iv_port, UINT2NUM(port));
|
152
|
+
rb_ivar_set(self, dnssd_iv_text_record,
|
153
|
+
text_record_new(rb_str_new(txt_rec, txt_len)));
|
154
|
+
|
155
|
+
return self;
|
156
|
+
}
|
157
|
+
|
158
|
+
static void
|
36
159
|
dnssd_callback(VALUE service, VALUE reply) {
|
37
|
-
VALUE result = rb_funcall2(
|
38
|
-
dnssd_id_call, 1, &reply
|
160
|
+
VALUE result = rb_funcall2(rb_ivar_get(service, dnssd_iv_block),
|
161
|
+
dnssd_id_call, 1, &reply);
|
39
162
|
rb_ivar_set(service, dnssd_iv_result, result);
|
40
163
|
}
|
41
164
|
|
@@ -58,53 +181,12 @@ dnssd_get_interface_index(VALUE interface) {
|
|
58
181
|
}
|
59
182
|
}
|
60
183
|
|
61
|
-
/*
|
62
|
-
* call-seq:
|
63
|
-
* DNSSD::Service.fullname(name, type, domain) => string
|
64
|
-
*
|
65
|
-
* Concatenate a three-part domain name (as seen in DNSSD::Reply#fullname())
|
66
|
-
* into a properly-escaped full domain name.
|
67
|
-
*
|
68
|
-
* Any dots or slashes in the _name_ must NOT be escaped.
|
69
|
-
* May be <code>nil</code> (to construct a PTR record name, e.g. "_ftp._tcp.apple.com").
|
70
|
-
*
|
71
|
-
* The _type_ is the service type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").
|
72
|
-
*
|
73
|
-
* The _domain_ is the domain name, e.g. "apple.com". Any literal dots or backslashes
|
74
|
-
* must be escaped.
|
75
|
-
*
|
76
|
-
* Raises a <code>ArgumentError</code> if the full service name cannot be constructed from
|
77
|
-
* the arguments.
|
78
|
-
*/
|
79
|
-
|
80
|
-
static VALUE
|
81
|
-
dnssd_service_s_fullname(VALUE klass, VALUE name, VALUE type, VALUE domain) {
|
82
|
-
return dnssd_create_fullname( StringValueCStr(name), StringValueCStr(type),
|
83
|
-
StringValueCStr(domain), 1 );
|
84
|
-
}
|
85
|
-
|
86
|
-
/*
|
87
|
-
* call-seq:
|
88
|
-
* DNSSD::Service.split(fullname) => array
|
89
|
-
* DNSSD::Service.split_fullname(fullname) => array
|
90
|
-
*
|
91
|
-
* Split a properly escaped multi-part domain name (as seen in DNSSD::Reply#fullname())
|
92
|
-
* into an array of names.
|
93
|
-
*
|
94
|
-
* DNSSD::Service.split('_http._tcp.local.') #=> ["_http.", "_tcp.", "local."]
|
95
|
-
*/
|
96
|
-
|
97
|
-
static VALUE
|
98
|
-
dnssd_service_s_split(VALUE klass, VALUE fullname) {
|
99
|
-
return dnssd_split_fullname(fullname);
|
100
|
-
}
|
101
|
-
|
102
184
|
/*
|
103
185
|
* call-seq:
|
104
186
|
* DNSSD::Service.new() => raises a RuntimeError
|
105
187
|
*
|
106
|
-
* Services can only be instantiated using
|
107
|
-
*
|
188
|
+
* Services can only be instantiated using ::enumerate_domains, ::browse,
|
189
|
+
* ::register, and ::resolve.
|
108
190
|
*/
|
109
191
|
|
110
192
|
static VALUE
|
@@ -142,11 +224,11 @@ dnssd_service_alloc(VALUE block) {
|
|
142
224
|
* call-seq:
|
143
225
|
* service.stopped? => true or false
|
144
226
|
*
|
145
|
-
* Returns
|
227
|
+
* Returns true if the service has been stopped.
|
146
228
|
*/
|
147
229
|
|
148
230
|
static VALUE
|
149
|
-
|
231
|
+
dnssd_service_stopped_p(VALUE service) {
|
150
232
|
DNSServiceRef *client = (DNSServiceRef*)RDATA(service)->data;
|
151
233
|
return client == NULL ? Qtrue : Qfalse;
|
152
234
|
}
|
@@ -155,27 +237,31 @@ dnssd_service_is_stopped(VALUE service) {
|
|
155
237
|
* call-seq:
|
156
238
|
* service.stop => service
|
157
239
|
*
|
158
|
-
* Stops
|
159
|
-
*
|
160
|
-
*
|
161
|
-
* It is good practice to all stop running services before exit.
|
240
|
+
* Stops the service, closing the underlying socket and killing the underlying
|
241
|
+
* thread.
|
162
242
|
*
|
163
|
-
*
|
164
|
-
* # found a service ...
|
165
|
-
* end
|
166
|
-
* sleep(2)
|
167
|
-
* service.stop
|
243
|
+
* It is good practice to all stop running services before exit.
|
168
244
|
*
|
245
|
+
* service = DNSSD.browse('_http._tcp') do |r|
|
246
|
+
* puts "Found #{r.name}"
|
247
|
+
* end
|
248
|
+
* sleep(2)
|
249
|
+
* service.stop
|
169
250
|
*/
|
170
251
|
|
171
252
|
static VALUE
|
172
253
|
dnssd_service_stop(VALUE service) {
|
173
254
|
VALUE thread;
|
174
255
|
DNSServiceRef *client = (DNSServiceRef*)RDATA(service)->data;
|
256
|
+
|
175
257
|
/* set to null right away for a bit more thread safety */
|
176
258
|
RDATA(service)->data = NULL;
|
177
|
-
|
259
|
+
|
260
|
+
if (client == NULL)
|
261
|
+
rb_raise(eDNSSDError, "service is already stopped");
|
262
|
+
|
178
263
|
dnssd_service_free_client(client);
|
264
|
+
|
179
265
|
thread = rb_ivar_get(service, dnssd_iv_thread);
|
180
266
|
rb_ivar_set(service, dnssd_iv_block, Qnil);
|
181
267
|
rb_ivar_set(service, dnssd_iv_thread, Qnil);
|
@@ -184,9 +270,20 @@ dnssd_service_stop(VALUE service) {
|
|
184
270
|
/* will raise error if thread is not a Ruby Thread */
|
185
271
|
rb_thread_kill(thread);
|
186
272
|
}
|
273
|
+
|
187
274
|
return service;
|
188
275
|
}
|
189
276
|
|
277
|
+
/* stop the service only if it is still running */
|
278
|
+
|
279
|
+
static VALUE
|
280
|
+
dnssd_service_stop2(VALUE service) {
|
281
|
+
if (RTEST(dnssd_service_stopped_p(service))) {
|
282
|
+
return service;
|
283
|
+
}
|
284
|
+
return dnssd_service_stop(service);
|
285
|
+
}
|
286
|
+
|
190
287
|
static VALUE
|
191
288
|
dnssd_service_process(VALUE service) {
|
192
289
|
int dns_sd_fd, nfds, result;
|
@@ -195,6 +292,11 @@ dnssd_service_process(VALUE service) {
|
|
195
292
|
DNSServiceRef *client;
|
196
293
|
GetDNSSDService(service, client);
|
197
294
|
|
295
|
+
if (client == NULL) {
|
296
|
+
/* looks like this thread has already been stopped */
|
297
|
+
return Qnil;
|
298
|
+
}
|
299
|
+
|
198
300
|
dns_sd_fd = DNSServiceRefSockFD(*client);
|
199
301
|
nfds = dns_sd_fd + 1;
|
200
302
|
for ( ;; ) {
|
@@ -205,7 +307,7 @@ dnssd_service_process(VALUE service) {
|
|
205
307
|
(fd_set *) NULL,
|
206
308
|
(struct timeval *) NULL);
|
207
309
|
if (result > 0) {
|
208
|
-
if (
|
310
|
+
if (FD_ISSET(dns_sd_fd, &readfds)) {
|
209
311
|
DNSServiceErrorType e = DNSServiceProcessResult(*client);
|
210
312
|
dnssd_check_error_code(e);
|
211
313
|
}
|
@@ -213,56 +315,33 @@ dnssd_service_process(VALUE service) {
|
|
213
315
|
break;
|
214
316
|
}
|
215
317
|
}
|
318
|
+
|
216
319
|
/* return the result from the processing */
|
217
320
|
return rb_ivar_get(service, dnssd_iv_result);
|
218
321
|
}
|
219
322
|
|
220
|
-
/* stop the service only if it is still running */
|
221
|
-
|
222
|
-
static VALUE
|
223
|
-
dnssd_service_stop2(VALUE service) {
|
224
|
-
if (dnssd_service_is_stopped(service)) {
|
225
|
-
return service;
|
226
|
-
}
|
227
|
-
return dnssd_service_stop(service);
|
228
|
-
}
|
229
|
-
|
230
323
|
static VALUE
|
231
324
|
dnssd_service_start(VALUE service) {
|
232
|
-
return rb_ensure(dnssd_service_process, service, dnssd_service_stop2,
|
325
|
+
return rb_ensure(dnssd_service_process, service, dnssd_service_stop2,
|
326
|
+
service);
|
233
327
|
}
|
234
328
|
|
235
329
|
static VALUE
|
236
330
|
dnssd_service_start_in_thread(VALUE service) {
|
237
|
-
/* race condition - service.@block could be called before the service
|
238
|
-
* is set and if the block calls
|
239
|
-
* the service has been started and is running. */
|
331
|
+
/* race condition - service.@block could be called before the service's
|
332
|
+
* @thread is set and if the block calls #stop will raise an error, even
|
333
|
+
* though the service has been started and is running. */
|
334
|
+
|
240
335
|
VALUE thread = rb_thread_create(dnssd_service_process, (void *)service);
|
241
336
|
rb_ivar_set(service, dnssd_iv_thread, thread);
|
242
|
-
/* !! IMPORTANT: prevents premature garbage collection of the service,
|
243
|
-
* this way the thread holds a reference to the service and
|
244
|
-
* the service gets marked as long as the thread is running.
|
245
|
-
* Running threads are always marked by Ruby. !! */
|
246
|
-
rb_ivar_set(thread, dnssd_iv_service, service);
|
247
|
-
return service;
|
248
|
-
}
|
249
337
|
|
250
|
-
/*
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
*/
|
338
|
+
/* !! IMPORTANT: prevents premature garbage collection of the service, this
|
339
|
+
* way the thread holds a reference to the service and the service gets
|
340
|
+
* marked as long as the thread is running. Running threads are always
|
341
|
+
* marked by Ruby. !! */
|
255
342
|
|
256
|
-
|
257
|
-
|
258
|
-
VALUE buf = rb_str_buf_new(32);
|
259
|
-
rb_str_buf_cat2(buf, "<#");
|
260
|
-
rb_str_buf_cat2(buf, rb_obj_classname(self));
|
261
|
-
if (dnssd_service_is_stopped(self)) {
|
262
|
-
rb_str_buf_cat2(buf, " (stopped)");
|
263
|
-
}
|
264
|
-
rb_str_buf_cat2(buf, ">");
|
265
|
-
return buf;
|
343
|
+
rb_ivar_set(thread, dnssd_iv_service, service);
|
344
|
+
return service;
|
266
345
|
}
|
267
346
|
|
268
347
|
static void DNSSD_API
|
@@ -273,7 +352,8 @@ dnssd_domain_enum_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
|
|
273
352
|
/* other parameters are undefined if errorCode != 0 */
|
274
353
|
dnssd_check_error_code(e);
|
275
354
|
service = (VALUE)context;
|
276
|
-
dnssd_callback(service,
|
355
|
+
dnssd_callback(service,
|
356
|
+
reply_from_domain_enum(service, flags, interface_index, domain));
|
277
357
|
}
|
278
358
|
|
279
359
|
static VALUE
|
@@ -286,16 +366,17 @@ sd_enumerate_domains(int argc, VALUE *argv, VALUE service) {
|
|
286
366
|
DNSServiceErrorType e;
|
287
367
|
DNSServiceRef *client;
|
288
368
|
|
289
|
-
rb_scan_args
|
369
|
+
rb_scan_args(argc, argv, "02", &tmp_flags, &interface);
|
290
370
|
|
291
371
|
/* optional parameters */
|
292
372
|
if (!NIL_P(tmp_flags))
|
293
373
|
flags = dnssd_to_flags(tmp_flags);
|
374
|
+
|
294
375
|
if (!NIL_P(interface))
|
295
376
|
interface_index = dnssd_get_interface_index(interface);
|
296
377
|
|
297
378
|
GetDNSSDService(service, client);
|
298
|
-
e = DNSServiceEnumerateDomains
|
379
|
+
e = DNSServiceEnumerateDomains(client, flags, interface_index,
|
299
380
|
dnssd_domain_enum_reply, (void *)service);
|
300
381
|
dnssd_check_error_code(e);
|
301
382
|
return service;
|
@@ -303,7 +384,7 @@ sd_enumerate_domains(int argc, VALUE *argv, VALUE service) {
|
|
303
384
|
|
304
385
|
/*
|
305
386
|
* call-seq:
|
306
|
-
* DNSSD.enumerate_domains!(flags, interface) { |reply| } =>
|
387
|
+
* DNSSD.enumerate_domains!(flags, interface) { |reply| } => service
|
307
388
|
*
|
308
389
|
* Synchronously enumerate domains available for browsing and registration.
|
309
390
|
* For each domain found a DNSSD::Reply object is passed to block with #domain
|
@@ -321,40 +402,39 @@ sd_enumerate_domains(int argc, VALUE *argv, VALUE service) {
|
|
321
402
|
*/
|
322
403
|
|
323
404
|
static VALUE
|
324
|
-
dnssd_enumerate_domains_bang
|
405
|
+
dnssd_enumerate_domains_bang(int argc, VALUE * argv, VALUE self) {
|
325
406
|
return dnssd_service_start(
|
326
|
-
sd_enumerate_domains(argc, argv, dnssd_service_alloc(rb_block_proc()))
|
327
|
-
);
|
407
|
+
sd_enumerate_domains(argc, argv, dnssd_service_alloc(rb_block_proc())));
|
328
408
|
}
|
329
409
|
|
330
410
|
/*
|
331
411
|
* call-seq:
|
332
|
-
* DNSSD.enumerate_domains(flags
|
412
|
+
* DNSSD.enumerate_domains(flags, interface) {|reply| } => serivce
|
333
413
|
*
|
334
414
|
* Asynchronously enumerate domains available for browsing and registration.
|
335
415
|
* For each domain found a DNSSD::DomainEnumReply object is passed to block.
|
336
|
-
* The returned _service_handle_ can be used to control when to
|
337
|
-
*
|
338
|
-
*
|
339
|
-
*
|
340
|
-
*
|
341
|
-
*
|
342
|
-
*
|
343
|
-
*
|
344
|
-
*
|
345
|
-
*
|
346
|
-
*
|
416
|
+
* The returned _service_handle_ can be used to control when to stop
|
417
|
+
* enumerating domains (see DNSSD::Service#stop).
|
418
|
+
*
|
419
|
+
* domains = []
|
420
|
+
*
|
421
|
+
* s = DNSSD.enumerate_domains do |d|
|
422
|
+
* domains << d.domain
|
423
|
+
* end
|
424
|
+
*
|
425
|
+
* sleep(0.2)
|
426
|
+
* s.stop
|
427
|
+
* p domains
|
347
428
|
*/
|
348
429
|
|
349
430
|
static VALUE
|
350
431
|
dnssd_enumerate_domains(int argc, VALUE * argv, VALUE self) {
|
351
432
|
return dnssd_service_start_in_thread(
|
352
|
-
sd_enumerate_domains(argc, argv, dnssd_service_alloc(rb_block_proc()))
|
353
|
-
);
|
433
|
+
sd_enumerate_domains(argc, argv, dnssd_service_alloc(rb_block_proc())));
|
354
434
|
}
|
355
435
|
|
356
436
|
static void DNSSD_API
|
357
|
-
dnssd_browse_reply
|
437
|
+
dnssd_browse_reply(DNSServiceRef client, DNSServiceFlags flags,
|
358
438
|
uint32_t interface_index, DNSServiceErrorType e,
|
359
439
|
const char *name, const char *type,
|
360
440
|
const char *domain, void *context) {
|
@@ -363,8 +443,7 @@ dnssd_browse_reply (DNSServiceRef client, DNSServiceFlags flags,
|
|
363
443
|
dnssd_check_error_code(e);
|
364
444
|
service = (VALUE)context;
|
365
445
|
dnssd_callback(service,
|
366
|
-
|
367
|
-
);
|
446
|
+
reply_from_browse(service, flags, interface_index, name, type, domain));
|
368
447
|
}
|
369
448
|
|
370
449
|
static VALUE
|
@@ -379,21 +458,21 @@ sd_browse(int argc, VALUE *argv, VALUE service) {
|
|
379
458
|
DNSServiceErrorType e;
|
380
459
|
DNSServiceRef *client;
|
381
460
|
|
382
|
-
rb_scan_args
|
383
|
-
&domain, &tmp_flags, &interface);
|
461
|
+
rb_scan_args(argc, argv, "13", &type, &domain, &tmp_flags, &interface);
|
384
462
|
type_str = StringValueCStr(type);
|
385
463
|
|
386
464
|
/* optional parameters */
|
387
465
|
if (!NIL_P(domain))
|
388
466
|
domain_str = dnssd_get_domain(domain);
|
467
|
+
|
389
468
|
if (!NIL_P(tmp_flags))
|
390
469
|
flags = dnssd_to_flags(tmp_flags);
|
470
|
+
|
391
471
|
if (!NIL_P(interface))
|
392
472
|
interface_index = dnssd_get_interface_index(interface);
|
393
473
|
|
394
474
|
GetDNSSDService(service, client);
|
395
|
-
e = DNSServiceBrowse
|
396
|
-
type_str, domain_str,
|
475
|
+
e = DNSServiceBrowse(client, flags, interface_index, type_str, domain_str,
|
397
476
|
dnssd_browse_reply, (void *)service);
|
398
477
|
dnssd_check_error_code(e);
|
399
478
|
return service;
|
@@ -401,51 +480,65 @@ sd_browse(int argc, VALUE *argv, VALUE service) {
|
|
401
480
|
|
402
481
|
/*
|
403
482
|
* call-seq:
|
404
|
-
* DNSSD.browse!(type, domain
|
483
|
+
* DNSSD.browse!(type, domain, flags, interface) {|reply| } => service
|
405
484
|
*
|
406
485
|
* Synchronously browse for services.
|
486
|
+
*
|
487
|
+
* +domain+ is optional
|
488
|
+
*
|
489
|
+
* +flags+ is 0 by default
|
490
|
+
*
|
491
|
+
* +interface+ is DNSSD::InterfaceAny by default
|
492
|
+
*
|
407
493
|
* For each service found a DNSSD::Reply object is passed to block.
|
408
494
|
*
|
409
|
-
*
|
410
|
-
*
|
411
|
-
*
|
412
|
-
*
|
413
|
-
*
|
414
|
-
*
|
495
|
+
* timeout 6 do
|
496
|
+
* DNSSD.browse! '_http._tcp' do |r|
|
497
|
+
* puts "found: #{r.name}"
|
498
|
+
* end
|
499
|
+
* rescue TimeoutError
|
500
|
+
* end
|
415
501
|
*
|
416
502
|
*/
|
417
503
|
|
418
504
|
static VALUE
|
419
505
|
dnssd_browse_bang(int argc, VALUE * argv, VALUE self) {
|
420
506
|
return dnssd_service_start(
|
421
|
-
sd_browse(argc, argv, dnssd_service_alloc(rb_block_proc()))
|
422
|
-
);
|
507
|
+
sd_browse(argc, argv, dnssd_service_alloc(rb_block_proc())));
|
423
508
|
}
|
424
509
|
|
425
510
|
/*
|
426
511
|
* call-seq:
|
427
|
-
* DNSSD.browse(type, domain
|
512
|
+
* DNSSD.browse(type, domain, flags, interface) {|reply| } => service
|
428
513
|
*
|
429
514
|
* Asynchronously browse for services.
|
515
|
+
*
|
516
|
+
* +domain+ is optional
|
517
|
+
*
|
518
|
+
* +flags+ is 0 by default
|
519
|
+
*
|
520
|
+
* +interface+ is DNSSD::InterfaceAny by default
|
521
|
+
*
|
430
522
|
* For each service found a DNSSD::BrowseReply object is passed to block.
|
431
|
-
* The returned _service_handle_ can be used to control when to
|
432
|
-
* stop browsing for services (see DNSSD::Service#stop).
|
433
523
|
*
|
434
|
-
*
|
435
|
-
*
|
436
|
-
* end
|
524
|
+
* The returned service can be used to control when to stop browsing for
|
525
|
+
* services (see DNSSD::Service#stop).
|
437
526
|
*
|
527
|
+
* s = DNSSD.browse '_http._tcp' do |b|
|
528
|
+
* puts "found: #{b.name}"
|
529
|
+
* end
|
530
|
+
*
|
531
|
+
* s.stop
|
438
532
|
*/
|
439
533
|
|
440
534
|
static VALUE
|
441
535
|
dnssd_browse(int argc, VALUE * argv, VALUE self) {
|
442
536
|
return dnssd_service_start_in_thread(
|
443
|
-
sd_browse(argc, argv, dnssd_service_alloc(rb_block_proc()))
|
444
|
-
);
|
537
|
+
sd_browse(argc, argv, dnssd_service_alloc(rb_block_proc())));
|
445
538
|
}
|
446
539
|
|
447
540
|
static void DNSSD_API
|
448
|
-
dnssd_register_reply
|
541
|
+
dnssd_register_reply(DNSServiceRef client, DNSServiceFlags flags,
|
449
542
|
DNSServiceErrorType e,
|
450
543
|
const char *name, const char *regtype,
|
451
544
|
const char *domain, void *context) {
|
@@ -453,13 +546,13 @@ dnssd_register_reply (DNSServiceRef client, DNSServiceFlags flags,
|
|
453
546
|
/* other parameters are undefined if errorCode != 0 */
|
454
547
|
dnssd_check_error_code(e);
|
455
548
|
service = (VALUE)context;
|
456
|
-
dnssd_callback(service,
|
549
|
+
dnssd_callback(service,
|
550
|
+
reply_from_register(service, flags, name, regtype, domain));
|
457
551
|
}
|
458
552
|
|
459
553
|
static VALUE
|
460
554
|
sd_register(int argc, VALUE *argv, VALUE service) {
|
461
|
-
VALUE name, type, domain, port,
|
462
|
-
text_record, tmp_flags, interface;
|
555
|
+
VALUE name, type, domain, port, text_record, tmp_flags, interface;
|
463
556
|
|
464
557
|
const char *name_str, *type_str, *domain_str = NULL;
|
465
558
|
uint16_t opaqueport;
|
@@ -471,8 +564,7 @@ sd_register(int argc, VALUE *argv, VALUE service) {
|
|
471
564
|
DNSServiceErrorType e;
|
472
565
|
DNSServiceRef *client;
|
473
566
|
|
474
|
-
rb_scan_args
|
475
|
-
&name, &type, &domain, &port,
|
567
|
+
rb_scan_args(argc, argv, "43", &name, &type, &domain, &port,
|
476
568
|
&text_record, &tmp_flags, &interface);
|
477
569
|
|
478
570
|
/* required parameters */
|
@@ -481,17 +573,20 @@ sd_register(int argc, VALUE *argv, VALUE service) {
|
|
481
573
|
|
482
574
|
if (!NIL_P(domain))
|
483
575
|
domain_str = dnssd_get_domain(domain);
|
576
|
+
|
484
577
|
/* convert from host to net byte order */
|
485
578
|
opaqueport = htons((uint16_t)NUM2UINT(port));
|
486
579
|
|
487
580
|
/* optional parameters */
|
488
581
|
if (!NIL_P(text_record)) {
|
489
|
-
text_record =
|
582
|
+
text_record = rb_funcall(text_record, dnssd_id_encode, 0);
|
490
583
|
txt_rec = RSTRING_PTR(text_record);
|
491
584
|
txt_len = RSTRING_LEN(text_record);
|
492
585
|
}
|
586
|
+
|
493
587
|
if (!NIL_P(tmp_flags))
|
494
588
|
flags = dnssd_to_flags(tmp_flags);
|
589
|
+
|
495
590
|
if(!NIL_P(interface))
|
496
591
|
interface_index = dnssd_get_interface_index(interface);
|
497
592
|
|
@@ -502,10 +597,10 @@ sd_register(int argc, VALUE *argv, VALUE service) {
|
|
502
597
|
rb_iv_set(service, "@port", port);
|
503
598
|
rb_iv_set(service, "@text_record", text_record);
|
504
599
|
/********/
|
505
|
-
|
506
|
-
|
507
|
-
NULL, opaqueport, txt_len, txt_rec,
|
508
|
-
|
600
|
+
|
601
|
+
e = DNSServiceRegister(client, flags, interface_index, name_str, type_str,
|
602
|
+
domain_str, NULL, opaqueport, txt_len, txt_rec, dnssd_register_reply,
|
603
|
+
(void*)service);
|
509
604
|
dnssd_check_error_code(e);
|
510
605
|
return service;
|
511
606
|
}
|
@@ -514,54 +609,60 @@ sd_register(int argc, VALUE *argv, VALUE service) {
|
|
514
609
|
* call-seq:
|
515
610
|
* DNSSD.register!(name, type, domain, port, text_record=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => obj
|
516
611
|
*
|
517
|
-
* Synchronously register a service. A DNSSD::Reply object is passed
|
518
|
-
*
|
519
|
-
*
|
520
|
-
* DNSSD.register!("My Files", "_http._tcp", nil, 8080) do |r|
|
521
|
-
* warn("successfully registered: #{r.inspect}")
|
522
|
-
* end
|
612
|
+
* Synchronously register a service. A DNSSD::Reply object is passed to the
|
613
|
+
* optional block when the registration completes.
|
523
614
|
*
|
615
|
+
* DNSSD.register! "My Files", "_http._tcp", nil, 8080 do |r|
|
616
|
+
* puts "successfully registered: #{r.inspect}"
|
617
|
+
* end
|
524
618
|
*/
|
525
619
|
|
526
620
|
static VALUE
|
527
621
|
dnssd_register_bang(int argc, VALUE * argv, VALUE self) {
|
622
|
+
VALUE block = Qnil;
|
623
|
+
|
624
|
+
if (rb_block_given_p())
|
625
|
+
block = rb_block_proc();
|
626
|
+
|
528
627
|
return dnssd_service_start(
|
529
|
-
sd_register(argc, argv, dnssd_service_alloc(
|
530
|
-
);
|
628
|
+
sd_register(argc, argv, dnssd_service_alloc(block)));
|
531
629
|
}
|
532
630
|
|
533
631
|
/*
|
534
632
|
* call-seq:
|
535
|
-
* DNSSD.register(name, type, domain, port, text_record=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply|
|
536
|
-
*
|
537
|
-
* Asynchronously register a service. A DNSSD::Reply object is
|
538
|
-
*
|
539
|
-
*
|
540
|
-
*
|
541
|
-
*
|
542
|
-
*
|
543
|
-
*
|
544
|
-
*
|
545
|
-
*
|
546
|
-
*
|
547
|
-
*
|
548
|
-
*
|
549
|
-
*
|
550
|
-
*
|
551
|
-
*
|
552
|
-
*
|
553
|
-
*
|
633
|
+
* DNSSD.register(name, type, domain, port, text_record=nil, flags=0, interface=DNSSD::InterfaceAny) { |reply| } => service
|
634
|
+
*
|
635
|
+
* Asynchronously register a service. A DNSSD::Reply object is passed to the
|
636
|
+
* optional block when the registration completes.
|
637
|
+
*
|
638
|
+
* The returned service can be used to control when to stop the service.
|
639
|
+
*
|
640
|
+
* # Start a webserver and register it using DNS Service Discovery
|
641
|
+
* require 'dnssd'
|
642
|
+
* require 'webrick'
|
643
|
+
*
|
644
|
+
* web_s = WEBrick::HTTPServer.new :Port => 8080, :DocumentRoot => Dir.pwd
|
645
|
+
* dns_s = DNSSD.register "My Files", "_http._tcp", nil, 8080 do |r|
|
646
|
+
* warn "successfully registered: #{r.inspect}"
|
647
|
+
* end
|
648
|
+
*
|
649
|
+
* trap "INT" do dns_s.stop; web_s.shutdown end
|
650
|
+
* web_s.start
|
554
651
|
*/
|
555
652
|
|
556
653
|
static VALUE
|
557
654
|
dnssd_register(int argc, VALUE * argv, VALUE self) {
|
655
|
+
VALUE block = Qnil;
|
656
|
+
|
657
|
+
if (rb_block_given_p())
|
658
|
+
block = rb_block_proc();
|
659
|
+
|
558
660
|
return dnssd_service_start_in_thread(
|
559
|
-
sd_register(argc, argv, dnssd_service_alloc(
|
560
|
-
);
|
661
|
+
sd_register(argc, argv, dnssd_service_alloc(block)));
|
561
662
|
}
|
562
663
|
|
563
664
|
static void DNSSD_API
|
564
|
-
dnssd_resolve_reply
|
665
|
+
dnssd_resolve_reply(DNSServiceRef client, DNSServiceFlags flags,
|
565
666
|
uint32_t interface_index, DNSServiceErrorType e,
|
566
667
|
const char *fullname, const char *host_target,
|
567
668
|
uint16_t opaqueport, uint16_t txt_len,
|
@@ -571,9 +672,8 @@ dnssd_resolve_reply (DNSServiceRef client, DNSServiceFlags flags,
|
|
571
672
|
dnssd_check_error_code(e);
|
572
673
|
service = (VALUE)context;
|
573
674
|
dnssd_callback(service,
|
574
|
-
|
575
|
-
host_target, opaqueport, txt_len, txt_rec)
|
576
|
-
);
|
675
|
+
reply_from_resolve(service, flags, interface_index, fullname,
|
676
|
+
host_target, opaqueport, txt_len, txt_rec));
|
577
677
|
}
|
578
678
|
|
579
679
|
static VALUE
|
@@ -590,18 +690,19 @@ sd_resolve(int argc, VALUE *argv, VALUE service) {
|
|
590
690
|
rb_scan_args(argc, argv, "32", &name, &type, &domain, &tmp_flags, &interface);
|
591
691
|
|
592
692
|
/* required parameters */
|
593
|
-
name_str = StringValueCStr(name)
|
594
|
-
|
595
|
-
|
693
|
+
name_str = StringValueCStr(name);
|
694
|
+
type_str = StringValueCStr(type);
|
695
|
+
domain_str = dnssd_get_domain(domain);
|
596
696
|
|
597
697
|
/* optional parameters */
|
598
698
|
if (!NIL_P(tmp_flags))
|
599
699
|
flags = dnssd_to_flags(tmp_flags);
|
700
|
+
|
600
701
|
if (!NIL_P(interface))
|
601
702
|
interface_index = dnssd_get_interface_index(interface);
|
602
703
|
|
603
704
|
GetDNSSDService(service, client);
|
604
|
-
err = DNSServiceResolve
|
705
|
+
err = DNSServiceResolve(client, flags, interface_index, name_str, type_str,
|
605
706
|
domain_str, dnssd_resolve_reply, (void *)service);
|
606
707
|
dnssd_check_error_code(err);
|
607
708
|
return service;
|
@@ -609,90 +710,91 @@ sd_resolve(int argc, VALUE *argv, VALUE service) {
|
|
609
710
|
|
610
711
|
/*
|
611
712
|
* call-seq:
|
612
|
-
* DNSSD.resolve!(name, type, domain, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } =>
|
713
|
+
* DNSSD.resolve!(name, type, domain, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => service
|
613
714
|
*
|
614
715
|
* Synchronously resolve a service discovered via DNSSD.browse().
|
615
|
-
* The service is resolved to a target host name, port number, and
|
616
|
-
* text record - all contained in the DNSSD::Reply object
|
617
|
-
* passed to the required block.
|
618
716
|
*
|
619
|
-
*
|
620
|
-
*
|
621
|
-
* puts r.inspect
|
622
|
-
* end
|
623
|
-
* rescue TimeoutError
|
624
|
-
* end
|
717
|
+
* The service is resolved to a target host name, port number, and text record
|
718
|
+
* - all contained in the DNSSD::Reply object passed to the required block.
|
625
719
|
*
|
720
|
+
* timeout 2 do
|
721
|
+
* DNSSD.resolve! "foo bar", "_http._tcp", "local" do |r|
|
722
|
+
* p r
|
723
|
+
* end
|
724
|
+
* rescue TimeoutError
|
725
|
+
* end
|
626
726
|
*/
|
627
727
|
|
628
728
|
static VALUE
|
629
729
|
dnssd_resolve_bang(int argc, VALUE * argv, VALUE self) {
|
630
730
|
return dnssd_service_start(
|
631
|
-
sd_resolve(argc, argv, dnssd_service_alloc(rb_block_proc()))
|
632
|
-
);
|
731
|
+
sd_resolve(argc, argv, dnssd_service_alloc(rb_block_proc())));
|
633
732
|
}
|
634
733
|
|
635
734
|
/*
|
636
735
|
* call-seq:
|
637
|
-
* DNSSD.resolve(name, type, domain, flags=0, interface=DNSSD::InterfaceAny) {|reply|
|
736
|
+
* DNSSD.resolve(name, type, domain, flags=0, interface=DNSSD::InterfaceAny) {|reply| } => service
|
638
737
|
*
|
639
738
|
* Asynchronously resolve a service discovered via DNSSD.browse().
|
640
|
-
* The service is resolved to a target host name, port number, and
|
641
|
-
* text record - all contained in the DNSSD::Reply object
|
642
|
-
* passed to the required block.
|
643
|
-
* The returned _service_handle_ can be used to control when to
|
644
|
-
* stop resolving the service (see DNSSD::Service#stop).
|
645
|
-
*
|
646
|
-
* s = DNSSD.resolve("foo bar", "_http._tcp", "local") do |r|
|
647
|
-
* puts r.inspect
|
648
|
-
* end
|
649
|
-
* sleep(2)
|
650
|
-
* s.stop
|
651
739
|
*
|
740
|
+
* The service is resolved to a target host name, port number, and text record
|
741
|
+
* - all contained in the DNSSD::Reply object passed to the required block.
|
742
|
+
*
|
743
|
+
* The returned service can be used to control when to stop resolving the
|
744
|
+
* service (see DNSSD::Service#stop).
|
745
|
+
*
|
746
|
+
* s = DNSSD.resolve "foo bar", "_http._tcp", "local" do |r|
|
747
|
+
* p r
|
748
|
+
* end
|
749
|
+
* sleep 2
|
750
|
+
* s.stop
|
652
751
|
*/
|
653
752
|
|
654
753
|
static VALUE
|
655
754
|
dnssd_resolve(int argc, VALUE * argv, VALUE self) {
|
656
755
|
return dnssd_service_start_in_thread(
|
657
|
-
sd_resolve(argc, argv, dnssd_service_alloc(rb_block_proc()))
|
658
|
-
);
|
756
|
+
sd_resolve(argc, argv, dnssd_service_alloc(rb_block_proc())));
|
659
757
|
}
|
660
758
|
|
661
759
|
void
|
662
760
|
Init_DNSSD_Service(void) {
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
dnssd_id_to_str
|
669
|
-
|
670
|
-
dnssd_iv_block
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
761
|
+
VALUE mDNSSD = rb_define_module("DNSSD");
|
762
|
+
|
763
|
+
dnssd_id_call = rb_intern("call");
|
764
|
+
dnssd_id_encode = rb_intern("encode");
|
765
|
+
dnssd_id_to_i = rb_intern("to_i");
|
766
|
+
dnssd_id_to_str = rb_intern("to_str");
|
767
|
+
|
768
|
+
dnssd_iv_block = rb_intern("@block");
|
769
|
+
dnssd_iv_domain = rb_intern("@domain");
|
770
|
+
dnssd_iv_interface = rb_intern("@interface");
|
771
|
+
dnssd_iv_port = rb_intern("@port");
|
772
|
+
dnssd_iv_result = rb_intern("@result");
|
773
|
+
dnssd_iv_service = rb_intern("@service");
|
774
|
+
dnssd_iv_target = rb_intern("@target");
|
775
|
+
dnssd_iv_text_record = rb_intern("@text_record");
|
776
|
+
dnssd_iv_thread = rb_intern("@thread");
|
777
|
+
|
778
|
+
cDNSSDReply = rb_define_class_under(mDNSSD, "Reply", rb_cObject);
|
779
|
+
cDNSSDService = rb_define_class_under(mDNSSD, "Service", rb_cObject);
|
780
|
+
cDNSSDTextRecord = rb_define_class_under(mDNSSD, "TextRecord", rb_cObject);
|
676
781
|
|
677
782
|
rb_define_singleton_method(cDNSSDService, "new", dnssd_service_new, -1);
|
678
783
|
rb_define_singleton_method(cDNSSDService, "fullname", dnssd_service_s_fullname, 3);
|
679
|
-
rb_define_singleton_method(cDNSSDService, "split_fullname", dnssd_service_s_split, 1);
|
680
|
-
rb_define_singleton_method(cDNSSDService, "split", dnssd_service_s_split, 1);
|
681
|
-
|
682
|
-
/* Access the services underlying thread. Returns nil if the service is synchronous. */
|
683
|
-
rb_define_attr(cDNSSDService, "thread", 1, 0);
|
684
784
|
|
685
785
|
rb_define_method(cDNSSDService, "stop", dnssd_service_stop, 0);
|
686
|
-
rb_define_method(cDNSSDService, "stopped?",
|
687
|
-
rb_define_method(cDNSSDService, "inspect", dnssd_service_inspect, 0);
|
786
|
+
rb_define_method(cDNSSDService, "stopped?", dnssd_service_stopped_p, 0);
|
688
787
|
|
689
|
-
rb_define_module_function(mDNSSD, "enumerate_domains", dnssd_enumerate_domains, -1);
|
690
|
-
rb_define_module_function(mDNSSD, "enumerate_domains!", dnssd_enumerate_domains_bang, -1);
|
691
788
|
rb_define_module_function(mDNSSD, "browse", dnssd_browse, -1);
|
692
789
|
rb_define_module_function(mDNSSD, "browse!", dnssd_browse_bang, -1);
|
693
|
-
|
694
|
-
rb_define_module_function(mDNSSD, "
|
790
|
+
|
791
|
+
rb_define_module_function(mDNSSD, "enumerate_domains", dnssd_enumerate_domains, -1);
|
792
|
+
rb_define_module_function(mDNSSD, "enumerate_domains!", dnssd_enumerate_domains_bang, -1);
|
793
|
+
|
695
794
|
rb_define_module_function(mDNSSD, "register", dnssd_register, -1);
|
696
795
|
rb_define_module_function(mDNSSD, "register!", dnssd_register_bang, -1);
|
796
|
+
|
797
|
+
rb_define_module_function(mDNSSD, "resolve", dnssd_resolve, -1);
|
798
|
+
rb_define_module_function(mDNSSD, "resolve!", dnssd_resolve_bang, -1);
|
697
799
|
}
|
698
800
|
|