]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-170.tar.gz mac-os-x-1052 v170
authorApple <opensource@apple.com>
Sat, 5 Jan 2008 00:13:11 +0000 (00:13 +0000)
committerApple <opensource@apple.com>
Sat, 5 Jan 2008 00:13:11 +0000 (00:13 +0000)
34 files changed:
Clients/dns-sd.c
Makefile
mDNSCore/DNSCommon.c
mDNSCore/DNSCommon.h
mDNSCore/DNSDigest.c
mDNSCore/mDNS.c
mDNSCore/mDNSDebug.h
mDNSCore/mDNSEmbeddedAPI.h
mDNSCore/uDNS.c
mDNSCore/uDNS.h
mDNSMacOSX/LegacyNATTraversal.c
mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
mDNSMacOSX/PreferencePane/PrivilegedOperations.c
mDNSMacOSX/PreferencePane/ddnswriteconfig.m
mDNSMacOSX/SamplemDNSClient.c
mDNSMacOSX/daemon.c
mDNSMacOSX/helper-error.h
mDNSMacOSX/helper-stubs.c
mDNSMacOSX/helper.c
mDNSMacOSX/mDNSMacOSX.c
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
mDNSMacOSX/pfkey.c
mDNSPosix/mDNSUNP.c
mDNSShared/Java/JNISupport.c
mDNSShared/PlatformCommon.c
mDNSShared/dns_sd.h
mDNSShared/dnsextd.c
mDNSShared/dnssd_clientlib.c
mDNSShared/dnssd_clientshim.c
mDNSShared/dnssd_clientstub.c
mDNSShared/mDNSDebug.c
mDNSShared/uds_daemon.c
mDNSWindows/mDNSWin32.c

index 718547cdcceb32b76402b3c6ce17bcddd50bf692..e80ee39af09becf357e80b84f6a736dece4e2efe 100644 (file)
@@ -433,6 +433,7 @@ static void myTimerCallBack(void)
                        else                      updatetest[1] = 'A';
                        updatetest[0] = 3 - updatetest[0];
                        updatetest[2] = updatetest[1];
+                       printtimestamp();
                        printf("Updating Test TXT record to %c\n", updatetest[1]);
                        err = DNSServiceUpdateRecord(client, NULL, 0, 1+updatetest[0], &updatetest[0], 0);
                        }
@@ -689,19 +690,19 @@ static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptIn
        }
 #else
        {
-       int operation = getopt(argc, (char *const *)argv, optstr);
+       int o = getopt(argc, (char *const *)argv, optstr);
        *pOptInd = optind;
-       return operation;
+       return o;
        }
 #endif
 
-static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, const DNSServiceFlags flags,
+static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef rec, const DNSServiceFlags flags,
     DNSServiceErrorType errorCode, void *context)
        {
        char *name = (char *)context;
        
        (void)service;  // Unused
-       (void)record;   // Unused
+       (void)rec;      // Unused
        (void)flags;    // Unused
        
        printtimestamp();
@@ -714,7 +715,7 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR
                default:                          printf("Error %d\n", errorCode); break;
                }
        if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
-       // DNSServiceRemoveRecord(service, record, 0); to test record removal
+       // DNSServiceRemoveRecord(service, rec, 0); to test record removal
        }
 
 static unsigned long getip(const char *const name)
@@ -811,7 +812,7 @@ int main(int argc, char **argv)
        {
        DNSServiceErrorType err;
        char buffer[TypeBufferSize], *typ, *dom;
-       int optind;
+       int opi;
 
        // Extract the program name from argv[0], which by convention contains the path to this executable.
        // Note that this is just a voluntary convention, not enforced by the kernel --
@@ -852,7 +853,7 @@ int main(int argc, char **argv)
                                                                #if HAS_ADDRINFO_API
                                                                        "G"
                                                                #endif
-                                                               , &optind);
+                                                               , &opi);
        if (operation == -1) goto Fail;
 
        if (opinterface) printf("Using interface %d\n", opinterface);
@@ -871,38 +872,38 @@ int main(int argc, char **argv)
                                        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "dns-sd.ibm.com.", NULL);
                                        break;
 
-               case 'B':       typ = (argc < optind+1) ? "" : argv[optind+0];
-                                       dom = (argc < optind+2) ? "" : argv[optind+1];  // Missing domain argument is the same as empty string i.e. use system default(s)
+               case 'B':       typ = (argc < opi+1) ? "" : argv[opi+0];
+                                       dom = (argc < opi+2) ? "" : argv[opi+1];  // Missing domain argument is the same as empty string i.e. use system default(s)
                                        typ = gettype(buffer, typ);
                                        if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
                                        printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
                                        err = DNSServiceBrowse(&client, 0, opinterface, typ, dom, browse_reply, NULL);
                                        break;
 
-               case 'L':       if (argc < optind+2) goto Fail;
-                                       typ = (argc < optind+2) ? ""      : argv[optind+1];
-                                       dom = (argc < optind+3) ? "local" : argv[optind+2];
+               case 'L':       if (argc < opi+2) goto Fail;
+                                       typ = (argc < opi+2) ? ""      : argv[opi+1];
+                                       dom = (argc < opi+3) ? "local" : argv[opi+2];
                                        typ = gettype(buffer, typ);
                                        if (dom[0] == '.' && dom[1] == 0) dom = "local";   // We allow '.' on the command line as a synonym for "local"
-                                       printf("Lookup %s.%s.%s\n", argv[optind+0], typ, dom);
-                                       err = DNSServiceResolve(&client, 0, opinterface, argv[optind+0], typ, dom, (DNSServiceResolveReply)resolve_reply, NULL);
+                                       printf("Lookup %s.%s.%s\n", argv[opi+0], typ, dom);
+                                       err = DNSServiceResolve(&client, 0, opinterface, argv[opi+0], typ, dom, (DNSServiceResolveReply)resolve_reply, NULL);
                                        break;
 
-               case 'R':       if (argc < optind+4) goto Fail;
-                                       typ = (argc < optind+2) ? "" : argv[optind+1];
-                                       dom = (argc < optind+3) ? "" : argv[optind+2];
+               case 'R':       if (argc < opi+4) goto Fail;
+                                       typ = (argc < opi+2) ? "" : argv[opi+1];
+                                       dom = (argc < opi+3) ? "" : argv[opi+2];
                                        typ = gettype(buffer, typ);
                                        if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
-                                       err = RegisterService(&client, argv[optind+0], typ, dom, NULL, argv[optind+3], argc-(optind+4), argv+(optind+4));
+                                       err = RegisterService(&client, argv[opi+0], typ, dom, NULL, argv[opi+3], argc-(opi+4), argv+(opi+4));
                                        break;
 
-               case 'P':       if (argc < optind+6) goto Fail;
+               case 'P':       if (argc < opi+6) goto Fail;
                                        err = DNSServiceCreateConnection(&client_pa);
                                        if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
-                                       err = RegisterProxyAddressRecord(client_pa, argv[optind+4], argv[optind+5]);
-                                       //err = RegisterProxyAddressRecord(client_pa, "two", argv[optind+5]);
+                                       err = RegisterProxyAddressRecord(client_pa, argv[opi+4], argv[opi+5]);
+                                       //err = RegisterProxyAddressRecord(client_pa, "two", argv[opi+5]);
                                        if (err) break;
-                                       err = RegisterService(&client, argv[optind+0], argv[optind+1], argv[optind+2], argv[optind+4], argv[optind+3], argc-(optind+6), argv+(optind+6));
+                                       err = RegisterService(&client, argv[opi+0], argv[opi+1], argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6));
                                        //DNSServiceRemoveRecord(client_pa, record, 0);
                                        //DNSServiceRemoveRecord(client_pa, record, 0);
                                        break;
@@ -911,11 +912,11 @@ int main(int argc, char **argv)
                case 'C':       {
                                        uint16_t rrtype, rrclass;
                                        DNSServiceFlags flags = kDNSServiceFlagsReturnIntermediates;
-                                       if (argc < optind+1) goto Fail;
-                                       rrtype = (argc <= optind+1) ? kDNSServiceType_A  : GetRRType(argv[optind+1]);
-                                       rrclass = (argc <= optind+2) ? kDNSServiceClass_IN : atoi(argv[optind+2]);
+                                       if (argc < opi+1) goto Fail;
+                                       rrtype = (argc <= opi+1) ? kDNSServiceType_A  : GetRRType(argv[opi+1]);
+                                       rrclass = (argc <= opi+2) ? kDNSServiceClass_IN : atoi(argv[opi+2]);
                                        if (rrtype == kDNSServiceType_TXT || rrtype == kDNSServiceType_PTR) flags |= kDNSServiceFlagsLongLivedQuery;
-                                       err = DNSServiceQueryRecord(&client, flags, opinterface, argv[optind+0], rrtype, rrclass, qr_reply, NULL);
+                                       err = DNSServiceQueryRecord(&client, flags, opinterface, argv[opi+0], rrtype, rrclass, qr_reply, NULL);
                                        break;
                                        }
 
@@ -963,14 +964,14 @@ int main(int argc, char **argv)
 
 #if HAS_NAT_PMP_API
                case 'X':   {
-                                       if (argc == optind)     // If no arguments, just fetch IP address
+                                       if (argc == opi)        // If no arguments, just fetch IP address
                                                err = DNSServiceNATPortMappingCreate(&client, 0, 0, 0, 0, 0, 0, port_mapping_create_reply, NULL);
-                                       else if (argc >= optind+2 && atoi(argv[optind+0]) == 0)
+                                       else if (argc >= opi+2 && atoi(argv[opi+0]) == 0)
                                                {
-                                               DNSServiceProtocol prot  = GetProtocol(argv[optind+0]);                                         // Must specify TCP or UDP
-                                               uint16_t IntPortAsNumber = atoi(argv[optind+1]);                                                        // Must specify internal port
-                                               uint16_t ExtPortAsNumber = (argc < optind+3) ? 0 : atoi(argv[optind+2]);        // Optional desired external port
-                                               uint32_t ttl             = (argc < optind+4) ? 0 : atoi(argv[optind+3]);        // Optional desired lease lifetime
+                                               DNSServiceProtocol prot  = GetProtocol(argv[opi+0]);                                            // Must specify TCP or UDP
+                                               uint16_t IntPortAsNumber = atoi(argv[opi+1]);                                                   // Must specify internal port
+                                               uint16_t ExtPortAsNumber = (argc < opi+3) ? 0 : atoi(argv[opi+2]);      // Optional desired external port
+                                               uint32_t ttl             = (argc < opi+4) ? 0 : atoi(argv[opi+3]);      // Optional desired lease lifetime
                                                Opaque16 intp = { { IntPortAsNumber >> 8, IntPortAsNumber & 0xFF } };
                                                Opaque16 extp = { { ExtPortAsNumber >> 8, ExtPortAsNumber & 0xFF } };
                                                err = DNSServiceNATPortMappingCreate(&client, 0, 0, prot, intp.NotAnInteger, extp.NotAnInteger, ttl, port_mapping_create_reply, NULL);
@@ -982,8 +983,8 @@ int main(int argc, char **argv)
 
 #if HAS_ADDRINFO_API
                case 'G':   {
-                                       if (argc != optind+2) goto Fail;
-                                       else err = DNSServiceGetAddrInfo(&client, kDNSServiceFlagsReturnIntermediates, opinterface, GetProtocol(argv[optind+0]), argv[optind+1], addrinfo_reply, NULL);
+                                       if (argc != opi+2) goto Fail;
+                                       else err = DNSServiceGetAddrInfo(&client, kDNSServiceFlagsReturnIntermediates, opinterface, GetProtocol(argv[opi+0]), argv[opi+1], addrinfo_reply, NULL);
                                        break;
                            }
 #endif
index d774618acc6554df31812f67defd29210d1d8e06..c6aca02a526ce843f0808bcf97e6a6b384cc2bf7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-164"
+MVERS = "mDNSResponder-170"
 
 DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
 
index 01e063ad08b061bb9b80dd5254b354ab25012d6b..7c17df69ee424ec16ae322704b4c4e270db58e0a 100644 (file)
     Change History (most recent first):
 
 $Log: DNSCommon.c,v $
+Revision 1.193  2007/12/17 23:42:36  cheshire
+Added comments about DNSDigest_SignMessage()
+
+Revision 1.192  2007/12/17 21:24:09  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+We suspend sending of mDNS queries responses when going to sleep, so calculate GetNextScheduledEvent() time accordingly
+
+Revision 1.191  2007/12/14 00:59:36  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+While going to sleep, don't block event scheduling
+
+Revision 1.190  2007/12/13 20:20:17  cheshire
+Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
+SameRData from functions to macros, which allows the code to be inlined (the compiler can't
+inline a function defined in a different compilation unit) and therefore optimized better.
+
+Revision 1.189  2007/12/13 00:17:32  cheshire
+RDataHashValue was not calculating hash value reliably for RDATA types that have 'holes' in the
+in-memory representation (particularly SOA was affected by this, resulting in multiple duplicate
+cache entities for the same SOA record, because they had erroneously different rdatahash values).
+
+Revision 1.188  2007/12/13 00:13:03  cheshire
+Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
+
+Revision 1.187  2007/12/08 00:35:20  cheshire
+<rdar://problem/5636422> Updating TXT records is too slow
+m->SuppressSending should not suppress all activity, just mDNS Query/Probe/Response
+
+Revision 1.186  2007/11/15 22:52:29  cheshire
+<rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
+
 Revision 1.185  2007/10/10 20:22:03  cheshire
 Added sanity checks in mDNSSendDNSMessage -- we've seen crashes in DNSDigest_SignMessage
 apparently caused by trying to sign zero-length messages
@@ -1273,20 +1304,52 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
        rr->namestorage.c[0]  = 0;              // MUST be set by client before calling mDNS_Register()
        }
 
-mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb)
+mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
        {
-       mDNSu32 sum = 0;
-       int i;
-       for (i=0; i+1 < rdlength; i+=2)
-               {
-               sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1];
-               sum = (sum<<3) | (sum>>29);
-               }
-       if (i < rdlength)
+       switch(rr->rrtype)
                {
-               sum += ((mDNSu32)(rdb->data[i])) << 8;
+               case kDNSType_NS:
+               case kDNSType_CNAME:
+               case kDNSType_PTR:
+               case kDNSType_DNAME: return DomainNameHashValue(&rr->rdata->u.name);
+
+               case kDNSType_SOA:   return rr->rdata->u.soa.serial  +
+                                                                       rr->rdata->u.soa.refresh +
+                                                                       rr->rdata->u.soa.retry   +
+                                                                       rr->rdata->u.soa.expire  +
+                                                                       rr->rdata->u.soa.min     +
+                                                                       DomainNameHashValue(&rr->rdata->u.soa.mname) +
+                                                                       DomainNameHashValue(&rr->rdata->u.soa.rname);
+
+               case kDNSType_MX:
+               case kDNSType_AFSDB:
+               case kDNSType_RT:
+               case kDNSType_KX:        return DomainNameHashValue(&rr->rdata->u.mx.exchange);
+
+               case kDNSType_RP:        return DomainNameHashValue(&rr->rdata->u.rp.mbox)   + DomainNameHashValue(&rr->rdata->u.rp.txt);
+
+               case kDNSType_PX:        return DomainNameHashValue(&rr->rdata->u.px.map822) + DomainNameHashValue(&rr->rdata->u.px.mapx400);
+
+               case kDNSType_SRV:       return DomainNameHashValue(&rr->rdata->u.srv.target);
+
+               case kDNSType_OPT:      // Okay to use blind memory sum because there are no 'holes' in the in-memory representation
+
+               default:
+                       {
+                       mDNSu32 sum = 0;
+                       int i;
+                       for (i=0; i+1 < rr->rdlength; i+=2)
+                               {
+                               sum += (((mDNSu32)(rr->rdata->u.data[i])) << 8) | rr->rdata->u.data[i+1];
+                               sum = (sum<<3) | (sum>>29);
+                               }
+                       if (i < rr->rdlength)
+                               {
+                               sum += ((mDNSu32)(rr->rdata->u.data[i])) << 8;
+                               }
+                       return(sum);
+                       }
                }
-       return(sum);
        }
 
 // r1 has to be a full ResourceRecord including rrtype and rdlength
@@ -1326,28 +1389,12 @@ mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBod
                                                                                                mDNSSameIPPort(r1->rdata->u.srv.port, r2->srv.port) &&
                                                                                                SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target));
 
-               case kDNSType_OPT:      // Okay to use memory compare because there are no 'holes' in the in-memory representation
+               case kDNSType_OPT:      // Okay to use blind memory compare because there are no 'holes' in the in-memory representation
 
                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 &&
-                       r1->rrtype == r2->rrtype &&
-                       SameDomainName(r1->name, r2->name) &&
-                       SameRData(r1, r2));
-       }
-
 // ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question.
 // SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call.
 // SameDomainName() is generally cheap when the names don't match, but expensive when they do match,
@@ -1368,14 +1415,6 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
        if (rr->rrtype != kDNSType_CNAME && rr->rrtype  != q->qtype  && q->qtype  != kDNSQType_ANY ) return(mDNSfalse);
        if (                                rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
 
-#if VerifySameNameAssumptions
-       if (rr->namehash != q->qnamehash || !SameDomainName(rr->name, &q->qname))
-               {
-               LogMsg("Bogus SameNameRecordAnswersQuestion call: RR %##s does not match Q %##s", rr->name->c, q->qname.c);
-               return(mDNSfalse);
-               }
-#endif
-
        return(mDNStrue);
        }
 
@@ -2007,7 +2046,7 @@ mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 r
        target = GetRRDomainNameTarget(rr);
        rr->rdlength   = GetRDLength(rr, mDNSfalse);
        rr->rdestimate = GetRDLength(rr, mDNStrue);
-       rr->rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr->rdlength, &rr->rdata->u);
+       rr->rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr);
        }
 
 mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end)
@@ -2159,9 +2198,9 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
 
        if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
 
-       // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have
-       // a corresponding case in SameRDataBody() to do a semantic comparison of the structure instead of a blind
-       // bitwise memory compare. This is because a domainname is a fixed size structure holding variable-length data.
+       // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have corresponding
+       // cases in SameRDataBody() and RDataHashValue() to do a semantic comparison (or checksum) of the structure instead of a blind
+       // bitwise memory compare (or sum). This is because a domainname is a fixed size structure holding variable-length data.
        // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that
        // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ.
        if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0)   // Used in update packets to mean "Delete An RRset" (RFC 2136)
@@ -2486,13 +2525,12 @@ mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport, const
 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
 struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
 
+// Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
+// is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
 mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
     mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo)
        {
-       mStatus status;
-       long nsent;
-       unsigned long msglen;
-       mDNSu8 lenbuf[2];
+       mStatus status = mStatus_NoError;
        mDNSu16 numQuestions   = msg->h.numQuestions;
        mDNSu16 numAnswers     = msg->h.numAnswers;
        mDNSu16 numAuthorities = msg->h.numAuthorities;
@@ -2515,30 +2553,25 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
        *ptr++ = (mDNSu8)(numAdditionals >> 8);
        *ptr++ = (mDNSu8)(numAdditionals &  0xFF);
 
-       if (authInfo)
-               {
-               end = DNSDigest_SignMessage(msg, &end, authInfo, 0);
-               if (!end) return mStatus_UnknownErr;
-               }
-
-       // Send the packet on the wire
-       if (sock)
-               {
-               msglen = (mDNSu16)(end - (mDNSu8 *)msg);
-               lenbuf[0] = (mDNSu8)(msglen >> 8);  // host->network byte conversion
-               lenbuf[1] = (mDNSu8)(msglen &  0xFF);
-
-               nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);
-               //!!!KRS make sure kernel is sending these as 1 packet!
-               if (nsent != 2) goto tcp_error;
-
-               nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
-               if (nsent != (long)msglen) goto tcp_error;
-               status = mStatus_NoError;
-               }
+       if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0);    // DNSDigest_SignMessage operates on message in network byte order
+       if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; }
        else
                {
-               status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, dst, dstport);
+               // Send the packet on the wire
+               if (!sock)
+                       status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, dst, dstport);
+               else
+                       {
+                       mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
+                       mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) };
+                       long nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);              // Should do scatter/gather here -- this is probably going out as two packets
+                       if (nsent != 2) { LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2); status = mStatus_ConnFailed; }
+                       else
+                               {
+                               nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
+                               if (nsent != msglen) { LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen); status = mStatus_ConnFailed; }
+                               }
+                       }
                }
 
        // Put all the integer values back the way they were before we return
@@ -2555,10 +2588,6 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
                }
 
        return(status);
-
-       tcp_error:
-       LogMsg("mDNSSendDNSMessage: error sending message over tcp");
-       return mStatus_UnknownErr;
        }
 
 // ***************************************************************************
@@ -2615,7 +2644,7 @@ mDNSexport void mDNS_Lock_(mDNS *const m)
 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
        {
        mDNSs32 e = m->timenow + 0x78000000;
-       if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) return(e);
+       if (m->mDNSPlatformStatus != mStatus_NoError) return(e);
        if (m->NewQuestions)
                {
                if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
@@ -2623,15 +2652,25 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
                }
        if (m->NewLocalOnlyQuestions)                                   return(m->timenow);
        if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
-       if (m->SuppressSending)                                         return(m->SuppressSending);
 #ifndef UNICAST_DISABLED
        if (e - m->NextuDNSEvent         > 0) e = m->NextuDNSEvent;
+       if (e - m->NextScheduledNATOp    > 0) e = m->NextScheduledNATOp;
 #endif
        if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
-       if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
-       if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
-       if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
-       if (e - m->NextScheduledNATOp    > 0) e = m->NextScheduledNATOp;
+
+       if (!m->SleepState)
+               {
+               if (m->SuppressSending)
+                       {
+                       if (e - m->SuppressSending       > 0) e = m->SuppressSending;
+                       }
+               else
+                       {
+                       if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
+                       if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
+                       if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
+                       }
+               }
        return(e);
        }
 
index 847957316a1b9eee02916d58b858b92171322f4b..f186ac69aac33f5a4fb3c10055199e2f3b4fac42 100644 (file)
     Change History (most recent first):
 
 $Log: DNSCommon.h,v $
+Revision 1.57  2007/12/13 20:20:17  cheshire
+Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
+SameRData from functions to macros, which allows the code to be inlined (the compiler can't
+inline a function defined in a different compilation unit) and therefore optimized better.
+
+Revision 1.56  2007/12/13 00:13:03  cheshire
+Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
+
+Revision 1.55  2007/12/13 00:09:28  cheshire
+For completeness added MX, AFSDB, RT, KX to list of RRTYPES that are considered to have a target domainname in their rdata
+
 Revision 1.54  2007/10/05 17:56:10  cheshire
 Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
 
@@ -192,18 +203,47 @@ extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
 #pragma mark - Resource Record Utility Functions
 #endif
 
-extern mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb);
+// IdenticalResourceRecord returns true if two resources records have
+// the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
+
+// IdenticalSameNameRecord is the same, except it skips the expensive SameDomainName() check,
+// which is at its most expensive and least useful in cases where we know in advance that the names match
+
+// Note: The dominant use of IdenticalResourceRecord is from ProcessQuery(), handling known-answer lists. In this case
+// it's common to have a whole bunch or records with exactly the same name (e.g. "_http._tcp.local") but different RDATA.
+// The SameDomainName() check is expensive when the names match, and in this case *all* the names match, so we
+// used to waste a lot of CPU time verifying that the names match, only then to find that the RDATA is different.
+// We observed mDNSResponder spending 30% of its total CPU time on this single task alone.
+// By swapping the checks so that we check the RDATA first, we can quickly detect when it's different
+// (99% of the time) and then bail out before we waste time on the expensive SameDomainName() check.
+
+#define IdenticalResourceRecord(r1,r2) ( \
+       (r1)->rrtype    == (r2)->rrtype      && \
+       (r1)->rrclass   == (r2)->rrclass     && \
+       (r1)->namehash  == (r2)->namehash    && \
+       (r1)->rdlength  == (r2)->rdlength    && \
+       (r1)->rdatahash == (r2)->rdatahash   && \
+       SameRDataBody((r1), &(r2)->rdata->u) && \
+       SameDomainName((r1)->name, (r2)->name))
+
+#define IdenticalSameNameRecord(r1,r2) ( \
+       (r1)->rrtype    == (r2)->rrtype      && \
+       (r1)->rrclass   == (r2)->rrclass     && \
+       (r1)->rdlength  == (r2)->rdlength    && \
+       (r1)->rdatahash == (r2)->rdatahash   && \
+       SameRDataBody((r1), &(r2)->rdata->u))
+
+extern mDNSu32 RDataHashValue(const ResourceRecord *const rr);
 extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2);
-extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2);
+#define SameRData(r1,r2) ((r1)->rrtype == (r2)->rrtype && (r1)->rdlength == (r2)->rdlength && (r1)->rdatahash == (r2)->rdatahash && SameRDataBody((r1), &(r2)->rdata->u))
 extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
 extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-extern mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2);
 extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
 extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
 
 #define GetRRDomainNameTarget(RR) (                                                                          \
-       ((RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_NS)          \
-                                                                        ? &(RR)->rdata->u.name       :          \
+       ((RR)->rrtype == kDNSType_NS || (RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_DNAME) ? &(RR)->rdata->u.name        : \
+       ((RR)->rrtype == kDNSType_MX || (RR)->rrtype == kDNSType_AFSDB || (RR)->rrtype == kDNSType_RT  || (RR)->rrtype == kDNSType_KX   ) ? &(RR)->rdata->u.mx.exchange : \
        ((RR)->rrtype == kDNSType_SRV                                  ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
 
 #define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique && (X)->resrec.RecordType != kDNSRecordTypeDeregistering)
index 809499bf64f2e51c195d7ed25206fa68601350fb..09ff7c7f7c077a9d3817b4793f15bcb9053bc1a2 100644 (file)
     Change History (most recent first):
 
 $Log: DNSDigest.c,v $
+Revision 1.25  2007/12/17 23:48:29  cheshire
+DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter
+
+Revision 1.24  2007/11/30 23:03:51  cheshire
+Fixes for EFI: Use "mDNSPlatformMemCopy" instead of assuming existence of "memcpy"
+
 Revision 1.23  2007/09/21 21:12:36  cheshire
 DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
 
@@ -810,7 +816,7 @@ int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
 #if !defined(HASH_BLOCK_DATA_ORDER)
                        while (sw--)
                                {
-                               memcpy (p=c->data,data,HASH_CBLOCK);
+                               mDNSPlatformMemCopy(p=c->data,data,HASH_CBLOCK);
                                HASH_BLOCK_DATA_ORDER_ALIGNED(c,p,1);
                                data+=HASH_CBLOCK;
                                len-=HASH_CBLOCK;
@@ -853,7 +859,7 @@ void HASH_TRANSFORM (HASH_CTX *c, const unsigned char *data)
        else
 #if !defined(HASH_BLOCK_DATA_ORDER)
                {
-               memcpy (c->data,data,HASH_CBLOCK);
+               mDNSPlatformMemCopy(c->data,data,HASH_CBLOCK);
                HASH_BLOCK_DATA_ORDER_ALIGNED (c,c->data,1);
                }
 #endif
@@ -1404,7 +1410,7 @@ mDNSexport mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, co
        return(keylen);
        }
 
-mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode)
+mDNSexport void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode)
        {
        AuthRecord tsig;
        mDNSu8  *rdata, *const countPtr = (mDNSu8 *)&msg->h.numAdditionals;     // Get existing numAdditionals value
@@ -1447,7 +1453,7 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAu
        // time
        // get UTC (universal time), convert to 48-bit unsigned in network byte order
        utc32 = (mDNSu32)mDNSPlatformUTC();
-       if (utc32 == (unsigned)-1) { LogMsg("ERROR: DNSDigest_SignMessage - mDNSPlatformUTC returned bad time -1"); return mDNSNULL; }
+       if (utc32 == (unsigned)-1) { LogMsg("ERROR: DNSDigest_SignMessage - mDNSPlatformUTC returned bad time -1"); *end = mDNSNULL; }
        utc48[0] = 0;
        utc48[1] = 0;
        utc48[2] = (mDNSu8)((utc32 >> 24) & 0xff);
@@ -1497,13 +1503,11 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAu
        
        tsig.resrec.rdlength = (mDNSu16)(rdata - tsig.resrec.rdata->u.data);
        *end = PutResourceRecordTTLJumbo(msg, ptr, &numAdditionals, &tsig.resrec, 0);
-       if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; }
+       if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); *end = mDNSNULL; return; }
 
        // Write back updated numAdditionals value
        countPtr[0] = (mDNSu8)(numAdditionals >> 8);
        countPtr[1] = (mDNSu8)(numAdditionals &  0xFF);
