dnssd 0.6.0 → 0.7.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.
Binary file
@@ -20,13 +20,6 @@ static VALUE eDNSSDUnknownError;
20
20
 
21
21
  static VALUE dnssd_errors[DNSSD_ERROR_END - DNSSD_ERROR_START];
22
22
 
23
- /*void
24
- dnssd_check_class(VALUE obj, VALUE cClass)
25
- {
26
- if (rb_obj_is_kind_of(obj, cClass) != Qtrue)
27
- rb_raise(rb_eRuntimeError, "need %s or a subclass", rb_class2name(cClass));
28
- }*/
29
-
30
23
  static void
31
24
  dnssd_errors_store(VALUE error, int num)
32
25
  {
@@ -40,9 +33,11 @@ dnssd_check_error_code(DNSServiceErrorType e)
40
33
  int num = (int)e;
41
34
  if (num) {
42
35
  if(DNSSD_ERROR_START <= num && num < DNSSD_ERROR_END) {
43
- rb_raise(dnssd_errors[num - DNSSD_ERROR_START], "DNSSD operation failed with error code: %i", num);
36
+ rb_raise(dnssd_errors[num - DNSSD_ERROR_START],
37
+ "DNSSD operation failed with error code: %d", num);
44
38
  } else {
45
- rb_raise(eDNSSDUnknownError, "DNSSD operation failed with unrecognized error code: %i", num);
39
+ rb_raise(eDNSSDUnknownError,
40
+ "DNSSD operation failed with unrecognized error code: %d", num);
46
41
  }
47
42
  }
48
43
  }
@@ -50,15 +45,19 @@ dnssd_check_error_code(DNSServiceErrorType e)
50
45
  void
51
46
  dnssd_instantiation_error(const char *what)
52
47
  {
53
- rb_raise(rb_eRuntimeError, "cannot instantiate %s, use DNSSD browse(), resolve() or register() instead", what);
48
+ rb_raise(rb_eRuntimeError,
49
+ "cannot instantiate %s, use DNSSD "
50
+ "enumerate_domains(), browse(), resolve() or register() instead",
51
+ what);
54
52
  }
55
53
 
56
54
  /*
57
55
  * Document-module: DNSSD
58
56
  * DNSSD is a wrapper for Apple's DNS Service Discovery library.
59
- * The methods DNSSD.browse(), DNSSD.register(), and DNSSD.resolve()
60
- * provide the basic API for making your applications DNS Service
61
- * Discovery aware.
57
+ * The methods DNSSD.enumerate_domains, DNSSD.browse(),
58
+ * DNSSD.register(), and DNSSD.resolve() provide the basic API
59
+ * for making your applications DNS Service Discovery aware.
60
+ *
62
61
  */
63
62
 
64
63
  static void
@@ -7,14 +7,36 @@
7
7
  #define RDNSSD_INCLUDED
8
8
 
9
9
  #include <ruby.h>
10
+ #include <intern.h>
10
11
  #include <dns_sd.h>
11
12
 
13
+ /* for if_indextoname() and other unix networking functions */
14
+ #ifdef HAVE_UNISTD_H
15
+ #include <unistd.h>
16
+ #endif
17
+ #ifdef HAVE_SYS_TYPES_H
18
+ #include <sys/types.h>
19
+ #endif
20
+ #ifdef HAVE_SYS_SOCKET_H
21
+ #include <sys/socket.h>
22
+ #endif
23
+ #ifdef HAVE_SYS_PARAM_H
24
+ #include <sys/param.h>
25
+ #endif
26
+ #ifdef HAVE_NET_IF_H
27
+ #include <net/if.h>
28
+ #endif
29
+ #ifdef HAVE_SYS_IF_H
30
+ #include <sys/if.h>
31
+ #endif
32
+
12
33
  extern VALUE mDNSSD;
13
34
 
14
35
  void dnssd_check_error_code(DNSServiceErrorType e);
15
36
  void dnssd_instantiation_error(const char *what);
16
37
 
17
- VALUE dnssd_create_fullname(VALUE name, VALUE regtype, VALUE domain, int err_flag);
38
+ VALUE dnssd_create_fullname(const char *name, const char *regtype, const char *domain, int err_flag);
39
+ VALUE dnssd_split_fullname(VALUE fullname);
18
40
 
19
41
  /* decodes a buffer, creating a new text record */
20
42
  VALUE dnssd_tr_new(long len, const char *buf);
@@ -24,12 +46,15 @@ VALUE dnssd_tr_to_encoded_str(VALUE v);
24
46
  /* Get DNSServiceFlags from self */
25
47
  DNSServiceFlags dnssd_to_flags(VALUE obj);
26
48
 
27
- VALUE dnssd_register_new(VALUE service, DNSServiceFlags flags, const char *name,
28
- const char *regtype, const char *domain );
49
+ VALUE dnssd_domain_enum_new(VALUE service, DNSServiceFlags flags,
50
+ uint32_t interface, const char *domain);
29
51
 
30
52
  VALUE dnssd_browse_new(VALUE service, DNSServiceFlags flags, uint32_t interface,
31
53
  const char *name, const char *regtype, const char *domain);
32
54
 
55
+ VALUE dnssd_register_new(VALUE service, DNSServiceFlags flags, const char *name,
56
+ const char *regtype, const char *domain);
57
+
33
58
  VALUE dnssd_resolve_new(VALUE service, DNSServiceFlags flags, uint32_t interface,
34
59
  const char *fullname, const char *host_target,
35
60
  uint16_t opaqueport, uint16_t txt_len, const char *txt_rec);
