]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-26.2.tar.gz mac-os-x-1025 mac-os-x-1026 mac-os-x-1027 mac-os-x-1028 mac-os-x-1028g5 v26.2
authorApple <opensource@apple.com>
Wed, 2 Apr 2003 01:45:59 +0000 (01:45 +0000)
committerApple <opensource@apple.com>
Wed, 2 Apr 2003 01:45:59 +0000 (01:45 +0000)
CFSocket.c
daemon.c
mDNSCore/mDNS.c
mDNSCore/mDNSClientAPI.h

index 2fcd97cc069532581050affacb0d4fdadbccf8e7..292d586fa00b8323287e596e2feef0980258b908 100644 (file)
@@ -77,6 +77,8 @@ void (*NotifyClientNetworkChanged)(void);
 #include <IOKit/IOKitLib.h>
 #include <IOKit/IOMessage.h>
 
+extern void LogErrorMessage(const char *format, ...);
+
 // ***************************************************************************
 // Structures
 
@@ -142,6 +144,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
 static ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
        struct sockaddr *const from, size_t *const fromlen, struct in_addr *dstaddr, char ifname[128])
        {
+       static int numLogMessages = 0;
        struct iovec databuffers = { (char *)buffer, max };
        struct msghdr   msg;
        ssize_t         n;
@@ -159,8 +162,22 @@ static ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
        
        // Receive the data
        n = recvmsg(s, &msg, 0);
-       if (n<0 || msg.msg_controllen < sizeof(struct cmsghdr) || (msg.msg_flags & MSG_CTRUNC))
-               { perror("recvmsg"); return(n); }
+       if (n<0)
+               {
+               if (numLogMessages++ < 100) LogErrorMessage("CFSocket.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
+               return(-1);
+               }
+       if (msg.msg_controllen < sizeof(struct cmsghdr))
+               {
+               if (numLogMessages++ < 100) LogErrorMessage("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %d",
+                       s, msg.msg_controllen, sizeof(struct cmsghdr));
+               return(-1);
+               }
+       if (msg.msg_flags & MSG_CTRUNC)
+               {
+               if (numLogMessages++ < 100) LogErrorMessage("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
+               return(-1);
+               }
        
        *fromlen = msg.msg_namelen;
        
@@ -197,19 +214,30 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef s, CFSocketCallBackType type, CFDa
        size_t fromlen = sizeof(from);
        char packetifname[128] = "";
        int err;
+       int s1 = -1;
        
        (void)address;  // Parameter not used
        (void)data;             // Parameter not used
        
-       if (type != kCFSocketReadCallBack) debugf("myCFSocketCallBack: Why is type not kCFSocketReadCallBack?");
+       if (type != kCFSocketReadCallBack) LogErrorMessage("CFSocketCallBack: CallBackType %d is not kCFSocketReadCallBack", type);
 #if mDNS_AllowPort53
        if (s == info->cfsocket53)
-               err = myrecvfrom(info->socket53, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &to, packetifname);
+               s1 = info->socket53;
        else
 #endif
-       err = myrecvfrom(info->socket, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &to, packetifname);
+       if (s == info->cfsocket)
+               s1 = info->socket;
+
+       err = myrecvfrom(s1, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &to, packetifname);
 
-       if (err < 0) { debugf("myCFSocketCallBack recvfrom error %d", err); return; }
+       if (err < 0 || s1 < 0 || s1 != CFSocketGetNative(s))
+               {
+               LogErrorMessage("CFSocketCallBack: s1 %d native socket %d", s1, CFSocketGetNative(s));
+               LogErrorMessage("CFSocketCallBack: cfs %X, cfsocket53 %X, cfsocket %X", s, info->cfsocket53, info->cfsocket);
+               LogErrorMessage("CFSocketCallBack: skt53 %X, sktv4 %X", info->socket53, info->socket);
+               LogErrorMessage("CFSocketCallBack recvfrom(%d) error %d errno %d", s1, err, errno);
+               return;
+               }
 
        senderaddr.NotAnInteger = from.sin_addr.s_addr;
        senderport.NotAnInteger = from.sin_port;
@@ -278,12 +306,15 @@ mDNSlocal mStatus SetupSocket(struct sockaddr_in *ifa_addr, mDNSIPPort port, int
        struct ip_mreq imr;
        struct sockaddr_in listening_sockaddr;
        CFRunLoopSourceRef rls;
-       
+
+       if (*s > 0) { LogErrorMessage("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
+       if (*c) { LogErrorMessage("SetupSocket ERROR: CFSocketRef %X is already set", *c); return(-1); }
+
        // Open the socket...
        *s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
        *c = NULL;
        if (*s < 0) { perror("socket"); return(*s); }
-       
+
        // ... with a shared UDP port
        err = setsockopt(*s, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
        if (err < 0) { perror("setsockopt - SO_REUSEPORT"); return(err); }
@@ -578,8 +609,8 @@ mDNSlocal mStatus SetupInterface(mDNS *const m, NetworkInterfaceInfo2 *info, str
        if (!err)
                err = SetupSocket(ifa_addr, MulticastDNSPort, &info->socket, &info->cfsocket, &myCFSocketContext);
 
-       debugf("SetupInterface: %s Flags %04X %.4a Registered",
-               ifa->ifa_name, ifa->ifa_flags, &info->ifinfo.ip);
+       debugf("SetupInterface: %s Flags %04X %.4a Registered socket53 %d socket5353 %d",
+               ifa->ifa_name, ifa->ifa_flags, &info->ifinfo.ip, info->socket53, info->socket);
 
        return(err);
        }
index 67365aef218597ebb0dc75f86cdc365c664a34d7..4432196a334189731c0492b407064e09e7c87b82 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -45,6 +45,7 @@
 #include "DNSServiceDiscoveryReply.h"
 
 #include "mDNSClientAPI.h"                             // Defines the interface to the client layer above
+#include "mDNSPlatformFunctions.h"             // For mDNSPlatformTimeNow() and mDNSPlatformOneSecond
 #include "mDNSPlatformEnvironment.h"   // Defines the specific types needed to run mDNS on this platform
 #include "mDNSsprintf.h"
 #include "mDNSvsprintf.h"                              // Used to implement LogErrorMessage();
@@ -94,14 +95,22 @@ struct DNSServiceDomainEnumeration_struct
        DNSQuestion def;        // Question asking for default domain
        };
 
+typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult;
+struct DNSServiceBrowserResult_struct
+       {
+       DNSServiceBrowserResult *next;
+       int resultType;
+       char name[256], type[256], dom[256];
+       };
+
 typedef struct DNSServiceBrowser_struct DNSServiceBrowser;
 struct DNSServiceBrowser_struct
        {
        DNSServiceBrowser *next;
        mach_port_t ClientMachPort;
        DNSQuestion q;
-       int resultType;         // Set to -1 if no outstanding reply
-       char name[256], type[256], dom[256];
+       DNSServiceBrowserResult *results;
+       mDNSs32 lastsuccess;
        };
 
 typedef struct DNSServiceResolver_struct DNSServiceResolver;
@@ -246,6 +255,12 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort)
                *b = (*b)->next;
                debugf("Aborting DNSServiceBrowser %d", ClientMachPort);
                mDNS_StopBrowse(&mDNSStorage, &x->q);
+               while (x->results)
+                       {
+                       DNSServiceBrowserResult *r = x->results;
+                       x->results = x->results->next;
+                       freeL("DNSServiceBrowserResult", r);
+                       }
                freeL("DNSServiceBrowser", x);
                return;
                }
@@ -388,19 +403,9 @@ mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port
 //*************************************************************************************************************
 // Browse for services
 
-mDNSlocal void DeliverInstance(DNSServiceBrowser *x, DNSServiceDiscoveryReplyFlags flags)
-       {
-       kern_return_t status;
-       debugf("DNSServiceBrowserReply_rpc sending reply for %s (%s)", x->name,
-               (flags & DNSServiceDiscoverReplyFlagsMoreComing) ? "more coming" : "last in batch");
-       status = DNSServiceBrowserReply_rpc(x->ClientMachPort, x->resultType, x->name, x->type, x->dom, flags, MDNS_MM_TIMEOUT);
-       x->resultType = -1;
-       if (status == MACH_SEND_TIMED_OUT)
-               AbortBlockedClient(x->ClientMachPort, "browse");
-       }
-
 mDNSlocal void DeliverInstanceTimerCallBack(CFRunLoopTimerRef timer, void *info)
        {
+       mDNSBool tryagain = mDNSfalse;
        DNSServiceBrowser *b = DNSServiceBrowserList;
        (void)timer;    // Parameter not used
 
@@ -411,14 +416,38 @@ mDNSlocal void DeliverInstanceTimerCallBack(CFRunLoopTimerRef timer, void *info)
                // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
                DNSServiceBrowser *x = b;
                b = b->next;
-               if (x->resultType != -1)
-                       DeliverInstance(x, 0);
+               if (x->results)                 // Try to deliver the list of results
+                       {
+                       mDNSs32 now = mDNSPlatformTimeNow();
+                       while (x->results)
+                               {
+                               DNSServiceBrowserResult *const r = x->results;
+                               DNSServiceDiscoveryReplyFlags flags = (r->next) ? DNSServiceDiscoverReplyFlagsMoreComing : 0;
+                               kern_return_t status = DNSServiceBrowserReply_rpc(x->ClientMachPort, r->resultType, r->name, r->type, r->dom, flags, 1);
+                               // If we failed to send the mach message, try again in one second
+                               if (status == MACH_SEND_TIMED_OUT)
+                                       { tryagain = mDNStrue; break; }
+                               else
+                                       {
+                                       x->lastsuccess = now;
+                                       x->results = x->results->next;
+                                       freeL("DNSServiceBrowserResult", r);
+                                       }
+                               }
+                       // If this client hasn't read a single message in the last 60 seconds, abort it
+                       if (now - x->lastsuccess >= 60 * mDNSPlatformOneSecond)
+                               AbortBlockedClient(x->ClientMachPort, "browse");
+                       }
                }
+       if (tryagain)
+               CFRunLoopTimerSetNextFireDate(DeliverInstanceTimer, CFAbsoluteTimeGetCurrent() + 1.0);
        }
 
 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
        {
-       DNSServiceBrowser *x = (DNSServiceBrowser *)question->Context;
+       DNSServiceBrowser *browser = (DNSServiceBrowser *)question->Context;
+       DNSServiceBrowserResult **p = &browser->results;
+       DNSServiceBrowserResult *x = mallocL("DNSServiceBrowserResult", sizeof(*x));
        domainlabel name;
        domainname type, domain;
        
@@ -434,7 +463,7 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
                return;
                }
 
-       if (x->resultType != -1) DeliverInstance(x, DNSServiceDiscoverReplyFlagsMoreComing);
+       if (!x) return;
 
        debugf("FoundInstance: %##s", answer->rdata->u.name.c);
        ConvertDomainLabelToCString_unescaped(&name, x->name);
@@ -443,6 +472,9 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
        if (answer->rrremainingttl)
                 x->resultType = DNSServiceBrowserReplyAddInstance;
        else x->resultType = DNSServiceBrowserReplyRemoveInstance;
+       x->next = NULL;
+       while (*p) p = &(*p)->next;
+       *p = x;
 
        // We schedule this timer 1/10 second in the future because CFRunLoop doesn't respect
        // the relative priority between CFSocket and CFRunLoopTimer, and continues to call
@@ -458,7 +490,8 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds
        DNSServiceBrowser *x = mallocL("DNSServiceBrowser", sizeof(*x));
        if (!x) { debugf("provide_DNSServiceBrowserCreate_rpc: No memory!"); return(mStatus_NoMemoryErr); }
        x->ClientMachPort = client;
-       x->resultType = -1;
+       x->results = NULL;
+       x->lastsuccess = 0;
        x->next = DNSServiceBrowserList;
        DNSServiceBrowserList = x;
 
@@ -638,7 +671,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus re
                }
        }
 
-mDNSlocal void CheckForDuplicateRegistrations(DNSServiceRegistration *x, domainlabel *n, domainname *t, domainname *d)
+mDNSlocal void CheckForDuplicateRegistrations(DNSServiceRegistration *x, domainlabel *n, domainname *t, domainname *d, mDNSIPPort port)
        {
        char name[256];
        int count = 0;
@@ -648,15 +681,15 @@ mDNSlocal void CheckForDuplicateRegistrations(DNSServiceRegistration *x, domainl
        mDNS_sprintf(name, "%##s", &srvname);
 
        for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
-               if (rr->rrtype == kDNSType_SRV && SameDomainName(&rr->name, &srvname))
+               if (rr->rrtype == kDNSType_SRV && rr->rdata->u.srv.port.NotAnInteger == port.NotAnInteger && SameDomainName(&rr->name, &srvname))
                        count++;
 
        if (count)
                {
-               debugf("Client %5d   registering Service Record Set \"%##s\"; WARNING! now have %d instances",
-                       x->ClientMachPort, &srvname, count+1);
-               LogErrorMessage("%5d: WARNING! Bogus client application has now registered %d identical instances of service %##s",
-                       x->ClientMachPort, count+1, &srvname);
+               debugf("Client %5d   registering Service Record Set \"%##s\"; WARNING! now have %d instances port %d",
+                       x->ClientMachPort, &srvname, count+1, (int)port.b[0] << 8 | port.b[1]);
+               LogErrorMessage("%5d: WARNING! Bogus client application has now registered %d identical instances of service %##s port %d",
+                       x->ClientMachPort, count+1, &srvname, (int)port.b[0] << 8 | port.b[1]);
                }
        }
 
@@ -715,7 +748,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un
        debugf("Client %d: provide_DNSServiceRegistrationCreate_rpc", client);
        debugf("Client %d: Register Service: %#s.%##s%##s %d %.30s",
                client, &x->name, &t, &d, (int)port.b[0] << 8 | port.b[1], txtRecord);
-       CheckForDuplicateRegistrations(x, &x->name, &t, &d);
+       if (port.NotAnInteger) CheckForDuplicateRegistrations(x, &x->name, &t, &d, port);
        err = mDNS_RegisterService(&mDNSStorage, &x->s, &x->name, &t, &d, mDNSNULL, port, txtinfo, data_len, RegCallback, x);
 
        if (err) AbortClient(client);
index e216582b1fa20bc21255cddf73d80a05c878320d..8d4ec196818ed01f95b4a4713c925de3c011f73d 100755 (executable)
@@ -31,6 +31,8 @@
 #include "mDNSPlatformFunctions.h"             // Defines the interface required of the supporting layer below
 #include "mDNSsprintf.h"
 
+extern void LogErrorMessage(const char *format, ...);
+
 #if(defined(_MSC_VER))
        // Disable warnings about Microsoft Visual Studio/C++ not understanding "pragma unused"
     #pragma warning( disable:4068 )
@@ -684,6 +686,7 @@ mDNSlocal mDNSu32 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
                case kDNSType_CNAME:// Same as PTR
                case kDNSType_PTR:      return(CompressedDomainNameLength(&rr->rdata->u.name, name));
                case kDNSType_TXT:  return(rr->rdata->RDLength); // TXT is not self-describing, so have to just trust rdlength
+               case kDNSType_AAAA:     return(16); break;
                case kDNSType_SRV:      return(6 + CompressedDomainNameLength(&rr->rdata->u.srv.target, name));
                default:                        debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
                                                        return(rr->rdata->RDLength);
@@ -696,7 +699,7 @@ mDNSlocal DNSQuestion *CacheRRActive(const mDNS *const m, ResourceRecord *rr)
        {
        DNSQuestion *q;
        for (q = m->ActiveQuestions; q; q=q->next)              // Scan our list of questions
-               if (!q->DuplicateOf && ResourceRecordAnswersQuestion(rr, q))
+               if (q->ThisQInterval > 0 && !q->DuplicateOf && ResourceRecordAnswersQuestion(rr, q))
                        return(q);
        return(mDNSNULL);
        }
@@ -880,8 +883,11 @@ mDNSlocal void mDNS_Deregister_internal(mDNS *const m, ResourceRecord *const rr,
                        rr->Callback(m, rr, mStatus_MemFree);
                else if (drt == mDNS_Dereg_conflict)
                        {
-                       m->SuppressProbes = timenow + mDNSPlatformOneSecond;
-                       if (m->SuppressProbes == 0) m->SuppressProbes = 1;
+                       m->ProbeFailTime = timenow;
+                       // If we've had ten probe failures, rate-limit to one every five seconds
+                       // The result is ORed with 1 to make sure SuppressProbes is not accidentally set to zero
+                       if (m->NumFailedProbes < 10) m->NumFailedProbes++;
+                       else m->SuppressProbes = (timenow + mDNSPlatformOneSecond * 5) | 1;
                        if (rr->Callback) rr->Callback(m, rr, mStatus_NameConflict);
                        }
                }
@@ -1334,7 +1340,8 @@ mDNSlocal const mDNSu8 *getResourceRecord(const DNSMessage *msg, const mDNSu8 *p
                                                                        rr->rrtype, pktrdlength, rr->rdata->MaxRDLength);
                                                                return(mDNSNULL);
                                                                }
-                                                       debugf("getResourceRecord: Warning! Reading resource type %d as opaque data", rr->rrtype);
+                                                       if (rr->rrtype != kDNSType_AAAA)
+                                                               debugf("getResourceRecord: Warning! Reading resource type %d as opaque data", rr->rrtype);
                                                        // Note: Just because we don't understand the record type, that doesn't
                                                        // mean we fail. The DNS protocol specifies rdlength, so we can
                                                        // safely skip over unknown records and ignore them.
@@ -1491,7 +1498,7 @@ mDNSlocal mDNSu8 *BuildResponse(mDNS *const m,
 
        if (m->CurrentRecord) debugf("BuildResponse ERROR m->CurrentRecord already set");
        m->CurrentRecord = m->ResourceRecords;
-       
+
        // If we're sleeping, only send deregistrations
        if (m->SleepState)
                {
@@ -1568,7 +1575,7 @@ mDNSlocal mDNSu8 *BuildResponse(mDNS *const m,
                                        if (response->h.numAnswers == 0) debugf("BuildResponse announcements failed");
                                        if (newptr || response->h.numAnswers == 0)
                                                {
-                                               if (minExistingAnnounceInterval > rr->NextSendInterval)
+                                               if (minExistingAnnounceInterval < rr->NextSendInterval)
                                                        minExistingAnnounceInterval = rr->NextSendInterval;
                                                rr->SendPriority      = 0;
                                                rr->Requester         = zeroIPAddr;
@@ -1701,7 +1708,7 @@ mDNSlocal void SendResponses(mDNS *const m, const mDNSs32 timenow)
                }
        }
 
-#define TimeToSendThisQuestion(Q,time) (!(Q)->DuplicateOf && time - (Q)->NextQTime >= 0)
+#define TimeToSendThisQuestion(Q,time) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf && (time) - (Q)->NextQTime >= 0)
 
 mDNSlocal mDNSBool HaveQueries(const mDNS *const m, const mDNSs32 timenow)
        {
@@ -2014,7 +2021,7 @@ mDNSlocal void TriggerImmediateQuestions(mDNS *const m, const ResourceRecord *co
        mDNSs32 needquery = timenow + mDNSPlatformOneSecond;
        DNSQuestion *q;
        for (q = m->ActiveQuestions; q; q=q->next)              // Scan our list of questions
-               if (!q->DuplicateOf && q->NextQTime - needquery > 0 && ResourceRecordAnswersQuestion(rr, q))
+               if (q->ThisQInterval > 0 && !q->DuplicateOf && q->NextQTime - needquery > 0 && ResourceRecordAnswersQuestion(rr, q))
                        {
                        q->NextQTime     = needquery;
                        // As long as responses are still coming in, don't do the exponential backoff
@@ -2096,7 +2103,18 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m, const mDNSs32 timenow)
        m->CurrentQuestion = q;         // Indicate which question we're answering, so we'll know if it gets deleted
        for (rr=m->rrcache; rr && m->CurrentQuestion == q; rr=rr->next)
                if (ResourceRecordAnswersQuestion(rr, q))
-                       AnswerQuestionWithResourceRecord(m, q, rr, timenow);
+                       {
+                       mDNSu32 SecsSinceRcvd = ((mDNSu32)(timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
+                       if (rr->rroriginalttl <= SecsSinceRcvd) rr->rrremainingttl = 0;
+                       else rr->rrremainingttl = rr->rroriginalttl - SecsSinceRcvd;
+                       
+                       // We only give positive responses to new questions.
+                       // Since this question is new, it has not received any answers yet, so there's no point
+                       // telling it about records that are going away that it never heard about in the first place.
+                       if (rr->rrremainingttl > 0)
+                               AnswerQuestionWithResourceRecord(m, q, rr, timenow);
+                       // MUST NOT touch q again after calling AnswerQuestionWithResourceRecord()
+                       }
        m->CurrentQuestion = mDNSNULL;
        m->lock_rrcache = 0;
        }
@@ -2111,9 +2129,9 @@ mDNSlocal void FlushCacheRecords(mDNS *const m, mDNSIPAddr InterfaceAddr, const
                        {
                        // If the record's interface matches the one we're flushing,
                        // then pretend we just received a 'goodbye' packet for this record.
-                       rr->TimeRcvd          = timenow;
-                       rr->UnansweredQueries = 0;
-                       rr->rroriginalttl     = 1;
+                       rr->TimeRcvd          = timenow - mDNSPlatformOneSecond * 60;
+                       rr->UnansweredQueries = 2;
+                       rr->rroriginalttl     = 0;
                        count++;
                        }
                }
@@ -2360,6 +2378,9 @@ mDNSexport void mDNSCoreTask(mDNS *const m)
        if (m->SuppressProbes && timenow - m->SuppressProbes >= 0)
                m->SuppressProbes = 0;
 
+       if (m->NumFailedProbes && timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10)
+               m->NumFailedProbes = 0;
+
        // 1. See if we can answer any of our new local questions from the cache
        while (m->NewQuestions) AnswerNewQuestion(m, timenow);
 
@@ -2373,12 +2394,15 @@ mDNSexport void mDNSCoreTask(mDNS *const m)
                }
        else if (m->SuppressSending == 0 || timenow - m->SuppressSending >= 0)
                {
+               int i;
                // If the platform code is ready,
                // and we're not suppressing packet generation right now
                // send our responses, probes, and questions
                m->SuppressSending = 0;
-               while (HaveResponses(m, timenow)) SendResponses(m, timenow);
-               while (HaveQueries  (m, timenow)) SendQueries  (m, timenow);
+               for (i=0; i<100 && HaveResponses(m, timenow); i++) SendResponses(m, timenow);
+               if (i >= 100) LogErrorMessage("mDNSCoreTask: HaveResponses returned true %d times", i);
+               for (i=0; i<100 && HaveQueries  (m, timenow); i++) SendQueries  (m, timenow);
+               if (i >= 100) LogErrorMessage("mDNSCoreTask: HaveQueries returned true %d times", i);
                }
 
        if (m->rrcache_size) TidyRRCache(m, timenow);
@@ -2415,7 +2439,7 @@ mDNSexport void mDNSCoreSleep(mDNS *const m, mDNSBool sleepstate)
                        rr->NextSendInterval  = DefaultSendIntervalForRecordType(rr->RecordType);
                        }
                for (q = m->ActiveQuestions; q; q=q->next)              // Scan our list of questions
-                       if (!q->DuplicateOf)
+                       if (q->ThisQInterval > 0 && !q->DuplicateOf)
                                {
                                q->NextQTime     = timenow;
                                q->ThisQInterval = mDNSPlatformOneSecond;  // MUST NOT be zero for an active question
@@ -2623,10 +2647,10 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
                                if (!result) result = CompareRData(&pktrr, our);
                                switch (result)
                                        {
-                                       case  1:        debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->name.c, DNSTypeName(our->rrtype));
+                                       case -1:        debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->name.c, DNSTypeName(our->rrtype));
                                                                break;
                                        case  0:        break;
-                                       case -1:        debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->name.c, DNSTypeName(our->rrtype));
+                                       case  1:        debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->name.c, DNSTypeName(our->rrtype));
                                                                mDNS_Deregister_internal(m, our, timenow, mDNS_Dereg_conflict);
                                                                return;
                                        }
@@ -2958,6 +2982,11 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                                rr->ProbeCount       = DefaultProbeCountForTypeUnique + 1;
                                                                rr->NextSendTime     = timenow;
                                                                rr->NextSendInterval = DefaultSendIntervalForRecordType(kDNSRecordTypeUnique);
+                                                               m->ProbeFailTime = timenow;
+                                                               // If we've had ten probe failures, rate-limit to one every five seconds
+                                                               // The result is ORed with 1 to make sure SuppressProbes is not accidentally set to zero
+                                                               if (m->NumFailedProbes < 10) m->NumFailedProbes++;
+                                                               else m->SuppressProbes = (timenow + mDNSPlatformOneSecond * 5) | 1;
                                                                }
                                                        else
                                                                {
@@ -3080,10 +3109,16 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
        {
        DNSQuestion *q;
-       for (q = m->ActiveQuestions; q; q=q->next)              // Scan our list of questions
-               if (q->rrtype  == question->rrtype  &&
-                       q->rrclass == question->rrclass &&
-                       SameDomainName(&q->name, &question->name)) return(q);
+       // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
+       // This prevents circular references, where two questions are each marked as a duplicate of the other.
+       // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
+       // further in the list.
+       for (q = m->ActiveQuestions; q && q != question; q=q->next)                                                     // Scan our list of questions
+               if (q->InterfaceAddr.NotAnInteger == question->InterfaceAddr.NotAnInteger &&    // for another question with the same InterfaceID,
+                       q->rrtype      == question->rrtype                                    &&        // type,
+                       q->rrclass     == question->rrclass                                   &&        // class,
+                       SameDomainName(&q->name, &question->name))                                                                      // and name
+                       return(q);
        return(mDNSNULL);
        }
 
@@ -3117,6 +3152,17 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                        return(mStatus_AlreadyRegistered);
                        }
 
