Thu Oct 15 15:58:34 2015 UTC ()
Revert prior. Instead just send the diagnostic to debugf instead of syslog as it's not really that interesting.


(roy)
diff -r1.5 -r1.6 src/external/apache2/mDNSResponder/dist/mDNSCore/mDNS.c

cvs diff -r1.5 -r1.6 src/external/apache2/mDNSResponder/dist/mDNSCore/mDNS.c (switch to unified diff)

--- src/external/apache2/mDNSResponder/dist/mDNSCore/mDNS.c 2015/10/15 10:29:57 1.5
+++ src/external/apache2/mDNSResponder/dist/mDNSCore/mDNS.c 2015/10/15 15:58:34 1.6
@@ -1,1700 +1,1698 @@ @@ -1,1700 +1,1698 @@
1/* -*- Mode: C; tab-width: 4 -*- 1/* -*- Mode: C; tab-width: 4 -*-
2 * 2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. 3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 * 4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License. 6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at 7 * You may obtain a copy of the License at
8 *  8 *
9 * http://www.apache.org/licenses/LICENSE-2.0 9 * http://www.apache.org/licenses/LICENSE-2.0
10 *  10 *
11 * Unless required by applicable law or agreed to in writing, software 11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, 12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and 14 * See the License for the specific language governing permissions and
15 * limitations under the License. 15 * limitations under the License.
16 * 16 *
17 * This code is completely 100% portable C. It does not depend on any external header files 17 * This code is completely 100% portable C. It does not depend on any external header files
18 * from outside the mDNS project -- all the types it expects to find are defined right here. 18 * from outside the mDNS project -- all the types it expects to find are defined right here.
19 *  19 *
20 * The previous point is very important: This file does not depend on any external 20 * The previous point is very important: This file does not depend on any external
21 * header files. It should compile on *any* platform that has a C compiler, without 21 * header files. It should compile on *any* platform that has a C compiler, without
22 * making *any* assumptions about availability of so-called "standard" C functions, 22 * making *any* assumptions about availability of so-called "standard" C functions,
23 * routines, or types (which may or may not be present on any given platform). 23 * routines, or types (which may or may not be present on any given platform).
24 24
25 * Formatting notes: 25 * Formatting notes:
26 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion 26 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
27 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>, 27 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
28 * but for the sake of brevity here I will say just this: Curly braces are not syntactially 28 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
29 * part of an "if" statement; they are the beginning and ending markers of a compound statement; 29 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
30 * therefore common sense dictates that if they are part of a compound statement then they 30 * therefore common sense dictates that if they are part of a compound statement then they
31 * should be indented to the same level as everything else in that compound statement. 31 * should be indented to the same level as everything else in that compound statement.
32 * Indenting curly braces at the same level as the "if" implies that curly braces are 32 * Indenting curly braces at the same level as the "if" implies that curly braces are
33 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;" 33 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
34 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't 34 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
35 * understand why variable y is not of type "char*" just proves the point that poor code 35 * understand why variable y is not of type "char*" just proves the point that poor code
36 * layout leads people to unfortunate misunderstandings about how the C language really works.) 36 * layout leads people to unfortunate misunderstandings about how the C language really works.)
37 */ 37 */
38 38
39#include "DNSCommon.h" // Defines general DNS untility routines 39#include "DNSCommon.h" // Defines general DNS untility routines
40#include "uDNS.h" // Defines entry points into unicast-specific routines 40#include "uDNS.h" // Defines entry points into unicast-specific routines
41 41
42// Disable certain benign warnings with Microsoft compilers 42// Disable certain benign warnings with Microsoft compilers
43#if(defined(_MSC_VER)) 43#if(defined(_MSC_VER))
44 // Disable "conditional expression is constant" warning for debug macros. 44 // Disable "conditional expression is constant" warning for debug macros.
45 // Otherwise, this generates warnings for the perfectly natural construct "while(1)" 45 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
46 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know 46 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
47 #pragma warning(disable:4127) 47 #pragma warning(disable:4127)
48  48
49 // Disable "assignment within conditional expression". 49 // Disable "assignment within conditional expression".
50 // Other compilers understand the convention that if you place the assignment expression within an extra pair 50 // Other compilers understand the convention that if you place the assignment expression within an extra pair
51 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary. 51 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
52 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal 52 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
53 // to the compiler that the assignment is intentional, we have to just turn this warning off completely. 53 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
54 #pragma warning(disable:4706) 54 #pragma warning(disable:4706)
55#endif 55#endif
56 56
57#if APPLE_OSX_mDNSResponder 57#if APPLE_OSX_mDNSResponder
58 58
59#include <WebFilterDNS/WebFilterDNS.h> 59#include <WebFilterDNS/WebFilterDNS.h>
60 60
61#if ! NO_WCF 61#if ! NO_WCF
62WCFConnection *WCFConnectionNew(void) __attribute__((weak_import)); 62WCFConnection *WCFConnectionNew(void) __attribute__((weak_import));
63void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import)); 63void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
64 64
65// Do we really need to define a macro for "if"? 65// Do we really need to define a macro for "if"?
66#define CHECK_WCF_FUNCTION(X) if (X) 66#define CHECK_WCF_FUNCTION(X) if (X)
67#endif // ! NO_WCF 67#endif // ! NO_WCF
68 68
69#else 69#else
70 70
71#define NO_WCF 1 71#define NO_WCF 1
72#endif // APPLE_OSX_mDNSResponder 72#endif // APPLE_OSX_mDNSResponder
73 73
74// Forward declarations 74// Forward declarations
75mDNSlocal void BeginSleepProcessing(mDNS *const m); 75mDNSlocal void BeginSleepProcessing(mDNS *const m);
76mDNSlocal void RetrySPSRegistrations(mDNS *const m); 76mDNSlocal void RetrySPSRegistrations(mDNS *const m);
77mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password); 77mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password);
78mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); 78mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
79mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q); 79mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
80mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q); 80mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q);
81 81
82// *************************************************************************** 82// ***************************************************************************
83#if COMPILER_LIKES_PRAGMA_MARK 83#if COMPILER_LIKES_PRAGMA_MARK
84#pragma mark - Program Constants 84#pragma mark - Program Constants
85#endif 85#endif
86 86
87#define NO_HINFO 1 87#define NO_HINFO 1
88 88
89 89
90// Any records bigger than this are considered 'large' records 90// Any records bigger than this are considered 'large' records
91#define SmallRecordLimit 1024 91#define SmallRecordLimit 1024
92 92
93#define kMaxUpdateCredits 10 93#define kMaxUpdateCredits 10
94#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6) 94#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
95 95
96mDNSexport const char *const mDNS_DomainTypeNames[] = 96mDNSexport const char *const mDNS_DomainTypeNames[] =
97 { 97 {
98 "b._dns-sd._udp.", // Browse 98 "b._dns-sd._udp.", // Browse
99 "db._dns-sd._udp.", // Default Browse 99 "db._dns-sd._udp.", // Default Browse
100 "lb._dns-sd._udp.", // Automatic Browse 100 "lb._dns-sd._udp.", // Automatic Browse
101 "r._dns-sd._udp.", // Registration 101 "r._dns-sd._udp.", // Registration
102 "dr._dns-sd._udp." // Default Registration 102 "dr._dns-sd._udp." // Default Registration
103 }; 103 };
104 104
105#ifdef UNICAST_DISABLED 105#ifdef UNICAST_DISABLED
106#define uDNS_IsActiveQuery(q, u) mDNSfalse 106#define uDNS_IsActiveQuery(q, u) mDNSfalse
107#endif 107#endif
108 108
109// *************************************************************************** 109// ***************************************************************************
110#if COMPILER_LIKES_PRAGMA_MARK 110#if COMPILER_LIKES_PRAGMA_MARK
111#pragma mark - 111#pragma mark -
112#pragma mark - General Utility Functions 112#pragma mark - General Utility Functions
113#endif 113#endif
114 114
115// If there is a authoritative LocalOnly record that answers questions of type A, AAAA and CNAME 115// If there is a authoritative LocalOnly record that answers questions of type A, AAAA and CNAME
116// this returns true. Main use is to handle /etc/hosts records.  116// this returns true. Main use is to handle /etc/hosts records.
117#define LORecordAnswersAddressType(rr) ((rr)->ARType == AuthRecordLocalOnly && \ 117#define LORecordAnswersAddressType(rr) ((rr)->ARType == AuthRecordLocalOnly && \
118 (rr)->resrec.RecordType & kDNSRecordTypeUniqueMask && \ 118 (rr)->resrec.RecordType & kDNSRecordTypeUniqueMask && \
119 ((rr)->resrec.rrtype == kDNSType_A || (rr)->resrec.rrtype == kDNSType_AAAA || \ 119 ((rr)->resrec.rrtype == kDNSType_A || (rr)->resrec.rrtype == kDNSType_AAAA || \
120 (rr)->resrec.rrtype == kDNSType_CNAME)) 120 (rr)->resrec.rrtype == kDNSType_CNAME))
121 121
122#define FollowCNAME(q, rr, AddRecord) (AddRecord && (q)->qtype != kDNSType_CNAME && \ 122#define FollowCNAME(q, rr, AddRecord) (AddRecord && (q)->qtype != kDNSType_CNAME && \
123 (rr)->RecordType != kDNSRecordTypePacketNegative && \ 123 (rr)->RecordType != kDNSRecordTypePacketNegative && \
124 (rr)->rrtype == kDNSType_CNAME) 124 (rr)->rrtype == kDNSType_CNAME)
125 125
126mDNSlocal void SetNextQueryStopTime(mDNS *const m, const DNSQuestion *const q) 126mDNSlocal void SetNextQueryStopTime(mDNS *const m, const DNSQuestion *const q)
127 { 127 {
128 if (m->mDNS_busy != m->mDNS_reentrancy+1) 128 if (m->mDNS_busy != m->mDNS_reentrancy+1)
129 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 129 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
130 130
131#if ForceAlerts 131#if ForceAlerts
132 if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; 132 if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0;
133#endif 133#endif
134 134
135 if (m->NextScheduledStopTime - q->StopTime > 0) 135 if (m->NextScheduledStopTime - q->StopTime > 0)
136 m->NextScheduledStopTime = q->StopTime; 136 m->NextScheduledStopTime = q->StopTime;
137 } 137 }
138 138
139mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q) 139mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
140 { 140 {
141 if (m->mDNS_busy != m->mDNS_reentrancy+1) 141 if (m->mDNS_busy != m->mDNS_reentrancy+1)
142 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 142 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
143 143
144#if ForceAlerts 144#if ForceAlerts
145 if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; 145 if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0;
146#endif 146#endif
147 147
148 if (ActiveQuestion(q)) 148 if (ActiveQuestion(q))
149 { 149 {
150 // Depending on whether this is a multicast or unicast question we want to set either: 150 // Depending on whether this is a multicast or unicast question we want to set either:
151 // m->NextScheduledQuery = NextQSendTime(q) or 151 // m->NextScheduledQuery = NextQSendTime(q) or
152 // m->NextuDNSEvent = NextQSendTime(q) 152 // m->NextuDNSEvent = NextQSendTime(q)
153 mDNSs32 *const timer = mDNSOpaque16IsZero(q->TargetQID) ? &m->NextScheduledQuery : &m->NextuDNSEvent; 153 mDNSs32 *const timer = mDNSOpaque16IsZero(q->TargetQID) ? &m->NextScheduledQuery : &m->NextuDNSEvent;
154 if (*timer - NextQSendTime(q) > 0) 154 if (*timer - NextQSendTime(q) > 0)
155 *timer = NextQSendTime(q); 155 *timer = NextQSendTime(q);
156 } 156 }
157 } 157 }
158 158
159mDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e) 159mDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e)
160 { 160 {
161#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 161#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
162 unsigned int i; 162 unsigned int i;
163 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; 163 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
164#endif 164#endif
165 e->next = r->rrauth_free; 165 e->next = r->rrauth_free;
166 r->rrauth_free = e; 166 r->rrauth_free = e;
167 r->rrauth_totalused--; 167 r->rrauth_totalused--;
168 } 168 }
169 169
170mDNSlocal void ReleaseAuthGroup(AuthHash *r, AuthGroup **cp) 170mDNSlocal void ReleaseAuthGroup(AuthHash *r, AuthGroup **cp)
171 { 171 {
172 AuthEntity *e = (AuthEntity *)(*cp); 172 AuthEntity *e = (AuthEntity *)(*cp);
173 LogMsg("ReleaseAuthGroup: Releasing AuthGroup %##s", (*cp)->name->c); 173 LogMsg("ReleaseAuthGroup: Releasing AuthGroup %##s", (*cp)->name->c);
174 if ((*cp)->rrauth_tail != &(*cp)->members) 174 if ((*cp)->rrauth_tail != &(*cp)->members)
175 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrauth_tail != &(*cp)->members)"); 175 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrauth_tail != &(*cp)->members)");
176 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); 176 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
177 (*cp)->name = mDNSNULL; 177 (*cp)->name = mDNSNULL;
178 *cp = (*cp)->next; // Cut record from list 178 *cp = (*cp)->next; // Cut record from list
179 ReleaseAuthEntity(r, e); 179 ReleaseAuthEntity(r, e);
180 } 180 }
181 181
182mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const PreserveAG) 182mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const PreserveAG)
183 { 183 {
184 AuthEntity *e = mDNSNULL; 184 AuthEntity *e = mDNSNULL;
185 185
186 if (r->rrauth_lock) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } 186 if (r->rrauth_lock) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
187 r->rrauth_lock = 1; 187 r->rrauth_lock = 1;
188  188
189 if (!r->rrauth_free) 189 if (!r->rrauth_free)
190 { 190 {
191 // We allocate just one AuthEntity at a time because we need to be able 191 // We allocate just one AuthEntity at a time because we need to be able
192 // free them all individually which normally happens when we parse /etc/hosts into 192 // free them all individually which normally happens when we parse /etc/hosts into
193 // AuthHash where we add the "new" entries and discard (free) the already added 193 // AuthHash where we add the "new" entries and discard (free) the already added
194 // entries. If we allocate as chunks, we can't free them individually. 194 // entries. If we allocate as chunks, we can't free them individually.
195 AuthEntity *storage = mDNSPlatformMemAllocate(sizeof(AuthEntity)); 195 AuthEntity *storage = mDNSPlatformMemAllocate(sizeof(AuthEntity));
196 storage->next = mDNSNULL; 196 storage->next = mDNSNULL;
197 r->rrauth_free = storage; 197 r->rrauth_free = storage;
198 } 198 }
199  199
200 // If we still have no free records, recycle all the records we can. 200 // If we still have no free records, recycle all the records we can.
201 // Enumerating the entire auth is moderately expensive, so when we do it, we reclaim all the records we can in one pass. 201 // Enumerating the entire auth is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
202 if (!r->rrauth_free) 202 if (!r->rrauth_free)
203 { 203 {
204 mDNSu32 oldtotalused = r->rrauth_totalused; 204 mDNSu32 oldtotalused = r->rrauth_totalused;
205 mDNSu32 slot; 205 mDNSu32 slot;
206 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 206 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
207 { 207 {
208 AuthGroup **cp = &r->rrauth_hash[slot]; 208 AuthGroup **cp = &r->rrauth_hash[slot];
209 while (*cp) 209 while (*cp)
210 { 210 {
211 if ((*cp)->members || (*cp)==PreserveAG) cp=&(*cp)->next; 211 if ((*cp)->members || (*cp)==PreserveAG) cp=&(*cp)->next;
212 else ReleaseAuthGroup(r, cp); 212 else ReleaseAuthGroup(r, cp);
213 } 213 }
214 } 214 }
215 LogInfo("GetAuthEntity: Recycled %d records to reduce auth cache from %d to %d", 215 LogInfo("GetAuthEntity: Recycled %d records to reduce auth cache from %d to %d",
216 oldtotalused - r->rrauth_totalused, oldtotalused, r->rrauth_totalused); 216 oldtotalused - r->rrauth_totalused, oldtotalused, r->rrauth_totalused);
217 } 217 }
218 218
219 if (r->rrauth_free) // If there are records in the free list, take one 219 if (r->rrauth_free) // If there are records in the free list, take one
220 { 220 {
221 e = r->rrauth_free; 221 e = r->rrauth_free;
222 r->rrauth_free = e->next; 222 r->rrauth_free = e->next;
223 if (++r->rrauth_totalused >= r->rrauth_report) 223 if (++r->rrauth_totalused >= r->rrauth_report)
224 { 224 {
225 LogInfo("RR Auth now using %ld objects", r->rrauth_totalused); 225 LogInfo("RR Auth now using %ld objects", r->rrauth_totalused);
226 if (r->rrauth_report < 100) r->rrauth_report += 10; 226 if (r->rrauth_report < 100) r->rrauth_report += 10;
227 else if (r->rrauth_report < 1000) r->rrauth_report += 100; 227 else if (r->rrauth_report < 1000) r->rrauth_report += 100;
228 else r->rrauth_report += 1000; 228 else r->rrauth_report += 1000;
229 } 229 }
230 mDNSPlatformMemZero(e, sizeof(*e)); 230 mDNSPlatformMemZero(e, sizeof(*e));
231 } 231 }
232 232
233 r->rrauth_lock = 0; 233 r->rrauth_lock = 0;
234 234
235 return(e); 235 return(e);
236 } 236 }
237 237
238mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) 238mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
239 { 239 {
240 AuthGroup *ag; 240 AuthGroup *ag;
241 for (ag = r->rrauth_hash[slot]; ag; ag=ag->next) 241 for (ag = r->rrauth_hash[slot]; ag; ag=ag->next)
242 if (ag->namehash == namehash && SameDomainName(ag->name, name)) 242 if (ag->namehash == namehash && SameDomainName(ag->name, name))
243 break; 243 break;
244 return(ag); 244 return(ag);
245 } 245 }
246 246
247mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) 247mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr)
248 { 248 {
249 return(AuthGroupForName(r, slot, rr->namehash, rr->name)); 249 return(AuthGroupForName(r, slot, rr->namehash, rr->name));
250 } 250 }
251 251
252mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr) 252mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr)
253 { 253 {
254 mDNSu16 namelen = DomainNameLength(rr->name); 254 mDNSu16 namelen = DomainNameLength(rr->name);
255 AuthGroup *ag = (AuthGroup*)GetAuthEntity(r, mDNSNULL); 255 AuthGroup *ag = (AuthGroup*)GetAuthEntity(r, mDNSNULL);
256 if (!ag) { LogMsg("GetAuthGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } 256 if (!ag) { LogMsg("GetAuthGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
257 ag->next = r->rrauth_hash[slot]; 257 ag->next = r->rrauth_hash[slot];
258 ag->namehash = rr->namehash; 258 ag->namehash = rr->namehash;
259 ag->members = mDNSNULL; 259 ag->members = mDNSNULL;
260 ag->rrauth_tail = &ag->members; 260 ag->rrauth_tail = &ag->members;
261 ag->name = (domainname*)ag->namestorage; 261 ag->name = (domainname*)ag->namestorage;
262 ag->NewLocalOnlyRecords = mDNSNULL; 262 ag->NewLocalOnlyRecords = mDNSNULL;
263 if (namelen > InlineCacheGroupNameSize) ag->name = mDNSPlatformMemAllocate(namelen); 263 if (namelen > InlineCacheGroupNameSize) ag->name = mDNSPlatformMemAllocate(namelen);
264 if (!ag->name) 264 if (!ag->name)
265 { 265 {
266 LogMsg("GetAuthGroup: Failed to allocate name storage for %##s", rr->name->c); 266 LogMsg("GetAuthGroup: Failed to allocate name storage for %##s", rr->name->c);
267 ReleaseAuthEntity(r, (AuthEntity*)ag); 267 ReleaseAuthEntity(r, (AuthEntity*)ag);
268 return(mDNSNULL); 268 return(mDNSNULL);
269 } 269 }
270 AssignDomainName(ag->name, rr->name); 270 AssignDomainName(ag->name, rr->name);
271 271
272 if (AuthGroupForRecord(r, slot, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c); 272 if (AuthGroupForRecord(r, slot, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c);
273 r->rrauth_hash[slot] = ag; 273 r->rrauth_hash[slot] = ag;
274 if (AuthGroupForRecord(r, slot, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c); 274 if (AuthGroupForRecord(r, slot, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c);
275  275
276 return(ag); 276 return(ag);
277 } 277 }
278 278
279// Returns the AuthGroup in which the AuthRecord was inserted 279// Returns the AuthGroup in which the AuthRecord was inserted
280mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) 280mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr)
281 { 281 {
282 AuthGroup *ag; 282 AuthGroup *ag;
283 const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 283 const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
284 ag = AuthGroupForRecord(r, slot, &rr->resrec); 284 ag = AuthGroupForRecord(r, slot, &rr->resrec);
285 if (!ag) ag = GetAuthGroup(r, slot, &rr->resrec); // If we don't have a AuthGroup for this name, make one now 285 if (!ag) ag = GetAuthGroup(r, slot, &rr->resrec); // If we don't have a AuthGroup for this name, make one now
286 if (ag) 286 if (ag)
287 { 287 {
288 LogInfo("InsertAuthRecord: inserting auth record %s from table", ARDisplayString(m, rr)); 288 LogInfo("InsertAuthRecord: inserting auth record %s from table", ARDisplayString(m, rr));
289 *(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list 289 *(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list
290 ag->rrauth_tail = &(rr->next); // Advance tail pointer 290 ag->rrauth_tail = &(rr->next); // Advance tail pointer
291 } 291 }
292 return ag; 292 return ag;
293 } 293 }
294 294
295mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr) 295mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr)
296 { 296 {
297 AuthGroup *a; 297 AuthGroup *a;
298 AuthGroup **ag = &a; 298 AuthGroup **ag = &a;
299 AuthRecord **rp; 299 AuthRecord **rp;
300 const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 300 const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
301 301
302 a = AuthGroupForRecord(r, slot, &rr->resrec); 302 a = AuthGroupForRecord(r, slot, &rr->resrec);
303 if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; } 303 if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; }
304 rp = &(*ag)->members; 304 rp = &(*ag)->members;
305 while (*rp) 305 while (*rp)
306 { 306 {
307 if (*rp != rr) 307 if (*rp != rr)
308 rp=&(*rp)->next; 308 rp=&(*rp)->next;
309 else 309 else
310 { 310 {
311 // We don't break here, so that we can set the tail below without tracking "prev" pointers 311 // We don't break here, so that we can set the tail below without tracking "prev" pointers
312 312
313 LogInfo("RemoveAuthRecord: removing auth record %s from table", ARDisplayString(m, rr)); 313 LogInfo("RemoveAuthRecord: removing auth record %s from table", ARDisplayString(m, rr));
314 *rp = (*rp)->next; // Cut record from list 314 *rp = (*rp)->next; // Cut record from list
315 } 315 }
316 } 316 }
317 // TBD: If there are no more members, release authgroup ? 317 // TBD: If there are no more members, release authgroup ?
318 (*ag)->rrauth_tail = rp; 318 (*ag)->rrauth_tail = rp;
319 return a; 319 return a;
320 } 320 }
321 321
322mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) 322mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
323 { 323 {
324 CacheGroup *cg; 324 CacheGroup *cg;
325 for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) 325 for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
326 if (cg->namehash == namehash && SameDomainName(cg->name, name)) 326 if (cg->namehash == namehash && SameDomainName(cg->name, name))
327 break; 327 break;
328 return(cg); 328 return(cg);
329 } 329 }
330 330
331mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) 331mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
332 { 332 {
333 return(CacheGroupForName(m, slot, rr->namehash, rr->name)); 333 return(CacheGroupForName(m, slot, rr->namehash, rr->name));
334 } 334 }
335 335
336mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr) 336mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
337 { 337 {
338 NetworkInterfaceInfo *intf; 338 NetworkInterfaceInfo *intf;
339 339
340 if (addr->type == mDNSAddrType_IPv4) 340 if (addr->type == mDNSAddrType_IPv4)
341 { 341 {
342 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception 342 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
343 if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); 343 if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
344 for (intf = m->HostInterfaces; intf; intf = intf->next) 344 for (intf = m->HostInterfaces; intf; intf = intf->next)
345 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) 345 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
346 if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0) 346 if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
347 return(mDNStrue); 347 return(mDNStrue);
348 } 348 }
349 349
350 if (addr->type == mDNSAddrType_IPv6) 350 if (addr->type == mDNSAddrType_IPv6)
351 { 351 {
352 if (mDNSv6AddressIsLinkLocal(&addr->ip.v6)) return(mDNStrue); 352 if (mDNSv6AddressIsLinkLocal(&addr->ip.v6)) return(mDNStrue);
353 for (intf = m->HostInterfaces; intf; intf = intf->next) 353 for (intf = m->HostInterfaces; intf; intf = intf->next)
354 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) 354 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
355 if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) && 355 if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
356 (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) && 356 (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
357 (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) && 357 (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
358 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0)) 358 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
359 return(mDNStrue); 359 return(mDNStrue);
360 } 360 }
361 361
362 return(mDNSfalse); 362 return(mDNSfalse);
363 } 363 }
364 364
365mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 365mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
366 { 366 {
367 NetworkInterfaceInfo *intf = m->HostInterfaces; 367 NetworkInterfaceInfo *intf = m->HostInterfaces;
368 while (intf && intf->InterfaceID != InterfaceID) intf = intf->next; 368 while (intf && intf->InterfaceID != InterfaceID) intf = intf->next;
369 return(intf); 369 return(intf);
370 } 370 }
371 371
372mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 372mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
373 { 373 {
374 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 374 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
375 return(intf ? intf->ifname : mDNSNULL); 375 return(intf ? intf->ifname : mDNSNULL);
376 } 376 }
377 377
378// Caller should hold the lock 378// Caller should hold the lock
379mDNSlocal void GenerateNegativeResponse(mDNS *const m) 379mDNSlocal void GenerateNegativeResponse(mDNS *const m)
380 { 380 {
381 DNSQuestion *q; 381 DNSQuestion *q;
382 if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; } 382 if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; }
383 q = m->CurrentQuestion; 383 q = m->CurrentQuestion;
384 LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 384 LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
385 385
386 MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL); 386 MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL);
387 AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); 387 AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
388 if (m->CurrentQuestion == q) { q->ThisQInterval = 0; } // Deactivate this question 388 if (m->CurrentQuestion == q) { q->ThisQInterval = 0; } // Deactivate this question
389 // Don't touch the question after this 389 // Don't touch the question after this
390 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 390 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
391 } 391 }
392 392
393mDNSlocal void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr) 393mDNSlocal void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr)
394 { 394 {
395 const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name); 395 const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name);
396 if (q->CNAMEReferrals >= 10 || selfref) 396 if (q->CNAMEReferrals >= 10 || selfref)
397 LogMsg("AnswerQuestionByFollowingCNAME: %p %##s (%s) NOT following CNAME referral %d%s for %s", 397 LogMsg("AnswerQuestionByFollowingCNAME: %p %##s (%s) NOT following CNAME referral %d%s for %s",
398 q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr)); 398 q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr));
399 else 399 else
400 { 400 {
401 const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value 401 const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value
402 402
403 // The SameDomainName check above is to ignore bogus CNAME records that point right back at 403 // The SameDomainName check above is to ignore bogus CNAME records that point right back at
404 // themselves. Without that check we can get into a case where we have two duplicate questions, 404 // themselves. Without that check we can get into a case where we have two duplicate questions,
405 // A and B, and when we stop question A, UpdateQuestionDuplicates copies the value of CNAMEReferrals 405 // A and B, and when we stop question A, UpdateQuestionDuplicates copies the value of CNAMEReferrals
406 // from A to B, and then A is re-appended to the end of the list as a duplicate of B (because 406 // from A to B, and then A is re-appended to the end of the list as a duplicate of B (because
407 // the target name is still the same), and then when we stop question B, UpdateQuestionDuplicates 407 // the target name is still the same), and then when we stop question B, UpdateQuestionDuplicates
408 // copies the B's value of CNAMEReferrals back to A, and we end up not incrementing CNAMEReferrals 408 // copies the B's value of CNAMEReferrals back to A, and we end up not incrementing CNAMEReferrals
409 // for either of them. This is not a problem for CNAME loops of two or more records because in 409 // for either of them. This is not a problem for CNAME loops of two or more records because in
410 // those cases the newly re-appended question A has a different target name and therefore cannot be 410 // those cases the newly re-appended question A has a different target name and therefore cannot be
411 // a duplicate of any other question ('B') which was itself a duplicate of the previous question A. 411 // a duplicate of any other question ('B') which was itself a duplicate of the previous question A.
412 412
413 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect, 413 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
414 // and track CNAMEs coming and going, we should really create a subordinate query here, 414 // and track CNAMEs coming and going, we should really create a subordinate query here,
415 // which we would subsequently cancel and retract if the CNAME referral record were removed. 415 // which we would subsequently cancel and retract if the CNAME referral record were removed.
416 // In reality this is such a corner case we'll ignore it until someone actually needs it. 416 // In reality this is such a corner case we'll ignore it until someone actually needs it.
417 417
418 LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s", 418 LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s",
419 q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr)); 419 q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr));
420 420
421 mDNS_StopQuery_internal(m, q); // Stop old query 421 mDNS_StopQuery_internal(m, q); // Stop old query
422 AssignDomainName(&q->qname, &rr->rdata->u.name); // Update qname 422 AssignDomainName(&q->qname, &rr->rdata->u.name); // Update qname
423 q->qnamehash = DomainNameHashValue(&q->qname); // and namehash 423 q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
424 // If a unicast query results in a CNAME that points to a .local, we need to re-try 424 // If a unicast query results in a CNAME that points to a .local, we need to re-try
425 // this as unicast. Setting the mDNSInterface_Unicast tells mDNS_StartQuery_internal 425 // this as unicast. Setting the mDNSInterface_Unicast tells mDNS_StartQuery_internal
426 // to try this as unicast query even though it is a .local name 426 // to try this as unicast query even though it is a .local name
427 if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname)) 427 if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname))
428 { 428 {
429 LogInfo("AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p %##s (%s) Record %s", 429 LogInfo("AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p %##s (%s) Record %s",
430 q, q->qname.c, DNSTypeName(q->qtype), RRDisplayString(m, rr)); 430 q, q->qname.c, DNSTypeName(q->qtype), RRDisplayString(m, rr));
431 q->InterfaceID = mDNSInterface_Unicast; 431 q->InterfaceID = mDNSInterface_Unicast;
432 } 432 }
433 mDNS_StartQuery_internal(m, q); // start new query 433 mDNS_StartQuery_internal(m, q); // start new query
434 // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal, 434 // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal,
435 // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero 435 // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
436 q->CNAMEReferrals = c; 436 q->CNAMEReferrals = c;
437 } 437 }
438 } 438 }
439 439
440// For a single given DNSQuestion pointed to by CurrentQuestion, deliver an add/remove result for the single given AuthRecord 440// For a single given DNSQuestion pointed to by CurrentQuestion, deliver an add/remove result for the single given AuthRecord
441// Note: All the callers should use the m->CurrentQuestion to see if the question is still valid or not 441// Note: All the callers should use the m->CurrentQuestion to see if the question is still valid or not
442mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) 442mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
443 { 443 {
444 DNSQuestion *q = m->CurrentQuestion; 444 DNSQuestion *q = m->CurrentQuestion;
445 mDNSBool followcname; 445 mDNSBool followcname;
446 446
447 if (!q) 447 if (!q)
448 { 448 {
449 LogMsg("AnswerLocalQuestionWithLocalAuthRecord: ERROR!! CurrentQuestion NULL while answering with %s", ARDisplayString(m, rr)); 449 LogMsg("AnswerLocalQuestionWithLocalAuthRecord: ERROR!! CurrentQuestion NULL while answering with %s", ARDisplayString(m, rr));
450 return; 450 return;
451 } 451 }
452  452
453 followcname = FollowCNAME(q, &rr->resrec, AddRecord); 453 followcname = FollowCNAME(q, &rr->resrec, AddRecord);
454 454
455 // We should not be delivering results for record types Unregistered, Deregistering, and (unverified) Unique 455 // We should not be delivering results for record types Unregistered, Deregistering, and (unverified) Unique
456 if (!(rr->resrec.RecordType & kDNSRecordTypeActiveMask)) 456 if (!(rr->resrec.RecordType & kDNSRecordTypeActiveMask))
457 { 457 {
458 LogMsg("AnswerLocalQuestionWithLocalAuthRecord: *NOT* delivering %s event for local record type %X %s", 458 LogMsg("AnswerLocalQuestionWithLocalAuthRecord: *NOT* delivering %s event for local record type %X %s",
459 AddRecord ? "Add" : "Rmv", rr->resrec.RecordType, ARDisplayString(m, rr)); 459 AddRecord ? "Add" : "Rmv", rr->resrec.RecordType, ARDisplayString(m, rr));
460 return; 460 return;
461 } 461 }
462 462
463 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it 463 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
464 if (AddRecord) rr->AnsweredLocalQ = mDNStrue; 464 if (AddRecord) rr->AnsweredLocalQ = mDNStrue;
465 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 465 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
466 if (q->QuestionCallback && !q->NoAnswer) 466 if (q->QuestionCallback && !q->NoAnswer)
467 { 467 {
468 q->CurrentAnswers += AddRecord ? 1 : -1; 468 q->CurrentAnswers += AddRecord ? 1 : -1;
469 if (LORecordAnswersAddressType(rr)) 469 if (LORecordAnswersAddressType(rr))
470 { 470 {
471 if (!followcname || q->ReturnIntermed) 471 if (!followcname || q->ReturnIntermed)
472 { 472 {
473 // Don't send this packet on the wire as we answered from /etc/hosts 473 // Don't send this packet on the wire as we answered from /etc/hosts
474 q->ThisQInterval = 0; 474 q->ThisQInterval = 0;
475 q->LOAddressAnswers += AddRecord ? 1 : -1; 475 q->LOAddressAnswers += AddRecord ? 1 : -1;
476 q->QuestionCallback(m, q, &rr->resrec, AddRecord); 476 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
477 } 477 }
478 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 478 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
479 // The callback above could have caused the question to stop. Detect that 479 // The callback above could have caused the question to stop. Detect that
480 // using m->CurrentQuestion 480 // using m->CurrentQuestion
481 if (followcname && m->CurrentQuestion == q) 481 if (followcname && m->CurrentQuestion == q)
482 AnswerQuestionByFollowingCNAME(m, q, &rr->resrec); 482 AnswerQuestionByFollowingCNAME(m, q, &rr->resrec);
483 return; 483 return;
484 } 484 }
485 else 485 else
486 q->QuestionCallback(m, q, &rr->resrec, AddRecord); 486 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
487 } 487 }
488 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 488 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
489 } 489 }
490 490
491mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) 491mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
492 { 492 {
493 if (m->CurrentQuestion) 493 if (m->CurrentQuestion)
494 LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)", 494 LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)",
495 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 495 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
496 m->CurrentQuestion = m->Questions; 496 m->CurrentQuestion = m->Questions;
497 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 497 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
498 { 498 {
499 mDNSBool answered; 499 mDNSBool answered;
500 DNSQuestion *q = m->CurrentQuestion; 500 DNSQuestion *q = m->CurrentQuestion;
501 if (RRAny(rr)) 501 if (RRAny(rr))
502 answered = ResourceRecordAnswersQuestion(&rr->resrec, q); 502 answered = ResourceRecordAnswersQuestion(&rr->resrec, q);
503 else 503 else
504 answered = LocalOnlyRecordAnswersQuestion(rr, q); 504 answered = LocalOnlyRecordAnswersQuestion(rr, q);
505 if (answered) 505 if (answered)
506 AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again 506 AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again
507 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 507 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
508 m->CurrentQuestion = q->next; 508 m->CurrentQuestion = q->next;
509 } 509 }
510 m->CurrentQuestion = mDNSNULL; 510 m->CurrentQuestion = mDNSNULL;
511 } 511 }
512 512
513// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() 513// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord()
514// delivers the appropriate add/remove events to listening questions: 514// delivers the appropriate add/remove events to listening questions:
515// 1. It runs though all our LocalOnlyQuestions delivering answers as appropriate, 515// 1. It runs though all our LocalOnlyQuestions delivering answers as appropriate,
516// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion(). 516// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
517// 2. If the AuthRecord is marked mDNSInterface_LocalOnly or mDNSInterface_P2P, then it also runs though 517// 2. If the AuthRecord is marked mDNSInterface_LocalOnly or mDNSInterface_P2P, then it also runs though
518// our main question list, delivering answers to mDNSInterface_Any questions as appropriate, 518// our main question list, delivering answers to mDNSInterface_Any questions as appropriate,
519// stopping if it reaches a NewQuestion -- brand-new questions are handled by AnswerNewQuestion(). 519// stopping if it reaches a NewQuestion -- brand-new questions are handled by AnswerNewQuestion().
520// 520//
521// AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(), 521// AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(),
522// and by mDNS_Deregister_internal() 522// and by mDNS_Deregister_internal()
523 523
524mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) 524mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
525 { 525 {
526 if (m->CurrentQuestion) 526 if (m->CurrentQuestion)
527 LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", 527 LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)",
528 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 528 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
529 529
530 m->CurrentQuestion = m->LocalOnlyQuestions; 530 m->CurrentQuestion = m->LocalOnlyQuestions;
531 while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions) 531 while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
532 { 532 {
533 mDNSBool answered; 533 mDNSBool answered;
534 DNSQuestion *q = m->CurrentQuestion; 534 DNSQuestion *q = m->CurrentQuestion;
535 // We are called with both LocalOnly/P2P record or a regular AuthRecord 535 // We are called with both LocalOnly/P2P record or a regular AuthRecord
536 if (RRAny(rr)) 536 if (RRAny(rr))
537 answered = ResourceRecordAnswersQuestion(&rr->resrec, q); 537 answered = ResourceRecordAnswersQuestion(&rr->resrec, q);
538 else 538 else
539 answered = LocalOnlyRecordAnswersQuestion(rr, q); 539 answered = LocalOnlyRecordAnswersQuestion(rr, q);
540 if (answered) 540 if (answered)
541 AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again 541 AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again
542 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 542 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
543 m->CurrentQuestion = q->next; 543 m->CurrentQuestion = q->next;
544 } 544 }
545 545
546 m->CurrentQuestion = mDNSNULL; 546 m->CurrentQuestion = mDNSNULL;
547 547
548 // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions 548 // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions
549 if (rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P) 549 if (rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P)
550 AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, rr, AddRecord); 550 AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, rr, AddRecord);
551 551
552 } 552 }
553 553
554// *************************************************************************** 554// ***************************************************************************
555#if COMPILER_LIKES_PRAGMA_MARK 555#if COMPILER_LIKES_PRAGMA_MARK
556#pragma mark - 556#pragma mark -
557#pragma mark - Resource Record Utility Functions 557#pragma mark - Resource Record Utility Functions
558#endif 558#endif
559 559
560#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA) 560#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
561 561
562#define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \ 562#define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \
563 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ 563 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
564 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ 564 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
565 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) ) 565 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
566 566
567#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \ 567#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
568 (ResourceRecordIsValidAnswer(RR) && \ 568 (ResourceRecordIsValidAnswer(RR) && \
569 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID))) 569 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
570 570
571#define DefaultProbeCountForTypeUnique ((mDNSu8)3) 571#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
572#define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0) 572#define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
573 573
574#define InitialAnnounceCount ((mDNSu8)8) 574#define InitialAnnounceCount ((mDNSu8)8)
575 575
576// For goodbye packets we set the count to 3, and for wakeups we set it to 18 576// For goodbye packets we set the count to 3, and for wakeups we set it to 18
577// (which will be up to 15 wakeup attempts over the course of 30 seconds, 577// (which will be up to 15 wakeup attempts over the course of 30 seconds,
578// and then if the machine fails to wake, 3 goodbye packets). 578// and then if the machine fails to wake, 3 goodbye packets).
579#define GoodbyeCount ((mDNSu8)3) 579#define GoodbyeCount ((mDNSu8)3)
580#define WakeupCount ((mDNSu8)18) 580#define WakeupCount ((mDNSu8)18)
581 581
582// Number of wakeups we send if WakeOnResolve is set in the question 582// Number of wakeups we send if WakeOnResolve is set in the question
583#define InitialWakeOnResolveCount ((mDNSu8)3) 583#define InitialWakeOnResolveCount ((mDNSu8)3)
584 584
585// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not. 585// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
586// This means that because the announce interval is doubled after sending the first packet, the first 586// This means that because the announce interval is doubled after sending the first packet, the first
587// observed on-the-wire inter-packet interval between announcements is actually one second. 587// observed on-the-wire inter-packet interval between announcements is actually one second.
588// The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent. 588// The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
589#define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4) 589#define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
590#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2) 590#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
591#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2) 591#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
592 592
593#define DefaultAPIntervalForRecordType(X) ((X) & kDNSRecordTypeActiveSharedMask ? DefaultAnnounceIntervalForTypeShared : \ 593#define DefaultAPIntervalForRecordType(X) ((X) & kDNSRecordTypeActiveSharedMask ? DefaultAnnounceIntervalForTypeShared : \
594 (X) & kDNSRecordTypeUnique ? DefaultProbeIntervalForTypeUnique : \ 594 (X) & kDNSRecordTypeUnique ? DefaultProbeIntervalForTypeUnique : \
595 (X) & kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0) 595 (X) & kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0)
596 596
597#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0) 597#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
598#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR)) 598#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
599#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond) 599#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
600#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR)) 600#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
601 601
602#define MaxUnansweredQueries 4 602#define MaxUnansweredQueries 4
603 603
604// SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent 604// SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
605// (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match). 605// (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
606// TTL and rdata may differ. 606// TTL and rdata may differ.
607// This is used for cache flush management: 607// This is used for cache flush management:
608// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent 608// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
609// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed 609// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
610 610
611// SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match 611// SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match
612 612
613#define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B)) 613#define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B))
614 614
615mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2) 615mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2)
616 { 616 {
617 if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); } 617 if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
618 if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); } 618 if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
619 if (r1->resrec.InterfaceID && 619 if (r1->resrec.InterfaceID &&
620 r2->resrec.InterfaceID && 620 r2->resrec.InterfaceID &&
621 r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse); 621 r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse);
622 return(mDNSBool)( 622 return(mDNSBool)(
623 r1->resrec.rrclass == r2->resrec.rrclass && 623 r1->resrec.rrclass == r2->resrec.rrclass &&
624 r1->resrec.namehash == r2->resrec.namehash && 624 r1->resrec.namehash == r2->resrec.namehash &&
625 SameDomainName(r1->resrec.name, r2->resrec.name)); 625 SameDomainName(r1->resrec.name, r2->resrec.name));
626 } 626 }
627 627
628// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our 628// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
629// authoratative record is unique (as opposed to shared). For unique records, we are supposed to have 629// authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
630// complete ownership of *all* types for this name, so *any* record type with the same name is a conflict. 630// complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
631// In addition, when probing we send our questions with the wildcard type kDNSQType_ANY, 631// In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
632// so a response of any type should match, even if it is not actually the type the client plans to use. 632// so a response of any type should match, even if it is not actually the type the client plans to use.
633 633
634// For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records, 634// For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records,
635// and require the rrtypes to match for the rdata to be considered potentially conflicting 635// and require the rrtypes to match for the rdata to be considered potentially conflicting
636mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr) 636mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
637 { 637 {
638 if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); } 638 if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
639 if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); } 639 if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
640 if (pktrr->resrec.InterfaceID && 640 if (pktrr->resrec.InterfaceID &&
641 authrr->resrec.InterfaceID && 641 authrr->resrec.InterfaceID &&
642 pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); 642 pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
643 if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0]) 643 if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0])
644 if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); 644 if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
645 return(mDNSBool)( 645 return(mDNSBool)(
646 pktrr->resrec.rrclass == authrr->resrec.rrclass && 646 pktrr->resrec.rrclass == authrr->resrec.rrclass &&
647 pktrr->resrec.namehash == authrr->resrec.namehash && 647 pktrr->resrec.namehash == authrr->resrec.namehash &&
648 SameDomainName(pktrr->resrec.name, authrr->resrec.name)); 648 SameDomainName(pktrr->resrec.name, authrr->resrec.name));
649 } 649 }
650 650
651// CacheRecord *ka is the CacheRecord from the known answer list in the query. 651// CacheRecord *ka is the CacheRecord from the known answer list in the query.
652// This is the information that the requester believes to be correct. 652// This is the information that the requester believes to be correct.
653// AuthRecord *rr is the answer we are proposing to give, if not suppressed. 653// AuthRecord *rr is the answer we are proposing to give, if not suppressed.
654// This is the information that we believe to be correct. 654// This is the information that we believe to be correct.
655// We've already determined that we plan to give this answer on this interface 655// We've already determined that we plan to give this answer on this interface
656// (either the record is non-specific, or it is specific to this interface) 656// (either the record is non-specific, or it is specific to this interface)
657// so now we just need to check the name, type, class, rdata and TTL. 657// so now we just need to check the name, type, class, rdata and TTL.
658mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr) 658mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
659 { 659 {
660 // If RR signature is different, or data is different, then don't suppress our answer 660 // If RR signature is different, or data is different, then don't suppress our answer
661 if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse); 661 if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
662  662
663 // If the requester's indicated TTL is less than half the real TTL, 663 // If the requester's indicated TTL is less than half the real TTL,
664 // we need to give our answer before the requester's copy expires. 664 // we need to give our answer before the requester's copy expires.
665 // If the requester's indicated TTL is at least half the real TTL, 665 // If the requester's indicated TTL is at least half the real TTL,
666 // then we can suppress our answer this time. 666 // then we can suppress our answer this time.
667 // If the requester's indicated TTL is greater than the TTL we believe, 667 // If the requester's indicated TTL is greater than the TTL we believe,
668 // then that's okay, and we don't need to do anything about it. 668 // then that's okay, and we don't need to do anything about it.
669 // (If two responders on the network are offering the same information, 669 // (If two responders on the network are offering the same information,
670 // that's okay, and if they are offering the information with different TTLs, 670 // that's okay, and if they are offering the information with different TTLs,
671 // the one offering the lower TTL should defer to the one offering the higher TTL.) 671 // the one offering the lower TTL should defer to the one offering the higher TTL.)
672 return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2); 672 return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
673 } 673 }
674 674
675mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr) 675mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
676 { 676 {
677 if (rr->resrec.RecordType == kDNSRecordTypeUnique) 677 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
678 { 678 {
679 if ((rr->LastAPTime + rr->ThisAPInterval) - m->timenow > mDNSPlatformOneSecond * 10) 679 if ((rr->LastAPTime + rr->ThisAPInterval) - m->timenow > mDNSPlatformOneSecond * 10)
680 { 680 {
681 LogMsg("SetNextAnnounceProbeTime: ProbeCount %d Next in %d %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr)); 681 LogMsg("SetNextAnnounceProbeTime: ProbeCount %d Next in %d %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
682 LogMsg("SetNextAnnounceProbeTime: m->SuppressProbes %d m->timenow %d diff %d", m->SuppressProbes, m->timenow, m->SuppressProbes - m->timenow); 682 LogMsg("SetNextAnnounceProbeTime: m->SuppressProbes %d m->timenow %d diff %d", m->SuppressProbes, m->timenow, m->SuppressProbes - m->timenow);
683 } 683 }
684 if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 684 if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
685 m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval); 685 m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
686 // Some defensive code: 686 // Some defensive code:
687 // If (rr->LastAPTime + rr->ThisAPInterval) happens to be far in the past, we don't want to allow 687 // If (rr->LastAPTime + rr->ThisAPInterval) happens to be far in the past, we don't want to allow
688 // NextScheduledProbe to be set excessively in the past, because that can cause bad things to happen. 688 // NextScheduledProbe to be set excessively in the past, because that can cause bad things to happen.
689 // See: <rdar://problem/7795434> mDNS: Sometimes advertising stops working and record interval is set to zero 689 // See: <rdar://problem/7795434> mDNS: Sometimes advertising stops working and record interval is set to zero
690 // A future time also needs to be set to avoid spamming logs about not all probes being sent. 690 if (m->NextScheduledProbe - m->timenow < 0)
691 if (m->NextScheduledProbe - m->timenow <= 0) 691 m->NextScheduledProbe = m->timenow;
692 m->NextScheduledProbe = m->timenow + 1; 
693 } 692 }
694 else if (rr->AnnounceCount && (ResourceRecordIsValidAnswer(rr) || rr->resrec.RecordType == kDNSRecordTypeDeregistering)) 693 else if (rr->AnnounceCount && (ResourceRecordIsValidAnswer(rr) || rr->resrec.RecordType == kDNSRecordTypeDeregistering))
695 { 694 {
696 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 695 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
697 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); 696 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
698 } 697 }
699 // A future time also needs to be set to avoid spamming logs about not all responses being sent. 698 if (m->NextScheduledResponse - m->timenow < 0)
700 if (m->NextScheduledResponse - m->timenow <= 0) 699 m->NextScheduledResponse = m->timenow;
701 m->NextScheduledResponse = m->timenow + 1; 
702 } 700 }
703 701
704mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) 702mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
705 { 703 {
706 // For reverse-mapping Sleep Proxy PTR records, probe interval is one second 704 // For reverse-mapping Sleep Proxy PTR records, probe interval is one second
707 rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType); 705 rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType);
708 706
709 // * If this is a record type that's going to probe, then we use the m->SuppressProbes time. 707 // * If this is a record type that's going to probe, then we use the m->SuppressProbes time.
710 // * Otherwise, if it's not going to probe, but m->SuppressProbes is set because we have other 708 // * Otherwise, if it's not going to probe, but m->SuppressProbes is set because we have other
711 // records that are going to probe, then we delay its first announcement so that it will 709 // records that are going to probe, then we delay its first announcement so that it will
712 // go out synchronized with the first announcement for the other records that *are* probing. 710 // go out synchronized with the first announcement for the other records that *are* probing.
713 // This is a minor performance tweak that helps keep groups of related records synchronized together. 711 // This is a minor performance tweak that helps keep groups of related records synchronized together.
714 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are 712 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
715 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete. 713 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
716 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated, 714 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
717 // because they will meet the criterion of being at least half-way to their scheduled announcement time. 715 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
718 // * If it's not going to probe and m->SuppressProbes is not already set then we should announce immediately. 716 // * If it's not going to probe and m->SuppressProbes is not already set then we should announce immediately.
719 717
720 if (rr->ProbeCount) 718 if (rr->ProbeCount)
721 { 719 {
722 // If we have no probe suppression time set, or it is in the past, set it now 720 // If we have no probe suppression time set, or it is in the past, set it now
723 if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) 721 if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
724 { 722 {
725 // To allow us to aggregate probes when a group of services are registered together, 723 // To allow us to aggregate probes when a group of services are registered together,
726 // the first probe is delayed 1/4 second. This means the common-case behaviour is: 724 // the first probe is delayed 1/4 second. This means the common-case behaviour is:
727 // 1/4 second wait; probe 725 // 1/4 second wait; probe
728 // 1/4 second wait; probe 726 // 1/4 second wait; probe
729 // 1/4 second wait; probe 727 // 1/4 second wait; probe
730 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered) 728 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
731 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); 729 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
732 730
733 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation 731 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
734 if (m->SuppressProbes - m->NextScheduledProbe >= 0) 732 if (m->SuppressProbes - m->NextScheduledProbe >= 0)
735 m->SuppressProbes = NonZeroTime(m->NextScheduledProbe); 733 m->SuppressProbes = NonZeroTime(m->NextScheduledProbe);
736 if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past 734 if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past
737 m->SuppressProbes = m->timenow; 735 m->SuppressProbes = m->timenow;
738 736
739 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation 737 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
740 if (m->SuppressProbes - m->NextScheduledQuery >= 0) 738 if (m->SuppressProbes - m->NextScheduledQuery >= 0)
741 m->SuppressProbes = NonZeroTime(m->NextScheduledQuery); 739 m->SuppressProbes = NonZeroTime(m->NextScheduledQuery);
742 if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past 740 if (m->SuppressProbes - m->timenow < 0) // Make sure we don't set m->SuppressProbes excessively in the past
743 m->SuppressProbes = m->timenow; 741 m->SuppressProbes = m->timenow;
744 742
745 // except... don't expect to be able to send before the m->SuppressSending timer fires 743 // except... don't expect to be able to send before the m->SuppressSending timer fires
746 if (m->SuppressSending && m->SuppressProbes - m->SuppressSending < 0) 744 if (m->SuppressSending && m->SuppressProbes - m->SuppressSending < 0)
747 m->SuppressProbes = NonZeroTime(m->SuppressSending); 745 m->SuppressProbes = NonZeroTime(m->SuppressSending);
748 746
749 if (m->SuppressProbes - m->timenow > mDNSPlatformOneSecond * 8) 747 if (m->SuppressProbes - m->timenow > mDNSPlatformOneSecond * 8)
750 { 748 {
751 LogMsg("InitializeLastAPTime ERROR m->SuppressProbes %d m->NextScheduledProbe %d m->NextScheduledQuery %d m->SuppressSending %d %d", 749 LogMsg("InitializeLastAPTime ERROR m->SuppressProbes %d m->NextScheduledProbe %d m->NextScheduledQuery %d m->SuppressSending %d %d",
752 m->SuppressProbes - m->timenow, 750 m->SuppressProbes - m->timenow,
753 m->NextScheduledProbe - m->timenow, 751 m->NextScheduledProbe - m->timenow,
754 m->NextScheduledQuery - m->timenow, 752 m->NextScheduledQuery - m->timenow,
755 m->SuppressSending, 753 m->SuppressSending,
756 m->SuppressSending - m->timenow); 754 m->SuppressSending - m->timenow);
757 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2)); 755 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
758 } 756 }
759 } 757 }
760 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; 758 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
761 } 759 }
762 else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0) 760 else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0)
763 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; 761 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
764 else 762 else
765 rr->LastAPTime = m->timenow - rr->ThisAPInterval; 763 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
766 764
767 // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we 765 // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
768 // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing. 766 // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing.
769 // After three probes one second apart with no answer, we conclude the client is now sleeping 767 // After three probes one second apart with no answer, we conclude the client is now sleeping
770 // and we can begin broadcasting our announcements to take over ownership of that IP address. 768 // and we can begin broadcasting our announcements to take over ownership of that IP address.
771 // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk 769 // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
772 // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address. 770 // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
773 if (rr->AddressProxy.type) rr->LastAPTime = m->timenow; 771 if (rr->AddressProxy.type) rr->LastAPTime = m->timenow;
774 772
775 // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating, 773 // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating,
776 // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited 774 // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited
777 // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower. 775 // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower.
778 // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage 776 // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage
779 // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records. 777 // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records.
780 if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6) 778 if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6)
781 if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA) 779 if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA)
782 rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10; 780 rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10;
783  781
784 // Set LastMCTime to now, to inhibit multicast responses 782 // Set LastMCTime to now, to inhibit multicast responses
785 // (no need to send additional multicast responses when we're announcing anyway) 783 // (no need to send additional multicast responses when we're announcing anyway)
786 rr->LastMCTime = m->timenow; 784 rr->LastMCTime = m->timenow;
787 rr->LastMCInterface = mDNSInterfaceMark; 785 rr->LastMCInterface = mDNSInterfaceMark;
788  786
789 SetNextAnnounceProbeTime(m, rr); 787 SetNextAnnounceProbeTime(m, rr);
790 } 788 }
791 789
792mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord *rr) 790mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord *rr)
793 { 791 {
794 const domainname *target; 792 const domainname *target;
795 if (rr->AutoTarget) 793 if (rr->AutoTarget)
796 { 794 {
797 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other 795 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
798 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate, 796 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
799 // with the port number in our advertised SRV record automatically tracking the external mapped port. 797 // with the port number in our advertised SRV record automatically tracking the external mapped port.
800 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name); 798 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
801 if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP; 799 if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP;
802 } 800 }
803 801
804 target = GetServiceTarget(m, rr); 802 target = GetServiceTarget(m, rr);
805 if (!target || target->c[0] == 0) 803 if (!target || target->c[0] == 0)
806 { 804 {
807 // defer registration until we've got a target 805 // defer registration until we've got a target
808 LogInfo("SetUnicastTargetToHostName No target for %s", ARDisplayString(m, rr)); 806 LogInfo("SetUnicastTargetToHostName No target for %s", ARDisplayString(m, rr));
809 rr->state = regState_NoTarget; 807 rr->state = regState_NoTarget;
810 return mDNSNULL; 808 return mDNSNULL;
811 } 809 }
812 else 810 else
813 { 811 {
814 LogInfo("SetUnicastTargetToHostName target %##s for resource record %s", target->c, ARDisplayString(m,rr)); 812 LogInfo("SetUnicastTargetToHostName target %##s for resource record %s", target->c, ARDisplayString(m,rr));
815 return target; 813 return target;
816 } 814 }
817 } 815 }
818 816
819// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname 817// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
820// Eventually we should unify this with GetServiceTarget() in uDNS.c 818// Eventually we should unify this with GetServiceTarget() in uDNS.c
821mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) 819mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
822 { 820 {
823 domainname *const target = GetRRDomainNameTarget(&rr->resrec); 821 domainname *const target = GetRRDomainNameTarget(&rr->resrec);
824 const domainname *newname = &m->MulticastHostname; 822 const domainname *newname = &m->MulticastHostname;
825 823
826 if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype)); 824 if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype));
827 825
828 if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage))) 826 if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage)))
829 { 827 {
830 const domainname *const n = SetUnicastTargetToHostName(m, rr); 828 const domainname *const n = SetUnicastTargetToHostName(m, rr);
831 if (n) newname = n; 829 if (n) newname = n;
832 else { target->c[0] = 0; SetNewRData(&rr->resrec, mDNSNULL, 0); return; } 830 else { target->c[0] = 0; SetNewRData(&rr->resrec, mDNSNULL, 0); return; }
833 } 831 }
834 832
835 if (target && SameDomainName(target, newname)) 833 if (target && SameDomainName(target, newname))
836 debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c); 834 debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
837  835
838 if (target && !SameDomainName(target, newname)) 836 if (target && !SameDomainName(target, newname))
839 { 837 {
840 AssignDomainName(target, newname); 838 AssignDomainName(target, newname);
841 SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash 839 SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
842  840
843 // If we're in the middle of probing this record, we need to start again, 841 // If we're in the middle of probing this record, we need to start again,
844 // because changing its rdata may change the outcome of the tie-breaker. 842 // because changing its rdata may change the outcome of the tie-breaker.
845 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.) 843 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
846 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 844 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
847 845
848 // If we've announced this record, we really should send a goodbye packet for the old rdata before 846 // If we've announced this record, we really should send a goodbye packet for the old rdata before
849 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records, 847 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
850 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way. 848 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
851 if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared) 849 if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
852 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", 850 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
853 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 851 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
854 852
855 rr->AnnounceCount = InitialAnnounceCount; 853 rr->AnnounceCount = InitialAnnounceCount;
856 rr->RequireGoodbye = mDNSfalse; 854 rr->RequireGoodbye = mDNSfalse;
857 InitializeLastAPTime(m, rr); 855 InitializeLastAPTime(m, rr);
858 } 856 }
859 } 857 }
860 858
861mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr) 859mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
862 { 860 {
863 if (rr->RecordCallback) 861 if (rr->RecordCallback)
864 { 862 {
865 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function 863 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
866 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 864 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
867 rr->Acknowledged = mDNStrue; 865 rr->Acknowledged = mDNStrue;
868 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 866 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
869 rr->RecordCallback(m, rr, mStatus_NoError); 867 rr->RecordCallback(m, rr, mStatus_NoError);
870 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 868 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
871 } 869 }
872 } 870 }
873 871
874mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr) 872mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
875 { 873 {
876 // Make sure that we don't activate the SRV record and associated service records, if it is in 874 // Make sure that we don't activate the SRV record and associated service records, if it is in
877 // NoTarget state. First time when a service is being instantiated, SRV record may be in NoTarget state. 875 // NoTarget state. First time when a service is being instantiated, SRV record may be in NoTarget state.
878 // We should not activate any of the other reords (PTR, TXT) that are part of the service. When 876 // We should not activate any of the other reords (PTR, TXT) that are part of the service. When
879 // the target becomes available, the records will be reregistered. 877 // the target becomes available, the records will be reregistered.
880 if (rr->resrec.rrtype != kDNSType_SRV) 878 if (rr->resrec.rrtype != kDNSType_SRV)
881 { 879 {
882 AuthRecord *srvRR = mDNSNULL; 880 AuthRecord *srvRR = mDNSNULL;
883 if (rr->resrec.rrtype == kDNSType_PTR) 881 if (rr->resrec.rrtype == kDNSType_PTR)
884 srvRR = rr->Additional1; 882 srvRR = rr->Additional1;
885 else if (rr->resrec.rrtype == kDNSType_TXT) 883 else if (rr->resrec.rrtype == kDNSType_TXT)
886 srvRR = rr->DependentOn; 884 srvRR = rr->DependentOn;
887 if (srvRR) 885 if (srvRR)
888 { 886 {
889 if (srvRR->resrec.rrtype != kDNSType_SRV) 887 if (srvRR->resrec.rrtype != kDNSType_SRV)
890 { 888 {
891 LogMsg("ActivateUnicastRegistration: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR)); 889 LogMsg("ActivateUnicastRegistration: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR));
892 } 890 }
893 else 891 else
894 { 892 {
895 LogInfo("ActivateUnicastRegistration: Found Service Record %s in state %d for %##s (%s)", 893 LogInfo("ActivateUnicastRegistration: Found Service Record %s in state %d for %##s (%s)",
896 ARDisplayString(m, srvRR), srvRR->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 894 ARDisplayString(m, srvRR), srvRR->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
897 rr->state = srvRR->state; 895 rr->state = srvRR->state;
898 } 896 }
899 } 897 }
900 } 898 }
901 899
902 if (rr->state == regState_NoTarget) 900 if (rr->state == regState_NoTarget)
903 { 901 {
904 LogInfo("ActivateUnicastRegistration record %s in regState_NoTarget, not activating", ARDisplayString(m, rr)); 902 LogInfo("ActivateUnicastRegistration record %s in regState_NoTarget, not activating", ARDisplayString(m, rr));
905 return; 903 return;
906 } 904 }
907 // When we wake up from sleep, we call ActivateUnicastRegistration. It is possible that just before we went to sleep, 905 // When we wake up from sleep, we call ActivateUnicastRegistration. It is possible that just before we went to sleep,
908 // the service/record was being deregistered. In that case, we should not try to register again. For the cases where 906 // the service/record was being deregistered. In that case, we should not try to register again. For the cases where
909 // the records are deregistered due to e.g., no target for the SRV record, we would have returned from above if it 907 // the records are deregistered due to e.g., no target for the SRV record, we would have returned from above if it
910 // was already in NoTarget state. If it was in the process of deregistration but did not complete fully before we went 908 // was already in NoTarget state. If it was in the process of deregistration but did not complete fully before we went
911 // to sleep, then it is okay to start in Pending state as we will go back to NoTarget state if we don't have a target. 909 // to sleep, then it is okay to start in Pending state as we will go back to NoTarget state if we don't have a target.
912 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 910 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
913 { 911 {
914 LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to DeregPending", ARDisplayString(m, rr), rr->state); 912 LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to DeregPending", ARDisplayString(m, rr), rr->state);
915 rr->state = regState_DeregPending; 913 rr->state = regState_DeregPending;
916 } 914 }
917 else 915 else
918 { 916 {
919 LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state); 917 LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state);
920 rr->state = regState_Pending; 918 rr->state = regState_Pending;
921 } 919 }
922 rr->ProbeCount = 0; 920 rr->ProbeCount = 0;
923 rr->AnnounceCount = 0; 921 rr->AnnounceCount = 0;
924 rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL; 922 rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
925 rr->LastAPTime = m->timenow - rr->ThisAPInterval; 923 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
926 rr->expire = 0; // Forget about all the leases, start fresh 924 rr->expire = 0; // Forget about all the leases, start fresh
927 rr->uselease = mDNStrue; 925 rr->uselease = mDNStrue;
928 rr->updateid = zeroID; 926 rr->updateid = zeroID;
929 rr->SRVChanged = mDNSfalse; 927 rr->SRVChanged = mDNSfalse;
930 rr->updateError = mStatus_NoError; 928 rr->updateError = mStatus_NoError;
931 // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core. 929 // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core.
932 // The records might already be registered with the server and hence could have NAT state. 930 // The records might already be registered with the server and hence could have NAT state.
933 if (rr->NATinfo.clientContext) 931 if (rr->NATinfo.clientContext)
934 { 932 {
935 mDNS_StopNATOperation_internal(m, &rr->NATinfo); 933 mDNS_StopNATOperation_internal(m, &rr->NATinfo);
936 rr->NATinfo.clientContext = mDNSNULL; 934 rr->NATinfo.clientContext = mDNSNULL;
937 } 935 }
938 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } 936 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
939 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } 937 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
940 if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 938 if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
941 m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval); 939 m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval);
942 } 940 }
943 941
944// Two records qualify to be local duplicates if: 942// Two records qualify to be local duplicates if:
945// (a) the RecordTypes are the same, or 943// (a) the RecordTypes are the same, or
946// (b) one is Unique and the other Verified 944// (b) one is Unique and the other Verified
947// (c) either is in the process of deregistering 945// (c) either is in the process of deregistering
948#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \ 946#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
949 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified) || \ 947 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified) || \
950 ((A)->resrec.RecordType == kDNSRecordTypeDeregistering || (B)->resrec.RecordType == kDNSRecordTypeDeregistering)) 948 ((A)->resrec.RecordType == kDNSRecordTypeDeregistering || (B)->resrec.RecordType == kDNSRecordTypeDeregistering))
951 949
952#define RecordIsLocalDuplicate(A,B) \ 950#define RecordIsLocalDuplicate(A,B) \
953 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec)) 951 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
954 952
955mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr) 953mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr)
956 { 954 {
957 AuthGroup *a; 955 AuthGroup *a;
958 AuthGroup **ag = &a; 956 AuthGroup **ag = &a;
959 AuthRecord **rp; 957 AuthRecord **rp;
960 const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 958 const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
961 959
962 a = AuthGroupForRecord(r, slot, &rr->resrec); 960 a = AuthGroupForRecord(r, slot, &rr->resrec);
963 if (!a) return mDNSNULL; 961 if (!a) return mDNSNULL;
964 rp = &(*ag)->members; 962 rp = &(*ag)->members;
965 while (*rp) 963 while (*rp)
966 { 964 {
967 if (!RecordIsLocalDuplicate(*rp, rr)) 965 if (!RecordIsLocalDuplicate(*rp, rr))
968 rp=&(*rp)->next; 966 rp=&(*rp)->next;
969 else 967 else
970 { 968 {
971 if ((*rp)->resrec.RecordType == kDNSRecordTypeDeregistering) 969 if ((*rp)->resrec.RecordType == kDNSRecordTypeDeregistering)
972 { 970 {
973 (*rp)->AnnounceCount = 0; 971 (*rp)->AnnounceCount = 0;
974 rp=&(*rp)->next; 972 rp=&(*rp)->next;
975 } 973 }
976 else return *rp; 974 else return *rp;
977 } 975 }
978 } 976 }
979 return (mDNSNULL); 977 return (mDNSNULL);
980 } 978 }
981 979
982mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr) 980mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr)
983 { 981 {
984 AuthGroup *a; 982 AuthGroup *a;
985 AuthGroup **ag = &a; 983 AuthGroup **ag = &a;
986 AuthRecord **rp; 984 AuthRecord **rp;
987 const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 985 const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
988 986
989 a = AuthGroupForRecord(r, slot, &rr->resrec); 987 a = AuthGroupForRecord(r, slot, &rr->resrec);
990 if (!a) return mDNSfalse; 988 if (!a) return mDNSfalse;
991 rp = &(*ag)->members; 989 rp = &(*ag)->members;
992 while (*rp) 990 while (*rp)
993 { 991 {
994 const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr; 992 const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
995 const AuthRecord *s2 = (*rp)->RRSet ? (*rp)->RRSet : *rp; 993 const AuthRecord *s2 = (*rp)->RRSet ? (*rp)->RRSet : *rp;
996 if (s1 != s2 && SameResourceRecordSignature((*rp), rr) && !IdenticalSameNameRecord(&(*rp)->resrec, &rr->resrec)) 994 if (s1 != s2 && SameResourceRecordSignature((*rp), rr) && !IdenticalSameNameRecord(&(*rp)->resrec, &rr->resrec))
997 return mDNStrue; 995 return mDNStrue;
998 else 996 else
999 rp=&(*rp)->next; 997 rp=&(*rp)->next;
1000 } 998 }
1001 return (mDNSfalse); 999 return (mDNSfalse);
1002 } 1000 }
1003 1001
1004// checks to see if "rr" is already present 1002// checks to see if "rr" is already present
1005mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr) 1003mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr)
1006 { 1004 {
1007 AuthGroup *a; 1005 AuthGroup *a;
1008 AuthGroup **ag = &a; 1006 AuthGroup **ag = &a;
1009 AuthRecord **rp; 1007 AuthRecord **rp;
1010 const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 1008 const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
1011 1009
1012 a = AuthGroupForRecord(r, slot, &rr->resrec); 1010 a = AuthGroupForRecord(r, slot, &rr->resrec);
1013 if (!a) return mDNSNULL; 1011 if (!a) return mDNSNULL;
1014 rp = &(*ag)->members; 1012 rp = &(*ag)->members;
1015 while (*rp) 1013 while (*rp)
1016 { 1014 {
1017 if (*rp != rr) 1015 if (*rp != rr)
1018 rp=&(*rp)->next; 1016 rp=&(*rp)->next;
1019 else 1017 else
1020 { 1018 {
1021 return *rp; 1019 return *rp;
1022 } 1020 }
1023 } 1021 }
1024 return (mDNSNULL); 1022 return (mDNSNULL);
1025 } 1023 }
1026 1024
1027// Exported so uDNS.c can call this 1025// Exported so uDNS.c can call this
1028mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) 1026mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
1029 { 1027 {
1030 domainname *target = GetRRDomainNameTarget(&rr->resrec); 1028 domainname *target = GetRRDomainNameTarget(&rr->resrec);
1031 AuthRecord *r; 1029 AuthRecord *r;
1032 AuthRecord **p = &m->ResourceRecords; 1030 AuthRecord **p = &m->ResourceRecords;
1033 AuthRecord **d = &m->DuplicateRecords; 1031 AuthRecord **d = &m->DuplicateRecords;
1034 1032
1035 if ((mDNSs32)rr->resrec.rroriginalttl <= 0) 1033 if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
1036 { LogMsg("mDNS_Register_internal: TTL %X should be 1 - 0x7FFFFFFF %s", rr->resrec.rroriginalttl, ARDisplayString(m, rr)); return(mStatus_BadParamErr); } 1034 { LogMsg("mDNS_Register_internal: TTL %X should be 1 - 0x7FFFFFFF %s", rr->resrec.rroriginalttl, ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1037 1035
1038 if (!rr->resrec.RecordType) 1036 if (!rr->resrec.RecordType)
1039 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } 1037 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1040 1038
1041 if (m->ShutdownTime) 1039 if (m->ShutdownTime)
1042 { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); } 1040 { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); }
1043  1041
1044 if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr)) 1042 if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr))
1045 { 1043 {
1046 mDNSInterfaceID previousID = rr->resrec.InterfaceID; 1044 mDNSInterfaceID previousID = rr->resrec.InterfaceID;
1047 if (rr->resrec.InterfaceID == mDNSInterface_Any || rr->resrec.InterfaceID == mDNSInterface_P2P) 1045 if (rr->resrec.InterfaceID == mDNSInterface_Any || rr->resrec.InterfaceID == mDNSInterface_P2P)
1048 { 1046 {
1049 rr->resrec.InterfaceID = mDNSInterface_LocalOnly; 1047 rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
1050 rr->ARType = AuthRecordLocalOnly; 1048 rr->ARType = AuthRecordLocalOnly;
1051 } 1049 }
1052 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) 1050 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
1053 { 1051 {
1054 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 1052 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
1055 if (intf && !intf->Advertise){ rr->resrec.InterfaceID = mDNSInterface_LocalOnly; rr->ARType = AuthRecordLocalOnly; } 1053 if (intf && !intf->Advertise){ rr->resrec.InterfaceID = mDNSInterface_LocalOnly; rr->ARType = AuthRecordLocalOnly; }
1056 } 1054 }
1057 if (rr->resrec.InterfaceID != previousID) 1055 if (rr->resrec.InterfaceID != previousID)
1058 LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr)); 1056 LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr));
1059 } 1057 }
1060 1058
1061 if (RRLocalOnly(rr)) 1059 if (RRLocalOnly(rr))
1062 { 1060 {
1063 if (CheckAuthSameRecord(&m->rrauth, rr)) 1061 if (CheckAuthSameRecord(&m->rrauth, rr))
1064 { 1062 {
1065 LogMsg("mDNS_Register_internal: ERROR!! Tried to register LocalOnly AuthRecord %p %##s (%s) that's already in the list", 1063 LogMsg("mDNS_Register_internal: ERROR!! Tried to register LocalOnly AuthRecord %p %##s (%s) that's already in the list",
1066 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1064 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1067 return(mStatus_AlreadyRegistered); 1065 return(mStatus_AlreadyRegistered);
1068 } 1066 }
1069 } 1067 }
1070 else 1068 else
1071 { 1069 {
1072 while (*p && *p != rr) p=&(*p)->next; 1070 while (*p && *p != rr) p=&(*p)->next;
1073 if (*p) 1071 if (*p)
1074 { 1072 {
1075 LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the list", 1073 LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the list",
1076 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1074 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1077 return(mStatus_AlreadyRegistered); 1075 return(mStatus_AlreadyRegistered);
1078 } 1076 }
1079 } 1077 }
1080 1078
1081 while (*d && *d != rr) d=&(*d)->next; 1079 while (*d && *d != rr) d=&(*d)->next;
1082 if (*d) 1080 if (*d)
1083 { 1081 {
1084 LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the Duplicate list", 1082 LogMsg("mDNS_Register_internal: ERROR!! Tried to register AuthRecord %p %##s (%s) that's already in the Duplicate list",
1085 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1083 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1086 return(mStatus_AlreadyRegistered); 1084 return(mStatus_AlreadyRegistered);
1087 } 1085 }
1088 1086
1089 if (rr->DependentOn) 1087 if (rr->DependentOn)
1090 { 1088 {
1091 if (rr->resrec.RecordType == kDNSRecordTypeUnique) 1089 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1092 rr->resrec.RecordType = kDNSRecordTypeVerified; 1090 rr->resrec.RecordType = kDNSRecordTypeVerified;
1093 else 1091 else
1094 { 1092 {
1095 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique", 1093 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
1096 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1094 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1097 return(mStatus_Invalid); 1095 return(mStatus_Invalid);
1098 } 1096 }
1099 if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique))) 1097 if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique)))
1100 { 1098 {
1101 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X", 1099 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
1102 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType); 1100 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
1103 return(mStatus_Invalid); 1101 return(mStatus_Invalid);
1104 } 1102 }
1105 } 1103 }
1106 1104
1107 // If this resource record is referencing a specific interface, make sure it exists. 1105 // If this resource record is referencing a specific interface, make sure it exists.
1108 // Skip checks for LocalOnly and P2P as they are not valid InterfaceIDs. Also, for scoped 1106 // Skip checks for LocalOnly and P2P as they are not valid InterfaceIDs. Also, for scoped
1109 // entries in /etc/hosts skip that check as that interface may not be valid at this time. 1107 // entries in /etc/hosts skip that check as that interface may not be valid at this time.
1110 if (rr->resrec.InterfaceID && rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P) 1108 if (rr->resrec.InterfaceID && rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P)
1111 { 1109 {
1112 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 1110 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
1113 if (!intf) 1111 if (!intf)
1114 { 1112 {
1115 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID); 1113 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID);
1116 return(mStatus_BadReferenceErr); 1114 return(mStatus_BadReferenceErr);
1117 } 1115 }
1118 } 1116 }
1119 1117
1120 rr->next = mDNSNULL; 1118 rr->next = mDNSNULL;
1121 1119
1122 // Field Group 1: The actual information pertaining to this resource record 1120 // Field Group 1: The actual information pertaining to this resource record
1123 // Set up by client prior to call 1121 // Set up by client prior to call
1124 1122
1125 // Field Group 2: Persistent metadata for Authoritative Records 1123 // Field Group 2: Persistent metadata for Authoritative Records
1126// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 1124// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1127// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 1125// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1128// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 1126// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1129// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 1127// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1130// rr->Callback = already set in mDNS_SetupResourceRecord 1128// rr->Callback = already set in mDNS_SetupResourceRecord
1131// rr->Context = already set in mDNS_SetupResourceRecord 1129// rr->Context = already set in mDNS_SetupResourceRecord
1132// rr->RecordType = already set in mDNS_SetupResourceRecord 1130// rr->RecordType = already set in mDNS_SetupResourceRecord
1133// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client 1131// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
1134// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client 1132// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
1135 // Make sure target is not uninitialized data, or we may crash writing debugging log messages 1133 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
1136 if (rr->AutoTarget && target) target->c[0] = 0; 1134 if (rr->AutoTarget && target) target->c[0] = 0;
1137 1135
1138 // Field Group 3: Transient state for Authoritative Records 1136 // Field Group 3: Transient state for Authoritative Records
1139 rr->Acknowledged = mDNSfalse; 1137 rr->Acknowledged = mDNSfalse;
1140 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 1138 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
1141 rr->AnnounceCount = InitialAnnounceCount; 1139 rr->AnnounceCount = InitialAnnounceCount;
1142 rr->RequireGoodbye = mDNSfalse; 1140 rr->RequireGoodbye = mDNSfalse;
1143 rr->AnsweredLocalQ = mDNSfalse; 1141 rr->AnsweredLocalQ = mDNSfalse;
1144 rr->IncludeInProbe = mDNSfalse; 1142 rr->IncludeInProbe = mDNSfalse;
1145 rr->ImmedUnicast = mDNSfalse; 1143 rr->ImmedUnicast = mDNSfalse;
1146 rr->SendNSECNow = mDNSNULL; 1144 rr->SendNSECNow = mDNSNULL;
1147 rr->ImmedAnswer = mDNSNULL; 1145 rr->ImmedAnswer = mDNSNULL;
1148 rr->ImmedAdditional = mDNSNULL; 1146 rr->ImmedAdditional = mDNSNULL;
1149 rr->SendRNow = mDNSNULL; 1147 rr->SendRNow = mDNSNULL;
1150 rr->v4Requester = zerov4Addr; 1148 rr->v4Requester = zerov4Addr;
1151 rr->v6Requester = zerov6Addr; 1149 rr->v6Requester = zerov6Addr;
1152 rr->NextResponse = mDNSNULL; 1150 rr->NextResponse = mDNSNULL;
1153 rr->NR_AnswerTo = mDNSNULL; 1151 rr->NR_AnswerTo = mDNSNULL;
1154 rr->NR_AdditionalTo = mDNSNULL; 1152 rr->NR_AdditionalTo = mDNSNULL;
1155 if (!rr->AutoTarget) InitializeLastAPTime(m, rr); 1153 if (!rr->AutoTarget) InitializeLastAPTime(m, rr);
1156// rr->LastAPTime = Set for us in InitializeLastAPTime() 1154// rr->LastAPTime = Set for us in InitializeLastAPTime()
1157// rr->LastMCTime = Set for us in InitializeLastAPTime() 1155// rr->LastMCTime = Set for us in InitializeLastAPTime()
1158// rr->LastMCInterface = Set for us in InitializeLastAPTime() 1156// rr->LastMCInterface = Set for us in InitializeLastAPTime()
1159 rr->NewRData = mDNSNULL; 1157 rr->NewRData = mDNSNULL;
1160 rr->newrdlength = 0; 1158 rr->newrdlength = 0;
1161 rr->UpdateCallback = mDNSNULL; 1159 rr->UpdateCallback = mDNSNULL;
1162 rr->UpdateCredits = kMaxUpdateCredits; 1160 rr->UpdateCredits = kMaxUpdateCredits;
1163 rr->NextUpdateCredit = 0; 1161 rr->NextUpdateCredit = 0;
1164 rr->UpdateBlocked = 0; 1162 rr->UpdateBlocked = 0;
1165 1163
1166 // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient 1164 // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient
1167 if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2; 1165 if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2;
1168 1166
1169 // Field Group 4: Transient uDNS state for Authoritative Records 1167 // Field Group 4: Transient uDNS state for Authoritative Records
1170 rr->state = regState_Zero; 1168 rr->state = regState_Zero;
1171 rr->uselease = 0; 1169 rr->uselease = 0;
1172 rr->expire = 0; 1170 rr->expire = 0;
1173 rr->Private = 0; 1171 rr->Private = 0;
1174 rr->updateid = zeroID; 1172 rr->updateid = zeroID;
1175 rr->zone = rr->resrec.name; 1173 rr->zone = rr->resrec.name;
1176 rr->nta = mDNSNULL; 1174 rr->nta = mDNSNULL;
1177 rr->tcp = mDNSNULL; 1175 rr->tcp = mDNSNULL;
1178 rr->OrigRData = 0; 1176 rr->OrigRData = 0;
1179 rr->OrigRDLen = 0; 1177 rr->OrigRDLen = 0;
1180 rr->InFlightRData = 0; 1178 rr->InFlightRData = 0;
1181 rr->InFlightRDLen = 0; 1179 rr->InFlightRDLen = 0;
1182 rr->QueuedRData = 0; 1180 rr->QueuedRData = 0;
1183 rr->QueuedRDLen = 0; 1181 rr->QueuedRDLen = 0;
1184 //mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo)); 1182 //mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo));
1185 // We should be recording the actual internal port for this service record here. Once we initiate our NAT mapping 1183 // We should be recording the actual internal port for this service record here. Once we initiate our NAT mapping
1186 // request we'll subsequently overwrite srv.port with the allocated external NAT port -- potentially multiple 1184 // request we'll subsequently overwrite srv.port with the allocated external NAT port -- potentially multiple
1187 // times with different values if the external NAT port changes during the lifetime of the service registration. 1185 // times with different values if the external NAT port changes during the lifetime of the service registration.
1188 //if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port; 1186 //if (rr->resrec.rrtype == kDNSType_SRV) rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port;
1189 1187
1190// rr->resrec.interface = already set in mDNS_SetupResourceRecord 1188// rr->resrec.interface = already set in mDNS_SetupResourceRecord
1191// rr->resrec.name->c = MUST be set by client 1189// rr->resrec.name->c = MUST be set by client
1192// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord 1190// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
1193// rr->resrec.rrclass = already set in mDNS_SetupResourceRecord 1191// rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
1194// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord 1192// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
1195// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set 1193// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
1196 1194
1197 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, 1195 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1198 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". 1196 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1199 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. 1197 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1200 if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; } 1198 if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
1201 1199
1202 if (rr->AutoTarget) 1200 if (rr->AutoTarget)
1203 { 1201 {
1204 SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime(); 1202 SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
1205#ifndef UNICAST_DISABLED 1203#ifndef UNICAST_DISABLED
1206 // If we have no target record yet, SetTargetToHostName will set rr->state == regState_NoTarget 1204 // If we have no target record yet, SetTargetToHostName will set rr->state == regState_NoTarget
1207 // In this case we leave the record half-formed in the list, and later we'll remove it from the list and re-add it properly. 1205 // In this case we leave the record half-formed in the list, and later we'll remove it from the list and re-add it properly.
1208 if (rr->state == regState_NoTarget) 1206 if (rr->state == regState_NoTarget)
1209 { 1207 {
1210 // Initialize the target so that we don't crash while logging etc. 1208 // Initialize the target so that we don't crash while logging etc.
1211 domainname *tar = GetRRDomainNameTarget(&rr->resrec); 1209 domainname *tar = GetRRDomainNameTarget(&rr->resrec);
1212 if (tar) tar->c[0] = 0; 1210 if (tar) tar->c[0] = 0;
1213 LogInfo("mDNS_Register_internal: record %s in NoTarget state", ARDisplayString(m, rr)); 1211 LogInfo("mDNS_Register_internal: record %s in NoTarget state", ARDisplayString(m, rr));
1214 } 1212 }
1215#endif 1213#endif
1216 } 1214 }
1217 else 1215 else
1218 { 1216 {
1219 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse); 1217 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
1220 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue); 1218 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
1221 } 1219 }
1222 1220
1223 if (!ValidateDomainName(rr->resrec.name)) 1221 if (!ValidateDomainName(rr->resrec.name))
1224 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } 1222 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
1225 1223
1226 // Don't do this until *after* we've set rr->resrec.rdlength 1224 // Don't do this until *after* we've set rr->resrec.rdlength
1227 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata)) 1225 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
1228 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } 1226 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
1229 1227
1230 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 1228 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
1231 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec); 1229 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec);
1232  1230
1233 if (RRLocalOnly(rr)) 1231 if (RRLocalOnly(rr))
1234 { 1232 {
1235 // If this is supposed to be unique, make sure we don't have any name conflicts. 1233 // If this is supposed to be unique, make sure we don't have any name conflicts.
1236 // If we found a conflict, we may still want to insert the record in the list but mark it appropriately 1234 // If we found a conflict, we may still want to insert the record in the list but mark it appropriately
1237 // (kDNSRecordTypeDeregistering) so that we deliver RMV events to the application. But this causes more 1235 // (kDNSRecordTypeDeregistering) so that we deliver RMV events to the application. But this causes more
1238 // complications and not clear whether there are any benefits. See rdar:9304275 for details. 1236 // complications and not clear whether there are any benefits. See rdar:9304275 for details.
1239 // Hence, just bail out. 1237 // Hence, just bail out.
1240 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 1238 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
1241 { 1239 {
1242 if (CheckAuthRecordConflict(&m->rrauth, rr)) 1240 if (CheckAuthRecordConflict(&m->rrauth, rr))
1243 { 1241 {
1244 LogInfo("mDNS_Register_internal: Name conflict %s (%p), InterfaceID %p", ARDisplayString(m, rr), rr, rr->resrec.InterfaceID); 1242 LogInfo("mDNS_Register_internal: Name conflict %s (%p), InterfaceID %p", ARDisplayString(m, rr), rr, rr->resrec.InterfaceID);
1245 return mStatus_NameConflict; 1243 return mStatus_NameConflict;
1246 } 1244 }
1247 } 1245 }
1248 } 1246 }
1249 1247
1250 // For uDNS records, we don't support duplicate checks at this time. 1248 // For uDNS records, we don't support duplicate checks at this time.
1251#ifndef UNICAST_DISABLED 1249#ifndef UNICAST_DISABLED
1252 if (AuthRecord_uDNS(rr)) 1250 if (AuthRecord_uDNS(rr))
1253 { 1251 {
1254 if (!m->NewLocalRecords) m->NewLocalRecords = rr; 1252 if (!m->NewLocalRecords) m->NewLocalRecords = rr;
1255 // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new 1253 // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new
1256 // records to the list, so we now need to update p to advance to the new end to the list before appending our new record. 1254 // records to the list, so we now need to update p to advance to the new end to the list before appending our new record.
1257 // Note that for AutoTunnel this should never happen, but this check makes the code future-proof. 1255 // Note that for AutoTunnel this should never happen, but this check makes the code future-proof.
1258 while (*p) p=&(*p)->next; 1256 while (*p) p=&(*p)->next;
1259 *p = rr; 1257 *p = rr;
1260 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; 1258 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
1261 rr->ProbeCount = 0; 1259 rr->ProbeCount = 0;
1262 rr->AnnounceCount = 0; 1260 rr->AnnounceCount = 0;
1263 if (rr->state != regState_NoTarget) ActivateUnicastRegistration(m, rr); 1261 if (rr->state != regState_NoTarget) ActivateUnicastRegistration(m, rr);
1264 return(mStatus_NoError); // <--- Note: For unicast records, code currently bails out at this point 1262 return(mStatus_NoError); // <--- Note: For unicast records, code currently bails out at this point
1265 } 1263 }
1266#endif 1264#endif
1267 1265
1268 // Now that we've finished building our new record, make sure it's not identical to one we already have 1266 // Now that we've finished building our new record, make sure it's not identical to one we already have
1269 if (RRLocalOnly(rr)) 1267 if (RRLocalOnly(rr))
1270 { 1268 {
1271 rr->ProbeCount = 0; 1269 rr->ProbeCount = 0;
1272 rr->AnnounceCount = 0; 1270 rr->AnnounceCount = 0;
1273 r = CheckAuthIdenticalRecord(&m->rrauth, rr); 1271 r = CheckAuthIdenticalRecord(&m->rrauth, rr);
1274 } 1272 }
1275 else 1273 else
1276 { 1274 {
1277 for (r = m->ResourceRecords; r; r=r->next) 1275 for (r = m->ResourceRecords; r; r=r->next)
1278 if (RecordIsLocalDuplicate(r, rr)) 1276 if (RecordIsLocalDuplicate(r, rr))
1279 { 1277 {
1280 if (r->resrec.RecordType == kDNSRecordTypeDeregistering) r->AnnounceCount = 0; 1278 if (r->resrec.RecordType == kDNSRecordTypeDeregistering) r->AnnounceCount = 0;
1281 else break; 1279 else break;
1282 } 1280 }
1283 } 1281 }
1284 1282
1285 if (r) 1283 if (r)
1286 { 1284 {
1287 debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr)); 1285 debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr));
1288 *d = rr; 1286 *d = rr;
1289 // If the previous copy of this record is already verified unique, 1287 // If the previous copy of this record is already verified unique,
1290 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state. 1288 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
1291 // Setting ProbeCount to zero will cause SendQueries() to advance this record to 1289 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
1292 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time. 1290 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
1293 if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified) 1291 if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
1294 rr->ProbeCount = 0; 1292 rr->ProbeCount = 0;
1295 } 1293 }
1296 else 1294 else
1297 { 1295 {
1298 debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr)); 1296 debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr));
1299 if (RRLocalOnly(rr)) 1297 if (RRLocalOnly(rr))
1300 { 1298 {
1301 AuthGroup *ag; 1299 AuthGroup *ag;
1302 ag = InsertAuthRecord(m, &m->rrauth, rr); 1300 ag = InsertAuthRecord(m, &m->rrauth, rr);
1303 if (ag && !ag->NewLocalOnlyRecords) { 1301 if (ag && !ag->NewLocalOnlyRecords) {
1304 m->NewLocalOnlyRecords = mDNStrue; 1302 m->NewLocalOnlyRecords = mDNStrue;
1305 ag->NewLocalOnlyRecords = rr; 1303 ag->NewLocalOnlyRecords = rr;
1306 } 1304 }
1307 // No probing for LocalOnly records, Acknowledge them right away 1305 // No probing for LocalOnly records, Acknowledge them right away
1308 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; 1306 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
1309 AcknowledgeRecord(m, rr); 1307 AcknowledgeRecord(m, rr);
1310 return(mStatus_NoError); 1308 return(mStatus_NoError);
1311 } 1309 }
1312 else 1310 else
1313 { 1311 {
1314 if (!m->NewLocalRecords) m->NewLocalRecords = rr; 1312 if (!m->NewLocalRecords) m->NewLocalRecords = rr;
1315 *p = rr; 1313 *p = rr;
1316 } 1314 }
1317 } 1315 }
1318 1316
1319 if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above 1317 if (!AuthRecord_uDNS(rr)) // This check is superfluous, given that for unicast records we (currently) bail out above
1320 { 1318 {
1321 // For records that are not going to probe, acknowledge them right away 1319 // For records that are not going to probe, acknowledge them right away
1322 if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) 1320 if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
1323 AcknowledgeRecord(m, rr); 1321 AcknowledgeRecord(m, rr);
1324 1322
1325 // Adding a record may affect whether or not we should sleep 1323 // Adding a record may affect whether or not we should sleep
1326 mDNS_UpdateAllowSleep(m); 1324 mDNS_UpdateAllowSleep(m);
1327 } 1325 }
1328 1326
1329 return(mStatus_NoError); 1327 return(mStatus_NoError);
1330 } 1328 }
1331 1329
1332mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr) 1330mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
1333 { 1331 {
1334 m->ProbeFailTime = m->timenow; 1332 m->ProbeFailTime = m->timenow;
1335 m->NumFailedProbes++; 1333 m->NumFailedProbes++;
1336 // If we've had fifteen or more probe failures, rate-limit to one every five seconds. 1334 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
1337 // If a bunch of hosts have all been configured with the same name, then they'll all 1335 // If a bunch of hosts have all been configured with the same name, then they'll all
1338 // conflict and run through the same series of names: name-2, name-3, name-4, etc., 1336 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
1339 // up to name-10. After that they'll start adding random increments in the range 1-100, 1337 // up to name-10. After that they'll start adding random increments in the range 1-100,
1340 // so they're more likely to branch out in the available namespace and settle on a set of 1338 // so they're more likely to branch out in the available namespace and settle on a set of
1341 // unique names quickly. If after five more tries the host is still conflicting, then we 1339 // unique names quickly. If after five more tries the host is still conflicting, then we
1342 // may have a serious problem, so we start rate-limiting so we don't melt down the network. 1340 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
1343 if (m->NumFailedProbes >= 15) 1341 if (m->NumFailedProbes >= 15)
1344 { 1342 {
1345 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); 1343 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
1346 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect", 1344 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
1347 m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1345 m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1348 } 1346 }
1349 } 1347 }
1350 1348
1351mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr) 1349mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
1352 { 1350 {
1353 RData *OldRData = rr->resrec.rdata; 1351 RData *OldRData = rr->resrec.rdata;
1354 mDNSu16 OldRDLen = rr->resrec.rdlength; 1352 mDNSu16 OldRDLen = rr->resrec.rdlength;
1355 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata 1353 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata
1356 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... 1354 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
1357 if (rr->UpdateCallback) 1355 if (rr->UpdateCallback)
1358 rr->UpdateCallback(m, rr, OldRData, OldRDLen); // ... and let the client know 1356 rr->UpdateCallback(m, rr, OldRData, OldRDLen); // ... and let the client know
1359 } 1357 }
1360 1358
1361// Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list. 1359// Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
1362// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 1360// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
1363// Exported so uDNS.c can call this 1361// Exported so uDNS.c can call this
1364mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) 1362mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
1365 { 1363 {
1366 AuthRecord *r2; 1364 AuthRecord *r2;
1367 mDNSu8 RecordType = rr->resrec.RecordType; 1365 mDNSu8 RecordType = rr->resrec.RecordType;
1368 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records 1366 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records
1369 mDNSBool dupList = mDNSfalse; 1367 mDNSBool dupList = mDNSfalse;
1370 1368
1371 if (RRLocalOnly(rr)) 1369 if (RRLocalOnly(rr))
1372 { 1370 {
1373 AuthGroup *a; 1371 AuthGroup *a;
1374 AuthGroup **ag = &a; 1372 AuthGroup **ag = &a;
1375 AuthRecord **rp; 1373 AuthRecord **rp;
1376 const mDNSu32 slot = AuthHashSlot(rr->resrec.name); 1374 const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
1377  1375
1378 a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec); 1376 a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
1379 if (!a) return mDNSfalse; 1377 if (!a) return mDNSfalse;
1380 rp = &(*ag)->members; 1378 rp = &(*ag)->members;
1381 while (*rp && *rp != rr) rp=&(*rp)->next; 1379 while (*rp && *rp != rr) rp=&(*rp)->next;
1382 p = rp; 1380 p = rp;
1383 } 1381 }
1384 else 1382 else
1385 { 1383 {
1386 while (*p && *p != rr) p=&(*p)->next; 1384 while (*p && *p != rr) p=&(*p)->next;
1387 } 1385 }
1388 1386
1389 if (*p) 1387 if (*p)
1390 { 1388 {
1391 // We found our record on the main list. See if there are any duplicates that need special handling. 1389 // We found our record on the main list. See if there are any duplicates that need special handling.
1392 if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment 1390 if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment
1393 { 1391 {
1394 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished 1392 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
1395 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory. 1393 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
1396 for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF; 1394 for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
1397 } 1395 }
1398 else 1396 else
1399 { 1397 {
1400 // Before we delete the record (and potentially send a goodbye packet) 1398 // Before we delete the record (and potentially send a goodbye packet)
1401 // first see if we have a record on the duplicate list ready to take over from it. 1399 // first see if we have a record on the duplicate list ready to take over from it.
1402 AuthRecord **d = &m->DuplicateRecords; 1400 AuthRecord **d = &m->DuplicateRecords;
1403 while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next; 1401 while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next;
1404 if (*d) 1402 if (*d)
1405 { 1403 {
1406 AuthRecord *dup = *d; 1404 AuthRecord *dup = *d;
1407 debugf("mDNS_Register_internal: Duplicate record %p taking over from %p %##s (%s)", 1405 debugf("mDNS_Register_internal: Duplicate record %p taking over from %p %##s (%s)",
1408 dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1406 dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1409 *d = dup->next; // Cut replacement record from DuplicateRecords list 1407 *d = dup->next; // Cut replacement record from DuplicateRecords list
1410 if (RRLocalOnly(rr)) 1408 if (RRLocalOnly(rr))
1411 { 1409 {
1412 dup->next = mDNSNULL; 1410 dup->next = mDNSNULL;
1413 if (!InsertAuthRecord(m, &m->rrauth, dup)) LogMsg("mDNS_Deregister_internal: ERROR!! cannot insert %s", ARDisplayString(m, dup)); 1411 if (!InsertAuthRecord(m, &m->rrauth, dup)) LogMsg("mDNS_Deregister_internal: ERROR!! cannot insert %s", ARDisplayString(m, dup));
1414 } 1412 }
1415 else 1413 else
1416 { 1414 {
1417 dup->next = rr->next; // And then... 1415 dup->next = rr->next; // And then...
1418 rr->next = dup; // ... splice it in right after the record we're about to delete 1416 rr->next = dup; // ... splice it in right after the record we're about to delete
1419 } 1417 }
1420 dup->resrec.RecordType = rr->resrec.RecordType; 1418 dup->resrec.RecordType = rr->resrec.RecordType;
1421 dup->ProbeCount = rr->ProbeCount; 1419 dup->ProbeCount = rr->ProbeCount;
1422 dup->AnnounceCount = rr->AnnounceCount; 1420 dup->AnnounceCount = rr->AnnounceCount;
1423 dup->RequireGoodbye = rr->RequireGoodbye; 1421 dup->RequireGoodbye = rr->RequireGoodbye;
1424 dup->AnsweredLocalQ = rr->AnsweredLocalQ; 1422 dup->AnsweredLocalQ = rr->AnsweredLocalQ;
1425 dup->ImmedAnswer = rr->ImmedAnswer; 1423 dup->ImmedAnswer = rr->ImmedAnswer;
1426 dup->ImmedUnicast = rr->ImmedUnicast; 1424 dup->ImmedUnicast = rr->ImmedUnicast;
1427 dup->ImmedAdditional = rr->ImmedAdditional; 1425 dup->ImmedAdditional = rr->ImmedAdditional;
1428 dup->v4Requester = rr->v4Requester; 1426 dup->v4Requester = rr->v4Requester;
1429 dup->v6Requester = rr->v6Requester; 1427 dup->v6Requester = rr->v6Requester;
1430 dup->ThisAPInterval = rr->ThisAPInterval; 1428 dup->ThisAPInterval = rr->ThisAPInterval;
1431 dup->LastAPTime = rr->LastAPTime; 1429 dup->LastAPTime = rr->LastAPTime;
1432 dup->LastMCTime = rr->LastMCTime; 1430 dup->LastMCTime = rr->LastMCTime;
1433 dup->LastMCInterface = rr->LastMCInterface; 1431 dup->LastMCInterface = rr->LastMCInterface;
1434 dup->Private = rr->Private; 1432 dup->Private = rr->Private;
1435 dup->state = rr->state; 1433 dup->state = rr->state;
1436 rr->RequireGoodbye = mDNSfalse; 1434 rr->RequireGoodbye = mDNSfalse;
1437 rr->AnsweredLocalQ = mDNSfalse; 1435 rr->AnsweredLocalQ = mDNSfalse;
1438 } 1436 }
1439 } 1437 }
1440 } 1438 }
1441 else 1439 else
1442 { 1440 {
1443 // We didn't find our record on the main list; try the DuplicateRecords list instead. 1441 // We didn't find our record on the main list; try the DuplicateRecords list instead.
1444 p = &m->DuplicateRecords; 1442 p = &m->DuplicateRecords;
1445 while (*p && *p != rr) p=&(*p)->next; 1443 while (*p && *p != rr) p=&(*p)->next;
1446 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it 1444 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
1447 if (*p) { rr->RequireGoodbye = mDNSfalse; dupList = mDNStrue; } 1445 if (*p) { rr->RequireGoodbye = mDNSfalse; dupList = mDNStrue; }
1448 if (*p) debugf("mDNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", 1446 if (*p) debugf("mDNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
1449 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1447 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1450 } 1448 }
1451 1449
1452 if (!*p) 1450 if (!*p)
1453 { 1451 {
1454 // No need to log an error message if we already know this is a potentially repeated deregistration 1452 // No need to log an error message if we already know this is a potentially repeated deregistration
1455 if (drt != mDNS_Dereg_repeat) 1453 if (drt != mDNS_Dereg_repeat)
1456 LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr)); 1454 LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr));
1457 return(mStatus_BadReferenceErr); 1455 return(mStatus_BadReferenceErr);
1458 } 1456 }
1459 1457
1460 // If this is a shared record and we've announced it at least once, 1458 // If this is a shared record and we've announced it at least once,
1461 // we need to retract that announcement before we delete the record 1459 // we need to retract that announcement before we delete the record
1462 1460
1463 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then 1461 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
1464 // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe. 1462 // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
1465 // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion" 1463 // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
1466 // mechanism to cope with the client callback modifying the question list while that's happening. 1464 // mechanism to cope with the client callback modifying the question list while that's happening.
1467 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain) 1465 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
1468 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice. 1466 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
1469 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other 1467 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
1470 // records, thereby invoking yet more callbacks, without limit. 1468 // records, thereby invoking yet more callbacks, without limit.
1471 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending 1469 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
1472 // actual goodbye packets. 1470 // actual goodbye packets.
1473  1471
1474#ifndef UNICAST_DISABLED 1472#ifndef UNICAST_DISABLED
1475 if (AuthRecord_uDNS(rr)) 1473 if (AuthRecord_uDNS(rr))
1476 { 1474 {
1477 if (rr->RequireGoodbye) 1475 if (rr->RequireGoodbye)
1478 { 1476 {
1479 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } 1477 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
1480 rr->resrec.RecordType = kDNSRecordTypeDeregistering; 1478 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
1481 m->LocalRemoveEvents = mDNStrue; 1479 m->LocalRemoveEvents = mDNStrue;
1482 uDNS_DeregisterRecord(m, rr); 1480 uDNS_DeregisterRecord(m, rr);
1483 // At this point unconditionally we bail out 1481 // At this point unconditionally we bail out
1484 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration, 1482 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
1485 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration 1483 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
1486 // process and will complete asynchronously. Either way we don't need to do anything more here. 1484 // process and will complete asynchronously. Either way we don't need to do anything more here.
1487 return(mStatus_NoError); 1485 return(mStatus_NoError);
1488 } 1486 }
1489 // Sometimes the records don't complete proper deregistration i.e., don't wait for a response 1487 // Sometimes the records don't complete proper deregistration i.e., don't wait for a response
1490 // from the server. In that case, if the records have been part of a group update, clear the 1488 // from the server. In that case, if the records have been part of a group update, clear the
1491 // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized 1489 // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized
1492 rr->updateid = zeroID; 1490 rr->updateid = zeroID;
1493 1491
1494 // We defer cleaning up NAT state only after sending goodbyes. This is important because 1492 // We defer cleaning up NAT state only after sending goodbyes. This is important because
1495 // RecordRegistrationGotZoneData guards against creating NAT state if clientContext is non-NULL. 1493 // RecordRegistrationGotZoneData guards against creating NAT state if clientContext is non-NULL.
1496 // This happens today when we turn on/off interface where we get multiple network transitions 1494 // This happens today when we turn on/off interface where we get multiple network transitions
1497 // and RestartRecordGetZoneData triggers re-registration of the resource records even though 1495 // and RestartRecordGetZoneData triggers re-registration of the resource records even though
1498 // they may be in Registered state which causes NAT information to be setup multiple times. Defering 1496 // they may be in Registered state which causes NAT information to be setup multiple times. Defering
1499 // the cleanup here keeps clientContext non-NULL and hence prevents that. Note that cleaning up 1497 // the cleanup here keeps clientContext non-NULL and hence prevents that. Note that cleaning up
1500 // NAT state here takes care of the case where we did not send goodbyes at all. 1498 // NAT state here takes care of the case where we did not send goodbyes at all.
1501 if (rr->NATinfo.clientContext) 1499 if (rr->NATinfo.clientContext)
1502 { 1500 {
1503 mDNS_StopNATOperation_internal(m, &rr->NATinfo); 1501 mDNS_StopNATOperation_internal(m, &rr->NATinfo);
1504 rr->NATinfo.clientContext = mDNSNULL; 1502 rr->NATinfo.clientContext = mDNSNULL;
1505 } 1503 }
1506 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } 1504 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
1507 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } 1505 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
1508 } 1506 }
1509#endif // UNICAST_DISABLED 1507#endif // UNICAST_DISABLED
1510 1508
1511 if (RecordType == kDNSRecordTypeUnregistered) 1509 if (RecordType == kDNSRecordTypeUnregistered)
1512 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr)); 1510 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
1513 else if (RecordType == kDNSRecordTypeDeregistering) 1511 else if (RecordType == kDNSRecordTypeDeregistering)
1514 { 1512 {
1515 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr)); 1513 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
1516 return(mStatus_BadReferenceErr); 1514 return(mStatus_BadReferenceErr);
1517 } 1515 }
1518 1516
1519 // <rdar://problem/7457925> Local-only questions don't get remove events for unique records 1517 // <rdar://problem/7457925> Local-only questions don't get remove events for unique records
1520 // We may want to consider changing this code so that we generate local-only question "rmv" 1518 // We may want to consider changing this code so that we generate local-only question "rmv"
1521 // events (and maybe goodbye packets too) for unique records as well as for shared records 1519 // events (and maybe goodbye packets too) for unique records as well as for shared records
1522 // Note: If we change the logic for this "if" statement, need to ensure that the code in 1520 // Note: If we change the logic for this "if" statement, need to ensure that the code in
1523 // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else" 1521 // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else"
1524 // clause will execute here and the record will be cut from the list. 1522 // clause will execute here and the record will be cut from the list.
1525 if (rr->WakeUp.HMAC.l[0] || 1523 if (rr->WakeUp.HMAC.l[0] ||
1526 (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))) 1524 (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)))
1527 { 1525 {
1528 verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr)); 1526 verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr));
1529 rr->resrec.RecordType = kDNSRecordTypeDeregistering; 1527 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
1530 rr->resrec.rroriginalttl = 0; 1528 rr->resrec.rroriginalttl = 0;
1531 rr->AnnounceCount = rr->WakeUp.HMAC.l[0] ? WakeupCount : (drt == mDNS_Dereg_rapid) ? 1 : GoodbyeCount; 1529 rr->AnnounceCount = rr->WakeUp.HMAC.l[0] ? WakeupCount : (drt == mDNS_Dereg_rapid) ? 1 : GoodbyeCount;
1532 rr->ThisAPInterval = mDNSPlatformOneSecond * 2; 1530 rr->ThisAPInterval = mDNSPlatformOneSecond * 2;
1533 rr->LastAPTime = m->timenow - rr->ThisAPInterval; 1531 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
1534 m->LocalRemoveEvents = mDNStrue; 1532 m->LocalRemoveEvents = mDNStrue;
1535 if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0) 1533 if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
1536 m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10); 1534 m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
1537 } 1535 }
1538 else 1536 else
1539 { 1537 {
1540 if (!dupList && RRLocalOnly(rr)) 1538 if (!dupList && RRLocalOnly(rr))
1541 { 1539 {
1542 AuthGroup *ag = RemoveAuthRecord(m, &m->rrauth, rr); 1540 AuthGroup *ag = RemoveAuthRecord(m, &m->rrauth, rr);
1543 if (ag->NewLocalOnlyRecords == rr) ag->NewLocalOnlyRecords = rr->next; 1541 if (ag->NewLocalOnlyRecords == rr) ag->NewLocalOnlyRecords = rr->next;
1544 } 1542 }
1545 else 1543 else
1546 { 1544 {
1547 *p = rr->next; // Cut this record from the list 1545 *p = rr->next; // Cut this record from the list
1548 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next; 1546 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
1549 } 1547 }
1550 // If someone is about to look at this, bump the pointer forward 1548 // If someone is about to look at this, bump the pointer forward
1551 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next; 1549 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
1552 rr->next = mDNSNULL; 1550 rr->next = mDNSNULL;
1553 1551
1554 // Should we generate local remove events here? 1552 // Should we generate local remove events here?
1555 // i.e. something like: 1553 // i.e. something like:
1556 // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } 1554 // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
1557 1555
1558 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr)); 1556 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
1559 rr->resrec.RecordType = kDNSRecordTypeUnregistered; 1557 rr->resrec.RecordType = kDNSRecordTypeUnregistered;
1560 1558
1561 if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared) 1559 if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
1562 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)", 1560 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
1563 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1561 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1564 1562
1565 // If we have an update queued up which never executed, give the client a chance to free that memory 1563 // If we have an update queued up which never executed, give the client a chance to free that memory
1566 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client 1564 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
1567 1565
1568 1566
1569 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function 1567 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1570 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 1568 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1571 // In this case the likely client action to the mStatus_MemFree message is to free the memory, 1569 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
1572 // so any attempt to touch rr after this is likely to lead to a crash. 1570 // so any attempt to touch rr after this is likely to lead to a crash.
1573 if (drt != mDNS_Dereg_conflict) 1571 if (drt != mDNS_Dereg_conflict)
1574 { 1572 {
1575 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 1573 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1576 LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr)); 1574 LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr));
1577 if (rr->RecordCallback) 1575 if (rr->RecordCallback)
1578 rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this 1576 rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
1579 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 1577 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1580 } 1578 }
1581 else 1579 else
1582 { 1580 {
1583 RecordProbeFailure(m, rr); 1581 RecordProbeFailure(m, rr);
1584 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 1582 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1585 if (rr->RecordCallback) 1583 if (rr->RecordCallback)
1586 rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this 1584 rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this
1587 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 1585 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1588 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously. 1586 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
1589 // Note that with all the client callbacks going on, by the time we get here all the 1587 // Note that with all the client callbacks going on, by the time we get here all the
1590 // records we marked may have been explicitly deregistered by the client anyway. 1588 // records we marked may have been explicitly deregistered by the client anyway.
1591 r2 = m->DuplicateRecords; 1589 r2 = m->DuplicateRecords;
1592 while (r2) 1590 while (r2)
1593 { 1591 {
1594 if (r2->ProbeCount != 0xFF) r2 = r2->next; 1592 if (r2->ProbeCount != 0xFF) r2 = r2->next;
1595 else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; } 1593 else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
1596 } 1594 }
1597 } 1595 }
1598 } 1596 }
1599 mDNS_UpdateAllowSleep(m); 1597 mDNS_UpdateAllowSleep(m);
1600 return(mStatus_NoError); 1598 return(mStatus_NoError);
1601 } 1599 }
1602 1600
1603// *************************************************************************** 1601// ***************************************************************************
1604#if COMPILER_LIKES_PRAGMA_MARK 1602#if COMPILER_LIKES_PRAGMA_MARK
1605#pragma mark - 1603#pragma mark -
1606#pragma mark - Packet Sending Functions 1604#pragma mark - Packet Sending Functions
1607#endif 1605#endif
1608 1606
1609mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add) 1607mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
1610 { 1608 {
1611 if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse) 1609 if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
1612 { 1610 {
1613 **nrpp = rr; 1611 **nrpp = rr;
1614 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo) 1612 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
1615 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does 1613 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
1616 // The referenced record will definitely be acceptable (by recursive application of this rule) 1614 // The referenced record will definitely be acceptable (by recursive application of this rule)
1617 if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo; 1615 if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
1618 rr->NR_AdditionalTo = add; 1616 rr->NR_AdditionalTo = add;
1619 *nrpp = &rr->NextResponse; 1617 *nrpp = &rr->NextResponse;
1620 } 1618 }
1621 debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1619 debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1622 } 1620 }
1623 1621
1624mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID) 1622mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
1625 { 1623 {
1626 AuthRecord *rr, *rr2; 1624 AuthRecord *rr, *rr2;
1627 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put 1625 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put
1628 { 1626 {
1629 // (Note: This is an "if", not a "while". If we add a record, we'll find it again 1627 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
1630 // later in the "for" loop, and we will follow further "additional" links then.) 1628 // later in the "for" loop, and we will follow further "additional" links then.)
1631 if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID)) 1629 if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
1632 AddRecordToResponseList(nrpp, rr->Additional1, rr); 1630 AddRecordToResponseList(nrpp, rr->Additional1, rr);
1633 1631
1634 if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID)) 1632 if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
1635 AddRecordToResponseList(nrpp, rr->Additional2, rr); 1633 AddRecordToResponseList(nrpp, rr->Additional2, rr);
1636 1634
1637 // For SRV records, automatically add the Address record(s) for the target host 1635 // For SRV records, automatically add the Address record(s) for the target host
1638 if (rr->resrec.rrtype == kDNSType_SRV) 1636 if (rr->resrec.rrtype == kDNSType_SRV)
1639 { 1637 {
1640 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records 1638 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
1641 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... 1639 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
1642 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... 1640 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
1643 rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target 1641 rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target
1644 SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name)) 1642 SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
1645 AddRecordToResponseList(nrpp, rr2, rr); 1643 AddRecordToResponseList(nrpp, rr2, rr);
1646 } 1644 }
1647 else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional 1645 else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional
1648 { 1646 {
1649 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records 1647 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
1650 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... 1648 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
1651 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... 1649 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
1652 rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name 1650 rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name
1653 SameDomainName(rr->resrec.name, rr2->resrec.name)) 1651 SameDomainName(rr->resrec.name, rr2->resrec.name))
1654 AddRecordToResponseList(nrpp, rr2, rr); 1652 AddRecordToResponseList(nrpp, rr2, rr);
1655 } 1653 }
1656 else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record 1654 else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record
1657 { 1655 {
1658 if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) && 1656 if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) &&
1659 SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) 1657 SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
1660 AddRecordToResponseList(nrpp, &m->DeviceInfo, rr); 1658 AddRecordToResponseList(nrpp, &m->DeviceInfo, rr);
1661 } 1659 }
1662 } 1660 }
1663 } 1661 }
1664 1662
1665mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID) 1663mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
1666 { 1664 {
1667 AuthRecord *rr; 1665 AuthRecord *rr;
1668 AuthRecord *ResponseRecords = mDNSNULL; 1666 AuthRecord *ResponseRecords = mDNSNULL;
1669 AuthRecord **nrp = &ResponseRecords; 1667 AuthRecord **nrp = &ResponseRecords;
1670 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 1668 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
1671 1669
1672 // Make a list of all our records that need to be unicast to this destination 1670 // Make a list of all our records that need to be unicast to this destination
1673 for (rr = m->ResourceRecords; rr; rr=rr->next) 1671 for (rr = m->ResourceRecords; rr; rr=rr->next)
1674 { 1672 {
1675 // If we find we can no longer unicast this answer, clear ImmedUnicast 1673 // If we find we can no longer unicast this answer, clear ImmedUnicast
1676 if (rr->ImmedAnswer == mDNSInterfaceMark || 1674 if (rr->ImmedAnswer == mDNSInterfaceMark ||
1677 mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) || 1675 mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
1678 mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) ) 1676 mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) )
1679 rr->ImmedUnicast = mDNSfalse; 1677 rr->ImmedUnicast = mDNSfalse;
1680 1678
1681 if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID) 1679 if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
1682 { 1680 {
1683 if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) || 1681 if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
1684 (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6))) 1682 (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
1685 { 1683 {
1686 rr->ImmedAnswer = mDNSNULL; // Clear the state fields 1684 rr->ImmedAnswer = mDNSNULL; // Clear the state fields
1687 rr->ImmedUnicast = mDNSfalse; 1685 rr->ImmedUnicast = mDNSfalse;
1688 rr->v4Requester = zerov4Addr; 1686 rr->v4Requester = zerov4Addr;
1689 rr->v6Requester = zerov6Addr; 1687 rr->v6Requester = zerov6Addr;
1690 1688
1691 // Only sent records registered for P2P over P2P interfaces 1689 // Only sent records registered for P2P over P2P interfaces
1692 if (intf && !mDNSPlatformValidRecordForInterface(rr, intf)) 1690 if (intf && !mDNSPlatformValidRecordForInterface(rr, intf))
1693 { 1691 {
1694 LogInfo("SendDelayedUnicastResponse: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, InterfaceID)); 1692 LogInfo("SendDelayedUnicastResponse: Not sending %s, on %s", ARDisplayString(m, rr), InterfaceNameForID(m, InterfaceID));
1695 continue; 1693 continue;
1696 } 1694 }
1697 1695
1698 if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo 1696 if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo
1699 { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; } 1697 { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; }
1700 } 1698 }
@@ -3503,2008 +3501,2008 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRe @@ -3503,2008 +3501,2008 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRe
3503 } 3501 }
3504 3502
3505// CacheRecordAdd is only called from CreateNewCacheEntry, *never* directly as a result of a client API call. 3503// CacheRecordAdd is only called from CreateNewCacheEntry, *never* directly as a result of a client API call.
3506// If new questions are created as a result of invoking client callbacks, they will be added to 3504// If new questions are created as a result of invoking client callbacks, they will be added to
3507// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 3505// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3508// rr is a new CacheRecord just received into our cache 3506// rr is a new CacheRecord just received into our cache
3509// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). 3507// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3510// Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 3508// Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3511// which may change the record list and/or question list. 3509// which may change the record list and/or question list.
3512// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 3510// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3513mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) 3511mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
3514 { 3512 {
3515 DNSQuestion *q; 3513 DNSQuestion *q;
3516 3514
3517 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers 3515 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers
3518 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion(). 3516 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
3519 for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 3517 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
3520 { 3518 {
3521 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 3519 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3522 { 3520 {
3523 // If this question is one that's actively sending queries, and it's received ten answers within one 3521 // If this question is one that's actively sending queries, and it's received ten answers within one
3524 // second of sending the last query packet, then that indicates some radical network topology change, 3522 // second of sending the last query packet, then that indicates some radical network topology change,
3525 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval 3523 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
3526 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating 3524 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
3527 // because we will anyway send another query within a few seconds. The first reset query is sent out 3525 // because we will anyway send another query within a few seconds. The first reset query is sent out
3528 // randomized over the next four seconds to reduce possible synchronization between machines. 3526 // randomized over the next four seconds to reduce possible synchronization between machines.
3529 if (q->LastAnswerPktNum != m->PktNum) 3527 if (q->LastAnswerPktNum != m->PktNum)
3530 { 3528 {
3531 q->LastAnswerPktNum = m->PktNum; 3529 q->LastAnswerPktNum = m->PktNum;
3532 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 && 3530 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
3533 q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond) 3531 q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
3534 { 3532 {
3535 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)", 3533 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)",
3536 q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval); 3534 q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval);
3537 q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4); 3535 q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
3538 q->ThisQInterval = InitialQuestionInterval; 3536 q->ThisQInterval = InitialQuestionInterval;
3539 SetNextQueryTime(m,q); 3537 SetNextQueryTime(m,q);
3540 } 3538 }
3541 } 3539 }
3542 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c, 3540 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c,
3543 DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ? 3541 DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ?
3544 &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ? 3542 &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ?
3545 rr->resrec.rDNSServer->port : zeroIPPort), q); 3543 rr->resrec.rDNSServer->port : zeroIPPort), q);
3546 q->CurrentAnswers++; 3544 q->CurrentAnswers++;
3547 q->unansweredQueries = 0; 3545 q->unansweredQueries = 0;
3548 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 3546 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
3549 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 3547 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
3550 if (q->CurrentAnswers > 4000) 3548 if (q->CurrentAnswers > 4000)
3551 { 3549 {
3552 static int msgcount = 0; 3550 static int msgcount = 0;
3553 if (msgcount++ < 10) 3551 if (msgcount++ < 10)
3554 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack", 3552 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
3555 q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers); 3553 q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
3556 rr->resrec.rroriginalttl = 0; 3554 rr->resrec.rroriginalttl = 0;
3557 rr->UnansweredQueries = MaxUnansweredQueries; 3555 rr->UnansweredQueries = MaxUnansweredQueries;
3558 } 3556 }
3559 } 3557 }
3560 } 3558 }
3561 3559
3562 if (!rr->DelayDelivery) 3560 if (!rr->DelayDelivery)
3563 { 3561 {
3564 if (m->CurrentQuestion) 3562 if (m->CurrentQuestion)
3565 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 3563 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3566 m->CurrentQuestion = m->Questions; 3564 m->CurrentQuestion = m->Questions;
3567 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 3565 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3568 { 3566 {
3569 q = m->CurrentQuestion; 3567 q = m->CurrentQuestion;
3570 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 3568 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3571 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 3569 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
3572 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 3570 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3573 m->CurrentQuestion = q->next; 3571 m->CurrentQuestion = q->next;
3574 } 3572 }
3575 m->CurrentQuestion = mDNSNULL; 3573 m->CurrentQuestion = mDNSNULL;
3576 } 3574 }
3577 3575
3578 SetNextCacheCheckTimeForRecord(m, rr); 3576 SetNextCacheCheckTimeForRecord(m, rr);
3579 } 3577 }
3580 3578
3581// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. 3579// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
3582// If new questions are created as a result of invoking client callbacks, they will be added to 3580// If new questions are created as a result of invoking client callbacks, they will be added to
3583// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 3581// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3584// rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique) 3582// rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
3585// but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any 3583// but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
3586// way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists, 3584// way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
3587// so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network. 3585// so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
3588// Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 3586// Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3589// which may change the record list and/or question list. 3587// which may change the record list and/or question list.
3590// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 3588// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3591mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) 3589mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
3592 { 3590 {
3593 LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c); 3591 LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
3594 if (m->CurrentQuestion) 3592 if (m->CurrentQuestion)
3595 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 3593 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3596 m->CurrentQuestion = m->Questions; 3594 m->CurrentQuestion = m->Questions;
3597 // We do this for *all* questions, not stopping when we get to m->NewQuestions, 3595 // We do this for *all* questions, not stopping when we get to m->NewQuestions,
3598 // since we're not caching the record and we'll get no opportunity to do this later 3596 // since we're not caching the record and we'll get no opportunity to do this later
3599 while (m->CurrentQuestion) 3597 while (m->CurrentQuestion)
3600 { 3598 {
3601 DNSQuestion *q = m->CurrentQuestion; 3599 DNSQuestion *q = m->CurrentQuestion;
3602 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 3600 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3603 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this" 3601 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this"
3604 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 3602 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3605 m->CurrentQuestion = q->next; 3603 m->CurrentQuestion = q->next;
3606 } 3604 }
3607 m->CurrentQuestion = mDNSNULL; 3605 m->CurrentQuestion = mDNSNULL;
3608 } 3606 }
3609 3607
3610// CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute. 3608// CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute.
3611// Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question. 3609// Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
3612// If new questions are created as a result of invoking client callbacks, they will be added to 3610// If new questions are created as a result of invoking client callbacks, they will be added to
3613// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 3611// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3614// rr is an existing cache CacheRecord that just expired and is being deleted 3612// rr is an existing cache CacheRecord that just expired and is being deleted
3615// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). 3613// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3616// Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 3614// Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3617// which may change the record list and/or question list. 3615// which may change the record list and/or question list.
3618// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 3616// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3619mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) 3617mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
3620 { 3618 {
3621 if (m->CurrentQuestion) 3619 if (m->CurrentQuestion)
3622 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", 3620 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)",
3623 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 3621 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3624 m->CurrentQuestion = m->Questions; 3622 m->CurrentQuestion = m->Questions;
3625 3623
3626 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters 3624 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
3627 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them. 3625 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them.
3628 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 3626 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3629 { 3627 {
3630 DNSQuestion *q = m->CurrentQuestion; 3628 DNSQuestion *q = m->CurrentQuestion;
3631 // When a question enters suppressed state, we generate RMV events and generate a negative 3629 // When a question enters suppressed state, we generate RMV events and generate a negative
3632 // response. A cache may be present that answers this question e.g., cache entry generated 3630 // response. A cache may be present that answers this question e.g., cache entry generated
3633 // before the question became suppressed. We need to skip the suppressed questions here as 3631 // before the question became suppressed. We need to skip the suppressed questions here as
3634 // the RMV event has already been generated. 3632 // the RMV event has already been generated.
3635 if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) 3633 if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
3636 { 3634 {
3637 verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); 3635 verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
3638 q->FlappingInterface1 = mDNSNULL; 3636 q->FlappingInterface1 = mDNSNULL;
3639 q->FlappingInterface2 = mDNSNULL; 3637 q->FlappingInterface2 = mDNSNULL;
3640  3638
3641 // When a question changes DNS server, it is marked with deliverAddEvents if we find any 3639 // When a question changes DNS server, it is marked with deliverAddEvents if we find any
3642 // cache entry corresponding to the new DNS server. Before we deliver the ADD event, the 3640 // cache entry corresponding to the new DNS server. Before we deliver the ADD event, the
3643 // cache entry may be removed in which case CurrentAnswers can be zero. 3641 // cache entry may be removed in which case CurrentAnswers can be zero.
3644 if (q->deliverAddEvents && !q->CurrentAnswers) 3642 if (q->deliverAddEvents && !q->CurrentAnswers)
3645 { 3643 {
3646 LogInfo("CacheRecordRmv: Question %p %##s (%s) deliverAddEvents set, DNSServer %#a:%d", 3644 LogInfo("CacheRecordRmv: Question %p %##s (%s) deliverAddEvents set, DNSServer %#a:%d",
3647 q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, 3645 q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL,
3648 mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort)); 3646 mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort));
3649 m->CurrentQuestion = q->next; 3647 m->CurrentQuestion = q->next;
3650 continue; 3648 continue;
3651 } 3649 }
3652 if (q->CurrentAnswers == 0) 3650 if (q->CurrentAnswers == 0)
3653 LogMsg("CacheRecordRmv ERROR!!: How can CurrentAnswers already be zero for %p %##s (%s) DNSServer %#a:%d", 3651 LogMsg("CacheRecordRmv ERROR!!: How can CurrentAnswers already be zero for %p %##s (%s) DNSServer %#a:%d",
3654 q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, 3652 q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL,
3655 mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort)); 3653 mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort));
3656 else 3654 else
3657 { 3655 {
3658 q->CurrentAnswers--; 3656 q->CurrentAnswers--;
3659 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--; 3657 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
3660 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--; 3658 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
3661 } 3659 }
3662 if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results 3660 if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
3663 { 3661 {
3664 if (q->CurrentAnswers == 0) 3662 if (q->CurrentAnswers == 0)
3665 { 3663 {
3666 LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents", 3664 LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
3667 q->qname.c, DNSTypeName(q->qtype)); 3665 q->qname.c, DNSTypeName(q->qtype));
3668 ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); 3666 ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
3669 } 3667 }
3670 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv); 3668 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
3671 } 3669 }
3672 } 3670 }
3673 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 3671 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3674 m->CurrentQuestion = q->next; 3672 m->CurrentQuestion = q->next;
3675 } 3673 }
3676 m->CurrentQuestion = mDNSNULL; 3674 m->CurrentQuestion = mDNSNULL;
3677 } 3675 }
3678 3676
3679mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e) 3677mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
3680 { 3678 {
3681#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 3679#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
3682 unsigned int i; 3680 unsigned int i;
3683 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; 3681 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
3684#endif 3682#endif
3685 e->next = m->rrcache_free; 3683 e->next = m->rrcache_free;
3686 m->rrcache_free = e; 3684 m->rrcache_free = e;
3687 m->rrcache_totalused--; 3685 m->rrcache_totalused--;
3688 } 3686 }
3689 3687
3690mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp) 3688mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
3691 { 3689 {
3692 CacheEntity *e = (CacheEntity *)(*cp); 3690 CacheEntity *e = (CacheEntity *)(*cp);
3693 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c); 3691 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
3694 if ((*cp)->rrcache_tail != &(*cp)->members) 3692 if ((*cp)->rrcache_tail != &(*cp)->members)
3695 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); 3693 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
3696 //if ((*cp)->name != (domainname*)((*cp)->namestorage)) 3694 //if ((*cp)->name != (domainname*)((*cp)->namestorage))
3697 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); 3695 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
3698 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); 3696 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
3699 (*cp)->name = mDNSNULL; 3697 (*cp)->name = mDNSNULL;
3700 *cp = (*cp)->next; // Cut record from list 3698 *cp = (*cp)->next; // Cut record from list
3701 ReleaseCacheEntity(m, e); 3699 ReleaseCacheEntity(m, e);
3702 } 3700 }
3703 3701
3704mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) 3702mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
3705 { 3703 {
3706 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r)); 3704 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
3707 if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata); 3705 if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
3708 r->resrec.rdata = mDNSNULL; 3706 r->resrec.rdata = mDNSNULL;
3709 ReleaseCacheEntity(m, (CacheEntity *)r); 3707 ReleaseCacheEntity(m, (CacheEntity *)r);
3710 } 3708 }
3711 3709
3712// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering 3710// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
3713// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all 3711// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
3714// callbacks for old records are delivered before callbacks for newer records. 3712// callbacks for old records are delivered before callbacks for newer records.
3715mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGroup *const cg) 3713mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGroup *const cg)
3716 { 3714 {
3717 CacheRecord **rp = &cg->members; 3715 CacheRecord **rp = &cg->members;
3718 3716
3719 if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; } 3717 if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
3720 m->lock_rrcache = 1; 3718 m->lock_rrcache = 1;
3721 3719
3722 while (*rp) 3720 while (*rp)
3723 { 3721 {
3724 CacheRecord *const rr = *rp; 3722 CacheRecord *const rr = *rp;
3725 mDNSs32 event = RRExpireTime(rr); 3723 mDNSs32 event = RRExpireTime(rr);
3726 if (m->timenow - event >= 0) // If expired, delete it 3724 if (m->timenow - event >= 0) // If expired, delete it
3727 { 3725 {
3728 *rp = rr->next; // Cut it from the list 3726 *rp = rr->next; // Cut it from the list
3729 verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s", 3727 verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s",
3730 m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); 3728 m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
3731 if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away 3729 if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away
3732 { 3730 {
3733 DNSQuestion *q = rr->CRActiveQuestion; 3731 DNSQuestion *q = rr->CRActiveQuestion;
3734 // When a cache record is about to expire, we expect to do four queries at 80-82%, 85-87%, 90-92% and 3732 // When a cache record is about to expire, we expect to do four queries at 80-82%, 85-87%, 90-92% and
3735 // then 95-97% of the TTL. If the DNS server does not respond, then we will remove the cache entry 3733 // then 95-97% of the TTL. If the DNS server does not respond, then we will remove the cache entry
3736 // before we pick a new DNS server. As the question interval is set to MaxQuestionInterval, we may 3734 // before we pick a new DNS server. As the question interval is set to MaxQuestionInterval, we may
3737 // not send out a query anytime soon. Hence, we need to reset the question interval. If this is 3735 // not send out a query anytime soon. Hence, we need to reset the question interval. If this is
3738 // a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to 3736 // a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to
3739 // MaxQuestionInterval. If we have inactive questions referring to negative cache entries, 3737 // MaxQuestionInterval. If we have inactive questions referring to negative cache entries,
3740 // don't ressurect them as they will deliver duplicate "No such Record" ADD events 3738 // don't ressurect them as they will deliver duplicate "No such Record" ADD events
3741 if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q)) 3739 if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q))
3742 { 3740 {
3743 q->ThisQInterval = InitialQuestionInterval; 3741 q->ThisQInterval = InitialQuestionInterval;
3744 q->LastQTime = m->timenow - q->ThisQInterval; 3742 q->LastQTime = m->timenow - q->ThisQInterval;
3745 SetNextQueryTime(m, q); 3743 SetNextQueryTime(m, q);
3746 } 3744 }
3747 CacheRecordRmv(m, rr); 3745 CacheRecordRmv(m, rr);
3748 m->rrcache_active--; 3746 m->rrcache_active--;
3749 } 3747 }
3750 ReleaseCacheRecord(m, rr); 3748 ReleaseCacheRecord(m, rr);
3751 } 3749 }
3752 else // else, not expired; see if we need to query 3750 else // else, not expired; see if we need to query
3753 { 3751 {
3754 // If waiting to delay delivery, do nothing until then 3752 // If waiting to delay delivery, do nothing until then
3755 if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0) 3753 if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
3756 event = rr->DelayDelivery; 3754 event = rr->DelayDelivery;
3757 else 3755 else
3758 { 3756 {
3759 if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr); 3757 if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr);
3760 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 3758 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3761 { 3759 {
3762 if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query 3760 if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query
3763 event = NextCacheCheckEvent(rr); // then just record when we want the next query 3761 event = NextCacheCheckEvent(rr); // then just record when we want the next query
3764 else // else trigger our question to go out now 3762 else // else trigger our question to go out now
3765 { 3763 {
3766 // Set NextScheduledQuery to timenow so that SendQueries() will run. 3764 // Set NextScheduledQuery to timenow so that SendQueries() will run.
3767 // SendQueries() will see that we have records close to expiration, and send FEQs for them. 3765 // SendQueries() will see that we have records close to expiration, and send FEQs for them.
3768 m->NextScheduledQuery = m->timenow; 3766 m->NextScheduledQuery = m->timenow;
3769 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(), 3767 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(),
3770 // which will correctly update m->NextCacheCheck for us. 3768 // which will correctly update m->NextCacheCheck for us.
3771 event = m->timenow + 0x3FFFFFFF; 3769 event = m->timenow + 0x3FFFFFFF;
3772 } 3770 }
3773 } 3771 }
3774 } 3772 }
3775 verbosedebugf("CheckCacheExpiration:%6d %5d %s", 3773 verbosedebugf("CheckCacheExpiration:%6d %5d %s",
3776 (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr)); 3774 (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
3777 if (m->rrcache_nextcheck[slot] - event > 0) 3775 if (m->rrcache_nextcheck[slot] - event > 0)
3778 m->rrcache_nextcheck[slot] = event; 3776 m->rrcache_nextcheck[slot] = event;
3779 rp = &rr->next; 3777 rp = &rr->next;
3780 } 3778 }
3781 } 3779 }
3782 if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp); 3780 if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp);
3783 cg->rrcache_tail = rp; 3781 cg->rrcache_tail = rp;
3784 m->lock_rrcache = 0; 3782 m->lock_rrcache = 0;
3785 } 3783 }
3786 3784
3787mDNSlocal void AnswerNewQuestion(mDNS *const m) 3785mDNSlocal void AnswerNewQuestion(mDNS *const m)
3788 { 3786 {
3789 mDNSBool ShouldQueryImmediately = mDNStrue; 3787 mDNSBool ShouldQueryImmediately = mDNStrue;
3790 DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer 3788 DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer
3791 mDNSu32 slot = HashSlot(&q->qname); 3789 mDNSu32 slot = HashSlot(&q->qname);
3792 CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 3790 CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3793 AuthRecord *lr; 3791 AuthRecord *lr;
3794 AuthGroup *ag; 3792 AuthGroup *ag;
3795 mDNSBool AnsweredFromCache = mDNSfalse; 3793 mDNSBool AnsweredFromCache = mDNSfalse;
3796 3794
3797 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 3795 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3798 3796
3799 if (cg) CheckCacheExpiration(m, slot, cg); 3797 if (cg) CheckCacheExpiration(m, slot, cg);
3800 if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; } 3798 if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; }
3801 m->NewQuestions = q->next; 3799 m->NewQuestions = q->next;
3802 // Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first 3800 // Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first
3803 // then CheckCacheExpiration may give this question add/remove callbacks, and it's not yet ready for that. 3801 // then CheckCacheExpiration may give this question add/remove callbacks, and it's not yet ready for that.
3804 // 3802 //
3805 // Also, CheckCacheExpiration() calls CacheRecordDeferredAdd() and CacheRecordRmv(), which invoke 3803 // Also, CheckCacheExpiration() calls CacheRecordDeferredAdd() and CacheRecordRmv(), which invoke
3806 // client callbacks, which may delete their own or any other question. Our mechanism for detecting 3804 // client callbacks, which may delete their own or any other question. Our mechanism for detecting
3807 // whether our current m->NewQuestions question got deleted by one of these callbacks is to store the 3805 // whether our current m->NewQuestions question got deleted by one of these callbacks is to store the
3808 // value of m->NewQuestions in 'q' before calling CheckCacheExpiration(), and then verify afterwards 3806 // value of m->NewQuestions in 'q' before calling CheckCacheExpiration(), and then verify afterwards
3809 // that they're still the same. If m->NewQuestions has changed (because mDNS_StopQuery_internal 3807 // that they're still the same. If m->NewQuestions has changed (because mDNS_StopQuery_internal
3810 // advanced it), that means the question was deleted, so we no longer need to worry about answering 3808 // advanced it), that means the question was deleted, so we no longer need to worry about answering
3811 // it (and indeed 'q' is now a dangling pointer, so dereferencing it at all would be bad, and the 3809 // it (and indeed 'q' is now a dangling pointer, so dereferencing it at all would be bad, and the
3812 // values we computed for slot and cg are now stale and relate to a question that no longer exists). 3810 // values we computed for slot and cg are now stale and relate to a question that no longer exists).
3813 // 3811 //
3814 // We can't use the usual m->CurrentQuestion mechanism for this because CacheRecordDeferredAdd() and 3812 // We can't use the usual m->CurrentQuestion mechanism for this because CacheRecordDeferredAdd() and
3815 // CacheRecordRmv() both use that themselves when walking the list of (non-new) questions generating callbacks. 3813 // CacheRecordRmv() both use that themselves when walking the list of (non-new) questions generating callbacks.
3816 // Fortunately mDNS_StopQuery_internal auto-advances both m->CurrentQuestion *AND* m->NewQuestions when 3814 // Fortunately mDNS_StopQuery_internal auto-advances both m->CurrentQuestion *AND* m->NewQuestions when
3817 // deleting a question, so luckily we have an easy alternative way of detecting if our question got deleted. 3815 // deleting a question, so luckily we have an easy alternative way of detecting if our question got deleted.
3818  3816
3819 if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!"); 3817 if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
3820 // This should be safe, because calling the client's question callback may cause the 3818 // This should be safe, because calling the client's question callback may cause the
3821 // question list to be modified, but should not ever cause the rrcache list to be modified. 3819 // question list to be modified, but should not ever cause the rrcache list to be modified.
3822 // If the client's question callback deletes the question, then m->CurrentQuestion will 3820 // If the client's question callback deletes the question, then m->CurrentQuestion will
3823 // be advanced, and we'll exit out of the loop 3821 // be advanced, and we'll exit out of the loop
3824 m->lock_rrcache = 1; 3822 m->lock_rrcache = 1;
3825 if (m->CurrentQuestion) 3823 if (m->CurrentQuestion)
3826 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", 3824 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)",
3827 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 3825 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3828 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted 3826 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
3829 3827
3830 if (q->NoAnswer == NoAnswer_Fail) 3828 if (q->NoAnswer == NoAnswer_Fail)
3831 { 3829 {
3832 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 3830 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3833 MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer); 3831 MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer);
3834 q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression 3832 q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression
3835 AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); 3833 AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
3836 // Don't touch the question if it has been stopped already 3834 // Don't touch the question if it has been stopped already
3837 if (m->CurrentQuestion == q) q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state 3835 if (m->CurrentQuestion == q) q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state
3838 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 3836 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
3839 } 3837 }
3840 if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while generating NoAnswer_Fail response"); goto exit; } 3838 if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while generating NoAnswer_Fail response"); goto exit; }
3841 3839
3842 // See if we want to tell it about LocalOnly records 3840 // See if we want to tell it about LocalOnly records
3843 if (m->CurrentRecord) 3841 if (m->CurrentRecord)
3844 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 3842 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3845 slot = AuthHashSlot(&q->qname); 3843 slot = AuthHashSlot(&q->qname);
3846 ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); 3844 ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname);
3847 if (ag) 3845 if (ag)
3848 { 3846 {
3849 m->CurrentRecord = ag->members; 3847 m->CurrentRecord = ag->members;
3850 while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords) 3848 while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords)
3851 { 3849 {
3852 AuthRecord *rr = m->CurrentRecord; 3850 AuthRecord *rr = m->CurrentRecord;
3853 m->CurrentRecord = rr->next; 3851 m->CurrentRecord = rr->next;
3854 // 3852 //
3855 // If the question is mDNSInterface_LocalOnly, all records local to the machine should be used 3853 // If the question is mDNSInterface_LocalOnly, all records local to the machine should be used
3856 // to answer the query. This is handled in AnswerNewLocalOnlyQuestion. 3854 // to answer the query. This is handled in AnswerNewLocalOnlyQuestion.
3857 // 3855 //
3858 // We handle mDNSInterface_Any and scoped questions here. See LocalOnlyRecordAnswersQuestion for more 3856 // We handle mDNSInterface_Any and scoped questions here. See LocalOnlyRecordAnswersQuestion for more
3859 // details on how we handle this case. For P2P we just handle "Interface_Any" questions. For LocalOnly 3857 // details on how we handle this case. For P2P we just handle "Interface_Any" questions. For LocalOnly
3860 // we handle both mDNSInterface_Any and scoped questions. 3858 // we handle both mDNSInterface_Any and scoped questions.
3861 3859
3862 if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && q->InterfaceID == mDNSInterface_Any)) 3860 if (rr->ARType == AuthRecordLocalOnly || (rr->ARType == AuthRecordP2P && q->InterfaceID == mDNSInterface_Any))
3863 if (LocalOnlyRecordAnswersQuestion(rr, q)) 3861 if (LocalOnlyRecordAnswersQuestion(rr, q))
3864 { 3862 {
3865 AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); 3863 AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
3866 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 3864 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
3867 } 3865 }
3868 } 3866 }
3869 } 3867 }
3870 m->CurrentRecord = mDNSNULL; 3868 m->CurrentRecord = mDNSNULL;
3871  3869
3872 if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while while giving LocalOnly record answers"); goto exit; } 3870 if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while while giving LocalOnly record answers"); goto exit; }
3873 3871
3874 if (q->LOAddressAnswers) 3872 if (q->LOAddressAnswers)
3875 { 3873 {
3876 LogInfo("AnswerNewQuestion: Question %p %##s (%s) answered using local auth records LOAddressAnswers %d", 3874 LogInfo("AnswerNewQuestion: Question %p %##s (%s) answered using local auth records LOAddressAnswers %d",
3877 q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers); 3875 q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers);
3878 goto exit; 3876 goto exit;
3879 } 3877 }
3880 3878
3881 // Before we go check the cache and ship this query on the wire, we have to be sure that there are 3879 // Before we go check the cache and ship this query on the wire, we have to be sure that there are
3882 // no local records that could possibly answer this question. As we did not check the NewLocalRecords, we 3880 // no local records that could possibly answer this question. As we did not check the NewLocalRecords, we
3883 // need to just peek at them to see whether it will answer this question. If it would answer, pretend 3881 // need to just peek at them to see whether it will answer this question. If it would answer, pretend
3884 // that we answered. AnswerAllLocalQuestionsWithLocalAuthRecord will answer shortly. This happens normally 3882 // that we answered. AnswerAllLocalQuestionsWithLocalAuthRecord will answer shortly. This happens normally
3885 // when we add new /etc/hosts entries and restart the question. It is a new question and also a new record. 3883 // when we add new /etc/hosts entries and restart the question. It is a new question and also a new record.
3886 if (ag) 3884 if (ag)
3887 { 3885 {
3888 lr = ag->NewLocalOnlyRecords; 3886 lr = ag->NewLocalOnlyRecords;
3889 while (lr) 3887 while (lr)
3890 { 3888 {
3891 if (LORecordAnswersAddressType(lr) && LocalOnlyRecordAnswersQuestion(lr, q)) 3889 if (LORecordAnswersAddressType(lr) && LocalOnlyRecordAnswersQuestion(lr, q))
3892 { 3890 {
3893 LogInfo("AnswerNewQuestion: Question %p %##s (%s) will be answered using new local auth records " 3891 LogInfo("AnswerNewQuestion: Question %p %##s (%s) will be answered using new local auth records "
3894 " LOAddressAnswers %d", q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers); 3892 " LOAddressAnswers %d", q, q->qname.c, DNSTypeName(q->qtype), q->LOAddressAnswers);
3895 goto exit; 3893 goto exit;
3896 } 3894 }
3897 lr = lr->next; 3895 lr = lr->next;
3898 } 3896 }
3899 } 3897 }
3900  3898
3901 3899
3902 // If we are not supposed to answer this question, generate a negative response. 3900 // If we are not supposed to answer this question, generate a negative response.
3903 // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question 3901 // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question
3904 if (QuerySuppressed(q)) { q->SuppressQuery = mDNSfalse; GenerateNegativeResponse(m); q->SuppressQuery = mDNStrue; } 3902 if (QuerySuppressed(q)) { q->SuppressQuery = mDNSfalse; GenerateNegativeResponse(m); q->SuppressQuery = mDNStrue; }
3905 else 3903 else
3906 { 3904 {
3907 CacheRecord *rr; 3905 CacheRecord *rr;
3908 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 3906 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3909 if (SameNameRecordAnswersQuestion(&rr->resrec, q)) 3907 if (SameNameRecordAnswersQuestion(&rr->resrec, q))
3910 { 3908 {
3911 // SecsSinceRcvd is whole number of elapsed seconds, rounded down 3909 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
3912 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; 3910 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
3913 if (rr->resrec.rroriginalttl <= SecsSinceRcvd) 3911 if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
3914 { 3912 {
3915 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d", 3913 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d",
3916 rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd); 3914 rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd);
3917 continue; // Go to next one in loop 3915 continue; // Go to next one in loop
3918 } 3916 }
3919  3917
3920 // If this record set is marked unique, then that means we can reasonably assume we have the whole set 3918 // If this record set is marked unique, then that means we can reasonably assume we have the whole set
3921 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there 3919 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
3922 if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique)) 3920 if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
3923 ShouldQueryImmediately = mDNSfalse; 3921 ShouldQueryImmediately = mDNSfalse;
3924 q->CurrentAnswers++; 3922 q->CurrentAnswers++;
3925 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 3923 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
3926 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 3924 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
3927 AnsweredFromCache = mDNStrue; 3925 AnsweredFromCache = mDNStrue;
3928 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 3926 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
3929 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 3927 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
3930 } 3928 }
3931 else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) 3929 else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
3932 ShouldQueryImmediately = mDNSfalse; 3930 ShouldQueryImmediately = mDNSfalse;
3933 } 3931 }
3934 // We don't use LogInfo for this "Question deleted" message because it happens so routinely that 3932 // We don't use LogInfo for this "Question deleted" message because it happens so routinely that
3935 // it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs. 3933 // it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs.
3936 if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; } 3934 if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; }
3937 3935
3938 // Neither a local record nor a cache entry could answer this question. If this question need to be retried 3936 // Neither a local record nor a cache entry could answer this question. If this question need to be retried
3939 // with search domains, generate a negative response which will now retry after appending search domains. 3937 // with search domains, generate a negative response which will now retry after appending search domains.
3940 // If the query was suppressed above, we already generated a negative response. When it gets unsuppressed, 3938 // If the query was suppressed above, we already generated a negative response. When it gets unsuppressed,
3941 // we will retry with search domains. 3939 // we will retry with search domains.
3942 if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains) 3940 if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains)
3943 { 3941 {
3944 LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 3942 LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3945 GenerateNegativeResponse(m); 3943 GenerateNegativeResponse(m);
3946 } 3944 }
3947 3945
3948 if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; } 3946 if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; }
3949 3947
3950 // Note: When a query gets suppressed or retried with search domains, we de-activate the question. 3948 // Note: When a query gets suppressed or retried with search domains, we de-activate the question.
3951 // Hence we don't execute the following block of code for those cases. 3949 // Hence we don't execute the following block of code for those cases.
3952 if (ShouldQueryImmediately && ActiveQuestion(q)) 3950 if (ShouldQueryImmediately && ActiveQuestion(q))
3953 { 3951 {
3954 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 3952 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3955 q->ThisQInterval = InitialQuestionInterval; 3953 q->ThisQInterval = InitialQuestionInterval;
3956 q->LastQTime = m->timenow - q->ThisQInterval; 3954 q->LastQTime = m->timenow - q->ThisQInterval;
3957 if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries 3955 if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries
3958 { 3956 {
3959 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms 3957 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
3960 if (!m->RandomQueryDelay) 3958 if (!m->RandomQueryDelay)
3961 m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1; 3959 m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1;
3962 q->LastQTime += m->RandomQueryDelay; 3960 q->LastQTime += m->RandomQueryDelay;
3963 } 3961 }
3964 } 3962 }
3965 3963
3966 // IN ALL CASES make sure that m->NextScheduledQuery is set appropriately. 3964 // IN ALL CASES make sure that m->NextScheduledQuery is set appropriately.
3967 // In cases where m->NewQuestions->DelayAnswering is set, we may have delayed generating our 3965 // In cases where m->NewQuestions->DelayAnswering is set, we may have delayed generating our
3968 // answers for this question until *after* its scheduled transmission time, in which case 3966 // answers for this question until *after* its scheduled transmission time, in which case
3969 // m->NextScheduledQuery may now be set to 'never', and in that case -- even though we're *not* doing 3967 // m->NextScheduledQuery may now be set to 'never', and in that case -- even though we're *not* doing
3970 // ShouldQueryImmediately -- we still need to make sure we set m->NextScheduledQuery correctly. 3968 // ShouldQueryImmediately -- we still need to make sure we set m->NextScheduledQuery correctly.
3971 SetNextQueryTime(m,q); 3969 SetNextQueryTime(m,q);
3972 3970
3973exit: 3971exit:
3974 m->CurrentQuestion = mDNSNULL; 3972 m->CurrentQuestion = mDNSNULL;
3975 m->lock_rrcache = 0; 3973 m->lock_rrcache = 0;
3976 } 3974 }
3977 3975
3978// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any 3976// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
3979// appropriate answers, stopping if it reaches a NewLocalOnlyRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord 3977// appropriate answers, stopping if it reaches a NewLocalOnlyRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord
3980mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) 3978mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
3981 { 3979 {
3982 mDNSu32 slot; 3980 mDNSu32 slot;
3983 AuthGroup *ag; 3981 AuthGroup *ag;
3984 DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer 3982 DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer
3985 m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any) 3983 m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any)
3986 3984
3987 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 3985 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3988 3986
3989 if (m->CurrentQuestion) 3987 if (m->CurrentQuestion)
3990 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", 3988 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)",
3991 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 3989 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3992 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted 3990 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
3993 3991
3994 if (m->CurrentRecord) 3992 if (m->CurrentRecord)
3995 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 3993 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3996 3994
3997 // 1. First walk the LocalOnly records answering the LocalOnly question 3995 // 1. First walk the LocalOnly records answering the LocalOnly question
3998 // 2. As LocalOnly questions should also be answered by any other Auth records local to the machine, 3996 // 2. As LocalOnly questions should also be answered by any other Auth records local to the machine,
3999 // walk the ResourceRecords list delivering the answers 3997 // walk the ResourceRecords list delivering the answers
4000 slot = AuthHashSlot(&q->qname); 3998 slot = AuthHashSlot(&q->qname);
4001 ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); 3999 ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname);
4002 if (ag) 4000 if (ag)
4003 { 4001 {
4004 m->CurrentRecord = ag->members; 4002 m->CurrentRecord = ag->members;
4005 while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords) 4003 while (m->CurrentRecord && m->CurrentRecord != ag->NewLocalOnlyRecords)
4006 { 4004 {
4007 AuthRecord *rr = m->CurrentRecord; 4005 AuthRecord *rr = m->CurrentRecord;
4008 m->CurrentRecord = rr->next; 4006 m->CurrentRecord = rr->next;
4009 if (LocalOnlyRecordAnswersQuestion(rr, q)) 4007 if (LocalOnlyRecordAnswersQuestion(rr, q))
4010 { 4008 {
4011 AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); 4009 AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
4012 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 4010 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
4013 } 4011 }
4014 } 4012 }
4015 } 4013 }
4016 4014
4017 if (m->CurrentQuestion == q) 4015 if (m->CurrentQuestion == q)
4018 { 4016 {
4019 m->CurrentRecord = m->ResourceRecords; 4017 m->CurrentRecord = m->ResourceRecords;
4020 4018
4021 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) 4019 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4022 { 4020 {
4023 AuthRecord *rr = m->CurrentRecord; 4021 AuthRecord *rr = m->CurrentRecord;
4024 m->CurrentRecord = rr->next; 4022 m->CurrentRecord = rr->next;
4025 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4023 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4026 { 4024 {
4027 AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue); 4025 AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
4028 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 4026 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
4029 } 4027 }
4030 } 4028 }
4031 } 4029 }
4032 4030
4033 m->CurrentQuestion = mDNSNULL; 4031 m->CurrentQuestion = mDNSNULL;
4034 m->CurrentRecord = mDNSNULL; 4032 m->CurrentRecord = mDNSNULL;
4035 } 4033 }
4036 4034
4037mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG) 4035mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG)
4038 { 4036 {
4039 CacheEntity *e = mDNSNULL; 4037 CacheEntity *e = mDNSNULL;
4040 4038
4041 if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } 4039 if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
4042 m->lock_rrcache = 1; 4040 m->lock_rrcache = 1;
4043  4041
4044 // If we have no free records, ask the client layer to give us some more memory 4042 // If we have no free records, ask the client layer to give us some more memory
4045 if (!m->rrcache_free && m->MainCallback) 4043 if (!m->rrcache_free && m->MainCallback)
4046 { 4044 {
4047 if (m->rrcache_totalused != m->rrcache_size) 4045 if (m->rrcache_totalused != m->rrcache_size)
4048 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu", 4046 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4049 m->rrcache_totalused, m->rrcache_size); 4047 m->rrcache_totalused, m->rrcache_size);
4050  4048
4051 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite 4049 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4052 // number of bogus records so that we keep growing our cache until the machine runs out of memory. 4050 // number of bogus records so that we keep growing our cache until the machine runs out of memory.
4053 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each), 4051 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
4054 // and we're actively using less than 1/32 of that cache, then we purge all the unused records 4052 // and we're actively using less than 1/32 of that cache, then we purge all the unused records
4055 // and recycle them, instead of allocating more memory. 4053 // and recycle them, instead of allocating more memory.
4056 if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active) 4054 if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active)
4057 LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", 4055 LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4058 m->rrcache_size, m->rrcache_active); 4056 m->rrcache_size, m->rrcache_active);
4059 else 4057 else
4060 { 4058 {
4061 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 4059 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4062 m->MainCallback(m, mStatus_GrowCache); 4060 m->MainCallback(m, mStatus_GrowCache);
4063 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 4061 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4064 } 4062 }
4065 } 4063 }
4066  4064
4067 // If we still have no free records, recycle all the records we can. 4065 // If we still have no free records, recycle all the records we can.
4068 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass. 4066 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4069 if (!m->rrcache_free) 4067 if (!m->rrcache_free)
4070 { 4068 {
4071 mDNSu32 oldtotalused = m->rrcache_totalused; 4069 mDNSu32 oldtotalused = m->rrcache_totalused;
4072 mDNSu32 slot; 4070 mDNSu32 slot;
4073 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 4071 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4074 { 4072 {
4075 CacheGroup **cp = &m->rrcache_hash[slot]; 4073 CacheGroup **cp = &m->rrcache_hash[slot];
4076 while (*cp) 4074 while (*cp)
4077 { 4075 {
4078 CacheRecord **rp = &(*cp)->members; 4076 CacheRecord **rp = &(*cp)->members;
4079 while (*rp) 4077 while (*rp)
4080 { 4078 {
4081 // Records that answer still-active questions are not candidates for recycling 4079 // Records that answer still-active questions are not candidates for recycling
4082 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash 4080 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4083 if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList) 4081 if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList)
4084 rp=&(*rp)->next; 4082 rp=&(*rp)->next;
4085 else 4083 else
4086 { 4084 {
4087 CacheRecord *rr = *rp; 4085 CacheRecord *rr = *rp;
4088 *rp = (*rp)->next; // Cut record from list 4086 *rp = (*rp)->next; // Cut record from list
4089 ReleaseCacheRecord(m, rr); 4087 ReleaseCacheRecord(m, rr);
4090 } 4088 }
4091 } 4089 }
4092 if ((*cp)->rrcache_tail != rp) 4090 if ((*cp)->rrcache_tail != rp)
4093 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp); 4091 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
4094 (*cp)->rrcache_tail = rp; 4092 (*cp)->rrcache_tail = rp;
4095 if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next; 4093 if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
4096 else ReleaseCacheGroup(m, cp); 4094 else ReleaseCacheGroup(m, cp);
4097 } 4095 }
4098 } 4096 }
4099 LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d", 4097 LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
4100 oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused); 4098 oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
4101 } 4099 }
4102 4100
4103 if (m->rrcache_free) // If there are records in the free list, take one 4101 if (m->rrcache_free) // If there are records in the free list, take one
4104 { 4102 {
4105 e = m->rrcache_free; 4103 e = m->rrcache_free;
4106 m->rrcache_free = e->next; 4104 m->rrcache_free = e->next;
4107 if (++m->rrcache_totalused >= m->rrcache_report) 4105 if (++m->rrcache_totalused >= m->rrcache_report)
4108 { 4106 {
4109 LogInfo("RR Cache now using %ld objects", m->rrcache_totalused); 4107 LogInfo("RR Cache now using %ld objects", m->rrcache_totalused);
4110 if (m->rrcache_report < 100) m->rrcache_report += 10; 4108 if (m->rrcache_report < 100) m->rrcache_report += 10;
4111 else if (m->rrcache_report < 1000) m->rrcache_report += 100; 4109 else if (m->rrcache_report < 1000) m->rrcache_report += 100;
4112 else m->rrcache_report += 1000; 4110 else m->rrcache_report += 1000;
4113 } 4111 }
4114 mDNSPlatformMemZero(e, sizeof(*e)); 4112 mDNSPlatformMemZero(e, sizeof(*e));
4115 } 4113 }
4116 4114
4117 m->lock_rrcache = 0; 4115 m->lock_rrcache = 0;
4118 4116
4119 return(e); 4117 return(e);
4120 } 4118 }
4121 4119
4122mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength) 4120mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength)
4123 { 4121 {
4124 CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg); 4122 CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
4125 if (r) 4123 if (r)
4126 { 4124 {
4127 r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage 4125 r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage
4128 if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage 4126 if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage
4129 { 4127 {
4130 r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength); 4128 r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
4131 if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength; 4129 if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
4132 else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; } 4130 else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
4133 } 4131 }
4134 } 4132 }
4135 return(r); 4133 return(r);
4136 } 4134 }
4137 4135
4138mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) 4136mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
4139 { 4137 {
4140 mDNSu16 namelen = DomainNameLength(rr->name); 4138 mDNSu16 namelen = DomainNameLength(rr->name);
4141 CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL); 4139 CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL);
4142 if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } 4140 if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
4143 cg->next = m->rrcache_hash[slot]; 4141 cg->next = m->rrcache_hash[slot];
4144 cg->namehash = rr->namehash; 4142 cg->namehash = rr->namehash;
4145 cg->members = mDNSNULL; 4143 cg->members = mDNSNULL;
4146 cg->rrcache_tail = &cg->members; 4144 cg->rrcache_tail = &cg->members;
4147 cg->name = (domainname*)cg->namestorage; 4145 cg->name = (domainname*)cg->namestorage;
4148 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", 4146 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4149 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c); 4147 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4150 if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen); 4148 if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
4151 if (!cg->name) 4149 if (!cg->name)
4152 { 4150 {
4153 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c); 4151 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c);
4154 ReleaseCacheEntity(m, (CacheEntity*)cg); 4152 ReleaseCacheEntity(m, (CacheEntity*)cg);
4155 return(mDNSNULL); 4153 return(mDNSNULL);
4156 } 4154 }
4157 AssignDomainName(cg->name, rr->name); 4155 AssignDomainName(cg->name, rr->name);
4158 4156
4159 if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c); 4157 if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
4160 m->rrcache_hash[slot] = cg; 4158 m->rrcache_hash[slot] = cg;
4161 if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c); 4159 if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
4162  4160
4163 return(cg); 4161 return(cg);
4164 } 4162 }
4165 4163
4166mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) 4164mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
4167 { 4165 {
4168 if (m->mDNS_busy != m->mDNS_reentrancy+1) 4166 if (m->mDNS_busy != m->mDNS_reentrancy+1)
4169 LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 4167 LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
4170 // Make sure we mark this record as thoroughly expired -- we don't ever want to give 4168 // Make sure we mark this record as thoroughly expired -- we don't ever want to give
4171 // a positive answer using an expired record (e.g. from an interface that has gone away). 4169 // a positive answer using an expired record (e.g. from an interface that has gone away).
4172 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to 4170 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4173 // summary deletion without giving the proper callback to any questions that are monitoring it. 4171 // summary deletion without giving the proper callback to any questions that are monitoring it.
4174 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries. 4172 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4175 rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60; 4173 rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60;
4176 rr->UnansweredQueries = MaxUnansweredQueries; 4174 rr->UnansweredQueries = MaxUnansweredQueries;
4177 rr->resrec.rroriginalttl = 0; 4175 rr->resrec.rroriginalttl = 0;
4178 SetNextCacheCheckTimeForRecord(m, rr); 4176 SetNextCacheCheckTimeForRecord(m, rr);
4179 } 4177 }
4180 4178
4181mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m) 4179mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
4182 { 4180 {
4183 mDNSs32 time; 4181 mDNSs32 time;
4184 mDNSPlatformLock(m); 4182 mDNSPlatformLock(m);
4185 if (m->mDNS_busy) 4183 if (m->mDNS_busy)
4186 { 4184 {
4187 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow."); 4185 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4188 if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy); 4186 if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
4189 } 4187 }
4190  4188
4191 if (m->timenow) time = m->timenow; 4189 if (m->timenow) time = m->timenow;
4192 else time = mDNS_TimeNow_NoLock(m); 4190 else time = mDNS_TimeNow_NoLock(m);
4193 mDNSPlatformUnlock(m); 4191 mDNSPlatformUnlock(m);
4194 return(time); 4192 return(time);
4195 } 4193 }
4196 4194
4197// To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that 4195// To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that
4198// had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute(). 4196// had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute().
4199// (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set) 4197// (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set)
4200#define SetSPSProxyListChanged(X) do { \ 4198#define SetSPSProxyListChanged(X) do { \
4201 if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \ 4199 if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \
4202 m->SPSProxyListChanged = (X); } while(0) 4200 m->SPSProxyListChanged = (X); } while(0)
4203 4201
4204// Called from mDNS_Execute() to expire stale proxy records 4202// Called from mDNS_Execute() to expire stale proxy records
4205mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list) 4203mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list)
4206 { 4204 {
4207 m->CurrentRecord = list; 4205 m->CurrentRecord = list;
4208 while (m->CurrentRecord) 4206 while (m->CurrentRecord)
4209 { 4207 {
4210 AuthRecord *rr = m->CurrentRecord; 4208 AuthRecord *rr = m->CurrentRecord;
4211 if (rr->resrec.RecordType != kDNSRecordTypeDeregistering && rr->WakeUp.HMAC.l[0]) 4209 if (rr->resrec.RecordType != kDNSRecordTypeDeregistering && rr->WakeUp.HMAC.l[0])
4212 { 4210 {
4213 // If m->SPSSocket is NULL that means we're not acting as a sleep proxy any more, 4211 // If m->SPSSocket is NULL that means we're not acting as a sleep proxy any more,
4214 // so we need to cease proxying for *all* records we may have, expired or not. 4212 // so we need to cease proxying for *all* records we may have, expired or not.
4215 if (m->SPSSocket && m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS 4213 if (m->SPSSocket && m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS
4216 { 4214 {
4217 if (m->NextScheduledSPS - rr->TimeExpire > 0) 4215 if (m->NextScheduledSPS - rr->TimeExpire > 0)
4218 m->NextScheduledSPS = rr->TimeExpire; 4216 m->NextScheduledSPS = rr->TimeExpire;
4219 } 4217 }
4220 else // else proxy record expired, so remove it 4218 else // else proxy record expired, so remove it
4221 { 4219 {
4222 LogSPS("CheckProxyRecords: Removing %d H-MAC %.6a I-MAC %.6a %d %s", 4220 LogSPS("CheckProxyRecords: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
4223 m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr)); 4221 m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr));
4224 SetSPSProxyListChanged(rr->resrec.InterfaceID); 4222 SetSPSProxyListChanged(rr->resrec.InterfaceID);
4225 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 4223 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
4226 // Don't touch rr after this -- memory may have been free'd 4224 // Don't touch rr after this -- memory may have been free'd
4227 } 4225 }
4228 } 4226 }
4229 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because 4227 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
4230 // new records could have been added to the end of the list as a result of that call. 4228 // new records could have been added to the end of the list as a result of that call.
4231 if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 4229 if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
4232 m->CurrentRecord = rr->next; 4230 m->CurrentRecord = rr->next;
4233 } 4231 }
4234 } 4232 }
4235 4233
4236mDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m) 4234mDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m)
4237 { 4235 {
4238 while (m->CurrentRecord) 4236 while (m->CurrentRecord)
4239 { 4237 {
4240 AuthRecord *rr = m->CurrentRecord; 4238 AuthRecord *rr = m->CurrentRecord;
4241 if (rr->AnsweredLocalQ && rr->resrec.RecordType == kDNSRecordTypeDeregistering) 4239 if (rr->AnsweredLocalQ && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
4242 { 4240 {
4243 debugf("CheckRmvEventsForLocalRecords: Generating local RMV events for %s", ARDisplayString(m, rr)); 4241 debugf("CheckRmvEventsForLocalRecords: Generating local RMV events for %s", ARDisplayString(m, rr));
4244 rr->resrec.RecordType = kDNSRecordTypeShared; 4242 rr->resrec.RecordType = kDNSRecordTypeShared;
4245 AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); 4243 AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse);
4246 if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now 4244 if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now
4247 { 4245 {
4248 rr->resrec.RecordType = kDNSRecordTypeDeregistering; 4246 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
4249 rr->AnsweredLocalQ = mDNSfalse; 4247 rr->AnsweredLocalQ = mDNSfalse;
4250 // SendResponses normally calls CompleteDeregistration after sending goodbyes. 4248 // SendResponses normally calls CompleteDeregistration after sending goodbyes.
4251 // For LocalOnly records, we don't do that and hence we need to do that here. 4249 // For LocalOnly records, we don't do that and hence we need to do that here.
4252 if (RRLocalOnly(rr)) CompleteDeregistration(m, rr); 4250 if (RRLocalOnly(rr)) CompleteDeregistration(m, rr);
4253 } 4251 }
4254 } 4252 }
4255 if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now 4253 if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now
4256 m->CurrentRecord = rr->next; 4254 m->CurrentRecord = rr->next;
4257 } 4255 }
4258 } 4256 }
4259 4257
4260mDNSlocal void TimeoutQuestions(mDNS *const m) 4258mDNSlocal void TimeoutQuestions(mDNS *const m)
4261 { 4259 {
4262 m->NextScheduledStopTime = m->timenow + 0x3FFFFFFF; 4260 m->NextScheduledStopTime = m->timenow + 0x3FFFFFFF;
4263 if (m->CurrentQuestion) 4261 if (m->CurrentQuestion)
4264 LogMsg("TimeoutQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, 4262 LogMsg("TimeoutQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c,
4265 DNSTypeName(m->CurrentQuestion->qtype)); 4263 DNSTypeName(m->CurrentQuestion->qtype));
4266 m->CurrentQuestion = m->Questions; 4264 m->CurrentQuestion = m->Questions;
4267 while (m->CurrentQuestion) 4265 while (m->CurrentQuestion)
4268 { 4266 {
4269 DNSQuestion *const q = m->CurrentQuestion; 4267 DNSQuestion *const q = m->CurrentQuestion;
4270 if (q->StopTime) 4268 if (q->StopTime)
4271 { 4269 {
4272 if (m->timenow - q->StopTime >= 0) 4270 if (m->timenow - q->StopTime >= 0)
4273 { 4271 {
4274 LogInfo("TimeoutQuestions: question %##s timed out, time %d", q->qname.c, m->timenow - q->StopTime); 4272 LogInfo("TimeoutQuestions: question %##s timed out, time %d", q->qname.c, m->timenow - q->StopTime);
4275 GenerateNegativeResponse(m); 4273 GenerateNegativeResponse(m);
4276 if (m->CurrentQuestion == q) q->StopTime = 0; 4274 if (m->CurrentQuestion == q) q->StopTime = 0;
4277 } 4275 }
4278 else 4276 else
4279 { 4277 {
4280 if (m->NextScheduledStopTime - q->StopTime > 0) 4278 if (m->NextScheduledStopTime - q->StopTime > 0)
4281 m->NextScheduledStopTime = q->StopTime; 4279 m->NextScheduledStopTime = q->StopTime;
4282 } 4280 }
4283 } 4281 }
4284 // If m->CurrentQuestion wasn't modified out from under us, advance it now 4282 // If m->CurrentQuestion wasn't modified out from under us, advance it now
4285 // We can't do this at the start of the loop because GenerateNegativeResponse 4283 // We can't do this at the start of the loop because GenerateNegativeResponse
4286 // depends on having m->CurrentQuestion point to the right question 4284 // depends on having m->CurrentQuestion point to the right question
4287 if (m->CurrentQuestion == q) 4285 if (m->CurrentQuestion == q)
4288 m->CurrentQuestion = q->next; 4286 m->CurrentQuestion = q->next;
4289 } 4287 }
4290 m->CurrentQuestion = mDNSNULL; 4288 m->CurrentQuestion = mDNSNULL;
4291 } 4289 }
4292 4290
4293mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) 4291mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
4294 { 4292 {
4295 mDNS_Lock(m); // Must grab lock before trying to read m->timenow 4293 mDNS_Lock(m); // Must grab lock before trying to read m->timenow
4296 4294
4297 if (m->timenow - m->NextScheduledEvent >= 0) 4295 if (m->timenow - m->NextScheduledEvent >= 0)
4298 { 4296 {
4299 int i; 4297 int i;
4300 AuthRecord *head, *tail; 4298 AuthRecord *head, *tail;
4301 mDNSu32 slot; 4299 mDNSu32 slot;
4302 AuthGroup *ag; 4300 AuthGroup *ag;
4303 4301
4304 verbosedebugf("mDNS_Execute"); 4302 verbosedebugf("mDNS_Execute");
4305 4303
4306 if (m->CurrentQuestion) 4304 if (m->CurrentQuestion)
4307 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", 4305 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)",
4308 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 4306 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4309  4307
4310 if (m->CurrentRecord) 4308 if (m->CurrentRecord)
4311 LogMsg("mDNS_Execute: ERROR m->CurrentRecord already set: %s", ARDisplayString(m, m->CurrentRecord)); 4309 LogMsg("mDNS_Execute: ERROR m->CurrentRecord already set: %s", ARDisplayString(m, m->CurrentRecord));
4312  4310
4313 // 1. If we're past the probe suppression time, we can clear it 4311 // 1. If we're past the probe suppression time, we can clear it
4314 if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0; 4312 if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
4315  4313
4316 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter 4314 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4317 if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0; 4315 if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0;
4318  4316
4319 // 3. Purge our cache of stale old records 4317 // 3. Purge our cache of stale old records
4320 if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0) 4318 if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
4321 { 4319 {
4322 mDNSu32 numchecked = 0; 4320 mDNSu32 numchecked = 0;
4323 m->NextCacheCheck = m->timenow + 0x3FFFFFFF; 4321 m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
4324 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 4322 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4325 { 4323 {
4326 if (m->timenow - m->rrcache_nextcheck[slot] >= 0) 4324 if (m->timenow - m->rrcache_nextcheck[slot] >= 0)
4327 { 4325 {
4328 CacheGroup **cp = &m->rrcache_hash[slot]; 4326 CacheGroup **cp = &m->rrcache_hash[slot];
4329 m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF; 4327 m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF;
4330 while (*cp) 4328 while (*cp)
4331 { 4329 {
4332 debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL"); 4330 debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL");
4333 numchecked++; 4331 numchecked++;
4334 CheckCacheExpiration(m, slot, *cp); 4332 CheckCacheExpiration(m, slot, *cp);
4335 if ((*cp)->members) cp=&(*cp)->next; 4333 if ((*cp)->members) cp=&(*cp)->next;
4336 else ReleaseCacheGroup(m, cp); 4334 else ReleaseCacheGroup(m, cp);
4337 } 4335 }
4338 } 4336 }
4339 // Even if we didn't need to actually check this slot yet, still need to 4337 // Even if we didn't need to actually check this slot yet, still need to
4340 // factor its nextcheck time into our overall NextCacheCheck value 4338 // factor its nextcheck time into our overall NextCacheCheck value
4341 if (m->NextCacheCheck - m->rrcache_nextcheck[slot] > 0) 4339 if (m->NextCacheCheck - m->rrcache_nextcheck[slot] > 0)
4342 m->NextCacheCheck = m->rrcache_nextcheck[slot]; 4340 m->NextCacheCheck = m->rrcache_nextcheck[slot];
4343 } 4341 }
4344 debugf("m->NextCacheCheck %4d checked, next in %d", numchecked, m->NextCacheCheck - m->timenow); 4342 debugf("m->NextCacheCheck %4d checked, next in %d", numchecked, m->NextCacheCheck - m->timenow);
4345 } 4343 }
4346  4344
4347 if (m->timenow - m->NextScheduledSPS >= 0) 4345 if (m->timenow - m->NextScheduledSPS >= 0)
4348 { 4346 {
4349 m->NextScheduledSPS = m->timenow + 0x3FFFFFFF; 4347 m->NextScheduledSPS = m->timenow + 0x3FFFFFFF;
4350 CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords 4348 CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords
4351 CheckProxyRecords(m, m->ResourceRecords); 4349 CheckProxyRecords(m, m->ResourceRecords);
4352 } 4350 }
4353 4351
4354 SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now 4352 SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now
4355 4353
4356 // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().) 4354 // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().)
4357 if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0) m->AnnounceOwner = 0; 4355 if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0) m->AnnounceOwner = 0;
4358 4356
4359 if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) 4357 if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
4360 { 4358 {
4361 m->DelaySleep = 0; 4359 m->DelaySleep = 0;
4362 if (m->SleepState == SleepState_Transferring) 4360 if (m->SleepState == SleepState_Transferring)
4363 { 4361 {
4364 LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers"); 4362 LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers");
4365 BeginSleepProcessing(m); 4363 BeginSleepProcessing(m);
4366 } 4364 }
4367 } 4365 }
4368 4366
4369 // 4. See if we can answer any of our new local questions from the cache 4367 // 4. See if we can answer any of our new local questions from the cache
4370 for (i=0; m->NewQuestions && i<1000; i++) 4368 for (i=0; m->NewQuestions && i<1000; i++)
4371 { 4369 {
4372 if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break; 4370 if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
4373 AnswerNewQuestion(m); 4371 AnswerNewQuestion(m);
4374 } 4372 }
4375 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit"); 4373 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4376 4374
4377 // Make sure we deliver *all* local RMV events, and clear the corresponding rr->AnsweredLocalQ flags, *before* 4375 // Make sure we deliver *all* local RMV events, and clear the corresponding rr->AnsweredLocalQ flags, *before*
4378 // we begin generating *any* new ADD events in the m->NewLocalOnlyQuestions and m->NewLocalRecords loops below. 4376 // we begin generating *any* new ADD events in the m->NewLocalOnlyQuestions and m->NewLocalRecords loops below.
4379 for (i=0; i<1000 && m->LocalRemoveEvents; i++) 4377 for (i=0; i<1000 && m->LocalRemoveEvents; i++)
4380 { 4378 {
4381 m->LocalRemoveEvents = mDNSfalse; 4379 m->LocalRemoveEvents = mDNSfalse;
4382 m->CurrentRecord = m->ResourceRecords; 4380 m->CurrentRecord = m->ResourceRecords;
4383 CheckRmvEventsForLocalRecords(m); 4381 CheckRmvEventsForLocalRecords(m);
4384 // Walk the LocalOnly records and deliver the RMV events 4382 // Walk the LocalOnly records and deliver the RMV events
4385 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 4383 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
4386 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) 4384 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
4387 { 4385 {
4388 m->CurrentRecord = ag->members; 4386 m->CurrentRecord = ag->members;
4389 if (m->CurrentRecord) CheckRmvEventsForLocalRecords(m); 4387 if (m->CurrentRecord) CheckRmvEventsForLocalRecords(m);
4390 } 4388 }
4391 } 4389 }
4392 4390
4393 if (i >= 1000) LogMsg("mDNS_Execute: m->LocalRemoveEvents exceeded loop limit"); 4391 if (i >= 1000) LogMsg("mDNS_Execute: m->LocalRemoveEvents exceeded loop limit");
4394  4392
4395 for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m); 4393 for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
4396 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit"); 4394 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4397 4395
4398 head = tail = mDNSNULL; 4396 head = tail = mDNSNULL;
4399 for (i=0; i<1000 && m->NewLocalRecords && m->NewLocalRecords != head; i++) 4397 for (i=0; i<1000 && m->NewLocalRecords && m->NewLocalRecords != head; i++)
4400 { 4398 {
4401 AuthRecord *rr = m->NewLocalRecords; 4399 AuthRecord *rr = m->NewLocalRecords;
4402 m->NewLocalRecords = m->NewLocalRecords->next; 4400 m->NewLocalRecords = m->NewLocalRecords->next;
4403 if (LocalRecordReady(rr)) 4401 if (LocalRecordReady(rr))
4404 { 4402 {
4405 debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); 4403 debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr));
4406 AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); 4404 AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
4407 } 4405 }
4408 else if (!rr->next) 4406 else if (!rr->next)
4409 { 4407 {
4410 // If we have just one record that is not ready, we don't have to unlink and 4408 // If we have just one record that is not ready, we don't have to unlink and
4411 // reinsert. As the NewLocalRecords will be NULL for this case, the loop will 4409 // reinsert. As the NewLocalRecords will be NULL for this case, the loop will
4412 // terminate and set the NewLocalRecords to rr. 4410 // terminate and set the NewLocalRecords to rr.
4413 debugf("mDNS_Execute: Just one LocalAuthRecord %s, breaking out of the loop early", ARDisplayString(m, rr)); 4411 debugf("mDNS_Execute: Just one LocalAuthRecord %s, breaking out of the loop early", ARDisplayString(m, rr));
4414 if (head != mDNSNULL || m->NewLocalRecords != mDNSNULL) 4412 if (head != mDNSNULL || m->NewLocalRecords != mDNSNULL)
4415 LogMsg("mDNS_Execute: ERROR!!: head %p, NewLocalRecords %p", head, m->NewLocalRecords); 4413 LogMsg("mDNS_Execute: ERROR!!: head %p, NewLocalRecords %p", head, m->NewLocalRecords);
4416  4414
4417 head = rr; 4415 head = rr;
4418 } 4416 }
4419 else 4417 else
4420 { 4418 {
4421 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records 4419 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records
4422 debugf("mDNS_Execute: Skipping LocalAuthRecord %s", ARDisplayString(m, rr)); 4420 debugf("mDNS_Execute: Skipping LocalAuthRecord %s", ARDisplayString(m, rr));
4423 // if this is the first record we are skipping, move to the end of the list. 4421 // if this is the first record we are skipping, move to the end of the list.
4424 // if we have already skipped records before, append it at the end. 4422 // if we have already skipped records before, append it at the end.
4425 while (*p && *p != rr) p=&(*p)->next; 4423 while (*p && *p != rr) p=&(*p)->next;
4426 if (*p) *p = rr->next; // Cut this record from the list 4424 if (*p) *p = rr->next; // Cut this record from the list
4427 else { LogMsg("mDNS_Execute: ERROR!! Cannot find record %s in ResourceRecords list", ARDisplayString(m, rr)); break; } 4425 else { LogMsg("mDNS_Execute: ERROR!! Cannot find record %s in ResourceRecords list", ARDisplayString(m, rr)); break; }
4428 if (!head) 4426 if (!head)
4429 { 4427 {
4430 while (*p) p=&(*p)->next; 4428 while (*p) p=&(*p)->next;
4431 *p = rr; 4429 *p = rr;
4432 head = tail = rr; 4430 head = tail = rr;
4433 } 4431 }
4434 else 4432 else
4435 { 4433 {
4436 tail->next = rr; 4434 tail->next = rr;
4437 tail = rr; 4435 tail = rr;
4438 } 4436 }
4439 rr->next = mDNSNULL; 4437 rr->next = mDNSNULL;
4440 } 4438 }
4441 } 4439 }
4442 m->NewLocalRecords = head; 4440 m->NewLocalRecords = head;
4443 debugf("mDNS_Execute: Setting NewLocalRecords to %s", (head ? ARDisplayString(m, head) : "NULL")); 4441 debugf("mDNS_Execute: Setting NewLocalRecords to %s", (head ? ARDisplayString(m, head) : "NULL"));
4444 4442
4445 if (i >= 1000) LogMsg("mDNS_Execute: m->NewLocalRecords exceeded loop limit"); 4443 if (i >= 1000) LogMsg("mDNS_Execute: m->NewLocalRecords exceeded loop limit");
4446 4444
4447 // Check to see if we have any new LocalOnly/P2P records to examine for delivering 4445 // Check to see if we have any new LocalOnly/P2P records to examine for delivering
4448 // to our local questions 4446 // to our local questions
4449 if (m->NewLocalOnlyRecords) 4447 if (m->NewLocalOnlyRecords)
4450 { 4448 {
4451 m->NewLocalOnlyRecords = mDNSfalse; 4449 m->NewLocalOnlyRecords = mDNSfalse;
4452 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 4450 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
4453 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) 4451 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
4454 { 4452 {
4455 for (i=0; i<100 && ag->NewLocalOnlyRecords; i++) 4453 for (i=0; i<100 && ag->NewLocalOnlyRecords; i++)
4456 { 4454 {
4457 AuthRecord *rr = ag->NewLocalOnlyRecords; 4455 AuthRecord *rr = ag->NewLocalOnlyRecords;
4458 ag->NewLocalOnlyRecords = ag->NewLocalOnlyRecords->next; 4456 ag->NewLocalOnlyRecords = ag->NewLocalOnlyRecords->next;
4459 // LocalOnly records should always be ready as they never probe 4457 // LocalOnly records should always be ready as they never probe
4460 if (LocalRecordReady(rr)) 4458 if (LocalRecordReady(rr))
4461 { 4459 {
4462 debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr)); 4460 debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr));
4463 AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); 4461 AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
4464 } 4462 }
4465 else LogMsg("mDNS_Execute: LocalOnlyRecord %s not ready", ARDisplayString(m, rr)); 4463 else LogMsg("mDNS_Execute: LocalOnlyRecord %s not ready", ARDisplayString(m, rr));
4466 } 4464 }
4467 // We limit about 100 per AuthGroup that can be serviced at a time 4465 // We limit about 100 per AuthGroup that can be serviced at a time
4468 if (i >= 100) LogMsg("mDNS_Execute: ag->NewLocalOnlyRecords exceeded loop limit"); 4466 if (i >= 100) LogMsg("mDNS_Execute: ag->NewLocalOnlyRecords exceeded loop limit");
4469 } 4467 }
4470 } 4468 }
4471 4469
4472 // 5. Some questions may have picked a new DNS server and the cache may answer these questions now. 4470 // 5. Some questions may have picked a new DNS server and the cache may answer these questions now.
4473 AnswerQuestionsForDNSServerChanges(m); 4471 AnswerQuestionsForDNSServerChanges(m);
4474 4472
4475 // 6. See what packets we need to send 4473 // 6. See what packets we need to send
4476 if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping)) 4474 if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping))
4477 DiscardDeregistrations(m); 4475 DiscardDeregistrations(m);
4478 if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)) 4476 if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0))
4479 { 4477 {
4480 // If the platform code is ready, and we're not suppressing packet generation right now 4478 // If the platform code is ready, and we're not suppressing packet generation right now
4481 // then send our responses, probes, and questions. 4479 // then send our responses, probes, and questions.
4482 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them. 4480 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4483 // We send queries next, because there might be final-stage probes that complete their probing here, causing 4481 // We send queries next, because there might be final-stage probes that complete their probing here, causing
4484 // them to advance to announcing state, and we want those to be included in any announcements we send out. 4482 // them to advance to announcing state, and we want those to be included in any announcements we send out.
4485 // Finally, we send responses, including the previously mentioned records that just completed probing. 4483 // Finally, we send responses, including the previously mentioned records that just completed probing.
4486 m->SuppressSending = 0; 4484 m->SuppressSending = 0;
4487  4485
4488 // 7. Send Query packets. This may cause some probing records to advance to announcing state 4486 // 7. Send Query packets. This may cause some probing records to advance to announcing state
4489 if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m); 4487 if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
4490 if (m->timenow - m->NextScheduledQuery >= 0) 4488 if (m->timenow - m->NextScheduledQuery >= 0)
4491 { 4489 {
4492 DNSQuestion *q; 4490 DNSQuestion *q;
4493 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second", 4491 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
4494 m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery); 4492 m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery);
4495 m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond; 4493 m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
4496 for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 4494 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
4497 if (ActiveQuestion(q) && m->timenow - NextQSendTime(q) >= 0) 4495 if (ActiveQuestion(q) && m->timenow - NextQSendTime(q) >= 0)
4498 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4496 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4499 } 4497 }
4500 if (m->timenow - m->NextScheduledProbe >= 0) 4498 if (m->timenow - m->NextScheduledProbe >= 0)
4501 { 4499 {
4502 LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second", 4500 debugf("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
4503 m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe); 4501 m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe);
4504 m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond; 4502 m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
4505 } 4503 }
4506  4504
4507 // 8. Send Response packets, including probing records just advanced to announcing state 4505 // 8. Send Response packets, including probing records just advanced to announcing state
4508 if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m); 4506 if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
4509 if (m->timenow - m->NextScheduledResponse >= 0) 4507 if (m->timenow - m->NextScheduledResponse >= 0)
4510 { 4508 {
4511 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second"); 4509 debugf("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4512 m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond; 4510 m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond;
4513 } 4511 }
4514 } 4512 }
4515 4513
4516 // Clear RandomDelay values, ready to pick a new different value next time 4514 // Clear RandomDelay values, ready to pick a new different value next time
4517 m->RandomQueryDelay = 0; 4515 m->RandomQueryDelay = 0;
4518 m->RandomReconfirmDelay = 0; 4516 m->RandomReconfirmDelay = 0;
4519 4517
4520 if (m->NextScheduledStopTime && m->timenow - m->NextScheduledStopTime >= 0) TimeoutQuestions(m); 4518 if (m->NextScheduledStopTime && m->timenow - m->NextScheduledStopTime >= 0) TimeoutQuestions(m);
4521#ifndef UNICAST_DISABLED 4519#ifndef UNICAST_DISABLED
4522 if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m); 4520 if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m);
4523 if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m); 4521 if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m);
4524 if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m); 4522 if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m);
4525#endif 4523#endif
4526 } 4524 }
4527 4525
4528 // Note about multi-threaded systems: 4526 // Note about multi-threaded systems:
4529 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(), 4527 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4530 // performing mDNS API operations that change our next scheduled event time. 4528 // performing mDNS API operations that change our next scheduled event time.
4531 // 4529 //
4532 // On multi-threaded systems (like the current Windows implementation) that have a single main thread 4530 // On multi-threaded systems (like the current Windows implementation) that have a single main thread
4533 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility 4531 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4534 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will 4532 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4535 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one 4533 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4536 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful 4534 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4537 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it 4535 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4538 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately 4536 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4539 // without blocking. This avoids the race condition between the signal from the other thread arriving 4537 // without blocking. This avoids the race condition between the signal from the other thread arriving
4540 // just *before* or just *after* the main thread enters the blocking primitive. 4538 // just *before* or just *after* the main thread enters the blocking primitive.
4541 // 4539 //
4542 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven, 4540 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4543 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to 4541 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4544 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer 4542 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4545 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale 4543 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4546 // by the time it gets to the timer callback function). 4544 // by the time it gets to the timer callback function).
4547 4545
4548 mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value 4546 mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4549 return(m->NextScheduledEvent); 4547 return(m->NextScheduledEvent);
4550 } 4548 }
4551 4549
4552mDNSlocal void SuspendLLQs(mDNS *m) 4550mDNSlocal void SuspendLLQs(mDNS *m)
4553 { 4551 {
4554 DNSQuestion *q; 4552 DNSQuestion *q;
4555 for (q = m->Questions; q; q = q->next) 4553 for (q = m->Questions; q; q = q->next)
4556 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established) 4554 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established)
4557 { q->ReqLease = 0; sendLLQRefresh(m, q); } 4555 { q->ReqLease = 0; sendLLQRefresh(m, q); }
4558 } 4556 }
4559 4557
4560mDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q) 4558mDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q)
4561 { 4559 {
4562 AuthRecord *rr; 4560 AuthRecord *rr;
4563 mDNSu32 slot; 4561 mDNSu32 slot;
4564 AuthGroup *ag; 4562 AuthGroup *ag;
4565 4563
4566 slot = AuthHashSlot(&q->qname); 4564 slot = AuthHashSlot(&q->qname);
4567 ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname); 4565 ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname);
4568 if (ag) 4566 if (ag)
4569 { 4567 {
4570 for (rr = ag->members; rr; rr=rr->next) 4568 for (rr = ag->members; rr; rr=rr->next)
4571 // Filter the /etc/hosts records - LocalOnly, Unique, A/AAAA/CNAME 4569 // Filter the /etc/hosts records - LocalOnly, Unique, A/AAAA/CNAME
4572 if (LORecordAnswersAddressType(rr) && LocalOnlyRecordAnswersQuestion(rr, q)) 4570 if (LORecordAnswersAddressType(rr) && LocalOnlyRecordAnswersQuestion(rr, q))
4573 { 4571 {
4574 LogInfo("QuestionHasLocalAnswers: Question %p %##s (%s) has local answer %s", q, q->qname.c, DNSTypeName(q->qtype), ARDisplayString(m, rr)); 4572 LogInfo("QuestionHasLocalAnswers: Question %p %##s (%s) has local answer %s", q, q->qname.c, DNSTypeName(q->qtype), ARDisplayString(m, rr));
4575 return mDNStrue; 4573 return mDNStrue;
4576 } 4574 }
4577 } 4575 }
4578 return mDNSfalse; 4576 return mDNSfalse;
4579 } 4577 }
4580 4578
4581// ActivateUnicastQuery() is called from three places: 4579// ActivateUnicastQuery() is called from three places:
4582// 1. When a new question is created 4580// 1. When a new question is created
4583// 2. On wake from sleep 4581// 2. On wake from sleep
4584// 3. When the DNS configuration changes 4582// 3. When the DNS configuration changes
4585// In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false) 4583// In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false)
4586// In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true) 4584// In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
4587mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately) 4585mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately)
4588 { 4586 {
4589 // For now this AutoTunnel stuff is specific to Mac OS X. 4587 // For now this AutoTunnel stuff is specific to Mac OS X.
4590 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer 4588 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
4591#if APPLE_OSX_mDNSResponder 4589#if APPLE_OSX_mDNSResponder
4592 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally. 4590 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
4593 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the 4591 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
4594 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel. 4592 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
4595 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then 4593 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
4596 // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic 4594 // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic
4597 // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query. 4595 // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query.
4598 4596
4599 if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) && 4597 if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) &&
4600 !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback) 4598 !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback)
4601 { 4599 {
4602 question->NoAnswer = NoAnswer_Suspended; 4600 question->NoAnswer = NoAnswer_Suspended;
4603 AddNewClientTunnel(m, question); 4601 AddNewClientTunnel(m, question);
4604 return; 4602 return;
4605 } 4603 }
4606#endif // APPLE_OSX_mDNSResponder 4604#endif // APPLE_OSX_mDNSResponder
4607 4605
4608 if (!question->DuplicateOf) 4606 if (!question->DuplicateOf)
4609 { 4607 {
4610 debugf("ActivateUnicastQuery: %##s %s%s%s", 4608 debugf("ActivateUnicastQuery: %##s %s%s%s",
4611 question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : ""); 4609 question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
4612 question->CNAMEReferrals = 0; 4610 question->CNAMEReferrals = 0;
4613 if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } 4611 if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
4614 if (question->LongLived) 4612 if (question->LongLived)
4615 { 4613 {
4616 question->state = LLQ_InitialRequest; 4614 question->state = LLQ_InitialRequest;
4617 question->id = zeroOpaque64; 4615 question->id = zeroOpaque64;
4618 question->servPort = zeroIPPort; 4616 question->servPort = zeroIPPort;
4619 if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; } 4617 if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
4620 } 4618 }
4621 // If the question has local answers, then we don't want answers from outside 4619 // If the question has local answers, then we don't want answers from outside
4622 if (ScheduleImmediately && !QuestionHasLocalAnswers(m, question)) 4620 if (ScheduleImmediately && !QuestionHasLocalAnswers(m, question))
4623 { 4621 {
4624 question->ThisQInterval = InitialQuestionInterval; 4622 question->ThisQInterval = InitialQuestionInterval;
4625 question->LastQTime = m->timenow - question->ThisQInterval; 4623 question->LastQTime = m->timenow - question->ThisQInterval;
4626 SetNextQueryTime(m, question); 4624 SetNextQueryTime(m, question);
4627 } 4625 }
4628 } 4626 }
4629 } 4627 }
4630 4628
4631// Caller should hold the lock 4629// Caller should hold the lock
4632mDNSexport void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDomainsChanged, FlushCache flushCacheRecords, 4630mDNSexport void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDomainsChanged, FlushCache flushCacheRecords,
4633 CallbackBeforeStartQuery BeforeStartCallback, void *context) 4631 CallbackBeforeStartQuery BeforeStartCallback, void *context)
4634 { 4632 {
4635 DNSQuestion *q; 4633 DNSQuestion *q;
4636 DNSQuestion *restart = mDNSNULL; 4634 DNSQuestion *restart = mDNSNULL;
4637 4635
4638 if (!m->mDNS_busy) LogMsg("mDNSCoreRestartAddressQueries: ERROR!! Lock not held"); 4636 if (!m->mDNS_busy) LogMsg("mDNSCoreRestartAddressQueries: ERROR!! Lock not held");
4639 4637
4640 // 1. Flush the cache records 4638 // 1. Flush the cache records
4641 if (flushCacheRecords) flushCacheRecords(m); 4639 if (flushCacheRecords) flushCacheRecords(m);
4642 4640
4643 // 2. Even though we may have purged the cache records above, before it can generate RMV event 4641 // 2. Even though we may have purged the cache records above, before it can generate RMV event
4644 // we are going to stop the question. Hence we need to deliver the RMV event before we 4642 // we are going to stop the question. Hence we need to deliver the RMV event before we
4645 // stop the question. 4643 // stop the question.
4646 // 4644 //
4647 // CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the 4645 // CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the
4648 // application callback can potentially stop the current question (detected by CurrentQuestion) or 4646 // application callback can potentially stop the current question (detected by CurrentQuestion) or
4649 // *any* other question which could be the next one that we may process here. RestartQuestion 4647 // *any* other question which could be the next one that we may process here. RestartQuestion
4650 // points to the "next" question which will be automatically advanced in mDNS_StopQuery_internal 4648 // points to the "next" question which will be automatically advanced in mDNS_StopQuery_internal
4651 // if the "next" question is stopped while the CurrentQuestion is stopped 4649 // if the "next" question is stopped while the CurrentQuestion is stopped
4652 4650
4653 if (m->RestartQuestion) 4651 if (m->RestartQuestion)
4654 LogMsg("mDNSCoreRestartAddressQueries: ERROR!! m->RestartQuestion already set: %##s (%s)", 4652 LogMsg("mDNSCoreRestartAddressQueries: ERROR!! m->RestartQuestion already set: %##s (%s)",
4655 m->RestartQuestion->qname.c, DNSTypeName(m->RestartQuestion->qtype)); 4653 m->RestartQuestion->qname.c, DNSTypeName(m->RestartQuestion->qtype));
4656 4654
4657 m->RestartQuestion = m->Questions; 4655 m->RestartQuestion = m->Questions;
4658 while (m->RestartQuestion) 4656 while (m->RestartQuestion)
4659 { 4657 {
4660 q = m->RestartQuestion; 4658 q = m->RestartQuestion;
4661 m->RestartQuestion = q->next; 4659 m->RestartQuestion = q->next;
4662 // GetZoneData questions are referenced by other questions (original query that started the GetZoneData 4660 // GetZoneData questions are referenced by other questions (original query that started the GetZoneData
4663 // question) through their "nta" pointer. Normally when the original query stops, it stops the 4661 // question) through their "nta" pointer. Normally when the original query stops, it stops the
4664 // GetZoneData question and also frees the memory (See CancelGetZoneData). If we stop the GetZoneData 4662 // GetZoneData question and also frees the memory (See CancelGetZoneData). If we stop the GetZoneData
4665 // question followed by the original query that refers to this GetZoneData question, we will end up 4663 // question followed by the original query that refers to this GetZoneData question, we will end up
4666 // freeing the GetZoneData question and then start the "freed" question at the end.  4664 // freeing the GetZoneData question and then start the "freed" question at the end.
4667 4665
4668 if (IsGetZoneDataQuestion(q)) 4666 if (IsGetZoneDataQuestion(q))
4669 { 4667 {
4670 DNSQuestion *refq = q->next; 4668 DNSQuestion *refq = q->next;
4671 LogInfo("mDNSCoreRestartAddressQueries: Skipping GetZoneDataQuestion %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 4669 LogInfo("mDNSCoreRestartAddressQueries: Skipping GetZoneDataQuestion %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
4672 // debug stuff, we just try to find the referencing question and don't do much with it 4670 // debug stuff, we just try to find the referencing question and don't do much with it
4673 while (refq) 4671 while (refq)
4674 { 4672 {
4675 if (q == &refq->nta->question) 4673 if (q == &refq->nta->question)
4676 { 4674 {
4677 LogInfo("mDNSCoreRestartAddressQueries: Question %p %##s (%s) referring to GetZoneDataQuestion %p, not stopping", refq, refq->qname.c, DNSTypeName(refq->qtype), q); 4675 LogInfo("mDNSCoreRestartAddressQueries: Question %p %##s (%s) referring to GetZoneDataQuestion %p, not stopping", refq, refq->qname.c, DNSTypeName(refq->qtype), q);
4678 } 4676 }
4679 refq = refq->next; 4677 refq = refq->next;
4680 } 4678 }
4681 continue; 4679 continue;
4682 } 4680 }
4683 4681
4684 // This function is called when /etc/hosts changes and that could affect A, AAAA and CNAME queries 4682 // This function is called when /etc/hosts changes and that could affect A, AAAA and CNAME queries
4685 if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA && q->qtype != kDNSType_CNAME) continue; 4683 if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA && q->qtype != kDNSType_CNAME) continue;
4686 4684
4687 // If the search domains did not change, then we restart all the queries. Otherwise, only 4685 // If the search domains did not change, then we restart all the queries. Otherwise, only
4688 // for queries for which we "might" have appended search domains ("might" because we may 4686 // for queries for which we "might" have appended search domains ("might" because we may
4689 // find results before we apply search domains even though AppendSearchDomains is set to 1) 4687 // find results before we apply search domains even though AppendSearchDomains is set to 1)
4690 if (!SearchDomainsChanged || q->AppendSearchDomains) 4688 if (!SearchDomainsChanged || q->AppendSearchDomains)
4691 { 4689 {
4692 // NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero 4690 // NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero
4693 // LOAddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before 4691 // LOAddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before
4694 // LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers). Let us say that 4692 // LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers). Let us say that
4695 // /etc/hosts has an A Record for web.apple.com. Any queries for web.apple.com will be answered locally. 4693 // /etc/hosts has an A Record for web.apple.com. Any queries for web.apple.com will be answered locally.
4696 // But this can't prevent a CNAME/AAAA query to not to be sent on the wire. When it is sent on the wire, 4694 // But this can't prevent a CNAME/AAAA query to not to be sent on the wire. When it is sent on the wire,
4697 // it could create cache entries. When we are restarting queries, we can't deliver the cache RMV events 4695 // it could create cache entries. When we are restarting queries, we can't deliver the cache RMV events
4698 // for the original query using these cache entries as ADDs were never delivered using these cache 4696 // for the original query using these cache entries as ADDs were never delivered using these cache
4699 // entries and hence this order is needed. 4697 // entries and hence this order is needed.
4700 4698
4701 // If the query is suppressed, the RMV events won't be delivered 4699 // If the query is suppressed, the RMV events won't be delivered
4702 if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Cache Record RMV events"); continue; } 4700 if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Cache Record RMV events"); continue; }
4703 4701
4704 // SuppressQuery status does not affect questions that are answered using local records 4702 // SuppressQuery status does not affect questions that are answered using local records
4705 if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Local Record RMV events"); continue; } 4703 if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Local Record RMV events"); continue; }
4706 4704
4707 LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d, qnameOrig %p", q, 4705 LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d, qnameOrig %p", q,
4708 q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains, q->qnameOrig); 4706 q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains, q->qnameOrig);
4709 mDNS_StopQuery_internal(m, q); 4707 mDNS_StopQuery_internal(m, q);
4710 // Reset state so that it looks like it was in the beginning i.e it should look at /etc/hosts, cache 4708 // Reset state so that it looks like it was in the beginning i.e it should look at /etc/hosts, cache
4711 // and then search domains should be appended. At the beginning, qnameOrig was NULL. 4709 // and then search domains should be appended. At the beginning, qnameOrig was NULL.
4712 if (q->qnameOrig) 4710 if (q->qnameOrig)
4713 { 4711 {
4714 LogInfo("mDNSCoreRestartAddressQueries: qnameOrig %##s", q->qnameOrig); 4712 LogInfo("mDNSCoreRestartAddressQueries: qnameOrig %##s", q->qnameOrig);
4715 AssignDomainName(&q->qname, q->qnameOrig); 4713 AssignDomainName(&q->qname, q->qnameOrig);
4716 mDNSPlatformMemFree(q->qnameOrig); 4714 mDNSPlatformMemFree(q->qnameOrig);
4717 q->qnameOrig = mDNSNULL; 4715 q->qnameOrig = mDNSNULL;
4718 q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0; 4716 q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0;
4719 } 4717 }
4720 q->SearchListIndex = 0; 4718 q->SearchListIndex = 0;
4721 q->next = restart; 4719 q->next = restart;
4722 restart = q; 4720 restart = q;
4723 } 4721 }
4724 } 4722 }
4725 4723
4726 // 3. Callback before we start the query 4724 // 3. Callback before we start the query
4727 if (BeforeStartCallback) BeforeStartCallback(m, context); 4725 if (BeforeStartCallback) BeforeStartCallback(m, context);
4728 4726
4729 // 4. Restart all the stopped queries 4727 // 4. Restart all the stopped queries
4730 while (restart) 4728 while (restart)
4731 { 4729 {
4732 q = restart; 4730 q = restart;
4733 restart = restart->next; 4731 restart = restart->next;
4734 q->next = mDNSNULL; 4732 q->next = mDNSNULL;
4735 LogInfo("mDNSCoreRestartAddressQueries: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); 4733 LogInfo("mDNSCoreRestartAddressQueries: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
4736 mDNS_StartQuery_internal(m, q); 4734 mDNS_StartQuery_internal(m, q);
4737 } 4735 }
4738 } 4736 }
4739 4737
4740mDNSexport void mDNSCoreRestartQueries(mDNS *const m) 4738mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
4741 { 4739 {
4742 DNSQuestion *q; 4740 DNSQuestion *q;
4743 4741
4744#ifndef UNICAST_DISABLED 4742#ifndef UNICAST_DISABLED
4745 // Retrigger all our uDNS questions 4743 // Retrigger all our uDNS questions
4746 if (m->CurrentQuestion) 4744 if (m->CurrentQuestion)
4747 LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", 4745 LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)",
4748 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 4746 m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4749 m->CurrentQuestion = m->Questions; 4747 m->CurrentQuestion = m->Questions;
4750 while (m->CurrentQuestion) 4748 while (m->CurrentQuestion)
4751 { 4749 {
4752 q = m->CurrentQuestion; 4750 q = m->CurrentQuestion;
4753 m->CurrentQuestion = m->CurrentQuestion->next; 4751 m->CurrentQuestion = m->CurrentQuestion->next;
4754 if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) ActivateUnicastQuery(m, q, mDNStrue); 4752 if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) ActivateUnicastQuery(m, q, mDNStrue);
4755 } 4753 }
4756#endif 4754#endif
4757 4755
4758 // Retrigger all our mDNS questions 4756 // Retrigger all our mDNS questions
4759 for (q = m->Questions; q; q=q->next) // Scan our list of questions 4757 for (q = m->Questions; q; q=q->next) // Scan our list of questions
4760 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) 4758 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
4761 { 4759 {
4762 q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question 4760 q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
4763 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it 4761 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
4764 q->LastQTime = m->timenow - q->ThisQInterval; 4762 q->LastQTime = m->timenow - q->ThisQInterval;
4765 q->RecentAnswerPkts = 0; 4763 q->RecentAnswerPkts = 0;
4766 ExpireDupSuppressInfo(q->DupSuppress, m->timenow); 4764 ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
4767 m->NextScheduledQuery = m->timenow; 4765 m->NextScheduledQuery = m->timenow;
4768 } 4766 }
4769 } 4767 }
4770 4768
4771// *************************************************************************** 4769// ***************************************************************************
4772#if COMPILER_LIKES_PRAGMA_MARK 4770#if COMPILER_LIKES_PRAGMA_MARK
4773#pragma mark - 4771#pragma mark -
4774#pragma mark - Power Management (Sleep/Wake) 4772#pragma mark - Power Management (Sleep/Wake)
4775#endif 4773#endif
4776 4774
4777mDNSexport void mDNS_UpdateAllowSleep(mDNS *const m) 4775mDNSexport void mDNS_UpdateAllowSleep(mDNS *const m)
4778 { 4776 {
4779#ifndef IDLESLEEPCONTROL_DISABLED 4777#ifndef IDLESLEEPCONTROL_DISABLED
4780 mDNSBool allowSleep = mDNStrue; 4778 mDNSBool allowSleep = mDNStrue;
4781 char reason[128]; 4779 char reason[128];
4782  4780
4783 reason[0] = 0; 4781 reason[0] = 0;
4784  4782
4785 if (m->SystemSleepOnlyIfWakeOnLAN) 4783 if (m->SystemSleepOnlyIfWakeOnLAN)
4786 { 4784 {
4787 // Don't sleep if we are a proxy for any services 4785 // Don't sleep if we are a proxy for any services
4788 if (m->ProxyRecords) 4786 if (m->ProxyRecords)
4789 { 4787 {
4790 allowSleep = mDNSfalse; 4788 allowSleep = mDNSfalse;
4791 mDNS_snprintf(reason, sizeof(reason), "sleep proxy for %d records", m->ProxyRecords); 4789 mDNS_snprintf(reason, sizeof(reason), "sleep proxy for %d records", m->ProxyRecords);
4792 LogInfo("Sleep disabled because we are proxying %d records", m->ProxyRecords); 4790 LogInfo("Sleep disabled because we are proxying %d records", m->ProxyRecords);
4793 } 4791 }
4794 4792
4795 if (allowSleep && mDNSCoreHaveAdvertisedMulticastServices(m)) 4793 if (allowSleep && mDNSCoreHaveAdvertisedMulticastServices(m))
4796 { 4794 {
4797 // Scan the list of active interfaces 4795 // Scan the list of active interfaces
4798 NetworkInterfaceInfo *intf; 4796 NetworkInterfaceInfo *intf;
4799 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 4797 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4800 { 4798 {
4801 if (intf->McastTxRx && !intf->Loopback) 4799 if (intf->McastTxRx && !intf->Loopback)
4802 { 4800 {
4803 // Disallow sleep if this interface doesn't support NetWake 4801 // Disallow sleep if this interface doesn't support NetWake
4804 if (!intf->NetWake) 4802 if (!intf->NetWake)
4805 { 4803 {
4806 allowSleep = mDNSfalse; 4804 allowSleep = mDNSfalse;
4807 mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname); 4805 mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname);
4808 LogInfo("Sleep disabled because %s does not support NetWake", intf->ifname); 4806 LogInfo("Sleep disabled because %s does not support NetWake", intf->ifname);
4809 break; 4807 break;
4810 } 4808 }
4811 4809
4812 // Disallow sleep if there is no sleep proxy server 4810 // Disallow sleep if there is no sleep proxy server
4813 if (FindSPSInCache1(m, &intf->NetWakeBrowse, mDNSNULL, mDNSNULL) == mDNSNULL) 4811 if (FindSPSInCache1(m, &intf->NetWakeBrowse, mDNSNULL, mDNSNULL) == mDNSNULL)
4814 { 4812 {
4815 allowSleep = mDNSfalse; 4813 allowSleep = mDNSfalse;
4816 mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname); 4814 mDNS_snprintf(reason, sizeof(reason), "%s does not support NetWake", intf->ifname);
4817 LogInfo("Sleep disabled because %s has no sleep proxy", intf->ifname); 4815 LogInfo("Sleep disabled because %s has no sleep proxy", intf->ifname);
4818 break; 4816 break;
4819 } 4817 }
4820 } 4818 }
4821 } 4819 }
4822 } 4820 }
4823 } 4821 }
4824  4822
4825 // Call the platform code to enable/disable sleep 4823 // Call the platform code to enable/disable sleep
4826 mDNSPlatformSetAllowSleep(m, allowSleep, reason); 4824 mDNSPlatformSetAllowSleep(m, allowSleep, reason);
4827#endif /* !defined(IDLESLEEPCONTROL_DISABLED) */ 4825#endif /* !defined(IDLESLEEPCONTROL_DISABLED) */
4828 } 4826 }
4829 4827
4830mDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id, const OwnerOptData *const owner) 4828mDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id, const OwnerOptData *const owner)
4831 { 4829 {
4832 const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC); 4830 const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC);
4833 const int sps = intf->NextSPSAttempt / 3; 4831 const int sps = intf->NextSPSAttempt / 3;
4834 AuthRecord *rr; 4832 AuthRecord *rr;
4835 4833
4836 if (!intf->SPSAddr[sps].type) 4834 if (!intf->SPSAddr[sps].type)
4837 { 4835 {
4838 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; 4836 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
4839 if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) 4837 if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
4840 m->NextScheduledSPRetry = intf->NextSPSAttemptTime; 4838 m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
4841 LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c); 4839 LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c);
4842 goto exit; 4840 goto exit;
4843 } 4841 }
4844 4842
4845 // Mark our mDNS records (not unicast records) for transfer to SPS 4843 // Mark our mDNS records (not unicast records) for transfer to SPS
4846 if (mDNSOpaque16IsZero(id)) 4844 if (mDNSOpaque16IsZero(id))
4847 for (rr = m->ResourceRecords; rr; rr=rr->next) 4845 for (rr = m->ResourceRecords; rr; rr=rr->next)
4848 if (rr->resrec.RecordType > kDNSRecordTypeDeregistering) 4846 if (rr->resrec.RecordType > kDNSRecordTypeDeregistering)
4849 if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) 4847 if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name))))
4850 if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner))) 4848 if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner)))
4851 rr->SendRNow = mDNSInterfaceMark; // mark it now 4849 rr->SendRNow = mDNSInterfaceMark; // mark it now
4852 4850
4853 while (1) 4851 while (1)
4854 { 4852 {
4855 mDNSu8 *p = m->omsg.data; 4853 mDNSu8 *p = m->omsg.data;
4856 // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates. 4854 // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates.
4857 // For now we follow that same logic for SPS registrations too. 4855 // For now we follow that same logic for SPS registrations too.
4858 // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our 4856 // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our
4859 // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet. 4857 // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet.
4860 InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags); 4858 InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags);
4861 4859
4862 for (rr = m->ResourceRecords; rr; rr=rr->next) 4860 for (rr = m->ResourceRecords; rr; rr=rr->next)
4863 if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)) 4861 if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0))
4864 if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner))) 4862 if (mDNSPlatformMemSame(owner, &rr->WakeUp, sizeof(*owner)))
4865 { 4863 {
4866 mDNSu8 *newptr; 4864 mDNSu8 *newptr;
4867 const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace; 4865 const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace;
4868 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 4866 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
4869 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it 4867 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
4870 newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit); 4868 newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
4871 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state 4869 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
4872 if (!newptr) 4870 if (!newptr)
4873 LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr)); 4871 LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr));
4874 else 4872 else
4875 { 4873 {
4876 LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr)); 4874 LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr));
4877 rr->SendRNow = mDNSNULL; 4875 rr->SendRNow = mDNSNULL;
4878 rr->ThisAPInterval = mDNSPlatformOneSecond; 4876 rr->ThisAPInterval = mDNSPlatformOneSecond;
4879 rr->LastAPTime = m->timenow; 4877 rr->LastAPTime = m->timenow;
4880 rr->updateid = m->omsg.h.id; 4878 rr->updateid = m->omsg.h.id;
4881 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 4879 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
4882 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); 4880 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
4883 p = newptr; 4881 p = newptr;
4884 } 4882 }
4885 } 4883 }
4886 4884
4887 if (!m->omsg.h.mDNS_numUpdates) break; 4885 if (!m->omsg.h.mDNS_numUpdates) break;
4888 else 4886 else
4889 { 4887 {
4890 AuthRecord opt; 4888 AuthRecord opt;
4891 mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL); 4889 mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
4892 opt.resrec.rrclass = NormalMaxDNSMessageData; 4890 opt.resrec.rrclass = NormalMaxDNSMessageData;
4893 opt.resrec.rdlength = sizeof(rdataOPT) * 2; // Two options in this OPT record 4891 opt.resrec.rdlength = sizeof(rdataOPT) * 2; // Two options in this OPT record
4894 opt.resrec.rdestimate = sizeof(rdataOPT) * 2; 4892 opt.resrec.rdestimate = sizeof(rdataOPT) * 2;
4895 opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 4893 opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease;
4896 opt.resrec.rdata->u.opt[0].optlen = DNSOpt_LeaseData_Space - 4; 4894 opt.resrec.rdata->u.opt[0].optlen = DNSOpt_LeaseData_Space - 4;
4897 opt.resrec.rdata->u.opt[0].u.updatelease = DEFAULT_UPDATE_LEASE; 4895 opt.resrec.rdata->u.opt[0].u.updatelease = DEFAULT_UPDATE_LEASE;
4898 if (!owner->HMAC.l[0]) // If no owner data, 4896 if (!owner->HMAC.l[0]) // If no owner data,
4899 SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]); // use our own interface information 4897 SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]); // use our own interface information
4900 else // otherwise, use the owner data we were given 4898 else // otherwise, use the owner data we were given
4901 { 4899 {
4902 opt.resrec.rdata->u.opt[1].u.owner = *owner; 4900 opt.resrec.rdata->u.opt[1].u.owner = *owner;
4903 opt.resrec.rdata->u.opt[1].opt = kDNSOpt_Owner; 4901 opt.resrec.rdata->u.opt[1].opt = kDNSOpt_Owner;
4904 opt.resrec.rdata->u.opt[1].optlen = DNSOpt_Owner_Space(&owner->HMAC, &owner->IMAC) - 4; 4902 opt.resrec.rdata->u.opt[1].optlen = DNSOpt_Owner_Space(&owner->HMAC, &owner->IMAC) - 4;
4905 } 4903 }
4906 LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt)); 4904 LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt));
4907 p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); 4905 p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
4908 if (!p) 4906 if (!p)
4909 LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt)); 4907 LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt));
4910 else 4908 else
4911 { 4909 {
4912 mStatus err; 4910 mStatus err;
4913 4911
4914 LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps, 4912 LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps,
4915 mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps])); 4913 mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps]));
4916 // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss 4914 // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
4917 err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL); 4915 err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL);
4918 if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err); 4916 if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err);
4919 if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1) 4917 if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1)
4920 { 4918 {
4921 LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c); 4919 LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c);
4922 intf->NetWakeResolve[sps].qtype = kDNSType_A; 4920 intf->NetWakeResolve[sps].qtype = kDNSType_A;
4923 mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]); 4921 mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]);
4924 return; 4922 return;
4925 } 4923 }
4926 } 4924 }
4927 } 4925 }
4928 } 4926 }
4929 4927
4930 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10; // If successful, update NextSPSAttemptTime 4928 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10; // If successful, update NextSPSAttemptTime
4931 4929
4932exit: 4930exit:
4933 if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++; 4931 if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++;
4934 } 4932 }
4935 4933
4936mDNSlocal mDNSBool RecordIsFirstOccurrenceOfOwner(mDNS *const m, const AuthRecord *const rr) 4934mDNSlocal mDNSBool RecordIsFirstOccurrenceOfOwner(mDNS *const m, const AuthRecord *const rr)
4937 { 4935 {
4938 AuthRecord *ar; 4936 AuthRecord *ar;
4939 for (ar = m->ResourceRecords; ar && ar != rr; ar=ar->next) 4937 for (ar = m->ResourceRecords; ar && ar != rr; ar=ar->next)
4940 if (mDNSPlatformMemSame(&rr->WakeUp, &ar->WakeUp, sizeof(rr->WakeUp))) return mDNSfalse; 4938 if (mDNSPlatformMemSame(&rr->WakeUp, &ar->WakeUp, sizeof(rr->WakeUp))) return mDNSfalse;
4941 return mDNStrue; 4939 return mDNStrue;
4942 } 4940 }
4943 4941
4944mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id) 4942mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *const intf, const mDNSOpaque16 id)
4945 { 4943 {
4946 AuthRecord *ar; 4944 AuthRecord *ar;
4947 OwnerOptData owner = zeroOwner; 4945 OwnerOptData owner = zeroOwner;
4948 4946
4949 SendSPSRegistrationForOwner(m, intf, id, &owner); 4947 SendSPSRegistrationForOwner(m, intf, id, &owner);
4950 4948
4951 for (ar = m->ResourceRecords; ar; ar=ar->next) 4949 for (ar = m->ResourceRecords; ar; ar=ar->next)
4952 { 4950 {
4953 if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)) && RecordIsFirstOccurrenceOfOwner(m, ar)) 4951 if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)) && RecordIsFirstOccurrenceOfOwner(m, ar))
4954 { 4952 {
4955 owner = ar->WakeUp; 4953 owner = ar->WakeUp;
4956 SendSPSRegistrationForOwner(m, intf, id, &owner); 4954 SendSPSRegistrationForOwner(m, intf, id, &owner);
4957 } 4955 }
4958 } 4956 }
4959 } 4957 }
4960 4958
4961// RetrySPSRegistrations is called from SendResponses, with the lock held 4959// RetrySPSRegistrations is called from SendResponses, with the lock held
4962mDNSlocal void RetrySPSRegistrations(mDNS *const m) 4960mDNSlocal void RetrySPSRegistrations(mDNS *const m)
4963 { 4961 {
4964 AuthRecord *rr; 4962 AuthRecord *rr;
4965 NetworkInterfaceInfo *intf; 4963 NetworkInterfaceInfo *intf;
4966 4964
4967 // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10 4965 // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10
4968 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 4966 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4969 if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10) 4967 if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10)
4970 intf->NextSPSAttemptTime++; 4968 intf->NextSPSAttemptTime++;
4971 4969
4972 // Retry any record registrations that are due 4970 // Retry any record registrations that are due
4973 for (rr = m->ResourceRecords; rr; rr=rr->next) 4971 for (rr = m->ResourceRecords; rr; rr=rr->next)
4974 if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 4972 if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
4975 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 4973 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4976 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID) 4974 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID)
4977 { 4975 {
4978 LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr)); 4976 LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr));
4979 SendSPSRegistration(m, intf, rr->updateid); 4977 SendSPSRegistration(m, intf, rr->updateid);
4980 } 4978 }
4981 4979
4982 // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt 4980 // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt
4983 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 4981 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4984 if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8) 4982 if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8)
4985 intf->NextSPSAttempt++; 4983 intf->NextSPSAttempt++;
4986 } 4984 }
4987 4985
4988mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 4986mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4989 { 4987 {
4990 NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext; 4988 NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext;
4991 int sps = (int)(question - intf->NetWakeResolve); 4989 int sps = (int)(question - intf->NetWakeResolve);
4992 (void)m; // Unused 4990 (void)m; // Unused
4993 LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer)); 4991 LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer));
4994 4992
4995 if (!AddRecord) return; // Don't care about REMOVE events 4993 if (!AddRecord) return; // Don't care about REMOVE events
4996 if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs 4994 if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs
4997 4995
4998 // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address 4996 // if (answer->rrtype == kDNSType_AAAA && sps == 0) return; // To test failing to resolve sleep proxy's address
4999 4997
5000 if (answer->rrtype == kDNSType_SRV) 4998 if (answer->rrtype == kDNSType_SRV)
5001 { 4999 {
5002 // 1. Got the SRV record; now look up the target host's IPv6 link-local address 5000 // 1. Got the SRV record; now look up the target host's IPv6 link-local address
5003 mDNS_StopQuery(m, question); 5001 mDNS_StopQuery(m, question);
5004 intf->SPSPort[sps] = answer->rdata->u.srv.port; 5002 intf->SPSPort[sps] = answer->rdata->u.srv.port;
5005 AssignDomainName(&question->qname, &answer->rdata->u.srv.target); 5003 AssignDomainName(&question->qname, &answer->rdata->u.srv.target);
5006 question->qtype = kDNSType_AAAA; 5004 question->qtype = kDNSType_AAAA;
5007 mDNS_StartQuery(m, question); 5005 mDNS_StartQuery(m, question);
5008 } 5006 }
5009 else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6)) 5007 else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6))
5010 { 5008 {
5011 // 2. Got the target host's IPv6 link-local address; record address and initiate an SPS registration if appropriate 5009 // 2. Got the target host's IPv6 link-local address; record address and initiate an SPS registration if appropriate
5012 mDNS_StopQuery(m, question); 5010 mDNS_StopQuery(m, question);
5013 question->ThisQInterval = -1; 5011 question->ThisQInterval = -1;
5014 intf->SPSAddr[sps].type = mDNSAddrType_IPv6; 5012 intf->SPSAddr[sps].type = mDNSAddrType_IPv6;
5015 intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6; 5013 intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6;
5016 mDNS_Lock(m); 5014 mDNS_Lock(m);
5017 if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now 5015 if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now
5018 mDNS_Unlock(m); 5016 mDNS_Unlock(m);
5019 } 5017 }
5020 else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0) 5018 else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0)
5021 { 5019 {
5022 // 3. Got negative response -- target host apparently has IPv6 disabled -- so try looking up the target host's IPv4 address(es) instead 5020 // 3. Got negative response -- target host apparently has IPv6 disabled -- so try looking up the target host's IPv4 address(es) instead
5023 mDNS_StopQuery(m, question); 5021 mDNS_StopQuery(m, question);
5024 LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c); 5022 LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c);
5025 question->qtype = kDNSType_A; 5023 question->qtype = kDNSType_A;
5026 mDNS_StartQuery(m, question); 5024 mDNS_StartQuery(m, question);
5027 } 5025 }
5028 else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr)) 5026 else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr))
5029 { 5027 {
5030 // 4. Got an IPv4 address for the target host; record address and initiate an SPS registration if appropriate 5028 // 4. Got an IPv4 address for the target host; record address and initiate an SPS registration if appropriate
5031 mDNS_StopQuery(m, question); 5029 mDNS_StopQuery(m, question);
5032 question->ThisQInterval = -1; 5030 question->ThisQInterval = -1;
5033 intf->SPSAddr[sps].type = mDNSAddrType_IPv4; 5031 intf->SPSAddr[sps].type = mDNSAddrType_IPv4;
5034 intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4; 5032 intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4;
5035 mDNS_Lock(m); 5033 mDNS_Lock(m);
5036 if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now 5034 if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now
5037 mDNS_Unlock(m); 5035 mDNS_Unlock(m);
5038 } 5036 }
5039 } 5037 }
5040 5038
5041mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m) 5039mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m)
5042 { 5040 {
5043 AuthRecord *rr; 5041 AuthRecord *rr;
5044 for (rr = m->ResourceRecords; rr; rr=rr->next) 5042 for (rr = m->ResourceRecords; rr; rr=rr->next)
5045 if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort)) 5043 if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort))
5046 return mDNStrue; 5044 return mDNStrue;
5047 return mDNSfalse; 5045 return mDNSfalse;
5048 } 5046 }
5049 5047
5050mDNSlocal void SendSleepGoodbyes(mDNS *const m) 5048mDNSlocal void SendSleepGoodbyes(mDNS *const m)
5051 { 5049 {
5052 AuthRecord *rr; 5050 AuthRecord *rr;
5053 m->SleepState = SleepState_Sleeping; 5051 m->SleepState = SleepState_Sleeping;
5054 5052
5055#ifndef UNICAST_DISABLED 5053#ifndef UNICAST_DISABLED
5056 SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records 5054 SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records
5057#endif /* UNICAST_DISABLED */ 5055#endif /* UNICAST_DISABLED */
5058 5056
5059 // Mark all the records we need to deregister and send them 5057 // Mark all the records we need to deregister and send them
5060 for (rr = m->ResourceRecords; rr; rr=rr->next) 5058 for (rr = m->ResourceRecords; rr; rr=rr->next)
5061 if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) 5059 if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
5062 rr->ImmedAnswer = mDNSInterfaceMark; 5060 rr->ImmedAnswer = mDNSInterfaceMark;
5063 SendResponses(m); 5061 SendResponses(m);
5064 } 5062 }
5065 5063
5066// BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep 5064// BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep
5067mDNSlocal void BeginSleepProcessing(mDNS *const m) 5065mDNSlocal void BeginSleepProcessing(mDNS *const m)
5068 { 5066 {
5069 mDNSBool SendGoodbyes = mDNStrue; 5067 mDNSBool SendGoodbyes = mDNStrue;
5070 const CacheRecord *sps[3] = { mDNSNULL }; 5068 const CacheRecord *sps[3] = { mDNSNULL };
5071 5069
5072 m->NextScheduledSPRetry = m->timenow; 5070 m->NextScheduledSPRetry = m->timenow;
5073 5071
5074 if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false"); 5072 if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false");
5075 else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services"); 5073 else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services");
5076 else // If we have at least one advertised service 5074 else // If we have at least one advertised service
5077 { 5075 {
5078 NetworkInterfaceInfo *intf; 5076 NetworkInterfaceInfo *intf;
5079 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 5077 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5080 { 5078 {
5081 if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname); 5079 if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname);
5082#if APPLE_OSX_mDNSResponder 5080#if APPLE_OSX_mDNSResponder
5083 else if (ActivateLocalProxy(m, intf->ifname) == mStatus_NoError) 5081 else if (ActivateLocalProxy(m, intf->ifname) == mStatus_NoError)
5084 { 5082 {
5085 SendGoodbyes = mDNSfalse; 5083 SendGoodbyes = mDNSfalse;
5086 LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname); 5084 LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname);
5087 // This will leave m->SleepState set to SleepState_Transferring, 5085 // This will leave m->SleepState set to SleepState_Transferring,
5088 // which is okay because with no outstanding resolves, or updates in flight, 5086 // which is okay because with no outstanding resolves, or updates in flight,
5089 // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed 5087 // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed
5090 } 5088 }
5091#endif // APPLE_OSX_mDNSResponder 5089#endif // APPLE_OSX_mDNSResponder
5092 else 5090 else
5093 { 5091 {
5094 FindSPSInCache(m, &intf->NetWakeBrowse, sps); 5092 FindSPSInCache(m, &intf->NetWakeBrowse, sps);
5095 if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)", 5093 if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)",
5096 intf->ifname, &intf->ip, NextQSendTime(&intf->NetWakeBrowse) - m->timenow, intf->NetWakeBrowse.ThisQInterval); 5094 intf->ifname, &intf->ip, NextQSendTime(&intf->NetWakeBrowse) - m->timenow, intf->NetWakeBrowse.ThisQInterval);
5097 else 5095 else
5098 { 5096 {
5099 int i; 5097 int i;
5100 SendGoodbyes = mDNSfalse; 5098 SendGoodbyes = mDNSfalse;
5101 intf->NextSPSAttempt = 0; 5099 intf->NextSPSAttempt = 0;
5102 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; 5100 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
5103 // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above 5101 // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above
5104 for (i=0; i<3; i++) 5102 for (i=0; i<3; i++)
5105 { 5103 {
5106#if ForceAlerts 5104#if ForceAlerts
5107 if (intf->SPSAddr[i].type) 5105 if (intf->SPSAddr[i].type)
5108 { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; } 5106 { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; }
5109 if (intf->NetWakeResolve[i].ThisQInterval >= 0) 5107 if (intf->NetWakeResolve[i].ThisQInterval >= 0)
5110 { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; } 5108 { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; }
5111#endif 5109#endif
5112 intf->SPSAddr[i].type = mDNSAddrType_None; 5110 intf->SPSAddr[i].type = mDNSAddrType_None;
5113 if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]); 5111 if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]);
5114 intf->NetWakeResolve[i].ThisQInterval = -1; 5112 intf->NetWakeResolve[i].ThisQInterval = -1;
5115 if (sps[i]) 5113 if (sps[i])
5116 { 5114 {
5117 LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i])); 5115 LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i]));
5118 mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf); 5116 mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf);
5119 intf->NetWakeResolve[i].ReturnIntermed = mDNStrue; 5117 intf->NetWakeResolve[i].ReturnIntermed = mDNStrue;
5120 mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]); 5118 mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]);
5121 } 5119 }
5122 } 5120 }
5123 } 5121 }
5124 } 5122 }
5125 } 5123 }
5126 } 5124 }
5127 5125
5128 if (SendGoodbyes) // If we didn't find even one Sleep Proxy 5126 if (SendGoodbyes) // If we didn't find even one Sleep Proxy
5129 { 5127 {
5130 LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server"); 5128 LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server");
5131 SendSleepGoodbyes(m); 5129 SendSleepGoodbyes(m);
5132 } 5130 }
5133 } 5131 }
5134 5132
5135// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep. 5133// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
5136// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up. 5134// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
5137// Normally, the platform support layer below mDNSCore should call this, not the client layer above. 5135// Normally, the platform support layer below mDNSCore should call this, not the client layer above.
5138mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) 5136mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
5139 { 5137 {
5140 AuthRecord *rr; 5138 AuthRecord *rr;
5141 5139
5142 LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow); 5140 LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
5143 5141
5144 if (sleep && !m->SleepState) // Going to sleep 5142 if (sleep && !m->SleepState) // Going to sleep
5145 { 5143 {
5146 mDNS_Lock(m); 5144 mDNS_Lock(m);
5147 // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server 5145 // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
5148 if (m->SPSSocket) 5146 if (m->SPSSocket)
5149 { 5147 {
5150 mDNSu8 oldstate = m->SPSState; 5148 mDNSu8 oldstate = m->SPSState;
5151 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here 5149 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5152 m->SPSState = 2; 5150 m->SPSState = 2;
5153 if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords); 5151 if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords);
5154 mDNS_ReclaimLockAfterCallback(); 5152 mDNS_ReclaimLockAfterCallback();
5155 } 5153 }
5156 5154
5157 m->SleepState = SleepState_Transferring; 5155 m->SleepState = SleepState_Transferring;
5158 if (m->SystemWakeOnLANEnabled && m->DelaySleep) 5156 if (m->SystemWakeOnLANEnabled && m->DelaySleep)
5159 { 5157 {
5160 // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep 5158 // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
5161 LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow); 5159 LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
5162 m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10); 5160 m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10);
5163 } 5161 }
5164 else 5162 else
5165 { 5163 {
5166 m->DelaySleep = 0; 5164 m->DelaySleep = 0;
5167 m->SleepLimit = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 10); 5165 m->SleepLimit = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 10);
5168 BeginSleepProcessing(m); 5166 BeginSleepProcessing(m);
5169 } 5167 }
5170 5168
5171#ifndef UNICAST_DISABLED 5169#ifndef UNICAST_DISABLED
5172 SuspendLLQs(m); 5170 SuspendLLQs(m);
5173#endif 5171#endif
5174 mDNS_Unlock(m); 5172 mDNS_Unlock(m);
5175 // RemoveAutoTunnel6Record needs to be called outside the lock, as it grabs the lock also. 5173 // RemoveAutoTunnel6Record needs to be called outside the lock, as it grabs the lock also.
5176#if APPLE_OSX_mDNSResponder 5174#if APPLE_OSX_mDNSResponder
5177 RemoveAutoTunnel6Record(m); 5175 RemoveAutoTunnel6Record(m);
5178#endif 5176#endif
5179 LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState, 5177 LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
5180 m->SleepState == SleepState_Transferring ? "Transferring" : 5178 m->SleepState == SleepState_Transferring ? "Transferring" :
5181 m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum); 5179 m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum);
5182 } 5180 }
5183 else if (!sleep) // Waking up 5181 else if (!sleep) // Waking up
5184 { 5182 {
5185 mDNSu32 slot; 5183 mDNSu32 slot;
5186 CacheGroup *cg; 5184 CacheGroup *cg;
5187 CacheRecord *cr; 5185 CacheRecord *cr;
5188 NetworkInterfaceInfo *intf; 5186 NetworkInterfaceInfo *intf;
5189 5187
5190 mDNS_Lock(m); 5188 mDNS_Lock(m);
5191 // Reset SleepLimit back to 0 now that we're awake again. 5189 // Reset SleepLimit back to 0 now that we're awake again.
5192 m->SleepLimit = 0; 5190 m->SleepLimit = 0;
5193 5191
5194 // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness 5192 // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness
5195 if (m->SleepState != SleepState_Awake) 5193 if (m->SleepState != SleepState_Awake)
5196 { 5194 {
5197 m->SleepState = SleepState_Awake; 5195 m->SleepState = SleepState_Awake;
5198 m->SleepSeqNum++; 5196 m->SleepSeqNum++;
5199 // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake) 5197 // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
5200 // then we enforce a minimum delay of 16 seconds before we begin sleep processing. 5198 // then we enforce a minimum delay of 16 seconds before we begin sleep processing.
5201 // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc., 5199 // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
5202 // before we make our determination of whether there's a Sleep Proxy out there we should register with. 5200 // before we make our determination of whether there's a Sleep Proxy out there we should register with.
5203 m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16); 5201 m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16);
5204 } 5202 }
5205 5203
5206 if (m->SPSState == 3) 5204 if (m->SPSState == 3)
5207 { 5205 {
5208 m->SPSState = 0; 5206 m->SPSState = 0;
5209 mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower); 5207 mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower);
5210 } 5208 }
5211 5209
5212 // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy, 5210 // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
5213 // on wake we go through our record list and clear updateid back to zero 5211 // on wake we go through our record list and clear updateid back to zero
5214 for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID; 5212 for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID;
5215 5213
5216 // ... and the same for NextSPSAttempt 5214 // ... and the same for NextSPSAttempt
5217 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1; 5215 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1;
5218 5216
5219 // Restart unicast and multicast queries 5217 // Restart unicast and multicast queries
5220 mDNSCoreRestartQueries(m); 5218 mDNSCoreRestartQueries(m);
5221 5219
5222 // and reactivtate service registrations 5220 // and reactivtate service registrations
5223 m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond); 5221 m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
5224 LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow); 5222 LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
5225 5223
5226 // 2. Re-validate our cache records 5224 // 2. Re-validate our cache records
5227 FORALL_CACHERECORDS(slot, cg, cr) 5225 FORALL_CACHERECORDS(slot, cg, cr)
5228 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); 5226 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
5229 5227
5230 // 3. Retrigger probing and announcing for all our authoritative records 5228 // 3. Retrigger probing and announcing for all our authoritative records
5231 for (rr = m->ResourceRecords; rr; rr=rr->next) 5229 for (rr = m->ResourceRecords; rr; rr=rr->next)
5232 if (AuthRecord_uDNS(rr)) 5230 if (AuthRecord_uDNS(rr))
5233 { 5231 {
5234 ActivateUnicastRegistration(m, rr); 5232 ActivateUnicastRegistration(m, rr);
5235 } 5233 }
5236 else 5234 else
5237 { 5235 {
5238 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; 5236 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
5239 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 5237 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
5240 rr->AnnounceCount = InitialAnnounceCount; 5238 rr->AnnounceCount = InitialAnnounceCount;
5241 rr->SendNSECNow = mDNSNULL; 5239 rr->SendNSECNow = mDNSNULL;
5242 InitializeLastAPTime(m, rr); 5240 InitializeLastAPTime(m, rr);
5243 } 5241 }
5244 5242
5245 // 4. Refresh NAT mappings 5243 // 4. Refresh NAT mappings
5246 // We don't want to have to assume that all hardware can necessarily keep accurate 5244 // We don't want to have to assume that all hardware can necessarily keep accurate
5247 // track of passage of time while asleep, so on wake we refresh our NAT mappings 5245 // track of passage of time while asleep, so on wake we refresh our NAT mappings
5248 // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address. 5246 // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address.
5249 // When we get a network configuration change, mDNSMacOSXNetworkChanged calls uDNS_SetupDNSConfig, which calls 5247 // When we get a network configuration change, mDNSMacOSXNetworkChanged calls uDNS_SetupDNSConfig, which calls
5250 // mDNS_SetPrimaryInterfaceInfo, which then sets m->retryGetAddr to immediately request our external address from the NAT gateway. 5248 // mDNS_SetPrimaryInterfaceInfo, which then sets m->retryGetAddr to immediately request our external address from the NAT gateway.
5251 m->retryIntervalGetAddr = NATMAP_INIT_RETRY; 5249 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
5252 m->retryGetAddr = m->timenow + mDNSPlatformOneSecond * 5; 5250 m->retryGetAddr = m->timenow + mDNSPlatformOneSecond * 5;
5253 LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m->retryGetAddr - m->timenow, m->timenow); 5251 LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m->retryGetAddr - m->timenow, m->timenow);
5254 RecreateNATMappings(m); 5252 RecreateNATMappings(m);
5255 mDNS_Unlock(m); 5253 mDNS_Unlock(m);
5256 } 5254 }
5257 } 5255 }
5258 5256
5259mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now) 5257mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
5260 { 5258 {
5261 DNSQuestion *q; 5259 DNSQuestion *q;
5262 AuthRecord *rr; 5260 AuthRecord *rr;
5263 NetworkInterfaceInfo *intf; 5261 NetworkInterfaceInfo *intf;
5264 5262
5265 mDNS_Lock(m); 5263 mDNS_Lock(m);
5266 5264
5267 if (m->DelaySleep) goto notready; 5265 if (m->DelaySleep) goto notready;
5268 5266
5269 // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks 5267 // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks
5270 if (m->SleepLimit - now > 0 && m->NextScheduledSPRetry - now > 0) goto notready; 5268 if (m->SleepLimit - now > 0 && m->NextScheduledSPRetry - now > 0) goto notready;
5271 5269
5272 m->NextScheduledSPRetry = now + 0x40000000UL; 5270 m->NextScheduledSPRetry = now + 0x40000000UL;
5273 5271
5274 // See if we might need to retransmit any lost Sleep Proxy Registrations 5272 // See if we might need to retransmit any lost Sleep Proxy Registrations
5275 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 5273 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5276 if (intf->NextSPSAttempt >= 0) 5274 if (intf->NextSPSAttempt >= 0)
5277 { 5275 {
5278 if (now - intf->NextSPSAttemptTime >= 0) 5276 if (now - intf->NextSPSAttemptTime >= 0)
5279 { 5277 {
5280 LogSPS("mDNSCoreReadyForSleep: retrying for %s SPS %d try %d", 5278 LogSPS("mDNSCoreReadyForSleep: retrying for %s SPS %d try %d",
5281 intf->ifname, intf->NextSPSAttempt/3, intf->NextSPSAttempt); 5279 intf->ifname, intf->NextSPSAttempt/3, intf->NextSPSAttempt);
5282 SendSPSRegistration(m, intf, zeroID); 5280 SendSPSRegistration(m, intf, zeroID);
5283 // Don't need to "goto notready" here, because if we do still have record registrations 5281 // Don't need to "goto notready" here, because if we do still have record registrations
5284 // that have not been acknowledged yet, we'll catch that in the record list scan below. 5282 // that have not been acknowledged yet, we'll catch that in the record list scan below.
5285 } 5283 }
5286 else 5284 else
5287 if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) 5285 if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
5288 m->NextScheduledSPRetry = intf->NextSPSAttemptTime; 5286 m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
5289 } 5287 }
5290 5288
5291 // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete 5289 // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete
5292 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 5290 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5293 { 5291 {
5294 int sps = (intf->NextSPSAttempt == 0) ? 0 : (intf->NextSPSAttempt-1)/3; 5292 int sps = (intf->NextSPSAttempt == 0) ? 0 : (intf->NextSPSAttempt-1)/3;
5295 if (intf->NetWakeResolve[sps].ThisQInterval >= 0) 5293 if (intf->NetWakeResolve[sps].ThisQInterval >= 0)
5296 { 5294 {
5297 LogSPS("mDNSCoreReadyForSleep: waiting for SPS Resolve %s %##s (%s)", 5295 LogSPS("mDNSCoreReadyForSleep: waiting for SPS Resolve %s %##s (%s)",
5298 intf->ifname, intf->NetWakeResolve[sps].qname.c, DNSTypeName(intf->NetWakeResolve[sps].qtype)); 5296 intf->ifname, intf->NetWakeResolve[sps].qname.c, DNSTypeName(intf->NetWakeResolve[sps].qtype));
5299 goto spsnotready; 5297 goto spsnotready;
5300 } 5298 }
5301 } 5299 }
5302 5300
5303 // Scan list of registered records 5301 // Scan list of registered records
5304 for (rr = m->ResourceRecords; rr; rr = rr->next) 5302 for (rr = m->ResourceRecords; rr; rr = rr->next)
5305 if (!AuthRecord_uDNS(rr)) 5303 if (!AuthRecord_uDNS(rr))
5306 if (!mDNSOpaque16IsZero(rr->updateid)) 5304 if (!mDNSOpaque16IsZero(rr->updateid))
5307 { LogSPS("mDNSCoreReadyForSleep: waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; } 5305 { LogSPS("mDNSCoreReadyForSleep: waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; }
5308 5306
5309 // Scan list of private LLQs, and make sure they've all completed their handshake with the server 5307 // Scan list of private LLQs, and make sure they've all completed their handshake with the server
5310 for (q = m->Questions; q; q = q->next) 5308 for (q = m->Questions; q; q = q->next)
5311 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) 5309 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp)
5312 { 5310 {
5313 LogSPS("mDNSCoreReadyForSleep: waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 5311 LogSPS("mDNSCoreReadyForSleep: waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5314 goto notready; 5312 goto notready;
5315 } 5313 }
5316 5314
5317 // Scan list of registered records 5315 // Scan list of registered records
5318 for (rr = m->ResourceRecords; rr; rr = rr->next) 5316 for (rr = m->ResourceRecords; rr; rr = rr->next)
5319 if (AuthRecord_uDNS(rr)) 5317 if (AuthRecord_uDNS(rr))
5320 { 5318 {
5321 if (rr->state == regState_Refresh && rr->tcp) 5319 if (rr->state == regState_Refresh && rr->tcp)
5322 { LogSPS("mDNSCoreReadyForSleep: waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } 5320 { LogSPS("mDNSCoreReadyForSleep: waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
5323 #if APPLE_OSX_mDNSResponder 5321 #if APPLE_OSX_mDNSResponder
5324 if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; } 5322 if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; }
5325 #endif 5323 #endif
5326 } 5324 }
5327 5325
5328 mDNS_Unlock(m); 5326 mDNS_Unlock(m);
5329 return mDNStrue; 5327 return mDNStrue;
5330 5328
5331spsnotready: 5329spsnotready:
5332 5330
5333 // If we failed to complete sleep proxy registration within ten seconds, we give up on that 5331 // If we failed to complete sleep proxy registration within ten seconds, we give up on that
5334 // and allow up to ten seconds more to complete wide-area deregistration instead 5332 // and allow up to ten seconds more to complete wide-area deregistration instead
5335 if (now - m->SleepLimit >= 0) 5333 if (now - m->SleepLimit >= 0)
5336 { 5334 {
5337 LogMsg("Failed to register with SPS, now sending goodbyes"); 5335 LogMsg("Failed to register with SPS, now sending goodbyes");
5338 5336
5339 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 5337 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5340 if (intf->NetWakeBrowse.ThisQInterval >= 0) 5338 if (intf->NetWakeBrowse.ThisQInterval >= 0)
5341 { 5339 {
5342 LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)", 5340 LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)",
5343 intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype)); 5341 intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
5344 mDNS_DeactivateNetWake_internal(m, intf); 5342 mDNS_DeactivateNetWake_internal(m, intf);
5345 } 5343 }
5346 5344
5347 for (rr = m->ResourceRecords; rr; rr = rr->next) 5345 for (rr = m->ResourceRecords; rr; rr = rr->next)
5348 if (!AuthRecord_uDNS(rr)) 5346 if (!AuthRecord_uDNS(rr))
5349 if (!mDNSOpaque16IsZero(rr->updateid)) 5347 if (!mDNSOpaque16IsZero(rr->updateid))
5350 { 5348 {
5351 LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m, rr)); 5349 LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m, rr));
5352 rr->updateid = zeroID; 5350 rr->updateid = zeroID;
5353 } 5351 }
5354 5352
5355 // We'd really like to allow up to ten seconds more here, 5353 // We'd really like to allow up to ten seconds more here,
5356 // but if we don't respond to the sleep notification within 30 seconds 5354 // but if we don't respond to the sleep notification within 30 seconds
5357 // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake. 5355 // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake.
5358 // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds 5356 // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds
5359 // more for SPS resolves and record registrations to complete, which puts us at 26 seconds. 5357 // more for SPS resolves and record registrations to complete, which puts us at 26 seconds.
5360 // If we allow just one more second to send our goodbyes, that puts us at 27 seconds. 5358 // If we allow just one more second to send our goodbyes, that puts us at 27 seconds.
5361 m->SleepLimit = now + mDNSPlatformOneSecond * 1; 5359 m->SleepLimit = now + mDNSPlatformOneSecond * 1;
5362 5360
5363 SendSleepGoodbyes(m); 5361 SendSleepGoodbyes(m);
5364 } 5362 }
5365 5363
5366notready: 5364notready:
5367 mDNS_Unlock(m); 5365 mDNS_Unlock(m);
5368 return mDNSfalse; 5366 return mDNSfalse;
5369 } 5367 }
5370 5368
5371mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now) 5369mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now)
5372 { 5370 {
5373 AuthRecord *ar; 5371 AuthRecord *ar;
5374 5372
5375 // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other 5373 // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other
5376 // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed. 5374 // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed.
5377 // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment, 5375 // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment,
5378 // and if that happens we don't want to just give up and go back to sleep and never try again. 5376 // and if that happens we don't want to just give up and go back to sleep and never try again.
5379 mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes 5377 mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes
5380 5378
5381 NATTraversalInfo *nat; 5379 NATTraversalInfo *nat;
5382 for (nat = m->NATTraversals; nat; nat=nat->next) 5380 for (nat = m->NATTraversals; nat; nat=nat->next)
5383 if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4) 5381 if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4)
5384 { 5382 {
5385 mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time 5383 mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time
5386 if (e - t > 0) e = t; 5384 if (e - t > 0) e = t;
5387 LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d", 5385 LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d",
5388 nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP", 5386 nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP",
5389 mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result, 5387 mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result,
5390 nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0, 5388 nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
5391 nat->retryInterval / mDNSPlatformOneSecond, 5389 nat->retryInterval / mDNSPlatformOneSecond,
5392 nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0, 5390 nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
5393 (t - now) / mDNSPlatformOneSecond); 5391 (t - now) / mDNSPlatformOneSecond);
5394 } 5392 }
5395 5393
5396 // This loop checks both the time we need to renew wide-area registrations, 5394 // This loop checks both the time we need to renew wide-area registrations,
5397 // and the time we need to renew Sleep Proxy registrations 5395 // and the time we need to renew Sleep Proxy registrations
5398 for (ar = m->ResourceRecords; ar; ar = ar->next) 5396 for (ar = m->ResourceRecords; ar; ar = ar->next)
5399 if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4) 5397 if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4)
5400 { 5398 {
5401 mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time 5399 mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time
5402 if (e - t > 0) e = t; 5400 if (e - t > 0) e = t;
5403 LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s", 5401 LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s",
5404 ar, ar->ThisAPInterval / mDNSPlatformOneSecond, 5402 ar, ar->ThisAPInterval / mDNSPlatformOneSecond,
5405 (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, 5403 (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
5406 ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, 5404 ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
5407 (t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar)); 5405 (t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar));
5408 } 5406 }
5409 5407
5410 return(e - now); 5408 return(e - now);
5411 } 5409 }
5412 5410
5413// *************************************************************************** 5411// ***************************************************************************
5414#if COMPILER_LIKES_PRAGMA_MARK 5412#if COMPILER_LIKES_PRAGMA_MARK
5415#pragma mark - 5413#pragma mark -
5416#pragma mark - Packet Reception Functions 5414#pragma mark - Packet Reception Functions
5417#endif 5415#endif
5418 5416
5419#define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo) 5417#define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
5420 5418
5421mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end, 5419mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end,
5422 const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords) 5420 const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords)
5423 { 5421 {
5424 mDNSu8 *responseptr = response->data; 5422 mDNSu8 *responseptr = response->data;
5425 const mDNSu8 *const limit = response->data + sizeof(response->data); 5423 const mDNSu8 *const limit = response->data + sizeof(response->data);
5426 const mDNSu8 *ptr = query->data; 5424 const mDNSu8 *ptr = query->data;
5427 AuthRecord *rr; 5425 AuthRecord *rr;
5428 mDNSu32 maxttl = 0x70000000; 5426 mDNSu32 maxttl = 0x70000000;
5429 int i; 5427 int i;
5430 5428
5431 // Initialize the response fields so we can answer the questions 5429 // Initialize the response fields so we can answer the questions
5432 InitializeDNSMessage(&response->h, query->h.id, ResponseFlags); 5430 InitializeDNSMessage(&response->h, query->h.id, ResponseFlags);
5433 5431
5434 // *** 5432 // ***
5435 // *** 1. Write out the list of questions we are actually going to answer with this packet 5433 // *** 1. Write out the list of questions we are actually going to answer with this packet
5436 // *** 5434 // ***
5437 if (LegacyQuery) 5435 if (LegacyQuery)
5438 { 5436 {
5439 maxttl = kStaticCacheTTL; 5437 maxttl = kStaticCacheTTL;
5440 for (i=0; i<query->h.numQuestions; i++) // For each question... 5438 for (i=0; i<query->h.numQuestions; i++) // For each question...
5441 { 5439 {
5442 DNSQuestion q; 5440 DNSQuestion q;
5443 ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question... 5441 ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question...
5444 if (!ptr) return(mDNSNULL); 5442 if (!ptr) return(mDNSNULL);
5445  5443
5446 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers 5444 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers
5447 { 5445 {
5448 if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question 5446 if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question
5449 { // then put the question in the question section 5447 { // then put the question in the question section
5450 responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass); 5448 responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass);
5451 if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); } 5449 if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); }
5452 break; // break out of the ResponseRecords loop, and go on to the next question 5450 break; // break out of the ResponseRecords loop, and go on to the next question
5453 } 5451 }
5454 } 5452 }
5455 } 5453 }
5456  5454
5457 if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); } 5455 if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); }
5458 } 5456 }
5459 5457
5460 // *** 5458 // ***
5461 // *** 2. Write Answers 5459 // *** 2. Write Answers
5462 // *** 5460 // ***
5463 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5461 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5464 if (rr->NR_AnswerTo) 5462 if (rr->NR_AnswerTo)
5465 { 5463 {
5466 mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, 5464 mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec,
5467 maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); 5465 maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl);
5468 if (p) responseptr = p; 5466 if (p) responseptr = p;
5469 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; } 5467 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; }
5470 } 5468 }
5471 5469
5472 // *** 5470 // ***
5473 // *** 3. Write Additionals 5471 // *** 3. Write Additionals
5474 // *** 5472 // ***
5475 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5473 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5476 if (rr->NR_AdditionalTo && !rr->NR_AnswerTo) 5474 if (rr->NR_AdditionalTo && !rr->NR_AnswerTo)
5477 { 5475 {
5478 mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, 5476 mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec,
5479 maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); 5477 maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl);
5480 if (p) responseptr = p; 5478 if (p) responseptr = p;
5481 else debugf("GenerateUnicastResponse: No more space for additionals"); 5479 else debugf("GenerateUnicastResponse: No more space for additionals");
5482 } 5480 }
5483 5481
5484 return(responseptr); 5482 return(responseptr);
5485 } 5483 }
5486 5484
5487// AuthRecord *our is our Resource Record 5485// AuthRecord *our is our Resource Record
5488// CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network 5486// CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
5489// Returns 0 if there is no conflict 5487// Returns 0 if there is no conflict
5490// Returns +1 if there was a conflict and we won 5488// Returns +1 if there was a conflict and we won
5491// Returns -1 if there was a conflict and we lost and have to rename 5489// Returns -1 if there was a conflict and we lost and have to rename
5492mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt) 5490mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt)
5493 { 5491 {
5494 mDNSu8 ourdata[256], *ourptr = ourdata, *ourend; 5492 mDNSu8 ourdata[256], *ourptr = ourdata, *ourend;
5495 mDNSu8 pktdata[256], *pktptr = pktdata, *pktend; 5493 mDNSu8 pktdata[256], *pktptr = pktdata, *pktend;
5496 if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); } 5494 if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
5497 if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); } 5495 if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
5498 5496
5499 ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec); 5497 ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
5500 pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec); 5498 pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
5501 while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; } 5499 while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
5502 if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict 5500 if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict
5503 5501
5504 if (ourptr >= ourend) return(-1); // Our data ran out first; We lost 5502 if (ourptr >= ourend) return(-1); // Our data ran out first; We lost
5505 if (pktptr >= pktend) return(+1); // Packet data ran out first; We won 5503 if (pktptr >= pktend) return(+1); // Packet data ran out first; We won
5506 if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost 5504 if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost
5507 if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won 5505 if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won
5508  5506
5509 LogMsg("CompareRData ERROR: Invalid state"); 5507 LogMsg("CompareRData ERROR: Invalid state");
5510 return(-1); 5508 return(-1);