Binary file
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Ruby Rendezvous Binding
3
- * $Id: rdnssd_service.c,v 1.12 2004/10/07 15:19:14 cmills Exp $
3
+ * $Id: rdnssd_service.c,v 1.24 2005/03/22 00:19:37 cmills Exp $
4
4
  *
5
5
  * Copyright (c) 2004 Chad Fowler, Charles Mills, Rich Kilmer
6
6
  * Licenced under the same terms as Ruby.
@@ -8,15 +8,10 @@
8
8
  */
9
9
 
10
10
  #include "rdnssd.h"
11
- #include <intern.h>
12
-
13
- /* for if_nametoindex() */
14
- #include <sys/types.h>
15
- #include <sys/socket.h>
16
- #include <net/if.h>
11
+ #include <assert.h>
17
12
 
18
13
  #ifndef DNSSD_API
19
- /* define as nothing if not defined in "dns_sd.h" header */
14
+ /* define as nothing if not defined in Apple's "dns_sd.h" header */
20
15
  #define DNSSD_API
21
16
  #endif
22
17
 
@@ -25,19 +20,19 @@ static ID dnssd_id_call;
25
20
  static ID dnssd_id_to_str;
26
21
  static ID dnssd_iv_block;
27
22
  static ID dnssd_iv_thread;
23
+ static ID dnssd_iv_result;
28
24
  static ID dnssd_iv_service;
29
25
 
30
26
  #define IsDNSSDService(obj) (rb_obj_is_kind_of(obj,cDNSSDService)==Qtrue)
31
- #define GetDNSSDService(obj, var) Data_Get_Struct(obj, DNSServiceRef, var)
32
-
33
- static VALUE dnssd_process(VALUE service);
27
+ #define GetDNSSDService(obj, var) \
28
+ do { assert(IsDNSSDService(obj)); Data_Get_Struct(obj, DNSServiceRef, var); } while (0)
34
29
 
35
- static void
36
- dnssd_check_block(VALUE block)
30
+ void
31
+ dnssd_callback(VALUE service, VALUE reply)
37
32
  {
38
- if (block == Qnil) {
39
- rb_raise(rb_eArgError, "block required");
40
- }
33
+ VALUE result = rb_funcall2( rb_ivar_get(service, dnssd_iv_block),
34
+ dnssd_id_call, 1, &reply );
35
+ rb_ivar_set(service, dnssd_iv_result, result);
41
36
  }
42
37
 
43
38
  static const char *
@@ -45,7 +40,7 @@ dnssd_get_domain(VALUE service_domain)
45
40
  {
46
41
  const char *domain = StringValueCStr(service_domain);
47
42
  /* max len including the null terminator and trailing '.' */
48
- if (strlen(domain) >= kDNSServiceMaxDomainName - 1)
43
+ if (RSTRING(service_domain)->len >= kDNSServiceMaxDomainName - 1)
49
44
  rb_raise(rb_eArgError, "domain name string too large");
50
45
  return domain;
51
46
  }
@@ -63,7 +58,7 @@ dnssd_get_interface_index(VALUE interface)
63
58
 
64
59
  /*
65
60
  * call-seq:
66
- * DNSSD::Serivce.fullname(name, type, domain) => string
61
+ * DNSSD::Service.fullname(name, type, domain) => string
67
62
  *
68
63
  * Concatenate a three-part domain name (as seen in DNSSD::Reply#fullname())
69
64
  * into a properly-escaped full domain name.
@@ -79,20 +74,36 @@ dnssd_get_interface_index(VALUE interface)
79
74
  * Raises a <code>ArgumentError</code> if the full service name cannot be constructed from
80
75
  * the arguments.
81
76
  */
82
-
83
77
  static VALUE
84
- dnssd_service_fullname(VALUE klass, VALUE name, VALUE type, VALUE domain)
78
+ dnssd_service_s_fullname(VALUE klass, VALUE name, VALUE type, VALUE domain)
85
79
  {
86
- return dnssd_create_fullname(name, type, domain, 1);
80
+ return dnssd_create_fullname( StringValueCStr(name), StringValueCStr(type),
81
+ StringValueCStr(domain), 1 );
87
82
  }
88
83
 
89
84
  /*
90
85
  * call-seq:
91
- * DNSSD::Serivce.new() => raises a RuntimeError
86
+ * DNSSD::Service.split(fullname) => array
87
+ * DNSSD::Service.split_fullname(fullname) => array
92
88
  *
93
- * Services can only be instantiated using DNSSD.browse(), DNSSD.register(), and DNSSD.resolve().
89
+ * Split a properly escaped multi-part domain name (as seen in DNSSD::Reply#fullname())
90
+ * into an array of names.
91
+ *
92
+ * DNSSD::Service.split('_http._tcp.local.') #=> ["_http.", "_tcp.", "local."]
94
93
  */
94
+ static VALUE
95
+ dnssd_service_s_split(VALUE klass, VALUE fullname)
96
+ {
97
+ return dnssd_split_fullname(fullname);
98
+ }
95
99
 
100
+ /*
101
+ * call-seq:
102
+ * DNSSD::Service.new() => raises a RuntimeError
103
+ *
104
+ * Services can only be instantiated using DNSSD.enumerate_domains(),
105
+ * DNSSD.browse(), DNSSD.register(), and DNSSD.resolve().
106
+ */
96
107
  static VALUE
97
108
  dnssd_service_new(int argc, VALUE *argv, VALUE klass)
98
109
  {
@@ -101,11 +112,8 @@ dnssd_service_new(int argc, VALUE *argv, VALUE klass)
101
112
  }
102
113
 
103
114
  static void