+               if (question->InterfaceAddr.NotAnInteger)
+                       {
+                       NetworkInterfaceInfo *p = m->HostInterfaces;
+                       while (p && p->ip.NotAnInteger != question->InterfaceAddr.NotAnInteger) p=p->next;
+                       if (!p)
+                               {
+                               LogErrorMessage("mDNS_StartQuery_internal: question->InterfaceAddr %.4a not found in interface list", &question->InterfaceAddr);
+                               question->InterfaceAddr.NotAnInteger = 0;
+                               }
+                       }
+
                question->next          = mDNSNULL;
                question->NextQTime     = timenow;
                question->ThisQInterval = mDNSPlatformOneSecond;  // MUST NOT be zero for an active question
@@ -3140,9 +3186,8 @@ mDNSlocal void mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const questio
 
        UpdateQuestionDuplicates(m, question);
 
-       question->next = mDNSNULL;
-       question->ThisQInterval = 0;
-       question->NextQInterval = 0;
+       question->ThisQInterval = -1;
+       question->NextQInterval = -1;
        
        // If we just deleted the question that AnswerLocalQuestions() is about to look at,
        // bump its pointer forward one question.
@@ -3158,6 +3203,8 @@ mDNSlocal void mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const questio
                m->NewQuestions    = m->NewQuestions->next;
                }
        