-
-       return *end;
        }
 
 mDNSexport mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord * lcr, DomainAuthInfo *info, mDNSu16 * rcode, mDNSu16 * tcode)
index 854c6565d8164e187cfae154c9a8af6163b6af3b..2d4f110d518bfcb598bc5517f16112eb4230a29c 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNS.c,v $
+Revision 1.767  2007/12/22 02:25:29  cheshire
+<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
+
+Revision 1.766  2007/12/15 01:12:27  cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+
+Revision 1.765  2007/12/15 00:18:51  cheshire
+Renamed question->origLease to question->ReqLease
+
+Revision 1.764  2007/12/14 00:49:53  cheshire
+Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
+the CurrentServiceRecordSet mechanism to guard against services being deleted,
+just like the record deregistration loop uses m->CurrentRecord.
+
+Revision 1.763  2007/12/13 20:20:17  cheshire
+Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
+SameRData from functions to macros, which allows the code to be inlined (the compiler can't
+inline a function defined in a different compilation unit) and therefore optimized better.
+
+Revision 1.762  2007/12/13 00:13:03  cheshire
+Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
+
+Revision 1.761  2007/12/13 00:03:31  cheshire
+Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
+
+Revision 1.760  2007/12/08 00:36:19  cheshire
+<rdar://problem/5636422> Updating TXT records is too slow
+Remove unnecessary delays on announcing record updates, and on processing them on reception
+
+Revision 1.759  2007/12/07 22:41:29  cheshire
+<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
+Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
+
+Revision 1.758  2007/12/07 00:45:57  cheshire
+<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
+
+Revision 1.757  2007/12/06 00:22:27  mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
+Revision 1.756  2007/12/05 01:52:30  cheshire
+<rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
+Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
+
+Revision 1.755  2007/12/03 23:36:45  cheshire
+<rdar://problem/5623140> mDNSResponder unicast DNS improvements
+Need to check GetServerForName() result is non-null before dereferencing pointer
+
+Revision 1.754  2007/12/01 01:21:27  jgraessley
+<rdar://problem/5623140> mDNSResponder unicast DNS improvements
+
+Revision 1.753  2007/12/01 00:44:15  cheshire
+Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
+
+Revision 1.752  2007/11/14 01:10:51  cheshire
+Fixed LogOperation() message wording
+
 Revision 1.751  2007/10/30 23:49:41  cheshire
 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
 LLQ state was not being transferred properly between duplicate questions
@@ -893,7 +949,7 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int
 mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
        {
        // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
-       if (AddRecord) rr->LocalAnswer = mDNStrue;
+       if (AddRecord) rr->AnsweredLocalQ = mDNStrue;
        mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
        if (q->QuestionCallback && !q->NoAnswer)
                q->QuestionCallback(m, q, &rr->resrec, AddRecord);
@@ -1015,40 +1071,7 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons
                SameDomainName(pktrr->resrec.name, authrr->resrec.name));
        }
 
-// IdenticalResourceRecord returns true if two resources records have
-// the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
-
-// IdenticalSameNameRecord is the same, except it skips the expensive SameDomainName() check,
-// which is at its most expensive and least useful in cases where we know in advance that the names match
-
-mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
-       {
-       if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
-       if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
-       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
-               return(mDNSfalse);
-       return(SameRData(r1, r2));
-       }
-
-mDNSlocal mDNSBool IdenticalSameNameRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
-       {
-       if (!r1) { LogMsg("IdenticalSameNameRecord ERROR: r1 is NULL"); return(mDNSfalse); }
-       if (!r2) { LogMsg("IdenticalSameNameRecord ERROR: r2 is NULL"); return(mDNSfalse); }
-       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass)
-               return(mDNSfalse);
-
-#if VerifySameNameAssumptions
-       if (r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
-               {
-               LogMsg("Bogus IdenticalSameNameRecord call: %##s does not match %##s", r1->name->c, r1->name->c);
-               return(mDNSfalse);
-               }
-#endif
-
-       return(SameRData(r1, r2));
-       }
-
-// CacheRecord *ks is the CacheRecord from the known answer list in the query.
+// CacheRecord *ka is the CacheRecord from the known answer list in the query.
 // This is the information that the requester believes to be correct.
 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
 // This is the information that we believe to be correct.
@@ -1088,8 +1111,10 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r
                }
        }
 
-mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
+mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr, mDNSs32 interval)
        {
+       rr->ThisAPInterval = interval;
+
        // To allow us to aggregate probes when a group of services are registered together,
        // the first probe is delayed 1/4 second. This means the common-case behaviour is:
        // 1/4 second wait; probe
@@ -1097,19 +1122,22 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
        // 1/4 second wait; probe
        // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
 
-       // If we have no probe suppression time set, or it is in the past, set it now
-       if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
+       if (rr->ProbeCount)
                {
-               m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
-               // If we already have a probe scheduled to go out sooner, then use that time to get better aggregation
-               if (m->SuppressProbes - m->NextScheduledProbe >= 0)
-                       m->SuppressProbes = m->NextScheduledProbe;
-               // If we already have a query scheduled to go out sooner, then use that time to get better aggregation
-               if (m->SuppressProbes - m->NextScheduledQuery >= 0)
-                       m->SuppressProbes = m->NextScheduledQuery;
+               // If we have no probe suppression time set, or it is in the past, set it now
+               if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
+                       {
+                       m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
+                       // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
+                       if (m->SuppressProbes - m->NextScheduledProbe >= 0)
+                               m->SuppressProbes = m->NextScheduledProbe;
+                       // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
+                       if (m->SuppressProbes - m->NextScheduledQuery >= 0)
+                               m->SuppressProbes = m->NextScheduledQuery;
+                       }
                }
-       
-       rr->LastAPTime      = m->SuppressProbes - rr->ThisAPInterval;
+
+       rr->LastAPTime      = m->SuppressProbes - interval;
        // Set LastMCTime to now, to inhibit multicast responses
        // (no need to send additional multicast responses when we're announcing anyway)
        rr->LastMCTime      = m->timenow;
@@ -1118,12 +1146,16 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
        // If this is a record type that's not going to probe, then delay its first announcement so that
        // it will go out synchronized with the first announcement for the other records that *are* probing.
        // This is a minor performance tweak that helps keep groups of related records synchronized together.
-       // The addition of "rr->ThisAPInterval / 2" is to make sure that, in the event that any of the probes are
+       // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
        // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
        // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
        // because they will meet the criterion of being at least half-way to their scheduled announcement time.
-       if (rr->resrec.RecordType != kDNSRecordTypeUnique)
-               rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
+       // The exception is unique records that have already been verified and are just being updated
+       // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
+       if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+               rr->LastAPTime = m->timenow - interval;
+       else if (rr->resrec.RecordType != kDNSRecordTypeUnique)
+               rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + interval / 2;
        
        SetNextAnnounceProbeTime(m, rr);
        }
@@ -1158,8 +1190,7 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
 
                rr->AnnounceCount  = InitialAnnounceCount;
                rr->RequireGoodbye = mDNSfalse;
-               rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
-               InitializeLastAPTime(m,rr);
+               InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
                }
        }
 
@@ -1176,6 +1207,16 @@ mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
                }
        }
 
+mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
+       {
+       rr->ProbeCount     = 0;
+       rr->AnnounceCount  = 0;
+       rr->ThisAPInterval = 5 * mDNSPlatformOneSecond;         // After doubling, first retry will happen after ten seconds
+       rr->LastAPTime     = m->timenow - rr->ThisAPInterval;
+       rr->state = regState_FetchingZoneData;
+       rr->uselease = mDNStrue;
+       }
+
 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
        ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
@@ -1259,7 +1300,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
        rr->AnnounceCount     = InitialAnnounceCount;
        rr->RequireGoodbye    = mDNSfalse;
-       rr->LocalAnswer       = mDNSfalse;
+       rr->AnsweredLocalQ    = mDNSfalse;
        rr->IncludeInProbe    = mDNSfalse;
        rr->ImmedAnswer       = mDNSNULL;
        rr->ImmedUnicast      = mDNSfalse;
@@ -1270,8 +1311,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->NextResponse      = mDNSNULL;
        rr->NR_AnswerTo       = mDNSNULL;
        rr->NR_AdditionalTo   = mDNSNULL;
-       rr->ThisAPInterval    = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
-       if (!rr->AutoTarget) InitializeLastAPTime(m, rr);
+       if (!rr->AutoTarget) InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
 //     rr->LastAPTime        = Set for us in InitializeLastAPTime()
 //     rr->LastMCTime        = Set for us in InitializeLastAPTime()
 //     rr->LastMCInterface   = Set for us in InitializeLastAPTime()
@@ -1328,7 +1368,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
 
        rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
-       rr->resrec.rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
+       rr->resrec.rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec);
        
        if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
                {
@@ -1384,11 +1424,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        else
                {
                if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
-               rr->ProbeCount    = 0;
-               rr->AnnounceCount = 0;
-               rr->state = regState_FetchingZoneData;
-               rr->uselease = mDNStrue;
-               rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
+               ActivateUnicastRegistration(m, rr);
                }
 #endif
        
@@ -1522,7 +1558,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                }
 #endif UNICAST_DISABLED
 
-       if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->LocalAnswer))
+       if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))
                {
                verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr));
                rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
@@ -1732,7 +1768,7 @@ mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
        // it should go ahead and immediately dispose of this registration
        rr->resrec.RecordType = kDNSRecordTypeShared;
        rr->RequireGoodbye    = mDNSfalse;
-       if (rr->LocalAnswer) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->LocalAnswer = mDNSfalse; }
+       if (rr->AnsweredLocalQ) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
        mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);             // Don't touch rr after this
        }
 
@@ -2062,13 +2098,13 @@ mDNSlocal void SendResponses(mDNS *const m)
                if (rr->SendRNow)
                        {
                        if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
-                               LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr));
+                               LogMsg("SendResponses: No active interface to send: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
                        rr->SendRNow = mDNSNULL;
                        }
 
                if (rr->ImmedAnswer)
                        {
-                       if (rr->NewRData) CompleteRDataUpdate(m,rr);    // Update our rdata, clear the NewRData pointer, and return memory to the client
+                       if (rr->NewRData) CompleteRDataUpdate(m, rr);   // Update our rdata, clear the NewRData pointer, and return memory to the client
        
                        if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                                CompleteDeregistration(m, rr);          // Don't touch rr after this
@@ -2094,11 +2130,14 @@ mDNSlocal void SendResponses(mDNS *const m)
 //    and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
 //    so allow at most 1/10 second lateness
+// 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
+//    (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
 #define CacheCheckGracePeriod(RR) (                                                   \
        ((RR)->DelayDelivery                           ) ? (mDNSPlatformOneSecond/10)   : \
        ((RR)->CRActiveQuestion == mDNSNULL            ) ? (60 * mDNSPlatformOneSecond) : \
        ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50)            : \
-       ((RR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : (mDNSPlatformOneSecond/10))
+       ((RR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : \
+       ((RR)->resrec.rroriginalttl > 0                ) ? (mDNSPlatformOneSecond/10)   : 0)
 
 // Note: MUST call SetNextCacheCheckTime any time we change:
 // rr->TimeRcvd
@@ -2211,7 +2250,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                                                q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data);
                                        query->h.numQuestions--;
                                        ka = *kalistptrptr;             // Go back to where we started and retract these answer records
-                                       while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
+                                       while (*ka) { CacheRecord *c = *ka; *ka = mDNSNULL; ka = &c->NextInKAList; }
                                        return(mDNSfalse);              // Return false, so we'll try again in the next packet
                                        }
                                }
@@ -2623,16 +2662,16 @@ mDNSlocal void SendQueries(mDNS *const m)
                // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
                while (KnownAnswerList)
                        {
-                       CacheRecord *rr = KnownAnswerList;
-                       mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
-                       mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
+                       CacheRecord *ka = KnownAnswerList;
+                       mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond;
+                       mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd);
                        if (newptr)
                                {
                                verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d",
-                                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
+                                       ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
                                queryptr = newptr;
-                               KnownAnswerList = rr->NextInKAList;
-                               rr->NextInKAList = mDNSNULL;
+                               KnownAnswerList = ka->NextInKAList;
+                               ka->NextInKAList = mDNSNULL;
                                }
                        else
                                {
@@ -2886,7 +2925,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                m->CurrentQuestion = m->Questions;
                while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
                        {
-                       DNSQuestion *q = m->CurrentQuestion;
+                       q = m->CurrentQuestion;
                        if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                                AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
                        if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
@@ -3068,7 +3107,6 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
 mDNSlocal void AnswerNewQuestion(mDNS *const m)
        {
        mDNSBool ShouldQueryImmediately = mDNStrue;
-       CacheRecord *rr;
        DNSQuestion *q = m->NewQuestions;               // Grab the question we're going to answer
        const mDNSu32 slot = HashSlot(&q->qname);
        CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
@@ -3120,6 +3158,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
 
        if (m->CurrentQuestion == q)
                {
+               CacheRecord *rr;
                for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                        if (SameNameRecordAnswersQuestion(&rr->resrec, q))
                                {
@@ -3487,15 +3526,8 @@ mDNSlocal void SuspendLLQs(mDNS *m)
        {
        DNSQuestion *q;
        for (q = m->Questions; q; q = q->next)
-               if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived)
-                       {
-                       // If necessary, tell server it can delete this LLQ state
-                       if (q->state == LLQ_Established) sendLLQRefresh(m, q, 0);
-                       if (q->nta) { CancelGetZoneData(m, q->nta); q->nta = mDNSNULL; }
-                       if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
-                       q->state = LLQ_InitialRequest;  // Will need to set up new LLQ on wake from sleep
-                       q->id = zeroOpaque64;
-                       }
+               if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established)
+                       { q->ReqLease = 0; sendLLQRefresh(m, q); }
        }
 
 mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question)
@@ -3503,7 +3535,12 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question)
        // For now this AutoTunnel stuff is specific to Mac OS X.
        // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
 #if APPLE_OSX_mDNSResponder
-       if (question->qtype == kDNSType_AAAA && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
+       // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
+       // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
+       // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
+       // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
+       // returns results for both at the same time.
+       if (RRTypeIsAddressType(question->qtype) && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
                {
                question->NoAnswer = NoAnswer_Suspended;
                AddNewClientTunnel(m, question);
@@ -3516,7 +3553,7 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question)
                LogOperation("ActivateUnicastQuery: %##s %s%s",
                        question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "");
                if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
-               if (question->LongLived) question->state = LLQ_InitialRequest;
+               if (question->LongLived) { question->state = LLQ_InitialRequest; question->id = zeroOpaque64; }
                question->ThisQInterval = InitialQuestionInterval;
                question->LastQTime     = m->timenow - question->ThisQInterval;
                SetNextQueryTime(m, question);
@@ -3570,12 +3607,13 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
                m->CurrentQuestion = m->Questions;
                while (m->CurrentQuestion)
                        {
-                       DNSQuestion *q = m->CurrentQuestion;
+                       q = m->CurrentQuestion;
                        m->CurrentQuestion = m->CurrentQuestion->next;
                        if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q);
                        }
-               // and reactivtate record (and service) registrations
-               uDNS_Wake(m);
+               // and reactivtate service registrations
+               m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
+               LogOperation("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate);
 #endif
         // 1. Retrigger all our mDNS questions
                for (q = m->Questions; q; q=q->next)                            // Scan our list of questions
@@ -3596,13 +3634,16 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
 
                // 3. Retrigger probing and announcing for all our authoritative records
                for (rr = m->ResourceRecords; rr; rr=rr->next)
-                       if (!AuthRecord_uDNS(rr))
+                       if (AuthRecord_uDNS(rr))
+                               {
+                               ActivateUnicastRegistration(m, rr);
+                               }
+                       else
                                {
                                if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
                                rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
                                rr->AnnounceCount  = InitialAnnounceCount;
-                               rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
-                               InitializeLastAPTime(m, rr);
+                               InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
                                }
                }
 
@@ -3824,7 +3865,7 @@ exit:
        m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
        }
 
-mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceRecord *pktrr)
+mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr)
        {
        mDNSu32 slot = HashSlot(pktrr->name);
        CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
@@ -3928,24 +3969,24 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                        {
                        const mDNSu32 slot = HashSlot(&pktq.qname);
                        CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
-                       CacheRecord *rr;
+                       CacheRecord *cr;
 
                        // Make a list indicating which of our own cache records we expect to see updated as a result of this query
                        // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
-                       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-                               if (SameNameRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
-                                       if (!rr->NextInKAList && eap != &rr->NextInKAList)
+                       for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+                               if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
+                                       if (!cr->NextInKAList && eap != &cr->NextInKAList)
                                                {
-                                               *eap = rr;
-                                               eap = &rr->NextInKAList;
-                                               if (rr->MPUnansweredQ == 0 || m->timenow - rr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
+                                               *eap = cr;
+                                               eap = &cr->NextInKAList;
+                                               if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
                                                        {
                                                        // Although MPUnansweredQ is only really used for multi-packet query processing,
                                                        // we increment it for both single-packet and multi-packet queries, so that it stays in sync
                                                        // with the MPUnansweredKA value, which by necessity is incremented for both query types.
-                                                       rr->MPUnansweredQ++;
-                                                       rr->MPLastUnansweredQT = m->timenow;
-                                                       rr->MPExpectingKA = mDNStrue;
+                                                       cr->MPUnansweredQ++;
+                                                       cr->MPLastUnansweredQT = m->timenow;
+                                                       cr->MPExpectingKA = mDNStrue;
                                                        }
                                                }
        
@@ -3983,7 +4024,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
        for (i=0; i<query->h.numAnswers; i++)                                           // For each record in the query's answer section...
                {
                // Get the record...
-               AuthRecord *rr;
                CacheRecord *ourcacherr;
                ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
                if (!ptr) goto exit;
@@ -4033,10 +4073,10 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                eap = &ExpectedAnswers;
                while (*eap)
                        {
-                       CacheRecord *rr = *eap;
-                       if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
-                               { *eap = rr->NextInKAList; rr->NextInKAList = mDNSNULL; }
-                       else eap = &rr->NextInKAList;
+                       CacheRecord *cr = *eap;
+                       if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec))
+                               { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; }
+                       else eap = &cr->NextInKAList;
                        }
                
                // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
@@ -4183,38 +4223,37 @@ exit:
        
        while (ExpectedAnswers)
                {
-               CacheRecord *rr;
-               rr = ExpectedAnswers;
-               ExpectedAnswers = rr->NextInKAList;
-               rr->NextInKAList = mDNSNULL;
+               CacheRecord *cr = ExpectedAnswers;
+               ExpectedAnswers = cr->NextInKAList;
+               cr->NextInKAList = mDNSNULL;
                
                // For non-truncated queries, we can definitively say that we should expect
                // to be seeing a response for any records still left in the ExpectedAnswers list
                if (!(query->h.flags.b[0] & kDNSFlag0_TC))
-                       if (rr->UnansweredQueries == 0 || m->timenow - rr->LastUnansweredTime >= mDNSPlatformOneSecond)
+                       if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond)
                                {
-                               rr->UnansweredQueries++;
-                               rr->LastUnansweredTime = m->timenow;
-                               if (rr->UnansweredQueries > 1)
+                               cr->UnansweredQueries++;
+                               cr->LastUnansweredTime = m->timenow;
+                               if (cr->UnansweredQueries > 1)
                                        debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
-                                               rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
-                               SetNextCacheCheckTime(m, rr);
+                                               cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
+                               SetNextCacheCheckTime(m, cr);
                                }
 
                // If we've seen multiple unanswered queries for this record,
                // then mark it to expire in five seconds if we don't get a response by then.
-               if (rr->UnansweredQueries >= MaxUnansweredQueries)
+               if (cr->UnansweredQueries >= MaxUnansweredQueries)
                        {
                        // Only show debugging message if this record was not about to expire anyway
-                       if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
+                       if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
                                debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
-                                       rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
-                       mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
+                                       cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
+                       mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
                        }
                // Make a guess, based on the multi-packet query / known answer counts, whether we think we
                // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
                // possible packet loss of up to 20% of the additional KA packets.)
-               else if (rr->MPUnansweredQ * 4 > rr->MPUnansweredKA * 5 + 8)
+               else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8)
                        {
                        // We want to do this conservatively.
                        // If there are so many machines on the network that they have to use multi-packet known-answer lists,
@@ -4222,30 +4261,29 @@ exit:
                        // By setting the record to expire in four minutes, we achieve two things:
                        // (a) the 90-95% final expiration queries will be less bunched together
                        // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
-                       mDNSu32 remain = (mDNSu32)(RRExpireTime(rr) - m->timenow) / 4;
+                       mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4;
                        if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond)
                                remain = 240 * (mDNSu32)mDNSPlatformOneSecond;
                        
                        // Only show debugging message if this record was not about to expire anyway
-                       if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
+                       if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
                                debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
-                                       rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
+                                       cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
 
                        if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
-                               rr->UnansweredQueries++;        // Treat this as equivalent to one definite unanswered query
-                       rr->MPUnansweredQ  = 0;                 // Clear MPQ/MPKA statistics
-                       rr->MPUnansweredKA = 0;
-                       rr->MPExpectingKA  = mDNSfalse;
+                               cr->UnansweredQueries++;        // Treat this as equivalent to one definite unanswered query
+                       cr->MPUnansweredQ  = 0;                 // Clear MPQ/MPKA statistics
+                       cr->MPUnansweredKA = 0;
+                       cr->MPExpectingKA  = mDNSfalse;
                        
                        if (remain < kDefaultReconfirmTimeForNoAnswer)
                                remain = kDefaultReconfirmTimeForNoAnswer;
-                       mDNS_Reconfirm_internal(m, rr, remain);
+                       mDNS_Reconfirm_internal(m, cr, remain);
                        }
                }
        
        while (DupQuestions)
                {
-               int i;
                DNSQuestion *q = DupQuestions;
                DupQuestions = q->NextInDQList;
                q->NextInDQList = mDNSNULL;
@@ -4338,7 +4376,7 @@ mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAd
                                        if (mDNSSameOpaque16(q->TargetQID, id))                     return(mDNStrue);
                                //      if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
                                        if (TrustedSource(m, srcaddr))                              return(mDNStrue);
-                                       LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) %#a from %#a: %s",
+                                       LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a] from %#a: %s",
                                                q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr));
                                        return(mDNSfalse);
                                        }
@@ -4618,8 +4656,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                                debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                                rr->resrec.RecordType     = kDNSRecordTypeUnique;
                                                                rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
-                                                               rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
-                                                               InitializeLastAPTime(m, rr);
+                                                               InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(kDNSRecordTypeUnique));
                                                                RecordProbeFailure(m, rr);      // Repeated late conflicts also cause us to back off to the slower probing rate
                                                                }
                                                        // If we're probing for this record, we just failed
@@ -4711,6 +4748,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
                                                // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
                                                // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
+                                               debugf("DE for %s", CRDisplayString(m, rr));
                                                rr->resrec.rroriginalttl = 1;
                                                rr->UnansweredQueries = MaxUnansweredQueries;
                                                SetNextCacheCheckTime(m, rr);
@@ -4756,58 +4794,76 @@ exit:
                // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
                // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
                // To avoid this, we need to ensure that the cache flushing operation will only act to
-               // *decrease* a record's remaining lifetime, never *increase* it. If a record has less than
-               // one second to go, we simply leave it alone, and leave it to expire at its assigned time.
+               // *decrease* a record's remaining lifetime, never *increase* it.
                for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
                        if (r1->resrec.InterfaceID == r2->resrec.InterfaceID &&
                                r1->resrec.rrtype      == r2->resrec.rrtype &&
                                r1->resrec.rrclass     == r2->resrec.rrclass)
-                               if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
+                               {
+                               // 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 && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
                                        {
-                                       // 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 we find mismatched TTLs in an RRSet, correct them.
+                                       // We only do this for records with a TTL of 2 or higher. It's possible to have a
+                                       // goodbye announcement with the cache flush bit set (or a case change on record rdata,
+                                       // which we treat as a goodbye followed by an addition) and in that case it would be
+                                       // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
+                                       // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
+                                       // because certain early Bonjour devices are known to have this specific mismatch, and
+                                       // there's no point filling syslog with messages about something we already know about.
+                                       // We also don't log this for uDNS responses, since a caching name server is obliged
+                                       // to give us an aged TTL to correct for how long it has held the record,
+                                       // so our received TTLs are expected to vary in that case
+                                       if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
                                                {
-                                               // If we find mismatched TTLs in an RRSet, correct them.
-                                               // We only do this for records with a TTL of 2 or higher. It's possible to have a
-                                               // goodbye announcement with the cache flush bit set (or a case change on record rdata,
-                                               // which we treat as a goodbye followed by an addition) and in that case it would be
-                                               // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
-                                               // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
-                                               // because certain early Bonjour devices are known to have this specific mismatch, and
-                                               // there's no point filling syslog with messages about something we already know about.
-                                               // We also don't log this for uDNS responses, since a caching name server is obliged
-                                               // to give us an aged TTL to correct for how long it has held the record,
-                                               // so our received TTLs are expected to vary in that case
-                                               if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
-                                                       {
-                                                       if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) &&
-                                                               mDNSOpaque16IsZero(response->h.id))
-                                                               LogOperation("Correcting TTL from %4d to %4d for %s",
-                                                                       r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
-                                                       r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
-                                                       }
+                                               if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) &&
+                                                       mDNSOpaque16IsZero(response->h.id))
+                                                       LogOperation("Correcting TTL from %4d to %4d for %s",
+                                                               r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
+                                               r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
+                                               }
+                                       r2->TimeRcvd = m->timenow;
+                                       }
+                               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.
+
+                                       // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
+                                       // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
+                                       // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
+                                       if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl <= 1 && r2->UnansweredQueries == MaxUnansweredQueries)
+                                               {
+                                               debugf("Cache flush for DE record %s", CRDisplayString(m, r2));
+                                               r2->resrec.rroriginalttl = 0;
+                                               m->NextCacheCheck = m->timenow;
+                                               m->NextScheduledEvent = m->timenow;
                                                }
-                                       else                            // else, if record is old, mark it to be flushed
+                                       else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
                                                {
-                                               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.
+                                               // We only set a record to expire in one second if it currently has *more* than a second to live
+                                               // If it's already due to expire in a second or less, we just leave it alone
                                                r2->resrec.rroriginalttl = 1;
                                                r2->UnansweredQueries = MaxUnansweredQueries;
+                                               r2->TimeRcvd = m->timenow - 1;
+                                               // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
+                                               // that we marked for deletion via an explicit DE record
                                                }