104
- dnssd_service_stop_client(VALUE service)
115
+ dnssd_service_free_client(DNSServiceRef *client)
105
116
  {
106
- DNSServiceRef *client = (DNSServiceRef*)RDATA(service)->data;
107
- /* set to null right away for a bit more thread safety */
108
- RDATA(service)->data = NULL;
109
117
  DNSServiceRefDeallocate(*client);
110
118
  free(client); /* free the pointer */
111
119
  }
@@ -115,10 +123,8 @@ dnssd_service_free(void *ptr)
115
123
  {
116
124
  DNSServiceRef *client = (DNSServiceRef*)ptr;
117
125
  if (client) {
118
- /* client will be non-null only if client has not been deallocated
119
- * see dnssd_service_stop_client() above. */
120
- DNSServiceRefDeallocate(*client);
121
- free(client); /* free the pointer, see dnssd_service_alloc() below */
126
+ /* client will be non-null only if client has not been deallocated */
127
+ dnssd_service_free_client(client);
122
128
  }
123
129
  }
124
130
 
@@ -129,71 +135,131 @@ dnssd_service_alloc(VALUE block)
129
135
  VALUE service = Data_Wrap_Struct(cDNSSDService, 0, dnssd_service_free, client);
130
136
  rb_ivar_set(service, dnssd_iv_block, block);
131
137
  rb_ivar_set(service, dnssd_iv_thread, Qnil);
138
+ rb_ivar_set(service, dnssd_iv_result, Qnil);
132
139
  return service;
133
140
  }
134
141
 
135
- static void
136
- dnssd_service_start(VALUE service)
137
- {
138
- VALUE thread = rb_thread_create(dnssd_process, (void *)service);
139
- rb_ivar_set(service, dnssd_iv_thread, thread);
140
- /* !! IMPORTANT: prevents premature garbage collection of the service,
141
- * this way the thread holds a reference to the service and
142
- * the service gets marked as long as the thread is running.
143
- * Running threads are always marked by Ruby. !! */
144
- rb_ivar_set(thread, dnssd_iv_service, service);
145
- }
146
-
147
142
  /*
148
143
  * call-seq:
149
144
  * service.stopped? => true or false
150
145
  *
151
146
  * Returns <code>true</code> if _service_ has been stopped, <code>false</code> otherwise.
152
147
  */
153
-
154
148
  static VALUE
155
149
  dnssd_service_is_stopped(VALUE service)
156
150
  {
157
- return NIL_P(rb_ivar_get(service, dnssd_iv_thread)) ? Qtrue : Qfalse;
151
+ DNSServiceRef *client = (DNSServiceRef*)RDATA(service)->data;
152
+ return client == NULL ? Qtrue : Qfalse;
158
153
  }
159
154
 
160
155
  /*
161
156
  * call-seq:
162
157
  * service.stop => service
163
158
  *
164
- * Stops the DNSSD::Service _service_; closing the underlying socket and killing
159
+ * Stops _service_ closing the underlying socket and killing
165
160
  * the underlying thread.
161
+ *
162
+ * It is good practice to all stop running services before exit.
163
+ *
164
+ * service = DNSSD.browse('_http._tcp') do |r|
165
+ * # found a service ...
166
+ * end
167
+ * sleep(2)
168
+ * service.stop
169
+ *
166
170
  */
167
-
168
171
  static VALUE
169
172
  dnssd_service_stop(VALUE service)
170
173
  {
171
- VALUE thread = rb_ivar_get(service, dnssd_iv_thread);
172
- if (NIL_P(thread)) rb_raise(rb_eRuntimeError, "service is already stopped");
173
-
174
- /* mark service as stopped, then kill thread -
175
- * just in case stop is called in thread! :( */
176
- rb_ivar_set(service, dnssd_iv_thread, Qnil);
177
- rb_thread_kill(thread);
178
-
179
- /* once thread is killed we don't need to reference the block any more */
174
+ VALUE thread;
175
+ DNSServiceRef *client = (DNSServiceRef*)RDATA(service)->data;
176
+ /* set to null right away for a bit more thread safety */
177
+ RDATA(service)->data = NULL;
178
+ if (client == NULL) rb_raise(rb_eRuntimeError, "service is already stopped");
179
+ dnssd_service_free_client(client);
180
+ thread = rb_ivar_get(service, dnssd_iv_thread);
180
181
  rb_ivar_set(service, dnssd_iv_block, Qnil);
181
-
182
- /* do this last! - thread must be killed */
183
- dnssd_service_stop_client(service);
182
+ rb_ivar_set(service, dnssd_iv_thread, Qnil);
183
+
184
+ if (!NIL_P(thread)) {
185
+ /* will raise error if thread is not a Ruby Thread */
186
+ rb_thread_kill(thread);
187
+ }
184
188
  return service;
185
189
  }
186
190
 