+       // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
+       question->next = mDNSNULL;
        }
 
 mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
@@ -3201,13 +3248,16 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R
        if (!query->GotSRV)
                {
                query->GotSRV             = mDNStrue;
+               query->qADD.InterfaceAddr = answer->InterfaceAddr;
                query->qADD.name          = answer->rdata->u.srv.target;
                mDNS_StartQuery_internal(m, &query->qADD, mDNSPlatformTimeNow());
                }
        // If this is not our first answer, only re-issue the address query if the target host name has changed
-       else if (!SameDomainName(&query->qADD.name, &answer->rdata->u.srv.target))
+       else if (query->qADD.InterfaceAddr.NotAnInteger != answer->InterfaceAddr.NotAnInteger ||
+               !SameDomainName(&query->qADD.name, &answer->rdata->u.srv.target))
                {
                mDNS_StopQuery_internal(m, &query->qADD);
+               query->qADD.InterfaceAddr = answer->InterfaceAddr;
                query->qADD.name          = answer->rdata->u.srv.target;
                mDNS_StartQuery_internal(m, &query->qADD, mDNSPlatformTimeNow());
                }
@@ -3317,9 +3367,9 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
 mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query)
        {
        mDNS_Lock(m);
-       if (query->qSRV.ThisQInterval) mDNS_StopQuery_internal(m, &query->qSRV);
-       if (query->qTXT.ThisQInterval) mDNS_StopQuery_internal(m, &query->qTXT);
-       if (query->qADD.ThisQInterval) mDNS_StopQuery_internal(m, &query->qADD);
+       if (query->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &query->qSRV);
+       if (query->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &query->qTXT);
+       if (query->qADD.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &query->qADD);
        mDNS_Unlock(m);
        }
 