-                                       r2->TimeRcvd = m->timenow;
-                                       SetNextCacheCheckTime(m, r2);
                                        }
+                               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
@@ -4942,6 +4998,11 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const n
        m->rec.r.NextInCFList       = mDNSNULL;
        }
 
+struct UDPSocket_struct
+       {
+       mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
+       };
+       
 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
        const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport,
        const mDNSInterfaceID InterfaceID)
@@ -4959,22 +5020,22 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
 #ifndef UNICAST_DISABLED
        if (mDNSSameAddress(srcaddr, &m->Router))
                {
-               if (mDNSSameIPPort(srcport, NATPMPPort))
+#ifdef _LEGACY_NAT_TRAVERSAL_
+               if (mDNSSameIPPort(srcport, SSDPPort) || (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)))
                        {
                        mDNS_Lock(m);
-                       uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
+                       LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
                        mDNS_Unlock(m);
                        return;
                        }
-#ifdef _LEGACY_NAT_TRAVERSAL_
-               if (mDNSSameIPPort(srcport, SSDPPort))
+#endif
+               if (mDNSSameIPPort(srcport, NATPMPPort))
                        {
                        mDNS_Lock(m);
-                       LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
+                       uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
                        mDNS_Unlock(m);
                        return;
                        }
-#endif
                }
 #endif
        if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
@@ -5058,8 +5119,7 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest
        return(mDNSNULL);
        }
 
-// This is called after a question is deleted, in case other identical questions were being
-// suppressed as duplicates
+// This is called after a question is deleted, in case other identical questions were being suppressed as duplicates
 mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question)
        {
        DNSQuestion *q;
@@ -5083,7 +5143,7 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
 
                                q->state             = question->state;
                        //      q->tcp               = question->tcp;
-                               q->origLease         = question->origLease;
+                               q->ReqLease          = question->ReqLease;
                                q->expire            = question->expire;
                                q->ntries            = question->ntries;
                                q->id                = question->id;
@@ -5109,7 +5169,7 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
                                }
        }
 
-// lookup a DNS Server, matching by name in split-dns configurations.  Result stored in addr parameter if successful
+// Look up a DNS Server, matching by name in split-dns configurations.
 mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name)
     {
        DNSServer *curmatch = mDNSNULL, *p;
@@ -5118,7 +5178,7 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name)
        for (p = m->DNSServers; p; p = p->next)
                {
                int scount = CountLabels(&p->domain);
-               if (!p->del && ncount >= scount && scount > curmatchlen)
+               if (!(p->flags & DNSServer_FlagDelete) && ncount >= scount && scount > curmatchlen)
                        if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain))
                                { curmatch = p; curmatchlen = scount; }
                }
@@ -5242,7 +5302,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                question->NoAnswer          = NoAnswer_Normal;
 
                question->state             = LLQ_InitialRequest;
-               question->origLease         = 0;
+               question->ReqLease          = 0;
                question->expire            = 0;
                question->ntries            = 0;
                question->id                = zeroOpaque64;
@@ -5311,13 +5371,13 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
        const mDNSu32 slot = HashSlot(&question->qname);
        CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
        CacheRecord *rr;
-       DNSQuestion **q = &m->Questions;
+       DNSQuestion **qp = &m->Questions;
        
        //LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
 
-       if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
-       while (*q && *q != question) q=&(*q)->next;
-       if (*q) *q = (*q)->next;
+       if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions;
+       while (*qp && *qp != question) qp=&(*qp)->next;
+       if (*qp) *qp = (*qp)->next;
        else
                {
 #if !ForceAlerts
@@ -5401,7 +5461,20 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
                        }
 
                // If necessary, tell server it can delete this LLQ state
-               if (question->state == LLQ_Established) sendLLQRefresh(m, question, 0);
+               if (question->state == LLQ_Established)
+                       {
+                       question->ReqLease = 0;
+                       sendLLQRefresh(m, question);
+                       // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while.
+                       // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't
+                       // crash trying to access our cancelled question, but we don't cancel the TCP operation itself --
+                       // we let that run out its natural course and complete asynchronously.
+                       if (question->tcp)
+                               {
+                               question->tcp->question = mDNSNULL;
+                               question->tcp           = mDNSNULL;
+                               }
+                       }
                }
 
        return(mStatus_NoError);
@@ -5824,8 +5897,7 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
                // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
                // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
                if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
-               rr->ThisAPInterval       = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
-               InitializeLastAPTime(m, rr);
+               InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
                while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
                if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
                if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
@@ -5950,7 +6022,7 @@ mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
                        intf->RR_A.RRSet = A;
 
        // Unregister these records.
-       // When doing the mDNS_Close processing, we first call DeadvertiseInterface for each interface, so by the time the platform
+       // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
        // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
        // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
        // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
@@ -6135,7 +6207,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                                        mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
                                        mDNSs32 initial  = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
                                        mDNSs32 qdelay   = dodelay ? mDNSPlatformOneSecond * 5 : 0;
-                                       if (dodelay) LogOperation("No cache records for expired %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
+                                       if (dodelay) LogOperation("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
                                                
                                        if (!q->ThisQInterval || q->ThisQInterval > initial)
                                                {
@@ -6156,8 +6228,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                                        if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
                                        rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
                                        if (rr->AnnounceCount < announce) rr->AnnounceCount  = announce;
-                                       rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
-                                       InitializeLastAPTime(m, rr);
+                                       InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
                                        }
                }
 
@@ -6293,7 +6364,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
        // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
        // giving the false impression that there's an active representative of this interface when there really isn't.
        // Don't need to do this when shutting down, because *all* interfaces are about to go away
-       if (revalidate && !m->mDNS_shutdown)
+       if (revalidate && !m->ShutdownTime)
                {
                mDNSu32 slot;
                CacheGroup *cg;
@@ -6394,9 +6465,10 @@ mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
                return mStatus_NoError;
                }
 
+       ActivateUnicastRegistration(m, &srs->RR_SRV);
        srs->state = regState_FetchingZoneData;
-       srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
-       return srs->nta ? mStatus_NoError : mStatus_NoMemoryErr;
+       srs->nta   = mDNSNULL;
+       return mStatus_NoError;
        }
 
 // Note:
@@ -6532,7 +6604,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        err = mDNS_Register_internal(m, &sr->RR_SRV);
        if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
        // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
-       // mDNS_Close, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
+       // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
        // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
        // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
        // make sure we've deregistered all our records and done any other necessary cleanup before that happens.
@@ -6826,7 +6898,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        // For debugging: To catch and report locking failures
        m->mDNS_busy               = 0;
        m->mDNS_reentrancy         = 0;
-       m->mDNS_shutdown           = mDNSfalse;
+       m->ShutdownTime            = 0;
        m->lock_rrcache            = 0;
        m->lock_Questions          = 0;
        m->lock_Records            = 0;
@@ -6922,6 +6994,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->LastNATReplyLocalTime    = timenow;
 
        m->UPnPInterfaceID          = 0;
+       m->SSDPSocket               = mDNSNULL;
        m->UPnPRouterPort           = zeroIPPort;
        m->UPnPSOAPPort             = zeroIPPort;
        m->UPnPRouterURL            = mDNSNULL;
@@ -6971,7 +7044,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
        // Let the platform layer get the current DNS information
        // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
        // (no need to hit the network with domain enumeration queries until we actually need that information).
-       for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->del = mDNStrue;
+       for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->flags |= DNSServer_FlagDelete;
 
        mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
 
@@ -6993,15 +7066,28 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                                }
                        }
 
+       // Flush all records that match a new resolver
+       FORALL_CACHERECORDS(slot, cg, cr)
+               {
+               ptr = GetServerForName(m, cr->resrec.name);
+               if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID)
+                       {
+                       if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
+                               mDNS_PurgeCacheResourceRecord(m, cr);
+                       else
+                               mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+                       }
+               }
+       
        while (*p)
                {
-               if ((*p)->del)
+               if (((*p)->flags & DNSServer_FlagDelete) != 0)
                        {
                        // Scan our cache, looking for uDNS records that we would have queried this server for.
                        // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
                        // different DNS servers can give different answers to the same question.
                        ptr = *p;
-                       ptr->del = mDNSfalse;   // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
+                       ptr->flags &= ~DNSServer_FlagDelete;    // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
                        FORALL_CACHERECORDS(slot, cg, cr)
                                if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr)
                                        mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
@@ -7009,7 +7095,10 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                        mDNSPlatformMemFree(ptr);
                        }
                else
+                       {
+                       (*p)->flags &= ~DNSServer_FlagNew;
                        p = &(*p)->next;
+                       }
                }
 
        // If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs).
@@ -7073,44 +7162,24 @@ mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
                }
        }
 
-mDNSexport void mDNS_Close(mDNS *const m)
+extern ServiceRecordSet *CurrentServiceRecordSet;
+
+mDNSexport void mDNS_StartExit(mDNS *const m)
        {
-       mDNSu32 rrcache_active = 0;
-       mDNSu32 rrcache_totalused = 0;
-       mDNSu32 slot;
        NetworkInterfaceInfo *intf;
        AuthRecord *rr;
+
        mDNS_Lock(m);
-       
-       m->mDNS_shutdown = mDNStrue;
+
+       m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
 
 #ifndef UNICAST_DISABLED
        SuspendLLQs(m);
-       SleepServiceRegistrations(m);
+       // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
+       // because we deregister all records and services later in this routine
        while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
 #endif
 
-       rrcache_totalused = m->rrcache_totalused;
-       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               {
-               while (m->rrcache_hash[slot])
-                       {
-                       CacheGroup *cg = m->rrcache_hash[slot];
-                       while (cg->members)
-                               {
-                               CacheRecord *cr = cg->members;
-                               cg->members = cg->members->next;
-                               if (cr->CRActiveQuestion) rrcache_active++;
-                               ReleaseCacheRecord(m, cr);
-                               }
-                       cg->rrcache_tail = &cg->members;
-                       ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
-                       }
-               }
-       debugf("mDNS_Close: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
-       if (rrcache_active != m->rrcache_active)
-               LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
-
        for (intf = m->HostInterfaces; intf; intf = intf->next)
                if (intf->Advertise)
                        DeadvertiseInterface(m, intf);
@@ -7134,17 +7203,22 @@ mDNSexport void mDNS_Close(mDNS *const m)
 
        // Make sure there are nothing but deregistering records remaining in the list
        if (m->CurrentRecord)
-               LogMsg("mDNS_Close ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+               LogMsg("mDNS_StartExit ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
 
        // First we deregister any non-shared records. In particular, we want to make sure we deregister
-       // any extra records added to a Service Record Set first, before we deregister its PTR record.
+       // any extra records added to a Service Record Set first, before we deregister its PTR record,
+       // because the freeing of the memory is triggered off the mStatus_MemFree for the PTR record.
        m->CurrentRecord = m->ResourceRecords;
        while (m->CurrentRecord)
                {
                rr = m->CurrentRecord;
-               m->CurrentRecord = rr->next;
                if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
                        mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+               // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when
+               // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record
+               // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate
+               if (m->CurrentRecord == rr)             // If m->CurrentRecord was not auto-advanced, do it ourselves now
+                       m->CurrentRecord = rr->next;
                }
 
        // Now deregister any remaining records we didn't get the first time through
@@ -7152,23 +7226,79 @@ mDNSexport void mDNS_Close(mDNS *const m)
        while (m->CurrentRecord)
                {
                rr = m->CurrentRecord;
-               m->CurrentRecord = rr->next;
                if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+                       {
+                       //LogOperation("mDNS_StartExit: Deregistering %s", ARDisplayString(m, rr));
                        mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+                       }
+               // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when
+               // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record
+               // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate
+               if (m->CurrentRecord == rr)             // If m->CurrentRecord was not auto-advanced, do it ourselves now
+                       m->CurrentRecord = rr->next;
+               }
+
+       CurrentServiceRecordSet = m->ServiceRegistrations;
+       while (CurrentServiceRecordSet)
+               {
+               ServiceRecordSet *srs = CurrentServiceRecordSet;
+               LogOperation("mDNS_StartExit: Deregistering %##s", srs->RR_SRV.resrec.name->c);
+               uDNS_DeregisterService(m, srs);
+               if (CurrentServiceRecordSet == srs)
+                       CurrentServiceRecordSet = srs->uDNS_next;
                }
 
-       if (m->ResourceRecords) LogOperation("mDNS_Close: Sending final packets for deregistering records");
-       else                    LogOperation("mDNS_Close: No deregistering records remain");
+       if (m->ResourceRecords) LogOperation("mDNS_StartExit: Sending final record deregistrations");
+       else                    LogOperation("mDNS_StartExit: No deregistering records remain");
+
+       if (m->ServiceRegistrations) LogOperation("mDNS_StartExit: Sending final service deregistrations");
+       else                         LogOperation("mDNS_StartExit: No deregistering services remain");
 
        // If any deregistering records remain, send their deregistration announcements before we exit
        if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
-       else if (m->ResourceRecords) SendResponses(m);
 
-       for (rr = m->ResourceRecords; rr; rr = rr->next)
-               LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, rr));
-       
        mDNS_Unlock(m);
-       debugf("mDNS_Close: mDNSPlatformClose");
+
+       LogOperation("mDNS_StartExit: done");
+       }
+
+mDNSexport void mDNS_FinalExit(mDNS *const m)
+       {
+       mDNSu32 rrcache_active = 0;
+       mDNSu32 rrcache_totalused = 0;
+       mDNSu32 slot;
+       AuthRecord *rr;
+       ServiceRecordSet *srs;
+
+       LogOperation("mDNS_FinalExit: mDNSPlatformClose");
        mDNSPlatformClose(m);
-       debugf("mDNS_Close: done");
+
+       rrcache_totalused = m->rrcache_totalused;
+       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+               {
+               while (m->rrcache_hash[slot])
+                       {
+                       CacheGroup *cg = m->rrcache_hash[slot];
+                       while (cg->members)
+                               {
+                               CacheRecord *cr = cg->members;
+                               cg->members = cg->members->next;
+                               if (cr->CRActiveQuestion) rrcache_active++;
+                               ReleaseCacheRecord(m, cr);
+                               }
+                       cg->rrcache_tail = &cg->members;
+                       ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
+                       }
+               }
+       debugf("mDNS_StartExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
+       if (rrcache_active != m->rrcache_active)
+               LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
+
+       for (rr = m->ResourceRecords; rr; rr = rr->next)
+               LogMsg("mDNS_FinalExit failed to send goodbye for: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
+
+       for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
+               LogMsg("mDNS_FinalExit failed to deregister service: %##s", srs->RR_SRV.resrec.name->c);
+
+       LogOperation("mDNS_FinalExit: done");
        }
index e5ad7d088cd56ed218646a083b57b231c4ec490f..81bcedbc84c7b9f33d83eef104e56fd609b3d50c 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNSDebug.h,v $
+Revision 1.38  2007/12/13 20:27:07  cheshire
+Remove unused VerifySameNameAssumptions symbol
+
+Revision 1.37  2007/12/01 00:33:17  cheshire
+Fixes from Bob Bradley for building on EFI
+
 Revision 1.36  2007/10/01 19:06:19  cheshire
 Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at
 
@@ -140,14 +146,39 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
        extern "C" {
 #endif
 
+// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing.
+
+#if (defined(__GNUC__))
+       #if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 2)))
+               #define MDNS_C99_VA_ARGS                1
+               #define MDNS_GNU_VA_ARGS                0
+       #else
+               #define MDNS_C99_VA_ARGS                0
+               #define MDNS_GNU_VA_ARGS                1
+       #endif
+       #define MDNS_HAS_VA_ARG_MACROS          1
+#elif (_MSC_VER >= 1400) // Visual Studio 2005 and later
+       #define MDNS_C99_VA_ARGS                        1
+       #define MDNS_GNU_VA_ARGS                        0
+       #define MDNS_HAS_VA_ARG_MACROS          1
+#elif (defined(__MWERKS__))
+       #define MDNS_C99_VA_ARGS                        1
+       #define MDNS_GNU_VA_ARGS                        0
+       #define MDNS_HAS_VA_ARG_MACROS          1
+#else
+       #define MDNS_C99_VA_ARGS                        0
+       #define MDNS_GNU_VA_ARGS                        0
+       #define MDNS_HAS_VA_ARG_MACROS          0
+#endif
+
 #if MDNS_DEBUGMSGS
 #define debugf debugf_
 extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #else // If debug breaks are off, use a preprocessor trick to optimize those calls out of the code
-       #if (defined(__GNUC__))
+       #if (MDNS_C99_VA_ARGS)
+               #define debugf( ... ) ((void)0)
+       #elif (MDNS_GNU_VA_ARGS)
                #define debugf( ARGS... ) ((void)0)
-       #elif (defined(__MWERKS__))
-               #define debugf( ... )
        #else
                #define debugf 1 ? ((void)0) : (void)
        #endif
@@ -157,10 +188,10 @@ extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #define verbosedebugf verbosedebugf_
 extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #else
-       #if (defined(__GNUC__))
+       #if (MDNS_C99_VA_ARGS)
+               #define verbosedebugf( ... ) ((void)0)
+       #elif (MDNS_GNU_VA_ARGS)
                #define verbosedebugf( ARGS... ) ((void)0)
-       #elif (defined(__MWERKS__))
-               #define verbosedebugf( ... )
        #else
                #define verbosedebugf 1 ? ((void)0) : (void)
        #endif
@@ -216,8 +247,6 @@ extern void udns_validatelists(void *const v);
 
 #define ForceAlerts 0
 
-#define VerifySameNameAssumptions 0
-
 #ifdef __cplusplus
        }
 #endif
index 8673da9c4f58da4657dee7358c1f42c4f922ef84..a67e1f37bfe182444630f55dc33388bd2bb92310 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNSEmbeddedAPI.h,v $
+Revision 1.463  2007/12/17 23:53:25  cheshire
+Added DNSDigest_SignMessageHostByteOrder, for signing messages not yet converted to network byte order
+
+Revision 1.462  2007/12/17 23:48:29  cheshire
+DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter
+
+Revision 1.461  2007/12/15 00:18:51  cheshire
+Renamed question->origLease to question->ReqLease
+
+Revision 1.460  2007/12/14 23:55:28  cheshire
+Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
+
+Revision 1.459  2007/12/07 22:40:34  cheshire
+Rename 'LocalAnswer' to more descriptive 'AnsweredLocalQ'
+
+Revision 1.458  2007/12/07 00:45:58  cheshire
+<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
+
+Revision 1.457  2007/12/06 00:22:27  mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
+Revision 1.456  2007/12/05 01:45:35  cheshire
+Renamed markedForDeletion -> MarkedForDeletion
+
+Revision 1.455  2007/12/01 01:21:27  jgraessley
+<rdar://problem/5623140> mDNSResponder unicast DNS improvements
+
+Revision 1.454  2007/12/01 00:34:03  cheshire
+Fixes from Bob Bradley for building on EFI
+
 Revision 1.453  2007/10/29 23:51:22  cheshire
 Added comment about NATTraversalInfo ExternalAddress field
 
@@ -605,13 +635,15 @@ Fixes to avoid code generation warning/error on FreeBSD 7
 #ifndef __mDNSClientAPI_h
 #define __mDNSClientAPI_h
 
-#if defined(EFI32) || defined(EFI64)
-// EFI doesn't have stdarg.h
+#if defined(EFI32) || defined(EFI64) || defined(EFIX64)
+// EFI doesn't have stdarg.h unless it's building with GCC.
 #include "Tiano.h"
+#if !defined(__GNUC__)
 #define va_list         VA_LIST
 #define va_start(a, b)  VA_START(a, b)
 #define va_end(a)       VA_END(a)
 #define va_arg(a, b)    VA_ARG(a, b)
+#endif
 #else
 #include <stdarg.h>            // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
 #endif
@@ -921,6 +953,21 @@ typedef struct { mDNSu8 c[256]; } UTF8str255;              // Null-terminated C string
 
 #define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL)
 
+typedef struct AuthRecord_struct AuthRecord;
+typedef struct ServiceRecordSet_struct ServiceRecordSet;
+typedef struct CacheRecord_struct CacheRecord;
+typedef struct CacheGroup_struct CacheGroup;
+typedef struct DNSQuestion_struct DNSQuestion;
+typedef struct ZoneData_struct ZoneData;
+typedef struct mDNS_struct mDNS;
+typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
+typedef struct NATTraversalInfo_struct NATTraversalInfo;
+
+// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets
+// The actual definition of these structures in the in the appropriate platform support code
+typedef struct TCPSocket_struct TCPSocket;
+typedef struct UDPSocket_struct UDPSocket;
+
 // ***************************************************************************
 #if 0
 #pragma mark - DNS Message structures
@@ -951,6 +998,23 @@ typedef packedstruct
        mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000
        } DNSMessage;
 
+typedef struct tcpInfo_t
+       {
+       mDNS             *m;
+       TCPSocket        *sock;
+       DNSMessage        request;
+       int               requestLen;
+       DNSQuestion      *question;   // For queries
+       ServiceRecordSet *srs;        // For service record updates
+       AuthRecord       *rr;         // For record updates
+       mDNSAddr          Addr;
+       mDNSIPPort        Port;
+       DNSMessage       *reply;
+       mDNSu16           replylen;
+       unsigned long     nread;
+       int               numReplies;
+       } tcpInfo_t;
+
 // ***************************************************************************
 #if 0
 #pragma mark - Resource Record structures
@@ -1120,16 +1184,7 @@ typedef struct
        } RData;
 #define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody))
 
-typedef struct AuthRecord_struct AuthRecord;
-typedef struct CacheRecord_struct CacheRecord;
-typedef struct CacheGroup_struct CacheGroup;
-typedef struct DNSQuestion_struct DNSQuestion;
-typedef struct ZoneData_struct ZoneData;
-typedef struct mDNS_struct mDNS;
-typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
-typedef struct NATTraversalInfo_struct NATTraversalInfo;
-
-// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
+// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
 typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
 
 // Note:
@@ -1149,11 +1204,6 @@ typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData
 #define NATMAP_DEFAULT_LEASE (60 * 60)                             // lease life in seconds
 #define NATMAP_VERS 0
 
-// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets
-// The actual definition of these structures in the in the appropriate platform support code
-typedef struct TCPSocket_struct TCPSocket;
-typedef struct UDPSocket_struct UDPSocket;
-
 typedef enum
        {
        NATOp_AddrRequest    = 0,
@@ -1361,7 +1411,7 @@ struct AuthRecord_struct
        mDNSu8          ProbeCount;                     // Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
        mDNSu8          AnnounceCount;          // Number of announcements remaining (kDNSRecordTypeShared)
        mDNSu8          RequireGoodbye;         // Set if this RR has been announced on the wire and will require a goodbye packet
-       mDNSu8          LocalAnswer;            // Set if this RR has been delivered to LocalOnly questions
+       mDNSu8          AnsweredLocalQ;         // Set if this RR has been delivered to LocalOnly questions
        mDNSu8          IncludeInProbe;         // Set if this RR is being put into a probe right now
        mDNSInterfaceID ImmedAnswer;            // Someone on this interface issued a query we need to answer (all-ones for all interfaces)
        mDNSu8          ImmedUnicast;           // Set if we may send our response directly via unicast to the requester
@@ -1427,7 +1477,7 @@ struct AuthRecord_struct
 typedef struct ARListElem
        {
        struct ARListElem *next;
-       AuthRecord ar;          // Note: Must be last struct in field to accomodate oversized AuthRecords
+       AuthRecord ar;          // Note: Must be last element of structure, to accomodate oversized AuthRecords
        } ARListElem;
 
 struct CacheGroup_struct                               // Header object for a list of CacheRecords with the same name
@@ -1493,13 +1543,19 @@ enum
        DNSServer_Disabled = 3
        };
 
+enum
+       {
+       DNSServer_FlagDelete = 1,
+       DNSServer_FlagNew    = 2
+       };
+
 typedef struct DNSServer
        {
        struct DNSServer *next;
        mDNSInterfaceID interface;      // For specialized uses; we can have DNS servers reachable over specific interfaces
        mDNSAddr        addr;
        mDNSIPPort      port;
-       mDNSBool        del;            // Set when we're planning to delete this from the list
+       mDNSu32         flags;          // Set when we're planning to delete this from the list
        mDNSu32         teststate;      // Have we sent bug-detection query to this server?
        mDNSs32         lasttest;       // Time we sent last bug-detection query to this server
        domainname      domain;         // name->server matching for "split dns"
@@ -1550,8 +1606,7 @@ struct ExtraResourceRecord_struct
        // that this extra memory is available, which would result in any fields after the AuthRecord getting smashed
        };
 
-// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
-typedef struct ServiceRecordSet_struct ServiceRecordSet;
+// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
 typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
 
 // A ServiceRecordSet is basically a convenience structure to group together
@@ -1695,7 +1750,7 @@ typedef struct DomainAuthInfo
        mDNSu8           keydata_opad[HMAC_LEN];        // padded key for outer hash rounds
        } DomainAuthInfo;
 
-// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
+// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
 typedef enum { QC_rmv = 0, QC_add = 1, QC_addnocache = 2 } QC_result;
 typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
 struct DNSQuestion_struct
@@ -1738,7 +1793,7 @@ struct DNSQuestion_struct
 
        // LLQ-specific fields. These fields are only meaningful when LongLived flag is set
        LLQ_State             state;
-       mDNSu32               origLease;                // seconds (relative)
+       mDNSu32               ReqLease;         // seconds (relative)
        mDNSs32               expire;                   // ticks (absolute)
        mDNSs16               ntries;
        mDNSOpaque64          id;
@@ -1771,7 +1826,7 @@ typedef struct
        mDNSu8          TXTinfo[2048];          // Additional demultiplexing information (e.g. LPR queue name)
        } ServiceInfo;
 
-// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
+// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
 typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
 typedef void mDNSServiceInfoQueryCallback(mDNS *const m, ServiceInfoQuery *query);
 struct ServiceInfoQuery_struct
