--- /dev/null
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+
+ Change History (most recent first):
+
+$Log: SampleUDSClient.c,v $
+Revision 1.7 2003/08/18 18:50:15 cheshire
+Can now give "-lo" as first parameter, to test "local only" mode
+
+Revision 1.6 2003/08/12 19:56:25 cheshire
+Update to APSL 2.0
+
+ */
+
+#include <dns_sd.h>
+#include <unistd.h>
+#include <DNSServiceDiscovery/DNSServiceDiscovery.h> // include Mach API to ensure no conflicts exist
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#define BIND_8_COMPAT 1
+#include <nameser.h>
+// T_SRV is not defined in older versions of nameser.h
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+
+// constants
+#define MAX_DOMAIN_LABEL 63
+#define MAX_DOMAIN_NAME 255
+#define MAX_CSTRING 2044
+
+
+// data structure defs
+typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
+
+typedef struct { u_char c[ 64]; } domainlabel;
+typedef struct { u_char c[256]; } domainname;
+
+
+typedef struct
+ {
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ domainname target;
+ } srv_rdata;
+
+
+// private function prototypes
+static void sighdlr(int signo);
+static char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc);
+static char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc);
+//static void MyCallbackWrapper(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *i, void *context);
+static void print_rdata(int type, int len, const u_char *rdata);
+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);
+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);
+static void my_enum_cb( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
+static void my_regecordcb(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context);
+static void browse_cb(DNSServiceRef sdr, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err, const char *serviceName, const char *regtype, const char *domain, void *context);
+
+
+// globals
+static DNSServiceRef sdr = NULL;
+static uint32_t InterfaceIndex = 0;
+
+static void regservice_cb(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context)
+ {
+ #pragma unused (sdRef, flags, errorCode, context)
+ printf("regservice_cb %s %s %s\n", name, regtype, domain);
+ }
+
+int main (int argc, char * argv[]) {
+ int err, t, i;
+ char *name, *type, *domain;
+ DNSServiceFlags flags;
+ DNSRecordRef recordrefs[10];
+ char host[256];
+ int ipaddr = 12345; // random IP address
+
+ char full[1024];
+
+ // First parameter "-lo" means "local only"
+ if (!strcmp(argv[1], "-lo")) { InterfaceIndex = -1; argv++; argc--; }
+
+ if (signal(SIGINT, sighdlr) == SIG_ERR) fprintf(stderr, "ERROR - can't catch interupt!\n");
+ if (argc < 2) exit(1);
+
+ if (!strcmp(argv[1], "-regrecord"))
+ {
+ err = DNSServiceCreateConnection(&sdr);
+ if (err)
+ {
+ printf("DNSServiceCreateConnection returned %d\n", err);
+ exit(1);
+ }
+ printf("registering 10 address records...\n");
+ for (i = 0; i < 10; i++)
+ {
+ sprintf(host, "testhost-%d.local.", i);
+ ipaddr++;
+ err = DNSServiceRegisterRecord(sdr, &recordrefs[i], kDNSServiceFlagsUnique, InterfaceIndex,
+ host, 1, 1, 4, &ipaddr, 60, my_regecordcb, NULL);
+ if (err)
+ {
+ printf("DNSServiceRegisterRecord returned error %d\n", err);
+ exit(1);
+ }
+ }
+ printf("processing results...\n");
+ for (i = 0; i < 10; i++) DNSServiceProcessResult(sdr);
+ printf("deregistering half of the records\n");
+ for (i = 0; i < 10; i++)
+ {
+ if (i % 2)
+ {
+ err = DNSServiceRemoveRecord(sdr, recordrefs[i], 0);
+ if (err)
+ {
+ printf("DNSServiceRemoveRecord returned error %d\n" ,err);
+ exit(1);
+ }
+ }
+ }
+ printf("sleeping 10...\n");
+ sleep(10);
+ printf("deregistering all remaining records\n");;
+ DNSServiceRefDeallocate(sdr);
+ printf("done. sleeping 10..\n");
+ sleep(10);
+ exit(1);
+ }
+
+ if (!strcmp(argv[1], "-browse"))
+ {
+ if (argc < 3) exit(1);
+ err = DNSServiceBrowse(&sdr, 0, InterfaceIndex, argv[2], NULL /*"local."*/, browse_cb, NULL);
+ if (err)
+ {
+ printf("DNSServiceBrowse returned error %d\n", err);
+ exit(1);
+ }
+ while(1) DNSServiceProcessResult(sdr);
+ }
+
+ if (!strcmp(argv[1], "-enum"))
+ {
+ if (!strcmp(argv[2], "browse")) flags = kDNSServiceFlagsBrowseDomains;
+ else if (!strcmp(argv[2], "register")) flags = kDNSServiceFlagsRegistrationDomains;
+ else exit(1);
+
+ err = DNSServiceEnumerateDomains(&sdr, flags, InterfaceIndex, my_enum_cb, NULL);
+ if (err)
+ {
+ printf("EnumerateDomains returned error %d\n", err);
+ exit(1);
+ }
+ while(1) DNSServiceProcessResult(sdr);
+ }
+ if (!strcmp(argv[1], "-query"))
+ {
+ t = atol(argv[5]);
+ err = DNSServiceConstructFullName(full, argv[2], argv[3], argv[4]);
+ if (err) exit(1);
+ printf("resolving fullname %s type %d\n", full, t);
+ err = DNSServiceQueryRecord(&sdr, 0, 0, full, t, 1, query_cb, NULL);
+ while (1) DNSServiceProcessResult(sdr);
+ }
+
+ if (!strcmp(argv[1], "-regservice"))
+ {
+ char *regtype = "_http._tcp";
+ char txtstring[] = "\x0DMy Txt Record";
+ if (argc > 2) name = argv[2];
+ else name = NULL;
+ if (argc > 3) regtype = argv[3];
+ uint16_t PortAsNumber = 123;
+ if (argc > 4) PortAsNumber = atoi(argv[4]);
+ Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
+ err = DNSServiceRegister(&sdr, 0, InterfaceIndex, name, regtype, "local.", NULL, registerPort.NotAnInteger, sizeof(txtstring)-1, txtstring, regservice_cb, NULL);
+ if (err)
+ {
+ printf("DNSServiceRegister returned error %d\n", err);
+ exit(1);
+ }
+ while (1) DNSServiceProcessResult(sdr);
+ }
+ if (!strcmp(argv[1], "-resolve"))
+ {
+ name = argv[2];
+ type = argv[3];
+ domain = argv[4];
+ err = DNSServiceResolve(&sdr, 0, InterfaceIndex, name, type, domain, resolve_cb, NULL);
+ if (err)
+ {
+ printf("DNSServiceResolve returned error %d\n", err);
+ exit(1);
+ }
+ while(1) DNSServiceProcessResult(sdr);
+ }
+ exit(1);
+ }
+
+
+
+// callbacks
+
+// wrapper to make callbacks fit CFRunLoop callback signature
+/*
+static void MyCallbackWrapper(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *i, void *context)
+ {
+ (void)sr;
+ (void)t;
+ (void)dr;
+ (void)i;
+
+ DNSServiceRef *sdr = context;
+ DNSServiceDiscoveryProcessResult(*sdr);
+ }
+*/
+
+static void browse_cb(DNSServiceRef sdr, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err, const char *serviceName, const char *regtype, const char *domain, void *context)
+ {
+ #pragma unused(sdr, ifi, context)
+
+ if (err)
+ {
+ printf("Callback: error %d\n", err);
+ return;
+ }
+ printf("BrowseCB: %s %s %s %s (%s)\n", serviceName, regtype, domain, (flags & kDNSServiceFlagsMoreComing ? "(more coming)" : ""), flags & kDNSServiceFlagsAdd ? "(ADD)" : "(REMOVE)");
+
+ }
+
+static void my_enum_cb( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context)
+ {
+ #pragma unused(sdRef, context)
+ char *type;
+ if (flags == kDNSServiceFlagsAdd) type = "add";
+ else if (flags == kDNSServiceFlagsRemove) type = "remove";
+ else if (flags == (kDNSServiceFlagsAdd | kDNSServiceFlagsDefault)) type = "add default";
+ else type = "unknown";
+
+
+ if (errorCode) printf("EnumerateDomainsCB: error code %d\n", errorCode);
+ else printf("%s domain %s on interface %d\n", type, replyDomain, interfaceIndex);
+ }
+
+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)
+ {
+ (void)DNSServiceRef;
+ (void)flags;
+ (void)interfaceIndex;
+ (void)rrclass;
+ (void)ttl;
+ (void)context;
+
+ if (errorCode)
+ {
+ printf("query callback: error==%d\n", errorCode);
+ return;
+ }
+ printf("query callback - name = %s, rdata=\n", name);
+ print_rdata(rrtype, rdlen, rdata);
+ }
+
+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)
+ {
+ int i;
+
+ #pragma unused(sdRef, flags, interfaceIndex, errorCode, context, txtRecord)
+ printf("Resolved %s to %s:%d (%d bytes txt data)\n", fullname, hosttarget, port, txtLen);
+ printf("TXT Data:\n");
+ for (i = 0; i < txtLen; i++)
+ if (txtRecord[i] >= ' ') printf("%c", txtRecord[i]);
+ }
+
+
+
+static void my_regecordcb(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context)
+ {
+ #pragma unused (sdRef, RecordRef, flags, context)
+ if (errorCode) printf("regrecord CB received error %d\n", errorCode);
+ else printf("regrecord callback - no errors\n");
+ }
+
+
+// resource record data interpretation routines
+static char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
+ {
+ const u_char * src = label->c; // Domain label we're reading
+ const u_char len = *src++; // Read length of this (non-null) label
+ const u_char *const end = src + len; // Work out where the label ends
+ if (len > MAX_DOMAIN_LABEL) return(NULL); // If illegal label, abort
+ while (src < end) // While we have characters in the label
+ {
+ u_char c = *src++;
+ if (esc)
+ {
+ if (c == '.') // If character is a dot,
+ *ptr++ = esc; // Output escape character
+ else if (c <= ' ') // If non-printing ascii,
+ { // Output decimal escape sequence
+ *ptr++ = esc;
+ *ptr++ = (char) ('0' + (c / 100) );
+ *ptr++ = (char) ('0' + (c / 10) % 10);
+ c = (u_char)('0' + (c ) % 10);
+ }
+ }
+ *ptr++ = (char)c; // Copy the character
+ }
+ *ptr = 0; // Null-terminate the string
+ return(ptr); // and return
+ }
+
+static char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
+ {
+ const u_char *src = name->c; // Domain name we're reading
+ const u_char *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid
+
+ if (*src == 0) *ptr++ = '.'; // Special case: For root, just write a dot
+
+ while (*src) // While more characters in the domain name
+ {
+ if (src + 1 + *src >= max) return(NULL);
+ ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
+ if (!ptr) return(NULL);
+ src += 1 + *src;
+ *ptr++ = '.'; // Write the dot after the label
+ }
+
+ *ptr++ = 0; // Null-terminate the string
+ return(ptr); // and return
+ }
+
+// print arbitrary rdata in a readable manned
+static void print_rdata(int type, int len, const u_char *rdata)
+ {
+ int i;
+ srv_rdata *srv;
+ char targetstr[MAX_CSTRING];
+ struct in_addr in;
+
+ switch (type)
+ {
+ case T_TXT:
+ // print all the alphanumeric and punctuation characters
+ for (i = 0; i < len; i++)
+ if (rdata[i] >= 32 && rdata[i] <= 127) printf("%c", rdata[i]);
+ printf("\n");
+ return;
+ case T_SRV:
+ srv = (srv_rdata *)rdata;
+ ConvertDomainNameToCString_withescape(&srv->target, targetstr, 0);
+ printf("pri=%d, w=%d, port=%d, target=%s\n", srv->priority, srv->weight, srv->port, targetstr);
+ return;
+ case T_A:
+ assert(len == 4);
+ memcpy(&in, rdata, sizeof(in));
+ printf("%s\n", inet_ntoa(in));
+ return;
+ case T_PTR:
+ ConvertDomainNameToCString_withescape((domainname *)rdata, targetstr, 0);
+ printf("%s\n", targetstr);
+ return;
+ default:
+ printf("ERROR: I dont know how to print RData of type %d\n", type);
+ return;
+ }
+ }
+
+
+
+
+// signal handlers, setup/teardown, etc.
+static void sighdlr(int signo)
+ {
+ assert(signo == SIGINT);
+ fprintf(stderr, "Received sigint - deallocating serviceref and exiting\n");
+ if (sdr)
+ DNSServiceRefDeallocate(sdr);
+ exit(1);
+ }
+
+
+
+
+
+
+