mDNSResponder-108.4.tar.gz mac-os-x-1049ppc mac-os-x-1049x86 v108.4
authorApple <opensource@apple.com>
Mon, 8 Jan 2007 22:13:12 +0000 (22:13 +0000)
committerApple <opensource@apple.com>
Mon, 8 Jan 2007 22:13:12 +0000 (22:13 +0000)
18 files changed:
Makefile
mDNSCore/DNSCommon.c
mDNSCore/DNSCommon.h
mDNSCore/mDNS.c
mDNSCore/mDNSEmbeddedAPI.h
mDNSCore/uDNS.c
mDNSCore/uDNS.h
mDNSMacOS9/mDNSMacOS9.c
mDNSMacOSX/mDNSMacOSX.c
mDNSPosix/mDNSPosix.c
mDNSShared/GenLinkedList.c [changed mode: 0755->0644]
mDNSShared/GenLinkedList.h [changed mode: 0755->0644]
mDNSShared/dns_sd.h [changed mode: 0755->0644]
mDNSShared/dnssd_clientlib.c [changed mode: 0755->0644]
mDNSShared/dnssd_clientstub.c [changed mode: 0755->0644]
mDNSShared/uds_daemon.c
mDNSVxWorks/mDNSVxWorksIPv4Only.c
mDNSWindows/mDNSWin32.c

index ce810ebcb78c7c0bedbcc788d98bdc3ac86c915c..1c65768707aa13b6b4096eaa7eb3c9943828e289 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-108.2"
+MVERS = "mDNSResponder-108.4"
 
 install:
        cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
index 2ce24894e8665cb9216b3c06239340b2449742ad..e16b4aefc51cdb751f47e06e9d126011d46841e1 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
     Change History (most recent first):
 
 $Log: DNSCommon.c,v $
+Revision 1.96.2.1  2006/10/31 02:50:16  cheshire
+<rdar://problem/4683163> mDNSResponder insufficiently defensive against malformed browsing PTR responses
+
+Revision 1.96  2006/03/10 21:51:42  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Split out SameRDataBody() into a separate routine so it can be called from other code
+
+Revision 1.95  2006/03/08 22:43:11  cheshire
+Use "localdomain" symbol instead of literal string
+
+Revision 1.94  2006/03/02 21:59:55  cheshire
+<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
+Improve sanity checks & debugging support in GetLargeResourceRecord()
+
+Revision 1.93  2006/03/02 20:30:47  cheshire
+Improved GetRRDisplayString to also show priority, weight, and port for SRV records
+
+Revision 1.92  2005/09/16 21:06:49  cheshire
+Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
+
+Revision 1.91  2005/07/10 22:10:37  cheshire
+The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to
+hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that
+large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires.
+
 Revision 1.90  2005/03/21 00:33:51  shersche
 <rdar://problem/4021486> Fix build warnings on Win32 platform
 
@@ -450,7 +476,8 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd,
                case kDNSType_TXT:  mDNS_snprintf(buffer+length, 79-length, "%#s", rd->txt.c);         break;
 
                case kDNSType_AAAA:     mDNS_snprintf(buffer+length, 79-length, "%.16a", &rd->ipv6);       break;
-               case kDNSType_SRV:      mDNS_snprintf(buffer+length, 79-length, "%##s", rd->srv.target.c); break;
+               case kDNSType_SRV:      mDNS_snprintf(buffer+length, 79-length, "%u %u %u %##s",
+                                                               rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
                default:                        mDNS_snprintf(buffer+length, 79-length, "RDLen %d: %s", rr->rdlength, rd->data);  break;
                }
        for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
@@ -863,7 +890,7 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
 
        src = type->c;                                                                          // Put the service type into the domain name
        len = *src;
-       if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, (domainname*)"\x05" "local")))
+       if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain)))
                {
                errormsg="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
                goto fail;
@@ -896,6 +923,11 @@ fail:
        return(mDNSNULL);
        }
 
+// A service name has the form: instance.application-protocol.transport-protocol.domain
+// DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character
+// set or length limits for the protocol names, and the final domain is allowed to be empty.
+// However, if the given FQDN doesn't contain at least three labels,
+// DeconstructServiceName will reject it and return mDNSfalse.
 mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
        domainlabel *const name, domainname *const type, domainname *const domain)
        {
@@ -904,29 +936,32 @@ mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
        const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME;
        mDNSu8 *dst;
 
-       dst = name->c;                                                                          // Extract the service name from the domain name
+       dst = name->c;                                                                          // Extract the service name
        len = *src;
-       if (len >= 0x40) { debugf("DeconstructServiceName: service name too long"); return(mDNSfalse); }
+       if (!len)        { debugf("DeconstructServiceName: FQDN empty!");            return(mDNSfalse); }
+       if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); }
        for (i=0; i<=len; i++) *dst++ = *src++;
 
-       dst = type->c;                                                                          // Extract the service type from the domain name
+       dst = type->c;                                                                          // Extract the service type
        len = *src;
-       if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); }
+       if (!len)        { debugf("DeconstructServiceName: FQDN contains only one label!");      return(mDNSfalse); }
+       if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); }
        for (i=0; i<=len; i++) *dst++ = *src++;
 
        len = *src;
-       if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); }
+       if (!len)        { debugf("DeconstructServiceName: FQDN contains only two labels!");   return(mDNSfalse); }
+       if (len >= 0x40) { debugf("DeconstructServiceName: Transport protocol name too long"); return(mDNSfalse); }
        for (i=0; i<=len; i++) *dst++ = *src++;
-       *dst++ = 0;             // Put the null root label on the end of the service type
+       *dst++ = 0;                                                                                     // Put terminator on the end of service type
 
-       dst = domain->c;                                                                        // Extract the service domain from the domain name
+       dst = domain->c;                                                                        // Extract the service domain
        while (*src)
                {
                len = *src;
                if (len >= 0x40)
-                       { debugf("DeconstructServiceName: service domain label too long"); return(mDNSfalse); }
+                       { debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); }
                if (src + 1 + len + 1 >= max)
-                       { debugf("DeconstructServiceName: service domain too long"); return(mDNSfalse); }
+                       { debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); }
                for (i=0; i<=len; i++) *dst++ = *src++;
                }
        *dst++ = 0;             // Put the null root label on the end
@@ -1092,25 +1127,32 @@ mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const
        return(sum);
        }
 
-mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2)
+// r1 has to be a full ResourceRecord including rrtype and rdlength
+// r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
+mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2)
        {
-       if (r1->rrtype     != r2->rrtype)     return(mDNSfalse);
-       if (r1->rdlength   != r2->rdlength)   return(mDNSfalse);
-       if (r1->rdatahash  != r2->rdatahash)  return(mDNSfalse);
        switch(r1->rrtype)
                {
                case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      return(SameDomainName(&r1->rdata->u.name, &r2->rdata->u.name));
+               case kDNSType_PTR:      return(SameDomainName(&r1->rdata->u.name, &r2->name));
 
-               case kDNSType_SRV:      return(mDNSBool)(       r1->rdata->u.srv.priority          == r2->rdata->u.srv.priority          &&
-                                                                                               r1->rdata->u.srv.weight            == r2->rdata->u.srv.weight            &&
-                                                                                               r1->rdata->u.srv.port.NotAnInteger == r2->rdata->u.srv.port.NotAnInteger &&
-                                                                                               SameDomainName(&r1->rdata->u.srv.target, &r2->rdata->u.srv.target)       );
+               case kDNSType_SRV:      return(mDNSBool)(       r1->rdata->u.srv.priority          == r2->srv.priority          &&
+                                                                                               r1->rdata->u.srv.weight            == r2->srv.weight            &&
+                                                                                               r1->rdata->u.srv.port.NotAnInteger == r2->srv.port.NotAnInteger &&
+                                                                                               SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target)       );
 
-               default:                        return(mDNSPlatformMemSame(r1->rdata->u.data, r2->rdata->u.data, r1->rdlength));
+               default:                        return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength));
                }
        }
 
+mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2)
+       {
+       if (r1->rrtype     != r2->rrtype)     return(mDNSfalse);
+       if (r1->rdlength   != r2->rdlength)   return(mDNSfalse);
+       if (r1->rdatahash  != r2->rdatahash)  return(mDNSfalse);
+       return(SameRDataBody(r1, &r2->rdata->u));
+       }
+
 mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
        {
        return (r1->namehash == r2->namehash &&
@@ -1383,9 +1425,10 @@ mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr)
        return val;
        }
 
-mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr, mDNSu16 pktRDLen)
+mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit, LargeCacheRecord *const cr, mDNSu16 pktRDLen)
        {
        int nread = 0;
+       ResourceRecord *const rr = &cr->r.resrec;
        rdataOpt *opt = (rdataOpt *)rr->rdata->u.data;
 
        while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOpt))
@@ -1787,11 +1830,10 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        CacheRecord *rr = &largecr->r;
        mDNSu16 pktrdlength;
        
-       if (largecr == &m->rec && rr->resrec.RecordType)
-               LogMsg("GetLargeResourceRecord: m->rec appears to be already in use");
+       if (largecr == &m->rec && largecr->r.resrec.RecordType)
+               LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &largecr->r));
 
        rr->next              = mDNSNULL;