@@ -1830,7 +1885,7 @@ typedef struct ClientTunnel
        {
        struct ClientTunnel *next;
        domainname dstname;
-       mDNSBool   markedForDeletion;
+       mDNSBool   MarkedForDeletion;
        mDNSv6Addr loc_inner;
        mDNSv4Addr loc_outer;
        mDNSv6Addr rmt_inner;
@@ -1875,7 +1930,6 @@ struct mDNS_struct
        // For debugging: To catch and report locking failures
        mDNSu32 mDNS_busy;                                      // Incremented between mDNS_Lock/mDNS_Unlock section
        mDNSu32 mDNS_reentrancy;                        // Incremented when calling a client callback
-       mDNSu8  mDNS_shutdown;                          // Set when we're shutting down, allows us to skip some unnecessary steps
        mDNSu8  lock_rrcache;                           // For debugging: Set at times when these lists may not be modified
        mDNSu8  lock_Questions;
        mDNSu8  lock_Records;
@@ -1887,6 +1941,7 @@ struct mDNS_struct
        mDNSs32  timenow;                                       // The time that this particular activation of the mDNS code started
        mDNSs32  timenow_last;                          // The time the last time we ran
        mDNSs32  NextScheduledEvent;            // Derived from values below
+       mDNSs32  ShutdownTime;                          // Set when we're shutting down, allows us to skip some unnecessary steps
        mDNSs32  SuppressSending;                       // Don't send *any* packets during this time
        mDNSs32  NextCacheCheck;                        // Next time to refresh cache record before it expires
        mDNSs32  NextScheduledQuery;            // Next time to send query in its exponential backoff sequence
@@ -1972,6 +2027,7 @@ struct mDNS_struct
        tcpLNTInfo        tcpDeviceInfo;                        // legacy NAT traversal TCP connection info for device info
        tcpLNTInfo       *tcpInfoUnmapList;                     // list of pending unmap requests
        mDNSInterfaceID   UPnPInterfaceID;
+       UDPSocket        *SSDPSocket;               // For SSDP request/response
        mDNSIPPort        UPnPRouterPort;                       // port we send discovery messages to
        mDNSIPPort        UPnPSOAPPort;                         // port we send SOAP messages to
        mDNSu8           *UPnPRouterURL;                        // router's URL string
@@ -2109,7 +2165,9 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
 // When mDNS has finished setting up the client's callback is called
 // A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError
 //
-// Call mDNS_Close to tidy up before exiting
+// Call mDNS_StartExit to tidy up before exiting
+// Because exiting may be an asynchronous process (e.g. if unicast records need to be deregistered)
+// client layer may choose to wait until mDNS_ExitNow() returns true before calling mDNS_FinalExit().
 //
 // Call mDNS_Register with a completed AuthRecord object to register a resource record
 // If the resource record type is kDNSRecordTypeUnique (or kDNSknownunique) then if a conflicting resource record is discovered,
@@ -2143,7 +2201,11 @@ extern mStatus mDNS_Init      (mDNS *const m, mDNS_PlatformSupport *const p,
 #define mDNS_Init_NoInitCallbackContext       mDNSNULL
 
 extern void    mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numrecords);
-extern void    mDNS_Close     (mDNS *const m);
+extern void    mDNS_StartExit (mDNS *const m);
+extern void    mDNS_FinalExit (mDNS *const m);
+#define mDNS_Close(m) do { mDNS_StartExit(m); mDNS_FinalExit(m); } while(0)
+#define mDNS_ExitNow(m, now) ((now) - (m)->ShutdownTime >= 0 || (!(m)->ResourceRecords && !(m)->ServiceRegistrations))
+
 extern mDNSs32 mDNS_Execute   (mDNS *const m);
 
 extern mStatus mDNS_Register  (mDNS *const m, AuthRecord *const rr);
@@ -2261,8 +2323,8 @@ extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
 // A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory,
 // because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size.
 // This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
-#define AssignDomainName(DST, SRC) do { mDNSu16 len = DomainNameLength((SRC)); \
-       if (len <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len); else (DST)->c[0] = 0; } while(0)
+#define AssignDomainName(DST, SRC) do { mDNSu16 len__ = DomainNameLength((SRC)); \
+       if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__); else (DST)->c[0] = 0; } while(0)
 
 // Comparison functions
 #define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0]))
@@ -2432,7 +2494,7 @@ extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mD
 extern void mDNS_AddSearchDomain(const domainname *const domain);
 
 #define mDNS_AddSearchDomain_CString(X) \
-       do { domainname d; if ((X) && MakeDomainNameFromDNSNameString(&d, (X)) && d.c[0]) mDNS_AddSearchDomain(&d); } while(0)
+       do { domainname d__; if ((X) && MakeDomainNameFromDNSNameString(&d__, (X)) && d__.c[0]) mDNS_AddSearchDomain(&d__); } while(0)
 
 // Routines called by the core, exported by DNSDigest.c
 
@@ -2443,7 +2505,17 @@ extern mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const
 // of the message, and is modified by this routine.  numAdditionals is a pointer to the number of additional
 // records in HOST byte order, which is incremented upon successful completion of this routine.  The function returns
 // the new end pointer on success, and NULL on failure.
-extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode);
+extern void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode);
+
+#define SwapDNSHeaderBytes(M) do { \
+    (M)->h.numQuestions   = (mDNSu16)((mDNSu8 *)&(M)->h.numQuestions  )[0] << 8 | ((mDNSu8 *)&(M)->h.numQuestions  )[1]; \
+    (M)->h.numAnswers     = (mDNSu16)((mDNSu8 *)&(M)->h.numAnswers    )[0] << 8 | ((mDNSu8 *)&(M)->h.numAnswers    )[1]; \
+    (M)->h.numAuthorities = (mDNSu16)((mDNSu8 *)&(M)->h.numAuthorities)[0] << 8 | ((mDNSu8 *)&(M)->h.numAuthorities)[1]; \
+    (M)->h.numAdditionals = (mDNSu16)((mDNSu8 *)&(M)->h.numAdditionals)[0] << 8 | ((mDNSu8 *)&(M)->h.numAdditionals)[1]; \
+    } while (0)
+
+#define DNSDigest_SignMessageHostByteOrder(M,E,INFO) \
+       do { SwapDNSHeaderBytes(M); DNSDigest_SignMessage((M), (E), (INFO), 0); SwapDNSHeaderBytes(M); } while (0)
 
 // verify a DNS message.  The message must be complete, with all values in network byte order.  end points to the
 // end of the record.  tsig is a pointer to the resource record that contains the TSIG OPT record.  info is
@@ -2510,10 +2582,15 @@ extern mDNSs32  mDNSPlatformRawTime     (void);
 extern mDNSs32  mDNSPlatformUTC         (void);
 #define mDNS_TimeNow_NoLock(m) (mDNSPlatformRawTime() + m->timenow_adjust)
 
+#if MDNS_DEBUGMSGS
+extern void    mDNSPlatformWriteDebugMsg(const char *msg);
+#endif
+extern void    mDNSPlatformWriteLogMsg(const char *ident, const char *msg, int flags);
+
 // Platform support modules should provide the following functions to map between opaque interface IDs
 // and interface indexes in order to support the DNS-SD API. If your target platform does not support
 // multiple interfaces and/or does not support the DNS-SD API, these functions can be empty.
-extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index);
+extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex);
 extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id);
 
 // Every platform support module must provide the following functions if it is to support unicast DNS
index d6fddfa1b4a4e8b439c0652c398d6129aa0b47c4..bcf8ddffae6c1c7c44da7c7454a24ef31a75bfe8 100755 (executable)
        Change History (most recent first):
 
 $Log: uDNS.c,v $
+Revision 1.545  2007/12/22 02:25:29  cheshire
+<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
+
+Revision 1.544  2007/12/18 00:40:11  cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+Reordered code to avoid double-TSIGs in some cases
+
+Revision 1.543  2007/12/17 23:57:43  cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+Need to include TSIG signature when sending LLQ cancellations over TLS
+
+Revision 1.542  2007/12/15 01:12:27  cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+
+Revision 1.541  2007/12/15 00:18:51  cheshire
+Renamed question->origLease to question->ReqLease
+
+Revision 1.540  2007/12/14 23:55:28  cheshire
+Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
+
+Revision 1.539  2007/12/14 20:44:24  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records
+
+Revision 1.538  2007/12/14 01:13:40  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+Additional fixes (existing code to deregister private records and services didn't work at all)
+
+Revision 1.537  2007/12/11 00:18:25  cheshire
+<rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it
+There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it.
+
+Revision 1.536  2007/12/10 23:07:00  cheshire
+Removed some unnecessary log messages
+
+Revision 1.535  2007/12/06 00:22:27  mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
+Revision 1.534  2007/12/04 00:49:37  cheshire
+<rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
+
+Revision 1.533  2007/12/01 01:21:27  jgraessley
+<rdar://problem/5623140> mDNSResponder unicast DNS improvements
+
+Revision 1.532  2007/11/30 20:16:44  cheshire
+Fixed compile warning: declaration of 'end' shadows a previous local
+
+Revision 1.531  2007/11/28 22:00:09  cheshire
+In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
+
+Revision 1.530  2007/11/16 22:19:40  cheshire
+<rdar://problem/5547474> mDNSResponder leaks on network changes
+The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created
+
+Revision 1.529  2007/11/15 22:52:29  cheshire
+<rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
+
 Revision 1.528  2007/11/02 21:32:30  cheshire
 <rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
 
@@ -1044,23 +1101,6 @@ Revision 1.227  2006/01/09 20:47:05  cheshire
        #pragma warning(disable:4706)
 #endif
 
-typedef struct tcpInfo_t
-       {
-       mDNS             *m;
-       TCPSocket        *sock;
-       DNSMessage        request;
-       int               requestLen;
-       DNSQuestion      *question;   // For queries
-       ServiceRecordSet *srs;        // For service record updates
-       AuthRecord       *rr;         // For record updates
-       mDNSAddr          Addr;
-       mDNSIPPort        Port;
-       DNSMessage       *reply;
-       mDNSu16           replylen;
-       unsigned long     nread;
-       int               numReplies;
-       } tcpInfo_t;
-
 typedef struct SearchListElem
        {
        struct SearchListElem *next;
@@ -1086,7 +1126,7 @@ static SearchListElem *SearchList = mDNSNULL;
 // -- it should just be a grouping of records that are treated the same as any other registered records.
 // In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
 // would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
-static ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
+ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -1175,6 +1215,7 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
        if (rr->ThisAPInterval / 2 <= elapsed) rr->ThisAPInterval *= 2;
        if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL || SendErr == mStatus_TransientErr)
                rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
+       rr->ThisAPInterval += mDNSRandom(rr->ThisAPInterval/20);
        if (rr->ThisAPInterval > 30 * 60 * mDNSPlatformOneSecond)
                rr->ThisAPInterval = 30 * 60 * mDNSPlatformOneSecond;
 
@@ -1201,8 +1242,8 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
                if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
                        mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
                        {
-                       if (!(*p)->del) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
-                       (*p)->del = mDNSfalse;
+                       if (!((*p)->flags & DNSServer_FlagDelete)) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
+                       (*p)->flags &= ~DNSServer_FlagDelete;
                        return(*p);
                        }
                p=&(*p)->next;
@@ -1216,7 +1257,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
                (*p)->interface = interface;
                (*p)->addr      = *addr;
                (*p)->port      = port;
-               (*p)->del       = mDNSfalse;
+               (*p)->flags     = DNSServer_FlagNew;
                (*p)->teststate = DNSServer_Untested;
                (*p)->lasttest  = m->timenow - INIT_UCAST_POLL_INTERVAL;
                AssignDomainName(&(*p)->domain, d);
@@ -1662,7 +1703,7 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
                llqBuf.llqOp    = kLLQOp_Setup;
                llqBuf.err      = LLQErr_NoError;       // Don't need to tell server UDP notification port when sending over UDP
                llqBuf.id       = q->id;
-               llqBuf.llqlease = q->origLease;
+               llqBuf.llqlease = q->ReqLease;
                llq = &llqBuf;
                }
 
@@ -1676,14 +1717,22 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
        InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
        responsePtr = putQuestion(&m->omsg, responsePtr, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
        if (responsePtr) responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse);
-       if (responsePtr) mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
+       if (responsePtr)
+               {
+               mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
+               if (err)
+                       {
+                       LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
+                       if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
+                       }
+               }
        else StartLLQPolling(m,q);
        }
 
 mDNSlocal void SetLLQTimer(mDNS *const m, DNSQuestion *const q, const LLQOptData *const llq)
        {
        mDNSs32 lease = (mDNSs32)llq->llqlease * mDNSPlatformOneSecond;
-       q->origLease     = llq->llqlease;
+       q->ReqLease      = llq->llqlease;
        q->LastQTime     = m->timenow;
        q->expire        = m->timenow + lease;
        q->ThisQInterval = lease/2 + mDNSRandom(lease/10);
@@ -1707,11 +1756,11 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const
 
                if (llq->err) { LogMsg("recvSetupResponse - received llq->err %d from server", llq->err); StartLLQPolling(m,q); return; }
        
-               if (q->origLease != llq->llqlease)
-                       debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->origLease, llq->llqlease);
+               if (q->ReqLease != llq->llqlease)
+                       debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->ReqLease, llq->llqlease);
        
                // cache expiration in case we go to sleep before finishing setup
-               q->origLease = llq->llqlease;
+               q->ReqLease = llq->llqlease;
                q->expire = m->timenow + ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond);
        
                // update state
@@ -1825,33 +1874,43 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
        {
        tcpInfo_t *tcpInfo = (tcpInfo_t *)context;
        mDNSBool   closed  = mDNSfalse;
-       mDNSu8    *end;
        mDNS      *m       = tcpInfo->m;
-
+       DNSQuestion *const q = tcpInfo->question;
        tcpInfo_t **backpointer =
-               tcpInfo->question ? &tcpInfo->question->tcp :
+               q                 ? &q           ->tcp :
                tcpInfo->srs      ? &tcpInfo->srs->tcp :
-               tcpInfo->rr       ? &tcpInfo->rr->tcp : mDNSNULL;
-       if (!backpointer) LogMsg("tcpCallback: Purpose of connection unidentified");
-       else if (*backpointer != tcpInfo)
+               tcpInfo->rr       ? &tcpInfo->rr ->tcp : mDNSNULL;
+       if (backpointer && *backpointer != tcpInfo)
                LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
-                       mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, tcpInfo->question, tcpInfo->srs, tcpInfo->rr);
+                       mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, q, tcpInfo->srs, tcpInfo->rr);
 
        if (err) goto exit;
 
        if (ConnectionEstablished)
                {
+               mDNSu8    *end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
                DomainAuthInfo *AuthInfo;
+
+               // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
+               // Don't know yet what's causing this, but at least we can be cautious and try to avoid crashing if we find our pointers in an unexpected state
+               if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage)
+                       LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
+                               tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage);
+               if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage)
+                       LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
+                               tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage);
+               if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return;
+               if (tcpInfo->rr  && tcpInfo->rr->        resrec.name != &tcpInfo->rr->        namestorage) return;
+
+               AuthInfo =  tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
+                                       tcpInfo->rr  ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name)         : mDNSNULL;
+
                // connection is established - send the message
-               if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state == LLQ_Established)
+               if (q && q->LongLived && q->state == LLQ_Established)
                        {
-                       //LogMsg("tcpCallback calling sendLLQRefresh %##s (%s)", tcpInfo->question->qname.c, DNSTypeName(tcpInfo->question->qtype));
-                       mDNS_Lock(m);
-                       sendLLQRefresh(m, tcpInfo->question, tcpInfo->question->origLease);
-                       mDNS_Unlock(m);
-                       return;
+                       end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
                        }
-               else if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
+               else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
                        {
                        // Notes:
                        // If we have a NAT port mapping, ExternalPort is the external port
@@ -1864,45 +1923,28 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                        LogOperation("tcpCallback: eventPort %d", llqData.err);
                        llqData.id    = zeroOpaque64;
                        llqData.llqlease = kLLQ_DefLease;
-                       InitializeDNSMessage(&tcpInfo->request.h, tcpInfo->question->TargetQID, uQueryFlags);
-                       end = putLLQ(&tcpInfo->request, tcpInfo->request.data, tcpInfo->question, &llqData, mDNStrue);
+                       InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
+                       end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData, mDNStrue);
                        if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; }
+                       AuthInfo = q->AuthInfo;         // Need to add TSIG to this message
                        }
-               else if (tcpInfo->question)
+               else if (q)
                        {
-                       DNSQuestion *q = tcpInfo->question;
                        InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags);
                        end = putQuestion(&tcpInfo->request, tcpInfo->request.data, tcpInfo->request.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
+                       AuthInfo = q->AuthInfo;         // Need to add TSIG to this message
                        }
-               else
-                       end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
-
-               // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
-               // Don't know yet what's causing this, but at least we can be cautious and try to avoid crashing if we find our pointers in an unexpected state
-               if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage)
-                       LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
-                               tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage);
-               if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage)
-                       LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
-                               tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage);
-               if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return;
-               if (tcpInfo->rr  && tcpInfo->rr->        resrec.name != &tcpInfo->rr->        namestorage) return;
-
-               AuthInfo =      tcpInfo->question ? tcpInfo->question->AuthInfo :
-                                       tcpInfo->srs      ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
-                                       tcpInfo->rr       ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL;
 
                err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
-
                if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; }
 
                // Record time we sent this question
-               if (tcpInfo->question)
+               if (q)
                        {
                        mDNS_Lock(m);
-                       tcpInfo->question->LastQTime = m->timenow;
-                       tcpInfo->question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
-                       SetNextQueryTime(m, tcpInfo->question);
+                       q->LastQTime = m->timenow;
+                       q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+                       SetNextQueryTime(m, q);
                        mDNS_Unlock(m);
                        }
                }
@@ -1920,7 +1962,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                                // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
                                // We'll only log this event if we've never received a reply before.
                                // BIND 9 appears to close an idle connection after 30 seconds.
-                               if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread);
+                               if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely tcpInfo->nread = %d", tcpInfo->nread);
                                err = mStatus_ConnFailed;
                                goto exit;
                                }
@@ -1956,7 +1998,11 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                        tcpInfo->replylen = 0;
                        
                        // If we're going to dispose this connection, do it FIRST, before calling client callback
