dnssd 1.1.0 → 1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,4 @@
1
1
  #include "dnssd.h"
2
- #include <assert.h>
3
2
 
4
3
  #ifndef DNSSD_API
5
4
  /* define as nothing if not defined in Apple's "dns_sd.h" header */
@@ -10,28 +9,52 @@ static VALUE cDNSSDReply;
10
9
  static VALUE cDNSSDService;
11
10
  static VALUE cDNSSDTextRecord;
12
11
 
13
- static ID dnssd_id_call;
14
- static ID dnssd_id_encode;
15
- static ID dnssd_id_to_i;
16
- static ID dnssd_id_to_str;
12
+ static ID dnssd_id_join;
13
+ static ID dnssd_id_push;
17
14
 
18
- static ID dnssd_iv_block;
15
+ static ID dnssd_iv_continue;
19
16
  static ID dnssd_iv_domain;
20
17
  static ID dnssd_iv_interface;
21
18
  static ID dnssd_iv_port;
22
- static ID dnssd_iv_result;
23
- static ID dnssd_iv_service;
19
+ static ID dnssd_iv_replies;
24
20
  static ID dnssd_iv_target;
25
21
  static ID dnssd_iv_text_record;
26
22
  static ID dnssd_iv_thread;
27
23
 
28
- #define IsDNSSDService(obj) (rb_obj_is_kind_of(obj,cDNSSDService)==Qtrue)
24
+ /* HACK why is this a macro */
29
25
  #define GetDNSSDService(obj, var) \
30
- do { assert(IsDNSSDService(obj)); Data_Get_Struct(obj, DNSServiceRef, var); } while (0)
26
+ do {\
27
+ Check_Type(obj, T_DATA);\
28
+ if (rb_obj_is_kind_of(obj, cDNSSDService) != Qtrue)\
29
+ rb_raise(rb_eTypeError,\
30
+ "wrong argument type %s (expected DNSSD::Service)",\
31
+ rb_class2name(CLASS_OF(obj)));\
32
+ Data_Get_Struct(obj, DNSServiceRef, var);\
33
+ } while (0)
31
34
 
32
- static DNSServiceFlags
33
- dnssd_to_flags(VALUE obj) {
34
- return (DNSServiceFlags)NUM2ULONG(rb_funcall(obj, dnssd_id_to_i, 0));
35
+ static void
36
+ dnssd_service_callback(VALUE self, VALUE reply) {
37
+ VALUE replies = rb_ivar_get(self, dnssd_iv_replies);
38
+
39
+ rb_funcall(replies, dnssd_id_push, 1, reply);
40
+ }
41
+
42
+ static void
43
+ dnssd_service_free_client(DNSServiceRef *client) {
44
+ if (*client) {
45
+ DNSServiceRefDeallocate(*client);
46
+ *client = NULL;
47
+ }
48
+ }
49
+
50
+ static void
51
+ dnssd_service_free(void *ptr) {
52
+ DNSServiceRef *client = (DNSServiceRef*)ptr;
53
+
54
+ if (client)
55
+ dnssd_service_free_client(client);
56
+
57
+ free(client);
35
58
  }
36
59
 
37
60
  static VALUE
@@ -48,6 +71,26 @@ create_fullname(const char *name, const char *regtype,
48
71
  return rb_str_new2(buffer);
49
72
  }
50
73
 
74
+ static VALUE
75
+ reply_new(VALUE service, DNSServiceFlags flags) {
76
+ return rb_funcall(cDNSSDReply, rb_intern("from_service"), 2, service,
77
+ UINT2NUM(flags));
78
+ }
79
+
80
+ static void
81
+ reply_set_interface(VALUE self, uint32_t interface) {
82
+ VALUE if_value;
83
+ char buffer[IF_NAMESIZE];
84
+
85
+ if (if_indextoname(interface, buffer)) {
86
+ if_value = rb_str_new2(buffer);
87
+ } else {
88
+ if_value = ULONG2NUM(interface);
89
+ }
90
+
91
+ rb_ivar_set(self, dnssd_iv_interface, if_value);
92
+ }
93
+
51
94
  /*
52
95
  * call-seq:
53
96
  * DNSSD::Service.fullname(name, type, domain) => String
@@ -77,147 +120,28 @@ dnssd_service_s_fullname(VALUE klass, VALUE name, VALUE type, VALUE domain) {
77
120
  }
78
121
 
79
122
  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
- }
123
+ dnssd_service_s_allocate(VALUE klass) {
124
+ DNSServiceRef *client = ALLOC(DNSServiceRef);
157
125
 
158
- static void
159
- dnssd_callback(VALUE service, VALUE reply) {
160
- VALUE result = rb_funcall2(rb_ivar_get(service, dnssd_iv_block),
161
- dnssd_id_call, 1, &reply);
162
- rb_ivar_set(service, dnssd_iv_result, result);
163
- }
126
+ *client = NULL;
164
127
 
165
- static const char *
166
- dnssd_get_domain(VALUE service_domain) {
167
- const char *domain = StringValueCStr(service_domain);
168
- /* max len including the null terminator and trailing '.' */
169
- if (RSTRING_LEN(service_domain) >= kDNSServiceMaxDomainName - 1)
170
- rb_raise(rb_eArgError, "domain name string too large");
171
- return domain;
172
- }
173
-
174
- static uint32_t
175
- dnssd_get_interface_index(VALUE interface) {
176
- /* if the interface is a string then convert it to the interface index */
177
- if (rb_respond_to(interface, dnssd_id_to_str)) {
178
- return if_nametoindex(StringValueCStr(interface));
179
- } else {
180
- return (uint32_t)NUM2ULONG(interface);
181
- }
128
+ return Data_Wrap_Struct(klass, 0, dnssd_service_free, client);
182
129
  }