-       rr->resrec.RecordType = RecordType;
        rr->resrec.name       = &largecr->namestorage;
 
        rr->NextInKAList      = mDNSNULL;
@@ -1823,7 +1865,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
        pktrdlength           = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
        if (ptr[2] & (kDNSClass_UniqueRRSet >> 8))
-               rr->resrec.RecordType |= kDNSRecordTypePacketUniqueMask;
+               RecordType |= kDNSRecordTypePacketUniqueMask;
        ptr += 10;
        if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
        end = ptr + pktrdlength;                // Adjust end to indicate the end of the rdata for this resource record
@@ -1884,7 +1926,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                                        rr->resrec.rdata->u.soa.min     = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
                                        break;
 
-               case kDNSType_OPT:  getOptRdata(ptr, end, &rr->resrec, pktrdlength); break;
+               case kDNSType_OPT:  getOptRdata(ptr, end, largecr, pktrdlength); break;
 
                default:                        if (pktrdlength > rr->resrec.rdata->MaxRDLength)
                                                                {
@@ -1907,6 +1949,8 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
        SetNewRData(&rr->resrec, mDNSNULL, 0);
 
+       // Success! Now fill in RecordType to show this record contains valid data
+       rr->resrec.RecordType = RecordType;
        return(ptr + pktrdlength);
        }
 
@@ -2047,14 +2091,14 @@ mDNSexport void mDNS_Lock(mDNS *const m)
        if (m->mDNS_busy == 0)
                {
                if (m->timenow)
-                       LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNSPlatformRawTime() + m->timenow_adjust);
-               m->timenow = mDNSPlatformRawTime() + m->timenow_adjust;
+                       LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNS_TimeNow_NoLock(m));
+               m->timenow = mDNS_TimeNow_NoLock(m);
                if (m->timenow == 0) m->timenow = 1;
                }
        else if (m->timenow == 0)
                {
                LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
-               m->timenow = mDNSPlatformRawTime() + m->timenow_adjust;
+               m->timenow = mDNS_TimeNow_NoLock(m);
                if (m->timenow == 0) m->timenow = 1;
                }
 
index 13b7ca80f2bc64dbbd1cf8d41316b63559e986c6..0f236c00d9f12641ddd3117fa4a8fb31d30a92ad 100644 (file)
     Change History (most recent first):
 
 $Log: DNSCommon.h,v $
+Revision 1.33  2006/03/10 21:51:41  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Split out SameRDataBody() into a separate routine so it can be called from other code
+
 Revision 1.32  2005/03/21 00:33:51  shersche
 <rdar://problem/4021486> Fix build warnings on Win32 platform
 
@@ -235,6 +239,7 @@ extern void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus r
 
 extern mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb);
 
+extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2);
 extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2);
 
 extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
index db6d0e537fbeb6f4fd98ba9e55cdfb96f4b1c402..8c9b5664a21c8d2321d0438c60b5ce83be0df561 100755 (executable)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
     Change History (most recent first):
 
 $Log: mDNS.c,v $
+Revision 1.535.2.3  2006/11/10 19:36:42  cheshire
+Further refinement: Only harmonize TTL if the value we're adjusting it to is at least 2 seconds
+
+Revision 1.535.2.2  2006/10/31 02:11:26  cheshire
+Compile error: Need to put back AllDNSLinkGroupv4 definition
+
+Revision 1.535.2.1  2006/10/31 01:28:06  cheshire
+<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
+
+Revision 1.535  2006/03/02 20:41:17  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Minor code tidying and comments to reduce the risk of similar programming errors in future
+
+Revision 1.534  2006/03/02 03:25:46  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
+
+Revision 1.533  2006/02/26 00:54:41  cheshire
+Fixes to avoid code generation warning/error on FreeBSD 7
+
+Revision 1.532  2005/12/02 20:24:36  cheshire
+<rdar://problem/4363209> Adjust cutoff time for KA list by one second
+
+Revision 1.531  2005/12/02 19:05:42  cheshire
+Tidy up constants
+
+Revision 1.530  2005/11/07 01:49:48  cheshire
+For consistency, use NonZeroTime() function instead of ?: expression
+
+Revision 1.529  2005/10/25 23:42:24  cheshire
+<rdar://problem/4316057> Error in ResolveSimultaneousProbe() when type or class don't match
+Changed switch statement to an "if"
+
+Revision 1.528  2005/10/25 23:34:22  cheshire
+<rdar://problem/4316048> RequireGoodbye state not set/respected sometimes when machine going to sleep
+
+Revision 1.527  2005/10/25 22:43:59  cheshire
+Add clarifying comments
+
 Revision 1.526  2005/10/20 00:10:33  cheshire
 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
 
@@ -503,7 +542,7 @@ Revision 1.388  2004/07/30 17:40:06  ksekar
 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
 
 Revision 1.387  2004/07/26 22:49:30  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
 
 Revision 1.386  2004/07/13 21:24:24  rpantos
 Fix for <rdar://problem/3701120>.
@@ -1737,22 +1776,30 @@ mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly  = (mDNSInterfaceID)1;
 
 mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark        = (mDNSInterfaceID)~0;
 
-#define UnicastDNSPortAsNumber 53
+#define UnicastDNSPortAsNumber   53
+#define NATPMPPortAsNumber       5351
+#define DNSEXTPortAsNumber       5352          // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
 #define MulticastDNSPortAsNumber 5353
+#define LoopbackIPCPortAsNumber  5354
+
 mDNSexport const mDNSIPPort UnicastDNSPort     = { { UnicastDNSPortAsNumber   >> 8, UnicastDNSPortAsNumber   & 0xFF } };
+mDNSexport const mDNSIPPort NATPMPPort         = { { NATPMPPortAsNumber       >> 8, NATPMPPortAsNumber       & 0xFF } };
+mDNSexport const mDNSIPPort DNSEXTPort         = { { DNSEXTPortAsNumber       >> 8, DNSEXTPortAsNumber       & 0xFF } };
 mDNSexport const mDNSIPPort MulticastDNSPort   = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort LoopbackIPCPort    = { { LoopbackIPCPortAsNumber  >> 8, LoopbackIPCPortAsNumber  & 0xFF } };
+
 mDNSexport const mDNSv4Addr AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
 mDNSexport const mDNSv4Addr AllDNSLinkGroupv4  = { { 224,   0,   0, 251 } };
 mDNSexport const mDNSv6Addr AllDNSLinkGroupv6  = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } };
 mDNSexport const mDNSAddr   AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
 mDNSexport const mDNSAddr   AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
 
-mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
-mDNSexport const mDNSOpaque16 QueryFlags    = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
-mDNSexport const mDNSOpaque16 uQueryFlags   = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
-mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
-mDNSexport const mDNSOpaque16 UpdateReqFlags= { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
-mDNSexport const mDNSOpaque16 UpdateRespFlags={ { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
+mDNSexport const mDNSOpaque16 zeroID          = { { 0, 0 } };
+mDNSexport const mDNSOpaque16 QueryFlags      = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
+mDNSexport const mDNSOpaque16 uQueryFlags     = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
+mDNSexport const mDNSOpaque16 ResponseFlags   = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
+mDNSexport const mDNSOpaque16 UpdateReqFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
+mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
 
 // Any records bigger than this are considered 'large' records
 #define SmallRecordLimit 1024
@@ -3121,7 +3168,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        numDereg++;
                                        responseptr = newptr;
                                        }
-                               else if (rr->NewRData)                                                  // If we have new data for this record
+                               else if (rr->NewRData && !m->SleepState)                                        // If we have new data for this record
                                        {
                                        RData *OldRData     = rr->resrec.rdata;
                                        mDNSu16 oldrdlength = rr->resrec.rdlength;
@@ -3132,6 +3179,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                                if (!newptr && m->omsg.h.numAnswers) break;
                                                numDereg++;
                                                responseptr = newptr;
+                                               rr->RequireGoodbye = mDNSfalse;
                                                }
                                        // Now try to see if we can fit the update in the same packet (not fatal if we can't)
                                        SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
@@ -3139,7 +3187,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                                rr->resrec.rrclass |= kDNSClass_UniqueRRSet;            // Temporarily set the cache flush bit so PutResourceRecord will set it
                                        newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
                                        rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
-                                       if (newptr) responseptr = newptr;
+                                       if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
                                        SetNewRData(&rr->resrec, OldRData, oldrdlength);
                                        }
                                else
@@ -3281,10 +3329,11 @@ mDNSlocal void SendResponses(mDNS *const m)
 
 // Note: MUST call SetNextCacheCheckTime any time we change:
 // rr->TimeRcvd
-// rr->DelayDelivery
 // rr->resrec.rroriginalttl
 // rr->UnansweredQueries
 // rr->CRActiveQuestion
+// Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
+// Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
 mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
        {
        rr->NextRequiredQuery = RRExpireTime(rr);
@@ -3367,7 +3416,8 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                                rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&      // which is not already in the known answer list
                                rr->resrec.rdlength <= SmallRecordLimit &&                                      // which is small enough to sensibly fit in the packet
                                ResourceRecordAnswersQuestion(&rr->resrec, q) &&                        // which answers our question
-                               rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0)                        // and it is less than half-way to expiry
+                               rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >                            // and its half-way-to-expiry time is at least 1 second away
+                                                                                               mDNSPlatformOneSecond)          // (also ensures we never include goodbye records with TTL=1)
                                {
                                *ka = rr;       // Link this record into our known answer chain
                                ka = &rr->NextInKAList;
@@ -3867,7 +3917,7 @@ mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, C
 
 mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
        {
-       rr->DelayDelivery = 0;
+       rr->DelayDelivery = 0;          // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
        if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set");
        m->CurrentQuestion = m->Questions;
        while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
@@ -3892,7 +3942,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
                        if (threshhold - RRExpireTime(rr) >= 0)         // If we have records about to expire within a second
                                if (delay - RRExpireTime(rr) < 0)               // then delay until after they've been deleted
                                        delay = RRExpireTime(rr);
-       if (delay - start > 0) return(delay ? delay : 1);       // Make sure we return non-zero if we want to delay
+       if (delay - start > 0) return(NonZeroTime(delay));
        else return(0);
        }
 
@@ -3950,6 +4000,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                        }
                }
        m->CurrentQuestion = mDNSNULL;