@@ -3552,6 +3602,17 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                // ... Add an HINFO record, etc.?
                }
 
+       { // Reactivate Interface Questions
+       DNSQuestion *q;
+       for (q = m->ActiveQuestions; q; q=q->next)              // Scan our list of questions
+               if (!q->InterfaceAddr.NotAnInteger || q->InterfaceAddr.NotAnInteger == set->ip.NotAnInteger)
+                       {
+                       q->NextQTime     = timenow;
+                       q->ThisQInterval = mDNSPlatformOneSecond;  // MUST be > zero for an active question
+                       q->NextQInterval = mDNSPlatformOneSecond;
+                       }
+       }
+
        set->next = mDNSNULL;
        *p = set;
        mDNS_Unlock(m);
@@ -3596,6 +3657,13 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
        // Flush any cache entries we received on this interface
        FlushCacheRecords(m, set->ip, timenow);
 
+       { // Deactivate Interface Questions
+       DNSQuestion *q;
+       for (q = m->ActiveQuestions; q; q=q->next)
+               if (q->InterfaceAddr.NotAnInteger == set->ip.NotAnInteger)
+                       q->ThisQInterval = 0;
+       }
+
        // If we were advertising on this interface, deregister now
        // When doing the mDNS_Close processing, we first call mDNS_DeadvertiseInterface for each interface
        // so by the time the platform support layer gets to call mDNS_DeregisterInterface,