183
130
 
184
131
  /*
185
132
  * call-seq:
186
- * DNSSD::Service.new() => raises a RuntimeError
133
+ * service.started? => true or false
187
134
  *
188
- * Services can only be instantiated using ::enumerate_domains, ::browse,
189
- * ::register, and ::resolve.
135
+ * Returns true if the service has been started.
190
136
  */
191
137
 
192
138
  static VALUE
193
- dnssd_service_new(int argc, VALUE *argv, VALUE klass) {
194
- dnssd_instantiation_error(rb_class2name(klass));
195
- return Qnil;
196
- }
197
-
198
- static void
199
- dnssd_service_free_client(DNSServiceRef *client) {
200
- DNSServiceRefDeallocate(*client);
201
- free(client); /* free the pointer */
202
- }
203
-
204
- static void
205
- dnssd_service_free(void *ptr) {
206
- DNSServiceRef *client = (DNSServiceRef*)ptr;
207
- if (client) {
208
- /* client will be non-null only if client has not been deallocated */
209
- dnssd_service_free_client(client);
210
- }
211
- }
139
+ dnssd_service_started_p(VALUE service) {
140
+ DNSServiceRef *client = (DNSServiceRef*)RDATA(service)->data;
141
+ if (client)
142
+ return (*client) == NULL ? Qfalse : Qtrue;
212
143
 
213
- static VALUE
214
- dnssd_service_alloc(VALUE block) {
215
- DNSServiceRef *client = ALLOC(DNSServiceRef);
216
- VALUE service = Data_Wrap_Struct(cDNSSDService, 0, dnssd_service_free, client);
217
- rb_ivar_set(service, dnssd_iv_block, block);
218
- rb_ivar_set(service, dnssd_iv_thread, Qnil);
219
- rb_ivar_set(service, dnssd_iv_result, Qnil);
220
- return service;
144
+ return Qtrue;
221
145
  }
222
146
 
223
147
  /*
@@ -230,7 +154,11 @@ dnssd_service_alloc(VALUE block) {
230
154
  static VALUE
231
155
  dnssd_service_stopped_p(VALUE service) {
232
156
  DNSServiceRef *client = (DNSServiceRef*)RDATA(service)->data;
233
- return client == NULL ? Qtrue : Qfalse;
157
+
158
+ if (client)
159
+ return (*client) == NULL ? Qtrue : Qfalse;
160
+
161
+ return Qtrue;
234
162
  }
235
163
 
236
164
  /*
@@ -250,527 +178,285 @@ dnssd_service_stopped_p(VALUE service) {
250
178
  */
251
179
 
252
180
  static VALUE
253
- dnssd_service_stop(VALUE service) {
181
+ dnssd_service_stop(VALUE self) {
254
182
  VALUE thread;
255
- DNSServiceRef *client = (DNSServiceRef*)RDATA(service)->data;
183
+ DNSServiceRef *client = (DNSServiceRef*)RDATA(self)->data;
256
184
 
257
185
  /* set to null right away for a bit more thread safety */
258
- RDATA(service)->data = NULL;
186
+ RDATA(self)->data = NULL;
259
187
 
260
188
  if (client == NULL)
261
189
  rb_raise(eDNSSDError, "service is already stopped");
262
190
 
263
- dnssd_service_free_client(client);
264
-
265
- thread = rb_ivar_get(service, dnssd_iv_thread);
266
- rb_ivar_set(service, dnssd_iv_block, Qnil);
267
- rb_ivar_set(service, dnssd_iv_thread, Qnil);
191
+ thread = rb_ivar_get(self, dnssd_iv_thread);
192
+ rb_ivar_set(self, dnssd_iv_continue, Qfalse);
268
193
 
269
- if (!NIL_P(thread)) {
270
- /* will raise error if thread is not a Ruby Thread */
271
- rb_thread_kill(thread);
194
+ if (!NIL_P(thread) && thread != rb_thread_current()) {
195
+ rb_thread_run(thread);
196
+ rb_funcall(thread, dnssd_id_join, 0);
272
197
  }
273
198
 
274
- return service;
275
- }
276
-
277
- /* stop the service only if it is still running */
199
+ dnssd_service_free_client(client);
278
200
 
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);
201
+ return self;
285
202
  }
286
203
 
287
204
  static VALUE
288
- dnssd_service_process(VALUE service) {
289
- int dns_sd_fd, nfds, result;
290
- fd_set readfds;
291
-
205
+ dnssd_service_process(VALUE self) {
292
206
  DNSServiceRef *client;
293
- GetDNSSDService(service, client);
207
+
208
+ GetDNSSDService(self, client);
294
209
 
295
210
  if (client == NULL) {
296
211
  /* looks like this thread has already been stopped */
297
212
  return Qnil;
298
213
  }
299
214
 
300
- dns_sd_fd = DNSServiceRefSockFD(*client);
301
- nfds = dns_sd_fd + 1;
302
- for ( ;; ) {
303
- FD_ZERO(&readfds);
304
- FD_SET(dns_sd_fd, &readfds);
305
- result = rb_thread_select(nfds, &readfds,
306
- (fd_set *) NULL,
307
- (fd_set *) NULL,
308
- (struct timeval *) NULL);
309
- if (result > 0) {
310
- if (FD_ISSET(dns_sd_fd, &readfds)) {
311
- DNSServiceErrorType e = DNSServiceProcessResult(*client);
312
- dnssd_check_error_code(e);
313
- }
314
- } else {
315
- break;
316
- }
317
- }
318
-
319
- /* return the result from the processing */
320
- return rb_ivar_get(service, dnssd_iv_result);
321
- }
322
-
323
- static VALUE
324
- dnssd_service_start(VALUE service) {
325
- return rb_ensure(dnssd_service_process, service, dnssd_service_stop2,
326
- service);
327
- }
328
-
329
- static VALUE
330
- dnssd_service_start_in_thread(VALUE service) {
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. */
215
+ rb_thread_wait_fd(DNSServiceRefSockFD(*client));
334
216
 
335
- VALUE thread = rb_thread_create(dnssd_service_process, (void *)service);
336
- rb_ivar_set(service, dnssd_iv_thread, thread);
217
+ if (rb_ivar_get(self, dnssd_iv_continue) == Qfalse)
218
+ return Qnil;
337
219
 
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. !! */
220
+ DNSServiceErrorType e = DNSServiceProcessResult(*client);
221
+ dnssd_check_error_code(e);
342
222
 
343
- rb_ivar_set(thread, dnssd_iv_service, service);
344
- return service;
223
+ return self;
345
224
  }
346
225
 
347
226
  static void DNSSD_API
348
- dnssd_domain_enum_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
349
- uint32_t interface_index, DNSServiceErrorType e,
350
- const char *domain, void *context) {
351
- VALUE service;
352
- /* other parameters are undefined if errorCode != 0 */
227
+ dnssd_service_browse_reply(DNSServiceRef client, DNSServiceFlags flags,
228
+ uint32_t interface, DNSServiceErrorType e, const char *name,
229
+ const char *type, const char *domain, void *context) {
230
+ VALUE service, reply;
231
+
353
232
  dnssd_check_error_code(e);
233
+
354
234
  service = (VALUE)context;
355
- dnssd_callback(service,
356
- reply_from_domain_enum(service, flags, interface_index, domain));
235
+
236
+ reply = reply_new(service, flags);
237
+ reply_set_interface(reply, interface);
238
+ rb_funcall(reply, rb_intern("set_names"), 3, rb_str_new2(name),
239
+ rb_str_new2(type), rb_str_new2(domain));
240
+
241
+ dnssd_service_callback(service, reply);
357
242
  }
358
243
 
359
- static VALUE
360
- sd_enumerate_domains(int argc, VALUE *argv, VALUE service) {
361
- VALUE tmp_flags, interface;
244
+ /* Binding to DNSServiceBrowse
245
+ */
362
246
 
247
+ static VALUE
248
+ dnssd_service_browse(VALUE self, VALUE _type, VALUE _domain, VALUE _flags,
249
+ VALUE _interface) {
250
+ const char *type;
251
+ const char *domain = NULL;
363
252
  DNSServiceFlags flags = 0;
364
- uint32_t interface_index = 0;
253
+ uint32_t interface = 0;
365
254
 
366
255
  DNSServiceErrorType e;
367
256
  DNSServiceRef *client;
368
257
 
369
- rb_scan_args(argc, argv, "02", &tmp_flags, &interface);
258
+ type = StringValueCStr(_type);
370
259
 
371
- /* optional parameters */
372
- if (!NIL_P(tmp_flags))
373
- flags = dnssd_to_flags(tmp_flags);
260
+ if (!NIL_P(_domain))
261
+ domain = StringValueCStr(_domain);
374
262
 
375
- if (!NIL_P(interface))
376
- interface_index = dnssd_get_interface_index(interface);
263
+ if (!NIL_P(_flags))
264
+ flags = (DNSServiceFlags)NUM2ULONG(_flags);
377
265
 
378
- GetDNSSDService(service, client);
379
- e = DNSServiceEnumerateDomains(client, flags, interface_index,
380
- dnssd_domain_enum_reply, (void *)service);
381
- dnssd_check_error_code(e);
382
- return service;
383
- }
266
+ if (!NIL_P(_interface))
267
+ interface = NUM2ULONG(_interface);
384
268
 
385
- /*
386
- * call-seq:
387
- * DNSSD.enumerate_domains!(flags, interface) { |reply| } => service
388
- *
389
- * Synchronously enumerate domains available for browsing and registration.
390
- * For each domain found a DNSSD::Reply object is passed to block with #domain
391
- * set to the enumerated domain.
392
- *
393
- * available_domains = []
394
- * timeout(2) do
395
- * DNSSD.enumerate_domains! do |r|
396
- * available_domains << r.domain
397
- * end
398
- * rescue TimeoutError
399
- * end
400
- * puts available_domains.inspect
401
- *
402
- */
269
+ GetDNSSDService(self, client);
403
270
 
404
- static VALUE
405
- dnssd_enumerate_domains_bang(int argc, VALUE * argv, VALUE self) {
406
- return dnssd_service_start(
407
- sd_enumerate_domains(argc, argv, dnssd_service_alloc(rb_block_proc())));
408
- }
271
+ e = DNSServiceBrowse(client, flags, interface, type, domain,
272
+ dnssd_service_browse_reply, (void *)self);
409
273
 
410
- /*
411
- * call-seq:
412
- * DNSSD.enumerate_domains(flags, interface) {|reply| } => serivce
413
- *
414
- * Asynchronously enumerate domains available for browsing and registration.
415
- * For each domain found a DNSSD::DomainEnumReply object is passed to block.
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
428
- */
274
+ dnssd_check_error_code(e);
429
275
 
430
- static VALUE
431
- dnssd_enumerate_domains(int argc, VALUE * argv, VALUE self) {
432
- return dnssd_service_start_in_thread(
433
- sd_enumerate_domains(argc, argv, dnssd_service_alloc(rb_block_proc())));
276
+ return self;
434
277
  }
435
278
 
436
279
  static void DNSSD_API
437
- dnssd_browse_reply(DNSServiceRef client, DNSServiceFlags flags,
438
- uint32_t interface_index, DNSServiceErrorType e,
439
- const char *name, const char *type,
280
+ dnssd_service_enumerate_domains_reply(DNSServiceRef client,
281
+ DNSServiceFlags flags, uint32_t interface, DNSServiceErrorType e,
440
282
  const char *domain, void *context) {
441
- VALUE service;
442
- /* other parameters are undefined if errorCode != 0 */
283
+ VALUE service, reply;
284
+
443
285
  dnssd_check_error_code(e);
286
+
444
287
  service = (VALUE)context;
445
- dnssd_callback(service,
446
- reply_from_browse(service, flags, interface_index, name, type, domain));
288
+
289
+ reply = reply_new(service, flags);
290
+ reply_set_interface(reply, interface);
291
+ rb_ivar_set(reply, dnssd_iv_domain, rb_str_new2(domain));
292
+
293
+ dnssd_service_callback(service, reply);
447
294
  }
448
295
 
449
- static VALUE
450
- sd_browse(int argc, VALUE *argv, VALUE service) {
451
- VALUE type, domain, tmp_flags, interface;
296
+ /* Binding to DNSServiceEnumerateDomains
297
+ */
452
298
 
453
- const char *type_str;
454
- const char *domain_str = NULL;
299
+ static VALUE
300
+ dnssd_service_enumerate_domains(VALUE self, VALUE _flags, VALUE _interface) {
455
301
  DNSServiceFlags flags = 0;
456
- uint32_t interface_index = 0;
302
+ uint32_t interface = 0;
457
303
 
458
304
  DNSServiceErrorType e;
459
305
  DNSServiceRef *client;
460
306
 
461
- rb_scan_args(argc, argv, "13", &type, &domain, &tmp_flags, &interface);
462
- type_str = StringValueCStr(type);
307
+ if (!NIL_P(_flags))
308
+ flags = (DNSServiceFlags)NUM2ULONG(_flags);
463
309
 
464
- /* optional parameters */
465
- if (!NIL_P(domain))
466
- domain_str = dnssd_get_domain(domain);
310
+ if (!NIL_P(_interface))
311
+ interface = NUM2ULONG(_interface);
467
312
 
468
- if (!NIL_P(tmp_flags))
469
- flags = dnssd_to_flags(tmp_flags);
313
+ GetDNSSDService(self, client);
470
314
 
471
- if (!NIL_P(interface))
472
- interface_index = dnssd_get_interface_index(interface);
315
+ e = DNSServiceEnumerateDomains(client, flags, interface,
316
+ dnssd_service_enumerate_domains_reply, (void *)self);
473
317
 
474
- GetDNSSDService(service, client);
475
- e = DNSServiceBrowse(client, flags, interface_index, type_str, domain_str,
476
- dnssd_browse_reply, (void *)service);
477
318
  dnssd_check_error_code(e);
478
- return service;
479
- }
480
319
 
481
- /*
482
- * call-seq:
483
- * DNSSD.browse!(type, domain, flags, interface) {|reply| } => service
484
- *
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
- *
493
- * For each service found a DNSSD::Reply object is passed to block.
494
- *
495
- * timeout 6 do
496
- * DNSSD.browse! '_http._tcp' do |r|
497
- * puts "found: #{r.name}"
498
- * end
499
- * rescue TimeoutError
500
- * end
501
- *
502
- */
503
-
504
- static VALUE
505
- dnssd_browse_bang(int argc, VALUE * argv, VALUE self) {
506
- return dnssd_service_start(
507
- sd_browse(argc, argv, dnssd_service_alloc(rb_block_proc())));
508
- }
509
-
510
- /*
511
- * call-seq:
512
- * DNSSD.browse(type, domain, flags, interface) {|reply| } => service
513
- *
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
- *
522
- * For each service found a DNSSD::BrowseReply object is passed to block.
523
- *
524
- * The returned service can be used to control when to stop browsing for
525
- * services (see DNSSD::Service#stop).
526
- *
527
- * s = DNSSD.browse '_http._tcp' do |b|
528
- * puts "found: #{b.name}"
529
- * end
530
- *
531
- * s.stop
532
- */
533
-
534
- static VALUE
535
- dnssd_browse(int argc, VALUE * argv, VALUE self) {
536
- return dnssd_service_start_in_thread(
537
- sd_browse(argc, argv, dnssd_service_alloc(rb_block_proc())));
320
+ return self;
538
321
  }
539
322
 
540
323
  static void DNSSD_API
541
- dnssd_register_reply(DNSServiceRef client, DNSServiceFlags flags,
542
- DNSServiceErrorType e,
543
- const char *name, const char *regtype,
324
+ dnssd_service_register_reply(DNSServiceRef client, DNSServiceFlags flags,
325
+ DNSServiceErrorType e, const char *name, const char *type,
544
326
  const char *domain, void *context) {
545
- VALUE service;
546
- /* other parameters are undefined if errorCode != 0 */
327
+ VALUE service, reply;
328
+
547
329
  dnssd_check_error_code(e);
330
+
548
331
  service = (VALUE)context;
549
- dnssd_callback(service,
550
- reply_from_register(service, flags, name, regtype, domain));
332
+
333
+ reply = reply_new(service, flags);
334
+ rb_funcall(reply, rb_intern("set_names"), 3, rb_str_new2(name),
335
+ rb_str_new2(type), rb_str_new2(domain));
336
+
337
+ dnssd_service_callback(service, reply);
551
338
  }
552
339
 
553
- static VALUE
554
- sd_register(int argc, VALUE *argv, VALUE service) {
555
- VALUE name, type, domain, port, text_record, tmp_flags, interface;
340
+ /* Binding to DNSServiceRegister
341
+ */
556
342
 
557
- const char *name_str, *type_str, *domain_str = NULL;
558
- uint16_t opaqueport;
343
+ static VALUE
344
+ dnssd_service_register(VALUE self, VALUE _name, VALUE _type, VALUE _domain,
345
+ VALUE _host, VALUE _port, VALUE _text_record, VALUE _flags,
346
+ VALUE _interface) {
347
+ const char *name, *type, *host = NULL, *domain = NULL;
348
+ uint16_t port;
559
349
  uint16_t txt_len = 0;
560
350
  char *txt_rec = NULL;
561
351
  DNSServiceFlags flags = 0;
562
- uint32_t interface_index = 0;
352
+ uint32_t interface = 0;
563
353
 
564
354
  DNSServiceErrorType e;
565
355
  DNSServiceRef *client;
566
356
 
567
- rb_scan_args(argc, argv, "43", &name, &type, &domain, &port,
568
- &text_record, &tmp_flags, &interface);
357
+ name = StringValueCStr(_name);
358
+ type = StringValueCStr(_type);
569
359
 
570
- /* required parameters */
571
- name_str = StringValueCStr(name);
572
- type_str = StringValueCStr(type);
360
+ if (!NIL_P(_host))
361
+ host = StringValueCStr(_host);
573
362
 
574
- if (!NIL_P(domain))
575
- domain_str = dnssd_get_domain(domain);
363
+ if (!NIL_P(_domain))
364
+ domain = StringValueCStr(_domain);
576
365
 
577
- /* convert from host to net byte order */
578
- opaqueport = htons((uint16_t)NUM2UINT(port));
366
+ port = htons((uint16_t)NUM2UINT(_port));
579
367
 
580
- /* optional parameters */
581
- if (!NIL_P(text_record)) {
582
- text_record = rb_funcall(text_record, dnssd_id_encode, 0);
583
- txt_rec = RSTRING_PTR(text_record);
584
- txt_len = RSTRING_LEN(text_record);
368
+ if (!NIL_P(_text_record)) {
369
+ txt_rec = RSTRING_PTR(_text_record);
370
+ txt_len = RSTRING_LEN(_text_record);
585
371
  }
586
372
 
587
- if (!NIL_P(tmp_flags))
588
- flags = dnssd_to_flags(tmp_flags);
373
+ if (!NIL_P(_flags))
374
+ flags = (DNSServiceFlags)NUM2ULONG(_flags);
589
375
 
590
- if(!NIL_P(interface))
591
- interface_index = dnssd_get_interface_index(interface);
376
+ if (!NIL_P(_interface))
377
+ interface = NUM2ULONG(_interface);
592
378
 
593
- GetDNSSDService(service, client);
379
+ GetDNSSDService(self, client);
594
380
 
595
- /* HACK */
596
- rb_iv_set(service, "@interface", interface);
597
- rb_iv_set(service, "@port", port);
598
- rb_iv_set(service, "@text_record", text_record);
599
- /********/
381
+ e = DNSServiceRegister(client, flags, interface, name, type,
382
+ domain, host, port, txt_len, txt_rec, dnssd_service_register_reply,
383
+ (void*)self);
600
384
 
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);
604
385
  dnssd_check_error_code(e);
605
- return service;
606
- }
607
386
 
608
- /*
609
- * call-seq:
610
- * DNSSD.register!(name, type, domain, port, text_record=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => obj
611
- *
612
- * Synchronously register a service. A DNSSD::Reply object is passed to the
613
- * optional block when the registration completes.
614
- *
615
- * DNSSD.register! "My Files", "_http._tcp", nil, 8080 do |r|
616
- * puts "successfully registered: #{r.inspect}"
617
- * end
618
- */
387
+ return self;
388
+ }
619
389
 
620
- static VALUE
621
- dnssd_register_bang(int argc, VALUE * argv, VALUE self) {
622
- VALUE block = Qnil;
390
+ static void DNSSD_API
391
+ dnssd_service_resolve_reply(DNSServiceRef client, DNSServiceFlags flags,
392
+ uint32_t interface, DNSServiceErrorType e, const char *name,
393
+ const char *target, uint16_t port, uint16_t txt_len,
394
+ const unsigned char *txt_rec, void *context) {
395
+ VALUE service, reply, text_record, text_record_str;
623
396
 
624
- if (rb_block_given_p())
625
- block = rb_block_proc();
397
+ dnssd_check_error_code(e);
626
398
 
627
- return dnssd_service_start(
628
- sd_register(argc, argv, dnssd_service_alloc(block)));
629
- }
399
+ service = (VALUE)context;
630
400
 
631
- /*
632
- * call-seq:
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
651
- */
401
+ reply = reply_new(service, flags);
652
402
 
653
- static VALUE
654
- dnssd_register(int argc, VALUE * argv, VALUE self) {
655
- VALUE block = Qnil;
403
+ reply_set_interface(reply, interface);
404
+ rb_funcall(reply, rb_intern("set_fullname"), 1, rb_str_new2(name));
405
+ rb_ivar_set(reply, dnssd_iv_target, rb_str_new2(target));
406
+ rb_ivar_set(reply, dnssd_iv_port, UINT2NUM(ntohs(port)));
656
407
 
657
- if (rb_block_given_p())
658
- block = rb_block_proc();
408
+ text_record_str = rb_str_new((char *)txt_rec, txt_len);
409
+ text_record = rb_class_new_instance(1, &text_record_str, cDNSSDTextRecord);
410
+ rb_ivar_set(reply, dnssd_iv_text_record, text_record);
659
411
 
660
- return dnssd_service_start_in_thread(
661
- sd_register(argc, argv, dnssd_service_alloc(block)));
412
+ dnssd_service_callback(service, reply);
662
413
  }
663
414
 
664
- static void DNSSD_API
665
- dnssd_resolve_reply(DNSServiceRef client, DNSServiceFlags flags,
666
- uint32_t interface_index, DNSServiceErrorType e,
667
- const char *fullname, const char *host_target,
668
- uint16_t opaqueport, uint16_t txt_len,
669
- const char *txt_rec, void *context) {
670
- VALUE service;
671
- /* other parameters are undefined if errorCode != 0 */
672
- dnssd_check_error_code(e);
673
- service = (VALUE)context;
674
- dnssd_callback(service,
675
- reply_from_resolve(service, flags, interface_index, fullname,
676
- host_target, opaqueport, txt_len, txt_rec));
677
- }
415
+ /* Binding to DNSServiceResolve
416
+ */
678
417
 
679
418
  static VALUE
680
- sd_resolve(int argc, VALUE *argv, VALUE service) {
681
- VALUE name, type, domain, tmp_flags, interface;
682
-
683
- const char *name_str, *type_str, *domain_str;
419
+ dnssd_service_resolve(VALUE self, VALUE _name, VALUE _type, VALUE _domain,
420
+ VALUE _flags, VALUE _interface) {
421
+ const char *name, *type, *domain;
684
422
  DNSServiceFlags flags = 0;
685
- uint32_t interface_index = 0;
423
+ uint32_t interface = 0;
686
424
 
687
- DNSServiceErrorType err;
425
+ DNSServiceErrorType e;
688
426
  DNSServiceRef *client;
689
427
 
690
- rb_scan_args(argc, argv, "32", &name, &type, &domain, &tmp_flags, &interface);
691
-
692
- /* required parameters */
693
- name_str = StringValueCStr(name);
694
- type_str = StringValueCStr(type);
695
- domain_str = dnssd_get_domain(domain);
428
+ name = StringValueCStr(_name);
429
+ type = StringValueCStr(_type);
430
+ domain = StringValueCStr(_domain);
696
431
 
697
- /* optional parameters */
698
- if (!NIL_P(tmp_flags))
699
- flags = dnssd_to_flags(tmp_flags);
432
+ if (!NIL_P(_flags))
433
+ flags = NUM2ULONG(_flags);
700
434
 
701
- if (!NIL_P(interface))
702
- interface_index = dnssd_get_interface_index(interface);
435
+ if (!NIL_P(_interface))
436
+ interface = NUM2ULONG(_interface);
703
437
 
704
- GetDNSSDService(service, client);
705
- err = DNSServiceResolve(client, flags, interface_index, name_str, type_str,
706
- domain_str, dnssd_resolve_reply, (void *)service);
707
- dnssd_check_error_code(err);
708
- return service;
709
- }
710
-
711
- /*
712
- * call-seq:
713
- * DNSSD.resolve!(name, type, domain, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => service
714
- *
715
- * Synchronously resolve a service discovered via DNSSD.browse().
716
- *
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.
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
726
- */
438
+ GetDNSSDService(self, client);
727
439
 
728
- static VALUE
729
- dnssd_resolve_bang(int argc, VALUE * argv, VALUE self) {
730
- return dnssd_service_start(
731
- sd_resolve(argc, argv, dnssd_service_alloc(rb_block_proc())));
732
- }
440
+ e = DNSServiceResolve(client, flags, interface, name, type, domain,
441
+ dnssd_service_resolve_reply, (void *)self);
733
442
 
734
- /*
735
- * call-seq:
736
- * DNSSD.resolve(name, type, domain, flags=0, interface=DNSSD::InterfaceAny) {|reply| } => service
737
- *
738
- * Asynchronously resolve a service discovered via DNSSD.browse().
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
751
- */
443
+ dnssd_check_error_code(e);
752
444
 
753
- static VALUE
754
- dnssd_resolve(int argc, VALUE * argv, VALUE self) {
755
- return dnssd_service_start_in_thread(
756
- sd_resolve(argc, argv, dnssd_service_alloc(rb_block_proc())));
445
+ return self;
757
446
  }
758
447
 
759
448
  void
760
449
  Init_DNSSD_Service(void) {
761
450
  VALUE mDNSSD = rb_define_module("DNSSD");
762
451
 
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");
452
+ dnssd_id_join = rb_intern("join");
453
+ dnssd_id_push = rb_intern("push");
767
454
 
768
- dnssd_iv_block = rb_intern("@block");
455
+ dnssd_iv_continue = rb_intern("@continue");
769
456
  dnssd_iv_domain = rb_intern("@domain");
770
457
  dnssd_iv_interface = rb_intern("@interface");
771
458
  dnssd_iv_port = rb_intern("@port");
772
- dnssd_iv_result = rb_intern("@result");
773
- dnssd_iv_service = rb_intern("@service");
459
+ dnssd_iv_replies = rb_intern("@replies");
774
460
  dnssd_iv_target = rb_intern("@target");
775
461
  dnssd_iv_text_record = rb_intern("@text_record");
776
462
  dnssd_iv_thread = rb_intern("@thread");
@@ -779,22 +465,25 @@ Init_DNSSD_Service(void) {
779
465
  cDNSSDService = rb_define_class_under(mDNSSD, "Service", rb_cObject);
780
466
  cDNSSDTextRecord = rb_define_class_under(mDNSSD, "TextRecord", rb_cObject);
781
467
 
782
- rb_define_singleton_method(cDNSSDService, "new", dnssd_service_new, -1);
468
+ rb_define_const(cDNSSDService, "MAX_DOMAIN_NAME",
469
+ ULONG2NUM(kDNSServiceMaxDomainName));
470
+ rb_define_const(cDNSSDService, "MAX_SERVICE_NAME",
471
+ ULONG2NUM(kDNSServiceMaxServiceName));
472
+
473
+
474
+ rb_define_alloc_func(cDNSSDService, dnssd_service_s_allocate);
783
475
  rb_define_singleton_method(cDNSSDService, "fullname", dnssd_service_s_fullname, 3);
784
476
 
477
+ rb_define_method(cDNSSDService, "started?", dnssd_service_started_p, 0);
478
+
785
479
  rb_define_method(cDNSSDService, "stop", dnssd_service_stop, 0);
786
480
  rb_define_method(cDNSSDService, "stopped?", dnssd_service_stopped_p, 0);
787
481
 
788
- rb_define_module_function(mDNSSD, "browse", dnssd_browse, -1);
789
- rb_define_module_function(mDNSSD, "browse!", dnssd_browse_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
-
794
- rb_define_module_function(mDNSSD, "register", dnssd_register, -1);
795
- rb_define_module_function(mDNSSD, "register!", dnssd_register_bang, -1);
482
+ rb_define_method(cDNSSDService, "_browse", dnssd_service_browse, 4);
483
+ rb_define_method(cDNSSDService, "_enumerate_domains", dnssd_service_enumerate_domains, 2);
484
+ rb_define_method(cDNSSDService, "_register", dnssd_service_register, 8);
485
+ rb_define_method(cDNSSDService, "_resolve", dnssd_service_resolve, 5);
796
486
 
797
- rb_define_module_function(mDNSSD, "resolve", dnssd_resolve, -1);
798
- rb_define_module_function(mDNSSD, "resolve!", dnssd_resolve_bang, -1);
487
+ rb_define_method(cDNSSDService, "_process", dnssd_service_process, 0);
799
488
  }
800
489