+       SetNextCacheCheckTime(m, rr);
        }
 
 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
@@ -3965,7 +4016,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
 mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
        {
        LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
-       if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set");
+       if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set");
        m->CurrentQuestion = m->Questions;
        while (m->CurrentQuestion)
                {
@@ -3996,7 +4047,7 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
                m->CurrentQuestion = q->next;
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
-                       verbosedebugf("CacheRecordRmv %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                       verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
                        if (q->CurrentAnswers == 0)
                                LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", q, q->qname.c, DNSTypeName(q->qtype));
                        else
@@ -4651,7 +4702,7 @@ mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt)
        if (*pktptr > *ourptr) return(-1);                                                              // Our data is numerically lower; We lost
        if (*pktptr < *ourptr) return(+1);                                                              // Packet data is numerically lower; We won
        
-       debugf("CompareRData: How did we get here?");
+       LogMsg("CompareRData ERROR: Invalid state");
        return(-1);
        }
 
@@ -4754,14 +4805,13 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
                                int result          = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
                                if (!result) result = (int)our->resrec.rrtype  - (int)m->rec.r.resrec.rrtype;
                                if (!result) result = CompareRData(our, &m->rec.r);
-                               switch (result)
+                               if (result > 0)
+                                       debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+                               else if (result < 0)
                                        {
-                                       case  1:        debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
-                                                               break;
-                                       case  0:        break;
-                                       case -1:        debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
-                                                               mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
-                                                               goto exit;
+                                       debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+                                       mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
+                                       goto exit;
                                        }
                                }
                        }
@@ -5251,8 +5301,14 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
        const mDNSInterfaceID InterfaceID)
        {
        int i;
-       const mDNSu8 *ptr = LocateAnswers(response, end);       // We ignore questions (if any) in a DNS response packet
-       CacheRecord *CacheFlushRecords = (CacheRecord*)1;       // "(CacheRecord*)1" is special (non-zero) end-of-list marker
+
+       // We ignore questions (if any) in a DNS response packet
+       const mDNSu8 *ptr = LocateAnswers(response, end);
+
+       // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
+       // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
+       // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
+       CacheRecord *CacheFlushRecords = (CacheRecord*)1;
        CacheRecord **cfp = &CacheFlushRecords;
 
        // All records in a DNS response packet are treated as equally valid statements of truth. If we want
@@ -5461,9 +5517,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event
                                        else
                                                rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
-                                       CacheRecordAdd(m, rr);
-                                       // MUST do this AFTER CacheRecordAdd(), because that's what sets CRActiveQuestion for us
-                                       SetNextCacheCheckTime(m, rr);
+                                       CacheRecordAdd(m, rr);  // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
                                        }
                                }
                        }
@@ -5484,33 +5538,38 @@ exit:
                r1->NextInCFList = mDNSNULL;
                for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
                        if (SameResourceRecordSignature(&r1->resrec, &r2->resrec))
-                               {
-                               // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
-                               // else, if record is old, mark it to be flushed
-                               if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
-                                       r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
-                               else
+                               if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
                                        {
-                                       verbosedebugf("Cache flush %p X %p %##s (%s)", r1, r2, r2->resrec.name->c, DNSTypeName(r2->resrec.rrtype));
-                                       // We set stale records to expire in one second.
-                                       // This gives the owner a chance to rescue it if necessary.
-                                       // This is important in the case of multi-homing and bridged networks:
-                                       //   Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
-                                       //   bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
-                                       //   set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
-                                       //   will promptly delete their cached copies of the (still valid) Ethernet IP address record.
-                                       //   By delaying the deletion by one second, we give X a change to notice that this bridging has
-                                       //   happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
-                                       // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
-                                       // final expiration queries for this record.
-                                       r2->resrec.rroriginalttl = 1;
-                                       r2->TimeRcvd          = m->timenow;
-                                       r2->UnansweredQueries = MaxUnansweredQueries;
+                                       // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
+                                       // else, if record is old, mark it to be flushed
+                                       if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
+                                               {
+                                               if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
+                                                       r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
+                                               }
+                                       else                            // else, if record is old, mark it to be flushed
+                                               {
+                                               verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
+                                               // We set stale records to expire in one second.
+                                               // This gives the owner a chance to rescue it if necessary.
+                                               // This is important in the case of multi-homing and bridged networks:
+                                               //   Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
+                                               //   bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
+                                               //   set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
+                                               //   will promptly delete their cached copies of the (still valid) Ethernet IP address record.
+                                               //   By delaying the deletion by one second, we give X a change to notice that this bridging has
+                                               //   happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
+                                               // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
+                                               // final expiration queries for this record.
+                                               r2->resrec.rroriginalttl = 1;
+                                               r2->UnansweredQueries = MaxUnansweredQueries;
+                                               }
+                                       r2->TimeRcvd = m->timenow;
                                        SetNextCacheCheckTime(m, r2);
                                        }
-                               }
                if (r1->DelayDelivery)  // If we were planning to delay delivery of this record, see if we still need to
                        {
+                       // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
                        r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
                        if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
                        }
@@ -5529,9 +5588,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
        const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
 
 #ifndef UNICAST_DISABLED       