-                       if (!tcpInfo->question || !tcpInfo->question->LongLived) { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
+                       // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp
+                       // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep
+                       if (backpointer)
+                               if (!q || !q->LongLived || m->SleepState)
+                                       { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
                        
                        if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                                {
@@ -1980,13 +2026,12 @@ exit:
                {
                // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
                // we won't end up double-disposing our tcpInfo_t
-               *backpointer = mDNSNULL;
+               if (backpointer) *backpointer = mDNSNULL;
 
                mDNS_Lock(m);           // Need to grab the lock to get m->timenow
 
-               if (tcpInfo->question)
+               if (q)
                        {
-                       DNSQuestion *q = tcpInfo->question;
                        if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL)
                                {
                                q->LastQTime     = m->timenow;
@@ -1995,7 +2040,10 @@ exit:
                                }
                        // ConnFailed is actually okay.  It just means that the server closed the connection but the LLQ is still okay.
                        // If the error isn't ConnFailed, then the LLQ is in bad shape.
-                       if (err != mStatus_ConnFailed) StartLLQPolling(m, tcpInfo->question);
+                       if (err != mStatus_ConnFailed)
+                               {
+                               if (q->LongLived && q->state != LLQ_Poll) StartLLQPolling(m, q);
+                               }
                        }
 
                if (tcpInfo->rr) SetRecordRetry(m, tcpInfo->rr, mStatus_NoError);
@@ -2016,21 +2064,27 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
        mDNSIPPort srcport = zeroIPPort;
        tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
        if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
-
        mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
+
        info->m          = m;
-       if (msg)
-               {
-               info->request    = *msg;
-               info->requestLen = (int) (end - ((mDNSu8*)msg));
-               }
+       info->sock       = mDNSPlatformTCPSocket(m, flags, &srcport);
+       info->requestLen = 0;
        info->question   = question;
        info->srs        = srs;
        info->rr         = rr;
        info->Addr       = *Addr;
        info->Port       = Port;
+       info->reply      = mDNSNULL;
+       info->replylen   = 0;
+       info->nread      = 0;
+       info->numReplies = 0;
+
+       if (msg)
+               {
+               info->requestLen = (int) (end - ((mDNSu8*)msg));
+               mDNSPlatformMemCopy(&info->request, msg, info->requestLen);
+               }
 
-       info->sock = mDNSPlatformTCPSocket(m, flags, &srcport);
        if (!info->sock) { LogMsg("SendServiceRegistration: uanble to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
        err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info);
 
@@ -2042,7 +2096,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
 
        // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
        if      (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); }
-       else if (err != mStatus_ConnPending    ) { LogOperation("MakeTCPConnection: connection failed"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+       else if (err != mStatus_ConnPending    ) { LogOperation("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); }
        return(info);
        }
 
@@ -2095,7 +2149,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
                else
                        {
                        q->state         = LLQ_SecondaryRequest;                // Right now, for private DNS, we skip the four-way LLQ handshake
-                       q->origLease     = kLLQ_DefLease;
+                       q->ReqLease      = kLLQ_DefLease;
                        q->ThisQInterval = 0;
                        }
                q->LastQTime     = m->timenow;
@@ -2133,7 +2187,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
        
                        // update question state
                        q->state         = LLQ_InitialRequest;
-                       q->origLease     = kLLQ_DefLease;
+                       q->ReqLease      = kLLQ_DefLease;
                        q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
                        q->LastQTime     = m->timenow;
                        SetNextQueryTime(m, q);
@@ -2303,11 +2357,9 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
        return;
 
 exit:
-
        if (err)
                {
                LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
-
                unlinkSRS(m, srs);
                srs->state = regState_Unregistered;
 
@@ -2405,6 +2457,16 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
                mDNS_StopQuery(m, question);
                zd->Addr.type  = mDNSAddrType_IPv4;
                zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr;
+               // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets,
+               // the code below will make us try to connect to loopback, resulting in an immediate "port unreachable" failure.
+               // This helps us test to make sure we handle this case gracefully
+               // <rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
+#if 0
+               zd->Addr.ip.v4.b[0] = 127;
+               zd->Addr.ip.v4.b[1] = 0;
+               zd->Addr.ip.v4.b[2] = 0;
+               zd->Addr.ip.v4.b[3] = 1;
+#endif
                zd->ZoneDataCallback(m, mStatus_NoError, zd);
                mDNSPlatformMemFree(zd);
                }
@@ -2509,7 +2571,7 @@ mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
 
 mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
        {
-       mDNSu8 *p = srs->RR_PTR.resrec.name->c;
+       const mDNSu8 *p = srs->RR_PTR.resrec.name->c;
        if (p[0]) p += 1 + p[0];
        if      (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP;
        else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP;
@@ -2528,29 +2590,29 @@ mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
 mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
        {
        ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext;
-       
+
        if (m->mDNS_busy != m->mDNS_reentrancy)
                LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
        srs->nta = mDNSNULL;
 
+       // Start off assuming we're going to use a lease
+       // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option
+       srs->srs_uselease = mDNStrue;
+
        if (err || !zoneData) return;
 
+       if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) return;
+
        // cache zone data
        AssignDomainName(&srs->zone, &zoneData->ZoneName);
        srs->SRSUpdateServer.type = mDNSAddrType_IPv4;
        srs->SRSUpdateServer      = zoneData->Addr;
-       if (!mDNSIPPortIsZero(zoneData->Port))
-               {
-               srs->SRSUpdatePort = zoneData->Port;
-               srs->Private       = zoneData->ZonePrivate;
-               }
-       else
-               {
-               debugf("Update port not advertised via SRV - guessing port 53, no lease option");
-               srs->SRSUpdatePort = UnicastDNSPort;
-               srs->srs_uselease = mDNSfalse;
-               }
+       srs->SRSUpdatePort        = zoneData->Port;
+       srs->Private              = zoneData->ZonePrivate;
+
+       srs->RR_SRV.LastAPTime     = m->timenow;
+       srs->RR_SRV.ThisAPInterval = 0;
 
        LogOperation("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
                &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC1918)" : "",
@@ -2603,9 +2665,11 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
 
        srs->id    = id;
        srs->state = regState_DeregPending;
+       srs->RR_SRV.expire = 0;         // Indicate that we have no active registration any more
 
        if (srs->Private)
                {
+               LogOperation("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
                if (srs->tcp) LogOperation("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
                if (srs->tcp) DisposeTCPConn(srs->tcp);
                srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
@@ -2622,7 +2686,6 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
        return;
 
 exit:
-
        if (err)
                {
                LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
@@ -2729,6 +2792,9 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
 // Called with lock held
 mDNSlocal void UpdateSRVRecords(mDNS *m)
        {
+       LogOperation("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : "");
+       if (m->SleepState) return;
+
        if (CurrentServiceRecordSet)
                LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
        CurrentServiceRecordSet = m->ServiceRegistrations;
@@ -2763,7 +2829,7 @@ mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
                        }
                else
                        {
-                       LogMsg("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress);
+                       LogOperation("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress);
                        h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
                        h->arv4.resrec.rdata->u.ipv4 = n->ExternalAddress;
                        mDNS_Register(m, &h->arv4);
@@ -2794,7 +2860,7 @@ mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
                        }
                else
                        {
-                       LogMsg("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4);
+                       LogOperation("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4);
                        h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
                        mDNS_Register_internal(m, &h->arv4);
                        }
@@ -2806,7 +2872,7 @@ mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
                AssignDomainName(&h->arv6.namestorage, &h->fqdn);
                h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6;
                h->arv6.state = regState_Unregistered;
-               LogMsg("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
+               LogOperation("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
                mDNS_Register_internal(m, &h->arv6);
                }
        }
@@ -2868,9 +2934,9 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res
        // Deliver success to client
        if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
        if (rr->resrec.rrtype == kDNSType_A)
-               LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
+               LogOperation("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
        else
-               LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
+               LogOperation("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
 
        rr->RecordContext = (void *)hi->StatusContext;
        if (hi->StatusCallback)
@@ -2896,7 +2962,7 @@ mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const R
                                h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending)
                                {
                                // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds
-                               m->NextSRVUpdate = NonZeroTime(m->timenow + (5 * mDNSPlatformOneSecond));
+                               m->NextSRVUpdate = NonZeroTime(m->timenow + 5 * mDNSPlatformOneSecond);
                                return;
                                }
                        h = h->next;
@@ -3268,6 +3334,8 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs,  mSt
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
                LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
+       LogOperation("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c);
+
        SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
 
        switch (srs->state)
@@ -3360,11 +3428,13 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs,  mSt
                                txt->InFlightRData = mDNSNULL;
                                }
                        break;
+               case regState_NoTarget:
+                       // This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
+                       return;
                case regState_FetchingZoneData:
                case regState_Registered:
                case regState_Unregistered:
                case regState_NATMap:
-               case regState_NoTarget:
                case regState_ExtraQueued:
                case regState_NATError:
                        LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld.  Unlinking.",
@@ -3457,6 +3527,10 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
                LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
+       LogOperation("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr));
+
+       if (m->SleepState) return;              // If we just sent a deregister on going to sleep, no further action required
+
        SetRecordRetry(m, rr, mStatus_NoError);
 
        if (rr->state == regState_UpdatePending)
@@ -3497,8 +3571,8 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                {
                if (!err)
                        {
-                       rr->state = regState_Registered;
                        if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse;
+                       rr->state = regState_Registered;
                        }
                else
                        {
@@ -3594,6 +3668,9 @@ mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interfac
                                natTraversalHandlePortMapReply(m, ptr, InterfaceID, PortMapReply->err, PortMapReply->extport, PortMapReply->NATRep_lease);
                }
        else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; }
+
+       // Don't need an SSDP socket if we get a NAT-PMP packet
+       if (m->SSDPSocket) { LogOperation("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
        }
 
 // <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
@@ -3647,16 +3724,16 @@ mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *c
        const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
        {
        const mDNSu8 *ptr = msg->data;
-       DNSQuestion q;
+       DNSQuestion pktq;
        DNSServer *s;
        mDNSu32 result = 0;
 
        // 1. Find out if this is an answer to one of our test questions
        if (msg->h.numQuestions != 1) return(mDNSfalse);
-       ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
+       ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &pktq);
        if (!ptr) return(mDNSfalse);
-       if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse);
-       if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse);
+       if (pktq.qtype != kDNSType_PTR || pktq.qclass != kDNSClass_IN) return(mDNSfalse);
+       if (!SameDomainName(&pktq.qname, DNSRelayTestQuestion)) return(mDNSfalse);
 
        // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
        // else, if the DNS relay gave us an error or no-answer response, it passed our test
@@ -3783,45 +3860,48 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
 #pragma mark - Query Routines
 #endif
 
-mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
+mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
        {
        mDNSu8 *end;
        LLQOptData llq;
-       mStatus err;
 
-       // If this is supposed to be a private question and the server dropped the TCP connection,
-       // we don't want to cancel it with a clear-text UDP packet, and and it's not worth the expense of
-       // setting up a new TLS session just to cancel the outstanding LLQ, so we just let it expire naturally
-       if (lease == 0 && q->AuthInfo && !q->tcp) return;
+       if (q->ReqLease)
+               if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
+                       {
+                       LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), LLQ_POLL_INTERVAL/3600);
+                       StartLLQPolling(m,q);
+                       return;
+                       }
 
-       if (q->AuthInfo && !q->tcp)
+       llq.vers     = kLLQ_Vers;
+       llq.llqOp    = kLLQOp_Refresh;
+       llq.err      = q->tcp ? GetLLQEventPort(m, &q->servAddr) : LLQErr_NoError;      // If using TCP tell server what UDP port to send notifications to
+       llq.id       = q->id;
+       llq.llqlease = q->ReqLease;
+
+       InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+       end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue);
+       if (!end) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
+       if (q->AuthInfo)
                {
-               //LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-               q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
-               q->LastQTime = m->timenow;
-               SetNextQueryTime(m, q);
-               return;
+               DNSDigest_SignMessageHostByteOrder(&m->omsg, &end, q->AuthInfo);
+               if (!end) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
                }
 
-       if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
+       if (q->AuthInfo && !q->tcp)
                {
-               LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), LLQ_POLL_INTERVAL/3600);
-               StartLLQPolling(m,q);
-               return;
+               LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
+               }
+       else
+               {
+               mStatus err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL);
+               if (err)
+                       {
+                       LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
+                       if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
+                       }
                }
-
-       llq.vers  = kLLQ_Vers;
-       llq.llqOp = kLLQOp_Refresh;
-       llq.err   = q->tcp ? GetLLQEventPort(m, &q->servAddr) : LLQErr_NoError; // If using TCP tell server what UDP port to send notifications to
-       llq.id    = q->id;
-       llq.llqlease = lease;
-
-       InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
-       end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue);
-       if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
-
-       err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
-       if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
 
        q->ntries++;
 
@@ -3844,7 +3924,7 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
        q->servAddr = zeroAddr;
        q->servPort = zeroIPPort;
 
-       if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port))
+       if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr))
                {
                q->servAddr = zoneInfo->Addr;
                q->servPort = zoneInfo->Port;
@@ -3917,6 +3997,10 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const
 
        newRR->nta = mDNSNULL;
 
+       // Start off assuming we're going to use a lease
+       // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option
+       newRR->uselease = mDNStrue;
+
        // make sure record is still in list (!!!)
        for (ptr = m->ResourceRecords; ptr; ptr = ptr->next) if (ptr == newRR) break;
        if (!ptr) { LogMsg("RecordRegistrationGotZoneData - RR no longer in list.  Discarding."); return; }
@@ -3959,6 +4043,8 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const
                return;
                }
 
+       newRR->ThisAPInterval = 5 * mDNSPlatformOneSecond;              // After doubling, first retry will happen after ten seconds
+
        mDNS_Lock(m);   // SendRecordRegistration expects to be called with the lock held
        SendRecordRegistration(m, newRR);
        mDNS_Unlock(m);
@@ -3988,6 +4074,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
                }
        else
                {
+               rr->expire = 0;         // Indicate that we have no active registration any more
                if (rr->Private)
                        {
                        LogOperation("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
@@ -4201,7 +4288,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                        {
                        case LLQ_InitialRequest:   startLLQHandshake(m, q); break;
                        case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break;
-                       case LLQ_Established:      sendLLQRefresh(m, q, q->origLease); break;
+                       case LLQ_Established:      sendLLQRefresh(m, q); break;
                        case LLQ_Poll:             break;       // Do nothing (handled below)
                        }
                }
@@ -4311,6 +4398,7 @@ mDNSlocal void CheckNATMappings(mDNS *m)
                {
                if (m->NATMcastRecvskt) { mDNSPlatformUDPClose(m->NATMcastRecvskt); m->NATMcastRecvskt = mDNSNULL; }
                if (m->NATMcastRecvsk2) { mDNSPlatformUDPClose(m->NATMcastRecvsk2); m->NATMcastRecvsk2 = mDNSNULL; }
+               if (m->SSDPSocket)      { LogOperation("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
                }
 
        if (m->NATTraversals)
@@ -4413,13 +4501,20 @@ mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m)
 
        for (rr = m->ResourceRecords; rr; rr = rr->next)
                {
-               if (rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending ||
+               if (rr->state == regState_FetchingZoneData ||
+                       rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending ||
                        rr->state == regState_DeregDeferred || rr->state == regState_Refresh || rr->state == regState_Registered)
                        {
                        if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0)
                                {
                                if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
-                               if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr);
+                               if (rr->state == regState_FetchingZoneData)
+                                       {
+                                       if (rr->nta) CancelGetZoneData(m, rr->nta);
+                                       rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
+                                       SetRecordRetry(m, rr, mStatus_NoError);
+                                       }
+                               else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr);
                                else SendRecordRegistration(m, rr);
                                }
                        if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0)
@@ -4442,13 +4537,20 @@ mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m)
                {
                ServiceRecordSet *srs = CurrentServiceRecordSet;
                CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
-               if (srs->state == regState_Pending || srs->state == regState_DeregPending  || srs->state == regState_DeregDeferred ||
+               if (srs->state == regState_FetchingZoneData ||
+                       srs->state == regState_Pending || srs->state == regState_DeregPending  || srs->state == regState_DeregDeferred ||
                        srs->state == regState_Refresh || srs->state == regState_UpdatePending || srs->state == regState_Registered)
                        {
                        if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow <= 0)
                                {
                                if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; }
-                               if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs);
+                               if (srs->state == regState_FetchingZoneData)
+                                       {
+                                       if (srs->nta) CancelGetZoneData(m, srs->nta);
+                                       srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
+                                       SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
+                                       }
+                               else if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs);
                                else SendServiceRegistration(m, srs);
                                }
                        if (nextevent - (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval) > 0)
@@ -4491,36 +4593,17 @@ mDNSexport void uDNS_Execute(mDNS *const m)
 
 mDNSexport void SleepRecordRegistrations(mDNS *m)
        {
-       AuthRecord *rr = m->ResourceRecords;
-
-       while (rr)
-               {
-               if (rr->state == regState_Registered ||
-                       rr->state == regState_Refresh)
-                       {
-                       SendRecordDeregistration(m, rr);
-                       rr->state = regState_Refresh;
-                       rr->LastAPTime = m->timenow;
-                       rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
-                       }
-               rr = rr->next;
-               }
-       }
-
-mDNSlocal void WakeRecordRegistrations(mDNS *m)
-       {
-       AuthRecord *rr = m->ResourceRecords;
-
-       while (rr)
-               {
-               if (rr->state == regState_Refresh)
-                       {
-                       // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
-                       rr->LastAPTime = m->timenow;
-                       rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
-                       }
-               rr = rr->next;
-               }
+       AuthRecord *rr;
+       for (rr = m->ResourceRecords; rr; rr=rr->next)
+               if (AuthRecord_uDNS(rr))
+                       if (rr->state == regState_Registered ||
+                               rr->state == regState_Refresh)
+                               {
+                               SendRecordDeregistration(m, rr);
+                               rr->state = regState_Refresh;
+                               rr->LastAPTime = m->timenow;
+                               rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
+                               }
        }
 
 mDNSexport void SleepServiceRegistrations(mDNS *m)
@@ -4528,6 +4611,7 @@ mDNSexport void SleepServiceRegistrations(mDNS *m)
        ServiceRecordSet *srs = m->ServiceRegistrations;
        while (srs)
                {
+               LogOperation("SleepServiceRegistrations: state %d %s", srs->state, ARDisplayString(m, &srs->RR_SRV));
                if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
 
                if (srs->NATinfo.clientContext)
@@ -4549,29 +4633,13 @@ mDNSexport void SleepServiceRegistrations(mDNS *m)
                        }
 
                if (srs->state == regState_Registered || srs->state == regState_Refresh)
-                       {
-                       mDNSOpaque16 origid = srs->id;
-                       srs->state = regState_DeregPending;     // state expected by SendDereg()
                        SendServiceDeregistration(m, srs);
-                       srs->id = origid;
-                       srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
-                       srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
-                       }
-               srs = srs->uDNS_next;
-               }
-       }
 
-mDNSlocal void WakeServiceRegistrations(mDNS *m)
-       {
-       ServiceRecordSet *srs = m->ServiceRegistrations;
-       while (srs)
-               {
-               if (srs->state == regState_Refresh)
-                       {
-                       // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
-                       srs->RR_SRV.LastAPTime = m->timenow;
-                       srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
-                       }
+               srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
+               srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
+               srs->SRSUpdateServer = zeroAddr;                // This will cause UpdateSRV to do a new StartGetZoneData
+               srs->RR_SRV.ThisAPInterval = 5 * mDNSPlatformOneSecond;         // After doubling, first retry will happen after ten seconds
+
                srs = srs->uDNS_next;
                }
        }
@@ -4777,12 +4845,6 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
 // 6) client calls to enumerate domains now go over LocalOnly interface
 //    (!!!KRS may add outgoing interface in addition)
 
-mDNSexport void uDNS_Wake(mDNS *const m)
-       {
-       WakeServiceRegistrations(m);
-       WakeRecordRegistrations(m);
-       }
-
 struct CompileTimeAssertionChecks_uDNS
        {
        // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
index c61e05c444cd9083d44d4baf6ce217d6f7920fe0..2676a2c19f130990141fd1954247b33cd31bb1b9 100755 (executable)
     Change History (most recent first):
 
 $Log: uDNS.h,v $
+Revision 1.90  2007/12/22 02:25:30  cheshire
+<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
+
+Revision 1.89  2007/12/15 01:12:27  cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+
 Revision 1.88  2007/10/25 20:06:13  cheshire
 Don't try to do SOA queries using private DNS (TLS over TCP) queries
 
@@ -231,9 +237,7 @@ Revision 1.33  2006/07/05 22:53:28  cheshire
 
 extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
 extern void startLLQHandshake(mDNS *m, DNSQuestion *q);
-extern void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease);
-
-extern void uDNS_Wake(mDNS *const m);
+extern void sendLLQRefresh(mDNS *m, DNSQuestion *q);
 
 extern void SleepServiceRegistrations(mDNS *m);
 extern void SleepRecordRegistrations(mDNS *m);
index 2be3dd4aff65712d037fa7cc66347571446203de..b1a23b6c3e09315dc4427ef72bf923bc8bfb6ea1 100644 (file)
@@ -17,6 +17,9 @@
     Change History (most recent first):
 
 $Log: LegacyNATTraversal.c,v $
+Revision 1.45  2007/12/06 00:22:27  mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
 Revision 1.44  2007/11/02 20:45:40  cheshire
 Don't log "connection failed" in customer builds
 
@@ -806,6 +809,9 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface
 
        if (ptr == mDNSNULL || ptr == end) return;      // not a valid message
        LogOperation("Router port %d, URL set to [%s]...", mDNSVal16(m->UPnPRouterPort), m->UPnPRouterURL);
+       
+       // Don't need the SSDP socket anymore
+       if (m->SSDPSocket) { LogOperation("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
 
        // now send message to get the device description
        GetDeviceDescription(m, &m->tcpDeviceInfo);
@@ -823,7 +829,10 @@ mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
        LogOperation("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress);
 
        if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSIPv4AddressIsZero(m->ExternalAddress))
+               {
+               if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); LogOperation("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
                mDNSPlatformSendUDP(m, msg, msg + sizeof(msg) - 1, 0, &m->Router, SSDPPort);
+               }
        }
 
 #endif /* _LEGACY_NAT_TRAVERSAL_ */
index 8e666109e9f595ff22cc0d04e7e39f6b2c68065f..412da6d315bd84cb55ed944e0742478f78cdef5e 100644 (file)
@@ -43,6 +43,9 @@
     Change History (most recent first):
 
 $Log: DNSServiceDiscoveryPref.m,v $
+Revision 1.11  2007/11/30 23:42:09  cheshire
+Fixed compile warning: declaration of 'index' shadows a global declaration
+
 Revision 1.10  2007/09/18 19:09:02  cheshire
 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
 
@@ -777,11 +780,11 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
 }
 
 
-- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index
+- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)ind
 {
     NSString *domain = nil;
-    if      ([aComboBox isEqualTo:browseDomainsComboBox]) domain = [browseDataSource objectAtIndex:index];
-    else if ([aComboBox isEqualTo:regDomainsComboBox])    domain = [registrationDataSource objectAtIndex:index];
+    if      ([aComboBox isEqualTo:browseDomainsComboBox]) domain = [browseDataSource objectAtIndex:ind];
+    else if ([aComboBox isEqualTo:regDomainsComboBox])    domain = [registrationDataSource objectAtIndex:ind];
     return domain;
 }
 
index 13552f6c5b933dde123b62ead8852ff066e463ce..01f09c5f0a0868ec9aea39d3f06a86ca285d3d36 100644 (file)
@@ -43,6 +43,9 @@
     Change History (most recent first):
 
 $Log: PrivilegedOperations.c,v $
+Revision 1.8  2007/11/30 23:42:33  cheshire
+Fixed compile warning: declaration of 'status' shadows a previous local
+
 Revision 1.7  2007/02/09 00:39:06  cheshire
 Fix compile warnings
 
@@ -146,7 +149,6 @@ OSStatus EnsureToolInstalled(void)
                        char *installerargs[] = { toolSourcePath, NULL };
                        err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL);
                        if (err == noErr) {
-                               int status;
                                int pid = wait(&status);
                                if (pid > 0 && WIFEXITED(status)) {
                                        err = WEXITSTATUS(status);
index 3f2fbbf5e78af422f755c849c2332df954cfb9db..f415180dbfc1e3e76357cadcf30b616d34444a67 100644 (file)
@@ -45,6 +45,9 @@
     Change History (most recent first):
 
 $Log: ddnswriteconfig.m,v $
+Revision 1.10  2007/11/30 23:43:04  cheshire
+Fixed compile warning: declaration of 'access' shadows a global declaration
+
 Revision 1.9  2007/09/18 19:09:02  cheshire
 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
 
@@ -313,14 +316,14 @@ MyMakeUidAccess(uid_t uid)
                0
                };
 
-       SecAccessRef access = NULL;
-       (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &access);
-       return access;
+       SecAccessRef a = NULL;
+       (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &a);
+       return a;
 }
 
 
 static OSStatus
-MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 serviceNameLength, const char *serviceName,
+MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef a, UInt32 serviceNameLength, const char *serviceName,
     UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData)
 {
        char * description       = DYNDNS_KEYCHAIN_DESCRIPTION;
@@ -340,7 +343,7 @@ MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 ser
                                      { kSecCreatorItemAttr,         creatorLength, (UInt32 *)&creator    } };
        SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
 
-       err = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, passwordLength, passwordData, keychain, access, NULL);
+       err = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, passwordLength, passwordData, keychain, a, NULL);
     return err;
 }
 
index c44edc8bd13abaad157c3a4b7861f7061f669aae..6497498b307f0e0a72952259809ec86f9afff651 100644 (file)
@@ -30,6 +30,9 @@
        Change History (most recent first):
 
 $Log: SamplemDNSClient.c,v $
+Revision 1.54  2007/11/30 23:39:55  cheshire
+Fixed compile warning: declaration of 'client' shadows a global declaration
+
 Revision 1.53  2007/09/18 19:09:02  cheshire
 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
 
@@ -111,9 +114,9 @@ static void MyHandleMachMessage(CFMachPortRef port, void *msg, CFIndex size, voi
        DNSServiceDiscovery_handleReply(msg);
        }
 
-static int AddDNSServiceClientToRunLoop(dns_service_discovery_ref client)
+static int AddDNSServiceClientToRunLoop(dns_service_discovery_ref c)
        {
-       mach_port_t port = DNSServiceDiscoveryMachPort(client);
+       mach_port_t port = DNSServiceDiscoveryMachPort(c);
        if (!port)
                return(-1);
        else
@@ -316,7 +319,7 @@ static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *cont
 int main(int argc, char **argv)
        {
        const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
-       char *dom;
+       char *d;
        setlinebuf(stdout);                             // Want to see lines as they appear, not block buffered
 
        if (argc < 2) goto Fail;                // Minimum command line is the command name and one argument
@@ -334,17 +337,17 @@ int main(int argc, char **argv)
                                        break;
 
                case 'B':       if (argc < optind+1) goto Fail;
-                                       dom = (argc < optind+2) ? "" : argv[optind+1];  // Missing domain argument is the same as empty string i.e. use system default(s)
-                                       if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
-                                       printf("Browsing for %s%s\n", argv[optind+0], dom);
-                                       client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil);
+                                       d = (argc < optind+2) ? "" : argv[optind+1];    // Missing domain argument is the same as empty string i.e. use system default(s)
+                                       if (d[0] == '.' && d[1] == 0) d[0] = 0; // We allow '.' on the command line as a synonym for empty string
+                                       printf("Browsing for %s%s\n", argv[optind+0], d);
+                                       client = DNSServiceBrowserCreate(argv[optind+0], d, browse_reply, nil);
                                        break;
 
                case 'L':       if (argc < optind+2) goto Fail;
-                                       dom = (argc < optind+3) ? "" : argv[optind+2];
-                                       if (dom[0] == '.' && dom[1] == 0) dom = "local";   // We allow '.' on the command line as a synonym for "local"
-                                       printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom);
-                                       client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil);
+                                       d = (argc < optind+3) ? "" : argv[optind+2];
+                                       if (d[0] == '.' && d[1] == 0) d = "local";   // We allow '.' on the command line as a synonym for "local"
+                                       printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], d);
+                                       client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], d, resolve_reply, nil);
                                        break;
 
                case 'R':       if (argc < optind+4) goto Fail;
index e7b7b9d0232b7ae72cd38068321e8e56d5478870..8acaf295b776a647fc5ea1539660b6bde4e1f297 100644 (file)
     Change History (most recent first):
 
 $Log: daemon.c,v $
+Revision 1.356  2007/12/18 00:28:56  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+Error in ReadyForSleep() logic -- missing "not" in "!mDNSOpaque16IsZero(q->TargetQID)"
+
+Revision 1.355  2007/12/17 22:29:22  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+Log message indicating when we make IOAllowPowerChange call; make sure nextTimerEvent is set appropriately
+
+Revision 1.354  2007/12/15 01:12:28  cheshire
+<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
+
+Revision 1.353  2007/12/14 19:14:02  cheshire
+Added (commented out) code for testing sleep/wake
+
+Revision 1.352  2007/12/14 00:58:29  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
+until TLS/TCP deregistrations have completed (up to five seconds maximum)
+
+Revision 1.351  2007/12/12 21:34:18  cheshire
+Now that <rdar://problem/5124399> "Not getting Keychain events" is apparently fixed,
+it makes sense to reduce our workaround retry count from 5 to 2 retries. Once we've
+confirmed that the bug is definitely fixed we'll remove the workaround altogether.
+
+Revision 1.350  2007/12/07 00:45:58  cheshire
+<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
+
+Revision 1.349  2007/12/04 22:00:54  cheshire
+Fixed mistake in comment
+
+Revision 1.348  2007/12/01 00:27:43  cheshire
+Fixed compile warning: declaration of 'r' shadows a previous local
+
 Revision 1.347  2007/11/02 22:00:13  cheshire
 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
 Need to hold the lock while calling SetDomainSecrets
@@ -709,9 +742,9 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
                        }
                while (x->results)
                        {
-                       DNSServiceBrowserResult *r = x->results;
+                       DNSServiceBrowserResult *t = x->results;
                        x->results = x->results->next;
-                       freeL("DNSServiceBrowserResult", r);
+                       freeL("DNSServiceBrowserResult", t);
                        }
                freeL("DNSServiceBrowser", x);
                return;
@@ -999,10 +1032,10 @@ mDNSexport void machserver_automatic_browse_domain_changed(const domainname *d,
                                        {
                                        if (SameDomainName(&(*q)->domain, d))
                                                {
-                                               DNSServiceBrowserQuestion *remove = *q;
+                                               DNSServiceBrowserQuestion *rem = *q;
                                                *q = (*q)->next;
-                                               mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q);
-                                               freeL("DNSServiceBrowserQuestion", remove );
+                                               mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q);
+                                               freeL("DNSServiceBrowserQuestion", rem);
                                                return;
                                                }
                                        q = &(*q)->next;
@@ -1111,11 +1144,11 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
 
        if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4)
                {
-               struct sockaddr_in *sin = (struct sockaddr_in*)&interface;
-               sin->sin_len         = sizeof(*sin);
-               sin->sin_family      = AF_INET;
-               sin->sin_port        = 0;
-               sin->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger;
+               struct sockaddr_in *s = (struct sockaddr_in*)&interface;
+               s->sin_len         = sizeof(*s);
+               s->sin_family      = AF_INET;
+               s->sin_port        = 0;
+               s->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger;
                }
        else if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv6)
                {
@@ -1130,11 +1163,11 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
 
        if (query->info->ip.type == mDNSAddrType_IPv4)
                {
-               struct sockaddr_in *sin = (struct sockaddr_in*)&address;
-               sin->sin_len           = sizeof(*sin);
-               sin->sin_family        = AF_INET;
-               sin->sin_port          = query->info->port.NotAnInteger;
-               sin->sin_addr.s_addr   = query->info->ip.ip.v4.NotAnInteger;
+               struct sockaddr_in *s = (struct sockaddr_in*)&address;
+               s->sin_len         = sizeof(*s);
+               s->sin_family      = AF_INET;
+               s->sin_port        = query->info->port.NotAnInteger;
+               s->sin_addr.s_addr = query->info->ip.ip.v4.NotAnInteger;
                }
        else
                {
@@ -1474,9 +1507,9 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un
 
        if (x->DefaultDomain)
                {
-               DNameListElem *ptr;
-               for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
-                       AddServiceInstance(x, &ptr->name);
+               DNameListElem *p;
+               for (p = AutoRegistrationDomains; p; p = p->next)
+                       AddServiceInstance(x, &p->name);
                }
 
        // Succeeded: Wrap up and return
@@ -1909,9 +1942,9 @@ mDNSlocal kern_return_t destroyBootstrapService()
        return bootstrap_register(server_priv_port, (char*)kmDNSBootstrapName, MACH_PORT_NULL);
        }
 
-mDNSlocal void ExitCallback(int signal)
+mDNSlocal void ExitCallback(int sig)
        {
-       (void)signal; // Unused
+       (void)sig; // Unused
        LogMsgIdent(mDNSResponderVersionString, "stopping");
 
        debugf("ExitCallback");
@@ -1928,27 +1961,27 @@ mDNSlocal void ExitCallback(int signal)
        while (DNSServiceRegistrationList)
                AbortClient(DNSServiceRegistrationList     ->ClientMachPort, DNSServiceRegistrationList);
 
-       debugf("ExitCallback: mDNS_Close");
-       mDNS_Close(&mDNSStorage);
        if (udsserver_exit(launchd_fd) < 0) LogMsg("ExitCallback: udsserver_exit failed");
-       exit(0);
+
+       debugf("ExitCallback: mDNS_StartExit");
+       mDNS_StartExit(&mDNSStorage);
        }
 
 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
-mDNSlocal void HandleSIG(int signal)
+mDNSlocal void HandleSIG(int sig)
        {
        debugf(" ");
-       debugf("HandleSIG %d", signal);
+       debugf("HandleSIG %d", sig);
        mach_msg_header_t header;
        header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
        header.msgh_remote_port = signal_port;
        header.msgh_local_port = MACH_PORT_NULL;
        header.msgh_size = sizeof(header);
-       header.msgh_id = signal;
+       header.msgh_id = sig;
        if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
                {
-               LogMsg("HandleSIG %d: mach_msg_send failed", signal);
-               if (signal == SIGTERM || signal == SIGINT) exit(-1);
+               LogMsg("HandleSIG %d: mach_msg_send failed", sig);
+               if (sig == SIGTERM || sig == SIGINT) exit(-1);
                }
        }
 
@@ -2068,7 +2101,8 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void
                case SIGINT:
                case SIGTERM:   ExitCallback(msg_header->msgh_id); break;
                case SIGINFO:   INFOCallback(); break;
-               case SIGUSR1:   LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
+               case SIGUSR1:   // mDNSCoreMachineSleep(m, !m->SleepState); break;
+                                               LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
                                                mDNSMacOSXNetworkChanged(m);
 
                                                // Simulate KeychainChanged
@@ -2156,9 +2190,9 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
        // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
        if (m->p->KeyChainBugTimer && now - m->p->KeyChainBugTimer >= 0)
                {
-               m->p->KeyChainBugTimer = NonZeroTime(now + m->p->KeyChainBugInterval);
                m->p->KeyChainBugInterval *= 2;
-               if (m->p->KeyChainBugInterval > 16 * mDNSPlatformOneSecond) m->p->KeyChainBugTimer = 0;
+               m->p->KeyChainBugTimer = NonZeroTime(now + m->p->KeyChainBugInterval);
+               if (m->p->KeyChainBugInterval > 2 * mDNSPlatformOneSecond) m->p->KeyChainBugTimer = 0;
                mDNS_Lock(m);
                SetDomainSecrets(m);
                mDNS_Unlock(m);
@@ -2263,7 +2297,7 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
 
        LogMsg("Task Scheduling Error: Continuously busy for more than a second");
        
-       // NOTE: To accurately diagnose *why* we're busy, the debugging code here to show needs to mirror the logic in GetNextScheduledEvent
+       // NOTE: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent
 
        if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
                LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
@@ -2293,12 +2327,33 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
        mDNS_Unlock(&mDNSStorage);
        }
 
+mDNSlocal mDNSBool ReadyForSleep(mDNS *m)
+       {
+       (void)m;
+
+       // 1. Scan list of private LLQs, and make sure they've all completed their handshake with the server
+       DNSQuestion *q;
+       for (q = m->Questions; q; q = q->next)
+               if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) return(mDNSfalse);
+
+       // 2. Scan list of registered records
+       AuthRecord *rr;
+       for (rr = m->ResourceRecords; rr; rr = rr->next)
+               if (rr->state == regState_Refresh && rr->tcp) return(mDNSfalse);
+
+       // 2. Scan list of registered services
+       ServiceRecordSet *srs;
+       for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
+               if (srs->state == regState_NoTarget && srs->tcp) return(mDNSfalse);
+
+       return(mDNStrue);
+       }
+
 mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context)
        {
        // Read all of the bytes so we won't wake again.
        char    buffer[100];
-       ssize_t read = sizeof(buffer);
-       while (read > 0) read = recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT);
+       while (recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT) > 0) continue;
        }
 
 mDNSlocal void * KQueueLoop(void *m_param)
@@ -2334,9 +2389,39 @@ mDNSlocal void * KQueueLoop(void *m_param)
                mDNSs32 end            = mDNSPlatformRawTime();
                if (end - start >= WatchDogReportingThreshold)
                        LogOperation("WARNING: Idle task took %dms to complete", end - start);
-               
+
+               mDNSs32 now = mDNS_TimeNow(m);
+
+               if (m->ShutdownTime)
+                       {
+                       if (mDNS_ExitNow(m, now))
+                               {
+                               LogOperation("mDNS_FinalExit");
+                               mDNS_FinalExit(&mDNSStorage);
+                               usleep(1000);           // Little 1ms pause before exiting, so we don't lose our final syslog messages
+                               exit(0);
+                               }
+                       if (nextTimerEvent - m->ShutdownTime >= 0)
+                               nextTimerEvent = m->ShutdownTime;
+                       }
+
+               if (m->p->SleepLimit)
+                       {
+                       mDNSBool ready = ReadyForSleep(m);
+                       if (ready || now - m->p->SleepLimit >= 0)
+                               {
+                               LogOperation("IOAllowPowerChange(%lX) %s at %ld (%d ticks remaining)", m->p->SleepCookie,
+                                       ready ? "ready for sleep" : "giving up", now, m->p->SleepLimit - now);
+                               m->p->SleepLimit = 0;
+                               IOAllowPowerChange(m->p->PowerConnection, m->p->SleepCookie);
+                               }
+                       else
+                               if (nextTimerEvent - m->p->SleepLimit >= 0)
+                                       nextTimerEvent = m->p->SleepLimit;
+                       }
+
                // Convert absolute wakeup time to a relative time from now
