dnssd 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ #!/usr/local/bin/ruby
2
+ #!/usr/bin/ruby
3
+ # :nodoc: all
4
+ #
5
+ # Extension configuration script for DNS_SD C Extension.
6
+ # $Id: extconf.rb,v 1.5 2004/10/04 18:29:53 cmills Exp $
7
+ #
8
+ #
9
+
10
+ def check_for_funcs(*funcs)
11
+ funcs.flatten!
12
+ funcs.each do |f|
13
+ abort("need function #{f}") unless have_func(f)
14
+ end
15
+ end
16
+
17
+ require "mkmf"
18
+
19
+ $CFLAGS << " -Wall"
20
+ $CFLAGS << " -DDEBUG" if $DEBUG
21
+
22
+ ### Print an error message and exit with an error condition
23
+ def abort( msg )
24
+ $stderr.puts( msg )
25
+ exit 1
26
+ end
27
+
28
+ unless RUBY_PLATFORM.include? "darwin"
29
+ have_library( "mdns", "DNSServiceRefSockFD" ) or
30
+ abort( "can't find rendezvous library" )
31
+ end
32
+
33
+ #have_library( "dns-sd", "DNSServiceRefSockFD" ) or
34
+ # abort( "Can't find rendezvous client library" )
35
+
36
+ have_header( "dns_sd.h" ) or
37
+ abort( "can't find the rendezvous client headers" )
38
+
39
+ check_for_funcs("htons", "ntohs", "if_indextoname", "if_nametoindex")
40
+
41
+ create_makefile("rdnssd")
42
+
@@ -0,0 +1,151 @@
1
+ /*
2
+ * == Authors
3
+ * Chad Fowler, Charles Mills, Rich Kilmer
4
+ *
5
+ * == Copyright
6
+ * Copyright (c) 2004 Chad Fowler, Charles Mills, Rich Kilmer
7
+ * Licensed under the same terms as Ruby.
8
+ * This software has absolutely no warranty.
9
+ */
10
+
11
+ #include "rdnssd.h"
12
+ #include <assert.h>
13
+
14
+ VALUE mDNSSD;
15
+ static VALUE eDNSSDError;
16
+ static VALUE eDNSSDUnknownError;
17
+
18
+ #define DNSSD_ERROR_START (-65556)
19
+ #define DNSSD_ERROR_END (-65536)
20
+
21
+ static VALUE dnssd_errors[DNSSD_ERROR_END - DNSSD_ERROR_START];
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
+ static void
31
+ dnssd_errors_store(VALUE error, int num)
32
+ {
33
+ assert(DNSSD_ERROR_START <= num && num < DNSSD_ERROR_END);
34
+ dnssd_errors[num - DNSSD_ERROR_START] = error;
35
+ }
36
+
37
+ void
38
+ dnssd_check_error_code(DNSServiceErrorType e)
39
+ {
40
+ int num = (int)e;
41
+ if (num) {
42
+ 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);
44
+ } else {
45
+ rb_raise(eDNSSDUnknownError, "DNSSD operation failed with unrecognized error code: %i", num);
46
+ }
47
+ }
48
+ }
49
+
50
+ void
51
+ dnssd_instantiation_error(const char *what)
52
+ {
53
+ rb_raise(rb_eRuntimeError, "cannot instantiate %s, use DNSSD browse(), resolve() or register() instead", what);
54
+ }
55
+
56
+ /*
57
+ * Document-module: DNSSD
58
+ * 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.
62
+ */
63
+
64
+ static void
65
+ Init_DNSSD(void)
66
+ {
67
+ VALUE error_class;
68
+ mDNSSD = rb_define_module("DNSSD");
69
+ eDNSSDError = rb_define_class_under(mDNSSD, "Error", rb_eStandardError);
70
+
71
+ /* Specifies all interfaces. */
72
+ rb_define_const(mDNSSD, "InterfaceAny", ULONG2NUM(kDNSServiceInterfaceIndexAny));
73
+ /* Specifies local interfaces only. */
74
+ rb_define_const(mDNSSD, "InterfaceLocalOnly", ULONG2NUM(kDNSServiceInterfaceIndexLocalOnly));
75
+
76
+ /* errors - these are 2 stepped (create and store) so that rdoc is happy */
77
+ eDNSSDUnknownError = rb_define_class_under(mDNSSD, "UnknownError", eDNSSDError);
78
+ dnssd_errors_store(eDNSSDUnknownError, -65537);
79
+
80
+ error_class = rb_define_class_under(mDNSSD, "NoSuchNameError", eDNSSDError);
81
+ dnssd_errors_store(error_class, -65538);
82
+
83
+ dnssd_errors_store(rb_eNoMemError, -65539);
84
+
85
+ error_class = rb_define_class_under(mDNSSD, "BadParamError", eDNSSDError);
86
+ dnssd_errors_store(error_class, -65540);
87
+
88
+ error_class = rb_define_class_under(mDNSSD, "BadReferenceError", eDNSSDError);
89
+ dnssd_errors_store(error_class, -65541);
90
+
91
+ error_class = rb_define_class_under(mDNSSD, "BadStateError", eDNSSDError);
92
+ dnssd_errors_store(error_class, -65542);
93
+
94
+ error_class = rb_define_class_under(mDNSSD, "BadFlagsError", eDNSSDError);
95
+ dnssd_errors_store(error_class, -65543);
96
+
97
+ error_class = rb_define_class_under(mDNSSD, "UnsupportedError", eDNSSDError);
98
+ dnssd_errors_store(error_class, -65544);
99
+
100
+ error_class = rb_define_class_under(mDNSSD, "NotInitializedError", eDNSSDError);
101
+ dnssd_errors_store(error_class, -65545);
102
+
103
+ error_class = rb_define_class_under(mDNSSD, "AlreadyRegisteredError", eDNSSDError);
104
+ dnssd_errors_store(error_class, -65547);
105
+
106
+ error_class = rb_define_class_under(mDNSSD, "NameConflictError", eDNSSDError);
107
+ dnssd_errors_store(error_class, -65548);
108
+
109
+ error_class = rb_define_class_under(mDNSSD, "InvalidError", eDNSSDError);
110
+ dnssd_errors_store(error_class, -65549);
111
+
112
+ error_class = rb_define_class_under(mDNSSD, "ClientIncompatibleError", eDNSSDError);
113
+ dnssd_errors_store(error_class, -65551);
114
+
115
+ error_class = rb_define_class_under(mDNSSD, "BadInterfaceIndexError", eDNSSDError);
116
+ dnssd_errors_store(error_class, -65552);
117
+
118
+ error_class = rb_define_class_under(mDNSSD, "ReferenceUsedError", eDNSSDError);
119
+ dnssd_errors_store(error_class, -65553);
120
+
121
+ error_class = rb_define_class_under(mDNSSD, "NoSuchRecordError", eDNSSDError);
122
+ dnssd_errors_store(error_class, -65554);
123
+
124
+ error_class = rb_define_class_under(mDNSSD, "NoAuthenticationError", eDNSSDError);
125
+ dnssd_errors_store(error_class, -65555);
126
+
127
+ error_class = rb_define_class_under(mDNSSD, "NoSuchKeyError", eDNSSDError);
128
+ dnssd_errors_store(error_class, -65556);
129
+ }
130
+
131
+ /* Document-class: DNSSD::Error
132
+ *
133
+ * Base class of all DNS Service Discovery related errors.
134
+ *
135
+ */
136
+
137
+ /* defined in other .c files */
138
+ void Init_DNSSD_Service(void);
139
+ void Init_DNSSD_TextRecord(void);
140
+ void Init_DNSSD_Replies(void);
141
+
142
+ void
143
+ Init_rdnssd(void)
144
+ {
145
+ /* called when library is required */
146
+ Init_DNSSD();
147
+ Init_DNSSD_Service();
148
+ Init_DNSSD_TextRecord();
149
+ Init_DNSSD_Replies();
150
+ }
151
+
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright (c) 2004 Chad Fowler, Charles Mills, Rich Kilmer
3
+ * Licenced under the same terms as Ruby.
4
+ * This software has absolutely no warrenty.
5
+ */
6
+ #ifndef RDNSSD_INCLUDED
7
+ #define RDNSSD_INCLUDED
8
+
9
+ #include <ruby.h>
10
+ #include <dns_sd.h>
11
+
12
+ extern VALUE mDNSSD;
13
+
14
+ void dnssd_check_error_code(DNSServiceErrorType e);
15
+ void dnssd_instantiation_error(const char *what);
16
+
17
+ VALUE dnssd_create_fullname(VALUE name, VALUE regtype, VALUE domain, int err_flag);
18
+
19
+ /* decodes a buffer, creating a new text record */
20
+ VALUE dnssd_tr_new(long len, const char *buf);
21
+
22
+ VALUE dnssd_tr_to_encoded_str(VALUE v);
23
+
24
+ /* Get DNSServiceFlags from self */
25
+ DNSServiceFlags dnssd_to_flags(VALUE obj);
26
+
27
+ VALUE dnssd_register_new(VALUE service, DNSServiceFlags flags, const char *name,
28
+ const char *regtype, const char *domain );
29
+
30
+ VALUE dnssd_browse_new(VALUE service, DNSServiceFlags flags, uint32_t interface,
31
+ const char *name, const char *regtype, const char *domain);
32
+
33
+ VALUE dnssd_resolve_new(VALUE service, DNSServiceFlags flags, uint32_t interface,
34
+ const char *fullname, const char *host_target,
35
+ uint16_t opaqueport, uint16_t txt_len, const char *txt_rec);
36
+
37
+ #endif /* RDNSSD_INCLUDED */
38
+
@@ -0,0 +1,515 @@
1
+ /*
2
+ * Ruby Rendezvous Binding
3
+ * $Id: rdnssd_service.c,v 1.12 2004/10/07 15:19:14 cmills Exp $
4
+ *
5
+ * Copyright (c) 2004 Chad Fowler, Charles Mills, Rich Kilmer
6
+ * Licenced under the same terms as Ruby.
7
+ * This software has absolutely no warranty.
8
+ */
9
+
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>
17
+
18
+ #ifndef DNSSD_API
19
+ /* define as nothing if not defined in "dns_sd.h" header */
20
+ #define DNSSD_API
21
+ #endif
22
+
23
+ static VALUE cDNSSDService;
24
+ static ID dnssd_id_call;
25
+ static ID dnssd_id_to_str;
26
+ static ID dnssd_iv_block;
27
+ static ID dnssd_iv_thread;
28
+ static ID dnssd_iv_service;
29
+
30
+ #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);
34
+
35
+ static void
36
+ dnssd_check_block(VALUE block)
37
+ {
38
+ if (block == Qnil) {
39
+ rb_raise(rb_eArgError, "block required");
40
+ }
41
+ }
42
+
43
+ static const char *
44
+ dnssd_get_domain(VALUE service_domain)
45
+ {
46
+ const char *domain = StringValueCStr(service_domain);
47
+ /* max len including the null terminator and trailing '.' */
48
+ if (strlen(domain) >= kDNSServiceMaxDomainName - 1)
49
+ rb_raise(rb_eArgError, "domain name string too large");
50
+ return domain;
51
+ }
52
+
53
+ static uint32_t
54
+ dnssd_get_interface_index(VALUE interface)
55
+ {
56
+ /* if the interface is a string then convert it to the interface index */
57
+ if (rb_respond_to(interface, dnssd_id_to_str)) {
58
+ return if_nametoindex(StringValueCStr(interface));
59
+ } else {
60
+ return (uint32_t)NUM2ULONG(interface);
61
+ }
62
+ }
63
+
64
+ /*
65
+ * call-seq:
66
+ * DNSSD::Serivce.fullname(name, type, domain) => string
67
+ *
68
+ * Concatenate a three-part domain name (as seen in DNSSD::Reply#fullname())
69
+ * into a properly-escaped full domain name.
70
+ *
71
+ * Any dots or slashes in the _name_ must NOT be escaped.
72
+ * May be <code>nil</code> (to construct a PTR record name, e.g. "_ftp._tcp.apple.com").
73
+ *
74
+ * The _type_ is the service type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").
75
+ *
76
+ * The _domain_ is the domain name, e.g. "apple.com". Any literal dots or backslashes
77
+ * must be escaped.
78
+ *
79
+ * Raises a <code>ArgumentError</code> if the full service name cannot be constructed from
80
+ * the arguments.
81
+ */
82
+
83
+ static VALUE
84
+ dnssd_service_fullname(VALUE klass, VALUE name, VALUE type, VALUE domain)
85
+ {
86
+ return dnssd_create_fullname(name, type, domain, 1);
87
+ }
88
+
89
+ /*
90
+ * call-seq:
91
+ * DNSSD::Serivce.new() => raises a RuntimeError
92
+ *
93
+ * Services can only be instantiated using DNSSD.browse(), DNSSD.register(), and DNSSD.resolve().
94
+ */
95
+
96
+ static VALUE
97
+ dnssd_service_new(int argc, VALUE *argv, VALUE klass)
98
+ {
99
+ dnssd_instantiation_error(rb_class2name(klass));
100
+ return Qnil;
101
+ }
102
+
103
+ static void
104
+ dnssd_service_stop_client(VALUE service)
105
+ {
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
+ DNSServiceRefDeallocate(*client);
110
+ free(client); /* free the pointer */
111
+ }
112
+
113
+ static void
114
+ dnssd_service_free(void *ptr)
115
+ {
116
+ DNSServiceRef *client = (DNSServiceRef*)ptr;
117
+ 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 */
122
+ }
123
+ }
124
+
125
+ static VALUE
126
+ dnssd_service_alloc(VALUE block)
127
+ {
128
+ DNSServiceRef *client = ALLOC(DNSServiceRef);
129
+ VALUE service = Data_Wrap_Struct(cDNSSDService, 0, dnssd_service_free, client);
130
+ rb_ivar_set(service, dnssd_iv_block, block);
131
+ rb_ivar_set(service, dnssd_iv_thread, Qnil);
132
+ return service;
133
+ }
134
+
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
+ /*
148
+ * call-seq:
149
+ * service.stopped? => true or false
150
+ *
151
+ * Returns <code>true</code> if _service_ has been stopped, <code>false</code> otherwise.
152
+ */
153
+
154
+ static VALUE
155
+ dnssd_service_is_stopped(VALUE service)
156
+ {
157
+ return NIL_P(rb_ivar_get(service, dnssd_iv_thread)) ? Qtrue : Qfalse;
158
+ }
159
+
160
+ /*
161
+ * call-seq:
162
+ * service.stop => service
163
+ *
164
+ * Stops the DNSSD::Service _service_; closing the underlying socket and killing
165
+ * the underlying thread.
166
+ */
167
+
168
+ static VALUE
169
+ dnssd_service_stop(VALUE service)
170
+ {
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 */
180
+ rb_ivar_set(service, dnssd_iv_block, Qnil);
181
+
182
+ /* do this last! - thread must be killed */
183
+ dnssd_service_stop_client(service);
184
+ return service;
185
+ }
186
+
187
+ /*
188
+ * call-seq:
189
+ * service.inspect => string
190
+ *
191
+ */
192
+
193
+ static VALUE
194
+ dnssd_service_inspect(VALUE self)
195
+ {
196
+ VALUE buf = rb_str_buf_new(0);
197
+ rb_str_buf_cat2(buf, "<#");
198
+ rb_str_buf_cat2(buf, rb_obj_classname(self));
199
+ if (dnssd_service_is_stopped(self)) {
200
+ rb_str_buf_cat2(buf, " (stopped)");
201
+ }
202
+ rb_str_buf_cat2(buf, ">");
203
+ return buf;
204
+ }
205
+
206
+ static VALUE
207
+ dnssd_service_get_block(VALUE service)
208
+ {
209
+ return rb_ivar_get(service, dnssd_iv_block);
210
+ }
211
+
212
+ static VALUE
213
+ dnssd_process(VALUE service)
214
+ {
215
+ int dns_sd_fd, nfds, result;
216
+ fd_set readfds;
217
+
218
+ DNSServiceRef *client;
219
+ GetDNSSDService(service, client);
220
+
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
+ }
237
+
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);
247
+
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);
255
+ }
256
+
257
+ /*
258
+ * call-seq:
259
+ * DNSSD.browse(service_type, domain=nil, flags=0, interface=DNSSD::InterfaceAny) do |browse_reply|
260
+ * block
261
+ * end => service_handle
262
+ *
263
+ * Browse for DNSSD services.
264
+ * For each service found DNSSD::BrowseReply object is passed to block.
265
+ * The returned _service_handle_ can be used to control when to
266
+ * stop browsing for services (see DNSSD::Service#stop).
267
+ *
268
+ */
269
+
270
+ static VALUE
271
+ dnssd_browse (int argc, VALUE * argv, VALUE self)
272
+ {
273
+ VALUE service_type, domain, tmp_flags, interface, block;
274
+
275
+ const char *type_str;
276
+ const char *domain_str = NULL;
277
+ DNSServiceFlags flags = 0;
278
+ uint32_t interface_index = 0;
279
+
280
+ DNSServiceErrorType e;
281
+ DNSServiceRef *client;
282
+ VALUE service;
283
+
284
+ rb_scan_args (argc, argv, "13&", &service_type, &domain,
285
+ &tmp_flags, &interface, &block);
286
+
287
+ /* required */
288
+ dnssd_check_block(block);
289
+ type_str = StringValueCStr(service_type);
290
+
291
+ /* optional parameters */
292
+ if (domain != Qnil)
293
+ domain_str = dnssd_get_domain(domain);
294
+ if (tmp_flags != Qnil)
295
+ flags = dnssd_to_flags(tmp_flags);
296
+ if (interface != Qnil)
297
+ interface_index = dnssd_get_interface_index(interface);
298
+
299
+ /* allocate this last since all other parameters are on the stack (thanks to & unary operator) */
300
+ service = dnssd_service_alloc(block);
301
+ GetDNSSDService(service, client);
302
+
303
+ e = DNSServiceBrowse (client, flags, interface_index,
304
+ type_str, domain_str,
305
+ dnssd_browse_reply, (void *)service);
306
+ dnssd_check_error_code(e);
307
+ dnssd_service_start(service);
308
+ return service;
309
+ }
310
+
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)
316
+ {
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);
326
+ }
327
+
328
+ /*
329
+ * 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.
339
+ * The returned _service_handle_ can be used to control when to
340
+ * stop the service (see DNSSD::Service#stop).
341
+ */
342
+
343
+ static VALUE
344
+ dnssd_register (int argc, VALUE * argv, VALUE self)
345
+ {
346
+ VALUE service_name, service_type, service_domain, service_port,
347
+ text_record, tmp_flags, interface, block;
348
+
349
+ const char *name_str, *type_str, *domain_str = NULL;
350
+ uint16_t opaqueport;
351
+ uint16_t txt_len = 0;
352
+ char *txt_rec = NULL;
353
+ DNSServiceFlags flags = 0;
354
+ uint32_t interface_index = 0;
355
+
356
+ DNSServiceErrorType e;
357
+ DNSServiceRef *client;
358
+ VALUE service;
359
+
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);
365
+
366
+ /* 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);
370
+
371
+ if (service_domain != Qnil)
372
+ domain_str = dnssd_get_domain(service_domain);
373
+ /* convert from host to net byte order */
374
+ opaqueport = htons((uint16_t)NUM2UINT(service_port));
375
+
376
+ /* optional parameters */
377
+ if (text_record != Qnil) {
378
+ text_record = dnssd_tr_to_encoded_str(text_record);
379
+ txt_rec = RSTRING(text_record)->ptr;
380
+ txt_len = RSTRING(text_record)->len;
381
+ }
382
+ if (tmp_flags != Qnil)
383
+ flags = dnssd_to_flags(tmp_flags);
384
+ if(interface != Qnil)
385
+ interface_index = dnssd_get_interface_index(interface);
386
+
387
+ /* allocate this last since all other parameters are on the stack (thanks to & unary operator) */
388
+ service = dnssd_service_alloc(block);
389
+ GetDNSSDService(service, client);
390
+
391
+ e = DNSServiceRegister( client, flags, interface_index,
392
+ name_str, type_str, domain_str,
393
+ NULL, opaqueport, txt_len, txt_rec,
394
+ /*block == Qnil ? NULL : dnssd_register_reply,*/
395
+ dnssd_register_reply, (void*)service );
396
+ dnssd_check_error_code(e);
397
+ dnssd_service_start(service);
398
+ return service;
399
+ }
400
+
401
+ /*
402
+ set text record using AddRecord
403
+ static VALUE
404
+ dnssd_service_record(VALUE self, VALUE text_record)
405
+ {
406
+ VALUE text_record, flags, time_to_live;
407
+
408
+
409
+ text_record = dnssd_tr_to_encoded_str(text_record);
410
+
411
+ }
412
+ */
413
+
414
+ static void DNSSD_API
415
+ dnssd_resolve_reply (DNSServiceRef client, DNSServiceFlags flags,
416
+ uint32_t interface_index, DNSServiceErrorType errorCode,
417
+ const char *fullname, const char *host_target,
418
+ uint16_t opaqueport, uint16_t txt_len,
419
+ const char *txt_rec, void *context)
420
+ {
421
+ /* other parameters are undefined if errorCode != 0 */
422
+ dnssd_check_error_code(errorCode);
423
+ VALUE service, block, resolve_reply;
424
+
425
+ 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);
432
+ }
433
+
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
+ static VALUE
448
+ dnssd_resolve(int argc, VALUE * argv, VALUE self)
449
+ {
450
+ VALUE service_name, service_type, service_domain,
451
+ tmp_flags, interface, block;
452
+
453
+ const char *name_str, *type_str, *domain_str;
454
+ DNSServiceFlags flags = 0;
455
+ uint32_t interface_index = 0;
456
+
457
+ DNSServiceErrorType err;
458
+ DNSServiceRef *client;
459
+ VALUE service;
460
+
461
+ rb_scan_args (argc, argv, "32&",
462
+ &service_name, &service_type, &service_domain,
463
+ &tmp_flags, &interface, &block);
464
+
465
+ /* 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);
470
+
471
+ /* optional parameters */
472
+ if (tmp_flags != Qnil)
473
+ flags = dnssd_to_flags(tmp_flags);
474
+ if (interface != Qnil) {
475
+ interface_index = dnssd_get_interface_index(interface);
476
+ }
477
+
478
+ /* allocate this last since all other parameters are on the stack (thanks to unary & operator) */
479
+ service = dnssd_service_alloc(block);
480
+ GetDNSSDService(service, client);
481
+
482
+ err = DNSServiceResolve (client, flags, interface_index, name_str, type_str,
483
+ domain_str, dnssd_resolve_reply, (void *) service);
484
+ dnssd_check_error_code(err);
485
+ dnssd_service_start(service);
486
+ return service;
487
+ }
488
+
489
+ void
490
+ Init_DNSSD_Service(void)
491
+ {
492
+ /* hack so rdoc documents the project correctly */
493
+ #ifdef mDNSSD_RDOC_HACK
494
+ mDNSSD = rb_define_module("DNSSD");
495
+ #endif
496
+ dnssd_id_call = rb_intern("call");
497
+ dnssd_id_to_str = rb_intern("to_str");
498
+ dnssd_iv_block = rb_intern("@block");
499
+ dnssd_iv_thread = rb_intern("@thread");
500
+ dnssd_iv_service = rb_intern("@service");
501
+
502
+ cDNSSDService = rb_define_class_under(mDNSSD, "Service", rb_cObject);
503
+
504
+ rb_define_singleton_method(cDNSSDService, "new", dnssd_service_new, -1);
505
+ rb_define_singleton_method(cDNSSDService, "fullname", dnssd_service_fullname, 3);
506
+
507
+ rb_define_method(cDNSSDService, "stop", dnssd_service_stop, 0);
508
+ rb_define_method(cDNSSDService, "stopped?", dnssd_service_is_stopped, 0);
509
+ rb_define_method(cDNSSDService, "inspect", dnssd_service_inspect, 0);
510
+
511
+ rb_define_module_function(mDNSSD, "browse", dnssd_browse, -1);
512
+ rb_define_module_function(mDNSSD, "resolve", dnssd_resolve, -1);
513
+ rb_define_module_function(mDNSSD, "register", dnssd_register, -1);
514
+ }
515
+