@@ -3665,9 +3733,9 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        if (host && host->c[0]) sr->Host = *host;
        else sr->Host.c[0] = 0;
        
-       mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, zeroIPAddr, kDNSType_PTR, 24*3600, kDNSRecordTypeShared, ServiceCallback, sr);
-       mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, zeroIPAddr, kDNSType_SRV, 60,      kDNSRecordTypeUnique, ServiceCallback, sr);
-       mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, zeroIPAddr, kDNSType_TXT, 60,      kDNSRecordTypeUnique, ServiceCallback, sr);
+       mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, zeroIPAddr, kDNSType_PTR, 2*3600, kDNSRecordTypeShared, ServiceCallback, sr);
+       mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, zeroIPAddr, kDNSType_SRV, 60,     kDNSRecordTypeUnique, ServiceCallback, sr);
+       mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, zeroIPAddr, kDNSType_TXT, 60,     kDNSRecordTypeUnique, ServiceCallback, sr);
        
        // If the client is registering an oversized TXT record,
        // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
@@ -3819,7 +3887,7 @@ mDNSexport void mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
 mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, ResourceRecord *rr,
        mDNSu8 DomainType, const mDNSIPAddr InterfaceAddr, char *domname)
        {
-       mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceAddr, kDNSType_PTR, 24*3600, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
+       mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceAddr, kDNSType_PTR, 2*3600, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
        ConvertCStringToDomainName(mDNS_DomainTypeNames[DomainType], &rr->name);
        ConvertCStringToDomainName(domname, &rr->rdata->u.name);
        return(mDNS_Register(m, rr));
@@ -3871,6 +3939,9 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->CurrentRecord      = mDNSNULL;
        m->HostInterfaces     = mDNSNULL;
        m->SuppressSending    = 0;
+       m->ProbeFailTime      = 0;
+       m->NumFailedProbes    = 0;
+       m->SuppressProbes     = 0;
        m->SleepState         = mDNSfalse;
        m->NetChanged         = mDNSfalse;
 
index c919500178883221242313c937f2a61eeefeeab0..c6ba060cf18d665ccb97b1f9ace4efa8d2bb2f9b 100755 (executable)
@@ -50,6 +50,7 @@ typedef enum                          // From RFC 1035
        kDNSType_MX,                    // 15 Mail Exchanger
        kDNSType_TXT,                   // 16 Arbitrary text string
        
+       kDNSType_AAAA = 28,             // 28 IPv6 address
        kDNSType_SRV = 33,              // 33 Service record
 
        kDNSQType_ANY = 255             // Not a DNS type, but a DNS query type, meaning "all types"
@@ -170,7 +171,7 @@ typedef struct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname t
 
 typedef union
        {
-       mDNSu8     data[512];   // Generic untyped data (temporarily set 512 for the benefit of iChat)
+       mDNSu8     data[768];   // Generic untyped data (temporarily set 768 for the benefit of Airport Extreme printing)
        mDNSIPAddr ip;                  // For 'A' record
        domainname name;                // For PTR and CNAME records
        UTF8str255 txt;                 // For TXT record
@@ -382,6 +383,8 @@ struct mDNS_struct
        ResourceRecord *CurrentRecord;  // Next ResourceRecord about to be examined
        NetworkInterfaceInfo *HostInterfaces;
        mDNSs32 SuppressSending;
+       mDNSs32 ProbeFailTime;
+       mDNSs32 NumFailedProbes;
        mDNSs32 SuppressProbes;
        mDNSBool SleepState;
        mDNSBool NetChanged;