]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSMacOSX/SampleUDSClient.c
mDNSResponder-58.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / SampleUDSClient.c
diff --git a/mDNSMacOSX/SampleUDSClient.c b/mDNSMacOSX/SampleUDSClient.c
new file mode 100755 (executable)
index 0000000..7838fc1
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * 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);
+    }
+
+