]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/SampleUDSClient.c
mDNSResponder-58.8.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / SampleUDSClient.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: SampleUDSClient.c,v $
26 Revision 1.7 2003/08/18 18:50:15 cheshire
27 Can now give "-lo" as first parameter, to test "local only" mode
28
29 Revision 1.6 2003/08/12 19:56:25 cheshire
30 Update to APSL 2.0
31
32 */
33
34 #include <dns_sd.h>
35 #include <unistd.h>
36 #include <DNSServiceDiscovery/DNSServiceDiscovery.h> // include Mach API to ensure no conflicts exist
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #define BIND_8_COMPAT 1
43 #include <nameser.h>
44 // T_SRV is not defined in older versions of nameser.h
45 #ifndef T_SRV
46 #define T_SRV 33
47 #endif
48
49 // constants
50 #define MAX_DOMAIN_LABEL 63
51 #define MAX_DOMAIN_NAME 255
52 #define MAX_CSTRING 2044
53
54
55 // data structure defs
56 typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
57
58 typedef struct { u_char c[ 64]; } domainlabel;
59 typedef struct { u_char c[256]; } domainname;
60
61
62 typedef struct
63 {
64 uint16_t priority;
65 uint16_t weight;
66 uint16_t port;
67 domainname target;
68 } srv_rdata;
69
70
71 // private function prototypes
72 static void sighdlr(int signo);
73 static char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc);
74 static char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc);
75 //static void MyCallbackWrapper(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *i, void *context);
76 static void print_rdata(int type, int len, const u_char *rdata);
77 static void query_cb(const DNSServiceRef DNSServiceRef, const DNSServiceFlags flags, const u_int32_t interfaceIndex, const DNSServiceErrorType errorCode, const char *name, const u_int16_t rrtype, const u_int16_t rrclass, const u_int16_t rdlen, const void *rdata, const u_int32_t ttl, void *context);
78 static void resolve_cb(const DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context);
79 static void my_enum_cb( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
80 static void my_regecordcb(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context);
81 static void browse_cb(DNSServiceRef sdr, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err, const char *serviceName, const char *regtype, const char *domain, void *context);
82
83
84 // globals
85 static DNSServiceRef sdr = NULL;
86 static uint32_t InterfaceIndex = 0;
87
88 static void regservice_cb(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context)
89 {
90 #pragma unused (sdRef, flags, errorCode, context)
91 printf("regservice_cb %s %s %s\n", name, regtype, domain);
92 }
93
94 int main (int argc, char * argv[]) {
95 int err, t, i;
96 char *name, *type, *domain;
97 DNSServiceFlags flags;
98 DNSRecordRef recordrefs[10];
99 char host[256];
100 int ipaddr = 12345; // random IP address
101
102 char full[1024];
103
104 // First parameter "-lo" means "local only"
105 if (!strcmp(argv[1], "-lo")) { InterfaceIndex = -1; argv++; argc--; }
106
107 if (signal(SIGINT, sighdlr) == SIG_ERR) fprintf(stderr, "ERROR - can't catch interupt!\n");
108 if (argc < 2) exit(1);
109
110 if (!strcmp(argv[1], "-regrecord"))
111 {
112 err = DNSServiceCreateConnection(&sdr);
113 if (err)
114 {
115 printf("DNSServiceCreateConnection returned %d\n", err);
116 exit(1);
117 }
118 printf("registering 10 address records...\n");
119 for (i = 0; i < 10; i++)
120 {
121 sprintf(host, "testhost-%d.local.", i);
122 ipaddr++;
123 err = DNSServiceRegisterRecord(sdr, &recordrefs[i], kDNSServiceFlagsUnique, InterfaceIndex,
124 host, 1, 1, 4, &ipaddr, 60, my_regecordcb, NULL);
125 if (err)
126 {
127 printf("DNSServiceRegisterRecord returned error %d\n", err);
128 exit(1);
129 }
130 }
131 printf("processing results...\n");
132 for (i = 0; i < 10; i++) DNSServiceProcessResult(sdr);
133 printf("deregistering half of the records\n");
134 for (i = 0; i < 10; i++)
135 {
136 if (i % 2)
137 {
138 err = DNSServiceRemoveRecord(sdr, recordrefs[i], 0);
139 if (err)
140 {
141 printf("DNSServiceRemoveRecord returned error %d\n" ,err);
142 exit(1);
143 }
144 }
145 }
146 printf("sleeping 10...\n");
147 sleep(10);
148 printf("deregistering all remaining records\n");;
149 DNSServiceRefDeallocate(sdr);
150 printf("done. sleeping 10..\n");
151 sleep(10);
152 exit(1);
153 }
154
155 if (!strcmp(argv[1], "-browse"))
156 {
157 if (argc < 3) exit(1);
158 err = DNSServiceBrowse(&sdr, 0, InterfaceIndex, argv[2], NULL /*"local."*/, browse_cb, NULL);
159 if (err)
160 {
161 printf("DNSServiceBrowse returned error %d\n", err);
162 exit(1);
163 }
164 while(1) DNSServiceProcessResult(sdr);
165 }
166
167 if (!strcmp(argv[1], "-enum"))
168 {
169 if (!strcmp(argv[2], "browse")) flags = kDNSServiceFlagsBrowseDomains;
170 else if (!strcmp(argv[2], "register")) flags = kDNSServiceFlagsRegistrationDomains;
171 else exit(1);
172
173 err = DNSServiceEnumerateDomains(&sdr, flags, InterfaceIndex, my_enum_cb, NULL);
174 if (err)
175 {
176 printf("EnumerateDomains returned error %d\n", err);
177 exit(1);
178 }
179 while(1) DNSServiceProcessResult(sdr);
180 }
181 if (!strcmp(argv[1], "-query"))
182 {
183 t = atol(argv[5]);
184 err = DNSServiceConstructFullName(full, argv[2], argv[3], argv[4]);
185 if (err) exit(1);
186 printf("resolving fullname %s type %d\n", full, t);
187 err = DNSServiceQueryRecord(&sdr, 0, 0, full, t, 1, query_cb, NULL);
188 while (1) DNSServiceProcessResult(sdr);
189 }
190
191 if (!strcmp(argv[1], "-regservice"))
192 {
193 char *regtype = "_http._tcp";
194 char txtstring[] = "\x0DMy Txt Record";
195 if (argc > 2) name = argv[2];
196 else name = NULL;
197 if (argc > 3) regtype = argv[3];
198 uint16_t PortAsNumber = 123;
199 if (argc > 4) PortAsNumber = atoi(argv[4]);
200 Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
201 err = DNSServiceRegister(&sdr, 0, InterfaceIndex, name, regtype, "local.", NULL, registerPort.NotAnInteger, sizeof(txtstring)-1, txtstring, regservice_cb, NULL);
202 if (err)
203 {
204 printf("DNSServiceRegister returned error %d\n", err);
205 exit(1);
206 }
207 while (1) DNSServiceProcessResult(sdr);
208 }
209 if (!strcmp(argv[1], "-resolve"))
210 {
211 name = argv[2];
212 type = argv[3];
213 domain = argv[4];
214 err = DNSServiceResolve(&sdr, 0, InterfaceIndex, name, type, domain, resolve_cb, NULL);
215 if (err)
216 {
217 printf("DNSServiceResolve returned error %d\n", err);
218 exit(1);
219 }
220 while(1) DNSServiceProcessResult(sdr);
221 }
222 exit(1);
223 }
224
225
226
227 // callbacks
228
229 // wrapper to make callbacks fit CFRunLoop callback signature
230 /*
231 static void MyCallbackWrapper(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *i, void *context)
232 {
233 (void)sr;
234 (void)t;
235 (void)dr;
236 (void)i;
237
238 DNSServiceRef *sdr = context;
239 DNSServiceDiscoveryProcessResult(*sdr);
240 }
241 */
242
243 static void browse_cb(DNSServiceRef sdr, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err, const char *serviceName, const char *regtype, const char *domain, void *context)
244 {
245 #pragma unused(sdr, ifi, context)
246
247 if (err)
248 {
249 printf("Callback: error %d\n", err);
250 return;
251 }
252 printf("BrowseCB: %s %s %s %s (%s)\n", serviceName, regtype, domain, (flags & kDNSServiceFlagsMoreComing ? "(more coming)" : ""), flags & kDNSServiceFlagsAdd ? "(ADD)" : "(REMOVE)");
253
254 }
255
256 static void my_enum_cb( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context)
257 {
258 #pragma unused(sdRef, context)
259 char *type;
260 if (flags == kDNSServiceFlagsAdd) type = "add";
261 else if (flags == kDNSServiceFlagsRemove) type = "remove";
262 else if (flags == (kDNSServiceFlagsAdd | kDNSServiceFlagsDefault)) type = "add default";
263 else type = "unknown";
264
265
266 if (errorCode) printf("EnumerateDomainsCB: error code %d\n", errorCode);
267 else printf("%s domain %s on interface %d\n", type, replyDomain, interfaceIndex);
268 }
269
270 static void query_cb(const DNSServiceRef DNSServiceRef, const DNSServiceFlags flags, const u_int32_t interfaceIndex, const DNSServiceErrorType errorCode, const char *name, const u_int16_t rrtype, const u_int16_t rrclass, const u_int16_t rdlen, const void *rdata, const u_int32_t ttl, void *context)
271 {
272 (void)DNSServiceRef;
273 (void)flags;
274 (void)interfaceIndex;
275 (void)rrclass;
276 (void)ttl;
277 (void)context;
278
279 if (errorCode)
280 {
281 printf("query callback: error==%d\n", errorCode);
282 return;
283 }
284 printf("query callback - name = %s, rdata=\n", name);
285 print_rdata(rrtype, rdlen, rdata);
286 }
287
288 static void resolve_cb(const DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
289 {
290 int i;
291
292 #pragma unused(sdRef, flags, interfaceIndex, errorCode, context, txtRecord)
293 printf("Resolved %s to %s:%d (%d bytes txt data)\n", fullname, hosttarget, port, txtLen);
294 printf("TXT Data:\n");
295 for (i = 0; i < txtLen; i++)
296 if (txtRecord[i] >= ' ') printf("%c", txtRecord[i]);
297 }
298
299
300
301 static void my_regecordcb(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context)
302 {
303 #pragma unused (sdRef, RecordRef, flags, context)
304 if (errorCode) printf("regrecord CB received error %d\n", errorCode);
305 else printf("regrecord callback - no errors\n");
306 }
307
308
309 // resource record data interpretation routines
310 static char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
311 {
312 const u_char * src = label->c; // Domain label we're reading
313 const u_char len = *src++; // Read length of this (non-null) label
314 const u_char *const end = src + len; // Work out where the label ends
315 if (len > MAX_DOMAIN_LABEL) return(NULL); // If illegal label, abort
316 while (src < end) // While we have characters in the label
317 {
318 u_char c = *src++;
319 if (esc)
320 {
321 if (c == '.') // If character is a dot,
322 *ptr++ = esc; // Output escape character
323 else if (c <= ' ') // If non-printing ascii,
324 { // Output decimal escape sequence
325 *ptr++ = esc;
326 *ptr++ = (char) ('0' + (c / 100) );
327 *ptr++ = (char) ('0' + (c / 10) % 10);
328 c = (u_char)('0' + (c ) % 10);
329 }
330 }
331 *ptr++ = (char)c; // Copy the character
332 }
333 *ptr = 0; // Null-terminate the string
334 return(ptr); // and return
335 }
336
337 static char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
338 {
339 const u_char *src = name->c; // Domain name we're reading
340 const u_char *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid
341
342 if (*src == 0) *ptr++ = '.'; // Special case: For root, just write a dot
343
344 while (*src) // While more characters in the domain name
345 {
346 if (src + 1 + *src >= max) return(NULL);
347 ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
348 if (!ptr) return(NULL);
349 src += 1 + *src;
350 *ptr++ = '.'; // Write the dot after the label
351 }
352
353 *ptr++ = 0; // Null-terminate the string
354 return(ptr); // and return
355 }
356
357 // print arbitrary rdata in a readable manned
358 static void print_rdata(int type, int len, const u_char *rdata)
359 {
360 int i;
361 srv_rdata *srv;
362 char targetstr[MAX_CSTRING];
363 struct in_addr in;
364
365 switch (type)
366 {
367 case T_TXT:
368 // print all the alphanumeric and punctuation characters
369 for (i = 0; i < len; i++)
370 if (rdata[i] >= 32 && rdata[i] <= 127) printf("%c", rdata[i]);
371 printf("\n");
372 return;
373 case T_SRV:
374 srv = (srv_rdata *)rdata;
375 ConvertDomainNameToCString_withescape(&srv->target, targetstr, 0);
376 printf("pri=%d, w=%d, port=%d, target=%s\n", srv->priority, srv->weight, srv->port, targetstr);
377 return;
378 case T_A:
379 assert(len == 4);
380 memcpy(&in, rdata, sizeof(in));
381 printf("%s\n", inet_ntoa(in));
382 return;
383 case T_PTR:
384 ConvertDomainNameToCString_withescape((domainname *)rdata, targetstr, 0);
385 printf("%s\n", targetstr);
386 return;
387 default:
388 printf("ERROR: I dont know how to print RData of type %d\n", type);
389 return;
390 }
391 }
392
393
394
395
396 // signal handlers, setup/teardown, etc.
397 static void sighdlr(int signo)
398 {
399 assert(signo == SIGINT);
400 fprintf(stderr, "Received sigint - deallocating serviceref and exiting\n");
401 if (sdr)
402 DNSServiceRefDeallocate(sdr);
403 exit(1);
404 }
405
406
407
408
409
410
411