/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * 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 #include #include // include Mach API to ensure no conflicts exist #include #include #include #include #include #define BIND_8_COMPAT 1 #include // 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); }