-       mDNSIPPort NATPort = mDNSOpaque16fromIntVal(NATMAP_PORT);
-
-       if (srcport.NotAnInteger == NATPort.NotAnInteger)
+       if (srcport.NotAnInteger == NATPMPPort.NotAnInteger)
                {
                mDNS_Lock(m);
                uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
index e2d402d518de18b7f4e5b6a54c5a6b13fa95ba8a..3113ff10227468f1fb7ee8df3353c4bcf03dec91 100755 (executable)
@@ -119,7 +119,7 @@ Revision 1.269  2005/01/11 22:50:52  ksekar
 Fixed constant naming (was using kLLQ_DefLease for update leases)
 
 Revision 1.268  2004/12/22 22:25:47  ksekar
-<rdar://problem/3734265> NATPMP: handle location changes
+<rdar://problem/3734265> NAT-PMP: handle location changes
 
 Revision 1.267  2004/12/22 00:13:49  ksekar
 <rdar://problem/3873993> Change version, port, and polling interval for LLQ
@@ -403,13 +403,13 @@ Revision 1.182  2004/07/30 17:40:06  ksekar
 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
 
 Revision 1.181  2004/07/29 19:27:15  ksekar
-NATPMP Support - minor fixes and cleanup
+NAT-PMP Support - minor fixes and cleanup
 
 Revision 1.180  2004/07/29 02:03:35  ksekar
 Delete unused #define and structure field
 
 Revision 1.179  2004/07/26 22:49:30  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
 
 Revision 1.178  2004/07/13 21:24:24  rpantos
 Fix for <rdar://problem/3701120>.
index c129f9d07146dcf386819a8c4fe9e7de852b9e52..6e2d70e023da4a97a9c5e8f2e4b17965a76640f4 100755 (executable)
@@ -211,7 +211,7 @@ Revision 1.168  2004/12/23 23:22:47  ksekar
 <rdar://problem/3933606> Unicast known answers "name" pointers point to garbage stack memory
 
 Revision 1.167  2004/12/22 22:25:47  ksekar
-<rdar://problem/3734265> NATPMP: handle location changes
+<rdar://problem/3734265> NAT-PMP: handle location changes
 
 Revision 1.166  2004/12/22 00:04:12  ksekar
 <rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply
@@ -558,16 +558,16 @@ Revision 1.61  2004/07/30 17:40:06  ksekar
 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
 
 Revision 1.60  2004/07/29 19:40:05  ksekar
-NATPMP Support - minor fixes and cleanup
+NAT-PMP Support - minor fixes and cleanup
 
 Revision 1.59  2004/07/29 19:27:15  ksekar
-NATPMP Support - minor fixes and cleanup
+NAT-PMP Support - minor fixes and cleanup
 
 Revision 1.58  2004/07/27 07:35:38  shersche
 fix syntax error, variables declared in the middle of a block
 
 Revision 1.57  2004/07/26 22:49:30  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
 
 Revision 1.56  2004/07/26 19:14:44  ksekar
 <rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
index 6d86705370e358c537ae86cb5b44a24f73c057bc..76943f753aafb0d8b7988aea8d21921a849ce21e 100755 (executable)
@@ -83,13 +83,13 @@ Revision 1.15  2004/07/30 17:40:06  ksekar
 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
 
 Revision 1.14  2004/07/29 19:27:15  ksekar
-NATPMP Support - minor fixes and cleanup
+NAT-PMP Support - minor fixes and cleanup
 
 Revision 1.13  2004/07/29 02:03:35  ksekar
 Delete unused #define and structure field
 
 Revision 1.12  2004/07/26 22:49:30  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
 
 Revision 1.11  2004/06/17 01:13:11  ksekar
 <rdar://problem/3696616>: polling interval too short
index 0dbbe5e397923bf2816c8d89cbcca27b2ee5d9f6..13cf72ee169e6ba4f09bb60f64725ff105b9a872 100644 (file)
@@ -74,7 +74,7 @@ Convert ServiceRegDomain to domainname instead of C string
 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
 
 Revision 1.30  2004/07/29 19:26:03  ksekar
-Plaform-level changes for NATPMP support
+Plaform-level changes for NAT-PMP support
 
 Revision 1.29  2004/05/26 20:53:16  cheshire
 Remove unncecessary "return( -1 );" at the end of mDNSPlatformUTC()
index b67eca908402c67066097476fabb04df466aea05..5b9ab354a04cf3b88f60b50a6831a158665ed6ae 100644 (file)
     Change History (most recent first):
 
 $Log: mDNSMacOSX.c,v $
+Revision 1.318.2.2  2006/12/14 21:38:51  cheshire
+Fix problem exposed by previous changes: kSecAccountItemAttr is not necessarily nul-terminated
+
+Revision 1.318.2.1  2006/10/31 02:37:04  cheshire
+<rdar://problem/4779534> Stop creating HINFO records
+
 Revision 1.318  2005/10/20 00:10:34  cheshire
 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
 
@@ -536,10 +542,10 @@ Revision 1.161  2004/08/11 00:17:46  ksekar
 set default bit for their domains
 
 Revision 1.160  2004/07/29 19:27:16  ksekar
-NATPMP Support - minor fixes and cleanup
+NAT-PMP Support - minor fixes and cleanup
 
 Revision 1.159  2004/07/26 22:49:31  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
 
 Revision 1.158  2004/07/13 21:24:24  rpantos
 Fix for <rdar://problem/3701120>.
@@ -966,6 +972,12 @@ Minor code tidying
 // including ones that mDNSResponder chooses not to use.
 #define LIST_ALL_INTERFACES 0
 
+// For debugging, being able to identify software versions is useful.
+// Some people are concerned that this information could be exploited by hackers.
+// I'm not totally convinced by that argument, but we don't want to cause our users distress,
+// so for shipping code, define "NO_HINFO" to suppress the generation of HINFO records. -- SC
+#define NO_HINFO 1
+
 // For enabling AAAA records over IPv4. Setting this to 0 sends only
 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
 // AAAA and A records over both IPv4 and IPv6.
@@ -2934,7 +2946,8 @@ mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain)
                                if (attr.tag == kSecAccountItemAttr)
                                        {
                                        if (!attr.length || attr.length > MAX_ESCAPED_DOMAIN_NAME) { LogMsg("SetSecretForDomain - Bad key length %d", attr.length); goto cleanup; }                                     
-                                       strncpy(keybuf, attr.data, attr.length);
+                                       memcpy(keybuf, attr.data, attr.length);
+                                       keybuf[attr.length] = 0;
                                        if (!MakeDomainNameFromDNSNameString(&keyname, keybuf)) { LogMsg("SetSecretForDomain - bad key %s", keybuf); goto cleanup; }
                                        debugf("Setting shared secret for zone %s with key %##s", dstring, keyname.c);
                                        mDNS_SetSecretForZone(m, d, &keyname, secret);
@@ -3517,6 +3530,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
        if (mDNSPlatformInit_CanReceiveUnicast())            m->CanReceiveUnicastOn5353 = mDNStrue;
 
+#ifndef NO_HINFO
        mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
        mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
        if (hlen + slen < 254)
@@ -3526,6 +3540,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
                mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen);
                mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen);
                }
+#endif /* NO_HINFO */
 
        m->p->unicastsockets.m     = m;
        m->p->unicastsockets.info  = NULL;
index 5290bf7209a28fc93fb1a7bfc86dd18111e85efe..ec5670adb7020590fd343b06b37ac0596f5b0782 100755 (executable)
@@ -121,7 +121,7 @@ Revision 1.50  2004/08/11 01:20:20  cheshire
 Declare private local functions using "mDNSlocal"
 
 Revision 1.49  2004/07/26 22:49:31  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
 
 Revision 1.48  2004/07/20 01:47:36  rpantos
 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 86ea29473de870c008cfd0000a752463055c50fd..3a0842f5bc0e4cc1abb1f070d1173ff0e341af5f 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
     Change History (most recent first):
 
 $Log: uds_daemon.c,v $
+Revision 1.199.2.1  2007/01/06 03:22:03  cheshire
+<rdar://problem/4912058> Crash at resolve_result_callback + 192
+
+Revision 1.199  2006/06/28 08:53:39  cheshire
+Added (commented out) debugging messages
+
+Revision 1.198  2006/06/27 20:16:07  cheshire
+Fix code layout
+
+Revision 1.197  2006/05/18 01:32:35  cheshire
+<rdar://problem/4472706> iChat: Lost connection with Bonjour
+(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
+
+Revision 1.196  2006/05/05 07:07:13  cheshire
+<rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
+
+Revision 1.195  2006/04/25 20:56:28  mkrochma
+Added comment about previous checkin
+
+Revision 1.194  2006/04/25 18:29:36  mkrochma
+Workaround for warning: unused variable 'status' when building mDNSPosix
+
+Revision 1.193  2006/03/19 17:14:38  cheshire
+<rdar://problem/4483117> Need faster purging of stale records
+read_rr_from_ipc_msg was not setting namehash and rdatahash
+
+Revision 1.192  2006/03/18 20:58:32  cheshire
+Misplaced curly brace
+
+Revision 1.191  2006/03/10 22:19:43  cheshire
+Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
+
+Revision 1.190  2006/03/10 21:56:12  cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
+when the TXT data changes, and then immediately afterwards a second callback with the new port number
+This change suppresses the first unneccessary (and confusing) callback
+
+Revision 1.189  2006/01/06 00:56:31  cheshire
+<rdar://problem/4400573> Should remove PID file on exit
+
+Revision 1.188  2005/10/11 22:15:03  cheshire
+<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
+Only compile uds_validatelists() when building for Mac OS X
+
+Revision 1.187  2005/10/11 20:30:27  cheshire
+<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
+
+Revision 1.186  2005/09/12 07:11:53  herscher
+<rdar://problem/4248878> Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms.
+
+Revision 1.185  2005/07/29 00:55:10  ksekar
+Removed validation check in uds_validatelists which generated false alarms
+
+Revision 1.184  2005/07/04 22:40:26  cheshire
+Additional debugging code to help catch memory corruption
+
 Revision 1.183  2005/06/13 22:39:11  cheshire
 <rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
 
@@ -590,9 +647,10 @@ Update to APSL 2.0
 
 #if defined(_WIN32)
 #include <process.h>
+#define MDNS_LAZY_REGISTER_SEARCH_DOMAINS
 #define dnssd_strerror(X)      win32_strerror(X)
 #define usleep(X)                              Sleep(((X)+999)/1000)
-static char * win32_strerror(int inErrorCode);
+static char *  win32_strerror(int inErrorCode);
 #else
 #include <fcntl.h>
 #include <errno.h>
@@ -619,6 +677,10 @@ static char * win32_strerror(int inErrorCode);
 #endif // LOCAL_PEERCRED
 #endif //__MACOSX__
 
+#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
+extern mStatus dDNS_RegisterSearchDomains( mDNS * const m );
+#endif
+
 // Types and Data Structures
 // ----------------------------------------------------------------------
 
@@ -790,8 +852,7 @@ typedef struct
     // const ResourceRecord *srv;
     mDNSBool   srv;
     mDNSBool   txt;
-    domainname target;
-    mDNSIPPort port;
+    rdataSRV   srvdata;
     mDNSu16    txtlen;
     mDNSu8     txtdata[AbsoluteMaxDNSMessageData];
     } resolve_termination_t;
@@ -819,53 +880,50 @@ static request_state      *       all_requests    =       NULL;
 #define MSG_PAD_BYTES 5                              // pad message buffer (read from client) with n zero'd bytes to guarantee
                                                      // n get_string() calls w/o buffer overrun
 // private function prototypes