-               mDNSs32 ticks = nextTimerEvent - mDNS_TimeNow(m);
+               mDNSs32 ticks = nextTimerEvent - now;
                if (ticks < 1) ticks = 1;
                
                static mDNSs32 RepeatedBusy = 0;        // Debugging sanity check, to guard against CPU spins
@@ -2401,14 +2486,14 @@ mDNSlocal void * KQueueLoop(void *m_param)
                        for (i = 0; i < events_found; i++)
                                {
                                const KQueueEntry *const kqentry = new_events[i].udata;
-                               mDNSs32 start = mDNSPlatformRawTime();
+                               mDNSs32 stime = mDNSPlatformRawTime();
 #if LogAllOperations || MDNS_DEBUGMSGS
                                const char *const KQtask = kqentry->KQtask;     // Grab a copy in case KQcallback deletes the task
 #endif
                                kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext);
-                               mDNSs32 end   = mDNSPlatformRawTime();
-                               if (end - start >= WatchDogReportingThreshold)
-                                       LogOperation("WARNING: %s took %dms to complete", KQtask, end - start);
+                               mDNSs32 etime = mDNSPlatformRawTime();
+                               if (etime - stime >= WatchDogReportingThreshold)
+                                       LogOperation("WARNING: %s took %dms to complete", KQtask, etime - stime);
                                }
                        }
                }
index 767b1674f252509dfaef4f50373df0c612eb2124..3552c8acbca76b27009ff1734da9db50fb8cfa84 100644 (file)
     Change History (most recent first):
 
 $Log: helper-error.h,v $
+Revision 1.8  2007/11/07 00:22:30  jgraessley
+Bug #: <rdar://problem/5573573> mDNSResponder doesn't build without IPSec
+Reviewed by: Stuart Cheshire
+
 Revision 1.7  2007/09/12 00:42:47  mcguire
 <rdar://problem/5468236> BTMM: Need to clean up security associations
 
@@ -73,3 +77,4 @@ ERROR(kmDNSHelperIPsecPolicyCreationFailed,       "Could not create IPsec policy
 ERROR(kmDNSHelperIPsecPolicySetFailed,            "Could not set IPsec policy")
 ERROR(kmDNSHelperIPsecRemoveSAFailed,             "Could not remove IPsec SA")
 ERROR(kmDNSHelperIPsecPolicySocketCreationFailed, "Could not create IPsec policy socket")
+ERROR(kmDNSHelperIPsecDisabled,                   "IPSec support was not compiled in to the helper")
index 3d625ca379f5fd91175db8a2567b367f91f81b0d..e2084e08e30a23d524a8fb26d85a78b9386cee20 100644 (file)
@@ -16,6 +16,9 @@
     Change History (most recent first):
 
 $Log: helper-stubs.c,v $
+Revision 1.6  2007/12/10 23:23:48  cheshire
+Removed unnecessary log message ("mDNSKeychainGetSecrets failed 0 00000000" because mDNSKeychainGetSecrets was failing to return a valid array)
+
 Revision 1.5  2007/09/07 22:44:03  mcguire
 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
 
@@ -72,7 +75,6 @@ mDNSHelperError(int err)
        return p;
        }
 
-
 /* Ugly but handy. */
 #define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) for (;;) {
 
@@ -171,13 +173,11 @@ mDNSKeychainGetSecrets(CFArrayRef *result)
        int retry = 0;
        int err = 0;
 
-
        MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
        kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry),
            &numsecrets, (vm_offset_t *)&secrets, &secretsCnt, &err);
        MACHRETRYLOOP_END(kr, retry, err, fin);
-       if (0 == numsecrets)
-               goto fin;
+
        if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
            secrets, secretsCnt, kCFAllocatorNull)))
                {
index 72257422fe4c5113dc150366b18e1adf8c1c65ee..8f4b8f8566b14a64cee4776a1e42f234f9bbc79a 100644 (file)
     Change History (most recent first):
 
 $Log: helper.c,v $
+Revision 1.23  2007/11/30 23:21:51  cheshire
+Rename variables to eliminate "declaration of 'sin_loc' shadows a previous local" warning
+
+Revision 1.22  2007/11/27 00:08:49  jgraessley
+<rdar://problem/5613538> Interface specific resolvers not setup correctly
+
+Revision 1.21  2007/11/07 00:22:30  jgraessley
+Bug #: <rdar://problem/5573573> mDNSResponder doesn't build without IPSec
+Reviewed by: Stuart Cheshire
+
 Revision 1.20  2007/09/12 18:07:44  cheshire
 Fix compile errors ("passing argument from incompatible pointer type")
 
@@ -103,6 +113,7 @@ Revision 1.1  2007/08/08 22:34:58  mcguire
 #include <SystemConfiguration/SCDynamicStore.h>
 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
+#include <TargetConditionals.h>
 #include "mDNSEmbeddedAPI.h"
 #include "dns_sd.h"
 #include "dnssd_ipc.h"
@@ -110,8 +121,10 @@ Revision 1.1  2007/08/08 22:34:58  mcguire
 #include "helper.h"
 #include "helpermsgServer.h"
 #include "helper-server.h"
+#include "ipsec_options.h"
 
 #if TARGET_OS_EMBEDDED
+#define NO_CFUSERNOTIFICATION 1
 #define NO_SECURITYFRAMEWORK 1
 #endif
 
@@ -153,6 +166,7 @@ authorized(audit_token_t *token)
        return ok;
        }
 
+#ifndef MDNS_NO_IPSEC
 static void
 closefds(int from)
        {
@@ -175,6 +189,7 @@ closefds(int from)
                }
        closedir(dirp);
        }
+#endif
 
 kern_return_t
 do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token)
@@ -272,6 +287,7 @@ char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the use
 char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
 char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
 
+#ifndef NO_CFUSERNOTIFICATION
 static CFStringRef CFS_OQ = NULL;
 static CFStringRef CFS_CQ = NULL;
 static CFStringRef CFS_Format = NULL;
@@ -400,9 +416,11 @@ static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, con
 
        return alertHeader;
        }
+#endif /* ndef NO_CFUSERNOTIFICATION */
 
 static void update_notification(void)
        {
+#ifndef NO_CFUSERNOTIFICATION
        debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
        if (!CFS_OQ)
                {
@@ -453,6 +471,7 @@ static void update_notification(void)
                ShowNameConflictNotification(header, *subtext);
                CFRelease(header);
                }
+#endif
        }
 
 kern_return_t
@@ -874,6 +893,7 @@ fin:
 #endif
        }
 
+#ifndef MDNS_NO_IPSEC
 typedef enum _mDNSTunnelPolicyWhich
        {
        kmDNSTunnelPolicySetup,
@@ -981,11 +1001,13 @@ fin:
                close(s);
        return err;
        }
+#endif /* ifndef MDNS_NO_IPSEC */
 
 int
 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown,
     v6addr_t address, int *err, audit_token_t token)
        {
+#ifndef MDNS_NO_IPSEC
        debug("entry");
        *err = 0;
        if (!authorized(&token))
@@ -1008,10 +1030,15 @@ do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown,
        debug("succeeded");
 
 fin:
+#else
+       (void)port; (void)updown; (void)address; (void)token;
+       *err = kmDNSHelperIPsecDisabled;
+#endif
        update_idle_timer();
        return KERN_SUCCESS;
        }
 
+#ifndef MDNS_NO_IPSEC
 static const char racoon_config_path[] = "/etc/racoon/remote/anonymous.conf";
 static const char racoon_config_path_orig[] = "/etc/racoon/remote/anonymous.conf.orig";
 
@@ -1237,9 +1264,12 @@ kickRacoon(void)
        return startRacoon();
        }
 
+#endif /* ndef MDNS_NO_IPSEC */
+
 int
 do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydata, int *err, audit_token_t token)
        {
+#ifndef MDNS_NO_IPSEC
        debug("entry");
        *err = 0;
 
@@ -1271,10 +1301,16 @@ do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydat
        debug("succeeded");
 
 fin:
+#else
+       (void)port; (void)updown; (void)keydata; (void)token;
+       *err = kmDNSHelperIPsecDisabled;
+#endif
        update_idle_timer();
        return KERN_SUCCESS;
        }
 
+#ifndef MDNS_NO_IPSEC
+
 static unsigned int routeSeq = 1;
 
 static int
@@ -1532,8 +1568,8 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which,
               v6addr_t rmt_inner, uint8_t rmt_bits,
               v4addr_t rmt_outer, uint16_t rmt_port)
        {
-       struct sockaddr_in6 sin_loc;
-       struct sockaddr_in6 sin_rmt;
+       struct sockaddr_in6 sin6_loc;
+       struct sockaddr_in6 sin6_rmt;
        ipsec_policy_t policy = NULL;
        size_t len = 0;
        int s = -1;
@@ -1549,17 +1585,17 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which,
                goto fin;
                }
 
-       memset(&sin_loc, 0, sizeof(sin_loc));
-       sin_loc.sin6_len = sizeof(sin_loc);
-       sin_loc.sin6_family = AF_INET6;
-       sin_loc.sin6_port = htons(0);
-       memcpy(&sin_loc.sin6_addr, loc_inner, sizeof(sin_loc.sin6_addr));
+       memset(&sin6_loc, 0, sizeof(sin6_loc));
+       sin6_loc.sin6_len = sizeof(sin6_loc);
+       sin6_loc.sin6_family = AF_INET6;
+       sin6_loc.sin6_port = htons(0);
+       memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr));
 
-       memset(&sin_rmt, 0, sizeof(sin_rmt));
-       sin_rmt.sin6_len = sizeof(sin_rmt);
-       sin_rmt.sin6_family = AF_INET6;
-       sin_rmt.sin6_port = htons(0);
-       memcpy(&sin_rmt.sin6_addr, rmt_inner, sizeof(sin_rmt.sin6_addr));
+       memset(&sin6_rmt, 0, sizeof(sin6_rmt));
+       sin6_rmt.sin6_len = sizeof(sin6_rmt);
+       sin6_rmt.sin6_family = AF_INET6;
+       sin6_rmt.sin6_port = htons(0);
+       memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr));
 
        int setup = which != kmDNSTunnelPolicyTeardown;
 
@@ -1569,8 +1605,8 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which,
            &policy, &len)))
                goto fin;
        if (0 != (err = sendPolicy(s, setup,
-           (struct sockaddr *)&sin_rmt, rmt_bits,
-           (struct sockaddr *)&sin_loc, loc_bits,
+           (struct sockaddr *)&sin6_rmt, rmt_bits,
+           (struct sockaddr *)&sin6_loc, loc_bits,
            policy, len)))
                goto fin;
        if (NULL != policy)
@@ -1584,8 +1620,8 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which,
            &policy, &len)))
                goto fin;
        if (0 != (err = sendPolicy(s, setup,
-           (struct sockaddr *)&sin_loc, loc_bits,
-           (struct sockaddr *)&sin_rmt, rmt_bits,
+           (struct sockaddr *)&sin6_loc, loc_bits,
+           (struct sockaddr *)&sin6_rmt, rmt_bits,
            policy, len)))
                goto fin;
 
@@ -1620,12 +1656,15 @@ fin:
        return err;
        }
 
+#endif /* ndef MDNS_NO_IPSEC */
+
 int
 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
     v6addr_t loc_inner, v4addr_t loc_outer, uint16_t loc_port,
     v6addr_t rmt_inner, v4addr_t rmt_outer, uint16_t rmt_port,
     const char *keydata, int *err, audit_token_t token)
        {
+#ifndef MDNS_NO_IPSEC
        static const char config[] =
          "%s"
          "remote %s [%u] {\n"
@@ -1773,6 +1812,12 @@ fin:
        if (0 <= fd)
                close(fd);
        unlink(tmp_path);
+#else
+       (void)replacedelete; (void)loc_inner; (void)loc_outer; (void)loc_port; (void)rmt_inner;
+       (void)rmt_outer; (void)rmt_port; (void)keydata; (void)token;
+       
+       *err = kmDNSHelperIPsecDisabled;
+#endif /* MDNS_NO_IPSEC */
        update_idle_timer();
        return KERN_SUCCESS;
        }
index 5cba5efa009f222f02f9b8b22dd6f20732baca68..a1987412c20b3dfb54e7ac32b9b6a96e309a4566 100644 (file)
     Change History (most recent first):
 
 $Log: mDNSMacOSX.c,v $
+Revision 1.521  2007/12/14 00:58:28  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
+until TLS/TCP deregistrations have completed (up to five seconds maximum)
+
+Revision 1.520  2007/12/10 23:01:01  cheshire
+Remove some unnecessary log messages
+
+Revision 1.519  2007/12/06 00:22:27  mcguire
+<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+
+Revision 1.518  2007/12/05 01:52:30  cheshire
+<rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
+Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
+
+Revision 1.517  2007/12/03 18:37:26  cheshire
+Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg
+from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them
+
+Revision 1.516  2007/12/01 01:21:27  jgraessley
+<rdar://problem/5623140> mDNSResponder unicast DNS improvements
+
+Revision 1.515  2007/12/01 00:40:00  cheshire
+Add mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg abstractions, to facilitate EFI conversion
+
+Revision 1.514  2007/12/01 00:38:32  cheshire
+Fixed compile warning: declaration of 'index' shadows a global declaration
+
+Revision 1.513  2007/11/27 00:08:49  jgraessley
+<rdar://problem/5613538> Interface-specific resolvers not setup correctly
+
+Revision 1.512  2007/11/16 22:09:26  cheshire
+Added missing type information in mDNSPlatformTCPCloseConnection debugging log message
+
+Revision 1.511  2007/11/14 23:06:13  cheshire
+<rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
+
+Revision 1.510  2007/11/14 22:29:19  cheshire
+Updated comments and debugging log messages
+
+Revision 1.509  2007/11/14 01:07:53  cheshire
+Updated comments
+
 Revision 1.508  2007/11/02 21:59:37  cheshire
 Added comment about locking
 
@@ -62,7 +105,7 @@ Revision 1.496  2007/10/04 20:33:05  mcguire
 <rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
 
 Revision 1.495  2007/10/02 05:03:38  cheshire
-Fix bugus indentation in mDNSPlatformDynDNSHostNameStatusChanged
+Fix bogus indentation in mDNSPlatformDynDNSHostNameStatusChanged
 
 Revision 1.494  2007/09/29 20:40:19  cheshire
 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
@@ -670,7 +713,6 @@ Add (commented out) trigger value for testing "mach_absolute_time went backwards
 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
 #include "PlatformCommon.h"
 
-
 #include <stdio.h>
 #include <stdarg.h>                 // For va_list support
 #include <net/if.h>
@@ -699,6 +741,7 @@ Add (commented out) trigger value for testing "mach_absolute_time went backwards
 
 #if TARGET_OS_EMBEDDED
 #define NO_SECURITYFRAMEWORK 1
+#define NO_CFUSERNOTIFICATION 1
 #endif
 
 #ifndef NO_SECURITYFRAMEWORK
@@ -821,42 +864,43 @@ mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
        return ifa;
        }
 
+// To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
        {
        NetworkInterfaceInfoOSX *i;
        for (i = m->p->InterfaceList; i; i = i->next)
                if (i->Exists && !strcmp(i->ifa_name, ifname) &&
-                       ((AAAA_OVER_V4                                              ) ||
+                       ((type == AF_UNSPEC                                         ) ||
                         (type == AF_INET  && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
                         (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
        return(NULL);
        }
 
-mDNSlocal int myIfIndexToName(u_short index, char *name)
+mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
        {
        struct ifaddrs *ifa;
        for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
                if (ifa->ifa_addr->sa_family == AF_LINK)
-                       if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index)
+                       if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
                                { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
        return -1;
        }
 
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
        {
        NetworkInterfaceInfoOSX *i;
-       if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
-       if (index == kDNSServiceInterfaceIndexAny      ) return(mDNSNULL);
+       if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
+       if (ifindex == kDNSServiceInterfaceIndexAny      ) return(mDNSNULL);
 
        // Don't get tricked by inactive interfaces with no InterfaceID set
        for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
+               if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
 
        // Not found. Make sure our interface list is up to date, then try again.
-       LogOperation("InterfaceID for interface index %d not found; Updating interface list", index);
+       LogOperation("InterfaceID for interface index %d not found; Updating interface list", ifindex);
        mDNSMacOSXNetworkChanged(m);
        for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
+               if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
 
        return(mDNSNULL);
        }
@@ -901,6 +945,12 @@ mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
        return result;
        }
 
+struct UDPSocket_struct
+       {
+       mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCore expects every UDPSocket_struct to begin with mDNSIPPort port
+       KQSocketSet ss;
+       };
+
 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
 // OR send via our primary v4 unicast socket
@@ -920,11 +970,8 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
        // anonymous socket created for this purpose, so that we'll receive the response.
        // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
        if (InterfaceID && !mDNSAddrIsDNSMulticast(dst))
-               {
-               const DNSMessage *const m = (DNSMessage *)msg;
-               if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
+               if ((((DNSMessage *)msg)->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
                        LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
-               }
 
        if (dst->type == mDNSAddrType_IPv4)
                {
@@ -934,6 +981,12 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                sin_to->sin_port           = dstPort.NotAnInteger;
                sin_to->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
                s = m->p->permanentsockets.sktv4;
+
+#ifdef _LEGACY_NAT_TRAVERSAL_
+               if (m->SSDPSocket && mDNSSameIPPort(dstPort, SSDPPort))
+                       s = m->SSDPSocket->ss.sktv4;
+#endif _LEGACY_NAT_TRAVERSAL_
+
                if (info)       // Specify outgoing interface
                        {
                        if (!mDNSAddrIsDNSMulticast(dst))
@@ -1083,6 +1136,7 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
                        {
                        dstaddr->type = mDNSAddrType_IPv4;
                        dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
+                       //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
                        }
                if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
                        {
@@ -1129,7 +1183,7 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
        while (1)
                {
                mDNSAddr senderAddr, destAddr;
-               mDNSIPPort senderPort, destPort = MulticastDNSPort;
+               mDNSIPPort senderPort, destPort = (m->SSDPSocket && ss == &m->SSDPSocket->ss ? m->SSDPSocket->port : MulticastDNSPort);
                struct sockaddr_storage from;
                size_t fromlen = sizeof(from);
                char packetifname[IF_NAMESIZE] = "";
@@ -1140,10 +1194,10 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
                count++;
                if (from.ss_family == AF_INET)
                        {
-                       struct sockaddr_in *sin = (struct sockaddr_in*)&from;
+                       struct sockaddr_in *s = (struct sockaddr_in*)&from;
                        senderAddr.type = mDNSAddrType_IPv4;
-                       senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr;
-                       senderPort.NotAnInteger = sin->sin_port;
+                       senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
+                       senderPort.NotAnInteger = s->sin_port;
                        //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
                        }
                else if (from.ss_family == AF_INET6)
@@ -1318,9 +1372,9 @@ mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
 #endif /* NO_SECURITYFRAMEWORK */
                }
 
-       mDNSBool connect = !sock->connected;
+       mDNSBool c = !sock->connected;
        sock->connected = mDNStrue;
-       sock->callback(sock, sock->context, connect, err);
+       sock->callback(sock, sock->context, c, err);
        // NOTE: the callback may call CloseConnection here, which frees the context structure!
        }
 
@@ -1532,7 +1586,7 @@ mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
                        sock->fd = -1;
                        }
 
-               freeL("mDNSPlatformTCPCloseConnection", sock);
+               freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
                }
        }
 
@@ -1627,7 +1681,7 @@ mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
 
 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
-mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family)
+mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
        {
        const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
        int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
@@ -1677,6 +1731,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
                listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
                err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
                if (err) { errstr = "bind"; goto fail; }
+               if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
                }
        else if (sa_family == AF_INET6)
                {
@@ -1724,6 +1779,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
                listening_sockaddr6.sin6_scope_id    = 0;
                err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
                if (err) { errstr = "bind"; goto fail; }
+               if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
                }
 
        fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
@@ -1753,11 +1809,6 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
        return(err);
        }
 
-struct UDPSocket_struct
-       {
-       KQSocketSet ss;
-       };
-
 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port)
        {
        mStatus err;
@@ -1767,7 +1818,8 @@ mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port
        p->ss.m     = m;
        p->ss.sktv4 = -1;
        p->ss.sktv6 = -1;
-       err = SetupSocket(&p->ss, port, AF_INET);
+       p->port = zeroIPPort;
+       err = SetupSocket(&p->ss, port, AF_INET, &p->port);
        if (err)
                {
                // In customer builds we don't want to log failures with port 5351, because this is a known issue
@@ -2148,7 +2200,7 @@ mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
                err = mDNS_Register(m, &info->AutoTunnelService);
                if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
 
-               LogMsg("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
+               LogOperation("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
                        info->AutoTunnelTarget.namestorage.c,     &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort),
                        info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
                }
@@ -2208,7 +2260,7 @@ mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
        LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
                n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), m->hostlabel.c, info->domain.c);
 
-       m->NextSRVUpdate = m->timenow;
+       m->NextSRVUpdate = NonZeroTime(m->timenow);
        DeregisterAutoTunnelRecords(m,info);
        RegisterAutoTunnelRecords(m,info);
 
@@ -2247,7 +2299,7 @@ mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m)
        if (!m->AutoTunnelHostAddrActive)
                {
                m->AutoTunnelHostAddrActive = mDNStrue;
-               LogMsg("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
+               LogOperation("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
                (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
                }
 
@@ -2291,14 +2343,14 @@ mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
 
-mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
+mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
        {
        DNSQuestion *q = m->Questions;
        while (q)
                {
-               if (q->NoAnswer == NoAnswer_Suspended && q->qtype == kDNSType_AAAA && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
+               if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
                        {
-                       LogOperation("Restart %##s", q->qname.c);
+                       LogOperation("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                        mDNSQuestionCallback *tmp = q->QuestionCallback;
                        q->QuestionCallback = AutoTunnelCallback;       // Set QuestionCallback to suppress another call back to AddNewClientTunnel
                        mDNS_StopQuery(m, q);
@@ -2318,12 +2370,24 @@ mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool su
                }
        }
 
+mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
+       {
+       // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
+       //    a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
+       // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
+       //    even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
+       // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
+       ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
+       ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
+       }
+
 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
        {
        ClientTunnel **p = &m->TunnelClients;
        while (*p != tun && *p) p = &(*p)->next;
        if (*p) *p = tun->next;
        ReissueBlockedQuestions(m, &tun->dstname, success);
+       LogOperation("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
        freeL("ClientTunnel", tun);
        }
 
@@ -2337,7 +2401,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R
 
        if (!answer->rdlength)
                {
-               LogOperation("AutoTunnelCallback NXDOMAIN %##s", question->qname.c);
+               LogOperation("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
                UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
                return;
                }
@@ -2346,7 +2410,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R
                {
                if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
                        {
-                       LogOperation("AutoTunnelCallback: supressing tunnel to self %.16a", &answer->rdata->u.ipv6);
+                       LogOperation("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
                        UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
                        return;
                        }
@@ -2402,6 +2466,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R
                                        }
                                else needSetKeys = mDNSfalse;
 
+                               LogOperation("AutoTunnelCallback: Disposing ClientTunnel %p", tun);
                                freeL("ClientTunnel", old);
                                }
                        }
@@ -2424,7 +2489,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
        ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
        if (!p) return;
        AssignDomainName(&p->dstname, &q->qname);
-       p->markedForDeletion = mDNSfalse;
+       p->MarkedForDeletion = mDNSfalse;
        p->loc_inner      = zerov6Addr;
        p->loc_outer      = zerov4Addr;
        p->rmt_inner      = zerov6Addr;
@@ -2432,7 +2497,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
        p->rmt_outer_port = zeroIPPort;
        mDNS_snprintf(p->b64keydata, sizeof(p->b64keydata), "%s", q->AuthInfo->b64keydata);
        p->next = m->TunnelClients;
-       m->TunnelClients = p;           // Intentionally build list in reverse order
+       m->TunnelClients = p;           // We intentionally build list in reverse order
 
        p->q.InterfaceID      = mDNSInterface_Any;
        p->q.Target           = zeroAddr;
@@ -2446,7 +2511,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
        p->q.QuestionCallback = AutoTunnelCallback;
        p->q.QuestionContext  = p;
 
-       LogOperation("AddNewClientTunnel start  %##s (%s)%s", &p->q.qname.c, DNSTypeName(p->q.qtype), q->LongLived ? " LongLived" : "");
+       LogOperation("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
        mDNS_StartQuery_internal(m, &p->q);
        }
 
@@ -2701,8 +2766,8 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
        for (i = m->p->InterfaceList; i; i = i->next)
                if (i->Exists)
                        {
-                       NetworkInterfaceInfo *n = &i->ifinfo;
-                       NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
+                       NetworkInterfaceInfo *const n = &i->ifinfo;
+                       NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
                        if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
 
                        if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary)       // Sanity check
@@ -2717,10 +2782,12 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
                                // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
                                // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
                                n->InterfaceID = (mDNSInterfaceID)primary;
+
                                // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
                                // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
                                // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
                                i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
+
                                mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
                                if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
                                LogOperation("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
@@ -2728,35 +2795,65 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
                                        i->Flashing        ? " (Flashing)"  : "",
                                        i->Occulting       ? " (Occulting)" : "",
                                        n->InterfaceActive ? " (Primary)"   : "");
-                               }
 
-                       if (!n->McastTxRx)
-                               debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
-                       else
-                               {
-                               if (i->sa_family == AF_INET)
+                               if (!n->McastTxRx)
+                                       debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
+                               else
                                        {
-                                       struct ip_mreq imr;
-                                       primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger;
-                                       imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
-                                       imr.imr_interface        = primary->ifa_v4addr;
-                                       mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
-                                       // Joining same group twice can give "Address already in use" error -- no need to report that
-                                       if (err < 0 && errno != EADDRINUSE)
-                                               LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno));
-                                       }
+                                       if (i->sa_family == AF_INET)
+                                               {
+                                               struct ip_mreq imr;
+                                               primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger;
+                                               imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
+                                               imr.imr_interface        = primary->ifa_v4addr;
+       
+                                               // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
+                                               // before trying to join the group, to clear out stale kernel state which may be lingering.
+                                               // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
+                                               // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
+                                               // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
+                                               // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
+                                               // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
+                                               // because by the time we get the configuration change notification, the interface is already gone,
+                                               // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
+                                               // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
+                                               if (SearchForInterfaceByName(m, i->ifa_name, AF_INET) == i)
+                                                       {
+                                                       LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
+                                                       mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
+                                                       if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations))
+                                                               LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno));
+                                                       }
+       
+                                               LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
+                                               mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
+                                               // Joining same group twice can give "Address already in use" error -- no need to report that
+                                               if (err < 0 && (errno != EADDRINUSE || LogAllOperations))
+                                                       LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
+                                               }
 #ifndef NO_IPV6
-                               if (i->sa_family == AF_INET6)
-                                       {
-                                       struct ipv6_mreq i6mr;
-                                       i6mr.ipv6mr_interface = primary->scope_id;
-                                       i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
-                                       mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
-                                       // Joining same group twice can give "Address already in use" error -- no need to report that
-                                       if (err < 0 && errno != EADDRINUSE)
-                                               LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno));
-                                       }
+                                       if (i->sa_family == AF_INET6)
+                                               {
+                                               struct ipv6_mreq i6mr;
+                                               i6mr.ipv6mr_interface = primary->scope_id;
+                                               i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
+       
+                                               if (SearchForInterfaceByName(m, i->ifa_name, AF_INET6) == i)
+                                                       {
+                                                       LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+                                                       mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
+                                                       if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations))
+                                                               LogMsg("setsockopt - IPV6_LEAVE_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+                                                       }
+       
+                                               LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+                                               mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
+                                               // Joining same group twice can give "Address already in use" error -- no need to report that
+                                               if (err < 0 && (errno != EADDRINUSE || LogAllOperations))
+                                                       LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+                                               }
 #endif