191
+ static VALUE
192
+ dnssd_service_process(VALUE service)
193
+ {
194
+ int dns_sd_fd, nfds, result;
195
+ fd_set readfds;
196
+
197
+ DNSServiceRef *client;
198
+ GetDNSSDService(service, client);
199
+
200
+ dns_sd_fd = DNSServiceRefSockFD(*client);
201
+ nfds = dns_sd_fd + 1;
202
+ for ( ;; ) {
203
+ FD_ZERO(&readfds);
204
+ FD_SET(dns_sd_fd, &readfds);
205
+ result = rb_thread_select(nfds, &readfds,
206
+ (fd_set *) NULL,
207
+ (fd_set *) NULL,
208
+ (struct timeval *) NULL);
209
+ if (result > 0) {
210
+ if ( FD_ISSET(dns_sd_fd, &readfds) ) {
211
+ DNSServiceErrorType e = DNSServiceProcessResult(*client);
212
+ dnssd_check_error_code(e);
213
+ }
214
+ } else {
215
+ break;
216
+ }
217
+ }
218
+ /* return the result from the processing */
219
+ return rb_ivar_get(service, dnssd_iv_result);
220
+ }
221
+
222
+ /* stop the service only if it is still running */
223
+ static VALUE
224
+ dnssd_service_stop2(VALUE service)
225
+ {
226
+ if (dnssd_service_is_stopped(service)) {
227
+ return service;
228
+ }
229
+ return dnssd_service_stop(service);
230
+ }
231
+
232
+ static VALUE
233
+ dnssd_service_start(VALUE service)
234
+ {
235
+ return rb_ensure(dnssd_service_process, service, dnssd_service_stop2, service);
236
+ }
237
+
238
+ static VALUE
239
+ dnssd_service_start_in_thread(VALUE service)
240
+ {
241
+ /* race condition - service.@block could be called before the service.@thread
242
+ * is set and if the block calls service.stop() will raise an error, even though
243
+ * the service has been started and is running. */
244
+ VALUE thread = rb_thread_create(dnssd_service_process, (void *)service);
245
+ rb_ivar_set(service, dnssd_iv_thread, thread);
246
+ /* !! IMPORTANT: prevents premature garbage collection of the service,
247
+ * this way the thread holds a reference to the service and
248
+ * the service gets marked as long as the thread is running.
249
+ * Running threads are always marked by Ruby. !! */
250
+ rb_ivar_set(thread, dnssd_iv_service, service);
251
+ return service;
252
+ }
253
+
187
254
  /*
188
255
  * call-seq:
189
256
  * service.inspect => string
190
257
  *
191
258
  */
192
-
193
259
  static VALUE
194
260
  dnssd_service_inspect(VALUE self)
195
261
  {
196
- VALUE buf = rb_str_buf_new(0);
262
+ VALUE buf = rb_str_buf_new(32);
197
263
  rb_str_buf_cat2(buf, "<#");
198
264
  rb_str_buf_cat2(buf, rb_obj_classname(self));
199
265
  if (dnssd_service_is_stopped(self)) {
@@ -203,74 +269,116 @@ dnssd_service_inspect(VALUE self)
203
269
  return buf;
204
270
  }
205
271
 
206
- static VALUE
207
- dnssd_service_get_block(VALUE service)
272
+ static void DNSSD_API
273
+ dnssd_domain_enum_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
274
+ uint32_t interface_index, DNSServiceErrorType e,
275
+ const char *domain, void *context)
208
276
  {
209
- return rb_ivar_get(service, dnssd_iv_block);
277
+ VALUE service;
278
+ /* other parameters are undefined if errorCode != 0 */
279
+ dnssd_check_error_code(e);
280
+ service = (VALUE)context;
281
+ dnssd_callback(service, dnssd_domain_enum_new(service, flags, interface_index, domain));
210
282
  }
211
283
 
212
284
  static VALUE
213
- dnssd_process(VALUE service)
285
+ sd_enumerate_domains(int argc, VALUE *argv, VALUE service)
214
286
  {
215
- int dns_sd_fd, nfds, result;
216
- fd_set readfds;
287
+ VALUE tmp_flags, interface;
288
+
289
+ DNSServiceFlags flags = 0;
290
+ uint32_t interface_index = 0;
217
291
 
218
- DNSServiceRef *client;
219
- GetDNSSDService(service, client);
292
+ DNSServiceErrorType e;
293
+ DNSServiceRef *client;
220
294
 
221
- dns_sd_fd = DNSServiceRefSockFD (*client);
222
- nfds = dns_sd_fd + 1;
223
- while (1) {
224
- FD_ZERO (&readfds);
225
- FD_SET (dns_sd_fd, &readfds);
226
- result = rb_thread_select (nfds, &readfds, (fd_set *) NULL, (fd_set *) NULL, (struct timeval *) NULL);
227
- if (result > 0) {
228
- if (FD_ISSET (dns_sd_fd, &readfds)) {
229
- DNSServiceProcessResult(*client);
230
- }
231
- } else {
232
- break;
233
- }
234
- }
235
- return Qnil;
236
- }
295
+ rb_scan_args (argc, argv, "02", &tmp_flags, &interface);
237
296
 
238
- static void DNSSD_API
239
- dnssd_browse_reply (DNSServiceRef client, DNSServiceFlags flags,
240
- uint32_t interface_index, DNSServiceErrorType errorCode,
241
- const char *replyName, const char *replyType,
242
- const char *replyDomain, void *context)
243
- {
244
- VALUE service, block, browse_reply;
245
- /* other parameters are undefined if errorCode != 0 */
246
- dnssd_check_error_code(errorCode);
297
+ /* optional parameters */
298
+ if (!NIL_P(tmp_flags))
299
+ flags = dnssd_to_flags(tmp_flags);
300
+ if (!NIL_P(interface))
301
+ interface_index = dnssd_get_interface_index(interface);
247
302
 
248
- service = (VALUE)context;
249
- block = dnssd_service_get_block(service);
250
- browse_reply = dnssd_browse_new(service, flags, interface_index,
251
- replyName, replyType, replyDomain);
252
-
253
- /* client is wrapped by service */
254
- rb_funcall2(block, dnssd_id_call, 1, &browse_reply);
303
+ GetDNSSDService(service, client);
304
+ e = DNSServiceEnumerateDomains (client, flags, interface_index,
305
+ dnssd_domain_enum_reply, (void *)service);
306
+ dnssd_check_error_code(e);
307
+ return service;
255
308
  }
256
309
 