-static void connect_callback(void *info);
-static int read_msg(request_state *rs);
-static int send_msg(reply_state *rs);
-static void abort_request(request_state *rs);
-static void request_callback(void *info);
-static void handle_resolve_request(request_state *rstate);
-static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void question_termination_callback(void *context);
-static void handle_browse_request(request_state *request);
-static void browse_termination_callback(void *context);
-static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void handle_regservice_request(request_state *request);
-static void regservice_termination_callback(void *context);
-static void process_service_registration(ServiceRecordSet *const srs, mDNSBool SuppressError);
-static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-static mStatus handle_add_request(request_state *rstate);
-static mStatus handle_update_request(request_state *rstate);
-static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep);
-static void append_reply(request_state *req, reply_state *rep);
-static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
-static void enum_termination_callback(void *context);
-static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void handle_query_request(request_state *rstate);
-static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
-static void handle_enum_request(request_state *rstate);
-static mStatus handle_regrecord_request(request_state *rstate);
-static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
-static void connected_registration_termination(void *context);
-static void handle_reconfirm_request(request_state *rstate);
-static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
-static mStatus handle_removerecord_request(request_state *rstate);
-static void reset_connected_rstate(request_state *rstate);
-static int deliver_error(request_state *rstate, mStatus err);
-static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
-static transfer_state send_undelivered_error(request_state *rs);
-static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
-static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
-static void my_perror(char *errmsg);
-static void unlink_request(request_state *rs);
-static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void resolve_termination_callback(void *context);
-static int validate_message(request_state *rstate);
-static mStatus remove_extra(request_state *rstate, service_instance *serv);
-static mStatus remove_record(request_state *rstate);
-static void free_service_instance(service_instance *srv);
-static uint32_t dnssd_htonl(uint32_t l);
-static void handle_setdomain_request(request_state *rstate);
+mDNSlocal void connect_callback(void *info);
+mDNSlocal int read_msg(request_state *rs);
+mDNSlocal int send_msg(reply_state *rs);
+mDNSlocal void abort_request(request_state *rs);
+mDNSlocal void request_callback(void *info);
+mDNSlocal void handle_resolve_request(request_state *rstate);
+mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+mDNSlocal void question_termination_callback(void *context);
+mDNSlocal void handle_browse_request(request_state *request);
+mDNSlocal void browse_termination_callback(void *context);
+mDNSlocal void handle_regservice_request(request_state *request);
+mDNSlocal void regservice_termination_callback(void *context);
+mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
+mDNSlocal mStatus handle_add_request(request_state *rstate);
+mDNSlocal mStatus handle_update_request(request_state *rstate);
+mDNSlocal void append_reply(request_state *req, reply_state *rep);
+mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
+mDNSlocal void enum_termination_callback(void *context);
+mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+mDNSlocal void handle_query_request(request_state *rstate);
+mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
+mDNSlocal void handle_enum_request(request_state *rstate);
+mDNSlocal mStatus handle_regrecord_request(request_state *rstate);
+mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
+mDNSlocal void connected_registration_termination(void *context);
+mDNSlocal void handle_reconfirm_request(request_state *rstate);
+mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
+mDNSlocal mStatus handle_removerecord_request(request_state *rstate);
+mDNSlocal void reset_connected_rstate(request_state *rstate);
+mDNSlocal int deliver_error(request_state *rstate, mStatus err);
+mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
+mDNSlocal transfer_state send_undelivered_error(request_state *rs);
+mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
+mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
+mDNSlocal void my_perror(char *errmsg);
+mDNSlocal void unlink_request(request_state *rs);
+mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+mDNSlocal void resolve_termination_callback(void *context);
+mDNSlocal int validate_message(request_state *rstate);
+mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv);
+mDNSlocal mStatus remove_record(request_state *rstate);
+mDNSlocal void free_service_instance(service_instance *srv);
+mDNSlocal uint32_t dnssd_htonl(uint32_t l);
+mDNSlocal void handle_setdomain_request(request_state *rstate);
 
 // initialization, setup/teardown functions
 
@@ -900,7 +958,7 @@ mDNSlocal void LogClientInfo(request_state *req)
                }
        }
 
-static void FatalError(char *errmsg)
+mDNSlocal void FatalError(char *errmsg)
        {
        LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
        *(long*)0 = 0;  // On OS X abort() doesn't generate a crash log, but writing to zero does
@@ -1037,6 +1095,8 @@ int udsserver_exit(void)
                debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
 #endif
 
+       if (PID_FILE[0]) unlink(PID_FILE);
+
     return 0;
     }
 
@@ -1088,7 +1148,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
                        else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;  // try again in a second
                        }
         if (result == t_terminated || result == t_error)
-        //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
+        //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
             {
             tmp = req;
             if (prev) prev->next = req->next;
@@ -1105,7 +1165,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
     return nextevent;
     }
 
-void udsserver_info(mDNS *const m)
+mDNSexport void udsserver_info(mDNS *const m)
     {
        mDNSs32 now = mDNS_TimeNow(m);
        mDNSu32 CacheUsed = 0, CacheActive = 0;
@@ -1116,6 +1176,7 @@ void udsserver_info(mDNS *const m)
 
     LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
 
+    LogMsgNoIdent("Slt Q   TTL U Type  if     len rdata");
        for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
                for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
                        {
@@ -1125,10 +1186,14 @@ void udsserver_info(mDNS *const m)
                                mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
                                CacheUsed++;
                                if (rr->CRActiveQuestion) CacheActive++;
-                               LogMsgNoIdent("%s%6ld %s%-6s%-6s%s",
-                                       rr->CRActiveQuestion ? "*" : " ", remain,
-                                       (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ", DNSTypeName(rr->resrec.rrtype),
-                                       ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname, CRDisplayString(m, rr));
+                               LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
+                                       slot,
+                                       rr->CRActiveQuestion ? "*" : " ",
+                                       remain,
+                                       (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ",
+                                       DNSTypeName(rr->resrec.rrtype),
+                                       ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname,
+                                       CRDisplayString(m, rr));
                                usleep(1000);   // Limit rate a little so we don't flood syslog too fast
                                }
                        }
@@ -1146,7 +1211,17 @@ void udsserver_info(mDNS *const m)
     LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
     }
 
-static void rename_service(service_instance *srv)
+#if __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING
+mDNSexport void uds_validatelists(void)
+       {
+       request_state *req;
+       for (req = all_requests; req; req=req->next)
+               if (req->sd < 0 && req->sd != -2)
+                       LogMemCorruption("UDS request list: %p is garbage (%X)", req, req->sd);
+       }
+#endif
+
+mDNSlocal void rename_service(service_instance *srv)
        {
        if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
                {
@@ -1156,11 +1231,10 @@ static void rename_service(service_instance *srv)
                }
        }
 
-void udsserver_handle_configchange(void)
+mDNSexport void udsserver_handle_configchange(void)
     {
     request_state *req;
 
-    
     for (req = all_requests; req; req = req->next)
         {
                if (req->service_registration)
@@ -1172,7 +1246,7 @@ void udsserver_handle_configchange(void)
                }
     }
 
-static void connect_callback(void *info)
+mDNSlocal void connect_callback(void *info)
     {
     dnssd_sock_t sd;
        dnssd_socklen_t len;
@@ -1229,7 +1303,7 @@ static void connect_callback(void *info)
     }
 
 // handler
-static void request_callback(void *info)
+mDNSlocal void request_callback(void *info)
        {
        request_state *rstate = info;
        transfer_state result;
@@ -1299,6 +1373,8 @@ static void request_callback(void *info)
                        return;
                        }
 
+               //LogOperation("request_callback: Opened dedicated errfd %d", errfd);
+
                #if defined(USE_TCP_LOOPBACK)
                        {
                        mDNSOpaque16 port;
@@ -1318,8 +1394,10 @@ static void request_callback(void *info)
                        strcpy(cliaddr.sun_path, ctrl_path);
                        }
                #endif
+               //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
                if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
                        {
+                       //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
                        my_perror("ERROR: connect");
                        abort_request(rstate);
                        unlink_request(rstate);
@@ -1346,6 +1424,7 @@ static void request_callback(void *info)
                        default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
                        }
 
+               //LogOperation("request_callback: Returning error code %d on socket %d", err, errfd);
                err = dnssd_htonl(err);
                nwritten = send(errfd, (dnssd_sockbuf_t) &err, sizeof(err), 0);
                // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
@@ -1353,7 +1432,9 @@ static void request_callback(void *info)
                if (nwritten < (int)sizeof(err))
                        LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
                                nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+               //else LogOperation("request_callback: Returned  error code %d on socket %d", err, errfd);
                dnssd_close(errfd);
+               //LogOperation("request_callback: Closed errfd %d", errfd);
                reset_connected_rstate(rstate);         // Reset ready to accept the next request on this pipe
                }
        else
@@ -1381,7 +1462,7 @@ static void request_callback(void *info)
 // massage the name parameters appropriately, but the rest of the operations (making the query call,
 // delivering the result to the client, and termination) are identical.
 
-static void handle_query_request(request_state *rstate)
+mDNSlocal void handle_query_request(request_state *rstate)
     {
     DNSServiceFlags flags;
     uint32_t ifi;
@@ -1447,7 +1528,7 @@ error:
     return;
     }
 
-static void handle_resolve_request(request_state *rstate)
+mDNSlocal void handle_resolve_request(request_state *rstate)
     {
     DNSServiceFlags flags;
     uint32_t interfaceIndex;
@@ -1547,7 +1628,7 @@ bad_param:
     unlink_request(rstate);
     }
     
-static void resolve_termination_callback(void *context)
+mDNSlocal void resolve_termination_callback(void *context)
     {
     resolve_termination_t *term = context;
     request_state *rs;
@@ -1567,8 +1648,8 @@ static void resolve_termination_callback(void *context)
     rs->termination_context = NULL;
     }
 