+                                       }
                                }
                        }
        return count;
@@ -2780,14 +2877,12 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
        // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
        // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
        // it refers to has gone away we'll crash.
-       // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
-       // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
        NetworkInterfaceInfoOSX *i;
        int count = 0;
        for (i = m->p->InterfaceList; i; i = i->next)
                {
                // If this interface is no longer active, or its InterfaceID is changing, deregister it
-               NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
+               NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
                if (i->ifinfo.InterfaceID)
                        if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
                                {
@@ -2801,14 +2896,17 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
                                mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
                                if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
                                i->ifinfo.InterfaceID = mDNSNULL;
-                               // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
+                               // NOTE: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
                                // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
-                               // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
+                               // If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
+
+                               // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
+                               // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
                                }
                }
 
        // Second pass:
-       // Now that everything that's going to deregister has done so, we can close sockets and free the memory
+       // Now that everything that's going to deregister has done so, we can clean up and free the memory
        NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
        while (*p)
                {
@@ -2953,7 +3051,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
                                                                // The option may be in the form of interface=xxx where xxx is an interface name.
                                                                if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0)
                                                                        {
-                                                                       NetworkInterfaceInfoOSX *i;
+                                                                       NetworkInterfaceInfoOSX *ni;
                                                                        char    ifname[IF_NAMESIZE+1];
                                                                        mDNSu32 ifindex = 0;
                                                                        // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
@@ -2961,12 +3059,12 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
                                                                        strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname));
                                                                        ifindex = if_nametoindex(ifname);
                                                                        if (ifindex == 0) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname); continue; }
-                                                                       LogOperation("%s: Interface specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex);
+                                                                       LogOperation("%s: Interface-specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex);
                                                                        // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
                                                                        // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
-                                                                       for (i = m->p->InterfaceList; i; i = i->next)
-                                                                               if (i->ifinfo.InterfaceID && i->scope_id == ifindex) break;
-                                                                       if (i != NULL) interface = i->ifinfo.InterfaceID;
+                                                                       for (ni = m->p->InterfaceList; ni; ni = ni->next)
+                                                                               if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break;
+                                                                       if (ni != NULL) interface = ni->ifinfo.InterfaceID;
                                                                        if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; }
                                                                        }
                                                                }
@@ -2980,7 +3078,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
                                                                if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address");
                                                                else
                                                                        {
-                                                                       DNSServer *s = mDNS_AddDNSServer(m, &d, mDNSInterface_Any, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort);
+                                                                       DNSServer *s = mDNS_AddDNSServer(m, &d, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort);
                                                                        if (s && disabled) s->teststate = DNSServer_Disabled;
                                                                        }
                                                                }
@@ -3009,12 +3107,12 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
        SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
        if (store)
                {
-               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
-               if (dict)
+               CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
+               if (ddnsdict)
                        {
                        if (fqdn)
                                {
-                               CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
+                               CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
                                if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
                                        {
                                        // for now, we only look at the first array element.  if we ever support multiple configurations, we will walk the list
@@ -3035,7 +3133,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
 
                        if (RegDomains)
                                {
-                               CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
+                               CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
                                if (regArray && CFArrayGetCount(regArray) > 0)
                                        {
                                        CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
@@ -3059,7 +3157,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
 
                        if (BrowseDomains)
                                {
-                               CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
+                               CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
                                if (browseArray)
                                        {
                                        for (i = 0; i < CFArrayGetCount(browseArray); i++)
@@ -3083,7 +3181,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
                                                }
                                        }
                                }
-                       CFRelease(dict);
+                       CFRelease(ddnsdict);
                        }
 
                if (RegDomains)
@@ -3118,56 +3216,50 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
 
                if (setservers || setsearch)
                        {
-                       CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
-                       if (key)
+                       CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DNS);
+                       if (dict)
                                {
-                               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, key);
-                               if (dict)
+                               if (setservers)
                                        {
-                                       if (setservers)
+                                       CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
+                                       if (values)
                                                {
-                                               CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
-                                               if (values)
+                                               for (i = 0; i < CFArrayGetCount(values); i++)
                                                        {
-                                                       for (i = 0; i < CFArrayGetCount(values); i++)
-                                                               {
-                                                               CFStringRef s = CFArrayGetValueAtIndex(values, i);
-                                                               char buf[256];
-                                                               mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
-                                                               if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
-                                                                       inet_aton(buf, (struct in_addr *) &addr.ip.v4))
-                                                                       mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
-                                                               }
+                                                       CFStringRef s = CFArrayGetValueAtIndex(values, i);
+                                                       mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
+                                                       if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
+                                                               inet_aton(buf, (struct in_addr *) &addr.ip.v4))
+                                                               mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
                                                        }
                                                }
-                                       if (setsearch)
+                                       }
+                               if (setsearch)
+                                       {
+                                       // Add the manual and/or DHCP-dicovered search domains
+                                       CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
+                                       if (searchDomains)
                                                {
-                                               // Add the manual and/or DHCP-dicovered search domains
-                                               CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
-                                               if (searchDomains)
+                                               for (i = 0; i < CFArrayGetCount(searchDomains); i++)
                                                        {
-                                                       for (i = 0; i < CFArrayGetCount(searchDomains); i++)
-                                                               {
-                                                               CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i);
-                                                               if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8))
-                                                                       mDNS_AddSearchDomain_CString(buf);
-                                                               }
-                                                       }
-                                               else    // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
-                                                       {
-                                                       // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
-                                                       // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
-                                                       // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
-                                                       // instead use the search domain list as the sole authority for what domains to search and in what order
-                                                       // (and the domain from the "domain" field will also appear somewhere in that list).
-                                                       CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
-                                                       if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8))
+                                                       CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i);
+                                                       if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8))
                                                                mDNS_AddSearchDomain_CString(buf);
                                                        }
                                                }
-                                       CFRelease(dict);
+                                       else    // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
+                                               {
+                                               // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
+                                               // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
+                                               // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
+                                               // instead use the search domain list as the sole authority for what domains to search and in what order
+                                               // (and the domain from the "domain" field will also appear somewhere in that list).
+                                               CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
+                                               if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8))
+                                                       mDNS_AddSearchDomain_CString(buf);
+                                               }
                                        }
-                               CFRelease(key);
+                               CFRelease(dict);
                                }
                        }
                CFRelease(store);
@@ -3176,103 +3268,85 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
 
 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
        {
-       SCDynamicStoreRef       store   = NULL;
-       CFDictionaryRef         dict    = NULL;
-       CFStringRef                     key             = NULL;
-       CFStringRef                     string  = NULL;
-       int                                     nAdditions = 0;
-       int                                     nDeletions = 0;
        char                            buf[256];
        mStatus                         err             = 0;
+       (void)m; // Unused
 
-       // get IPv4 settings
-
-       store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
-       require_action(store, exit, err = mStatus_UnknownErr);
-
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
-       require_action(key, exit, err = mStatus_UnknownErr);
-
-       dict = SCDynamicStoreCopyValue(store, key);
-       require_action(dict, exit, err = mStatus_UnknownErr);
-
-       // handle router changes
-
-       r->type  = mDNSAddrType_IPv4;
-       r->ip.v4 = zerov4Addr;
-        
-       string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
-
-       if (string)
-               {
-               struct sockaddr_in saddr;
-
-               if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
-                       LogMsg("Could not convert router to CString");
-               else
-                       {
-                       saddr.sin_len = sizeof(saddr);
-                       saddr.sin_family = AF_INET;
-                       saddr.sin_port = 0;
-                       inet_aton(buf, &saddr.sin_addr);
-
-                       if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf);
-                       else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
-                       }
-               }
-
-       // handle primary interface changes
-       // if we gained or lost DNS servers (e.g. logged into VPN) "toggle" primary address so it gets re-registered even if it is unchanged
-       if (nAdditions || nDeletions) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
-
-       string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
-
-       if (string)
+       SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
+       if (!store) LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed");
+       else
                {
-               mDNSBool HavePrimaryGlobalv6 = mDNSfalse;  // does the primary interface have a global v6 address?
-               struct ifaddrs *ifa = myGetIfAddrs(1);
-
-               *v4 = *v6 = zeroAddr;
-
-               if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
-
-               // find primary interface in list
-               while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
+               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
+               if (dict)
                        {
-                       mDNSAddr tmp6 = zeroAddr;
-                       if (!strcmp(buf, ifa->ifa_name))
+                       r->type  = mDNSAddrType_IPv4;
+                       r->ip.v4 = zerov4Addr;
+                       CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
+                       if (string)
                                {
-                               if (ifa->ifa_addr->sa_family == AF_INET)
-                                       {
-                                       if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
-                                       }
-                               else if (ifa->ifa_addr->sa_family == AF_INET6)
+                               if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
+                                       LogMsg("Could not convert router to CString");
+                               else
                                        {
-                                       SetupAddr(&tmp6, ifa->ifa_addr);
-                                       if (tmp6.ip.v6.b[0] >> 5 == 1)   // global prefix: 001
-                                               { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
+                                       struct sockaddr_in saddr;
+                                       saddr.sin_len = sizeof(saddr);
+                                       saddr.sin_family = AF_INET;
+                                       saddr.sin_port = 0;
+                                       inet_aton(buf, &saddr.sin_addr);
+               
+                                       if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf);
+                                       else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
                                        }
                                }
-                       else
+               
+                       string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
+                       if (string)
                                {
-                               // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
-                               if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
+                               mDNSBool HavePrimaryGlobalv6 = mDNSfalse;  // does the primary interface have a global v6 address?
+                               struct ifaddrs *ifa = myGetIfAddrs(1);
+               
+                               *v4 = *v6 = zeroAddr;
+               
+                               if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
+               
+                               // find primary interface in list
+                               while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
                                        {
-                                       SetupAddr(&tmp6, ifa->ifa_addr);
-                                       if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
+                                       mDNSAddr tmp6 = zeroAddr;
+                                       if (!strcmp(buf, ifa->ifa_name))
+                                               {
+                                               if (ifa->ifa_addr->sa_family == AF_INET)
+                                                       {
+                                                       if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
+                                                       }
+                                               else if (ifa->ifa_addr->sa_family == AF_INET6)
+                                                       {
+                                                       SetupAddr(&tmp6, ifa->ifa_addr);
+                                                       if (tmp6.ip.v6.b[0] >> 5 == 1)   // global prefix: 001
+                                                               { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
+                                                       }
+                                               }
+                                       else
+                                               {
+                                               // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
+                                               if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
+                                                       {
+                                                       SetupAddr(&tmp6, ifa->ifa_addr);
+                                                       if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
+                                                       }
+                                               }
+                                       ifa = ifa->ifa_next;
                                        }
+               
+                               // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
+                               // V4 to communicate w/ our DNS server
                                }
-                       ifa = ifa->ifa_next;
+               
+                       exit:
+                       CFRelease(dict);
                        }
-
-               // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
-               // V4 to communicate w/ our DNS server
+               CFRelease(store);
                }
-
-       exit:
-       if (dict) CFRelease(dict);
-       if (key) CFRelease(key);
-       if (store) CFRelease(store);
        return err;
        }
 
@@ -3357,7 +3431,7 @@ mDNSexport void SetDomainSecrets(mDNS *m)
        for (client = m->TunnelClients; client; client = client->next)
                {
                LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
-               client->markedForDeletion = mDNStrue;
+               client->MarkedForDeletion = mDNStrue;
                }
        }
 #endif APPLE_OSX_mDNSResponder
@@ -3429,7 +3503,7 @@ mDNSexport void SetDomainSecrets(mDNS *m)
                                        if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
                                        {
                                        LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
-                                       client->markedForDeletion = mDNSfalse;
+                                       client->MarkedForDeletion = mDNSfalse;
                                        // If the key has changed, reconfigure the tunnel
                                        if (strncmp(stringbuf, client->b64keydata, sizeof(client->b64keydata)))
                                                {
@@ -3486,20 +3560,20 @@ mDNSexport void SetDomainSecrets(mDNS *m)
        #if APPLE_OSX_mDNSResponder
                {
                // clean up ClientTunnels
-               ClientTunnel **ptr = &m->TunnelClients;
-               while (*ptr)
+               ClientTunnel **pp = &m->TunnelClients;
+               while (*pp)
                        {
-                       if ((*ptr)->markedForDeletion)
+                       if ((*pp)->MarkedForDeletion)
                                {
-                               ClientTunnel *cur = *ptr;
-                               LogOperation("SetDomainSecrets: removing client %##s from list", cur->dstname.c);
+                               ClientTunnel *cur = *pp;
+                               LogOperation("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
                                if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
                                AutoTunnelSetKeys(cur, mDNSfalse);
-                               *ptr = cur->next;
+                               *pp = cur->next;
                                freeL("ClientTunnel", cur);
                                }
                        else 
-                               ptr = &(*ptr)->next;
+                               pp = &(*pp)->next;
                        }
 
                DomainAuthInfo *info = m->AuthInfoList;
@@ -3632,7 +3706,7 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
        int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
        int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS  ) != 0);
        if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/20;       // If these were the only changes, shorten delay
-
+       
 #if LogAllOperations
        int i;
        for (i=0; i<c; i++)
@@ -3653,6 +3727,9 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
                m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
                m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
 
+       // If we have a global DNS change, then disregard delay and reconfigure immediately
+       if (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS) != 0) m->p->NetworkChanged = NonZeroTime(m->timenow);
+
        // KeyChain frequently fails to notify clients of change events. To work around this
        // we set a timer and periodically poll to detect if any changes have occurred.
        // Without this Back To My Mac just does't work for a large number of users.
@@ -3772,6 +3849,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
        mDNS *const m = (mDNS *const)refcon;
        KQueueLock(m);
        (void)service;    // Parameter not used
+       LogOperation("PowerChanged %X %lX", messageType, messageArgument);
        switch(messageType)
                {
                case kIOMessageCanSystemPowerOff:               debugf      ("PowerChanged kIOMessageCanSystemPowerOff (no action)");                           break; // E0000240
@@ -3795,7 +3873,15 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
                                                                                                mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false);                                            break; // E0000320
                default:                                                                LogOperation("PowerChanged unknown message %X", messageType);                                           break;
                }
-       IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
+
+       if (!m->p->SleepLimit && messageType == kIOMessageSystemWillSleep)
+               {
+               m->p->SleepLimit  = NonZeroTime(mDNS_TimeNow(m) + mDNSPlatformOneSecond * 5);
+               m->p->SleepCookie = (long)messageArgument;
+               }
+       else
+               IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
+
        KQueueUnlock(m, "Sleep/Wake");
        }
 #endif /* NO_IOPOWER */
@@ -3913,9 +3999,9 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        m->p->permanentsockets.kqsv4.KQcontext  = m->p->permanentsockets.kqsv6.KQcontext  = &m->p->permanentsockets;
        m->p->permanentsockets.kqsv4.KQtask     = m->p->permanentsockets.kqsv6.KQtask     = "UDP packet reception";
 
-       err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET);
+       err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
 #ifndef NO_IPV6
-       err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6);
+       err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
 #endif
 
        struct sockaddr_in s4;
@@ -3937,6 +4023,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        m->p->usernicelabel.c[0] = 0;
        m->p->NotifyUser         = 0;
        m->p->KeyChainBugTimer   = 0;
+       m->p->SleepLimit         = 0;
 
        m->AutoTunnelHostAddr.b[0] = 0;         // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
 
index 25fe6a4df8df118cc9cbe7ca4230bdf38a0ef010..a721c1172590260240ce21b1bf5f9cd0a227b7ff 100644 (file)
@@ -17,6 +17,9 @@
     Change History (most recent first):
 
 $Log: mDNSMacOSX.h,v $
+Revision 1.75  2007/12/14 00:45:21  cheshire
+Add SleepLimit and SleepCookie, for when we need to delay sleep until TLS/TCP record deregistration completes
+
 Revision 1.74  2007/11/02 20:18:13  cheshire
 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
 
@@ -171,6 +174,8 @@ struct mDNS_PlatformSupport_struct
        IONotificationPortRef    PowerPortRef;
        io_connect_t             PowerConnection;
        io_object_t              PowerNotifier;
+       mDNSs32                  SleepLimit;            // Set when we get kIOMessageSystemWillSleep notification
+       long                     SleepCookie;           // Cookie we need to pass to IOAllowPowerChange()
        pthread_mutex_t          BigMutex;
        mDNSs32                  BigMutexStartTime;
        int                                              WakeKQueueLoopFD;
@@ -218,7 +223,7 @@ struct CompileTimeAssertionChecks_mDNSMacOSX
        // other overly-large structures instead of having a pointer to them, can inadvertently
        // cause structure sizes (and therefore memory usage) to balloon unreasonably.
        char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <=  4100) ? 1 : -1];
-       char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   260) ? 1 : -1];
+       char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   268) ? 1 : -1];
        };
 
 #ifdef  __cplusplus
index 0454e3e5e820b1e5572e5723be758c05d026104e..904efc0e6e29de639eacf999b8726620460a314e 100644 (file)
@@ -67,7 +67,7 @@
 
 /* Begin PBXBuildFile section */
                2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; };
-               2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Server, Client, ); }; };
+               2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Server, Client, ); COMPILER_FLAGS = "-Wno-error"; }; };
                2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; };
                2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
                2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
@@ -83,7 +83,6 @@
                2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202520C56C36500DDFD48 /* libpfkey.h */; };
                2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; };
                2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */; };
-               2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
                2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
                2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; };
                2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = D284BE500ADD80740027CCDF /* mDNSResponder */;
+                       remoteGlobalIDString = D284BE500ADD80740027CCDF;
                        remoteInfo = mDNSResponder;
                };
                03067D690C83A3890022BE1F /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = D284BE750ADD80800027CCDF /* mDNSResponder debug */;
+                       remoteGlobalIDString = D284BE750ADD80800027CCDF;
                        remoteInfo = "mDNSResponder debug";
                };
                03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = D284BEA50ADD80920027CCDF /* dns-sd tool */;
+                       remoteGlobalIDString = D284BEA50ADD80920027CCDF;
                        remoteInfo = "dns-sd tool";
                };
                03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */;
+                       remoteGlobalIDString = 2E0405EF0C31955500F13B59;
                        remoteInfo = mDNSResponderHelper;
                };
                03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 03067D640C83A3700022BE1F /* Build Some */;
+                       remoteGlobalIDString = 03067D640C83A3700022BE1F;
                        remoteInfo = "Build Some";
                };
                D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */ = {
                                2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */,
                                2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */,
                                2E4D9B050C38C19500480551 /* Security.framework in Frameworks */,
-                               2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXNativeTarget;
                        buildConfigurationList = 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */;
                        buildPhases = (
+                               030BBED60CE11EEC00472F0C /* ShellScript */,
                                2EC8F8ED0C39CCCA003C9C48 /* Headers */,
                                2E0405ED0C31955500F13B59 /* Sources */,
                                2E0405EE0C31955500F13B59 /* Frameworks */,
                        isa = PBXNativeTarget;
                        buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
                        buildPhases = (
+                               030BBF010CE13A2800472F0C /* ShellScript */,
                                D284BEC20ADD80A20027CCDF /* Headers */,
                                D284BEC40ADD80A20027CCDF /* Sources */,
                                D284BECE0ADD80A20027CCDF /* Frameworks */,
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
+                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */;
                        projectDirPath = "";
 /* End PBXRezBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
+               030BBED60CE11EEC00472F0C /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "if [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n";
+               };
+               030BBF010CE13A2800472F0C /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "rm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\n";
+                       showEnvVarsInLog = 0;
+               };
                D284BE510ADD80740027CCDF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc -arch i386 -arch ppc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi\n\nif [ -e /usr/include/sandbox.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > ${CONFIGURATION_TEMP_DIR}/sandbox.h\nfi\n";
+                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n";
                };
                D284BE6C0ADD80740027CCDF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc -arch i386 -arch ppc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi\n\nif [ -e /usr/include/sandbox.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > ${CONFIGURATION_TEMP_DIR}/sandbox.h\nfi\n";
+                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\ncc -arch i386 -arch ppc \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n";
                };
                DB2CC4550662DE1700335AB3 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                                HEADER_SEARCH_PATHS = "${CONFIGURATION_TEMP_DIR}";
                                INSTALL_PATH = /usr/sbin;
                                LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt";
+                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
                                MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               OTHER_LDFLAGS = (
+                                       "$(inherited)",
+                                       "-lipsec",
+                               );
                                PREBINDING = NO;
                                PRODUCT_NAME = mDNSResponderHelper;
                        };
                                        "-Wmissing-prototypes",
                                        "-Wno-four-char-constants",
                                        "-Wno-unknown-pragmas",
+                                       "-Wshadow",
                                );
                                YACC_GENERATED_FILE_STEM = Standard;
                        };
                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                INSTALL_PATH = /usr/bin;
-                               MACOSX_DEPLOYMENT_TARGET = 10.2;
+                               MACOSX_DEPLOYMENT_TARGET = 10.4;
                                OTHER_CFLAGS = "-no-cpp-precomp";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                INSTALL_PATH = "/Library/Application Support/Bonjour";
-                               MACOSX_DEPLOYMENT_TARGET = 10.3;
+                               MACOSX_DEPLOYMENT_TARGET = 10.4;
                                OTHER_CFLAGS = "";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                GCC_SYMBOLS_PRIVATE_EXTERN = NO;
                                INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
                                INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
-                               MACOSX_DEPLOYMENT_TARGET = 10.3;
+                               MACOSX_DEPLOYMENT_TARGET = 10.4;
                                OTHER_CFLAGS = "";
                                OTHER_LDFLAGS = "-twolevel_namespace";
                                OTHER_REZFLAGS = "";
index b2a4d9df2ce92d97b378fc40d63ccc6ff1ee6169..09448102e4ba5cf821c07d39f9b9aeb57767c249 100644 (file)
@@ -60,6 +60,9 @@
 
 #include "ipsec_strerror.h"
 #include "libpfkey.h"
+#include "ipsec_options.h"
+
+#ifndef MDNS_NO_IPSEC
 
 #define CALLOC(size, cast) (cast)calloc(1, (size))
 
@@ -2124,3 +2127,5 @@ pfkey_setsadbxsa2(buf, lim, mode0, reqid)
 
        return(buf + len);
 }
+
+#endif /* ndef MDNS_NO_IPSEC */
index ad1821ca5b0ab5e832980e3b7838e5dcff664d3b..2c9f32f721e12a31a715dc1960082f67ca26bc5f 100755 (executable)
@@ -17,6 +17,9 @@
     Change History (most recent first):
 
 $Log: mDNSUNP.c,v $
+Revision 1.35  2007/11/15 21:36:19  cheshire
+<rdar://problem/5289340> POSIX: Off by one overflow in get_ifi_info_linuxv6()
+
 Revision 1.34  2006/08/14 23:24:47  cheshire
 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
 
@@ -200,7 +203,7 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
        FILE *fp;
        char addr[8][5];
        int flags, myflags, index, plen, scope;
-       char ifname[8], lastname[IFNAMSIZ];
+       char ifname[9], lastname[IFNAMSIZ];
        char addr6[32+7+1]; /* don't forget the seven ':' */
        struct addrinfo hints, *res0;
        struct sockaddr_in6 *sin6;
index d321b503bed65fc78a31df2816217164143236ac..c1d3b66687bd8f1f5c445eddd0dbb29ef56ab89b 100644 (file)
     Change History (most recent first):
 
 $Log: JNISupport.c,v $
+Revision 1.22  2007/11/30 23:38:53  cheshire
+Fix compiler warning:
+/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni.h:609: warning: declaration of 'index' shadows a global declaration
+
 Revision 1.21  2007/09/18 19:09:02  cheshire
 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
 
@@ -122,9 +126,14 @@ static DWORD       if_nametoindex( const char * nameStr );
 #include <sys/socket.h>
 #include <net/if.h>
 #endif // _WIN32
-#include <jni.h>
 
+// When compiling with "-Wshadow" set, including jni.h produces the following error:
+// /System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni.h:609: warning: declaration of 'index' shadows a global declaration
+// To work around this, we use the preprocessor to map the identifier 'index', which appears harmlessly in function prototype declarations,
+// to something 'jni_index', which doesn't conflict
+#define index jni_index
 #include "DNSSD.java.h"
+#undef index
 
 //#include <syslog.h>
 
index 08b4945bbd8012712b2f69c1e74ead293ae88239..61c53614b00b8c2b362f96499720a9585046c63b 100644 (file)
     Change History (most recent first):
 
 $Log: PlatformCommon.c,v $
+Revision 1.14  2007/12/03 18:37:26  cheshire
+Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg
+from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them
+
 Revision 1.13  2007/10/22 20:07:07  cheshire
 Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
 Posix build can share the code (better than just pasting it into mDNSPosix.c)
@@ -69,6 +73,7 @@ Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
 #include <errno.h>                             // Needed for errno etc.
 #include <sys/socket.h>                        // Needed for socket() etc.
 #include <netinet/in.h>                        // Needed for sockaddr_in
+#include <syslog.h>
 
 #include "mDNSEmbeddedAPI.h"   // Defines the interface provided to the client layer above
 #include "DNSCommon.h"
@@ -179,3 +184,26 @@ mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const fi
        LogMsg("ERROR: malformatted config file");
        if (f) fclose(f);       
        }
+
+#if MDNS_DEBUGMSGS
+mDNSexport void        mDNSPlatformWriteDebugMsg(const char *msg)
+       {
+       fprintf(stderr,"%s\n", msg);
+       fflush(stderr);
+       }
+#endif
+
+mDNSexport void        mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, int logoptflags)
+       {
+       if (mDNS_DebugMode)     // In debug mode we write to stderr
+               {
+               fprintf(stderr,"%s\n", buffer);
+               fflush(stderr);
+               }
+       else                            // else, in production mode, we write to syslog
+               {
+               openlog(ident, LOG_CONS | logoptflags, LOG_DAEMON);
+               syslog(LOG_ERR, "%s", buffer);
+               closelog();
+               }
+       }
index de5527759cbf2639a004919e1b3180fcc8154ab9..da571b2a5845265449e5a57c6a04ed82bbeae6c8 100644 (file)
@@ -77,7 +77,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 1640000
+#define _DNS_SD_H 1700000
 
 #ifdef  __cplusplus
     extern "C" {
 #include <sys/types.h>
 
 /* EFI does not have stdint.h, or anything else equivalent */
-#elif defined(EFI32) || defined(EFI64)
+#elif defined(EFI32) || defined(EFI64) || defined(EFIX64)
+#include "Tiano.h"
+#if !defined(_STDINT_H_)
 typedef UINT8       uint8_t;
 typedef INT8        int8_t;
 typedef UINT16      uint16_t;
 typedef INT16       int16_t;
 typedef UINT32      uint32_t;
 typedef INT32       int32_t;
-
+#endif
 /* Windows has its own differences */
 #elif defined(_WIN32)
 #include <windows.h>
@@ -299,7 +301,7 @@ enum
      * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
      * cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
      *
-     * 3. Don't double-deallocate
+     * 3. Don't Double-Deallocate
      * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates
      * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef
      * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref))