257
310
  /*
258
311
  * call-seq:
259
- * DNSSD.browse(service_type, domain=nil, flags=0, interface=DNSSD::InterfaceAny) do |browse_reply|
260
- * block
261
- * end => service_handle
312
+ * DNSSD.enumerate_domains!(flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => obj
313
+ *
314
+ * Synchronously enumerate domains available for browsing and registration.
315
+ * For each domain found a DNSSD::Reply object is passed to block with #domain
316
+ * set to the enumerated domain.
317
+ *
318
+ * available_domains = []
319
+ * timeout(2) do
320
+ * DNSSD.enumerate_domains! do |r|
321
+ * available_domains << r.domain
322
+ * end
323
+ * rescue TimeoutError
324
+ * end
325
+ * puts available_domains.inspect
262
326
  *
263
- * Browse for DNSSD services.
264
- * For each service found DNSSD::BrowseReply object is passed to block.
327
+ */
328
+
329
+ static VALUE
330
+ dnssd_enumerate_domains_bang (int argc, VALUE * argv, VALUE self)
331
+ {
332
+ return dnssd_service_start(
333
+ sd_enumerate_domains(argc, argv, dnssd_service_alloc(rb_block_proc()))
334
+ );
335
+ }
336
+ /*
337
+ * call-seq:
338
+ * DNSSD.enumerate_domains(flags=0, interface=DNSSD::InterfaceAny) {|reply| bloc } => serivce_handle
339
+ *
340
+ * Asynchronously enumerate domains available for browsing and registration.
341
+ * For each domain found a DNSSD::DomainEnumReply object is passed to block.
265
342
  * The returned _service_handle_ can be used to control when to
266
- * stop browsing for services (see DNSSD::Service#stop).
343
+ * stop enumerating domains (see DNSSD::Service#stop).
344
+ *
345
+ * available_domains = []
346
+ * s = DNSSD.enumerate_domains do |d|
347
+ * available_domains << d.domain
348
+ * end
349
+ * sleep(0.2)
350
+ * s.stop
351
+ * puts available_domains.inspect
267
352
  *
268
353
  */
269
354
 
270
355
  static VALUE
271
- dnssd_browse (int argc, VALUE * argv, VALUE self)
356
+ dnssd_enumerate_domains(int argc, VALUE * argv, VALUE self)
357
+ {
358
+ return dnssd_service_start_in_thread(
359
+ sd_enumerate_domains(argc, argv, dnssd_service_alloc(rb_block_proc()))
360
+ );
361
+ }
362
+
363
+ static void DNSSD_API
364
+ dnssd_browse_reply (DNSServiceRef client, DNSServiceFlags flags,
365
+ uint32_t interface_index, DNSServiceErrorType e,
366
+ const char *name, const char *type,
367
+ const char *domain, void *context)
272
368
  {
273
- VALUE service_type, domain, tmp_flags, interface, block;
369
+ VALUE service;
370
+ /* other parameters are undefined if errorCode != 0 */
371
+ dnssd_check_error_code(e);
372
+ service = (VALUE)context;
373
+ dnssd_callback(service,
374
+ dnssd_browse_new (service, flags, interface_index, name, type, domain)
375
+ );
376
+ }
377
+
378
+ static VALUE
379
+ sd_browse(int argc, VALUE *argv, VALUE service)
380
+ {
381
+ VALUE type, domain, tmp_flags, interface;
274
382
 
275
383
  const char *type_str;
276
384
  const char *domain_str = NULL;
@@ -279,72 +387,91 @@ dnssd_browse (int argc, VALUE * argv, VALUE self)
279
387
 
280
388
  DNSServiceErrorType e;
281
389
  DNSServiceRef *client;
282
- VALUE service;
283
-
284
- rb_scan_args (argc, argv, "13&", &service_type, &domain,
285
- &tmp_flags, &interface, &block);
286
390
 
287
- /* required */
288
- dnssd_check_block(block);
289
- type_str = StringValueCStr(service_type);
391
+ rb_scan_args (argc, argv, "13", &type,
392
+ &domain, &tmp_flags, &interface);
393
+ type_str = StringValueCStr(type);
290
394
 
291
395
  /* optional parameters */
292
- if (domain != Qnil)
396
+ if (!NIL_P(domain))
293
397
  domain_str = dnssd_get_domain(domain);
294
- if (tmp_flags != Qnil)
398
+ if (!NIL_P(tmp_flags))
295
399
  flags = dnssd_to_flags(tmp_flags);
296
- if (interface != Qnil)
400
+ if (!NIL_P(interface))
297
401
  interface_index = dnssd_get_interface_index(interface);
298
402
 
299
- /* allocate this last since all other parameters are on the stack (thanks to & unary operator) */
300
- service = dnssd_service_alloc(block);
301
403
  GetDNSSDService(service, client);
302
-
303
404
  e = DNSServiceBrowse (client, flags, interface_index,
304
405
  type_str, domain_str,
305
406
  dnssd_browse_reply, (void *)service);
306
407
  dnssd_check_error_code(e);
307
- dnssd_service_start(service);
308
- return service;
408
+ return service;
309
409
  }
310
410
 
311
- static void DNSSD_API
312
- dnssd_register_reply (DNSServiceRef client, DNSServiceFlags flags,
313
- DNSServiceErrorType errorCode,
314
- const char *name, const char *regtype,
315
- const char *domain, void *context)
411
+ /*
412
+ * call-seq:
413
+ * DNSSD.browse!(type, domain=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => obj
414
+ *
415
+ * Synchronously browse for services.
416
+ * For each service found a DNSSD::Reply object is passed to block.
417
+ *
418
+ * timeout(6) do
419
+ * DNSSD.browse!('_http._tcp') do |r|
420
+ * puts "found: #{r.inspect}"
421
+ * end
422
+ * rescue TimeoutError
423
+ * end
424
+ *
425
+ */
426
+ static VALUE
427
+ dnssd_browse_bang(int argc, VALUE * argv, VALUE self)
316
428
  {
317
- VALUE service, block, register_reply;
318
- /* other parameters are undefined if errorCode != 0 */
319
- dnssd_check_error_code(errorCode);
320
-
321
- service = (VALUE)context;
322
- block = dnssd_service_get_block(service);
323
- register_reply = dnssd_register_new(service, flags, name, regtype, domain);
324
-
325
- rb_funcall2(block, dnssd_id_call, 1, &register_reply);
429
+ return dnssd_service_start(
430
+ sd_browse(argc, argv, dnssd_service_alloc(rb_block_proc()))
431
+ );
326
432
  }