-static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-{
+mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
     size_t len = 0;
     char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
     char *data;
@@ -1578,7 +1659,8 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     resolve_termination_t *res = rs->termination_context;
     (void)m; // Unused
 
-       LogOperation("%3d: DNSServiceResolve(%##s, %s) RESULT %s", rs->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
+       LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
+               rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
     
     // This code used to do this trick of just keeping a copy of the pointer to
     // the answer record in the cache, but the unicast query code doesn't currently
@@ -1586,20 +1668,32 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     
        if (!AddRecord)
                {
-               // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
+               // After unicast query code is updated to store its records in the common cache, use this...
                // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
+               // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
+               // intead of this...
+               if (answer->rrtype == kDNSType_SRV && res->srv &&                                    SameRDataBody(answer, (RDataBody *)&res->srvdata))
+                       res->srv = mDNSfalse;
+               if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
+                       res->txt = mDNSfalse;
                return;
                }
 
-    // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
+       // After unicast query code is updated to store its records in the common cache, use this...
     // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
-
+    // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
+       // intead of this...
     if (answer->rrtype == kDNSType_SRV)
-       {
-       AssignDomainName(&res->target, &answer->rdata->u.srv.target);
-       res->port = answer->rdata->u.srv.port;
-       res->srv = mDNStrue;
-       }
+               {
+               // Don't copy structure in its entirety, because the CacheEntity may be an intentionally truncated object
+               // (to economize on space) and reading past the end may run into unmapped memory, causing a crash.
+               //res->srvdata = answer->rdata->u.srv;
+               // The AssignDomainName() macro is smart enough to only copy the valid part of the name, and not
+               // try to copy the full 255 bytes which may not all be there.
+               AssignDomainName(&res->srvdata.target, &answer->rdata->u.srv.target);
+               res->srvdata.port = answer->rdata->u.srv.port;
+               res->srv = mDNStrue;
+               }
     if (answer->rrtype == kDNSType_TXT)
        {
        if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
@@ -1611,7 +1705,7 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     if (!res->txt || !res->srv) return;                // only deliver result to client if we have both answers
     
     ConvertDomainNameToCString(answer->name, fullname);
-    ConvertDomainNameToCString(&res->target, target);
+    ConvertDomainNameToCString(&res->srvdata.target, target);
 
     // calculate reply length
     len += sizeof(DNSServiceFlags);
@@ -1633,8 +1727,8 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     // write reply data to message
     put_string(fullname, &data);
     put_string(target, &data);
-       *data++ = res->port.b[0];
-       *data++ = res->port.b[1];
+       *data++ = res->srvdata.port.b[0];
+       *data++ = res->srvdata.port.b[1];
     put_short(res->txtlen, &data);
     put_rdata(res->txtlen, res->txtdata, &data);
     
@@ -1650,7 +1744,7 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     }
 
 // what gets called when a resolve is completed and we need to send the data back to the client
-static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
     {
     char *data;
     char name[MAX_ESCAPED_DOMAIN_NAME];
@@ -1674,7 +1768,7 @@ static void question_result_callback(mDNS *const m, DNSQuestion *question, const
     rep =  create_reply(query_reply, len, req);
 
     rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
-    rep->rhdr->ifi  dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
+    rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
     rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
 
     data = rep->sdata;
@@ -1690,7 +1784,7 @@ static void question_result_callback(mDNS *const m, DNSQuestion *question, const
     return;
     }
 
-static void question_termination_callback(void *context)
+mDNSlocal void question_termination_callback(void *context)
     {
     DNSQuestion *q = context;
        LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
@@ -1701,7 +1795,7 @@ static void question_termination_callback(void *context)
 // If there's a comma followed by another character,
 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
 // Otherwise, it returns a pointer to the final nul at the end of the string
-static char *FindFirstSubType(char *p)
+mDNSlocal char *FindFirstSubType(char *p)
        {
        while (*p)
                {
@@ -1716,7 +1810,7 @@ static char *FindFirstSubType(char *p)
 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
 // Otherwise, it returns a pointer to the final nul at the end of the string
-static char *FindNextSubType(char *p)
+mDNSlocal char *FindNextSubType(char *p)
        {
        while (*p)
                {
@@ -1770,14 +1864,14 @@ mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
        }
 
 #ifdef _HAVE_SETDOMAIN_SUPPORT_
-static void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
+mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
        {
        (void)m;  // unused
        if (result == mStatus_MemFree) free(rr->RecordContext);  // context is the enclosing list structure
        }
 #endif
 
-static void handle_setdomain_request(request_state *request)
+mDNSlocal void handle_setdomain_request(request_state *request)
        {
        mStatus err = mStatus_NoError;
        char *ptr;
@@ -1866,11 +1960,80 @@ static void handle_setdomain_request(request_state *request)
     unlink_request(request);
     }
 
-static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
+// Generates a response message giving name, type, domain, plus interface index,
+// suitable for a browse result or service registration result.
+// On successful completion rep is set to point to a malloc'd reply_state struct
+mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
+       {
+       domainlabel name;
+       domainname type, dom;
+       *rep = NULL;
+       if (!DeconstructServiceName(servicename, &name, &type, &dom))
+               return kDNSServiceErr_Invalid;
+       else
+               {
+               char namestr[MAX_DOMAIN_LABEL+1];
+               char typestr[MAX_ESCAPED_DOMAIN_NAME];
+               char domstr [MAX_ESCAPED_DOMAIN_NAME];
+               int len;
+               char *data;
+       
+               ConvertDomainLabelToCString_unescaped(&name, namestr);
+               ConvertDomainNameToCString(&type, typestr);
+               ConvertDomainNameToCString(&dom, domstr);
+               
+               // Calculate reply data length
+               len = sizeof(DNSServiceFlags);
+               len += sizeof(uint32_t);  // if index
+               len += sizeof(DNSServiceErrorType);
+               len += (int) (strlen(namestr) + 1);
+               len += (int) (strlen(typestr) + 1);
+               len += (int) (strlen(domstr) + 1);
+               
+               // Build reply header
+               *rep = create_reply(query_reply, len, request);
+               (*rep)->rhdr->flags = dnssd_htonl(0);
+               (*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
+               (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
+               
+               // Build reply body
+               data = (*rep)->sdata;
+               put_string(namestr, &data);
+               put_string(typestr, &data);
+               put_string(domstr, &data);
+
+               return mStatus_NoError;
+               }
+       }
+
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
+       request_state *req = question->QuestionContext;
+       reply_state *rep;
+       (void)m; // Unused
+
+       if (answer->rrtype != kDNSType_PTR)
+               { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
+
+       if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError)
+               {
+               LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
+                       req->sd, answer->name->c, answer->rdata->u.name.c);
+               return;
+               }
+
+       LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
+               req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
+
+       if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);
+       append_reply(req, rep);
+       }
+
+mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
        {
        browser_t *b, *p;
        mStatus err;
-   
+
        for (p = info->browsers; p; p = p->next)
                {
                if (SameDomainName(&p->domain, d))
@@ -1880,7 +2043,7 @@ static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
        b = mallocL("browser_t", sizeof(*b));
        if (!b) return mStatus_NoMemoryErr;
        AssignDomainName(&b->domain, d);
-       err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, browse_result_callback, info->rstate);
+       err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
        if (err)
                {
                LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
@@ -1894,7 +2057,7 @@ static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
                return err;
        }
 
-static void handle_browse_request(request_state *request)
+mDNSlocal void handle_browse_request(request_state *request)
     {
     DNSServiceFlags flags;
     uint32_t interfaceIndex;
@@ -1928,6 +2091,13 @@ static void handle_browse_request(request_state *request)
     InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
     if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr;  goto error; }
 
+#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
+       if ( !domain || ( domain[0] == '\0' ) )
+               {
+               dDNS_RegisterSearchDomains( gmDNS );
+               }
+#endif
+               
        typedn.c[0] = 0;
        NumSubTypes = ChopSubTypes(regtype);    // Note: Modifies regtype string to remove trailing subtypes
        if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr;  goto error; }
@@ -1989,31 +2159,7 @@ error:
     unlink_request(request);
     }
 
-static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-    {
-    request_state *req = question->QuestionContext;
-    reply_state *rep;
-    mStatus err;
-    (void)m; // Unused
-       LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
-               req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
-
-    err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
-    if (err)
-        {
-        if (deliver_async_error(req, browse_reply, err) < 0)
-            {
-            abort_request(req);
-            unlink_request(req);
-            }
-        return;
-        }
-    if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);  // non-zero TTL indicates add
-    append_reply(req, rep);
-    return;
-    }
-
-static void browse_termination_callback(void *context)
+mDNSlocal void browse_termination_callback(void *context)
     {
        browser_info_t *info = context;
        browser_t *ptr;
@@ -2108,7 +2254,7 @@ mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
        return(count);
        }
 
-static mStatus register_service_instance(request_state *request, const domainname *domain)
+mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
        {
        service_info *info = request->service_registration;
        service_instance *ptr, *instance;
@@ -2193,7 +2339,7 @@ mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBo
        }
 
 // service registration
-static void handle_regservice_request(request_state *request)
+mDNSlocal void handle_regservice_request(request_state *request)
     {
     DNSServiceFlags flags;
     uint32_t ifi;
@@ -2246,7 +2392,7 @@ static void handle_regservice_request(request_state *request)
                if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
                memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
                }
-       else service->txtdata = NULL;              
+       else service->txtdata = NULL;
 
        // Check for sub-types after the service type
        service->num_subtypes = ChopSubTypes(service->type_as_string);  // Note: Modifies regtype string to remove trailing subtypes
@@ -2342,7 +2488,7 @@ bad_param:
 // handles name conflicts, and delivers completed registration information to the client (via
 // process_service_registraion())
 
-static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
+mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
     {
     mStatus err;
        mDNSBool SuppressError = mDNSfalse;
@@ -2356,7 +2502,7 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
                service_info *info = instance->request->service_registration;
                if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
         // don't send errors up to client for wide-area, empty-string registrations
-               }                       
+               }
        
     if (result == mStatus_NoError)
                LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED  ",  instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
@@ -2369,6 +2515,7 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
 
     if (result == mStatus_NoError)
                {
+               request_state *req = instance->request;
                if (instance->allowremotequery)
                        {
                        ExtraResourceRecord *e;
@@ -2378,7 +2525,22 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
                        srs->RR_TXT.AllowRemoteQuery = mDNStrue;
                        for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
                        }
-        process_service_registration(srs, SuppressError);
+        
+               if (!req) LogMsg("ERROR: regservice_callback - null request object");
+               else
+                       {
+                       reply_state *rep;
+                       if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
+                               LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
+                       else
+                               {
+                               transfer_state send_result = send_msg(rep);
+                               if (send_result == t_error || send_result == t_terminated)
+                                       { abort_request(req); unlink_request(req); freeL("reply_state", rep); }
+                               else if (send_result == t_complete) freeL("regservice_callback", rep);
+                               else append_reply(req, rep);
+                               }
+                       }
         if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
                RecordUpdatedNiceLabel(m, 0);   // Successfully got new name, tell user immediately
                return;
@@ -2453,7 +2615,7 @@ mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
        freeL("ExtraResourceRecord", extra);
        }
 
-static mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
+mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
        {
        ServiceRecordSet *srs = &instance->srs;
     ExtraResourceRecord *extra;
@@ -2483,7 +2645,7 @@ static mStatus add_record_to_service(request_state *rstate, service_instance *in
        return result;
        }
 
-static mStatus handle_add_request(request_state *rstate)
+mDNSlocal mStatus handle_add_request(request_state *rstate)
     {
     uint32_t ttl;
     uint16_t rrtype, rdlen;
@@ -2517,7 +2679,7 @@ static mStatus handle_add_request(request_state *rstate)
        return(result);
     }
 
-static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
+mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
        {
        int rdsize;
        RData *newrd;
@@ -2540,7 +2702,7 @@ static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32
        return result;
        }
 
-static mStatus handle_update_request(request_state *rstate)
+mDNSlocal mStatus handle_update_request(request_state *rstate)
     {
        uint16_t rdlen;
     char *ptr, *rdata;
@@ -2599,43 +2761,13 @@ end:
     return(result);
     }
     
-static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
+mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
     {
     (void)m; // Unused
     if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
     }
-    
-static void process_service_registration(ServiceRecordSet *const srs, mDNSBool SuppressError)
-    {
-    reply_state *rep;
-    transfer_state send_result;
-    mStatus err;
-    service_instance *instance = srs->ServiceContext;
-    request_state *req = instance->request;
-
-       if (!req) { LogMsg("ERROR: process_service_registration - null request object"); return; }
-    err = gen_rr_response(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
-    if (err)
-        {
-        if (SuppressError && deliver_async_error(req, reg_service_reply, err) < 0)
-            {
-            abort_request(req);
-            unlink_request(req);
-            }
-        return;
-        }
-    send_result = send_msg(rep);
-    if (send_result == t_error || send_result == t_terminated)
-        {
-        abort_request(req);
-        unlink_request(req);
-        freeL("process_service_registration", rep);
-        }
-    else if (send_result == t_complete) freeL("process_service_registration", rep);
-    else append_reply(req, rep);
-    }
 
-static void free_service_instance(service_instance *srv)
+mDNSlocal void free_service_instance(service_instance *srv)
        {
        request_state *rstate = srv->request;
        ExtraResourceRecord *e = srv->srs.Extras, *tmp;
@@ -2669,7 +2801,7 @@ static void free_service_instance(service_instance *srv)
        freeL("regservice_callback", srv);
        }
 
-static void regservice_termination_callback(void *context)
+mDNSlocal void regservice_termination_callback(void *context)
     {
        service_info *info = context;
        service_instance *i, *p;
@@ -2690,7 +2822,7 @@ static void regservice_termination_callback(void *context)
        freeL("service_info", info);
        }
 
-static mStatus handle_regrecord_request(request_state *rstate)
+mDNSlocal mStatus handle_regrecord_request(request_state *rstate)
     {
     AuthRecord *rr;
     registered_record_entry *re;
@@ -2733,7 +2865,7 @@ static mStatus handle_regrecord_request(request_state *rstate)
     return(result);
     }
 
-static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
+mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
     {
     registered_record_entry *re = rr->RecordContext;
        request_state *rstate = re ? re->rstate : NULL;
@@ -2785,7 +2917,7 @@ static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
     else if (ts == t_morecoming) append_reply(rstate, reply);   // client is blocked, link reply into list
        }
 
-static void connected_registration_termination(void *context)
+mDNSlocal void connected_registration_termination(void *context)
     {
     int shared;
     registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
@@ -2800,7 +2932,7 @@ static void connected_registration_termination(void *context)
                }
        }
     
-static mStatus handle_removerecord_request(request_state *rstate)
+mDNSlocal mStatus handle_removerecord_request(request_state *rstate)
     {
     mStatus err = mStatus_BadReferenceErr;
     char *ptr;
@@ -2828,7 +2960,7 @@ static mStatus handle_removerecord_request(request_state *rstate)
     }
 
 // remove a resource record registered via DNSServiceRegisterRecord()
-static mStatus remove_record(request_state *rstate)
+mDNSlocal mStatus remove_record(request_state *rstate)
     {
     int shared;
     mStatus err = mStatus_UnknownErr;
@@ -2852,7 +2984,7 @@ static mStatus remove_record(request_state *rstate)
        return err;
     }
 
-static mStatus remove_extra(request_state *rstate, service_instance *serv)
+mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv)
        {
        mStatus err = mStatus_BadReferenceErr;
        ExtraResourceRecord *ptr;
@@ -2866,7 +2998,7 @@ static mStatus remove_extra(request_state *rstate, service_instance *serv)
        }
 
 // domain enumeration
-static void handle_enum_request(request_state *rstate)
+mDNSlocal void handle_enum_request(request_state *rstate)
     {
     DNSServiceFlags flags;
     uint32_t ifi;
@@ -2902,6 +3034,10 @@ static void handle_enum_request(request_state *rstate)
     term = mallocL("handle_enum_request", sizeof(enum_termination_t));
     if (!def || !all || !term) FatalError("ERROR: malloc");
 
+#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
+       dDNS_RegisterSearchDomains( gmDNS );
+#endif
+               
     // enumeration requires multiple questions, so we must link all the context pointers so that
     // necessary context can be reached from the callbacks
     def->rstate = rstate;
@@ -2938,7 +3074,7 @@ static void handle_enum_request(request_state *rstate)
         }
     }
 
-static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
     {
     char domain[MAX_ESCAPED_DOMAIN_NAME];
     domain_enum_t *de = question->QuestionContext;
@@ -2954,7 +3090,7 @@ static void enum_result_callback(mDNS *const m, DNSQuestion *question, const Res
         flags |= kDNSServiceFlagsAdd;
         if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
             flags |= kDNSServiceFlagsDefault;
-       }       
+       }
     ConvertDomainNameToCString(&answer->rdata->u.name, domain);
        // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
        // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
@@ -2970,18 +3106,17 @@ static void enum_result_callback(mDNS *const m, DNSQuestion *question, const Res
     return;
     }
 
-static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
+mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
     {
     size_t len;
     reply_state *reply;
     char *data;
-    
-    
+
     len = sizeof(DNSServiceFlags);
     len += sizeof(uint32_t);
     len += sizeof(DNSServiceErrorType);
     len += strlen(domain) + 1;
-  
+
     reply = create_reply(enumeration_reply, len, rstate);
     reply->rhdr->flags = dnssd_htonl(flags);
     reply->rhdr->ifi = dnssd_htonl(ifi);
@@ -2991,7 +3126,7 @@ static reply_state *format_enumeration_reply(request_state *rstate, const char *
     return reply;
     }
 
-static void enum_termination_callback(void *context)
+mDNSlocal void enum_termination_callback(void *context)
     {
     enum_termination_t *t = context;
     mDNS *coredata = gmDNS;
@@ -3004,21 +3139,27 @@ static void enum_termination_callback(void *context)
     freeL("enum_termination_callback", t);
     }
 
-static void handle_reconfirm_request(request_state *rstate)
+mDNSlocal void handle_reconfirm_request(request_state *rstate)
     {
-    AuthRecord *rr;
-
-    rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 1);
-    if (!rr) return;
-       LogOperation("%3d: DNSServiceReconfirmRecord(%##s) %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
-    mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
-    abort_request(rstate);
-    unlink_request(rstate);
-    freeL("handle_reconfirm_request", rr);
-    }
+    AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0);
+    if (rr)
+               {
+               mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
+               LogOperation(
+                       (status == mStatus_NoError) ?
+                       "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
+                       "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
+                       rstate->sd, RRDisplayString(gmDNS, &rr->resrec),
+                       mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status);
+               status = 0;  // Adding this line eliminates a build failure when building mDNSPosix on Tiger
+               }
+       abort_request(rstate);
+       unlink_request(rstate);
+       freeL("handle_reconfirm_request", rr);
+       }
 
 // setup rstate to accept new reg/dereg requests
-static void reset_connected_rstate(request_state *rstate)
+mDNSlocal void reset_connected_rstate(request_state *rstate)
     {
     rstate->ts = t_morecoming;
     rstate->hdr_bytes = 0;
@@ -3031,7 +3172,7 @@ static void reset_connected_rstate(request_state *rstate)
 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
 // (ttl only extracted/set if ttl argument is non-zero).  returns NULL for a bad-parameter error
-static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
+mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
     {
     char *rdata, name[256];
     AuthRecord *rr;
@@ -3075,65 +3216,20 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_f
         freeL("read_rr_from_ipc_msg", rr);
         return NULL;
        }
+    
     if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery  = mDNStrue;
     rr->resrec.rrclass = class;
     rr->resrec.rdlength = rdlen;
     rr->resrec.rdata->MaxRDLength = rdlen;
     rdata = get_rdata(&msgbuf, rdlen);
     memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
-    if (GetTTL)
-       {
-        rr->resrec.rroriginalttl = get_long(&msgbuf);
-       }
+    if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf);
+    rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
+    SetNewRData(&rr->resrec, mDNSNULL, 0);     // Sets rr->rdatahash for us
     return rr;
     }
 
-// generate a response message for a browse result, service registration result, or any other call with the
-// identical callback signature.  on successful completion rep is set to point to a malloc'd reply_state struct,
-// and mStatus_NoError is returned.  otherwise the appropriate error is returned.
-
-static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
-    {
-    char *data;
-    int len;
-    domainlabel name;
-    domainname type, dom;
-       char namestr[MAX_DOMAIN_LABEL+1];               // Unescaped name: up to 63 bytes plus C-string terminating NULL.
-       char typestr[MAX_ESCAPED_DOMAIN_NAME];
-       char domstr [MAX_ESCAPED_DOMAIN_NAME];
-
-    *rep = NULL;
-    
-    if (!DeconstructServiceName(servicename, &name, &type, &dom))
-        return kDNSServiceErr_Unknown;
-
-    ConvertDomainLabelToCString_unescaped(&name, namestr);
-    ConvertDomainNameToCString(&type, typestr);
-    ConvertDomainNameToCString(&dom, domstr);
-
-    // calculate reply data length
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);  // if index
-    len += sizeof(DNSServiceErrorType);
-    len += (int) (strlen(namestr) + 1);
-    len += (int) (strlen(typestr) + 1);
-    len += (int) (strlen(domstr) + 1);
-    
-    *rep = create_reply(query_reply, len, request);
-
-    (*rep)->rhdr->flags = dnssd_htonl(0);
-    (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
-    (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
-
-    data = (*rep)->sdata;
-    
-    put_string(namestr, &data);
-    put_string(typestr, &data);
-    put_string(domstr, &data);
-    return mStatus_NoError;
-    }
-
-static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
+mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
     {
     domainlabel n;
     domainname d, t;
@@ -3146,7 +3242,7 @@ static int build_domainname_from_strings(domainname *srv, char *name, char *regt
     }
 
 // append a reply to the list in a request object
-static void append_reply(request_state *req, reply_state *rep)
+mDNSlocal void append_reply(request_state *req, reply_state *rep)
     {
     reply_state *ptr;
 
@@ -3163,7 +3259,7 @@ static void append_reply(request_state *req, reply_state *rep)
 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
 // returns the current state of the request (morecoming, error, complete, terminated.)
 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
-static int read_msg(request_state *rs)
+mDNSlocal int read_msg(request_state *rs)
     {
     uint32_t nleft;
     int nread;
@@ -3238,8 +3334,8 @@ static int read_msg(request_state *rs)
                 return t_error;
                }
             rs->msgdata = rs->msgbuf;
-            }
             bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
+            }
         nleft = rs->hdr.datalen - rs->data_bytes;
         nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
         if (nread == 0)        { rs->ts = t_terminated;  return t_terminated;  }
@@ -3266,7 +3362,7 @@ rerror:
     return t_error;
     }
 
-static int send_msg(reply_state *rs)
+mDNSlocal int send_msg(reply_state *rs)
     {
     ssize_t nwriten;
     
@@ -3318,12 +3414,11 @@ static int send_msg(reply_state *rs)
     return rs->ts;
     }
 
-static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
-{
+mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
+       {
     reply_state *reply;
     int totallen;
 
-    
     if ((unsigned)datalen < sizeof(reply_hdr))
         {
         LogMsg("ERROR: create_reply - data length less than lenght of required fields");
@@ -3350,7 +3445,7 @@ static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *r
     return reply;
     }
 
-static int deliver_error(request_state *rstate, mStatus err)
+mDNSlocal int deliver_error(request_state *rstate, mStatus err)
        {
        int nwritten = -1;
        undelivered_error_t *undeliv;
@@ -3382,7 +3477,7 @@ static int deliver_error(request_state *rstate, mStatus err)
        }
 
 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
-static transfer_state send_undelivered_error(request_state *rs)
+mDNSlocal transfer_state send_undelivered_error(request_state *rs)
        {
        int nwritten;
        
@@ -3410,7 +3505,7 @@ static transfer_state send_undelivered_error(request_state *rs)
 // send bogus data along with an error code to the app callback
 // returns 0 on success (linking reply into list of not fully delivered),
 // -1 on failure (request should be aborted)
-static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
+mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
     {
     int len;
     reply_state *reply;
@@ -3431,7 +3526,7 @@ static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
     return 0;
     }
 
-static void abort_request(request_state *rs)
+mDNSlocal void abort_request(request_state *rs)
     {
     reply_state *rep, *ptr;
 
@@ -3439,7 +3534,10 @@ static void abort_request(request_state *rs)
     if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
        LogOperation("%3d: Removing FD", rs->sd);
     udsSupportRemoveFDFromEventLoop(rs->sd);                                   // Note: This also closes file descriptor rs->sd for us
-    rs->sd = dnssd_InvalidSocket;
+
+       // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
+       // for detecting when the memory for an object is inadvertently freed while the object is still on some list
+    rs->sd = -2;
 
     // free pending replies
     rep = rs->replies;
@@ -3458,7 +3556,7 @@ static void abort_request(request_state *rs)
         }
     }
 
-static void unlink_request(request_state *rs)
+mDNSlocal void unlink_request(request_state *rs)
     {
     request_state *ptr;
     
@@ -3478,7 +3576,7 @@ static void unlink_request(request_state *rs)
     }
 
 //hack to search-replace perror's to LogMsg's
-static void my_perror(char *errmsg)
+mDNSlocal void my_perror(char *errmsg)
     {
     LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
     }
@@ -3487,7 +3585,7 @@ static void my_perror(char *errmsg)
 // without overrunning it.
 // returns 0 on success, -1 on error.
 
-static int validate_message(request_state *rstate)
+mDNSlocal int validate_message(request_state *rstate)
     {
     uint32_t min_size;
     
@@ -3546,7 +3644,7 @@ static int validate_message(request_state *rstate)
     
     }
 
-static uint32_t dnssd_htonl(uint32_t l)
+mDNSlocal uint32_t dnssd_htonl(uint32_t l)
        {
        uint32_t        ret;
        char    *       data;
@@ -3560,7 +3658,7 @@ static uint32_t dnssd_htonl(uint32_t l)
 
 #if defined(_WIN32)
 
-static char * win32_strerror(int inErrorCode)
+mDNSlocal char * win32_strerror(int inErrorCode)
        {
        static char buffer[1024];
        DWORD       n;
index d8c2824f792e850dbfb7e3aa5ac36db4ab2dcd51..3b2926acec4487b12bdbf7fd3ed1f4ee0a5cf6c5 100644 (file)
@@ -65,7 +65,7 @@ Convert ServiceRegDomain to domainname instead of C string
 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
 
 Revision 1.17  2004/07/29 19:26:03  ksekar
-Plaform-level changes for NATPMP support
+Plaform-level changes for NAT-PMP support
 
 Revision 1.16  2004/04/22 05:11:28  bradley
 Added mDNSPlatformUTC for TSIG signed dynamic updates.
index 93a14a71eb991e3888d4de3d788262f13fc590a0..50df66f09aacd5d3cd726483c21539c9fb2cd783 100755 (executable)
@@ -222,7 +222,7 @@ Revision 1.46  2004/08/05 05:43:01  shersche
 Bug #: 3751566
 
 Revision 1.45  2004/07/26 22:49:31  ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
 
 Revision 1.44  2004/07/26 05:42:50  shersche
 use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"