@@ -308,6 +310,13 @@ enum
      * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt
      * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses
      * to freed memory, leading to crashes or other equally undesirable results.
+     *
+     * 4. Thread Safety
+     * The dns_sd.h API does not presuppose any particular threading model, and consequently
+     * does no locking of its own (which would require linking some specific threading library).
+     * If client code calls API routines on the same DNSServiceRef concurrently
+     * from multiple threads, it is the client's responsibility to use a mutext
+     * lock or take similar appropriate precautions to serialize those calls.
      */
 
     };
@@ -735,7 +744,6 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply)
 
 
 /* DNSServiceEnumerateDomains() Parameters:
- *
  *
  * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds
  *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
@@ -781,7 +789,6 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
  *********************************************************************************************/
 
 /* Register a service that is discovered via Browse() and Resolve() calls.
- *
  *
  * DNSServiceRegisterReply() Callback Parameters:
  *
@@ -953,7 +960,6 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister
  * DNSServiceRef, then it's the caller's responsibility to use a mutext lock
  * or take similar appropriate precautions to serialize those calls.
  *
- *
  * Parameters;
  *
  * sdRef:           A DNSServiceRef initialized by DNSServiceRegister().
@@ -996,7 +1002,6 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord
  *   - A record added to a registered service via DNSServiceAddRecord()
  *   - An individual record registered by DNSServiceRegisterRecord()
  *
- *
  * Parameters:
  *
  * sdRef:           A DNSServiceRef that was initialized by DNSServiceRegister()
@@ -1064,7 +1069,6 @@ DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
  *********************************************************************************************/
 
 /* Browse for instances of a service.
- *
  *
  * DNSServiceBrowseReply() Parameters:
  *
@@ -1303,7 +1307,6 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
  *
  * Query for an arbitrary DNS record.
  *
- *
  * DNSServiceQueryRecordReply() Callback Parameters:
  *
  * sdRef:           The DNSServiceRef initialized by DNSServiceQueryRecord().
@@ -1346,7 +1349,7 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
 
 typedef void (DNSSD_API *DNSServiceQueryRecordReply)
     (
-    DNSServiceRef                       DNSServiceRef,
+    DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
     uint32_t                            interfaceIndex,
     DNSServiceErrorType                 errorCode,
@@ -1422,7 +1425,6 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
  *
  * Queries for the IP address of a hostname by using either Multicast or Unicast DNS.
  *
- *
  * DNSServiceGetAddrInfoReply() parameters:
  *
  * sdRef:           The DNSServiceRef initialized by DNSServiceGetAddrInfo().
@@ -1538,7 +1540,6 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
  * Create a connection to the daemon allowing efficient registration of
  * multiple individual records.
  *
- *
  * Parameters:
  *
  * sdRef:           A pointer to an uninitialized DNSServiceRef. Deallocating
@@ -1560,7 +1561,6 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  * Note that name conflicts occurring for records registered via this call must be handled
  * by the client in the callback.
  *
- *
  * DNSServiceRegisterRecordReply() parameters:
  *
  * sdRef:           The connected DNSServiceRef initialized by
@@ -1721,7 +1721,6 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
  * port mapping, the client should be prepared to handle these notifications of changes
  * in the environment, and should update its recorded address and/or port as appropriate.
  *
- *
  * DNSServiceNATPortMappingReply() parameters:
  *
  * sdRef:           The DNSServiceRef initialized by DNSServiceNATPortMappingCreate().
@@ -2193,7 +2192,7 @@ uint16_t DNSSD_API TXTRecordGetCount
  *
  * txtRecord:       Pointer to the received TXT Record bytes.
  *
- * index:           An index into the TXT Record.
+ * itemIndex:       An index into the TXT Record.
  *
  * keyBufLen:       The size of the string buffer being supplied.
  *
@@ -2218,7 +2217,7 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
     (
     uint16_t         txtLen,
     const void       *txtRecord,
-    uint16_t         index,
+    uint16_t         itemIndex,
     uint16_t         keyBufLen,
     char             *key,
     uint8_t          *valueLen,
@@ -2239,7 +2238,6 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
  * register in this wide-area domain in addition to .local. In addition, this
  * domain will be returned as a Browse domain via domain enumeration calls.
  *
- *
  * Parameters:
  *
  * flags:           Pass kDNSServiceFlagsAdd to add a domain for a user. Call without
index a3860f22bd84ae10f8714423a91f401781ae103b..5a6541cf67d3c615f3da6928f7da24eca705bf29 100644 (file)
     Change History (most recent first):
 
 $Log: dnsextd.c,v $
+Revision 1.87  2007/12/17 23:34:50  cheshire
+Don't need to set ptr to result of DNSDigest_SignMessage -- ptr is updated anyway (it's passed by reference)
+
+Revision 1.86  2007/12/13 20:22:34  cheshire
+Got rid of redundant SameResourceRecord() routine; replaced calls to this
+with calls to IdenticalResourceRecord() which does exactly the same thing.
+
+Revision 1.85  2007/12/01 00:30:36  cheshire
+Fixed compile warning: declaration of 'time' shadows a global declaration
+
 Revision 1.84  2007/10/24 18:19:37  cheshire
 Fixed header byte order bug sending update responses
 
@@ -1094,7 +1104,7 @@ mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
 
                if ( zone->updateKeys )
                        {
-                       ptr = DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 );
+                       DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 );
                        require_action( ptr, exit, Log("UpdateSRV: Error constructing lease expiration update" ) );
                        }
 
@@ -1429,7 +1439,7 @@ mDNSlocal void DeleteOneRecord(DaemonInfo *d, CacheRecord *rr, domainname *zname
 
        if ( zone && zone->updateKeys)
                {
-               ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 );
+               DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 );
                if (!ptr) goto end;
                }
 
@@ -1493,7 +1503,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
        LargeCacheRecord lcr;
        ResourceRecord *rr = &lcr.r.resrec;
        const mDNSu8 *ptr, *end;
-       struct timeval time;
+       struct timeval tv;
        DNSQuestion zone;
        char buf[MaxMsg];
        
@@ -1530,7 +1540,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
                          if (SameDomainName((*rptr)->rr.resrec.name, rr->name) &&
                                 (DeleteAllRRSets ||
                                 (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) ||
-                                 (DeleteOneRR && SameResourceRecord(&(*rptr)->rr.resrec, rr))))
+                                 (DeleteOneRR && IdenticalResourceRecord(&(*rptr)->rr.resrec, rr))))
                                  {
                                  tmp = *rptr;
                                  VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf));
@@ -1544,12 +1554,12 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
                else if (lease > 0)
                        {
                        // see if add or refresh
-                       while (*rptr && !SameResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
+                       while (*rptr && !IdenticalResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
                        if (*rptr)
                                {
                                // refresh
-                               if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
-                               (*rptr)->expire = time.tv_sec + (unsigned)lease;
+                               if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
+                               (*rptr)->expire = tv.tv_sec + (unsigned)lease;
                                VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
                                }
                        else
@@ -1561,7 +1571,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
                                        bucket = rr->namehash % d->nbuckets;
                                        rptr = &d->table[bucket];
                                        }
-                               if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
+                               if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
                                allocsize = sizeof(RRTableElem);
                                if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize);
                                tmp = malloc(allocsize);
@@ -1570,7 +1580,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
                                tmp->rr.resrec.rdata = (RData *)&tmp->rr.rdatastorage;
                                AssignDomainName(&tmp->name, rr->name);
                                tmp->rr.resrec.name = &tmp->name;
-                               tmp->expire = time.tv_sec + (unsigned)lease;
+                               tmp->expire = tv.tv_sec + (unsigned)lease;
                                tmp->cli.sin_addr = pkt->src.sin_addr;
                                AssignDomainName(&tmp->zone, &zone.qname);
                                tmp->next = d->table[bucket];
@@ -1953,7 +1963,7 @@ mDNSlocal void *UpdateAnswerList(void *args)
                {
                for (na = &NewAnswers; *na; na = &(*na)->next)
                        {
-                       if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec))
+                       if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec))
                                { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
                        }
                }
@@ -1963,7 +1973,7 @@ mDNSlocal void *UpdateAnswerList(void *args)
        while (*na)
                {
                for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
-                       if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
+                       if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
                if (!*ka)
                        {
                        // answer is not in list - splice from NewAnswers list, add to Event list
@@ -2708,19 +2718,18 @@ RecvUDPMessage
 
        if ( IsNotify( &context->pkt ) )
                {
-               int err = RecvNotify( self, &context->pkt );
+               int e = RecvNotify( self, &context->pkt );
                free(context);
-               return err;
+               return e;
                }
        else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
                {
                if ( IsLLQRequest( &context->pkt ) )
                        {
                        // LLQ messages handled by main thread
-
-                       int err = RecvLLQ( self, &context->pkt, NULL );
+                       int e = RecvLLQ( self, &context->pkt, NULL );
                        free(context);
-                       return err;
+                       return e;
                        }
 
                if ( IsLLQAck(&context->pkt ) )
@@ -2739,15 +2748,15 @@ RecvUDPMessage
        else
                {
                PktMsg reply;
-               int    res;
+               int    e;
 
                memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
 
                reply.msg.h.flags.b[0]  =  kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
                reply.msg.h.flags.b[1]  =  kDNSFlag1_RA | kDNSFlag1_RC_NXDomain;
 
-               res = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
-               require_action_quiet( res == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
+               e = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
+               require_action_quiet( e == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
 
                err = mStatus_NoAuth;
                }
index f32351f218859a0311e8a861c7ed592e5d2b2431..01ffaff9fbf4d601579b49cdf94530f4a2ec670d 100644 (file)
@@ -28,6 +28,9 @@
    Change History (most recent first):
 
 $Log: dnssd_clientlib.c,v $
+Revision 1.18  2007/11/30 23:06:10  cheshire
+Fixed compile warning: declaration of 'index' shadows a global declaration
+
 Revision 1.17  2007/10/02 19:36:04  cheshire
 <rdar://problem/5516444> TXTRecordGetValuePtr should be case-insenstive
 
@@ -353,7 +356,7 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
        (
        uint16_t         txtLen,
        const void       *txtRecord,
-       uint16_t         index,
+       uint16_t         itemIndex,
        uint16_t         keyBufLen,
        char             *key,
        uint8_t          *valueLen,
@@ -363,7 +366,7 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
        uint16_t count = 0;
        uint8_t *p = (uint8_t*)txtRecord;
        uint8_t *e = p + txtLen;
-       while (p<e && count<index) { p += 1 + p[0]; count++; }  // Find requested item
+       while (p<e && count<itemIndex) { p += 1 + p[0]; count++; }      // Find requested item
        if (p<e && p + 1 + p[0] <= e)   // If valid
                {
                uint8_t *x = p+1;
index 0b02ad809e0ccf7ad77aef83862ac01e8c1be21a..3bd7c1ff186757a172590d89bc6709ef59845d5a 100644 (file)
@@ -25,6 +25,9 @@
        Change History (most recent first):
 
 $Log: dnssd_clientshim.c,v $
+Revision 1.16  2007/11/30 20:12:24  cheshire
+Removed unused "badparam:" label
+
 Revision 1.15  2007/07/27 19:30:41  cheshire
 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
 to properly reflect tri-state nature of the possible responses
@@ -711,8 +714,6 @@ DNSServiceErrorType DNSServiceQueryRecord
        *sdRef = (DNSServiceRef)x;
        return(mStatus_NoError);
 
-badparam:
-       err = mStatus_BadParamErr;
 fail:
        LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
        return(err);
index bc47f6b72d0e6ae8b8ea94a0cf9a59b51bc443eb..d197344ce868ba98a07d9921b6fe3c9159202d86 100644 (file)
        Change History (most recent first):
 
 $Log: dnssd_clientstub.c,v $
+Revision 1.100  2007/11/02 17:56:37  cheshire
+<rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
+Wrap hack code in "#if APPLE_OSX_mDNSResponder" since (as far as we know right now)
+we don't want to do this on 64-bit Linux, Solaris, etc.
+
+Revision 1.99  2007/11/02 17:29:40  cheshire
+<rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
+To get 64-bit code that works, we need to NOT use the standard CMSG_* macros
+
+Revision 1.98  2007/11/01 19:52:43  cheshire
+Wrap debugging messages in "#if DEBUG_64BIT_SCM_RIGHTS"
+
+Revision 1.97  2007/11/01 19:45:55  cheshire
+Added "DEBUG_64BIT_SCM_RIGHTS" debugging code
+See <rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
+
+Revision 1.96  2007/11/01 15:59:33  cheshire
+umask not being set and restored properly in USE_NAMED_ERROR_RETURN_SOCKET code
+(no longer used on OS X, but relevant for other platforms)
+
+Revision 1.95  2007/10/31 20:07:16  cheshire
+<rdar://problem/5541498> Set SO_NOSIGPIPE on client socket
+Refinement: the cleanup code still needs to close listenfd when necesssary
+
+Revision 1.94  2007/10/15 22:34:27  cheshire
+<rdar://problem/5541498> Set SO_NOSIGPIPE on client socket
+
 Revision 1.93  2007/10/10 00:48:54  cheshire
 <rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
 
@@ -480,6 +507,9 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
                }
        else
                {
+               #ifdef SO_NOSIGPIPE
+               const unsigned long optval = 1;
+               #endif
                *ref = NULL;
                sdr->sockfd    = socket(AF_DNSSD, SOCK_STREAM, 0);
                sdr->validator = sdr->sockfd ^ ValidatorBits;
@@ -489,6 +519,11 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
                        FreeDNSServiceOp(sdr);
                        return kDNSServiceErr_NoMemory;
                        }
+               #ifdef SO_NOSIGPIPE
+               // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
+               if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
+                       syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", errno, strerror(errno));
+               #endif
                #if defined(USE_TCP_LOOPBACK)
                saddr.sin_family      = AF_INET;
                saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
@@ -565,8 +600,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
                        }
                #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
                        {
+                       mode_t mask;
+                       int bindresult;
                        dnssd_sockaddr_t caddr;
-                       mode_t mask = umask(0);
                        listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
                        if (!dnssd_SocketValid(listenfd)) goto cleanup;
 
@@ -577,8 +613,10 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
                        caddr.sun_len = sizeof(struct sockaddr_un);
                        #endif
                        strcpy(caddr.sun_path, data);
+                       mask = umask(0);
+                       bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
                        umask(mask);
-                       if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0) goto cleanup;
+                       if (bindresult < 0) goto cleanup;
                        listen(listenfd, 1);
                        }
                #else
@@ -634,29 +672,66 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
                errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
                if (!dnssd_SocketValid(errsd)) goto cleanup;
 #else
+
+#if APPLE_OSX_mDNSResponder
+// On Leopard, the stock definitions of the CMSG_* macros in /usr/include/sys/socket.h,
+// while arguably correct in theory, nonetheless in practice produce code that doesn't work on 64-bit machines
+// For details see <rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
+#undef  CMSG_DATA
+#define CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + (sizeof(struct cmsghdr)))
+#undef  CMSG_SPACE
+#define CMSG_SPACE(l)   ((sizeof(struct cmsghdr)) + (l))
+#undef  CMSG_LEN
+#define CMSG_LEN(l)     ((sizeof(struct cmsghdr)) + (l))
+#endif
+
                struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
                struct msghdr msg;
                struct cmsghdr *cmsg;
-               char cbuf[sizeof(struct cmsghdr) + sizeof(dnssd_sock_t)];
+               char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))];
                msg.msg_name       = 0;
                msg.msg_namelen    = 0;
                msg.msg_iov        = &vec;
                msg.msg_iovlen     = 1;
                msg.msg_control    = cbuf;
-               msg.msg_controllen = sizeof(cbuf);
+               msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
                msg.msg_flags      = 0;
                cmsg = CMSG_FIRSTHDR(&msg);
-               cmsg->cmsg_len     = sizeof(cbuf);
+               cmsg->cmsg_len     = CMSG_LEN(sizeof(dnssd_sock_t));
                cmsg->cmsg_level   = SOL_SOCKET;
                cmsg->cmsg_type    = SCM_RIGHTS;
                *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
+
 #if TEST_KQUEUE_CONTROL_MESSAGE_BUG
                sleep(1);
 #endif
+
+#if DEBUG_64BIT_SCM_RIGHTS
+               syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
+                       errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
+                       sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
+                       CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
+                       (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
+#endif DEBUG_64BIT_SCM_RIGHTS
+
                if (sendmsg(sdr->sockfd, &msg, 0) < 0)
+                       {
                        syslog(LOG_WARNING, "dnssd_clientstub ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
                                errsd, listenfd, errno, strerror(errno));
+                       err = kDNSServiceErr_Incompatible;
+                       goto cleanup;
+                       }
+
+#if DEBUG_64BIT_SCM_RIGHTS
+               syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
+#endif DEBUG_64BIT_SCM_RIGHTS
+
 #endif
+               // Close our end of the socketpair *before* blocking in read_all to get the four-byte error code.
+               // Otherwise, if the daemon closes our socket (or crashes), we block in read_all() forever
+               // because the socket is not closed (we still have an open reference to it ourselves).
+               dnssd_close(listenfd);
+               listenfd = dnssd_InvalidSocket;         // Make sure we don't close it a second time in the cleanup handling below
                }
 
        // At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code,
index ca3eda963dbad7fd939b6836cb833e1c6140ae82..4d0adbc6891b793837e3cb7531a279d3e4c7aa75 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: mDNSDebug.c,v $
+Revision 1.13  2007/12/01 00:40:30  cheshire
+Fixes from Bob Bradley for building on EFI
+
 Revision 1.12  2007/10/01 19:06:19  cheshire
 Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at
 
@@ -68,14 +71,11 @@ Changes necessary to support mDNSResponder on Linux.
 
 #include <stdio.h>
 
-#if defined(WIN32)
-// Need to add Windows syslog support here
+#if defined(WIN32) || defined(EFI32) || defined(EFI64) || defined(EFIX64)
+// Need to add Windows/EFI syslog support here
 #define LOG_PID 0x01
 #define LOG_CONS 0x02
 #define LOG_PERROR 0x20
-#define openlog(A,B,C) (void)(A); (void)(B)
-#define syslog(A,B,C)
-#define closelog()
 #else
 #include <syslog.h>
 #endif
@@ -95,44 +95,27 @@ mDNSexport int mDNS_DebugMode = mDNSfalse;
 #if MDNS_DEBUGMSGS
 mDNSexport void debugf_(const char *format, ...)
        {
-       unsigned char buffer[512];
+       char buffer[512];
        va_list ptr;
        va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+       buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0;
        va_end(ptr);
-       fprintf(stderr,"%s\n", buffer);
-       fflush(stderr);
+       mDNSPlatformWriteDebugMsg(buffer);
        }
 #endif
 
 #if MDNS_DEBUGMSGS > 1
 mDNSexport void verbosedebugf_(const char *format, ...)
        {
-       unsigned char buffer[512];
+       char buffer[512];
        va_list ptr;
        va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+       buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0;
        va_end(ptr);
-       fprintf(stderr,"%s\n", buffer);
-       fflush(stderr);
+       mDNSPlatformWriteDebugMsg(buffer);
        }
 #endif
 
-mDNSlocal void WriteLogMsg(const char *ident, const char *buffer, int logoptflags)
-       {
-       if (mDNS_DebugMode)     // In debug mode we write to stderr
-               {
-               fprintf(stderr,"%s\n", buffer);
-               fflush(stderr);
-               }
-       else                            // else, in production mode, we write to syslog
-               {
-               openlog(ident, LOG_CONS | logoptflags, LOG_DAEMON);
-               syslog(LOG_ERR, "%s", buffer);
-               closelog();
-               }
-       }
-
 // Log message with default "mDNSResponder" ident string at the start
 mDNSexport void LogMsg(const char *format, ...)
        {
@@ -141,7 +124,7 @@ mDNSexport void LogMsg(const char *format, ...)
        va_start(ptr,format);
        buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
        va_end(ptr);
-       WriteLogMsg(ProgramName, buffer, 0);
+       mDNSPlatformWriteLogMsg(ProgramName, buffer, 0);
        }
 
 // Log message with specified ident string at the start
@@ -152,7 +135,7 @@ mDNSexport void LogMsgIdent(const char *ident, const char *format, ...)
        va_start(ptr,format);
        buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
        va_end(ptr);
-       WriteLogMsg(ident, buffer, ident && *ident ? LOG_PID : 0);
+       mDNSPlatformWriteLogMsg(ident, buffer, ident && *ident ? LOG_PID : 0);
        }
 
 // Log message with no ident string at the start
@@ -163,7 +146,7 @@ mDNSexport void LogMsgNoIdent(const char *format, ...)
        va_start(ptr,format);
        buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
        va_end(ptr);
-       WriteLogMsg("", buffer, 0);
+       mDNSPlatformWriteLogMsg("", buffer, 0);
        }
 
 mDNSlocal const char *CStringForLogLevel(LogLevel_t level)
index 201a44b0ab338d27de549a521d7089c6b43bbf42..3e0a60196f8c9007a2dd1130fc99ab188716a41f 100644 (file)
        Change History (most recent first):
 
 $Log: uds_daemon.c,v $
+Revision 1.384  2007/12/22 01:38:05  cheshire
+Improve display of "Auth Records" SIGINFO output
+
+Revision 1.383  2007/12/07 00:45:58  cheshire
+<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
+
+Revision 1.382  2007/11/30 20:11:48  cheshire
+Fixed compile warning: declaration of 'remove' shadows a global declaration
+
+Revision 1.381  2007/11/28 22:02:52  cheshire
+Remove pointless "if (!domain)" check (domain is an array on the stack, so its address can never be null)
+
+Revision 1.380  2007/11/28 18:38:41  cheshire
+Fixed typo in log message: "DNSServiceResolver" -> "DNSServiceResolve"
+
 Revision 1.379  2007/11/01 19:32:14  cheshire
 Added "DEBUG_64BIT_SCM_RIGHTS" debugging code
 
@@ -2067,10 +2082,10 @@ mDNSlocal void udsserver_automatic_browse_domain_changed(const DNameListElem *co
                                        if (p) debugf("udsserver_automatic_browse_domain_changed %##s still in list, not removing", &d->name);
                                        else
                                                {
-                                               browser_t *remove = *ptr;
+                                               browser_t *rem = *ptr;
                                                *ptr = (*ptr)->next;
-                                               mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q);
-                                               freeL("browser_t/udsserver_automatic_browse_domain_changed", remove);
+                                               mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q);
+                                               freeL("browser_t/udsserver_automatic_browse_domain_changed", rem);
                                                }
                                        }
                                }
@@ -2138,9 +2153,9 @@ mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, in
                {
                if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
                        {
-                       ARListElem *remove = *ptr;
+                       ARListElem *rem = *ptr;
                        *ptr = (*ptr)->next;
-                       mDNS_Deregister(m, &remove->ar);
+                       mDNS_Deregister(m, &rem->ar);
                        return;
                        }
                else ptr = &(*ptr)->next;
@@ -2335,7 +2350,7 @@ mDNSlocal mStatus handle_browse_request(request_state *request)
 
        if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
 
-       if (!domain || (domain[0] == '\0')) uDNS_RegisterSearchDomains(&mDNSStorage);
+       if (domain[0] == '\0') uDNS_RegisterSearchDomains(&mDNSStorage);
 
        typedn.c[0] = 0;
        NumSubTypes = ChopSubTypes(regtype);    // Note: Modifies regtype string to remove trailing subtypes
@@ -3300,7 +3315,13 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
                req = newreq;
                }
 
-       switch(req->hdr.op)
+       // If we're shutting down, don't allow new client requests
+       // We do allow "cancel" and "getproperty" during shutdown
+       if (mDNSStorage.ShutdownTime && req->hdr.op != cancel_request && req->hdr.op != getproperty_request)
+               {
+               err = mStatus_ServiceNotRunning;
+               }
+       else switch(req->hdr.op)
                {
                // These are all operations that have their own first-class request_state object
                case connection_request:
@@ -3331,8 +3352,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
        if (req->msgbuf) freeL("request_state msgbuf", req->msgbuf);
 
        // There's no return data for a cancel request (DNSServiceRefDeallocate returns no result)
-       // For a DNSServiceGetProperty call, the handler already generated the response,
-       // so no need to do it again here
+       // For a DNSServiceGetProperty call, the handler already generated the response, so no need to do it again here
        if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request)
                {
                err = dnssd_htonl(err);
@@ -3402,10 +3422,10 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
                request->errsd = sd;
 #if APPLE_OSX_mDNSResponder
        struct xucred x;
-       socklen_t len = sizeof(x);
-       if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &len) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid;
+       socklen_t xucredlen = sizeof(x);
+       if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid;
        else my_perror("ERROR: getsockopt, LOCAL_PEERCRED");
-       debugf("LOCAL_PEERCRED %d %u %u %d", len, x.cr_version, x.cr_uid, x.cr_ngroups);
+       debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups);
 #endif APPLE_OSX_mDNSResponder
                LogOperation("%3d: Adding FD for uid %u", request->sd, request->uid);
                udsSupportAddFDToEventLoop(sd, request_callback, request);
@@ -3665,11 +3685,19 @@ mDNSexport void udsserver_info(mDNS *const m)
                AuthRecord *ar;
                LogMsgNoIdent("    Int    Next  Expire   State");
                for (ar = m->ResourceRecords; ar; ar=ar->next)
-                       LogMsgNoIdent("%7d %7d %7d %7d %s",
-                               ar->ThisAPInterval / mDNSPlatformOneSecond,
-                               AuthRecord_uDNS(ar) || ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
-                               AuthRecord_uDNS(ar) && ar->expire        ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
-                               ar->state, ARDisplayString(m, ar));
+                       if (AuthRecord_uDNS(ar))
+                               LogMsgNoIdent("%7d %7d %7d %7d %s",
+                                       ar->ThisAPInterval / mDNSPlatformOneSecond,
+                                       (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
+                                       ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
+                                       ar->state, ARDisplayString(m, ar));
+                       else if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
+                               LogMsgNoIdent("%7d %7d               M %s",
+                                       ar->ThisAPInterval / mDNSPlatformOneSecond,
+                                       ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
+                                       ARDisplayString(m, ar));
+                       else
+                               LogMsgNoIdent("                             LO %s", ARDisplayString(m, ar));
                }
 
        LogMsgNoIdent("----- ServiceRegistrations -----");
@@ -3864,7 +3892,7 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
                        if ((*req)->u.resolve.ReportTime && now - (*req)->u.resolve.ReportTime >= 0)
                                {
                                (*req)->u.resolve.ReportTime = 0;
-                               LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
+                               LogMsgNoIdent("Client application bug: DNSServiceResolve(%##s) active for over two minutes. "
                                        "This places considerable burden on the network.", (*req)->u.resolve.qsrv.qname.c);
                                }
 
index 13b04048bb5e64bc1d55435f72f180530679e5ff..1cb1f6466bfecb946de6c96bba939b68b6ce39aa 100755 (executable)
@@ -17,6 +17,9 @@
     Change History (most recent first):
     
 $Log: mDNSWin32.c,v $
+Revision 1.130  2007/11/16 18:53:56  cheshire
+TCPSocketFlags needs to be first field of TCPSocket_struct
+
 Revision 1.129  2007/10/17 22:52:26  cheshire
 Get rid of unused mDNS_UpdateLLQs()
 
@@ -219,8 +222,8 @@ struct      mDNSPlatformInterfaceInfo
 
 struct TCPSocket_struct
 {
+       TCPSocketFlags flags;           // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
        SocketRef                               fd;
-       TCPSocketFlags          flags;
        BOOL                                    connected;
        TCPConnectionCallback   callback;
        void                            *       context;