433
+
327
434
 
328
435
  /*
329
436
  * call-seq:
330
- * DNSSD.register(service_name, service_type, service_domain, service_port, text_record=nil, flags=0, interface=DNSSD::InterfaceAny) do |register_reply|
331
- * block
332
- * end => service_handle
333
- *
334
- * Register a service.
335
- * If a block is provided a DNSSD::RegisterReply object will passed to the block
336
- * when the registration completes or asynchronously fails.
337
- * If no block is passed the client will not be notified of the default values picked
338
- * on its behalf or of any error that occur.
437
+ * DNSSD.browse(type, domain=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => service_handle
438
+ *
439
+ * Asynchronously browse for services.
440
+ * For each service found a DNSSD::BrowseReply object is passed to block.
339
441
  * The returned _service_handle_ can be used to control when to
340
- * stop the service (see DNSSD::Service#stop).
442
+ * stop browsing for services (see DNSSD::Service#stop).
443
+ *
444
+ * s = DNSSD.browse('_http._tcp') do |b|
445
+ * puts "found: #{b.inspect}"
446
+ * end
447
+ *
341
448
  */
449
+ static VALUE
450
+ dnssd_browse(int argc, VALUE * argv, VALUE self)
451
+ {
452
+ return dnssd_service_start_in_thread(
453
+ sd_browse(argc, argv, dnssd_service_alloc(rb_block_proc()))
454
+ );
455
+ }
456
+
457
+ static void DNSSD_API
458
+ dnssd_register_reply (DNSServiceRef client, DNSServiceFlags flags,
459
+ DNSServiceErrorType e,
460
+ const char *name, const char *regtype,
461
+ const char *domain, void *context)
462
+ {
463
+ VALUE service;
464
+ /* other parameters are undefined if errorCode != 0 */
465
+ dnssd_check_error_code(e);
466
+ service = (VALUE)context;
467
+ dnssd_callback(service, dnssd_register_new(service, flags, name, regtype, domain));
468
+ }
342
469
 
343
470
  static VALUE
