2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
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
29 Revision 1.6 2003/08/12 19:56:25 cheshire
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
44 // T_SRV is not defined in older versions of nameser.h
50 #define MAX_DOMAIN_LABEL 63
51 #define MAX_DOMAIN_NAME 255
52 #define MAX_CSTRING 2044
55 // data structure defs
56 typedef union { unsigned char b
[2]; unsigned short NotAnInteger
; } Opaque16
;
58 typedef struct { u_char c
[ 64]; } domainlabel
;
59 typedef struct { u_char c
[256]; } domainname
;
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
);
85 static DNSServiceRef sdr
= NULL
;
86 static uint32_t InterfaceIndex
= 0;
88 static void regservice_cb(DNSServiceRef sdRef
, DNSServiceFlags flags
, DNSServiceErrorType errorCode
, const char *name
, const char *regtype
, const char *domain
, void *context
)
90 #pragma unused (sdRef, flags, errorCode, context)
91 printf("regservice_cb %s %s %s\n", name
, regtype
, domain
);
94 int main (int argc
, char * argv
[]) {
96 char *name
, *type
, *domain
;
97 DNSServiceFlags flags
;
98 DNSRecordRef recordrefs
[10];
100 int ipaddr
= 12345; // random IP address
104 // First parameter "-lo" means "local only"
105 if (!strcmp(argv
[1], "-lo")) { InterfaceIndex
= -1; argv
++; argc
--; }
107 if (signal(SIGINT
, sighdlr
) == SIG_ERR
) fprintf(stderr
, "ERROR - can't catch interupt!\n");
108 if (argc
< 2) exit(1);
110 if (!strcmp(argv
[1], "-regrecord"))
112 err
= DNSServiceCreateConnection(&sdr
);
115 printf("DNSServiceCreateConnection returned %d\n", err
);
118 printf("registering 10 address records...\n");
119 for (i
= 0; i
< 10; i
++)
121 sprintf(host
, "testhost-%d.local.", i
);
123 err
= DNSServiceRegisterRecord(sdr
, &recordrefs
[i
], kDNSServiceFlagsUnique
, InterfaceIndex
,
124 host
, 1, 1, 4, &ipaddr
, 60, my_regecordcb
, NULL
);
127 printf("DNSServiceRegisterRecord returned error %d\n", err
);
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
++)
138 err
= DNSServiceRemoveRecord(sdr
, recordrefs
[i
], 0);
141 printf("DNSServiceRemoveRecord returned error %d\n" ,err
);
146 printf("sleeping 10...\n");
148 printf("deregistering all remaining records\n");;
149 DNSServiceRefDeallocate(sdr
);
150 printf("done. sleeping 10..\n");
155 if (!strcmp(argv
[1], "-browse"))
157 if (argc
< 3) exit(1);
158 err
= DNSServiceBrowse(&sdr
, 0, InterfaceIndex
, argv
[2], NULL
/*"local."*/, browse_cb
, NULL
);
161 printf("DNSServiceBrowse returned error %d\n", err
);
164 while(1) DNSServiceProcessResult(sdr
);
167 if (!strcmp(argv
[1], "-enum"))
169 if (!strcmp(argv
[2], "browse")) flags
= kDNSServiceFlagsBrowseDomains
;
170 else if (!strcmp(argv
[2], "register")) flags
= kDNSServiceFlagsRegistrationDomains
;
173 err
= DNSServiceEnumerateDomains(&sdr
, flags
, InterfaceIndex
, my_enum_cb
, NULL
);
176 printf("EnumerateDomains returned error %d\n", err
);
179 while(1) DNSServiceProcessResult(sdr
);
181 if (!strcmp(argv
[1], "-query"))
184 err
= DNSServiceConstructFullName(full
, argv
[2], argv
[3], argv
[4]);
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
);
191 if (!strcmp(argv
[1], "-regservice"))
193 char *regtype
= "_http._tcp";
194 char txtstring
[] = "\x0DMy Txt Record";
195 if (argc
> 2) name
= argv
[2];
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
);
204 printf("DNSServiceRegister returned error %d\n", err
);
207 while (1) DNSServiceProcessResult(sdr
);
209 if (!strcmp(argv
[1], "-resolve"))
214 err
= DNSServiceResolve(&sdr
, 0, InterfaceIndex
, name
, type
, domain
, resolve_cb
, NULL
);
217 printf("DNSServiceResolve returned error %d\n", err
);
220 while(1) DNSServiceProcessResult(sdr
);
229 // wrapper to make callbacks fit CFRunLoop callback signature
231 static void MyCallbackWrapper(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *i, void *context)
238 DNSServiceRef *sdr = context;
239 DNSServiceDiscoveryProcessResult(*sdr);
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
)
245 #pragma unused(sdr, ifi, context)
249 printf("Callback: error %d\n", err
);
252 printf("BrowseCB: %s %s %s %s (%s)\n", serviceName
, regtype
, domain
, (flags
& kDNSServiceFlagsMoreComing
? "(more coming)" : ""), flags
& kDNSServiceFlagsAdd
? "(ADD)" : "(REMOVE)");
256 static void my_enum_cb( DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
, DNSServiceErrorType errorCode
, const char *replyDomain
, void *context
)
258 #pragma unused(sdRef, context)
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";
266 if (errorCode
) printf("EnumerateDomainsCB: error code %d\n", errorCode
);
267 else printf("%s domain %s on interface %d\n", type
, replyDomain
, interfaceIndex
);
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
)
274 (void)interfaceIndex
;
281 printf("query callback: error==%d\n", errorCode
);
284 printf("query callback - name = %s, rdata=\n", name
);
285 print_rdata(rrtype
, rdlen
, rdata
);
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
)
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
]);
301 static void my_regecordcb(DNSServiceRef sdRef
, DNSRecordRef RecordRef
, DNSServiceFlags flags
, DNSServiceErrorType errorCode
, void *context
)
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");
309 // resource record data interpretation routines
310 static char *ConvertDomainLabelToCString_withescape(const domainlabel
*const label
, char *ptr
, char esc
)
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
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
326 *ptr
++ = (char) ('0' + (c
/ 100) );
327 *ptr
++ = (char) ('0' + (c
/ 10) % 10);
328 c
= (u_char
)('0' + (c
) % 10);
331 *ptr
++ = (char)c
; // Copy the character
333 *ptr
= 0; // Null-terminate the string
334 return(ptr
); // and return
337 static char *ConvertDomainNameToCString_withescape(const domainname
*const name
, char *ptr
, char esc
)
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
342 if (*src
== 0) *ptr
++ = '.'; // Special case: For root, just write a dot
344 while (*src
) // While more characters in the domain name
346 if (src
+ 1 + *src
>= max
) return(NULL
);
347 ptr
= ConvertDomainLabelToCString_withescape((const domainlabel
*)src
, ptr
, esc
);
348 if (!ptr
) return(NULL
);
350 *ptr
++ = '.'; // Write the dot after the label
353 *ptr
++ = 0; // Null-terminate the string
354 return(ptr
); // and return
357 // print arbitrary rdata in a readable manned
358 static void print_rdata(int type
, int len
, const u_char
*rdata
)
362 char targetstr
[MAX_CSTRING
];
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
]);
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
);
380 memcpy(&in
, rdata
, sizeof(in
));
381 printf("%s\n", inet_ntoa(in
));
384 ConvertDomainNameToCString_withescape((domainname
*)rdata
, targetstr
, 0);
385 printf("%s\n", targetstr
);
388 printf("ERROR: I dont know how to print RData of type %d\n", type
);
396 // signal handlers, setup/teardown, etc.
397 static void sighdlr(int signo
)
399 assert(signo
== SIGINT
);
400 fprintf(stderr
, "Received sigint - deallocating serviceref and exiting\n");
402 DNSServiceRefDeallocate(sdr
);