dnssd 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/MANIFEST +0 -0
- data/ext/dns_sd.h +1493 -0
- data/ext/extconf.rb +42 -0
- data/ext/rdnssd.c +151 -0
- data/ext/rdnssd.h +38 -0
- data/ext/rdnssd_service.c +515 -0
- data/ext/rdnssd_structs.c +588 -0
- data/ext/rdnssd_tr.c +252 -0
- data/ext/run_rdoc +4 -0
- data/lib/dnssd.rb +137 -0
- metadata +47 -0
data/ext/extconf.rb
ADDED
@@ -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
|
+
|
data/ext/rdnssd.c
ADDED
@@ -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
|
+
|
data/ext/rdnssd.h
ADDED
@@ -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, ®ister_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
|
+
|