dnssd 1.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 dnssd_id_to_str;
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 dnssd_iv_thread;
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
- void
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( rb_ivar_get(service, dnssd_iv_block),
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 DNSSD.enumerate_domains(),
107
- * DNSSD.browse(), DNSSD.register(), and DNSSD.resolve().
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 <code>true</code> if _service_ has been stopped, <code>false</code> otherwise.
227
+ * Returns true if the service has been stopped.
146
228
  */
147
229
 
148
230
  static VALUE
149
- dnssd_service_is_stopped(VALUE service) {
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 _service_ closing the underlying socket and killing
159
- * the underlying thread.
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
- * service = DNSSD.browse('_http._tcp') do |r|
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
- if (client == NULL) rb_raise(eDNSSDError, "service is already stopped");
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 ( FD_ISSET(dns_sd_fd, &readfds) ) {
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, service);
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.@thread
238
- * is set and if the block calls service.stop() will raise an error, even though
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
- * call-seq:
252
- * service.inspect => string
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
- static VALUE
257
- dnssd_service_inspect(VALUE self) {
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, dnssd_domain_enum_new(service, flags, interface_index, domain));
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 (argc, argv, "02", &tmp_flags, &interface);
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 (client, flags, interface_index,
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| } => obj
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 (int argc, VALUE * argv, VALUE self) {
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=0, interface=DNSSD::InterfaceAny) {|reply| bloc } => serivce_handle
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
- * stop enumerating domains (see DNSSD::Service#stop).
338
- *
339
- * available_domains = []
340
- * s = DNSSD.enumerate_domains do |d|
341
- * available_domains << d.domain
342
- * end
343
- * sleep(0.2)
344
- * s.stop
345
- * puts available_domains.inspect
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 (DNSServiceRef client, DNSServiceFlags flags,
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
- dnssd_browse_new (service, flags, interface_index, name, type, domain)
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 (argc, argv, "13", &type,
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 (client, flags, interface_index,
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=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => obj
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
- * timeout(6) do
410
- * DNSSD.browse!('_http._tcp') do |r|
411
- * puts "found: #{r.inspect}"
412
- * end
413
- * rescue TimeoutError
414
- * end
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=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => service_handle
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
- * s = DNSSD.browse('_http._tcp') do |b|
435
- * puts "found: #{b.inspect}"
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 (DNSServiceRef client, DNSServiceFlags flags,
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, dnssd_register_new(service, flags, name, regtype, domain));
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 (argc, argv, "43",
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 = dnssd_tr_to_encoded_str(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
- e = DNSServiceRegister (client, flags, interface_index,
506
- name_str, type_str, domain_str,
507
- NULL, opaqueport, txt_len, txt_rec,
508
- dnssd_register_reply, (void*)service );
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
- * to the block when the registration completes.
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(rb_block_proc()))
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| block } => service_handle
536
- *
537
- * Asynchronously register a service. A DNSSD::Reply object is
538
- * passed to the block when the registration completes.
539
- * The returned _service_handle_ can be used to control when to
540
- * stop the service (see DNSSD::Service#stop).
541
- *
542
- * # Start a webserver and register it using DNS Service Discovery
543
- * require 'dnssd'
544
- * require 'webrick'
545
- *
546
- * web_s = WEBrick::HTTPServer.new(:Port=>8080, :DocumentRoot=>Dir::pwd)
547
- * dns_s = DNSSD.register("My Files", "_http._tcp", nil, 8080) do |r|
548
- * warn("successfully registered: #{r.inspect}")
549
- * end
550
- *
551
- * trap("INT"){ dns_s.stop; web_s.shutdown }
552
- * web_s.start
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(rb_block_proc()))
560
- );
661
+ sd_register(argc, argv, dnssd_service_alloc(block)));
561
662
  }
562
663
 
563
664
  static void DNSSD_API
564
- dnssd_resolve_reply (DNSServiceRef client, DNSServiceFlags flags,
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
- dnssd_resolve_new(service, flags, interface_index, fullname,
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
- type_str = StringValueCStr(type),
595
- domain_str = dnssd_get_domain(domain);
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 (client, flags, interface_index, name_str, type_str,
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 } => obj
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
- * timeout(2) do
620
- * DNSSD.resolve!("foo bar", "_http._tcp", "local") do |r|
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| block } => service_handle
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
- /* hack so rdoc documents the project correctly */
664
- #ifdef mDNSSD_RDOC_HACK
665
- mDNSSD = rb_define_module("DNSSD");
666
- #endif
667
- dnssd_id_call = rb_intern("call");
668
- dnssd_id_to_str = rb_intern("to_str");
669
- dnssd_id_to_i = rb_intern("to_i");
670
- dnssd_iv_block = rb_intern("@block");
671
- dnssd_iv_thread = rb_intern("@thread");
672
- dnssd_iv_result = rb_intern("@result");
673
- dnssd_iv_service = rb_intern("@service");
674
-
675
- cDNSSDService = rb_define_class_under(mDNSSD, "Service", rb_cObject);
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?", dnssd_service_is_stopped, 0);
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
- rb_define_module_function(mDNSSD, "resolve", dnssd_resolve, -1);
694
- rb_define_module_function(mDNSSD, "resolve!", dnssd_resolve_bang, -1);
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