344
- dnssd_register (int argc, VALUE * argv, VALUE self)
471
+ sd_register(int argc, VALUE *argv, VALUE service)
345
472
  {
346
- VALUE service_name, service_type, service_domain, service_port,
347
- text_record, tmp_flags, interface, block;
473
+ VALUE name, type, domain, port,
474
+ text_record, tmp_flags, interface;
348
475
 
349
476
  const char *name_str, *type_str, *domain_str = NULL;
350
477
  uint16_t opaqueport;
@@ -355,100 +482,117 @@ dnssd_register (int argc, VALUE * argv, VALUE self)
355
482
 
356
483
  DNSServiceErrorType e;
357
484
  DNSServiceRef *client;
358
- VALUE service;
359
485
 
360
- rb_scan_args (argc, argv, "43&",
361
- &service_name, &service_type,
362
- &service_domain, &service_port,
363
- &text_record, &tmp_flags,
364
- &interface, &block);
486
+ rb_scan_args (argc, argv, "43",
487
+ &name, &type, &domain, &port,
488
+ &text_record, &tmp_flags, &interface);
365
489
 
366
490
  /* required parameters */
367
- dnssd_check_block(block); /* in the future this may not be required */
368
- name_str = StringValueCStr(service_name);
369
- type_str = StringValueCStr(service_type);
491
+ name_str = StringValueCStr(name);
492
+ type_str = StringValueCStr(type);
370
493
 
371
- if (service_domain != Qnil)
372
- domain_str = dnssd_get_domain(service_domain);
494
+ if (!NIL_P(domain))
495
+ domain_str = dnssd_get_domain(domain);
373
496
  /* convert from host to net byte order */
374
- opaqueport = htons((uint16_t)NUM2UINT(service_port));
497
+ opaqueport = htons((uint16_t)NUM2UINT(port));
375
498
 
376
499
  /* optional parameters */
377
- if (text_record != Qnil) {
500
+ if (!NIL_P(text_record)) {
378
501
  text_record = dnssd_tr_to_encoded_str(text_record);
379
502
  txt_rec = RSTRING(text_record)->ptr;
380
503
  txt_len = RSTRING(text_record)->len;
381
504
  }
382
- if (tmp_flags != Qnil)
505
+ if (!NIL_P(tmp_flags))
383
506
  flags = dnssd_to_flags(tmp_flags);
384
- if(interface != Qnil)
507
+ if(!NIL_P(interface))
385
508
  interface_index = dnssd_get_interface_index(interface);
386
509
 
387
- /* allocate this last since all other parameters are on the stack (thanks to & unary operator) */
388
- service = dnssd_service_alloc(block);
389
510
  GetDNSSDService(service, client);
390
511
 
391
- e = DNSServiceRegister( client, flags, interface_index,
512
+ /* HACK */
513
+ rb_iv_set(service, "@interface", interface);
514
+ rb_iv_set(service, "@port", port);
515
+ rb_iv_set(service, "@text_record", text_record);
516
+ /********/
517
+ e = DNSServiceRegister (client, flags, interface_index,
392
518
  name_str, type_str, domain_str,
393
519
  NULL, opaqueport, txt_len, txt_rec,
394
- /*block == Qnil ? NULL : dnssd_register_reply,*/
395
520
  dnssd_register_reply, (void*)service );
396
521
  dnssd_check_error_code(e);
397
- dnssd_service_start(service);
398
522
  return service;
399
523
  }
400
524
 
401
525
  /*
402
- set text record using AddRecord
526
+ * call-seq:
527
+ * DNSSD.register!(name, type, domain, port, text_record=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => obj
528
+ *
529
+ * Synchronously register a service. A DNSSD::Reply object is passed
530
+ * to the block when the registration completes.
531
+ *
532
+ * DNSSD.register!("My Files", "_http._tcp", nil, 8080) do |r|
533
+ * warn("successfully registered: #{r.inspect}")
534
+ * end
535
+ *
536
+ */
403
537
  static VALUE
404
- dnssd_service_record(VALUE self, VALUE text_record)
538
+ dnssd_register_bang(int argc, VALUE * argv, VALUE self)
405
539
  {
406
- VALUE text_record, flags, time_to_live;
407
-
408
-
409
- text_record = dnssd_tr_to_encoded_str(text_record);
410
-
540
+ return dnssd_service_start(
541
+ sd_register(argc, argv, dnssd_service_alloc(rb_block_proc()))
542
+ );
543
+ }
544
+
545
+ /*
546
+ * call-seq:
547
+ * DNSSD.register(name, type, domain, port, text_record=nil, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => service_handle
548
+ *
549
+ * Asynchronously register a service. A DNSSD::Reply object is
550
+ * passed to the block when the registration completes.
551
+ * The returned _service_handle_ can be used to control when to
552
+ * stop the service (see DNSSD::Service#stop).
553
+ *
554
+ * # Start a webserver and register it using DNS Service Discovery
555
+ * require 'dnssd'
556
+ * require 'webrick'
557
+ *
558
+ * web_s = WEBrick::HTTPServer.new(:Port=>8080, :DocumentRoot=>Dir::pwd)
559
+ * dns_s = DNSSD.register("My Files", "_http._tcp", nil, 8080) do |r|
560
+ * warn("successfully registered: #{r.inspect}")
561
+ * end
562
+ *
563
+ * trap("INT"){ dns_s.stop; web_s.shutdown }
564
+ * web_s.start
565
+ *
566
+ */
567
+ static VALUE
568
+ dnssd_register(int argc, VALUE * argv, VALUE self)
569
+ {
570
+ return dnssd_service_start_in_thread(
571
+ sd_register(argc, argv, dnssd_service_alloc(rb_block_proc()))
572
+ );
411
573
  }
412
- */
413
574
 
414
575
  static void DNSSD_API
415
576
  dnssd_resolve_reply (DNSServiceRef client, DNSServiceFlags flags,
416
- uint32_t interface_index, DNSServiceErrorType errorCode,
577
+ uint32_t interface_index, DNSServiceErrorType e,
417
578
  const char *fullname, const char *host_target,
418
579
  uint16_t opaqueport, uint16_t txt_len,
419
580
  const char *txt_rec, void *context)
420
581
  {
582
+ VALUE service;
421
583
  /* other parameters are undefined if errorCode != 0 */
422
- dnssd_check_error_code(errorCode);
423
- VALUE service, block, resolve_reply;
424
-
584
+ dnssd_check_error_code(e);
425
585
  service = (VALUE)context;
426
- block = dnssd_service_get_block(service);
427
- resolve_reply = dnssd_resolve_new(service, flags, interface_index,
428
- fullname, host_target, opaqueport,
429
- txt_len, txt_rec);
430
-
431
- rb_funcall2(block, dnssd_id_call, 1, &resolve_reply);
586
+ dnssd_callback(service,
587
+ dnssd_resolve_new(service, flags, interface_index, fullname,
588
+ host_target, opaqueport, txt_len, txt_rec)
589
+ );
432
590
  }
433
591
 
434
- /*
435
- * call-seq:
436
- * DNSSD.resolve(service_name, service_type, service_domain, flags=0, interface=DNSSD::InterfaceAny) do |resolve_reply|
437
- * block
438
- * end => service_handle
439
- *
440
- * Resolve a service discovered via DNSSD.browse().
441
- * The service is resolved to a target host name, port number, and text record - all contained
442
- * in the DNSSD::ResolveReply object passed to the required block.
443
- * The returned _service_handle_ can be used to control when to
444
- * stop resolving the service (see DNSSD::Service#stop).
445
- */
446
-
447
592
  static VALUE
448
- dnssd_resolve(int argc, VALUE * argv, VALUE self)
593
+ sd_resolve(int argc, VALUE *argv, VALUE service)
449
594
  {
450
- VALUE service_name, service_type, service_domain,
451
- tmp_flags, interface, block;
595
+ VALUE name, type, domain, tmp_flags, interface;
452
596
 
453
597
  const char *name_str, *type_str, *domain_str;
454
598
  DNSServiceFlags flags = 0;
@@ -456,34 +600,76 @@ dnssd_resolve(int argc, VALUE * argv, VALUE self)
456
600
 
457
601
  DNSServiceErrorType err;
458
602
  DNSServiceRef *client;
459
- VALUE service;
460
603
 
461
- rb_scan_args (argc, argv, "32&",
462
- &service_name, &service_type, &service_domain,
463
- &tmp_flags, &interface, &block);
604
+ rb_scan_args(argc, argv, "32", &name, &type, &domain, &tmp_flags, &interface);
464
605
 
465
606
  /* required parameters */
466
- dnssd_check_block(block);
467
- name_str = StringValueCStr(service_name),
468
- type_str = StringValueCStr(service_type),
469
- domain_str = dnssd_get_domain(service_domain);
607
+ name_str = StringValueCStr(name),
608
+ type_str = StringValueCStr(type),
609
+ domain_str = dnssd_get_domain(domain);
470
610
 
471
611
  /* optional parameters */
472
- if (tmp_flags != Qnil)
612
+ if (!NIL_P(tmp_flags))
473
613
  flags = dnssd_to_flags(tmp_flags);
474
- if (interface != Qnil) {
614
+ if (!NIL_P(interface))
475
615
  interface_index = dnssd_get_interface_index(interface);
476
- }
477
616
 
478
- /* allocate this last since all other parameters are on the stack (thanks to unary & operator) */
479
- service = dnssd_service_alloc(block);
480
617
  GetDNSSDService(service, client);
481
-
482
618
  err = DNSServiceResolve (client, flags, interface_index, name_str, type_str,
483
- domain_str, dnssd_resolve_reply, (void *) service);
619
+ domain_str, dnssd_resolve_reply, (void *)service);
484
620
  dnssd_check_error_code(err);
485
- dnssd_service_start(service);
486
- return service;
621
+ return service;
622
+ }
623
+
624
+ /*
625
+ * call-seq:
626
+ * DNSSD.resolve!(name, type, domain, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => obj
627
+ *
628
+ * Synchronously resolve a service discovered via DNSSD.browse().
629
+ * The service is resolved to a target host name, port number, and
630
+ * text record - all contained in the DNSSD::Reply object
631
+ * passed to the required block.
632
+ *
633
+ * timeout(2) do
634
+ * DNSSD.resolve!("foo bar", "_http._tcp", "local") do |r|
635
+ * puts r.inspect
636
+ * end
637
+ * rescue TimeoutError
638
+ * end
639
+ *
640
+ */
641
+ static VALUE
642
+ dnssd_resolve_bang(int argc, VALUE * argv, VALUE self)
643
+ {
644
+ return dnssd_service_start(
645
+ sd_resolve(argc, argv, dnssd_service_alloc(rb_block_proc()))
646
+ );
647
+ }
648
+
649
+ /*
650
+ * call-seq:
651
+ * DNSSD.resolve(name, type, domain, flags=0, interface=DNSSD::InterfaceAny) {|reply| block } => service_handle
652
+ *
653
+ * Asynchronously resolve a service discovered via DNSSD.browse().
654
+ * The service is resolved to a target host name, port number, and
655
+ * text record - all contained in the DNSSD::Reply object
656
+ * passed to the required block.
657
+ * The returned _service_handle_ can be used to control when to
658
+ * stop resolving the service (see DNSSD::Service#stop).
659
+ *
660
+ * s = DNSSD.resolve("foo bar", "_http._tcp", "local") do |r|
661
+ * puts r.inspect
662
+ * end
663
+ * sleep(2)
664
+ * s.stop
665
+ *
666
+ */
667
+ static VALUE
668
+ dnssd_resolve(int argc, VALUE * argv, VALUE self)
669
+ {
670
+ return dnssd_service_start_in_thread(
671
+ sd_resolve(argc, argv, dnssd_service_alloc(rb_block_proc()))
672
+ );
487
673
  }
488
674
 
489
675
  void
@@ -497,19 +683,30 @@ Init_DNSSD_Service(void)
497
683
  dnssd_id_to_str = rb_intern("to_str");
498
684
  dnssd_iv_block = rb_intern("@block");
499
685
  dnssd_iv_thread = rb_intern("@thread");
686
+ dnssd_iv_result = rb_intern("@result");
500
687
  dnssd_iv_service = rb_intern("@service");
501
688
 
502
689
  cDNSSDService = rb_define_class_under(mDNSSD, "Service", rb_cObject);
503
690
 
504
691
  rb_define_singleton_method(cDNSSDService, "new", dnssd_service_new, -1);
505
- rb_define_singleton_method(cDNSSDService, "fullname", dnssd_service_fullname, 3);
692
+ rb_define_singleton_method(cDNSSDService, "fullname", dnssd_service_s_fullname, 3);
693
+ rb_define_singleton_method(cDNSSDService, "split_fullname", dnssd_service_s_split, 1);
694
+ rb_define_singleton_method(cDNSSDService, "split", dnssd_service_s_split, 1);
695
+
696
+ /* Access the services underlying thread. Returns nil if the service is synchronous. */
697
+ rb_define_attr(cDNSSDService, "thread", 1, 0);
506
698
 
507
699
  rb_define_method(cDNSSDService, "stop", dnssd_service_stop, 0);
508
700
  rb_define_method(cDNSSDService, "stopped?", dnssd_service_is_stopped, 0);
509
701
  rb_define_method(cDNSSDService, "inspect", dnssd_service_inspect, 0);
510
702
 
703
+ rb_define_module_function(mDNSSD, "enumerate_domains", dnssd_enumerate_domains, -1);
704
+ rb_define_module_function(mDNSSD, "enumerate_domains!", dnssd_enumerate_domains_bang, -1);
511
705
  rb_define_module_function(mDNSSD, "browse", dnssd_browse, -1);
706
+ rb_define_module_function(mDNSSD, "browse!", dnssd_browse_bang, -1);
512
707
  rb_define_module_function(mDNSSD, "resolve", dnssd_resolve, -1);
708
+ rb_define_module_function(mDNSSD, "resolve!", dnssd_resolve_bang, -1);
513
709
  rb_define_module_function(mDNSSD, "register", dnssd_register, -1);
710
+ rb_define_module_function(mDNSSD, "register!", dnssd_register_bang, -1);
514
711
  }
515
712