mDNS.c revision 4904:cd464a980538
1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (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
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
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.
19 *
20 * The previous point is very important: This file does not depend on any external
21 * header files. It should complile on *any* platform that has a C compiler, without
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).
24
25 * Formatting notes:
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>,
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;
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.
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;"
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
36 * layout leads people to unfortunate misunderstandings about how the C language really works.)
37
38    Change History (most recent first):
39
40$Log: mDNS.c,v $
41Revision 1.537.2.1  2006/08/29 06:24:22  cheshire
42Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
43
44Revision 1.537  2006/03/19 02:00:07  cheshire
45<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
46
47Revision 1.536  2006/03/08 23:29:53  cheshire
48<rdar://problem/4468716> Improve "Service Renamed" log message
49
50Revision 1.535  2006/03/02 20:41:17  cheshire
51<rdar://problem/4111464> After record update, old record sometimes remains in cache
52Minor code tidying and comments to reduce the risk of similar programming errors in future
53
54Revision 1.534  2006/03/02 03:25:46  cheshire
55<rdar://problem/4111464> After record update, old record sometimes remains in cache
56Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
57
58Revision 1.533  2006/02/26 00:54:41  cheshire
59Fixes to avoid code generation warning/error on FreeBSD 7
60
61Revision 1.532  2005/12/02 20:24:36  cheshire
62<rdar://problem/4363209> Adjust cutoff time for KA list by one second
63
64Revision 1.531  2005/12/02 19:05:42  cheshire
65Tidy up constants
66
67Revision 1.530  2005/11/07 01:49:48  cheshire
68For consistency, use NonZeroTime() function instead of ?: expression
69
70Revision 1.529  2005/10/25 23:42:24  cheshire
71<rdar://problem/4316057> Error in ResolveSimultaneousProbe() when type or class don't match
72Changed switch statement to an "if"
73
74Revision 1.528  2005/10/25 23:34:22  cheshire
75<rdar://problem/4316048> RequireGoodbye state not set/respected sometimes when machine going to sleep
76
77Revision 1.527  2005/10/25 22:43:59  cheshire
78Add clarifying comments
79
80Revision 1.526  2005/10/20 00:10:33  cheshire
81<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
82
83Revision 1.525  2005/09/24 00:47:17  cheshire
84Fix comment typos
85
86Revision 1.524  2005/09/16 21:06:49  cheshire
87Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
88
89Revision 1.523  2005/03/21 00:33:51  shersche
90<rdar://problem/4021486> Fix build warnings on Win32 platform
91
92Revision 1.522  2005/03/04 21:48:12  cheshire
93<rdar://problem/4037283> Fractional time rounded down instead of up on platforms with coarse clock granularity
94
95Revision 1.521  2005/02/25 04:21:00  cheshire
96<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
97
98Revision 1.520  2005/02/16 01:14:11  cheshire
99Convert RR Cache LogOperation() calls to debugf()
100
101Revision 1.519  2005/02/15 01:57:20  cheshire
102When setting "q->LastQTxTime = m->timenow", must also clear q->RecentAnswerPkts to zero
103
104Revision 1.518  2005/02/10 22:35:17  cheshire
105<rdar://problem/3727944> Update name
106
107Revision 1.517  2005/02/03 00:21:21  cheshire
108Update comments about BIND named and zero-length TXT records
109
110Revision 1.516  2005/01/28 06:06:32  cheshire
111Update comment
112
113Revision 1.515  2005/01/27 00:21:49  cheshire
114<rdar://problem/3973798> Remove mDNSResponder sleep/wake syslog message
115
116Revision 1.514  2005/01/21 01:33:45  cheshire
117<rdar://problem/3962979> Shutdown time regression: mDNSResponder not responding to SIGTERM
118
119Revision 1.513  2005/01/21 00:07:54  cheshire
120<rdar://problem/3962717> Infinite loop when the same service is registered twice, and then suffers a name conflict
121
122Revision 1.512  2005/01/20 00:37:45  cheshire
123<rdar://problem/3941448> mDNSResponder crashed in mDNSCoreReceiveResponse
124Take care not to recycle records while they are on the CacheFlushRecords list
125
126Revision 1.511  2005/01/19 22:48:53  cheshire
127<rdar://problem/3955355> Handle services with subtypes correctly when doing mDNS_RenameAndReregisterService()
128
129Revision 1.510  2005/01/19 03:12:45  cheshire
130Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
131
132Revision 1.509  2005/01/19 03:08:49  cheshire
133<rdar://problem/3961051> CPU Spin in mDNSResponder
134Log messages to help catch and report CPU spins
135
136Revision 1.508  2005/01/18 18:56:32  cheshire
137<rdar://problem/3934245> QU responses not promoted to multicast responses when appropriate
138
139Revision 1.507  2005/01/18 01:12:07  cheshire
140<rdar://problem/3956258> Logging into VPN causes mDNSResponder to reissue multicast probes
141
142Revision 1.506  2005/01/17 23:28:53  cheshire
143Fix compile error
144
145Revision 1.505  2005/01/11 02:02:56  shersche
146Move variable declaration to the beginning of statement block
147
148Revision 1.504  2004/12/20 20:24:35  cheshire
149<rdar://problem/3928456> Network efficiency: Don't keep polling if we have at least one unique-type answer
150
151Revision 1.503  2004/12/20 18:41:47  cheshire
152<rdar://problem/3591622> Low memory support: Provide answers even when we don't have cache space
153
154Revision 1.502  2004/12/20 18:04:08  cheshire
155<rdar://problem/3923098> For now, don't put standard wide-area unicast responses in our main cache
156
157Revision 1.501  2004/12/19 23:50:18  cheshire
158<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
159Don't show "No active interface to send" messages for kDNSServiceInterfaceIndexLocalOnly services
160
161Revision 1.500  2004/12/18 03:13:46  cheshire
162<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
163
164Revision 1.499  2004/12/17 23:37:45  cheshire
165<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
166(and other repetitive configuration changes)
167
168Revision 1.498  2004/12/17 05:25:46  cheshire
169<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
170
171Revision 1.497  2004/12/17 03:20:58  cheshire
172<rdar://problem/3925168> Don't send unicast replies we know will be ignored
173
174Revision 1.496  2004/12/16 22:18:26  cheshire
175Make AddressIsLocalSubnet() a little more selective -- ignore point-to-point interfaces
176
177Revision 1.495  2004/12/16 21:27:37  ksekar
178Fixed build failures when compiled with verbose debugging messages
179
180Revision 1.494  2004/12/16 20:46:56  cheshire
181Fix compiler warnings
182
183Revision 1.493  2004/12/16 20:13:00  cheshire
184<rdar://problem/3324626> Cache memory management improvements
185
186Revision 1.492  2004/12/16 08:03:24  shersche
187Fix compilation error when UNICAST_DISABLED is set
188
189Revision 1.491  2004/12/11 01:52:11  cheshire
190<rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
191
192Revision 1.490  2004/12/10 20:06:25  cheshire
193<rdar://problem/3915074> Reduce egregious stack space usage
194Reduced SendDelayedUnicastResponse() stack frame from 9K to 112 bytes
195
196Revision 1.489  2004/12/10 20:03:43  cheshire
197<rdar://problem/3915074> Reduce egregious stack space usage
198Reduced mDNSCoreReceiveQuery() stack frame from 9K to 144 bytes
199
200Revision 1.488  2004/12/10 19:50:41  cheshire
201<rdar://problem/3915074> Reduce egregious stack space usage
202Reduced SendResponses() stack frame from 9K to 176 bytes
203
204Revision 1.487  2004/12/10 19:39:13  cheshire
205<rdar://problem/3915074> Reduce egregious stack space usage
206Reduced SendQueries() stack frame from 18K to 112 bytes
207
208Revision 1.486  2004/12/10 14:16:17  cheshire
209<rdar://problem/3889788> Relax update rate limiting
210We now allow an average rate of ten updates per minute.
211Updates in excess of that are rate limited, but more gently than before.
212
213Revision 1.485  2004/12/10 02:09:24  cheshire
214<rdar://problem/3898376> Modify default TTLs
215
216Revision 1.484  2004/12/09 03:15:40  ksekar
217<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
218
219Revision 1.483  2004/12/07 23:00:14  ksekar
220<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration:
221Call RecordProbeFailure even if there is no record callback
222
223Revision 1.482  2004/12/07 22:49:06  cheshire
224<rdar://problem/3908850> BIND doesn't allow zero-length TXT records
225
226Revision 1.481  2004/12/07 21:26:04  ksekar
227<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
228
229Revision 1.480  2004/12/07 20:42:33  cheshire
230Add explicit context parameter to mDNS_RemoveRecordFromService()
231
232Revision 1.479  2004/12/07 17:50:49  ksekar
233<rdar://problem/3908850> BIND doesn't allow zero-length TXT records
234
235Revision 1.478  2004/12/06 21:15:22  ksekar
236<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
237
238Revision 1.477  2004/12/04 02:12:45  cheshire
239<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
240
241Revision 1.476  2004/11/29 23:34:31  cheshire
242On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
243is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
244only nudges the time value to 1 if the interval calculation happens to result in the value zero.
245
246Revision 1.475  2004/11/29 23:13:31  cheshire
247<rdar://problem/3484552> All unique records in a set should have the cache flush bit set
248Additional check: Make sure we don't unnecessarily send packets containing only additionals.
249(This could occur with multi-packet KA lists, if the answer and additionals were marked
250by the query packet, and then the answer were later suppressed in a subsequent KA packet.)
251
252Revision 1.474  2004/11/29 17:18:12  cheshire
253Remove "Unknown DNS packet type" message for update responses
254
255Revision 1.473  2004/11/25 01:57:52  cheshire
256<rdar://problem/3484552> All unique records in a set should have the cache flush bit set
257
258Revision 1.472  2004/11/25 01:28:09  cheshire
259<rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
260
261Revision 1.471  2004/11/25 01:10:13  cheshire
262Move code to add additional records to a subroutine called AddAdditionalsToResponseList()
263
264Revision 1.470  2004/11/24 21:54:44  cheshire
265<rdar://problem/3894475> mDNSCore not receiving unicast responses properly
266
267Revision 1.469  2004/11/24 04:50:39  cheshire
268Minor tidying
269
270Revision 1.468  2004/11/24 01:47:07  cheshire
271<rdar://problem/3780207> DNSServiceRegisterRecord should call CallBack on success.
272
273Revision 1.467  2004/11/24 01:41:28  cheshire
274Rename CompleteProbing() to AcknowledgeRecord()
275
276Revision 1.466  2004/11/23 21:08:07  ksekar
277Don't use ID to demux multicast/unicast now that unicast uses random IDs
278
279Revision 1.465  2004/11/15 20:09:21  ksekar
280<rdar://problem/3719050> Wide Area support for Add/Remove record
281
282Revision 1.464  2004/11/03 01:44:36  cheshire
283Update debugging messages
284
285Revision 1.463  2004/10/29 02:38:48  cheshire
286Fix Windows compile errors
287
288Revision 1.462  2004/10/28 19:21:07  cheshire
289Guard against registering interface with zero InterfaceID
290
291Revision 1.461  2004/10/28 19:02:16  cheshire
292Remove \n from LogMsg() call
293
294Revision 1.460  2004/10/28 03:24:40  cheshire
295Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
296
297Revision 1.459  2004/10/26 22:34:37  cheshire
298<rdar://problem/3468995> Need to protect mDNSResponder from unbounded packet flooding
299
300Revision 1.458  2004/10/26 20:45:28  cheshire
301Show mask in "invalid mask" message
302
303Revision 1.457  2004/10/26 06:28:36  cheshire
304Now that we don't check IP TTL any more, remove associated log message
305
306Revision 1.456  2004/10/26 06:21:42  cheshire
307Adjust mask validity check to allow an all-ones mask (for IPv6 ::1 loopback address)
308
309Revision 1.455  2004/10/26 06:11:40  cheshire
310Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
311
312Revision 1.454  2004/10/23 01:16:00  cheshire
313<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
314
315Revision 1.453  2004/10/22 20:52:06  ksekar
316<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
317
318Revision 1.452  2004/10/20 01:50:40  cheshire
319<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
320Implemented ForceMCast mode for AuthRecords as well as for Questions
321
322Revision 1.451  2004/10/19 21:33:15  cheshire
323<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
324Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
325doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
326
327Revision 1.450  2004/10/19 17:42:59  ksekar
328Fixed compiler warnings for non-debug builds.
329
330Revision 1.449  2004/10/18 22:57:07  cheshire
331<rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
332
333Revision 1.448  2004/10/16 00:16:59  cheshire
334<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
335
336Revision 1.447  2004/10/15 00:51:21  cheshire
337<rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
338
339Revision 1.446  2004/10/14 00:43:34  cheshire
340<rdar://problem/3815984> Services continue to announce SRV and HINFO
341
342Revision 1.445  2004/10/12 21:07:09  cheshire
343Set up m->p in mDNS_Init() before calling mDNSPlatformTimeInit()
344
345Revision 1.444  2004/10/11 17:54:16  ksekar
346Changed hashtable pointer output from debugf to verbosedebugf.
347
348Revision 1.443  2004/10/10 07:05:45  cheshire
349For consistency, use symbol "localdomain" instead of literal string
350
351Revision 1.442  2004/10/08 20:25:10  cheshire
352Change of plan for <rdar://problem/3831716> -- we're not going to do that at this time
353
354Revision 1.441  2004/10/08 03:25:01  ksekar
355<rdar://problem/3831716> domain enumeration should use LLQs
356
357Revision 1.440  2004/10/06 01:44:19  cheshire
358<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
359
360Revision 1.439  2004/10/03 23:14:11  cheshire
361Add "mDNSEthAddr" type and "zeroEthAddr" constant
362
363Revision 1.438  2004/09/29 23:07:04  cheshire
364Patch from Pavel Repin to fix compile error on Windows
365
366Revision 1.437  2004/09/28 02:23:50  cheshire
367<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
368Don't need to search the entire cache for nearly-expired records -- just the appropriate hash slot
369For records with the cache flush bit set, defer the decision until the end of the packet
370
371Revision 1.436  2004/09/28 01:27:04  cheshire
372Update incorrect log message
373
374Revision 1.435  2004/09/25 02:41:39  cheshire
375<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
376
377Revision 1.434  2004/09/25 02:32:06  cheshire
378Update comments
379
380Revision 1.433  2004/09/25 02:24:27  cheshire
381Removed unused rr->UseCount
382
383Revision 1.432  2004/09/24 21:35:17  cheshire
384<rdar://problem/3561220> Browses are no longer piggybacking on other browses
385TargetPort and TargetQID are allowed to be undefined if no question->Target is set
386
387Revision 1.431  2004/09/24 21:33:12  cheshire
388Adjust comment
389
390Revision 1.430  2004/09/24 02:15:49  cheshire
391<rdar://problem/3680865> Late conflicts don't send goodbye packets on other interfaces
392
393Revision 1.429  2004/09/24 00:20:21  cheshire
394<rdar://problem/3483349> Any rrtype is a conflict for unique records
395
396Revision 1.428  2004/09/24 00:12:25  cheshire
397Get rid of unused RRUniqueOrKnownUnique(RR)
398
399Revision 1.427  2004/09/23 20:44:11  cheshire
400<rdar://problem/3813148> Reduce timeout before expiring records on failure
401
402Revision 1.426  2004/09/23 20:21:07  cheshire
403<rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
404Associate a unique sequence number with each received packet, and only increment the count of recent answer
405packets if the packet sequence number for this answer record is not one we've already seen and counted.
406
407Revision 1.425  2004/09/23 20:14:38  cheshire
408Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
409
410Revision 1.424  2004/09/23 00:58:36  cheshire
411<rdar://problem/3781269> Rate limiting interferes with updating TXT records
412
413Revision 1.423  2004/09/23 00:50:53  cheshire
414<rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
415
416Revision 1.422  2004/09/22 02:34:46  cheshire
417Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
418
419Revision 1.421  2004/09/21 23:29:49  cheshire
420<rdar://problem/3680045> DNSServiceResolve should delay sending packets
421
422Revision 1.420  2004/09/21 23:01:42  cheshire
423Update debugf messages
424
425Revision 1.419  2004/09/21 19:51:14  cheshire
426Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
427
428Revision 1.418  2004/09/21 18:40:17  cheshire
429<rdar://problem/3376752> Adjust default record TTLs
430
431Revision 1.417  2004/09/21 17:32:16  cheshire
432<rdar://problem/3809484> Rate limiting imposed too soon
433
434Revision 1.416  2004/09/20 23:52:01  cheshire
435CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
436
437Revision 1.415  2004/09/18 01:14:09  cheshire
438<rdar://problem/3485375> Resolve() should not bother doing AAAA queries on machines with no IPv6 interfaces
439
440Revision 1.414  2004/09/18 01:06:48  cheshire
441Add comments
442
443Revision 1.413  2004/09/17 01:08:48  cheshire
444Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
445  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
446  declared in that file are ONLY appropriate to single-address-space embedded applications.
447  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
448
449Revision 1.412  2004/09/17 00:46:33  cheshire
450mDNS_TimeNow should take const mDNS parameter
451
452Revision 1.411  2004/09/17 00:31:51  cheshire
453For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
454
455Revision 1.410  2004/09/17 00:19:10  cheshire
456For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
457
458Revision 1.409  2004/09/16 21:59:15  cheshire
459For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
460
461Revision 1.408  2004/09/16 21:36:36  cheshire
462<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
463Changes to add necessary locking calls around unicast DNS operations
464
465Revision 1.407  2004/09/16 02:29:39  cheshire
466Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
467uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
468
469Revision 1.406  2004/09/16 01:58:14  cheshire
470Fix compiler warnings
471
472Revision 1.405  2004/09/16 00:24:48  cheshire
473<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
474
475Revision 1.404  2004/09/15 21:44:11  cheshire
476<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
477Show time value in log to help diagnose errors
478
479Revision 1.403  2004/09/15 00:46:32  ksekar
480Changed debugf to verbosedebugf in CheckCacheExpiration
481
482Revision 1.402  2004/09/14 23:59:55  cheshire
483<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
484
485Revision 1.401  2004/09/14 23:27:46  cheshire
486Fix compile errors
487
488Revision 1.400  2004/09/02 03:48:47  cheshire
489<rdar://problem/3709039> Disable targeted unicast query support by default
4901. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
4912. New field AllowRemoteQuery in AuthRecord structure
4923. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
4934. mDNS.c only answers remote queries if AllowRemoteQuery is set
494
495Revision 1.399  2004/09/02 01:39:40  cheshire
496For better readability, follow consistent convention that QR bit comes first, followed by OP bits
497
498Revision 1.398  2004/09/01 03:59:29  ksekar
499<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
500
501Revision 1.397  2004/08/25 22:04:25  rpantos
502Fix the standard Windows compile error.
503
504Revision 1.396  2004/08/25 00:37:27  ksekar
505<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
506
507Revision 1.395  2004/08/18 17:21:18  ksekar
508Removed double-call of uDNS_AdvertiseInterface from mDNS_SetFQDNs()
509
510Revision 1.394  2004/08/14 03:22:41  cheshire
511<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
512Add GetUserSpecifiedDDNSName() routine
513Convert ServiceRegDomain to domainname instead of C string
514Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
515
516Revision 1.393  2004/08/13 23:42:52  cheshire
517Removed unused "zeroDomainNamePtr"
518
519Revision 1.392  2004/08/13 23:37:02  cheshire
520Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
521"uDNS_info.UnicastHostname" for clarity
522
523Revision 1.391  2004/08/13 23:25:00  cheshire
524Now that we do both uDNS and mDNS, global replace "m->hostname" with
525"m->MulticastHostname" for clarity
526
527Revision 1.390  2004/08/11 02:17:01  cheshire
528<rdar://problem/3514236> Registering service with port number 0 should create a "No Such Service" record
529
530Revision 1.389  2004/08/10 23:19:14  ksekar
531<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
532Moved routines/constants to allow extern access for garbage collection daemon
533
534Revision 1.388  2004/07/30 17:40:06  ksekar
535<rdar://problem/3739115>: TXT Record updates not available for wide-area services
536
537Revision 1.387  2004/07/26 22:49:30  ksekar
538<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
539
540Revision 1.386  2004/07/13 21:24:24  rpantos
541Fix for <rdar://problem/3701120>.
542
543Revision 1.385  2004/06/18 19:09:59  cheshire
544<rdar://problem/3588761> Current method of doing subtypes causes name collisions
545
546Revision 1.384  2004/06/15 04:31:23  cheshire
547Make sure to clear m->CurrentRecord at the end of AnswerNewLocalOnlyQuestion()
548
549Revision 1.383  2004/06/11 00:04:59  cheshire
550<rdar://problem/3595602> TTL must be greater than zero for DNSServiceRegisterRecord
551
552Revision 1.382  2004/06/08 04:59:40  cheshire
553Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
554
555Revision 1.381  2004/06/05 00:57:30  cheshire
556Remove incorrect LogMsg()
557
558Revision 1.380  2004/06/05 00:04:26  cheshire
559<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
560
561Revision 1.379  2004/05/28 23:42:36  ksekar
562<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
563
564Revision 1.378  2004/05/25 17:25:25  cheshire
565Remove extraneous blank lines and white space
566
567Revision 1.377  2004/05/18 23:51:25  cheshire
568Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
569
570Revision 1.376  2004/05/05 18:30:44  ksekar
571Restored surpressed Cache Tail debug messages.
572
573Revision 1.375  2004/04/26 21:36:25  cheshire
574Only send IPv4 (or v6) multicast when IPv4 (or v6) multicast send/receive
575is indicated as being available on that interface
576
577Revision 1.374  2004/04/21 02:53:26  cheshire
578Typo in debugf statement
579
580Revision 1.373  2004/04/21 02:49:11  cheshire
581To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
582
583Revision 1.372  2004/04/21 02:38:51  cheshire
584Add debugging checks
585
586Revision 1.371  2004/04/14 23:09:28  ksekar
587Support for TSIG signed dynamic updates.
588
589Revision 1.370  2004/04/09 17:40:26  cheshire
590Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
591
592Revision 1.369  2004/04/09 16:34:00  cheshire
593Debugging code for later; currently unused
594
595Revision 1.368  2004/04/02 19:19:48  cheshire
596Add code to do optional logging of multi-packet KA list time intervals
597
598Revision 1.367  2004/03/20 03:16:10  cheshire
599Minor refinement to "Excessive update rate" message
600
601Revision 1.366  2004/03/20 03:12:57  cheshire
602<rdar://problem/3587619>: UpdateCredits not granted promptly enough
603
604Revision 1.365  2004/03/19 23:51:22  cheshire
605Change to use symbolic constant kUpdateCreditRefreshInterval instead of (mDNSPlatformOneSecond * 60)
606
607Revision 1.364  2004/03/13 01:57:33  ksekar
608<rdar://problem/3192546>: DynDNS: Dynamic update of service records
609
610Revision 1.363  2004/03/12 21:00:51  cheshire
611Also show port numbers when logging "apparent spoof mDNS Response" messages
612
613Revision 1.362  2004/03/12 08:58:18  cheshire
614Guard against empty TXT records
615
616Revision 1.361  2004/03/09 03:00:46  cheshire
617<rdar://problem/3581961> Don't take lock until after mDNS_Update() has validated that the data is good.
618
619Revision 1.360  2004/03/08 02:52:41  cheshire
620Minor debugging fix: Make sure 'target' is initialized so we don't crash writing debugging log messages
621
622Revision 1.359  2004/03/02 03:21:56  cheshire
623<rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
624
625Revision 1.358  2004/02/20 08:18:34  cheshire
626<rdar://problem/3564799>: mDNSResponder sometimes announces AAAA records unnecessarily
627
628Revision 1.357  2004/02/18 01:47:41  cheshire
629<rdar://problem/3553472>: Insufficient delay waiting for multi-packet KA lists causes AirPort traffic storms
630
631Revision 1.356  2004/02/06 23:04:19  ksekar
632Basic Dynamic Update support via mDNS_Register (dissabled via
633UNICAST_REGISTRATION #define)
634
635Revision 1.355  2004/02/05 09:32:33  cheshire
636Fix from Bob Bradley: When using the "%.*s" string form,
637guard against truncating in the middle of a multi-byte UTF-8 character.
638
639Revision 1.354  2004/02/05 09:30:22  cheshire
640Update comments
641
642Revision 1.353  2004/01/28 03:41:00  cheshire
643<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
644
645Revision 1.352  2004/01/28 02:30:07  ksekar
646Added default Search Domains to unicast browsing, controlled via
647Networking sharing prefs pane.  Stopped sending unicast messages on
648every interface.  Fixed unicast resolving via mach-port API.
649
650Revision 1.351  2004/01/27 20:15:22  cheshire
651<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
652
653Revision 1.350  2004/01/24 23:38:16  cheshire
654Use mDNSVal16() instead of shifting and ORing operations
655
656Revision 1.349  2004/01/23 23:23:14  ksekar
657Added TCP support for truncated unicast messages.
658
659Revision 1.348  2004/01/22 03:54:11  cheshire
660Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
661which means "do this query via multicast, even if it's apparently a unicast domain"
662
663Revision 1.347  2004/01/22 03:50:49  cheshire
664If the client has specified an explicit InterfaceID, then do query by multicast, not unicast
665
666Revision 1.346  2004/01/22 03:48:41  cheshire
667Make sure uDNS client doesn't accidentally use query ID zero
668
669Revision 1.345  2004/01/22 03:43:08  cheshire
670Export constants like mDNSInterface_LocalOnly so that the client layers can use them
671
672Revision 1.344  2004/01/21 21:53:18  cheshire
673<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
674
675Revision 1.343  2003/12/23 00:07:47  cheshire
676Make port number in debug message be five-character field, left justified
677
678Revision 1.342  2003/12/20 01:34:28  cheshire
679<rdar://problem/3515876>: Error putting additional records into packets
680Another fix from Rampi: responseptr needs to be updated inside the "for" loop,
681after every record, not once at the end.
682
683Revision 1.341  2003/12/18 22:56:12  cheshire
684<rdar://problem/3510798>: Reduce syslog messages about ignored spoof packets
685
686Revision 1.340  2003/12/16 02:31:37  cheshire
687Minor update to comments
688
689Revision 1.339  2003/12/13 05:50:33  bradley
690Fixed crash with mDNS_Lock/Unlock being called for the initial GrowCache before the platform
691layer has been initialized. Protect mDNS_reentrancy when completing the core initialization to
692fix a race condition during async initialization. Fixed buffer overrun for 1 byte mDNS_snprintf.
693
694Revision 1.338  2003/12/13 03:05:27  ksekar
695<rdar://problem/3192548>: DynDNS: Unicast query of service records
696
697Revision 1.337  2003/12/01 21:46:05  cheshire
698mDNS_StartQuery returns mStatus_BadInterfaceErr if the specified interface does not exist
699
700Revision 1.336  2003/12/01 21:26:19  cheshire
701Guard against zero-length sbuffer in mDNS_vsnprintf()
702
703Revision 1.335  2003/12/01 20:27:48  cheshire
704Display IPv6 addresses correctly (e.g. in log messages) on little-endian processors
705
706Revision 1.334  2003/11/20 22:59:53  cheshire
707Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
708Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
709
710Revision 1.333  2003/11/20 20:49:53  cheshire
711Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
712
713Revision 1.332  2003/11/20 05:47:37  cheshire
714<rdar://problem/3490355>: Don't exclude known answers whose expiry time is before the next query
715Now that we only include answers in the known answer list if they are less than
716halfway to expiry, the check to also see if we have another query scheduled
717before the record expires is no longer necessary (and in fact, not correct).
718
719Revision 1.331  2003/11/19 22:31:48  cheshire
720When automatically adding A records to SRVs, add them as additionals, not answers
721
722Revision 1.330  2003/11/19 22:28:50  cheshire
723Increment/Decrement mDNS_reentrancy around calls to m->MainCallback()
724to allow client to make mDNS calls (specifically the call to mDNS_GrowCache())
725
726Revision 1.329  2003/11/19 22:19:24  cheshire
727Show log message when ignoring packets with bad TTL.
728This is to help diagnose problems on Linux versions that may not report the TTL reliably.
729
730Revision 1.328  2003/11/19 22:06:38  cheshire
731Show log messages when a service or hostname is renamed
732
733Revision 1.327  2003/11/19 22:03:44  cheshire
734Move common "m->NextScheduledResponse = m->timenow" to before "if" statement
735
736Revision 1.326  2003/11/17 22:27:02  cheshire
737Another fix from ramaprasad.kr@hp.com: Improve reply delay computation
738on platforms that have native clock rates below fifty ticks per second.
739
740Revision 1.325  2003/11/17 20:41:44  cheshire
741Fix some missing mDNS_Lock(m)/mDNS_Unlock(m) calls.
742
743Revision 1.324  2003/11/17 20:36:32  cheshire
744Function rename: Remove "mDNS_" prefix from AdvertiseInterface() and
745DeadvertiseInterface() -- they're internal private routines, not API routines.
746
747Revision 1.323  2003/11/14 20:59:08  cheshire
748Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
749Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
750
751Revision 1.322  2003/11/14 19:47:52  cheshire
752Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
753
754Revision 1.321  2003/11/14 19:18:34  cheshire
755Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
756
757Revision 1.320  2003/11/13 06:45:04  cheshire
758Fix compiler warning on certain compilers
759
760Revision 1.319  2003/11/13 00:47:40  cheshire
761<rdar://problem/3437556> We should delay AAAA record query if A record already in cache.
762
763Revision 1.318  2003/11/13 00:33:26  cheshire
764Change macro "RRIsAddressType" to "RRTypeIsAddressType"
765
766Revision 1.317  2003/11/13 00:10:49  cheshire
767<rdar://problem/3436412>: Verify that rr data is different before updating.
768
769Revision 1.316  2003/11/08 23:37:54  cheshire
770Give explicit zero initializers to blank static structure, required by certain compilers.
771(Thanks to ramaprasad.kr@hp.com for reporting this.)
772
773Revision 1.315  2003/11/07 03:32:56  cheshire
774<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
775This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
776purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
777to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
778can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
779
780Revision 1.314  2003/11/07 03:19:49  cheshire
781Minor variable renaming for clarity
782
783Revision 1.313  2003/11/07 03:14:49  cheshire
784Previous checkin proved to be overly simplistic; reversing
785
786Revision 1.312  2003/11/03 23:45:15  cheshire
787<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
788Build cache lists in FIFO order, not customary C LIFO order
789(Append new elements to tail of cache list, instead of prepending at the head.)
790
791Revision 1.311  2003/10/09 18:00:11  cheshire
792Another compiler warning fix.
793
794Revision 1.310  2003/10/07 20:27:05  cheshire
795Patch from Bob Bradley, to fix warning and compile error on Windows
796
797Revision 1.309  2003/09/26 01:06:36  cheshire
798<rdar://problem/3427923> Set kDNSClass_UniqueRRSet bit for updates too
799Made new routine HaveSentEntireRRSet() to check if flag should be set
800
801Revision 1.308  2003/09/23 01:05:01  cheshire
802Minor changes to comments and debugf() message
803
804Revision 1.307  2003/09/09 20:13:30  cheshire
805<rdar://problem/3411105> Don't send a Goodbye record if we never announced it
806Ammend checkin 1.304: Off-by-one error: By this place in the function we've already decremented
807rr->AnnounceCount, so the check needs to be for InitialAnnounceCount-1, not InitialAnnounceCount
808
809Revision 1.306  2003/09/09 03:00:03  cheshire
810<rdar://problem/3413099> Services take a long time to disappear when switching networks.
811Added two constants: kDefaultReconfirmTimeForNoAnswer and kDefaultReconfirmTimeForCableDisconnect
812
813Revision 1.305  2003/09/09 02:49:31  cheshire
814<rdar://problem/3413975> Initial probes and queries not grouped on wake-from-sleep
815
816Revision 1.304  2003/09/09 02:41:19  cheshire
817<rdar://problem/3411105> Don't send a Goodbye record if we never announced it
818
819Revision 1.303  2003/09/05 19:55:02  cheshire
820<rdar://problem/3409533> Include address records when announcing SRV records
821
822Revision 1.302  2003/09/05 00:01:36  cheshire
823<rdar://problem/3407549> Don't accelerate queries that have large KA lists
824
825Revision 1.301  2003/09/04 22:51:13  cheshire
826<rdar://problem/3398213> Group probes and goodbyes better
827
828Revision 1.300  2003/09/03 02:40:37  cheshire
829<rdar://problem/3404842> mDNSResponder complains about '_'s
830Underscores are not supposed to be legal in standard DNS names, but IANA appears
831to have allowed them in previous service name registrations, so we should too.
832
833Revision 1.299  2003/09/03 02:33:09  cheshire
834<rdar://problem/3404795> CacheRecordRmv ERROR
835Don't update m->NewQuestions until *after* CheckCacheExpiration();
836
837Revision 1.298  2003/09/03 01:47:01  cheshire
838<rdar://problem/3319418> Services always in a state of flux
839Change mDNS_Reconfirm_internal() minimum timeout from 5 seconds to 45-60 seconds
840
841Revision 1.297  2003/08/29 19:44:15  cheshire
842<rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
8431. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
844   that already have at least one unique answer in the cache
8452. For these queries, go straight to QM, skipping QU
846
847Revision 1.296  2003/08/29 19:08:21  cheshire
848<rdar://problem/3400986> Traffic reduction: Eliminate huge KA lists after wake from sleep
849Known answers are no longer eligible to go in the KA list if they are more than half-way to their expiry time.
850
851Revision 1.295  2003/08/28 01:10:59  cheshire
852<rdar://problem/3396034> Add syslog message to report when query is reset because of immediate answer burst
853
854Revision 1.294  2003/08/27 02:30:22  cheshire
855<rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
856One more change: "query->GotTXT" is now a straightforward bi-state boolean again
857
858Revision 1.293  2003/08/27 02:25:31  cheshire
859<rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
860
861Revision 1.292  2003/08/21 19:27:36  cheshire
862<rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
863
864Revision 1.291  2003/08/21 18:57:44  cheshire
865<rdar://problem/3387140> Synchronized queries on the network
866
867Revision 1.290  2003/08/21 02:25:23  cheshire
868Minor changes to comments and debugf() messages
869
870Revision 1.289  2003/08/21 02:21:50  cheshire
871<rdar://problem/3386473> Efficiency: Reduce repeated queries
872
873Revision 1.288  2003/08/20 23:39:30  cheshire
874<rdar://problem/3344098> Review syslog messages, and remove as appropriate
875
876Revision 1.287  2003/08/20 20:47:18  cheshire
877Fix compiler warning
878
879Revision 1.286  2003/08/20 02:18:51  cheshire
880<rdar://problem/3344098> Cleanup: Review syslog messages
881
882Revision 1.285  2003/08/20 01:59:06  cheshire
883<rdar://problem/3384478> rdatahash and rdnamehash not updated after changing rdata
884Made new routine SetNewRData() to update rdlength, rdestimate, rdatahash and rdnamehash in one place
885
886Revision 1.284  2003/08/19 22:20:00  cheshire
887<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
888More minor refinements
889
890Revision 1.283  2003/08/19 22:16:27  cheshire
891Minor fix: Add missing "mDNS_Unlock(m);" in mDNS_DeregisterInterface() error case.
892
893Revision 1.282  2003/08/19 06:48:25  cheshire
894<rdar://problem/3376552> Guard against excessive record updates
895Each record starts with 10 UpdateCredits.
896Every update consumes one UpdateCredit.
897UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
898As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
899When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
900
901Revision 1.281  2003/08/19 04:49:28  cheshire
902<rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
9031. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
9042. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
9053. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
906
907Revision 1.280  2003/08/19 02:33:36  cheshire
908Update comments
909
910Revision 1.279  2003/08/19 02:31:11  cheshire
911<rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
912Final expiration queries now only mark the question for sending on the particular interface
913pertaining to the record that's expiring.
914
915Revision 1.278  2003/08/18 22:53:37  cheshire
916<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
917
918Revision 1.277  2003/08/18 19:05:44  cheshire
919<rdar://problem/3382423> UpdateRecord not working right
920Added "newrdlength" field to hold new length of updated rdata
921
922Revision 1.276  2003/08/16 03:39:00  cheshire
923<rdar://problem/3338440> InterfaceID -1 indicates "local only"
924
925Revision 1.275  2003/08/16 02:51:27  cheshire
926<rdar://problem/3366590> mDNSResponder takes too much RPRVT
927Don't try to compute namehash etc, until *after* validating the name
928
929Revision 1.274  2003/08/16 01:12:40  cheshire
930<rdar://problem/3366590> mDNSResponder takes too much RPRVT
931Now that the minimum rdata object size has been reduced to 64 bytes, it is no longer safe to do a
932simple C structure assignment of a domainname, because that object is defined to be 256 bytes long,
933and in the process of copying it, the C compiler may run off the end of the rdata object into
934unmapped memory. All assignments of domainname objects of uncertain size are now replaced with a
935call to the macro AssignDomainName(), which is careful to copy only as many bytes as are valid.
936
937Revision 1.273  2003/08/15 20:16:02  cheshire
938<rdar://problem/3366590> mDNSResponder takes too much RPRVT
939We want to avoid touching the rdata pages, so we don't page them in.
9401. RDLength was stored with the rdata, which meant touching the page just to find the length.
941   Moved this from the RData to the ResourceRecord object.
9422. To avoid unnecessarily touching the rdata just to compare it,
943   compute a hash of the rdata and store the hash in the ResourceRecord object.
944
945Revision 1.272  2003/08/14 19:29:04  cheshire
946<rdar://problem/3378473> Include cache records in SIGINFO output
947Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
948
949Revision 1.271  2003/08/14 02:17:05  cheshire
950<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
951
952Revision 1.270  2003/08/13 17:07:28  ksekar
953<rdar://problem/3376458>: Extra RR linked to list even if registration fails - causes crash
954Added check to result of mDNS_Register() before linking extra record into list.
955
956Revision 1.269  2003/08/12 19:56:23  cheshire
957Update to APSL 2.0
958
959Revision 1.268  2003/08/12 15:01:10  cheshire
960Add comments
961
962Revision 1.267  2003/08/12 14:59:27  cheshire
963<rdar://problem/3374490> Rate-limiting blocks some legitimate responses
964When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
965whether to suppress the response, also check LastMCInterface to see if it matches.
966
967Revision 1.266  2003/08/12 12:47:16  cheshire
968In mDNSCoreMachineSleep debugf message, display value of m->timenow
969
970Revision 1.265  2003/08/11 20:04:28  cheshire
971<rdar://problem/3366553> Improve efficiency by restricting cases where we have to walk the entire cache
972
973Revision 1.264  2003/08/09 00:55:02  cheshire
974<rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
975Don't scan the whole cache after every packet.
976
977Revision 1.263  2003/08/09 00:35:29  cheshire
978Moved AnswerNewQuestion() later in the file, in preparation for next checkin
979
980Revision 1.262  2003/08/08 19:50:33  cheshire
981<rdar://problem/3370332> Remove "Cache size now xxx" messages
982
983Revision 1.261  2003/08/08 19:18:45  cheshire
984<rdar://problem/3271219> Only retrigger questions on platforms with the "PhantomInterfaces" bug
985
986Revision 1.260  2003/08/08 18:55:48  cheshire
987<rdar://problem/3370365> Guard against time going backwards
988
989Revision 1.259  2003/08/08 18:36:04  cheshire
990<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
991
992Revision 1.258  2003/08/08 16:22:05  cheshire
993<rdar://problem/3335473> Need to check validity of TXT (and other) records
994Remove unneeded LogMsg
995
996Revision 1.257  2003/08/07 01:41:08  cheshire
997<rdar://problem/3367346> Ignore packets with invalid source address (all zeroes or all ones)
998
999Revision 1.256  2003/08/06 23:25:51  cheshire
1000<rdar://problem/3290674> Increase TTL for A/AAAA/SRV from one minute to four
1001
1002Revision 1.255  2003/08/06 23:22:50  cheshire
1003Add symbolic constants: kDefaultTTLforUnique (one minute) and kDefaultTTLforShared (two hours)
1004
1005Revision 1.254  2003/08/06 21:33:39  cheshire
1006Fix compiler warnings on PocketPC 2003 (Windows CE)
1007
1008Revision 1.253  2003/08/06 20:43:57  cheshire
1009<rdar://problem/3335473> Need to check validity of TXT (and other) records
1010Created ValidateDomainName() and ValidateRData(), used by mDNS_Register_internal() and mDNS_Update()
1011
1012Revision 1.252  2003/08/06 20:35:47  cheshire
1013Enhance debugging routine GetRRDisplayString() so it can also be used to display
1014other RDataBody objects, not just the one currently attached the given ResourceRecord
1015
1016Revision 1.251  2003/08/06 19:07:34  cheshire
1017<rdar://problem/3366251> mDNSResponder not inhibiting multicast responses as much as it should
1018Was checking LastAPTime instead of LastMCTime
1019
1020Revision 1.250  2003/08/06 19:01:55  cheshire
1021Update comments
1022
1023Revision 1.249  2003/08/06 00:13:28  cheshire
1024Tidy up debugf messages
1025
1026Revision 1.248  2003/08/05 22:20:15  cheshire
1027<rdar://problem/3330324> Need to check IP TTL on responses
1028
1029Revision 1.247  2003/08/05 00:56:39  cheshire
1030<rdar://problem/3357075> mDNSResponder sending additional records, even after precursor record suppressed
1031
1032Revision 1.246  2003/08/04 19:20:49  cheshire
1033Add kDNSQType_ANY to list in DNSTypeName() so it can be displayed in debugging messages
1034
1035Revision 1.245  2003/08/02 01:56:29  cheshire
1036For debugging: log message if we ever get more than one question in a truncated packet
1037
1038Revision 1.244  2003/08/01 23:55:32  cheshire
1039Fix for compiler warnings on Windows, submitted by Bob Bradley
1040
1041Revision 1.243  2003/07/25 02:26:09  cheshire
1042Typo: FIxed missing semicolon
1043
1044Revision 1.242  2003/07/25 01:18:41  cheshire
1045Fix memory leak on shutdown in mDNS_Close() (detected in Windows version)
1046
1047Revision 1.241  2003/07/23 21:03:42  cheshire
1048Only show "Found record..." debugf message in verbose mode
1049
1050Revision 1.240  2003/07/23 21:01:11  cheshire
1051<rdar://problem/3340584> Need Nagle-style algorithm to coalesce multiple packets into one
1052After sending a packet, suppress further sending for the next 100ms.
1053
1054Revision 1.239  2003/07/22 01:30:05  cheshire
1055<rdar://problem/3329099> Don't try to add the same question to the duplicate-questions list more than once
1056
1057Revision 1.238  2003/07/22 00:10:20  cheshire
1058<rdar://problem/3337355> ConvertDomainLabelToCString() needs to escape escape characters
1059
1060Revision 1.237  2003/07/19 03:23:13  cheshire
1061<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
1062
1063Revision 1.236  2003/07/19 03:04:55  cheshire
1064Fix warnings; some debugf message improvements
1065
1066Revision 1.235  2003/07/19 00:03:32  cheshire
1067<rdar://problem/3160248> ScheduleNextTask needs to be smarter after a no-op packet is received
1068ScheduleNextTask is quite an expensive operation.
1069We don't need to do all that work after receiving a no-op packet that didn't change our state.
1070
1071Revision 1.234  2003/07/18 23:52:11  cheshire
1072To improve consistency of field naming, global search-and-replace:
1073NextProbeTime    -> NextScheduledProbe
1074NextResponseTime -> NextScheduledResponse
1075
1076Revision 1.233  2003/07/18 00:29:59  cheshire
1077<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
1078
1079Revision 1.232  2003/07/18 00:11:38  cheshire
1080Add extra case to switch statements to handle HINFO data for Get, Put and Display
1081(In all but GetRDLength(), this is is just a fall-through to kDNSType_TXT)
1082
1083Revision 1.231  2003/07/18 00:06:37  cheshire
1084To make code a little easier to read in GetRDLength(), search-and-replace "rr->rdata->u." with "rd->"
1085
1086Revision 1.230  2003/07/17 18:16:54  cheshire
1087<rdar://problem/3319418> Services always in a state of flux
1088In preparation for working on this, made some debugf messages a little more selective
1089
1090Revision 1.229  2003/07/17 17:35:04  cheshire
1091<rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
1092
1093Revision 1.228  2003/07/16 20:50:27  cheshire
1094<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
1095
1096Revision 1.227  2003/07/16 05:01:36  cheshire
1097Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
1098<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
1099
1100Revision 1.226  2003/07/16 04:51:44  cheshire
1101Fix use of constant 'mDNSPlatformOneSecond' where it should have said 'InitialQuestionInterval'
1102
1103Revision 1.225  2003/07/16 04:46:41  cheshire
1104Minor wording cleanup: The correct DNS term is "response", not "reply"
1105
1106Revision 1.224  2003/07/16 04:39:02  cheshire
1107Textual cleanup (no change to functionality):
1108Construct "c >= 'A' && c <= 'Z'" appears in too many places; replaced with macro "mDNSIsUpperCase(c)"
1109
1110Revision 1.223  2003/07/16 00:09:22  cheshire
1111Textual cleanup (no change to functionality):
1112Construct "((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" appears in too many places;
1113replace with macro "TicksTTL(rr)"
1114Construct "rr->TimeRcvd + ((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)"
1115replaced with macro "RRExpireTime(rr)"
1116
1117Revision 1.222  2003/07/15 23:40:46  cheshire
1118Function rename: UpdateDupSuppressInfo() is more accurately called ExpireDupSuppressInfo()
1119
1120Revision 1.221  2003/07/15 22:17:56  cheshire
1121<rdar://problem/3328394> mDNSResponder is not being efficient when doing certain queries
1122
1123Revision 1.220  2003/07/15 02:12:51  cheshire
1124Slight tidy-up of debugf messages and comments
1125
1126Revision 1.219  2003/07/15 01:55:12  cheshire
1127<rdar://problem/3315777> Need to implement service registration with subtypes
1128
1129Revision 1.218  2003/07/14 16:26:06  cheshire
1130<rdar://problem/3324795> Duplicate query suppression not working right
1131Refinement: Don't record DS information for a question in the first quarter second
1132right after we send it -- in the case where a question happens to be accelerated by
1133the maximum allowed amount, we don't want it to then be suppressed because the previous
1134time *we* sent that question falls (just) within the valid duplicate suppression window.
1135
1136Revision 1.217  2003/07/13 04:43:53  cheshire
1137<rdar://problem/3325169> Services on multiple interfaces not always resolving
1138Minor refinement: No need to make address query broader than the original SRV query that provoked it
1139
1140Revision 1.216  2003/07/13 03:13:17  cheshire
1141<rdar://problem/3325169> Services on multiple interfaces not always resolving
1142If we get an identical SRV on a second interface, convert address queries to non-specific
1143
1144Revision 1.215  2003/07/13 02:28:00  cheshire
1145<rdar://problem/3325166> SendResponses didn't all its responses
1146Delete all references to RRInterfaceActive -- it's now superfluous
1147
1148Revision 1.214  2003/07/13 01:47:53  cheshire
1149Fix one error and one warning in the Windows build
1150
1151Revision 1.213  2003/07/12 04:25:48  cheshire
1152Fix minor signed/unsigned warnings
1153
1154Revision 1.212  2003/07/12 01:59:11  cheshire
1155Minor changes to debugf messages
1156
1157Revision 1.211  2003/07/12 01:47:01  cheshire
1158<rdar://problem/3324495> After name conflict, appended number should be higher than previous number
1159
1160Revision 1.210  2003/07/12 01:43:28  cheshire
1161<rdar://problem/3324795> Duplicate query suppression not working right
1162The correct cutoff time for duplicate query suppression is timenow less one-half the query interval.
1163The code was incorrectly using the last query time plus one-half the query interval.
1164This was only correct in the case where query acceleration was not in effect.
1165
1166Revision 1.209  2003/07/12 01:27:50  cheshire
1167<rdar://problem/3320079> Hostname conflict naming should not use two hyphens
1168Fix missing "-1" in RemoveLabelSuffix()
1169
1170Revision 1.208  2003/07/11 01:32:38  cheshire
1171Syntactic cleanup (no change to funcationality): Now that we only have one host name,
1172rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
1173
1174Revision 1.207  2003/07/11 01:28:00  cheshire
1175<rdar://problem/3161289> No more local.arpa
1176
1177Revision 1.206  2003/07/11 00:45:02  cheshire
1178<rdar://problem/3321909> Client should get callback confirming successful host name registration
1179
1180Revision 1.205  2003/07/11 00:40:18  cheshire
1181Tidy up debug message in HostNameCallback()
1182
1183Revision 1.204  2003/07/11 00:20:32  cheshire
1184<rdar://problem/3320087> mDNSResponder should log a message after 16 unsuccessful probes
1185
1186Revision 1.203  2003/07/10 23:53:41  cheshire
1187<rdar://problem/3320079> Hostname conflict naming should not use two hyphens
1188
1189Revision 1.202  2003/07/04 02:23:20  cheshire
1190<rdar://problem/3311955> Responder too aggressive at flushing stale data
1191Changed mDNSResponder to require four unanswered queries before purging a record, instead of two.
1192
1193Revision 1.201  2003/07/04 01:09:41  cheshire
1194<rdar://problem/3315775> Need to implement subtype queries
1195Modified ConstructServiceName() to allow three-part service types
1196
1197Revision 1.200  2003/07/03 23:55:26  cheshire
1198Minor change to wording of syslog warning messages
1199
1200Revision 1.199  2003/07/03 23:51:13  cheshire
1201<rdar://problem/3315652>:	Lots of "have given xxx answers" syslog warnings
1202Added more detailed debugging information
1203
1204Revision 1.198  2003/07/03 22:19:30  cheshire
1205<rdar://problem/3314346> Bug fix in 3274153 breaks TiVo
1206Make exception to allow _tivo_servemedia._tcp.
1207
1208Revision 1.197  2003/07/02 22:33:05  cheshire
1209<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1210Minor refinements:
1211When cache is exhausted, verify that rrcache_totalused == rrcache_size and report if not
1212Allow cache to grow to 512 records before considering it a potential denial-of-service attack
1213
1214Revision 1.196  2003/07/02 21:19:45  cheshire
1215<rdar://problem/3313413> Update copyright notices, etc., in source code comments
1216
1217Revision 1.195  2003/07/02 19:56:58  cheshire
1218<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1219Minor refinement: m->rrcache_active was not being decremented when
1220an active record was deleted because its TTL expired
1221
1222Revision 1.194  2003/07/02 18:47:40  cheshire
1223Minor wording change to log messages
1224
1225Revision 1.193  2003/07/02 02:44:13  cheshire
1226Fix warning in non-debug build
1227
1228Revision 1.192  2003/07/02 02:41:23  cheshire
1229<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1230
1231Revision 1.191  2003/07/02 02:30:51  cheshire
1232HashSlot() returns an array index. It can't be negative; hence it should not be signed.
1233
1234Revision 1.190  2003/06/27 00:03:05  vlubet
1235<rdar://problem/3304625> Merge of build failure fix for gcc 3.3
1236
1237Revision 1.189  2003/06/11 19:24:03  cheshire
1238<rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
1239Slight refinement to previous checkin
1240
1241Revision 1.188  2003/06/10 20:33:28  cheshire
1242<rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
1243
1244Revision 1.187  2003/06/10 04:30:44  cheshire
1245<rdar://problem/3286234> Need to re-probe/re-announce on configuration change
1246Only interface-specific records were re-probing and re-announcing, not non-specific records.
1247
1248Revision 1.186  2003/06/10 04:24:39  cheshire
1249<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
1250Some additional refinements:
1251Don't try to do this for unicast-response queries
1252better tracking of Qs and KAs in multi-packet KA lists
1253
1254Revision 1.185  2003/06/10 03:52:49  cheshire
1255Update comments and debug messages
1256
1257Revision 1.184  2003/06/10 02:26:39  cheshire
1258<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
1259Make mDNS_Reconfirm() call mDNS_Lock(), like the other API routines
1260
1261Revision 1.183  2003/06/09 18:53:13  cheshire
1262Simplify some debugf() statements (replaced block of 25 lines with 2 lines)
1263
1264Revision 1.182  2003/06/09 18:38:42  cheshire
1265<rdar://problem/3285082> Need to be more tolerant when there are mDNS proxies on the network
1266Only issue a correction if the TTL in the proxy packet is less than half the correct value.
1267
1268Revision 1.181  2003/06/07 06:45:05  cheshire
1269<rdar://problem/3283666> No need for multiple machines to all be sending the same queries
1270
1271Revision 1.180  2003/06/07 06:31:07  cheshire
1272Create little four-line helper function "FindIdenticalRecordInCache()"
1273
1274Revision 1.179  2003/06/07 06:28:13  cheshire
1275For clarity, change name of "DNSQuestion q" to "DNSQuestion pktq"
1276
1277Revision 1.178  2003/06/07 06:25:12  cheshire
1278Update some comments
1279
1280Revision 1.177  2003/06/07 04:50:53  cheshire
1281<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
1282
1283Revision 1.176  2003/06/07 04:33:26  cheshire
1284<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
1285Minor change: Increment/decrement logic for q->CurrentAnswers should be in
1286CacheRecordAdd() and CacheRecordRmv(), not AnswerQuestionWithResourceRecord()
1287
1288Revision 1.175  2003/06/07 04:11:52  cheshire
1289Minor changes to comments and debug messages
1290
1291Revision 1.174  2003/06/07 01:46:38  cheshire
1292<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
1293
1294Revision 1.173  2003/06/07 01:22:13  cheshire
1295<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
1296
1297Revision 1.172  2003/06/07 00:59:42  cheshire
1298<rdar://problem/3283454> Need some randomness to spread queries on the network
1299
1300Revision 1.171  2003/06/06 21:41:10  cheshire
1301For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
1302
1303Revision 1.170  2003/06/06 21:38:55  cheshire
1304Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
1305already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
1306
1307Revision 1.169  2003/06/06 21:35:55  cheshire
1308Fix mis-named macro: GetRRHostNameTarget is really GetRRDomainNameTarget
1309(the target is a domain name, but not necessarily a host name)
1310
1311Revision 1.168  2003/06/06 21:33:31  cheshire
1312Instead of using (mDNSPlatformOneSecond/2) all over the place, define a constant "InitialQuestionInterval"
1313
1314Revision 1.167  2003/06/06 21:30:42  cheshire
1315<rdar://problem/3282962> Don't delay queries for shared record types
1316
1317Revision 1.166  2003/06/06 17:20:14  cheshire
1318For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
1319(Global search-and-replace; no functional change to code execution.)
1320
1321Revision 1.165  2003/06/04 02:53:21  cheshire
1322Add some "#pragma warning" lines so it compiles clean on Microsoft compilers
1323
1324Revision 1.164  2003/06/04 01:25:33  cheshire
1325<rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
1326Display time interval between first and subsequent queries
1327
1328Revision 1.163  2003/06/03 19:58:14  cheshire
1329<rdar://problem/3277665> mDNS_DeregisterService() fixes:
1330When forcibly deregistering after a conflict, ensure we don't send an incorrect goodbye packet.
1331Guard against a couple of possible mDNS_DeregisterService() race conditions.
1332
1333Revision 1.162  2003/06/03 19:30:39  cheshire
1334Minor addition refinements for
1335<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
1336
1337Revision 1.161  2003/06/03 18:29:03  cheshire
1338Minor changes to comments and debugf() messages
1339
1340Revision 1.160  2003/06/03 05:02:16  cheshire
1341<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
1342
1343Revision 1.159  2003/06/03 03:31:57  cheshire
1344<rdar://problem/3277033> False self-conflict when there are duplicate registrations on one machine
1345
1346Revision 1.158  2003/06/02 22:57:09  cheshire
1347Minor clarifying changes to comments and log messages;
1348IdenticalResourceRecordAnyInterface() is really more accurately called just IdenticalResourceRecord()
1349
1350Revision 1.157  2003/05/31 00:09:49  cheshire
1351<rdar://problem/3274862> Add ability to discover what services are on a network
1352
1353Revision 1.156  2003/05/30 23:56:49  cheshire
1354<rdar://problem/3274847> Crash after error in mDNS_RegisterService()
1355Need to set "sr->Extras = mDNSNULL" before returning
1356
1357Revision 1.155  2003/05/30 23:48:00  cheshire
1358<rdar://problem/3274832> Announcements not properly grouped
1359Due to inconsistent setting of rr->LastAPTime at different places in the
1360code, announcements were not properly grouped into a single packet.
1361Fixed by creating a single routine called InitializeLastAPTime().
1362
1363Revision 1.154  2003/05/30 23:38:14  cheshire
1364<rdar://problem/3274814> Fix error in IPv6 reverse-mapping PTR records
1365Wrote buffer[32] where it should have said buffer[64]
1366
1367Revision 1.153  2003/05/30 19:10:56  cheshire
1368<rdar://problem/3274153> ConstructServiceName needs to be more restrictive
1369
1370Revision 1.152  2003/05/29 22:39:16  cheshire
1371<rdar://problem/3273209> Don't truncate strings in the middle of a UTF-8 character
1372
1373Revision 1.151  2003/05/29 06:35:42  cheshire
1374<rdar://problem/3272221> mDNSCoreReceiveResponse() purging wrong record
1375
1376Revision 1.150  2003/05/29 06:25:45  cheshire
1377<rdar://problem/3272218> Need to call CheckCacheExpiration() *before* AnswerNewQuestion()
1378
1379Revision 1.149  2003/05/29 06:18:39  cheshire
1380<rdar://problem/3272217> Split AnswerLocalQuestions into CacheRecordAdd and CacheRecordRmv
1381
1382Revision 1.148  2003/05/29 06:11:34  cheshire
1383<rdar://problem/3272214> Report if there appear to be too many "Resolve" callbacks
1384
1385Revision 1.147  2003/05/29 06:01:18  cheshire
1386Change some debugf() calls to LogMsg() calls to help with debugging
1387
1388Revision 1.146  2003/05/28 21:00:44  cheshire
1389Re-enable "immediate answer burst" debugf message
1390
1391Revision 1.145  2003/05/28 20:57:44  cheshire
1392<rdar://problem/3271550> mDNSResponder reports "Cannot perform multi-packet
1393known-answer suppression ..." This is a known issue caused by a bug in the OS X 10.2
1394version of mDNSResponder, so for now we should suppress this warning message.
1395
1396Revision 1.144  2003/05/28 18:05:12  cheshire
1397<rdar://problem/3009899> mDNSResponder allows invalid service registrations
1398Fix silly mistake: old logic allowed "TDP" and "UCP" as valid names
1399
1400Revision 1.143  2003/05/28 04:31:29  cheshire
1401<rdar://problem/3270733> mDNSResponder not sending probes at the prescribed time
1402
1403Revision 1.142  2003/05/28 03:13:07  cheshire
1404<rdar://problem/3009899> mDNSResponder allows invalid service registrations
1405Require that the transport protocol be _udp or _tcp
1406
1407Revision 1.141  2003/05/28 02:19:12  cheshire
1408<rdar://problem/3270634> Misleading messages generated by iChat
1409Better fix: Only generate the log message for queries where the TC bit is set.
1410
1411Revision 1.140  2003/05/28 01:55:24  cheshire
1412Minor change to log messages
1413
1414Revision 1.139  2003/05/28 01:52:51  cheshire
1415<rdar://problem/3270634> Misleading messages generated by iChat
1416
1417Revision 1.138  2003/05/27 22:35:00  cheshire
1418<rdar://problem/3270277> mDNS_RegisterInterface needs to retrigger questions
1419
1420Revision 1.137  2003/05/27 20:04:33  cheshire
1421<rdar://problem/3269900> mDNSResponder crash in mDNS_vsnprintf()
1422
1423Revision 1.136  2003/05/27 18:50:07  cheshire
1424<rdar://problem/3269768> mDNS_StartResolveService doesn't inform client of port number changes
1425
1426Revision 1.135  2003/05/26 04:57:28  cheshire
1427<rdar://problem/3268953> Delay queries when there are already answers in the cache
1428
1429Revision 1.134  2003/05/26 04:54:54  cheshire
1430<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
1431Accidentally deleted '%' case from the switch statement
1432
1433Revision 1.133  2003/05/26 03:21:27  cheshire
1434Tidy up address structure naming:
1435mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
1436mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
1437mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
1438
1439Revision 1.132  2003/05/26 03:01:26  cheshire
1440<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
1441
1442Revision 1.131  2003/05/26 00:42:05  cheshire
1443<rdar://problem/3268876> Temporarily include mDNSResponder version in packets
1444
1445Revision 1.130  2003/05/24 16:39:48  cheshire
1446<rdar://problem/3268631> SendResponses also needs to handle multihoming better
1447
1448Revision 1.129  2003/05/23 02:15:37  cheshire
1449Fixed misleading use of the term "duplicate suppression" where it should have
1450said "known answer suppression". (Duplicate answer suppression is something
1451different, and duplicate question suppression is yet another thing, so the use
1452of the completely vague term "duplicate suppression" was particularly bad.)
1453
1454Revision 1.128  2003/05/23 01:55:13  cheshire
1455<rdar://problem/3267127> After name change, mDNSResponder needs to re-probe for name uniqueness
1456
1457Revision 1.127  2003/05/23 01:02:15  ksekar
1458<rdar://problem/3032577>: mDNSResponder needs to include unique id in default name
1459
1460Revision 1.126  2003/05/22 02:29:22  cheshire
1461<rdar://problem/2984918> SendQueries needs to handle multihoming better
1462Complete rewrite of SendQueries. Works much better now :-)
1463
1464Revision 1.125  2003/05/22 01:50:45  cheshire
1465Fix warnings, and improve log messages
1466
1467Revision 1.124  2003/05/22 01:41:50  cheshire
1468DiscardDeregistrations doesn't need InterfaceID parameter
1469
1470Revision 1.123  2003/05/22 01:38:55  cheshire
1471Change bracketing of #pragma mark
1472
1473Revision 1.122  2003/05/21 19:59:04  cheshire
1474<rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
1475Minor refinements; make sure we don't truncate in the middle of a multi-byte UTF-8 character
1476
1477Revision 1.121  2003/05/21 17:54:07  ksekar
1478<rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
1479New rename behavior - domain name "foo" becomes "foo--2" on conflict, richtext name becomes "foo (2)"
1480
1481Revision 1.120  2003/05/19 22:14:14  ksekar
1482<rdar://problem/3162914> mDNS probe denials/conflicts not detected unless conflict is of the same type
1483
1484Revision 1.119  2003/05/16 01:34:10  cheshire
1485Fix some warnings
1486
1487Revision 1.118  2003/05/14 18:48:40  cheshire
1488<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
1489More minor refinements:
1490mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
1491mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
1492
1493Revision 1.117  2003/05/14 07:08:36  cheshire
1494<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
1495Previously, when there was any network configuration change, mDNSResponder
1496would tear down the entire list of active interfaces and start again.
1497That was very disruptive, and caused the entire cache to be flushed,
1498and caused lots of extra network traffic. Now it only removes interfaces
1499that have really gone, and only adds new ones that weren't there before.
1500
1501Revision 1.116  2003/05/14 06:51:56  cheshire
1502<rdar://problem/3027144> mDNSResponder doesn't refresh server info if changed during sleep
1503
1504Revision 1.115  2003/05/14 06:44:31  cheshire
1505Improve debugging message
1506
1507Revision 1.114  2003/05/07 01:47:03  cheshire
1508<rdar://problem/3250330> Also protect against NULL domainlabels
1509
1510Revision 1.113  2003/05/07 00:28:18  cheshire
1511<rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
1512
1513Revision 1.112  2003/05/06 00:00:46  cheshire
1514<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
1515
1516Revision 1.111  2003/05/05 23:42:08  cheshire
1517<rdar://problem/3245631> Resolves never succeed
1518Was setting "rr->LastAPTime = timenow - rr->LastAPTime"
1519instead of  "rr->LastAPTime = timenow - rr->ThisAPInterval"
1520
1521Revision 1.110  2003/04/30 21:09:59  cheshire
1522<rdar://problem/3244727> mDNS_vsnprintf needs to be more defensive against invalid domain names
1523
1524Revision 1.109  2003/04/26 02:41:56  cheshire
1525<rdar://problem/3241281> Change timenow from a local variable to a structure member
1526
1527Revision 1.108  2003/04/25 01:45:56  cheshire
1528<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
1529
1530Revision 1.107  2003/04/25 00:41:31  cheshire
1531<rdar://problem/3239912> Create single routine PurgeCacheResourceRecord(), to avoid bugs in future
1532
1533Revision 1.106  2003/04/22 03:14:45  cheshire
1534<rdar://problem/3232229> Include Include instrumented mDNSResponder in panther now
1535
1536Revision 1.105  2003/04/22 01:07:43  cheshire
1537<rdar://problem/3176248> DNSServiceRegistrationUpdateRecord should support a default ttl
1538If TTL parameter is zero, leave record TTL unchanged
1539
1540Revision 1.104  2003/04/21 19:15:52  cheshire
1541Fix some compiler warnings
1542
1543Revision 1.103  2003/04/19 02:26:35  cheshire
1544<rdar://problem/3233804> Incorrect goodbye packet after conflict
1545
1546Revision 1.102  2003/04/17 03:06:28  cheshire
1547<rdar://problem/3231321> No need to query again when a service goes away
1548Set UnansweredQueries to 2 when receiving a "goodbye" packet
1549
1550Revision 1.101  2003/04/15 20:58:31  jgraessl
1551<rdar://problem/3229014> Added a hash to lookup records in the cache.
1552
1553Revision 1.100  2003/04/15 18:53:14  cheshire
1554<rdar://problem/3229064> Bug in ScheduleNextTask
1555mDNS.c 1.94 incorrectly combined two "if" statements into one.
1556
1557Revision 1.99  2003/04/15 18:09:13  jgraessl
1558<rdar://problem/3228892>
1559Reviewed by: Stuart Cheshire
1560Added code to keep track of when the next cache item will expire so we can
1561call TidyRRCache only when necessary.
1562
1563Revision 1.98  2003/04/03 03:43:55  cheshire
1564<rdar://problem/3216837> Off-by-one error in probe rate limiting
1565
1566Revision 1.97  2003/04/02 01:48:17  cheshire
1567<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
1568Additional fix pointed out by Josh:
1569Also set ProbeFailTime when incrementing NumFailedProbes when resetting a record back to probing state
1570
1571Revision 1.96  2003/04/01 23:58:55  cheshire
1572Minor comment changes
1573
1574Revision 1.95  2003/04/01 23:46:05  cheshire
1575<rdar://problem/3214832> mDNSResponder can get stuck in infinite loop after many location cycles
1576mDNS_DeregisterInterface() flushes the RR cache by marking all records received on that interface
1577to expire in one second. However, if a mDNS_StartResolveService() call is made in that one-second
1578window, it can get an SRV answer from one of those soon-to-be-deleted records, resulting in
1579FoundServiceInfoSRV() making an interface-specific query on the interface that was just removed.
1580
1581Revision 1.94  2003/03/29 01:55:19  cheshire
1582<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
1583Solution: Major cleanup of packet timing and conflict handling rules
1584
1585Revision 1.93  2003/03/28 01:54:36  cheshire
1586Minor tidyup of IPv6 (AAAA) code
1587
1588Revision 1.92  2003/03/27 03:30:55  cheshire
1589<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
1590Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
1591Fixes:
15921. Make mDNS_DeregisterInterface() safe to call from a callback
15932. Make HostNameCallback() use DeadvertiseInterface() instead
1594   (it never really needed to deregister the interface at all)
1595
1596Revision 1.91  2003/03/15 04:40:36  cheshire
1597Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
1598
1599Revision 1.90  2003/03/14 20:26:37  cheshire
1600Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
1601
1602Revision 1.89  2003/03/12 19:57:50  cheshire
1603Fixed typo in debug message
1604
1605Revision 1.88  2003/03/12 00:17:44  cheshire
1606<rdar://problem/3195426> GetFreeCacheRR needs to be more willing to throw away recent records
1607
1608Revision 1.87  2003/03/11 01:27:20  cheshire
1609Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
1610
1611Revision 1.86  2003/03/06 20:44:33  cheshire
1612Comment tidyup
1613
1614Revision 1.85  2003/03/05 03:38:35  cheshire
1615<rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
1616Fixed by leaving client in list after conflict, until client explicitly deallocates
1617
1618Revision 1.84  2003/03/05 01:27:30  cheshire
1619<rdar://problem/3185482> Different TTL for multicast versus unicast responses
1620When building unicast responses, record TTLs are capped to 10 seconds
1621
1622Revision 1.83  2003/03/04 23:48:52  cheshire
1623<rdar://problem/3188865> Double probes after wake from sleep
1624Don't reset record type to kDNSRecordTypeUnique if record is DependentOn another
1625
1626Revision 1.82  2003/03/04 23:38:29  cheshire
1627<rdar://problem/3099194> mDNSResponder needs performance improvements
1628Only set rr->CRActiveQuestion to point to the
1629currently active representative of a question set
1630
1631Revision 1.81  2003/02/21 03:35:34  cheshire
1632<rdar://problem/3179007> mDNSResponder needs to include AAAA records in additional answer section
1633
1634Revision 1.80  2003/02/21 02:47:53  cheshire
1635<rdar://problem/3099194> mDNSResponder needs performance improvements
1636Several places in the code were calling CacheRRActive(), which searched the entire
1637question list every time, to see if this cache resource record answers any question.
1638Instead, we now have a field "CRActiveQuestion" in the resource record structure
1639
1640Revision 1.79  2003/02/21 01:54:07  cheshire
1641<rdar://problem/3099194> mDNSResponder needs performance improvements
1642Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
1643
1644Revision 1.78  2003/02/20 06:48:32  cheshire
1645<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
1646Reviewed by: Josh Graessley, Bob Bradley
1647
1648Revision 1.77  2003/01/31 03:35:59  cheshire
1649<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1650When there were *two* active questions in the list, they were incorrectly
1651finding *each other* and *both* being marked as duplicates of another question
1652
1653Revision 1.76  2003/01/29 02:46:37  cheshire
1654Fix for IPv6:
1655A physical interface is identified solely by its InterfaceID (not by IP and type).
1656On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
1657In cases where the requested outbound protocol (v4 or v6) is not supported on
1658that InterfaceID, the platform support layer should simply discard that packet.
1659
1660Revision 1.75  2003/01/29 01:47:40  cheshire
1661Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
1662
1663Revision 1.74  2003/01/28 05:26:25  cheshire
1664<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1665Add 'Active' flag for interfaces
1666
1667Revision 1.73  2003/01/28 03:45:12  cheshire
1668Fixed missing "not" in "!mDNSAddrIsDNSMulticast(dstaddr)"
1669
1670Revision 1.72  2003/01/28 01:49:48  cheshire
1671<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1672FindDuplicateQuestion() was incorrectly finding the question itself in the list,
1673and incorrectly marking it as a duplicate (of itself), so that it became inactive.
1674
1675Revision 1.71  2003/01/28 01:41:44  cheshire
1676<rdar://problem/3153091> Race condition when network change causes bad stuff
1677When an interface goes away, interface-specific questions on that interface become orphaned.
1678Orphan questions cause HaveQueries to return true, but there's no interface to send them on.
1679Fix: mDNS_DeregisterInterface() now calls DeActivateInterfaceQuestions()
1680
1681Revision 1.70  2003/01/23 19:00:20  cheshire
1682Protect against infinite loops in mDNS_Execute
1683
1684Revision 1.69  2003/01/21 22:56:32  jgraessl
1685<rdar://problem/3124348>  service name changes are not properly handled
1686Submitted by: Stuart Cheshire
1687Reviewed by: Joshua Graessley
1688Applying changes for 3124348 to main branch. 3124348 changes went in to a
1689branch for SU.
1690
1691Revision 1.68  2003/01/17 04:09:27  cheshire
1692<rdar://problem/3141038> mDNSResponder Resolves are unreliable on multi-homed hosts
1693
1694Revision 1.67  2003/01/17 03:56:45  cheshire
1695Default 24-hour TTL is far too long. Changing to two hours.
1696
1697Revision 1.66  2003/01/13 23:49:41  jgraessl
1698Merged changes for the following fixes in to top of tree:
1699<rdar://problem/3086540>  computer name changes not handled properly
1700<rdar://problem/3124348>  service name changes are not properly handled
1701<rdar://problem/3124352>  announcements sent in pairs, failing chattiness test
1702
1703Revision 1.65  2002/12/23 22:13:28  jgraessl
1704Reviewed by: Stuart Cheshire
1705Initial IPv6 support for mDNSResponder.
1706
1707Revision 1.64  2002/11/26 20:49:06  cheshire
1708<rdar://problem/3104543> RFC 1123 allows the first character of a name label to be either a letter or a digit
1709
1710Revision 1.63  2002/09/21 20:44:49  zarzycki
1711Added APSL info
1712
1713Revision 1.62  2002/09/20 03:25:37  cheshire
1714Fix some compiler warnings
1715
1716Revision 1.61  2002/09/20 01:05:24  cheshire
1717Don't kill the Extras list in mDNS_DeregisterService()
1718
1719Revision 1.60  2002/09/19 23:47:35  cheshire
1720Added mDNS_RegisterNoSuchService() function for assertion of non-existence
1721of a particular named service
1722
1723Revision 1.59  2002/09/19 21:25:34  cheshire
1724mDNS_snprintf() doesn't need to be in a separate file
1725
1726Revision 1.58  2002/09/19 04:20:43  cheshire
1727Remove high-ascii characters that confuse some systems
1728
1729Revision 1.57  2002/09/17 01:07:08  cheshire
1730Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
1731
1732Revision 1.56  2002/09/16 19:44:17  cheshire
1733Merge in license terms from Quinn's copy, in preparation for Darwin release
1734*/
1735
1736#pragma ident	"%Z%%M%	%I%	%E% SMI"
1737
1738#include "DNSCommon.h"                  // Defines general DNS untility routines
1739#include "uDNS.h"						// Defines entry points into unicast-specific routines
1740// Disable certain benign warnings with Microsoft compilers
1741#if(defined(_MSC_VER))
1742	// Disable "conditional expression is constant" warning for debug macros.
1743	// Otherwise, this generates warnings for the perfectly natural construct "while(1)"
1744	// If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
1745	#pragma warning(disable:4127)
1746
1747	// Disable "assignment within conditional expression".
1748	// Other compilers understand the convention that if you place the assignment expression within an extra pair
1749	// of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1750	// The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1751	// to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1752	#pragma warning(disable:4706)
1753#endif
1754
1755// ***************************************************************************
1756#if COMPILER_LIKES_PRAGMA_MARK
1757#pragma mark -
1758#pragma mark - Program Constants
1759#endif
1760
1761mDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
1762mDNSexport const mDNSv4Addr      zerov4Addr        = { { 0 } };
1763mDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
1764mDNSexport const mDNSEthAddr     zeroEthAddr       = { { 0 } };
1765mDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
1766mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
1767mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
1768
1769mDNSexport const mDNSInterfaceID mDNSInterface_Any        = 0;
1770mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly  = (mDNSInterfaceID)1;
1771
1772mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark        = (mDNSInterfaceID)~0;
1773
1774#define UnicastDNSPortAsNumber   53
1775#define NATPMPPortAsNumber       5351
1776#define DNSEXTPortAsNumber       5352		// Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
1777#define MulticastDNSPortAsNumber 5353
1778#define LoopbackIPCPortAsNumber  5354
1779
1780mDNSexport const mDNSIPPort UnicastDNSPort     = { { UnicastDNSPortAsNumber   >> 8, UnicastDNSPortAsNumber   & 0xFF } };
1781mDNSexport const mDNSIPPort NATPMPPort         = { { NATPMPPortAsNumber       >> 8, NATPMPPortAsNumber       & 0xFF } };
1782mDNSexport const mDNSIPPort DNSEXTPort         = { { DNSEXTPortAsNumber       >> 8, DNSEXTPortAsNumber       & 0xFF } };
1783mDNSexport const mDNSIPPort MulticastDNSPort   = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
1784mDNSexport const mDNSIPPort LoopbackIPCPort    = { { LoopbackIPCPortAsNumber  >> 8, LoopbackIPCPortAsNumber  & 0xFF } };
1785
1786mDNSexport const mDNSv4Addr AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
1787mDNSexport const mDNSAddr   AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
1788mDNSexport const mDNSAddr   AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
1789
1790mDNSexport const mDNSOpaque16 zeroID          = { { 0, 0 } };
1791mDNSexport const mDNSOpaque16 QueryFlags      = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
1792mDNSexport const mDNSOpaque16 uQueryFlags     = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
1793mDNSexport const mDNSOpaque16 ResponseFlags   = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
1794mDNSexport const mDNSOpaque16 UpdateReqFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
1795mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
1796
1797// Any records bigger than this are considered 'large' records
1798#define SmallRecordLimit 1024
1799
1800#define kMaxUpdateCredits 10
1801#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
1802
1803mDNSexport const char *const mDNS_DomainTypeNames[] =
1804	{
1805	 "b._dns-sd._udp.",		// Browse
1806	"db._dns-sd._udp.",		// Default Browse
1807	"lb._dns-sd._udp.",		// Legacy Browse
1808	 "r._dns-sd._udp.",		// Registration
1809	"dr._dns-sd._udp."		// Default Registration
1810	};
1811
1812#ifdef UNICAST_DISABLED
1813#define uDNS_IsActiveQuery(q, u) mDNSfalse
1814#endif
1815
1816// ***************************************************************************
1817#if COMPILER_LIKES_PRAGMA_MARK
1818#pragma mark -
1819#pragma mark - Specialized mDNS version of vsnprintf
1820#endif
1821
1822static const struct mDNSprintf_format
1823	{
1824	unsigned      leftJustify : 1;
1825	unsigned      forceSign : 1;
1826	unsigned      zeroPad : 1;
1827	unsigned      havePrecision : 1;
1828	unsigned      hSize : 1;
1829	unsigned      lSize : 1;
1830	char          altForm;
1831	char          sign;		// +, - or space
1832	unsigned int  fieldWidth;
1833	unsigned int  precision;
1834	} mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1835
1836mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
1837	{
1838	mDNSu32 nwritten = 0;
1839	int c;
1840	if (buflen == 0) return(0);
1841	buflen--;		// Pre-reserve one space in the buffer for the terminating null
1842	if (buflen == 0) goto exit;
1843
1844	for (c = *fmt; c != 0; c = *++fmt)
1845		{
1846		if (c != '%')
1847			{
1848			*sbuffer++ = (char)c;
1849			if (++nwritten >= buflen) goto exit;
1850			}
1851		else
1852			{
1853			unsigned int i=0, j;
1854			// The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
1855			// generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
1856			// The size needs to be enough for a 256-byte domain name plus some error text.
1857			#define mDNS_VACB_Size 300
1858			char mDNS_VACB[mDNS_VACB_Size];
1859			#define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
1860			#define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
1861			char *s = mDNS_VACB_Lim, *digits;
1862			struct mDNSprintf_format F = mDNSprintf_format_default;
1863
1864			while (1)	//  decode flags
1865				{
1866				c = *++fmt;
1867				if      (c == '-') F.leftJustify = 1;
1868				else if (c == '+') F.forceSign = 1;
1869				else if (c == ' ') F.sign = ' ';
1870				else if (c == '#') F.altForm++;
1871				else if (c == '0') F.zeroPad = 1;
1872				else break;
1873				}
1874
1875			if (c == '*')	//  decode field width
1876				{
1877				int f = va_arg(arg, int);
1878				if (f < 0) { f = -f; F.leftJustify = 1; }
1879				F.fieldWidth = (unsigned int)f;
1880				c = *++fmt;
1881				}
1882			else
1883				{
1884				for (; c >= '0' && c <= '9'; c = *++fmt)
1885					F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
1886				}
1887
1888			if (c == '.')	//  decode precision
1889				{
1890				if ((c = *++fmt) == '*')
1891					{ F.precision = va_arg(arg, unsigned int); c = *++fmt; }
1892				else for (; c >= '0' && c <= '9'; c = *++fmt)
1893						F.precision = (10 * F.precision) + (c - '0');
1894				F.havePrecision = 1;
1895				}
1896
1897			if (F.leftJustify) F.zeroPad = 0;
1898
1899			conv:
1900			switch (c)	//  perform appropriate conversion
1901				{
1902				unsigned long n;
1903				case 'h' :	F.hSize = 1; c = *++fmt; goto conv;
1904				case 'l' :	// fall through
1905				case 'L' :	F.lSize = 1; c = *++fmt; goto conv;
1906				case 'd' :
1907				case 'i' :	if (F.lSize) n = (unsigned long)va_arg(arg, long);
1908							else n = (unsigned long)va_arg(arg, int);
1909							if (F.hSize) n = (short) n;
1910							if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
1911							else if (F.forceSign) F.sign = '+';
1912							goto decimal;
1913				case 'u' :	if (F.lSize) n = va_arg(arg, unsigned long);
1914							else n = va_arg(arg, unsigned int);
1915							if (F.hSize) n = (unsigned short) n;
1916							F.sign = 0;
1917							goto decimal;
1918				decimal:	if (!F.havePrecision)
1919								{
1920								if (F.zeroPad)
1921									{
1922									F.precision = F.fieldWidth;
1923									if (F.sign) --F.precision;
1924									}
1925								if (F.precision < 1) F.precision = 1;
1926								}
1927							if (F.precision > mDNS_VACB_Size - 1)
1928								F.precision = mDNS_VACB_Size - 1;
1929							for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
1930							for (; i < F.precision; i++) *--s = '0';
1931							if (F.sign) { *--s = F.sign; i++; }
1932							break;
1933
1934				case 'o' :	if (F.lSize) n = va_arg(arg, unsigned long);
1935							else n = va_arg(arg, unsigned int);
1936							if (F.hSize) n = (unsigned short) n;
1937							if (!F.havePrecision)
1938								{
1939								if (F.zeroPad) F.precision = F.fieldWidth;
1940								if (F.precision < 1) F.precision = 1;
1941								}
1942							if (F.precision > mDNS_VACB_Size - 1)
1943								F.precision = mDNS_VACB_Size - 1;
1944							for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
1945							if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
1946							for (; i < F.precision; i++) *--s = '0';
1947							break;
1948
1949				case 'a' :	{
1950							unsigned char *a = va_arg(arg, unsigned char *);
1951							if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
1952							else
1953								{
1954								s = mDNS_VACB;	// Adjust s to point to the start of the buffer, not the end
1955								if (F.altForm)
1956									{
1957									mDNSAddr *ip = (mDNSAddr*)a;
1958									switch (ip->type)
1959										{
1960										case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
1961										case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
1962										default:                F.precision =  0; break;
1963										}
1964									}
1965								switch (F.precision)
1966									{
1967									case  4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
1968														a[0], a[1], a[2], a[3]); break;
1969									case  6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
1970														a[0], a[1], a[2], a[3], a[4], a[5]); break;
1971									case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
1972														"%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
1973														a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
1974														a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
1975									default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
1976														" address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
1977									}
1978								}
1979							}
1980							break;
1981
1982				case 'p' :	F.havePrecision = F.lSize = 1;
1983							F.precision = 8;
1984				case 'X' :	digits = "0123456789ABCDEF";
1985							goto hexadecimal;
1986				case 'x' :	digits = "0123456789abcdef";
1987				hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
1988							else n = va_arg(arg, unsigned int);
1989							if (F.hSize) n = (unsigned short) n;
1990							if (!F.havePrecision)
1991								{
1992								if (F.zeroPad)
1993									{
1994									F.precision = F.fieldWidth;
1995									if (F.altForm) F.precision -= 2;
1996									}
1997								if (F.precision < 1) F.precision = 1;
1998								}
1999							if (F.precision > mDNS_VACB_Size - 1)
2000								F.precision = mDNS_VACB_Size - 1;
2001							for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
2002							for (; i < F.precision; i++) *--s = '0';
2003							if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
2004							break;
2005
2006				case 'c' :	*--s = (char)va_arg(arg, int); i = 1; break;
2007
2008				case 's' :	s = va_arg(arg, char *);
2009							if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
2010							else switch (F.altForm)
2011								{
2012								case 0: i=0;
2013										if (!F.havePrecision)				// C string
2014											while(s[i]) i++;
2015										else
2016											{
2017											while ((i < F.precision) && s[i]) i++;
2018											// Make sure we don't truncate in the middle of a UTF-8 character
2019											// If last character we got was any kind of UTF-8 multi-byte character,
2020											// then see if we have to back up.
2021											// This is not as easy as the similar checks below, because
2022											// here we can't assume it's safe to examine the *next* byte, so we
2023											// have to confine ourselves to working only backwards in the string.
2024											j = i;		// Record where we got to
2025											// Now, back up until we find first non-continuation-char
2026											while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
2027											// Now s[i-1] is the first non-continuation-char
2028											// and (j-i) is the number of continuation-chars we found
2029											if (i>0 && (s[i-1] & 0xC0) == 0xC0)	// If we found a start-char
2030												{
2031												i--;		// Tentatively eliminate this start-char as well
2032												// Now (j-i) is the number of characters we're considering eliminating.
2033												// To be legal UTF-8, the start-char must contain (j-i) one-bits,
2034												// followed by a zero bit. If we shift it right by (7-(j-i)) bits
2035												// (with sign extension) then the result has to be 0xFE.
2036												// If this is right, then we reinstate the tentatively eliminated bytes.
2037												if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
2038												}
2039											}
2040										break;
2041								case 1: i = (unsigned char) *s++; break;	// Pascal string
2042								case 2: {									// DNS label-sequence name
2043										unsigned char *a = (unsigned char *)s;
2044										s = mDNS_VACB;	// Adjust s to point to the start of the buffer, not the end
2045										if (*a == 0) *s++ = '.';	// Special case for root DNS name
2046										while (*a)
2047											{
2048											if (*a > 63)
2049												{ s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
2050											if (s + *a >= &mDNS_VACB[254])
2051												{ s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
2052											s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%#s.", a);
2053											a += 1 + *a;
2054											}
2055										i = (mDNSu32)(s - mDNS_VACB);
2056										s = mDNS_VACB;	// Reset s back to the start of the buffer
2057										break;
2058										}
2059								}
2060							// Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
2061							if (F.havePrecision && i > F.precision)
2062								{ i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
2063							break;
2064
2065				case 'n' :	s = va_arg(arg, char *);
2066							if      (F.hSize) * (short *) s = (short)nwritten;
2067							else if (F.lSize) * (long  *) s = (long)nwritten;
2068							else              * (int   *) s = (int)nwritten;
2069							continue;
2070
2071				default:	s = mDNS_VACB;
2072							i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
2073
2074				case '%' :	*sbuffer++ = (char)c;
2075							if (++nwritten >= buflen) goto exit;
2076							break;
2077				}
2078
2079			if (i < F.fieldWidth && !F.leftJustify)			// Pad on the left
2080				do	{
2081					*sbuffer++ = ' ';
2082					if (++nwritten >= buflen) goto exit;
2083					} while (i < --F.fieldWidth);
2084
2085			// Make sure we don't truncate in the middle of a UTF-8 character.
2086			// Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
2087			// allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
2088			// so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
2089			// formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
2090			if (i > buflen - nwritten)
2091				{ i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
2092			for (j=0; j<i; j++) *sbuffer++ = *s++;			// Write the converted result
2093			nwritten += i;
2094			if (nwritten >= buflen) goto exit;
2095
2096			for (; i < F.fieldWidth; i++)					// Pad on the right
2097				{
2098				*sbuffer++ = ' ';
2099				if (++nwritten >= buflen) goto exit;
2100				}
2101			}
2102		}
2103	exit:
2104	*sbuffer++ = 0;
2105	return(nwritten);
2106	}
2107
2108mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
2109	{
2110	mDNSu32 length;
2111
2112	va_list ptr;
2113	va_start(ptr,fmt);
2114	length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
2115	va_end(ptr);
2116
2117	return(length);
2118	}
2119
2120// ***************************************************************************
2121#if COMPILER_LIKES_PRAGMA_MARK
2122#pragma mark -
2123#pragma mark - General Utility Functions
2124#endif
2125
2126#define InitialQuestionInterval (mDNSPlatformOneSecond/2)
2127#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
2128#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
2129
2130mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
2131	{
2132	if (ActiveQuestion(q))
2133		if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
2134			m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
2135	}
2136
2137mDNSlocal CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
2138	{
2139	CacheGroup *cg;
2140	for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
2141		if (cg->namehash == namehash && SameDomainName(cg->name, name))
2142			break;
2143	return(cg);
2144	}
2145
2146mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
2147	{
2148	return(CacheGroupForName(m, slot, rr->namehash, rr->name));
2149	}
2150
2151mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
2152	{
2153	NetworkInterfaceInfo *intf;
2154
2155	if (addr->type == mDNSAddrType_IPv4)
2156		{
2157		if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue);
2158		for (intf = m->HostInterfaces; intf; intf = intf->next)
2159			if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
2160				if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
2161					return(mDNStrue);
2162		}
2163
2164	if (addr->type == mDNSAddrType_IPv6)
2165		{
2166		if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue);
2167		for (intf = m->HostInterfaces; intf; intf = intf->next)
2168			if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
2169				if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
2170					(((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
2171					(((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
2172					(((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
2173						return(mDNStrue);
2174		}
2175
2176	return(mDNSfalse);
2177	}
2178
2179// Set up a AuthRecord with sensible default values.
2180// These defaults may be overwritten with new values before mDNS_Register is called
2181mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
2182	mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
2183	{
2184	mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
2185	// Don't try to store a TTL bigger than we can represent in platform time units
2186	if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
2187		ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
2188	else if (ttl == 0)		// And Zero TTL is illegal
2189		ttl = DefaultTTLforRRType(rrtype);
2190
2191	// Field Group 1: The actual information pertaining to this resource record
2192	rr->resrec.RecordType        = RecordType;
2193	rr->resrec.InterfaceID       = InterfaceID;
2194	rr->resrec.name              = &rr->namestorage;
2195	rr->resrec.rrtype            = rrtype;
2196	rr->resrec.rrclass           = kDNSClass_IN;
2197	rr->resrec.rroriginalttl     = ttl;
2198//	rr->resrec.rdlength          = MUST set by client and/or in mDNS_Register_internal
2199//	rr->resrec.rdestimate        = set in mDNS_Register_internal
2200//	rr->resrec.rdata             = MUST be set by client
2201
2202	if (RDataStorage)
2203		rr->resrec.rdata = RDataStorage;
2204	else
2205		{
2206		rr->resrec.rdata = &rr->rdatastorage;
2207		rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
2208		}
2209
2210	// Field Group 2: Persistent metadata for Authoritative Records
2211	rr->Additional1       = mDNSNULL;
2212	rr->Additional2       = mDNSNULL;
2213	rr->DependentOn       = mDNSNULL;
2214	rr->RRSet             = mDNSNULL;
2215	rr->RecordCallback    = Callback;
2216	rr->RecordContext     = Context;
2217
2218	rr->HostTarget        = mDNSfalse;
2219	rr->AllowRemoteQuery  = mDNSfalse;
2220	rr->ForceMCast        = mDNSfalse;
2221
2222	// Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
2223
2224	rr->namestorage.c[0]  = 0;		// MUST be set by client before calling mDNS_Register()
2225	}
2226
2227// For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
2228// Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
2229mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord)
2230	{
2231	// Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
2232	if (AddRecord) rr->LocalAnswer = mDNStrue;
2233	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2234	if (q->QuestionCallback)
2235		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
2236	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2237	}
2238
2239// When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers
2240// to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
2241// If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
2242// Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
2243mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord)
2244	{
2245	if (m->CurrentQuestion) LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set");
2246
2247	m->CurrentQuestion = m->LocalOnlyQuestions;
2248	while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
2249		{
2250		DNSQuestion *q = m->CurrentQuestion;
2251		m->CurrentQuestion = q->next;
2252		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2253			AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);			// MUST NOT dereference q again
2254		}
2255
2256	// If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
2257	if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
2258		{
2259		m->CurrentQuestion = m->Questions;
2260		while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
2261			{
2262			DNSQuestion *q = m->CurrentQuestion;
2263			m->CurrentQuestion = q->next;
2264			if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2265				AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);		// MUST NOT dereference q again
2266			}
2267		}
2268
2269	m->CurrentQuestion = mDNSNULL;
2270	}
2271
2272// ***************************************************************************
2273#if COMPILER_LIKES_PRAGMA_MARK
2274#pragma mark -
2275#pragma mark - Resource Record Utility Functions
2276#endif
2277
2278#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
2279
2280#define ResourceRecordIsValidAnswer(RR) ( ((RR)->             resrec.RecordType & kDNSRecordTypeActiveMask)  && \
2281		((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
2282		((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
2283		((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask))  )
2284
2285#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
2286	(ResourceRecordIsValidAnswer(RR) && \
2287	((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
2288
2289#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
2290#define DefaultProbeCountForRecordType(X)      ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
2291
2292#define InitialAnnounceCount ((mDNSu8)10)
2293
2294// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
2295// This means that because the announce interval is doubled after sending the first packet, the first
2296// observed on-the-wire inter-packet interval between announcements is actually one second.
2297// The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
2298#define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
2299#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
2300#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
2301
2302#define DefaultAPIntervalForRecordType(X)  ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared     ) ? DefaultAnnounceIntervalForTypeShared : \
2303											(X) & (kDNSRecordTypeUnique                              ) ? DefaultProbeIntervalForTypeUnique    : \
2304											(X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
2305
2306#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
2307#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
2308#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
2309#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
2310
2311#define MaxUnansweredQueries 4
2312
2313// SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
2314// (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
2315// TTL and rdata may differ.
2316// This is used for cache flush management:
2317// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
2318// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
2319mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, const ResourceRecord *const r2)
2320	{
2321	if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
2322	if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
2323	if (r1->InterfaceID &&
2324		r2->InterfaceID &&
2325		r1->InterfaceID != r2->InterfaceID) return(mDNSfalse);
2326	return(mDNSBool)(
2327		r1->rrtype == r2->rrtype &&
2328		r1->rrclass == r2->rrclass &&
2329		r1->namehash == r2->namehash &&
2330		SameDomainName(r1->name, r2->name));
2331	}
2332
2333// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
2334// authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
2335// complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
2336// In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
2337// so a response of any type should match, even if it is not actually the type the client plans to use.
2338mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
2339	{
2340	if (!pktrr)  { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
2341	if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
2342	if (pktrr->resrec.InterfaceID &&
2343		authrr->resrec.InterfaceID &&
2344		pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
2345	if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
2346	return(mDNSBool)(
2347		pktrr->resrec.rrclass == authrr->resrec.rrclass &&
2348		pktrr->resrec.namehash == authrr->resrec.namehash &&
2349		SameDomainName(pktrr->resrec.name, authrr->resrec.name));
2350	}
2351
2352// IdenticalResourceRecord returns true if two resources records have
2353// the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
2354mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
2355	{
2356	if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
2357	if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
2358	if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
2359		return(mDNSfalse);
2360	return(SameRData(r1, r2));
2361	}
2362
2363// CacheRecord *ks is the CacheRecord from the known answer list in the query.
2364// This is the information that the requester believes to be correct.
2365// AuthRecord *rr is the answer we are proposing to give, if not suppressed.
2366// This is the information that we believe to be correct.
2367// We've already determined that we plan to give this answer on this interface
2368// (either the record is non-specific, or it is specific to this interface)
2369// so now we just need to check the name, type, class, rdata and TTL.
2370mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
2371	{
2372	// If RR signature is different, or data is different, then don't suppress our answer
2373	if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
2374
2375	// If the requester's indicated TTL is less than half the real TTL,
2376	// we need to give our answer before the requester's copy expires.
2377	// If the requester's indicated TTL is at least half the real TTL,
2378	// then we can suppress our answer this time.
2379	// If the requester's indicated TTL is greater than the TTL we believe,
2380	// then that's okay, and we don't need to do anything about it.
2381	// (If two responders on the network are offering the same information,
2382	// that's okay, and if they are offering the information with different TTLs,
2383	// the one offering the lower TTL should defer to the one offering the higher TTL.)
2384	return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
2385	}
2386
2387mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
2388	{
2389	if (rr->resrec.RecordType == kDNSRecordTypeUnique)
2390		{
2391		//LogMsg("ProbeCount %d Next %ld %s",
2392		//	rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
2393		if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
2394			m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
2395		}
2396	else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
2397		{
2398		if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
2399			m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
2400		}
2401	}
2402
2403mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
2404	{
2405	// To allow us to aggregate probes when a group of services are registered together,
2406	// the first probe is delayed 1/4 second. This means the common-case behaviour is:
2407	// 1/4 second wait; probe
2408	// 1/4 second wait; probe
2409	// 1/4 second wait; probe
2410	// 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
2411
2412	// If we have no probe suppression time set, or it is in the past, set it now
2413	if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
2414		{
2415		m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
2416		// If we already have a probe scheduled to go out sooner, then use that time to get better aggregation
2417		if (m->SuppressProbes - m->NextScheduledProbe >= 0)
2418			m->SuppressProbes = m->NextScheduledProbe;
2419		// If we already have a query scheduled to go out sooner, then use that time to get better aggregation
2420		if (m->SuppressProbes - m->NextScheduledQuery >= 0)
2421			m->SuppressProbes = m->NextScheduledQuery;
2422		}
2423
2424	// We announce to flush stale data from other caches. It is a reasonable assumption that any
2425	// old stale copies will probably have the same TTL we're using, so announcing longer than
2426	// this serves no purpose -- any stale copies of that record will have expired by then anyway.
2427	rr->AnnounceUntil   = m->timenow + TicksTTL(rr);
2428	rr->LastAPTime      = m->SuppressProbes - rr->ThisAPInterval;
2429	// Set LastMCTime to now, to inhibit multicast responses
2430	// (no need to send additional multicast responses when we're announcing anyway)
2431	rr->LastMCTime      = m->timenow;
2432	rr->LastMCInterface = mDNSInterfaceMark;
2433
2434	// If this is a record type that's not going to probe, then delay its first announcement so that
2435	// it will go out synchronized with the first announcement for the other records that *are* probing.
2436	// This is a minor performance tweak that helps keep groups of related records synchronized together.
2437	// The addition of "rr->ThisAPInterval / 2" is to make sure that, in the event that any of the probes are
2438	// delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
2439	// When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
2440	// because they will meet the criterion of being at least half-way to their scheduled announcement time.
2441	if (rr->resrec.RecordType != kDNSRecordTypeUnique)
2442		rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
2443
2444	SetNextAnnounceProbeTime(m, rr);
2445	}
2446
2447#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
2448
2449mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
2450	{
2451	domainname *target = GetRRDomainNameTarget(&rr->resrec);
2452
2453	if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
2454
2455	if (target && SameDomainName(target, &m->MulticastHostname))
2456		debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
2457
2458	if (target && !SameDomainName(target, &m->MulticastHostname))
2459		{
2460		AssignDomainName(target, &m->MulticastHostname);
2461		SetNewRData(&rr->resrec, mDNSNULL, 0);
2462
2463		// If we're in the middle of probing this record, we need to start again,
2464		// because changing its rdata may change the outcome of the tie-breaker.
2465		// (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
2466		rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
2467
2468		// If we've announced this record, we really should send a goodbye packet for the old rdata before
2469		// changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
2470		// so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
2471		if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
2472			debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
2473				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2474
2475		rr->AnnounceCount  = InitialAnnounceCount;
2476		rr->RequireGoodbye = mDNSfalse;
2477		rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
2478		InitializeLastAPTime(m,rr);
2479		}
2480	}
2481
2482mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
2483	{
2484	if (!rr->Acknowledged && rr->RecordCallback)
2485		{
2486		// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2487		// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2488		rr->Acknowledged = mDNStrue;
2489		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2490		rr->RecordCallback(m, rr, mStatus_NoError);
2491		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2492		}
2493	}
2494
2495// Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
2496#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
2497	((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
2498#define RecordIsLocalDuplicate(A,B) \
2499	((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
2500
2501mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
2502	{
2503	domainname *target = GetRRDomainNameTarget(&rr->resrec);
2504	AuthRecord *r;
2505	AuthRecord **p = &m->ResourceRecords;
2506	AuthRecord **d = &m->DuplicateRecords;
2507
2508	mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
2509
2510	if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
2511		{ LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
2512
2513#ifndef UNICAST_DISABLED
2514    if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name))
2515    	rr->uDNS_info.id = zeroID;
2516    else return uDNS_RegisterRecord(m, rr);
2517#endif
2518
2519	while (*p && *p != rr) p=&(*p)->next;
2520	while (*d && *d != rr) d=&(*d)->next;
2521	if (*d || *p)
2522		{
2523		LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list",
2524			rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2525		return(mStatus_AlreadyRegistered);
2526		}
2527
2528	if (rr->DependentOn)
2529		{
2530		if (rr->resrec.RecordType == kDNSRecordTypeUnique)
2531			rr->resrec.RecordType =  kDNSRecordTypeVerified;
2532		else
2533			{
2534			LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
2535				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2536			return(mStatus_Invalid);
2537			}
2538		if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified)))
2539			{
2540			LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
2541				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
2542			return(mStatus_Invalid);
2543			}
2544		}
2545
2546	// If this resource record is referencing a specific interface, make sure it exists
2547	if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
2548		{
2549		NetworkInterfaceInfo *intf;
2550		for (intf = m->HostInterfaces; intf; intf = intf->next)
2551			if (intf->InterfaceID == rr->resrec.InterfaceID) break;
2552		if (!intf)
2553			{
2554			debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID);
2555			return(mStatus_BadReferenceErr);
2556			}
2557		}
2558
2559	rr->next = mDNSNULL;
2560
2561	// Field Group 1: Persistent metadata for Authoritative Records
2562//	rr->Additional1       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2563//	rr->Additional2       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2564//	rr->DependentOn       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2565//	rr->RRSet             = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2566//	rr->Callback          = already set in mDNS_SetupResourceRecord
2567//	rr->Context           = already set in mDNS_SetupResourceRecord
2568//	rr->RecordType        = already set in mDNS_SetupResourceRecord
2569//	rr->HostTarget        = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2570//	rr->AllowRemoteQuery  = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2571	// Make sure target is not uninitialized data, or we may crash writing debugging log messages
2572	if (rr->HostTarget && target) target->c[0] = 0;
2573
2574	// Field Group 2: Transient state for Authoritative Records
2575	rr->Acknowledged      = mDNSfalse;
2576	rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
2577	rr->AnnounceCount     = InitialAnnounceCount;
2578	rr->RequireGoodbye    = mDNSfalse;
2579	rr->LocalAnswer       = mDNSfalse;
2580	rr->IncludeInProbe    = mDNSfalse;
2581	rr->ImmedAnswer       = mDNSNULL;
2582	rr->ImmedUnicast      = mDNSfalse;
2583	rr->ImmedAdditional   = mDNSNULL;
2584	rr->SendRNow          = mDNSNULL;
2585	rr->v4Requester       = zerov4Addr;
2586	rr->v6Requester       = zerov6Addr;
2587	rr->NextResponse      = mDNSNULL;
2588	rr->NR_AnswerTo       = mDNSNULL;
2589	rr->NR_AdditionalTo   = mDNSNULL;
2590	rr->ThisAPInterval    = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
2591	if (!rr->HostTarget) InitializeLastAPTime(m, rr);
2592//	rr->AnnounceUntil     = Set for us in InitializeLastAPTime()
2593//	rr->LastAPTime        = Set for us in InitializeLastAPTime()
2594//	rr->LastMCTime        = Set for us in InitializeLastAPTime()
2595//	rr->LastMCInterface   = Set for us in InitializeLastAPTime()
2596	rr->NewRData          = mDNSNULL;
2597	rr->newrdlength       = 0;
2598	rr->UpdateCallback    = mDNSNULL;
2599	rr->UpdateCredits     = kMaxUpdateCredits;
2600	rr->NextUpdateCredit  = 0;
2601	rr->UpdateBlocked     = 0;
2602
2603//	rr->resrec.interface         = already set in mDNS_SetupResourceRecord
2604//	rr->resrec.name->c            = MUST be set by client
2605//	rr->resrec.rrtype            = already set in mDNS_SetupResourceRecord
2606//	rr->resrec.rrclass           = already set in mDNS_SetupResourceRecord
2607//	rr->resrec.rroriginalttl     = already set in mDNS_SetupResourceRecord
2608//	rr->resrec.rdata             = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
2609
2610	if (rr->HostTarget)
2611		SetTargetToHostName(m, rr);	// Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
2612	else
2613		{
2614		rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
2615		rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
2616		}
2617
2618	if (!ValidateDomainName(rr->resrec.name))
2619		{ LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2620
2621	// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2622	// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2623	// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2624	if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
2625
2626	// Don't do this until *after* we've set rr->resrec.rdlength
2627	if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
2628		{ LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2629
2630	rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
2631	rr->resrec.rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
2632
2633	if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
2634		{
2635		// If this is supposed to be unique, make sure we don't have any name conflicts
2636		if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2637			{
2638			const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
2639			for (r = m->ResourceRecords; r; r=r->next)
2640				{
2641				const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
2642				if (s1 != s2 && SameResourceRecordSignature(&r->resrec, &rr->resrec) && !SameRData(&r->resrec, &rr->resrec))
2643					break;
2644				}
2645			if (r)	// If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
2646				{
2647				debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2648				rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
2649				rr->resrec.rroriginalttl = 0;
2650				rr->ImmedAnswer          = mDNSInterfaceMark;
2651				m->NextScheduledResponse = m->timenow;
2652				}
2653			}
2654		}
2655
2656	// Now that we've finished building our new record, make sure it's not identical to one we already have
2657	for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
2658
2659	if (r)
2660		{
2661		debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr));
2662		*d = rr;
2663		// If the previous copy of this record is already verified unique,
2664		// then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
2665		// Setting ProbeCount to zero will cause SendQueries() to advance this record to
2666		// kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
2667		if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
2668			rr->ProbeCount = 0;
2669		}
2670	else
2671		{
2672		debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr));
2673		if (!m->NewLocalRecords) m->NewLocalRecords = rr;
2674		*p = rr;
2675		}
2676
2677	// For records that are not going to probe, acknowledge them right away
2678	if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
2679		AcknowledgeRecord(m, rr);
2680
2681	return(mStatus_NoError);
2682	}
2683
2684mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
2685	{
2686	m->ProbeFailTime = m->timenow;
2687	m->NumFailedProbes++;
2688	// If we've had fifteen or more probe failures, rate-limit to one every five seconds.
2689	// If a bunch of hosts have all been configured with the same name, then they'll all
2690	// conflict and run through the same series of names: name-2, name-3, name-4, etc.,
2691	// up to name-10. After that they'll start adding random increments in the range 1-100,
2692	// so they're more likely to branch out in the available namespace and settle on a set of
2693	// unique names quickly. If after five more tries the host is still conflicting, then we
2694	// may have a serious problem, so we start rate-limiting so we don't melt down the network.
2695	if (m->NumFailedProbes >= 15)
2696		{
2697		m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
2698		LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
2699			m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2700		}
2701	}
2702
2703mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
2704	{
2705	RData *OldRData = rr->resrec.rdata;
2706	SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);	// Update our rdata
2707	rr->NewRData = mDNSNULL;									// Clear the NewRData pointer ...
2708	if (rr->UpdateCallback)
2709		rr->UpdateCallback(m, rr, OldRData);					// ... and let the client know
2710	}
2711
2712// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
2713// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
2714// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
2715typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
2716
2717// NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
2718// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2719mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
2720	{
2721	AuthRecord *r2;
2722	mDNSu8 RecordType = rr->resrec.RecordType;
2723	AuthRecord **p = &m->ResourceRecords;	// Find this record in our list of active records
2724
2725#ifndef UNICAST_DISABLED
2726    if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name)))
2727		return uDNS_DeregisterRecord(m, rr);
2728#endif
2729
2730	while (*p && *p != rr) p=&(*p)->next;
2731
2732	if (*p)
2733		{
2734		// We found our record on the main list. See if there are any duplicates that need special handling.
2735		if (drt == mDNS_Dereg_conflict)		// If this was a conflict, see that all duplicates get the same treatment
2736			{
2737			// Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
2738			// deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
2739			for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
2740			}
2741		else
2742			{
2743			// Before we delete the record (and potentially send a goodbye packet)
2744			// first see if we have a record on the duplicate list ready to take over from it.
2745			AuthRecord **d = &m->DuplicateRecords;
2746			while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next;
2747			if (*d)
2748				{
2749				AuthRecord *dup = *d;
2750				debugf("Duplicate record %p taking over from %p %##s (%s)",
2751					dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2752				*d        = dup->next;		// Cut replacement record from DuplicateRecords list
2753				dup->next = rr->next;		// And then...
2754				rr->next  = dup;			// ... splice it in right after the record we're about to delete
2755				dup->resrec.RecordType        = rr->resrec.RecordType;
2756				dup->ProbeCount      = rr->ProbeCount;
2757				dup->AnnounceCount   = rr->AnnounceCount;
2758				dup->RequireGoodbye  = rr->RequireGoodbye;
2759				dup->ImmedAnswer     = rr->ImmedAnswer;
2760				dup->ImmedUnicast    = rr->ImmedUnicast;
2761				dup->ImmedAdditional = rr->ImmedAdditional;
2762				dup->v4Requester     = rr->v4Requester;
2763				dup->v6Requester     = rr->v6Requester;
2764				dup->ThisAPInterval  = rr->ThisAPInterval;
2765				dup->AnnounceUntil   = rr->AnnounceUntil;
2766				dup->LastAPTime      = rr->LastAPTime;
2767				dup->LastMCTime      = rr->LastMCTime;
2768				dup->LastMCInterface = rr->LastMCInterface;
2769				rr->RequireGoodbye = mDNSfalse;
2770				}
2771			}
2772		}
2773	else
2774		{
2775		// We didn't find our record on the main list; try the DuplicateRecords list instead.
2776		p = &m->DuplicateRecords;
2777		while (*p && *p != rr) p=&(*p)->next;
2778		// If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2779		if (*p) rr->RequireGoodbye = mDNSfalse;
2780		if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2781			rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2782		}
2783
2784	if (!*p)
2785		{
2786		// No need to log an error message if we already know this is a potentially repeated deregistration
2787		if (drt != mDNS_Dereg_repeat)
2788			LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list",
2789				rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2790		return(mStatus_BadReferenceErr);
2791		}
2792
2793	// If this is a shared record and we've announced it at least once,
2794	// we need to retract that announcement before we delete the record
2795	if (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
2796		{
2797		verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)",
2798			rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2799		rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
2800		rr->resrec.rroriginalttl = 0;
2801		rr->ImmedAnswer          = mDNSInterfaceMark;
2802		if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
2803			m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
2804		}
2805	else
2806		{
2807		*p = rr->next;					// Cut this record from the list
2808		// If someone is about to look at this, bump the pointer forward
2809		if (m->CurrentRecord   == rr) m->CurrentRecord   = rr->next;
2810		if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
2811		rr->next = mDNSNULL;
2812
2813		if      (RecordType == kDNSRecordTypeUnregistered)
2814			debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered",
2815				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2816		else if (RecordType == kDNSRecordTypeDeregistering)
2817			debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering",
2818				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2819		else
2820			{
2821			verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)",
2822				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2823			rr->resrec.RecordType = kDNSRecordTypeUnregistered;
2824			}
2825
2826		if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
2827			debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2828				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2829
2830		// If we have an update queued up which never executed, give the client a chance to free that memory
2831		if (rr->NewRData) CompleteRDataUpdate(m, rr);	// Update our rdata, clear the NewRData pointer, and return memory to the client
2832
2833		if (rr->LocalAnswer) AnswerLocalQuestions(m, rr, mDNSfalse);
2834
2835		// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2836		// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2837		// In this case the likely client action to the mStatus_MemFree message is to free the memory,
2838		// so any attempt to touch rr after this is likely to lead to a crash.
2839		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2840		if (drt != mDNS_Dereg_conflict)
2841			{
2842			if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);			// MUST NOT touch rr after this
2843			}
2844		else
2845			{
2846			RecordProbeFailure(m, rr);
2847			if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict);	// MUST NOT touch rr after this
2848			// Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2849			// Note that with all the client callbacks going on, by the time we get here all the
2850			// records we marked may have been explicitly deregistered by the client anyway.
2851			r2 = m->DuplicateRecords;
2852			while (r2)
2853				{
2854				if (r2->ProbeCount != 0xFF) r2 = r2->next;
2855				else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
2856				}
2857			}
2858		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2859		}
2860	return(mStatus_NoError);
2861	}
2862
2863// ***************************************************************************
2864#if COMPILER_LIKES_PRAGMA_MARK
2865#pragma mark -
2866#pragma mark -
2867#pragma mark - Packet Sending Functions
2868#endif
2869
2870mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
2871	{
2872	if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
2873		{
2874		**nrpp = rr;
2875		// NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2876		// If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2877		// The referenced record will definitely be acceptable (by recursive application of this rule)
2878		if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
2879		rr->NR_AdditionalTo = add;
2880		*nrpp = &rr->NextResponse;
2881		}
2882	debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2883	}
2884
2885mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
2886	{
2887	AuthRecord  *rr, *rr2;
2888	for (rr=ResponseRecords; rr; rr=rr->NextResponse)			// For each record we plan to put
2889		{
2890		// (Note: This is an "if", not a "while". If we add a record, we'll find it again
2891		// later in the "for" loop, and we will follow further "additional" links then.)
2892		if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
2893			AddRecordToResponseList(nrpp, rr->Additional1, rr);
2894
2895		if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
2896			AddRecordToResponseList(nrpp, rr->Additional2, rr);
2897
2898		// For SRV records, automatically add the Address record(s) for the target host
2899		if (rr->resrec.rrtype == kDNSType_SRV)
2900			for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)					// Scan list of resource records
2901				if (RRTypeIsAddressType(rr2->resrec.rrtype) &&					// For all address records (A/AAAA) ...
2902					ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&	// ... which are valid for answer ...
2903					rr->resrec.rdatahash == rr2->resrec.namehash &&			// ... whose name is the name of the SRV target
2904					SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
2905					AddRecordToResponseList(nrpp, rr2, rr);
2906		}
2907	}
2908
2909mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
2910	{
2911	AuthRecord *rr;
2912	AuthRecord  *ResponseRecords = mDNSNULL;
2913	AuthRecord **nrp             = &ResponseRecords;
2914
2915	// Make a list of all our records that need to be unicast to this destination
2916	for (rr = m->ResourceRecords; rr; rr=rr->next)
2917		{
2918		// If we find we can no longer unicast this answer, clear ImmedUnicast
2919		if (rr->ImmedAnswer == mDNSInterfaceMark               ||
2920			mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
2921			mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr)  )
2922			rr->ImmedUnicast = mDNSfalse;
2923
2924		if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
2925			if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
2926				(dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
2927				{
2928				rr->ImmedAnswer  = mDNSNULL;				// Clear the state fields
2929				rr->ImmedUnicast = mDNSfalse;
2930				rr->v4Requester  = zerov4Addr;
2931				rr->v6Requester  = zerov6Addr;
2932				if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse)	// rr->NR_AnswerTo
2933					{ rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; }
2934				}
2935		}
2936
2937	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
2938
2939	while (ResponseRecords)
2940		{
2941		mDNSu8 *responseptr = m->omsg.data;
2942		mDNSu8 *newptr;
2943		InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
2944
2945		// Put answers in the packet
2946		while (ResponseRecords && ResponseRecords->NR_AnswerTo)
2947			{
2948			rr = ResponseRecords;
2949			if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2950				rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
2951			newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2952			rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
2953			if (!newptr && m->omsg.h.numAnswers) break;	// If packet full, send it now
2954			if (newptr) responseptr = newptr;
2955			ResponseRecords = rr->NextResponse;
2956			rr->NextResponse    = mDNSNULL;
2957			rr->NR_AnswerTo     = mDNSNULL;
2958			rr->NR_AdditionalTo = mDNSNULL;
2959			rr->RequireGoodbye  = mDNStrue;
2960			}
2961
2962		// Add additionals, if there's space
2963		while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
2964			{
2965			rr = ResponseRecords;
2966			if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2967				rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
2968			newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec);
2969			rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
2970
2971			if (newptr) responseptr = newptr;
2972			if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue;
2973			else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark;
2974			ResponseRecords = rr->NextResponse;
2975			rr->NextResponse    = mDNSNULL;
2976			rr->NR_AnswerTo     = mDNSNULL;
2977			rr->NR_AdditionalTo = mDNSNULL;
2978			}
2979
2980		if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, -1, mDNSNULL);
2981		}
2982	}
2983
2984mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
2985	{
2986	// Clearing rr->RequireGoodbye signals mDNS_Deregister_internal()
2987	// that it should go ahead and immediately dispose of this registration
2988	rr->resrec.RecordType = kDNSRecordTypeShared;
2989	rr->RequireGoodbye    = mDNSfalse;
2990	mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);		// Don't touch rr after this
2991	}
2992
2993// NOTE: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
2994// the record list and/or question list.
2995// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2996mDNSlocal void DiscardDeregistrations(mDNS *const m)
2997	{
2998	if (m->CurrentRecord) LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set");
2999	m->CurrentRecord = m->ResourceRecords;
3000
3001	while (m->CurrentRecord)
3002		{
3003		AuthRecord *rr = m->CurrentRecord;
3004		if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3005			CompleteDeregistration(m, rr);		// Don't touch rr after this
3006		else
3007			m->CurrentRecord = rr->next;
3008		}
3009	}
3010
3011mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
3012	{
3013	if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0;
3014	else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval);
3015	}
3016
3017// Note about acceleration of announcements to facilitate automatic coalescing of
3018// multiple independent threads of announcements into a single synchronized thread:
3019// The announcements in the packet may be at different stages of maturity;
3020// One-second interval, two-second interval, four-second interval, and so on.
3021// After we've put in all the announcements that are due, we then consider
3022// whether there are other nearly-due announcements that are worth accelerating.
3023// To be eligible for acceleration, a record MUST NOT be older (further along
3024// its timeline) than the most mature record we've already put in the packet.
3025// In other words, younger records can have their timelines accelerated to catch up
3026// with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
3027// Older records cannot have their timelines accelerated; this would just widen
3028// the gap between them and their younger bretheren and get them even more out of sync.
3029
3030// NOTE: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
3031// the record list and/or question list.
3032// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3033mDNSlocal void SendResponses(mDNS *const m)
3034	{
3035	int pktcount = 0;
3036	AuthRecord *rr, *r2;
3037	mDNSs32 maxExistingAnnounceInterval = 0;
3038	const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
3039
3040	m->NextScheduledResponse = m->timenow + 0x78000000;
3041
3042	for (rr = m->ResourceRecords; rr; rr=rr->next)
3043		if (rr->ImmedUnicast)
3044			{
3045			mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} };
3046			mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} };
3047			v4.ip.v4 = rr->v4Requester;
3048			v6.ip.v6 = rr->v6Requester;
3049			if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer);
3050			if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer);
3051			if (rr->ImmedUnicast)
3052				{
3053				LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr));
3054				rr->ImmedUnicast = mDNSfalse;
3055				}
3056			}
3057
3058	// ***
3059	// *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
3060	// ***
3061
3062	// Run through our list of records, and decide which ones we're going to announce on all interfaces
3063	for (rr = m->ResourceRecords; rr; rr=rr->next)
3064		{
3065		while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
3066		if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
3067			{
3068			rr->ImmedAnswer = mDNSInterfaceMark;		// Send on all interfaces
3069			if (maxExistingAnnounceInterval < rr->ThisAPInterval)
3070				maxExistingAnnounceInterval = rr->ThisAPInterval;
3071			if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
3072			}
3073		}
3074
3075	// Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
3076	// Eligible records that are more than half-way to their announcement time are accelerated
3077	for (rr = m->ResourceRecords; rr; rr=rr->next)
3078		if ((rr->resrec.InterfaceID && rr->ImmedAnswer) ||
3079			(rr->ThisAPInterval <= maxExistingAnnounceInterval &&
3080			TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) &&
3081			ResourceRecordIsValidAnswer(rr)))
3082			rr->ImmedAnswer = mDNSInterfaceMark;		// Send on all interfaces
3083
3084	// When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
3085	// NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
3086	// which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
3087	// then all that means is that it won't get sent -- which would not be the end of the world.
3088	for (rr = m->ResourceRecords; rr; rr=rr->next)
3089		if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
3090			for (r2=m->ResourceRecords; r2; r2=r2->next)				// Scan list of resource records
3091				if (RRTypeIsAddressType(r2->resrec.rrtype) &&			// For all address records (A/AAAA) ...
3092					ResourceRecordIsValidAnswer(r2) &&					// ... which are valid for answer ...
3093					rr->LastMCTime - r2->LastMCTime >= 0 &&				// ... which we have not sent recently ...
3094					rr->resrec.rdatahash == r2->resrec.namehash &&		// ... whose name is the name of the SRV target
3095					SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
3096					(rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
3097					r2->ImmedAdditional = r2->resrec.InterfaceID;		// ... then mark this address record for sending too
3098
3099	// If there's a record which is supposed to be unique that we're going to send, then make sure that we give
3100	// the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
3101	// then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
3102	// record, then other RRSet members that have not been sent recently will get flushed out of client caches.
3103	// -- If a record is marked to be sent on a certain interface, make sure the whole set is marked to be sent on that interface
3104	// -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
3105	for (rr = m->ResourceRecords; rr; rr=rr->next)
3106		if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3107			{
3108			if (rr->ImmedAnswer)			// If we're sending this as answer, see that its whole RRSet is similarly marked
3109				{
3110				for (r2 = m->ResourceRecords; r2; r2=r2->next)
3111					if (ResourceRecordIsValidAnswer(r2))
3112						if (r2->ImmedAnswer != mDNSInterfaceMark &&
3113							r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
3114							r2->ImmedAnswer = rr->ImmedAnswer;
3115				}
3116			else if (rr->ImmedAdditional)	// If we're sending this as additional, see that its whole RRSet is similarly marked
3117				{
3118				for (r2 = m->ResourceRecords; r2; r2=r2->next)
3119					if (ResourceRecordIsValidAnswer(r2))
3120						if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
3121							r2->ImmedAdditional = rr->ImmedAdditional;
3122				}
3123			}
3124
3125	// Now set SendRNow state appropriately
3126	for (rr = m->ResourceRecords; rr; rr=rr->next)
3127		{
3128		if (rr->ImmedAnswer == mDNSInterfaceMark)		// Sending this record on all appropriate interfaces
3129			{
3130			rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
3131			rr->ImmedAdditional = mDNSNULL;				// No need to send as additional if sending as answer
3132			rr->LastMCTime      = m->timenow;
3133			rr->LastMCInterface = rr->ImmedAnswer;
3134			// If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
3135			if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
3136				{
3137				rr->AnnounceCount--;
3138				rr->ThisAPInterval *= 2;
3139				rr->LastAPTime = m->timenow;
3140				if (rr->LastAPTime + rr->ThisAPInterval - rr->AnnounceUntil >= 0) rr->AnnounceCount = 0;
3141				debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
3142				}
3143			}
3144		else if (rr->ImmedAnswer)						// Else, just respond to a single query on single interface:
3145			{
3146			rr->SendRNow        = rr->ImmedAnswer;		// Just respond on that interface
3147			rr->ImmedAdditional = mDNSNULL;				// No need to send as additional too
3148			rr->LastMCTime      = m->timenow;
3149			rr->LastMCInterface = rr->ImmedAnswer;
3150			}
3151		SetNextAnnounceProbeTime(m, rr);
3152		//if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
3153		}
3154
3155	// ***
3156	// *** 2. Loop through interface list, sending records as appropriate
3157	// ***
3158
3159	while (intf)
3160		{
3161		int numDereg    = 0;
3162		int numAnnounce = 0;
3163		int numAnswer   = 0;
3164		mDNSu8 *responseptr = m->omsg.data;
3165		mDNSu8 *newptr;
3166		InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
3167
3168		// First Pass. Look for:
3169		// 1. Deregistering records that need to send their goodbye packet
3170		// 2. Updated records that need to retract their old data
3171		// 3. Answers and announcements we need to send
3172		// In all cases, if we fail, and we've put at least one answer, we break out of the for loop so we can
3173		// send this packet and then try again.
3174		// If we have not put even one answer, then we don't bail out. We pretend we succeeded anyway,
3175		// because otherwise we'll end up in an infinite loop trying to send a record that will never fit.
3176		for (rr = m->ResourceRecords; rr; rr=rr->next)
3177			if (rr->SendRNow == intf->InterfaceID)
3178				{
3179				if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3180					{
3181					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
3182					if (!newptr && m->omsg.h.numAnswers) break;
3183					numDereg++;
3184					responseptr = newptr;
3185					}
3186				else if (rr->NewRData && !m->SleepState)					// If we have new data for this record
3187					{
3188					RData *OldRData     = rr->resrec.rdata;
3189					mDNSu16 oldrdlength = rr->resrec.rdlength;
3190					// See if we should send a courtesy "goodbye" for the old data before we replace it.
3191					if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
3192						{
3193						newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
3194						if (!newptr && m->omsg.h.numAnswers) break;
3195						numDereg++;
3196						responseptr = newptr;
3197						rr->RequireGoodbye = mDNSfalse;
3198						}
3199					// Now try to see if we can fit the update in the same packet (not fatal if we can't)
3200					SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
3201					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3202						rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
3203					newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
3204					rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
3205					if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
3206					SetNewRData(&rr->resrec, OldRData, oldrdlength);
3207					}
3208				else
3209					{
3210					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3211						rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
3212					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl);
3213					rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
3214					if (!newptr && m->omsg.h.numAnswers) break;
3215					rr->RequireGoodbye = (mDNSu8) (!m->SleepState);
3216					if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
3217					responseptr = newptr;
3218					}
3219				// If sending on all interfaces, go to next interface; else we're finished now
3220				if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
3221					rr->SendRNow = GetNextActiveInterfaceID(intf);
3222				else
3223					rr->SendRNow = mDNSNULL;
3224				}
3225
3226		// Second Pass. Add additional records, if there's space.
3227		newptr = responseptr;
3228		for (rr = m->ResourceRecords; rr; rr=rr->next)
3229			if (rr->ImmedAdditional == intf->InterfaceID)
3230				if (ResourceRecordIsValidAnswer(rr))
3231					{
3232					// If we have at least one answer already in the packet, then plan to add additionals too
3233					mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0);
3234
3235					// If we're not planning to send any additionals, but this record is a unique one, then
3236					// make sure we haven't already sent any other members of its RRSet -- if we have, then they
3237					// will have had the cache flush bit set, so now we need to finish the job and send the rest.
3238					if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask))
3239						{
3240						const AuthRecord *a;
3241						for (a = m->ResourceRecords; a; a=a->next)
3242							if (a->LastMCTime      == m->timenow &&
3243								a->LastMCInterface == intf->InterfaceID &&
3244								SameResourceRecordSignature(&a->resrec, &rr->resrec)) { SendAdditional = mDNStrue; break; }
3245						}
3246					if (!SendAdditional)					// If we don't want to send this after all,
3247						rr->ImmedAdditional = mDNSNULL;		// then cancel its ImmedAdditional field
3248					else if (newptr)						// Else, try to add it if we can
3249						{
3250						if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3251							rr->resrec.rrclass |= kDNSClass_UniqueRRSet;	// Temporarily set the cache flush bit so PutResourceRecord will set it
3252						newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
3253						rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;		// Make sure to clear cache flush bit back to normal state
3254						if (newptr)
3255							{
3256							responseptr = newptr;
3257							rr->ImmedAdditional = mDNSNULL;
3258							rr->RequireGoodbye = mDNStrue;
3259							// If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
3260							// This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
3261							// when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
3262							// all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
3263							rr->LastMCTime      = m->timenow;
3264							rr->LastMCInterface = intf->InterfaceID;
3265							}
3266						}
3267					}
3268
3269		if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
3270			{
3271			debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
3272				numDereg,                  numDereg                  == 1 ? "" : "s",
3273				numAnnounce,               numAnnounce               == 1 ? "" : "s",
3274				numAnswer,                 numAnswer                 == 1 ? "" : "s",
3275				m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
3276			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
3277			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
3278			if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3279			if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
3280			// There might be more things to send on this interface, so go around one more time and try again.
3281			}
3282		else	// Nothing more to send on this interface; go to next
3283			{
3284			const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3285			#if MDNS_DEBUGMSGS && 0
3286			const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
3287			debugf(msg, intf, next);
3288			#endif
3289			intf = next;
3290			}
3291		}
3292
3293	// ***
3294	// *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
3295	// ***
3296
3297	if (m->CurrentRecord) LogMsg("SendResponses: ERROR m->CurrentRecord already set");
3298	m->CurrentRecord = m->ResourceRecords;
3299	while (m->CurrentRecord)
3300		{
3301		rr = m->CurrentRecord;
3302		m->CurrentRecord = rr->next;
3303
3304		if (rr->SendRNow)
3305			{
3306			if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
3307				LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr));
3308			rr->SendRNow = mDNSNULL;
3309			}
3310
3311		if (rr->ImmedAnswer)
3312			{
3313			if (rr->NewRData) CompleteRDataUpdate(m,rr);	// Update our rdata, clear the NewRData pointer, and return memory to the client
3314
3315			if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3316				CompleteDeregistration(m, rr);		// Don't touch rr after this
3317			else
3318				{
3319				rr->ImmedAnswer  = mDNSNULL;
3320				rr->ImmedUnicast = mDNSfalse;
3321				rr->v4Requester  = zerov4Addr;
3322				rr->v6Requester  = zerov6Addr;
3323				}
3324			}
3325		}
3326	verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow);
3327	}
3328
3329// Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
3330// so we want to be lazy about how frequently we do it.
3331// 1. If a cache record is currently referenced by *no* active questions,
3332//    then we don't mind expiring it up to a minute late (who will know?)
3333// 2. Else, if a cache record is due for some of its final expiration queries,
3334//    we'll allow them to be late by up to 2% of the TTL
3335// 3. Else, if a cache record has completed all its final expiration queries without success,
3336//    and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
3337// 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
3338//    so allow at most 1/10 second lateness
3339#define CacheCheckGracePeriod(RR) (                                                   \
3340	((RR)->DelayDelivery                           ) ? (mDNSPlatformOneSecond/10)   : \
3341	((RR)->CRActiveQuestion == mDNSNULL            ) ? (60 * mDNSPlatformOneSecond) : \
3342	((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50)            : \
3343	((RR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : (mDNSPlatformOneSecond/10))
3344
3345// Note: MUST call SetNextCacheCheckTime any time we change:
3346// rr->TimeRcvd
3347// rr->resrec.rroriginalttl
3348// rr->UnansweredQueries
3349// rr->CRActiveQuestion
3350// Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
3351// Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
3352mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
3353	{
3354	rr->NextRequiredQuery = RRExpireTime(rr);
3355
3356	// If we have an active question, then see if we want to schedule a refresher query for this record.
3357	// Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
3358	if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3359		{
3360		rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
3361		rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
3362		verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
3363			rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
3364			(rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
3365		}
3366
3367	if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
3368		m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
3369
3370	if (rr->DelayDelivery)
3371		if (m->NextCacheCheck - rr->DelayDelivery > 0)
3372			m->NextCacheCheck = rr->DelayDelivery;
3373	}
3374
3375#define kMinimumReconfirmTime                     ((mDNSu32)mDNSPlatformOneSecond *  5)
3376#define kDefaultReconfirmTimeForWake              ((mDNSu32)mDNSPlatformOneSecond *  5)
3377#define kDefaultReconfirmTimeForNoAnswer          ((mDNSu32)mDNSPlatformOneSecond * 15)
3378#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
3379
3380mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
3381	{
3382	if (interval < kMinimumReconfirmTime)
3383		interval = kMinimumReconfirmTime;
3384	if (interval > 0x10000000)	// Make sure interval doesn't overflow when we multiply by four below
3385		interval = 0x10000000;
3386
3387	// If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
3388	if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3))
3389		{
3390		// Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
3391		// For all the reconfirmations in a given batch, we want to use the same random value
3392		// so that the reconfirmation questions can be grouped into a single query packet
3393		if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
3394		interval += mDNSRandomFromFixedSeed(m->RandomReconfirmDelay, interval/3);
3395		rr->TimeRcvd          = m->timenow - (mDNSs32)interval * 3;
3396		rr->resrec.rroriginalttl     = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
3397		SetNextCacheCheckTime(m, rr);
3398		}
3399	debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s", RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr));
3400	return(mStatus_NoError);
3401	}
3402
3403#define MaxQuestionInterval         (3600 * mDNSPlatformOneSecond)
3404
3405// BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
3406// It also appends to the list of known answer records that need to be included,
3407// and updates the forcast for the size of the known answer section.
3408mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q,
3409	CacheRecord ***kalistptrptr, mDNSu32 *answerforecast)
3410	{
3411	mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
3412	mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3413	const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
3414	mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
3415	if (!newptr)
3416		{
3417		debugf("BuildQuestion: No more space in this packet for question %##s", q->qname.c);
3418		return(mDNSfalse);
3419		}
3420	else if (newptr + *answerforecast >= limit)
3421		{
3422		verbosedebugf("BuildQuestion: Retracting question %##s new forecast total %d",
3423			q->qname.c, newptr + *answerforecast - query->data);
3424		query->h.numQuestions--;
3425		return(mDNSfalse);
3426		}
3427	else
3428		{
3429		mDNSu32 forecast = *answerforecast;
3430		const mDNSu32 slot = HashSlot(&q->qname);
3431		CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3432		CacheRecord *rr;
3433		CacheRecord **ka = *kalistptrptr;	// Make a working copy of the pointer we're going to update
3434
3435		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// If we have a resource record in our cache,
3436			if (rr->resrec.InterfaceID == q->SendQNow &&					// received on this interface
3437				rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&	// which is not already in the known answer list
3438				rr->resrec.rdlength <= SmallRecordLimit &&					// which is small enough to sensibly fit in the packet
3439				ResourceRecordAnswersQuestion(&rr->resrec, q) &&			// which answers our question
3440				rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >				// and its half-way-to-expiry time is at least 1 second away
3441												mDNSPlatformOneSecond)		// (also ensures we never include goodbye records with TTL=1)
3442				{
3443				*ka = rr;	// Link this record into our known answer chain
3444				ka = &rr->NextInKAList;
3445				// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3446				forecast += 12 + rr->resrec.rdestimate;
3447				// If we're trying to put more than one question in this packet, and it doesn't fit
3448				// then undo that last question and try again next time
3449				if (query->h.numQuestions > 1 && newptr + forecast >= limit)
3450					{
3451					debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3452						q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data);
3453					query->h.numQuestions--;
3454					ka = *kalistptrptr;		// Go back to where we started and retract these answer records
3455					while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
3456					return(mDNSfalse);		// Return false, so we'll try again in the next packet
3457					}
3458				}
3459
3460		// Traffic reduction:
3461		// If we already have at least one unique answer in the cache,
3462		// OR we have so many shared answers that the KA list is too big to fit in one packet
3463		// The we suppress queries number 3 and 5:
3464		// Query 1 (immediately;      ThisQInterval =  1 sec; request unicast replies)
3465		// Query 2 (after  1 second;  ThisQInterval =  2 sec; send normally)
3466		// Query 3 (after  2 seconds; ThisQInterval =  4 sec; may suppress)
3467		// Query 4 (after  4 seconds; ThisQInterval =  8 sec; send normally)
3468		// Query 5 (after  8 seconds; ThisQInterval = 16 sec; may suppress)
3469		// Query 6 (after 16 seconds; ThisQInterval = 32 sec; send normally)
3470		if (q->UniqueAnswers || newptr + forecast >= limit)
3471			if (q->ThisQInterval == InitialQuestionInterval * 8 || q->ThisQInterval == InitialQuestionInterval * 32)
3472				{
3473				query->h.numQuestions--;
3474				ka = *kalistptrptr;		// Go back to where we started and retract these answer records
3475				while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
3476				return(mDNStrue);		// Return true: pretend we succeeded, even though we actually suppressed this question
3477				}
3478
3479		// Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
3480		*queryptr        = newptr;				// Update the packet pointer
3481		*answerforecast  = forecast;			// Update the forecast
3482		*kalistptrptr    = ka;					// Update the known answer list pointer
3483		if (ucast) m->ExpectUnicastResponse = m->timenow;
3484
3485		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// For every resource record in our cache,
3486			if (rr->resrec.InterfaceID == q->SendQNow &&					// received on this interface
3487				rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&	// which is not in the known answer list
3488				ResourceRecordAnswersQuestion(&rr->resrec, q))				// which answers our question
3489					{
3490					rr->UnansweredQueries++;								// indicate that we're expecting a response
3491					rr->LastUnansweredTime = m->timenow;
3492					SetNextCacheCheckTime(m, rr);
3493					}
3494
3495		return(mDNStrue);
3496		}
3497	}
3498
3499mDNSlocal void ReconfirmAntecedents(mDNS *const m, DNSQuestion *q)
3500	{
3501	mDNSu32 slot;
3502	CacheGroup *cg;
3503	CacheRecord *rr;
3504	domainname *target;
3505	FORALL_CACHERECORDS(slot, cg, rr)
3506		if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdatahash == q->qnamehash && SameDomainName(target, &q->qname))
3507			mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
3508	}
3509
3510// Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
3511mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time)
3512	{
3513	int i;
3514	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3515	}
3516
3517mDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID)
3518	{
3519	int i;
3520	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3521	}
3522
3523mDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf)
3524	{
3525	int i;
3526	mDNSBool v4 = !intf->IPv4Available;		// If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
3527	mDNSBool v6 = !intf->IPv6Available;		// If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
3528	for (i=0; i<DupSuppressInfoSize; i++)
3529		if (ds[i].InterfaceID == intf->InterfaceID)
3530			{
3531			if      (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue;
3532			else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue;
3533			if (v4 && v6) return(mDNStrue);
3534			}
3535	return(mDNSfalse);
3536	}
3537
3538mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type)
3539	{
3540	int i, j;
3541
3542	// See if we have this one in our list somewhere already
3543	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break;
3544
3545	// If not, find a slot we can re-use
3546	if (i >= DupSuppressInfoSize)
3547		{
3548		i = 0;
3549		for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++)
3550			if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0)
3551				i = j;
3552		}
3553
3554	// Record the info about this query we saw
3555	ds[i].Time        = Time;
3556	ds[i].InterfaceID = InterfaceID;
3557	ds[i].Type        = Type;
3558
3559	return(i);
3560	}
3561
3562mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
3563	{
3564	// If more than 90% of the way to the query time, we should unconditionally accelerate it
3565	if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10))
3566		return(mDNStrue);
3567
3568	// If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
3569	if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2))
3570		{
3571		// We forecast: qname (n) type (2) class (2)
3572		mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
3573		const mDNSu32 slot = HashSlot(&q->qname);
3574		CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3575		CacheRecord *rr;
3576		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// If we have a resource record in our cache,
3577			if (rr->resrec.rdlength <= SmallRecordLimit &&					// which is small enough to sensibly fit in the packet
3578				ResourceRecordAnswersQuestion(&rr->resrec, q) &&			// which answers our question
3579				rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 &&			// and it is less than half-way to expiry
3580				rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery
3581				{
3582				// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3583				forecast += 12 + rr->resrec.rdestimate;
3584				if (forecast >= 512) return(mDNSfalse);	// If this would add 512 bytes or more to the packet, don't accelerate
3585				}
3586		return(mDNStrue);
3587		}
3588
3589	return(mDNSfalse);
3590	}
3591
3592// How Standard Queries are generated:
3593// 1. The Question Section contains the question
3594// 2. The Additional Section contains answers we already know, to suppress duplicate responses
3595
3596// How Probe Queries are generated:
3597// 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
3598// if some other host is already using *any* records with this name, we want to know about it.
3599// 2. The Authority Section contains the proposed values we intend to use for one or more
3600// of our records with that name (analogous to the Update section of DNS Update packets)
3601// because if some other host is probing at the same time, we each want to know what the other is
3602// planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
3603
3604mDNSlocal void SendQueries(mDNS *const m)
3605	{
3606	mDNSu32 slot;
3607	CacheGroup *cg;
3608	CacheRecord *cr;
3609	AuthRecord *ar;
3610	int pktcount = 0;
3611	DNSQuestion *q;
3612	// For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
3613	mDNSs32 maxExistingQuestionInterval = 0;
3614	const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
3615	CacheRecord *KnownAnswerList = mDNSNULL;
3616
3617	// 1. If time for a query, work out what we need to do
3618	if (m->timenow - m->NextScheduledQuery >= 0)
3619		{
3620		CacheRecord *rr;
3621		m->NextScheduledQuery = m->timenow + 0x78000000;
3622
3623		// We're expecting to send a query anyway, so see if any expiring cache records are close enough
3624		// to their NextRequiredQuery to be worth batching them together with this one
3625		FORALL_CACHERECORDS(slot, cg, rr)
3626			if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3627				if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
3628					{
3629					q = rr->CRActiveQuestion;
3630					ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
3631					if (q->Target.type) q->SendQNow = mDNSInterfaceMark;	// If unicast query, mark it
3632					else if (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
3633					else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
3634					}
3635
3636		// Scan our list of questions to see which *unicast* queries need to be sent
3637		for (q = m->Questions; q; q=q->next)
3638			if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
3639				{
3640				mDNSu8       *qptr        = m->omsg.data;
3641				const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
3642				InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
3643				qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
3644				mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, -1, mDNSNULL);
3645				q->ThisQInterval   *= 2;
3646				if (q->ThisQInterval > MaxQuestionInterval)
3647					q->ThisQInterval = MaxQuestionInterval;
3648				q->LastQTime        = m->timenow;
3649				q->LastQTxTime      = m->timenow;
3650				q->RecentAnswerPkts = 0;
3651				q->SendQNow         = mDNSNULL;
3652				m->ExpectUnicastResponse = m->timenow;
3653				}
3654
3655		// Scan our list of questions to see which *multicast* queries we're definitely going to send
3656		for (q = m->Questions; q; q=q->next)
3657			if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow))
3658				{
3659				q->SendQNow = mDNSInterfaceMark;		// Mark this question for sending on all interfaces
3660				if (maxExistingQuestionInterval < q->ThisQInterval)
3661					maxExistingQuestionInterval = q->ThisQInterval;
3662				}
3663
3664		// Scan our list of questions
3665		// (a) to see if there are any more that are worth accelerating, and
3666		// (b) to update the state variables for *all* the questions we're going to send
3667		for (q = m->Questions; q; q=q->next)
3668			{
3669			if (q->SendQNow ||
3670				(!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))
3671				{
3672				// If at least halfway to next query time, advance to next interval
3673				// If less than halfway to next query time, then
3674				// treat this as logically a repeat of the last transmission, without advancing the interval
3675				if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
3676					{
3677					q->SendQNow = mDNSInterfaceMark;	// Mark this question for sending on all interfaces
3678					q->ThisQInterval *= 2;
3679					if (q->ThisQInterval > MaxQuestionInterval)
3680						q->ThisQInterval = MaxQuestionInterval;
3681					else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * 8)
3682						{
3683						debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
3684							q->qname.c, DNSTypeName(q->qtype));
3685						ReconfirmAntecedents(m, q);		// Sending third query, and no answers yet; time to begin doubting the source
3686						}
3687					}
3688
3689				// Mark for sending. (If no active interfaces, then don't even try.)
3690				q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
3691				if (q->SendOnAll)
3692					{
3693					q->SendQNow  = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
3694					q->LastQTime = m->timenow;
3695					}
3696
3697				// If we recorded a duplicate suppression for this question less than half an interval ago,
3698				// then we consider it recent enough that we don't need to do an identical query ourselves.
3699				ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
3700
3701				q->LastQTxTime      = m->timenow;
3702				q->RecentAnswerPkts = 0;
3703				if (q->RequestUnicast) q->RequestUnicast--;
3704				}
3705			// For all questions (not just the ones we're sending) check what the next scheduled event will be
3706			SetNextQueryTime(m,q);
3707			}
3708		}
3709
3710	// 2. Scan our authoritative RR list to see what probes we might need to send
3711	if (m->timenow - m->NextScheduledProbe >= 0)
3712		{
3713		m->NextScheduledProbe = m->timenow + 0x78000000;
3714
3715		if (m->CurrentRecord) LogMsg("SendQueries:   ERROR m->CurrentRecord already set");
3716		m->CurrentRecord = m->ResourceRecords;
3717		while (m->CurrentRecord)
3718			{
3719			AuthRecord *rr = m->CurrentRecord;
3720			m->CurrentRecord = rr->next;
3721			if (rr->resrec.RecordType == kDNSRecordTypeUnique)			// For all records that are still probing...
3722				{
3723				// 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
3724				if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
3725					{
3726					SetNextAnnounceProbeTime(m, rr);
3727					}
3728				// 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
3729				else if (rr->ProbeCount)
3730					{
3731					// Mark for sending. (If no active interfaces, then don't even try.)
3732					rr->SendRNow   = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
3733					rr->LastAPTime = m->timenow;
3734					rr->ProbeCount--;
3735					SetNextAnnounceProbeTime(m, rr);
3736					}
3737				// else, if it has now finished probing, move it to state Verified,
3738				// and update m->NextScheduledResponse so it will be announced
3739				else
3740					{
3741					AuthRecord *r2;
3742					rr->resrec.RecordType     = kDNSRecordTypeVerified;
3743					rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
3744					rr->LastAPTime     = m->timenow - DefaultAnnounceIntervalForTypeUnique;
3745					SetNextAnnounceProbeTime(m, rr);
3746					// If we have any records on our duplicate list that match this one, they have now also completed probing
3747					for (r2 = m->DuplicateRecords; r2; r2=r2->next)
3748						if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
3749							r2->ProbeCount = 0;
3750					AcknowledgeRecord(m, rr);
3751					}
3752				}
3753			}
3754		m->CurrentRecord = m->DuplicateRecords;
3755		while (m->CurrentRecord)
3756			{
3757			AuthRecord *rr = m->CurrentRecord;
3758			m->CurrentRecord = rr->next;
3759			if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0)
3760				AcknowledgeRecord(m, rr);
3761			}
3762		}
3763
3764	// 3. Now we know which queries and probes we're sending,
3765	// go through our interface list sending the appropriate queries on each interface
3766	while (intf)
3767		{
3768		AuthRecord *rr;
3769		mDNSu8 *queryptr = m->omsg.data;
3770		InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
3771		if (KnownAnswerList) verbosedebugf("SendQueries:   KnownAnswerList set... Will continue from previous packet");
3772		if (!KnownAnswerList)
3773			{
3774			// Start a new known-answer list
3775			CacheRecord **kalistptr = &KnownAnswerList;
3776			mDNSu32 answerforecast = 0;
3777
3778			// Put query questions in this packet
3779			for (q = m->Questions; q; q=q->next)
3780				if (q->SendQNow == intf->InterfaceID)
3781					{
3782					debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
3783						SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting    ",
3784						q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data);
3785					// If we're suppressing this question, or we successfully put it, update its SendQNow state
3786					if (SuppressOnThisInterface(q->DupSuppress, intf) ||
3787						BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
3788							q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3789					}
3790
3791			// Put probe questions in this packet
3792			for (rr = m->ResourceRecords; rr; rr=rr->next)
3793				if (rr->SendRNow == intf->InterfaceID)
3794					{
3795					mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
3796					mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3797					const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
3798					mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
3799					// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3800					mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
3801					if (newptr && newptr + forecast < limit)
3802						{
3803						queryptr       = newptr;
3804						answerforecast = forecast;
3805						rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3806						rr->IncludeInProbe = mDNStrue;
3807						verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d",
3808							rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
3809						}
3810					else
3811						{
3812						verbosedebugf("SendQueries:   Retracting Question %##s (%s)",
3813							rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3814						m->omsg.h.numQuestions--;
3815						}
3816					}
3817				}
3818
3819		// Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
3820		while (KnownAnswerList)
3821			{
3822			CacheRecord *rr = KnownAnswerList;
3823			mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
3824			mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
3825			if (newptr)
3826				{
3827				verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d",
3828					rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
3829				queryptr = newptr;
3830				KnownAnswerList = rr->NextInKAList;
3831				rr->NextInKAList = mDNSNULL;
3832				}
3833			else
3834				{
3835				// If we ran out of space and we have more than one question in the packet, that's an error --
3836				// we shouldn't have put more than one question if there was a risk of us running out of space.
3837				if (m->omsg.h.numQuestions > 1)
3838					LogMsg("SendQueries:   Put %d answers; No more space for known answers", m->omsg.h.numAnswers);
3839				m->omsg.h.flags.b[0] |= kDNSFlag0_TC;
3840				break;
3841				}
3842			}
3843
3844		for (rr = m->ResourceRecords; rr; rr=rr->next)
3845			if (rr->IncludeInProbe)
3846				{
3847				mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
3848				rr->IncludeInProbe = mDNSfalse;
3849				if (newptr) queryptr = newptr;
3850				else LogMsg("SendQueries:   How did we fail to have space for the Update record %##s (%s)?",
3851					rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3852				}
3853
3854		if (queryptr > m->omsg.data)
3855			{
3856			if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
3857				LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
3858			debugf("SendQueries:   Sending %d Question%s %d Answer%s %d Update%s on %p",
3859				m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
3860				m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
3861				m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
3862			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
3863			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
3864			if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3865			if (++pktcount >= 1000)
3866				{ LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
3867			// There might be more records left in the known answer list, or more questions to send
3868			// on this interface, so go around one more time and try again.
3869			}
3870		else	// Nothing more to send on this interface; go to next
3871			{
3872			const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3873			#if MDNS_DEBUGMSGS && 0
3874			const char *const msg = next ? "SendQueries:   Nothing more on %p; moving to %p" : "SendQueries:   Nothing more on %p";
3875			debugf(msg, intf, next);
3876			#endif
3877			intf = next;
3878			}
3879		}
3880
3881	// 4. Final housekeeping
3882
3883	// 4a. Debugging check: Make sure we announced all our records
3884	for (ar = m->ResourceRecords; ar; ar=ar->next)
3885		if (ar->SendRNow)
3886			{
3887			if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
3888				LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
3889			ar->SendRNow = mDNSNULL;
3890			}
3891
3892	// 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
3893	// that their interface which went away might come back again, the logic will want to send queries
3894	// for those records, but we can't because their interface isn't here any more, so to keep the
3895	// state machine ticking over we just pretend we did so.
3896	// If the interface does not come back in time, the cache record will expire naturally
3897	FORALL_CACHERECORDS(slot, cg, cr)
3898		if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
3899			{
3900			cr->UnansweredQueries++;
3901			cr->CRActiveQuestion->SendQNow = mDNSNULL;
3902			SetNextCacheCheckTime(m, cr);
3903			}
3904
3905	// 4c. Debugging check: Make sure we sent all our planned questions
3906	// Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
3907	// we legitimately couldn't send because the interface is no longer available
3908	for (q = m->Questions; q; q=q->next)
3909		if (q->SendQNow)
3910			{
3911			LogMsg("SendQueries: No active interface to send: %##s %s", q->qname.c, DNSTypeName(q->qtype));
3912			q->SendQNow = mDNSNULL;
3913			}
3914	}
3915
3916// ***************************************************************************
3917#if COMPILER_LIKES_PRAGMA_MARK
3918#pragma mark -
3919#pragma mark - RR List Management & Task Management
3920#endif
3921
3922// NOTE: AnswerQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
3923// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3924mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, CacheRecord *rr, mDNSBool AddRecord)
3925	{
3926	verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)",
3927		q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3928
3929	// Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue)
3930	// may be called twice, once when the record is received, and again when it's time to notify local clients.
3931	// If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
3932
3933	rr->LastUsed = m->timenow;
3934	if (ActiveQuestion(q) && rr->CRActiveQuestion != q)
3935		{
3936		if (!rr->CRActiveQuestion) m->rrcache_active++;	// If not previously active, increment rrcache_active count
3937		rr->CRActiveQuestion = q;						// We know q is non-null
3938		SetNextCacheCheckTime(m, rr);
3939		}
3940
3941	// If this is:
3942	// (a) a no-cache add, where we've already done at least one 'QM' query, or
3943	// (b) a normal add, where we have at least one unique-type answer,
3944	// then there's no need to keep polling the network.
3945	// (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
3946	if ((AddRecord == 2 && !q->RequestUnicast) ||
3947		(AddRecord == 1 && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
3948		if (ActiveQuestion(q))
3949			{
3950			q->LastQTime      = m->timenow;
3951			q->LastQTxTime    = m->timenow;
3952			q->RecentAnswerPkts = 0;
3953			q->ThisQInterval  = MaxQuestionInterval;
3954			q->RequestUnicast = mDNSfalse;
3955			}
3956
3957	if (rr->DelayDelivery) return;		// We'll come back later when CacheRecordDeferredAdd() calls us
3958
3959	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
3960	if (q->QuestionCallback)
3961		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
3962	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
3963	// CAUTION: MUST NOT do anything more with q after calling q->QuestionCallback(), because the client's callback function
3964	// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3965	// Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv()
3966	// and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions
3967	// being deleted out from under them.
3968	}
3969
3970mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
3971	{
3972	rr->DelayDelivery = 0;		// Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
3973	if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set");
3974	m->CurrentQuestion = m->Questions;
3975	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3976		{
3977		DNSQuestion *q = m->CurrentQuestion;
3978		m->CurrentQuestion = q->next;
3979		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3980			AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
3981		}
3982	m->CurrentQuestion = mDNSNULL;
3983	}
3984
3985mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot)
3986	{
3987	const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond;	// See if there are any records expiring within one second
3988	const mDNSs32 start      = m->timenow - 0x10000000;
3989	mDNSs32 delay = start;
3990	CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
3991	CacheRecord *rr;
3992	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3993		if (rr->resrec.namehash == namehash && SameDomainName(rr->resrec.name, name))
3994			if (threshhold - RRExpireTime(rr) >= 0)		// If we have records about to expire within a second
3995				if (delay - RRExpireTime(rr) < 0)		// then delay until after they've been deleted
3996					delay = RRExpireTime(rr);
3997	if (delay - start > 0) return(NonZeroTime(delay));
3998	else return(0);
3999	}
4000
4001// CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4002// If new questions are created as a result of invoking client callbacks, they will be added to
4003// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4004// rr is a new CacheRecord just received into our cache
4005// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4006// NOTE: CacheRecordAdd calls AnswerQuestionWithResourceRecord which can call a user callback,
4007// which may change the record list and/or question list.
4008// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4009mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
4010	{
4011	if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set");
4012	m->CurrentQuestion = m->Questions;
4013	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4014		{
4015		DNSQuestion *q = m->CurrentQuestion;
4016		m->CurrentQuestion = q->next;
4017		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4018			{
4019			// If this question is one that's actively sending queries, and it's received ten answers within one
4020			// second of sending the last query packet, then that indicates some radical network topology change,
4021			// so reset its exponential backoff back to the start. We must be at least at the eight-second interval
4022			// to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
4023			// because we will anyway send another query within a few seconds. The first reset query is sent out
4024			// randomized over the next four seconds to reduce possible synchronization between machines.
4025			if (q->LastAnswerPktNum != m->PktNum)
4026				{
4027				q->LastAnswerPktNum = m->PktNum;
4028				if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
4029					q->ThisQInterval > InitialQuestionInterval*32 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
4030					{
4031					LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
4032						q->qname.c, DNSTypeName(q->qtype));
4033					q->LastQTime      = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
4034					q->ThisQInterval  = InitialQuestionInterval;
4035					SetNextQueryTime(m,q);
4036					}
4037				}
4038			verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
4039				rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
4040			q->CurrentAnswers++;
4041			if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
4042			if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
4043			if (q->CurrentAnswers > 4000)
4044				{
4045				static int msgcount = 0;
4046				if (msgcount++ < 10)
4047					LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
4048						q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
4049				rr->resrec.rroriginalttl = 1;
4050				rr->UnansweredQueries = MaxUnansweredQueries;
4051				}
4052			AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
4053			// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4054			}
4055		}
4056	m->CurrentQuestion = mDNSNULL;
4057	SetNextCacheCheckTime(m, rr);
4058	}
4059
4060// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4061// If new questions are created as a result of invoking client callbacks, they will be added to
4062// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4063// rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
4064// but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
4065// way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
4066// so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
4067// NOTE: NoCacheAnswer calls AnswerQuestionWithResourceRecord which can call a user callback,
4068// which may change the record list and/or question list.
4069// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4070mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
4071	{
4072	LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
4073	if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set");
4074	m->CurrentQuestion = m->Questions;
4075	while (m->CurrentQuestion)
4076		{
4077		DNSQuestion *q = m->CurrentQuestion;
4078		m->CurrentQuestion = q->next;
4079		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4080			AnswerQuestionWithResourceRecord(m, q, rr, 2);	// Value '2' indicates "don't expect 'remove' events for this"
4081		// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4082		}
4083	m->CurrentQuestion = mDNSNULL;
4084	}
4085
4086// CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute
4087// If new questions are created as a result of invoking client callbacks, they will be added to
4088// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4089// rr is an existing cache CacheRecord that just expired and is being deleted
4090// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4091// NOTE: CacheRecordRmv calls AnswerQuestionWithResourceRecord which can call a user callback,
4092// which may change the record list and/or question list.
4093// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4094mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
4095	{
4096	if (m->CurrentQuestion) LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set");
4097	m->CurrentQuestion = m->Questions;
4098	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4099		{
4100		DNSQuestion *q = m->CurrentQuestion;
4101		m->CurrentQuestion = q->next;
4102		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4103			{
4104			verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
4105			if (q->CurrentAnswers == 0)
4106				LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
4107					q, q->qname.c, DNSTypeName(q->qtype));
4108			else
4109				{
4110				q->CurrentAnswers--;
4111				if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
4112				if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
4113				}
4114			if (q->CurrentAnswers == 0)
4115				{
4116				debugf("CacheRecordRmv: Zero current answers for %##s (%s); will reconfirm antecedents",
4117					q->qname.c, DNSTypeName(q->qtype));
4118				ReconfirmAntecedents(m, q);
4119				}
4120			q->FlappingInterface = mDNSNULL;
4121			AnswerQuestionWithResourceRecord(m, q, rr, mDNSfalse);
4122			// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4123			}
4124		}
4125	m->CurrentQuestion = mDNSNULL;
4126	}
4127
4128mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
4129	{
4130#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
4131	unsigned int i;
4132	for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
4133#endif
4134	e->next = m->rrcache_free;
4135	m->rrcache_free = e;
4136	m->rrcache_totalused--;
4137	}
4138
4139mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
4140	{
4141	CacheEntity *e = (CacheEntity *)(*cp);
4142	//LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
4143	if ((*cp)->rrcache_tail != &(*cp)->members)
4144		LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
4145	//if ((*cp)->name != (domainname*)((*cp)->namestorage))
4146	//	LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
4147	if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
4148	(*cp)->name = mDNSNULL;
4149	*cp = (*cp)->next;			// Cut record from list
4150	ReleaseCacheEntity(m, e);
4151	}
4152
4153mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
4154	{
4155	if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
4156	r->resrec.rdata = mDNSNULL;
4157	ReleaseCacheEntity(m, (CacheEntity *)r);
4158	}
4159
4160// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
4161// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
4162// callbacks for old records are delivered before callbacks for newer records.
4163mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg)
4164	{
4165	CacheRecord **rp = &cg->members;
4166
4167	if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
4168	m->lock_rrcache = 1;
4169
4170	while (*rp)
4171		{
4172		CacheRecord *const rr = *rp;
4173		mDNSs32 event = RRExpireTime(rr);
4174		if (m->timenow - event >= 0)	// If expired, delete it
4175			{
4176			*rp = rr->next;				// Cut it from the list
4177			verbosedebugf("CheckCacheExpiration: Deleting %s", CRDisplayString(m, rr));
4178			if (rr->CRActiveQuestion)	// If this record has one or more active questions, tell them it's going away
4179				{
4180				CacheRecordRmv(m, rr);
4181				m->rrcache_active--;
4182				}
4183			ReleaseCacheRecord(m, rr);
4184			}
4185		else							// else, not expired; see if we need to query
4186			{
4187			if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
4188				event = rr->DelayDelivery;
4189			else
4190				{
4191				if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr);
4192				if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
4193					{
4194					if (m->timenow - rr->NextRequiredQuery < 0)		// If not yet time for next query
4195						event = rr->NextRequiredQuery;				// then just record when we want the next query
4196					else											// else trigger our question to go out now
4197						{
4198						// Set NextScheduledQuery to timenow so that SendQueries() will run.
4199						// SendQueries() will see that we have records close to expiration, and send FEQs for them.
4200						m->NextScheduledQuery = m->timenow;
4201						// After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
4202						// which will correctly update m->NextCacheCheck for us.
4203						event = m->timenow + 0x3FFFFFFF;
4204						}
4205					}
4206				}
4207			verbosedebugf("CheckCacheExpiration:%6d %5d %s",
4208				(event-m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
4209			if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
4210				m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
4211			rp = &rr->next;
4212			}
4213		}
4214	if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp);
4215	cg->rrcache_tail = rp;
4216	m->lock_rrcache = 0;
4217	}
4218
4219mDNSlocal void AnswerNewQuestion(mDNS *const m)
4220	{
4221	mDNSBool ShouldQueryImmediately = mDNStrue;
4222	CacheRecord *rr;
4223	DNSQuestion *q = m->NewQuestions;		// Grab the question we're going to answer
4224	const mDNSu32 slot = HashSlot(&q->qname);
4225	CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4226
4227	verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4228
4229	if (cg) CheckCacheExpiration(m, cg);
4230	m->NewQuestions = q->next;				// Advance NewQuestions to the next *after* calling CheckCacheExpiration();
4231
4232	if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
4233	// This should be safe, because calling the client's question callback may cause the
4234	// question list to be modified, but should not ever cause the rrcache list to be modified.
4235	// If the client's question callback deletes the question, then m->CurrentQuestion will
4236	// be advanced, and we'll exit out of the loop
4237	m->lock_rrcache = 1;
4238	if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set");
4239	m->CurrentQuestion = q;		// Indicate which question we're answering, so we'll know if it gets deleted
4240
4241	if (q->InterfaceID == mDNSInterface_Any)	// If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
4242		{
4243		if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
4244		m->CurrentRecord = m->ResourceRecords;
4245		while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4246			{
4247			AuthRecord *rr = m->CurrentRecord;
4248			m->CurrentRecord = rr->next;
4249			if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
4250				if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4251					{
4252					AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
4253					// MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
4254					if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4255					}
4256			}
4257		m->CurrentRecord   = mDNSNULL;
4258		}
4259
4260	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4261		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4262			{
4263			// SecsSinceRcvd is whole number of elapsed seconds, rounded down
4264			mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
4265			if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
4266				{
4267				LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s)",
4268					rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
4269				continue;	// Go to next one in loop
4270				}
4271
4272			// If this record set is marked unique, then that means we can reasonably assume we have the whole set
4273			// -- we don't need to rush out on the network and query immediately to see if there are more answers out there
4274			if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
4275				ShouldQueryImmediately = mDNSfalse;
4276			q->CurrentAnswers++;
4277			if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
4278			if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
4279			AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
4280			// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4281			if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4282			}
4283		else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
4284			if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
4285				ShouldQueryImmediately = mDNSfalse;
4286
4287	if (ShouldQueryImmediately && m->CurrentQuestion == q)
4288		{
4289		q->ThisQInterval  = InitialQuestionInterval;
4290		q->LastQTime      = m->timenow - q->ThisQInterval;
4291		m->NextScheduledQuery = m->timenow;
4292		}
4293	m->CurrentQuestion = mDNSNULL;
4294	m->lock_rrcache = 0;
4295	}
4296
4297// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
4298// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
4299mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
4300	{
4301	DNSQuestion *q = m->NewLocalOnlyQuestions;		// Grab the question we're going to answer
4302	m->NewLocalOnlyQuestions = q->next;				// Advance NewQuestions to the next (if any)
4303
4304	debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4305
4306	if (m->CurrentQuestion) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set");
4307	m->CurrentQuestion = q;		// Indicate which question we're answering, so we'll know if it gets deleted
4308
4309	if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
4310	m->CurrentRecord = m->ResourceRecords;
4311	while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4312		{
4313		AuthRecord *rr = m->CurrentRecord;
4314		m->CurrentRecord = rr->next;
4315		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4316			{
4317			AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
4318			// MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
4319			if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4320			}
4321		}
4322
4323	m->CurrentQuestion = mDNSNULL;
4324	m->CurrentRecord   = mDNSNULL;
4325	}
4326
4327mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG)
4328	{
4329	CacheEntity *e = mDNSNULL;
4330
4331	if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
4332	m->lock_rrcache = 1;
4333
4334	// If we have no free records, ask the client layer to give us some more memory
4335	if (!m->rrcache_free && m->MainCallback)
4336		{
4337		if (m->rrcache_totalused != m->rrcache_size)
4338			LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4339				m->rrcache_totalused, m->rrcache_size);
4340
4341		// We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4342		// number of bogus records so that we keep growing our cache until the machine runs out of memory.
4343		// To guard against this, if we're actively using less than 1/32 of our cache, then we
4344		// purge all the unused records and recycle them, instead of allocating more memory.
4345		if (m->rrcache_size >= 512 && m->rrcache_size / 32 > m->rrcache_active)
4346			debugf("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4347				m->rrcache_size, m->rrcache_active);
4348		else
4349			{
4350			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4351			m->MainCallback(m, mStatus_GrowCache);
4352			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4353			}
4354		}
4355
4356	// If we still have no free records, recycle all the records we can.
4357	// Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4358	if (!m->rrcache_free)
4359		{
4360		#if MDNS_DEBUGMSGS
4361		mDNSu32 oldtotalused = m->rrcache_totalused;
4362		#endif
4363		mDNSu32 slot;
4364		for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4365			{
4366			CacheGroup **cp = &m->rrcache_hash[slot];
4367			while (*cp)
4368				{
4369				CacheRecord **rp = &(*cp)->members;
4370				while (*rp)
4371					{
4372					// Records that answer still-active questions are not candidates for recycling
4373					// Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4374					if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList)
4375						rp=&(*rp)->next;
4376					else
4377						{
4378						CacheRecord *rr = *rp;
4379						*rp = (*rp)->next;			// Cut record from list
4380						ReleaseCacheRecord(m, rr);
4381						}
4382					}
4383				if ((*cp)->rrcache_tail != rp)
4384					verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
4385				(*cp)->rrcache_tail = rp;
4386				if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
4387				else ReleaseCacheGroup(m, cp);
4388				}
4389			}
4390		#if MDNS_DEBUGMSGS
4391		debugf("Clear unused records; m->rrcache_totalused was %lu; now %lu", oldtotalused, m->rrcache_totalused);
4392		#endif
4393		}
4394
4395	if (m->rrcache_free)	// If there are records in the free list, take one
4396		{
4397		e = m->rrcache_free;
4398		m->rrcache_free = e->next;
4399		if (++m->rrcache_totalused >= m->rrcache_report)
4400			{
4401			debugf("RR Cache now using %ld objects", m->rrcache_totalused);
4402			if (m->rrcache_report < 100) m->rrcache_report += 10;
4403			else                         m->rrcache_report += 100;
4404			}
4405		mDNSPlatformMemZero(e, sizeof(*e));
4406		}
4407
4408	m->lock_rrcache = 0;
4409
4410	return(e);
4411	}
4412
4413mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength)
4414	{
4415	CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
4416	if (r)
4417		{
4418		r->resrec.rdata = (RData*)&r->rdatastorage;	// By default, assume we're usually going to be using local storage
4419		if (RDLength > InlineCacheRDSize)			// If RDLength is too big, allocate extra storage
4420			{
4421			r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
4422			if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
4423			else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
4424			}
4425		}
4426	return(r);
4427	}
4428
4429mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
4430	{
4431	mDNSu16 namelen = DomainNameLength(rr->name);
4432	CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL);
4433	if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
4434	cg->next         = m->rrcache_hash[slot];
4435	cg->namehash     = rr->namehash;
4436	cg->members      = mDNSNULL;
4437	cg->rrcache_tail = &cg->members;
4438	cg->name         = (domainname*)cg->namestorage;
4439	//LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4440	//	(namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4441	if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
4442	if (!cg->name)
4443		{
4444		LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c);
4445		ReleaseCacheEntity(m, (CacheEntity*)cg);
4446		return(mDNSNULL);
4447		}
4448	AssignDomainName(cg->name, rr->name);
4449
4450	if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
4451	m->rrcache_hash[slot] = cg;
4452	if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
4453
4454	return(cg);
4455	}
4456
4457mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
4458	{
4459	// Make sure we mark this record as thoroughly expired -- we don't ever want to give
4460	// a positive answer using an expired record (e.g. from an interface that has gone away).
4461	// We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4462	// summary deletion without giving the proper callback to any questions that are monitoring it.
4463	// By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4464	rr->TimeRcvd          = m->timenow - mDNSPlatformOneSecond * 60;
4465	rr->UnansweredQueries = MaxUnansweredQueries;
4466	rr->resrec.rroriginalttl     = 0;
4467	SetNextCacheCheckTime(m, rr);
4468	}
4469
4470mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
4471	{
4472	mDNSs32 time;
4473	mDNSPlatformLock(m);
4474	if (m->mDNS_busy)
4475		{
4476		LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4477		if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
4478		}
4479
4480	if (m->timenow) time = m->timenow;
4481	else            time = mDNS_TimeNow_NoLock(m);
4482	mDNSPlatformUnlock(m);
4483	return(time);
4484	}
4485
4486mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
4487	{
4488	mDNS_Lock(m);	// Must grab lock before trying to read m->timenow
4489
4490	if (m->timenow - m->NextScheduledEvent >= 0)
4491		{
4492		int i;
4493
4494		verbosedebugf("mDNS_Execute");
4495		if (m->CurrentQuestion) LogMsg("mDNS_Execute: ERROR! m->CurrentQuestion already set");
4496
4497		// 1. If we're past the probe suppression time, we can clear it
4498		if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
4499
4500		// 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4501		if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0;
4502
4503		// 3. Purge our cache of stale old records
4504		if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
4505			{
4506			mDNSu32 slot;
4507			m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
4508			for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4509				{
4510				CacheGroup **cp = &m->rrcache_hash[slot];
4511				while (*cp)
4512					{
4513					CheckCacheExpiration(m, *cp);
4514					if ((*cp)->members) cp=&(*cp)->next;
4515					else ReleaseCacheGroup(m, cp);
4516					}
4517				}
4518			LogOperation("Cache checked. Next in %ld ticks", m->NextCacheCheck - m->timenow);
4519			}
4520
4521		// 4. See if we can answer any of our new local questions from the cache
4522		for (i=0; m->NewQuestions && i<1000; i++)
4523			{
4524			if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
4525			AnswerNewQuestion(m);
4526			}
4527		if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4528
4529		for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
4530		if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4531
4532		for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
4533			{
4534			AuthRecord *rr = m->NewLocalRecords;
4535			m->NewLocalRecords = m->NewLocalRecords->next;
4536			AnswerLocalQuestions(m, rr, mDNStrue);
4537			}
4538		if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
4539
4540		// 5. See what packets we need to send
4541		if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) DiscardDeregistrations(m);
4542		else if (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)
4543			{
4544			// If the platform code is ready, and we're not suppressing packet generation right now
4545			// then send our responses, probes, and questions.
4546			// We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4547			// We send queries next, because there might be final-stage probes that complete their probing here, causing
4548			// them to advance to announcing state, and we want those to be included in any announcements we send out.
4549			// Finally, we send responses, including the previously mentioned records that just completed probing.
4550			m->SuppressSending = 0;
4551
4552			// 6. Send Query packets. This may cause some probing records to advance to announcing state
4553			if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
4554			if (m->timenow - m->NextScheduledQuery >= 0)
4555				{
4556				LogMsg("mDNS_Execute: SendQueries didn't send all its queries; will try again in one second");
4557				m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
4558				}
4559			if (m->timenow - m->NextScheduledProbe >= 0)
4560				{
4561				LogMsg("mDNS_Execute: SendQueries didn't send all its probes; will try again in one second");
4562				m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
4563				}
4564
4565			// 7. Send Response packets, including probing records just advanced to announcing state
4566			if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
4567			if (m->timenow - m->NextScheduledResponse >= 0)
4568				{
4569				LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4570				m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond;
4571				}
4572			}
4573
4574		// Clear RandomDelay values, ready to pick a new different value next time
4575		m->RandomQueryDelay     = 0;
4576		m->RandomReconfirmDelay = 0;
4577		}
4578
4579	// Note about multi-threaded systems:
4580	// On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4581	// performing mDNS API operations that change our next scheduled event time.
4582	//
4583	// On multi-threaded systems (like the current Windows implementation) that have a single main thread
4584	// calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4585	// of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4586	// signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4587	// more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4588	// in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4589	// does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4590	// without blocking. This avoids the race condition between the signal from the other thread arriving
4591	// just *before* or just *after* the main thread enters the blocking primitive.
4592	//
4593	// On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4594	// with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4595	// set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4596	// callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4597	// by the time it gets to the timer callback function).
4598
4599#ifndef UNICAST_DISABLED
4600	uDNS_Execute(m);
4601#endif
4602	mDNS_Unlock(m);		// Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4603	return(m->NextScheduledEvent);
4604	}
4605
4606// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
4607// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
4608// Normally, the platform support layer below mDNSCore should call this, not the client layer above.
4609// Note that sleep/wake calls do not have to be paired one-for-one; it is acceptable to call
4610// mDNSCoreMachineSleep(m, mDNSfalse) any time there is reason to believe that the machine may have just
4611// found itself in a new network environment. For example, if the Ethernet hardware indicates that the
4612// cable has just been connected, the platform support layer should call mDNSCoreMachineSleep(m, mDNSfalse)
4613// to make mDNSCore re-issue its outstanding queries, probe for record uniqueness, etc.
4614// While it is safe to call mDNSCoreMachineSleep(m, mDNSfalse) at any time, it does cause extra network
4615// traffic, so it should only be called when there is legitimate reason to believe the machine
4616// may have become attached to a new network.
4617mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
4618	{
4619	AuthRecord *rr;
4620
4621	mDNS_Lock(m);
4622
4623	m->SleepState = sleepstate;
4624	LogOperation("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
4625
4626	if (sleepstate)
4627		{
4628#ifndef UNICAST_DISABLED
4629		uDNS_Sleep(m);
4630#endif
4631		// Mark all the records we need to deregister and send them
4632		for (rr = m->ResourceRecords; rr; rr=rr->next)
4633			if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
4634				rr->ImmedAnswer = mDNSInterfaceMark;
4635		SendResponses(m);
4636		}
4637	else
4638		{
4639		DNSQuestion *q;
4640		mDNSu32 slot;
4641		CacheGroup *cg;
4642		CacheRecord *cr;
4643
4644#ifndef UNICAST_DISABLED
4645		uDNS_Wake(m);
4646#endif
4647        // 1. Retrigger all our questions
4648		for (q = m->Questions; q; q=q->next)				// Scan our list of questions
4649			if (ActiveQuestion(q))
4650				{
4651				q->ThisQInterval    = InitialQuestionInterval;	// MUST be > zero for an active question
4652				q->RequestUnicast   = 2;						// Set to 2 because is decremented once *before* we check it
4653				q->LastQTime        = m->timenow - q->ThisQInterval;
4654				q->RecentAnswerPkts = 0;
4655				ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
4656				m->NextScheduledQuery = m->timenow;
4657				}
4658
4659		// 2. Re-validate our cache records
4660		m->NextCacheCheck  = m->timenow;
4661		FORALL_CACHERECORDS(slot, cg, cr)
4662			mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
4663
4664		// 3. Retrigger probing and announcing for all our authoritative records
4665		for (rr = m->ResourceRecords; rr; rr=rr->next)
4666			{
4667			if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
4668			rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
4669			rr->AnnounceCount  = InitialAnnounceCount;
4670			rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
4671			InitializeLastAPTime(m, rr);
4672			}
4673		}
4674
4675	mDNS_Unlock(m);
4676	}
4677
4678// ***************************************************************************
4679#if COMPILER_LIKES_PRAGMA_MARK
4680#pragma mark -
4681#pragma mark - Packet Reception Functions
4682#endif
4683
4684#define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
4685
4686mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end,
4687	const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords)
4688	{
4689	mDNSu8          *responseptr     = response->data;
4690	const mDNSu8    *const limit     = response->data + sizeof(response->data);
4691	const mDNSu8    *ptr             = query->data;
4692	AuthRecord  *rr;
4693	mDNSu32          maxttl = 0x70000000;
4694	int i;
4695
4696	// Initialize the response fields so we can answer the questions
4697	InitializeDNSMessage(&response->h, query->h.id, ResponseFlags);
4698
4699	// ***
4700	// *** 1. Write out the list of questions we are actually going to answer with this packet
4701	// ***
4702	if (LegacyQuery)
4703		{
4704		maxttl = 10;
4705		for (i=0; i<query->h.numQuestions; i++)						// For each question...
4706			{
4707			DNSQuestion q;
4708			ptr = getQuestion(query, ptr, end, InterfaceID, &q);	// get the question...
4709			if (!ptr) return(mDNSNULL);
4710
4711			for (rr=ResponseRecords; rr; rr=rr->NextResponse)		// and search our list of proposed answers
4712				{
4713				if (rr->NR_AnswerTo == ptr)							// If we're going to generate a record answering this question
4714					{												// then put the question in the question section
4715					responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass);
4716					if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); }
4717					break;		// break out of the ResponseRecords loop, and go on to the next question
4718					}
4719				}
4720			}
4721
4722		if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); }
4723		}
4724
4725	// ***
4726	// *** 2. Write Answers
4727	// ***
4728	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4729		if (rr->NR_AnswerTo)
4730			{
4731			mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, maxttl);
4732			if (p) responseptr = p;
4733			else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; }
4734			}
4735
4736	// ***
4737	// *** 3. Write Additionals
4738	// ***
4739	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4740		if (rr->NR_AdditionalTo && !rr->NR_AnswerTo)
4741			{
4742			mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, maxttl);
4743			if (p) responseptr = p;
4744			else debugf("GenerateUnicastResponse: No more space for additionals");
4745			}
4746
4747	return(responseptr);
4748	}
4749
4750// AuthRecord *our is our Resource Record
4751// CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
4752// Returns 0 if there is no conflict
4753// Returns +1 if there was a conflict and we won
4754// Returns -1 if there was a conflict and we lost and have to rename
4755mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt)
4756	{
4757	mDNSu8 ourdata[256], *ourptr = ourdata, *ourend;
4758	mDNSu8 pktdata[256], *pktptr = pktdata, *pktend;
4759	if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
4760	if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
4761
4762	ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
4763	pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
4764	while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
4765	if (ourptr >= ourend && pktptr >= pktend) return(0);			// If data identical, not a conflict
4766
4767	if (ourptr >= ourend) return(-1);								// Our data ran out first; We lost
4768	if (pktptr >= pktend) return(+1);								// Packet data ran out first; We won
4769	if (*pktptr > *ourptr) return(-1);								// Our data is numerically lower; We lost
4770	if (*pktptr < *ourptr) return(+1);								// Packet data is numerically lower; We won
4771
4772	LogMsg("CompareRData ERROR: Invalid state");
4773	return(-1);
4774	}
4775
4776// See if we have an authoritative record that's identical to this packet record,
4777// whose canonical DependentOn record is the specified master record.
4778// The DependentOn pointer is typically used for the TXT record of service registrations
4779// It indicates that there is no inherent conflict detection for the TXT record
4780// -- it depends on the SRV record to resolve name conflicts
4781// If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
4782// pointer chain (if any) to make sure we reach the canonical DependentOn record
4783// If the record has no DependentOn, then just return that record's pointer
4784// Returns NULL if we don't have any local RRs that are identical to the one from the packet
4785mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master)
4786	{
4787	const AuthRecord *r1;
4788	for (r1 = m->ResourceRecords; r1; r1=r1->next)
4789		{
4790		if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
4791			{
4792			const AuthRecord *r2 = r1;
4793			while (r2->DependentOn) r2 = r2->DependentOn;
4794			if (r2 == master) return(mDNStrue);
4795			}
4796		}
4797	for (r1 = m->DuplicateRecords; r1; r1=r1->next)
4798		{
4799		if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
4800			{
4801			const AuthRecord *r2 = r1;
4802			while (r2->DependentOn) r2 = r2->DependentOn;
4803			if (r2 == master) return(mDNStrue);
4804			}
4805		}
4806	return(mDNSfalse);
4807	}
4808
4809// Find the canonical RRSet pointer for this RR received in a packet.
4810// If we find any identical AuthRecord in our authoritative list, then follow its RRSet
4811// pointers (if any) to make sure we return the canonical member of this name/type/class
4812// Returns NULL if we don't have any local RRs that are identical to the one from the packet
4813mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr)
4814	{
4815	const AuthRecord *rr;
4816	for (rr = m->ResourceRecords; rr; rr=rr->next)
4817		{
4818		if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
4819			{
4820			while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet;
4821			return(rr);
4822			}
4823		}
4824	return(mDNSNULL);
4825	}
4826
4827// PacketRRConflict is called when we've received an RR (pktrr) which has the same name
4828// as one of our records (our) but different rdata.
4829// 1. If our record is not a type that's supposed to be unique, we don't care.
4830// 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
4831// 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
4832//     points to our record, ignore this conflict (e.g. the packet record matches one of our
4833//     TXT records, and that record is marked as dependent on 'our', its SRV record).
4834// 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
4835//    are members of the same RRSet, then this is not a conflict.
4836mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr)
4837	{
4838	const AuthRecord *ourset = our->RRSet ? our->RRSet : our;
4839
4840	// If not supposed to be unique, not a conflict
4841	if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse);
4842
4843	// If a dependent record, not a conflict
4844	if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse);
4845
4846	// If the pktrr matches a member of ourset, not a conflict
4847	if (FindRRSet(m, pktrr) == ourset) return(mDNSfalse);
4848
4849	// Okay, this is a conflict
4850	return(mDNStrue);
4851	}
4852
4853// NOTE: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
4854// the record list and/or question list.
4855// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4856mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
4857	DNSQuestion *q, AuthRecord *our)
4858	{
4859	int i;
4860	const mDNSu8 *ptr = LocateAuthorities(query, end);
4861	mDNSBool FoundUpdate = mDNSfalse;
4862
4863	for (i = 0; i < query->h.numAuthorities; i++)
4864		{
4865		ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
4866		if (!ptr) break;
4867		if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
4868			{
4869			FoundUpdate = mDNStrue;
4870			if (PacketRRConflict(m, our, &m->rec.r))
4871				{
4872				int result          = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
4873				if (!result) result = (int)our->resrec.rrtype  - (int)m->rec.r.resrec.rrtype;
4874				if (!result) result = CompareRData(our, &m->rec.r);
4875				if (result > 0)
4876					debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4877				else if (result < 0)
4878					{
4879					debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4880					mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
4881					goto exit;
4882					}
4883				}
4884			}
4885		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
4886		}
4887	if (!FoundUpdate)
4888		debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4889exit:
4890	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
4891	}
4892
4893mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceRecord *pktrr)
4894	{
4895	mDNSu32 slot = HashSlot(pktrr->name);
4896	CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
4897	CacheRecord *rr;
4898	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4899		if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalResourceRecord(pktrr, &rr->resrec)) break;
4900	return(rr);
4901	}
4902
4903// ProcessQuery examines a received query to see if we have any answers to give
4904mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
4905	const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
4906	mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
4907	{
4908	mDNSBool      FromLocalSubnet    = AddressIsLocalSubnet(m, InterfaceID, srcaddr);
4909	AuthRecord   *ResponseRecords    = mDNSNULL;
4910	AuthRecord  **nrp                = &ResponseRecords;
4911	CacheRecord  *ExpectedAnswers    = mDNSNULL;			// Records in our cache we expect to see updated
4912	CacheRecord **eap                = &ExpectedAnswers;
4913	DNSQuestion  *DupQuestions       = mDNSNULL;			// Our questions that are identical to questions in this packet
4914	DNSQuestion **dqp                = &DupQuestions;
4915	mDNSs32       delayresponse      = 0;
4916	mDNSBool      SendLegacyResponse = mDNSfalse;
4917	const mDNSu8 *ptr                = query->data;
4918	mDNSu8       *responseptr        = mDNSNULL;
4919	AuthRecord   *rr;
4920	int i;
4921
4922	// ***
4923	// *** 1. Parse Question Section and mark potential answers
4924	// ***
4925	for (i=0; i<query->h.numQuestions; i++)						// For each question...
4926		{
4927		mDNSBool QuestionNeedsMulticastResponse;
4928		int NumAnswersForThisQuestion = 0;
4929		DNSQuestion pktq, *q;
4930		ptr = getQuestion(query, ptr, end, InterfaceID, &pktq);	// get the question...
4931		if (!ptr) goto exit;
4932
4933		// The only queries that *need* a multicast response are:
4934		// * Queries sent via multicast
4935		// * from port 5353
4936		// * that don't have the kDNSQClass_UnicastResponse bit set
4937		// These queries need multicast responses because other clients will:
4938		// * suppress their own identical questions when they see these questions, and
4939		// * expire their cache records if they don't see the expected responses
4940		// For other queries, we may still choose to send the occasional multicast response anyway,
4941		// to keep our neighbours caches warm, and for ongoing conflict detection.
4942		QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse);
4943		// Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
4944		pktq.qclass &= ~kDNSQClass_UnicastResponse;
4945
4946		// Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
4947		// can result in user callbacks which may change the record list and/or question list.
4948		// Also note: we just mark potential answer records here, without trying to build the
4949		// "ResponseRecords" list, because we don't want to risk user callbacks deleting records
4950		// from that list while we're in the middle of trying to build it.
4951		if (m->CurrentRecord) LogMsg("ProcessQuery ERROR m->CurrentRecord already set");
4952		m->CurrentRecord = m->ResourceRecords;
4953		while (m->CurrentRecord)
4954			{
4955			rr = m->CurrentRecord;
4956			m->CurrentRecord = rr->next;
4957			if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
4958				{
4959				if (rr->resrec.RecordType == kDNSRecordTypeUnique)
4960					ResolveSimultaneousProbe(m, query, end, &pktq, rr);
4961				else if (ResourceRecordIsValidAnswer(rr))
4962					{
4963					NumAnswersForThisQuestion++;
4964					// Notes:
4965					// NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
4966					// NR_AnswerTo == (mDNSu8*)~1             means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
4967					// NR_AnswerTo == (mDNSu8*)~0             means "definitely answer via multicast" (can't downgrade to unicast later)
4968					// If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
4969					// but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link)
4970					// then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
4971					if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
4972						{
4973						// We only mark this question for sending if it is at least one second since the last time we multicast it
4974						// on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
4975						// This is to guard against the case where someone blasts us with queries as fast as they can.
4976						if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
4977							(rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
4978							rr->NR_AnswerTo = (mDNSu8*)~0;
4979						}
4980					else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
4981					}
4982				}
4983			}
4984
4985		// If we couldn't answer this question, someone else might be able to,
4986		// so use random delay on response to reduce collisions
4987		if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond;	// Divided by 50 = 20ms
4988
4989		// We only do the following accelerated cache expiration processing and duplicate question suppression processing
4990		// for multicast queries with multicast responses.
4991		// For any query generating a unicast response we don't do this because we can't assume we will see the response
4992		if (QuestionNeedsMulticastResponse)
4993			{
4994			const mDNSu32 slot = HashSlot(&pktq.qname);
4995			CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
4996			CacheRecord *rr;
4997
4998			// Make a list indicating which of our own cache records we expect to see updated as a result of this query
4999			// Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
5000			for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5001				if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
5002					if (!rr->NextInKAList && eap != &rr->NextInKAList)
5003						{
5004						*eap = rr;
5005						eap = &rr->NextInKAList;
5006						if (rr->MPUnansweredQ == 0 || m->timenow - rr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
5007							{
5008							// Although MPUnansweredQ is only really used for multi-packet query processing,
5009							// we increment it for both single-packet and multi-packet queries, so that it stays in sync
5010							// with the MPUnansweredKA value, which by necessity is incremented for both query types.
5011							rr->MPUnansweredQ++;
5012							rr->MPLastUnansweredQT = m->timenow;
5013							rr->MPExpectingKA = mDNStrue;
5014							}
5015						}
5016
5017			// Check if this question is the same as any of mine.
5018			// We only do this for non-truncated queries. Right now it would be too complicated to try
5019			// to keep track of duplicate suppression state between multiple packets, especially when we
5020			// can't guarantee to receive all of the Known Answer packets that go with a particular query.
5021			if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5022				for (q = m->Questions; q; q=q->next)
5023					if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
5024						if (!q->InterfaceID || q->InterfaceID == InterfaceID)
5025							if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
5026								if (q->qtype == pktq.qtype &&
5027									q->qclass == pktq.qclass &&
5028									q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
5029									{ *dqp = q; dqp = &q->NextInDQList; }
5030			}
5031		}
5032
5033	// ***
5034	// *** 2. Now we can safely build the list of marked answers
5035	// ***
5036	for (rr = m->ResourceRecords; rr; rr=rr->next)				// Now build our list of potential answers
5037		if (rr->NR_AnswerTo)									// If we marked the record...
5038			AddRecordToResponseList(&nrp, rr, mDNSNULL);		// ... add it to the list
5039
5040	// ***
5041	// *** 3. Add additional records
5042	// ***
5043	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
5044
5045	// ***
5046	// *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list
5047	// ***
5048	for (i=0; i<query->h.numAnswers; i++)						// For each record in the query's answer section...
5049		{
5050		// Get the record...
5051		AuthRecord *rr;
5052		CacheRecord *ourcacherr;
5053		ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
5054		if (!ptr) goto exit;
5055
5056		// See if this Known-Answer suppresses any of our currently planned answers
5057		for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5058			if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5059				{ rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5060
5061		// See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
5062		for (rr=m->ResourceRecords; rr; rr=rr->next)
5063			{
5064			// If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
5065			if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5066				{
5067				if (srcaddr->type == mDNSAddrType_IPv4)
5068					{
5069					if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
5070					}
5071				else if (srcaddr->type == mDNSAddrType_IPv6)
5072					{
5073					if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
5074					}
5075				if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
5076					{
5077					rr->ImmedAnswer  = mDNSNULL;
5078					rr->ImmedUnicast = mDNSfalse;
5079#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5080					LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
5081#endif
5082					}
5083				}
5084			}
5085
5086		// See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
5087		// even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
5088		ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
5089		if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
5090			{
5091			ourcacherr->MPUnansweredKA++;
5092			ourcacherr->MPExpectingKA = mDNSfalse;
5093			}
5094
5095		// Having built our ExpectedAnswers list from the questions in this packet, we can definitively
5096		// remove from our ExpectedAnswers list any records that are suppressed in the very same packet.
5097		// For answers that are suppressed in subsequent KA list packets, we rely on the MPQ/MPKA counting to track them.
5098		eap = &ExpectedAnswers;
5099		while (*eap)
5100			{
5101			CacheRecord *rr = *eap;
5102			if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
5103				{ *eap = rr->NextInKAList; rr->NextInKAList = mDNSNULL; }
5104			else eap = &rr->NextInKAList;
5105			}
5106
5107		// See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
5108		if (!ourcacherr)
5109			{
5110			dqp = &DupQuestions;
5111			while (*dqp)
5112				{
5113				DNSQuestion *q = *dqp;
5114				if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
5115					{ *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
5116				else dqp = &q->NextInDQList;
5117				}
5118			}
5119		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5120		}
5121
5122	// ***
5123	// *** 5. Cancel any additionals that were added because of now-deleted records
5124	// ***
5125	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5126		if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo))
5127			{ rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5128
5129	// ***
5130	// *** 6. Mark the send flags on the records we plan to send
5131	// ***
5132	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5133		{
5134		if (rr->NR_AnswerTo)
5135			{
5136			mDNSBool SendMulticastResponse = mDNSfalse;		// Send modern multicast response
5137			mDNSBool SendUnicastResponse   = mDNSfalse;		// Send modern unicast response (not legacy unicast response)
5138
5139			// If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
5140			if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0)
5141				{
5142				SendMulticastResponse = mDNStrue;
5143				// If this record was marked for modern (delayed) unicast response, then mark it as promoted to
5144				// multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
5145				// If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
5146				if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0;
5147				}
5148
5149			// If the client insists on a multicast response, then we'd better send one
5150			if      (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
5151			else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse   = mDNStrue;
5152			else if (rr->NR_AnswerTo)                SendLegacyResponse    = mDNStrue;
5153
5154			if (SendMulticastResponse || SendUnicastResponse)
5155				{
5156#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5157				rr->ImmedAnswerMarkTime = m->timenow;
5158#endif
5159				m->NextScheduledResponse = m->timenow;
5160				// If we're already planning to send this on another interface, just send it on all interfaces
5161				if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID)
5162					rr->ImmedAnswer = mDNSInterfaceMark;
5163				else
5164					{
5165					rr->ImmedAnswer = InterfaceID;			// Record interface to send it on
5166					if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue;
5167					if (srcaddr->type == mDNSAddrType_IPv4)
5168						{
5169						if      (mDNSIPv4AddressIsZero(rr->v4Requester))                rr->v4Requester = srcaddr->ip.v4;
5170						else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr;
5171						}
5172					else if (srcaddr->type == mDNSAddrType_IPv6)
5173						{
5174						if      (mDNSIPv6AddressIsZero(rr->v6Requester))                rr->v6Requester = srcaddr->ip.v6;
5175						else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr;
5176						}
5177					}
5178				}
5179			// If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
5180			// so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
5181			// else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
5182			// else, for a simple unique record reply, we can reply immediately; no need for delay
5183			if      (query->h.flags.b[0] & kDNSFlag0_TC)            delayresponse = mDNSPlatformOneSecond * 20;	// Divided by 50 = 400ms
5184			else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond;		// Divided by 50 = 20ms
5185			}
5186		else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0)
5187			{
5188			// Since additional records are an optimization anyway, we only ever send them on one interface at a time
5189			// If two clients on different interfaces do queries that invoke the same optional additional answer,
5190			// then the earlier client is out of luck
5191			rr->ImmedAdditional = InterfaceID;
5192			// No need to set m->NextScheduledResponse here
5193			// We'll send these additional records when we send them, or not, as the case may be
5194			}
5195		}
5196
5197	// ***
5198	// *** 7. If we think other machines are likely to answer these questions, set our packet suppression timer
5199	// ***
5200	if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50))
5201		{
5202#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5203		mDNSs32 oldss = m->SuppressSending;
5204		if (oldss && delayresponse)
5205			LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50);
5206#endif
5207		// Pick a random delay:
5208		// We start with the base delay chosen above (typically either 1 second or 20 seconds),
5209		// and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
5210		// This is an integer value, with resolution determined by the platform clock rate.
5211		// We then divide that by 50 to get the delay value in ticks. We defer the division until last
5212		// to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
5213		// The +49 before dividing is to ensure we round up, not down, to ensure that even
5214		// on platforms where the native clock rate is less than fifty ticks per second,
5215		// we still guarantee that the final calculated delay is at least one platform tick.
5216		// We want to make sure we don't ever allow the delay to be zero ticks,
5217		// because if that happens we'll fail the Bonjour Conformance Test.
5218		// Our final computed delay is 20-120ms for normal delayed replies,
5219		// or 400-500ms in the case of multi-packet known-answer lists.
5220		m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50;
5221		if (m->SuppressSending == 0) m->SuppressSending = 1;
5222#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5223		if (oldss && delayresponse)
5224			LogMsg("Set     SuppressSending to   %5ld", m->SuppressSending - m->timenow);
5225#endif
5226		}
5227
5228	// ***
5229	// *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
5230	// ***
5231	if (SendLegacyResponse)
5232		responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
5233
5234exit:
5235	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5236
5237	// ***
5238	// *** 9. Finally, clear our link chains ready for use next time
5239	// ***
5240	while (ResponseRecords)
5241		{
5242		rr = ResponseRecords;
5243		ResponseRecords = rr->NextResponse;
5244		rr->NextResponse    = mDNSNULL;
5245		rr->NR_AnswerTo     = mDNSNULL;
5246		rr->NR_AdditionalTo = mDNSNULL;
5247		}
5248
5249	while (ExpectedAnswers)
5250		{
5251		CacheRecord *rr;
5252		rr = ExpectedAnswers;
5253		ExpectedAnswers = rr->NextInKAList;
5254		rr->NextInKAList = mDNSNULL;
5255
5256		// For non-truncated queries, we can definitively say that we should expect
5257		// to be seeing a response for any records still left in the ExpectedAnswers list
5258		if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5259			if (rr->UnansweredQueries == 0 || m->timenow - rr->LastUnansweredTime >= mDNSPlatformOneSecond)
5260				{
5261				rr->UnansweredQueries++;
5262				rr->LastUnansweredTime = m->timenow;
5263				if (rr->UnansweredQueries > 1)
5264					debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
5265						rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5266				SetNextCacheCheckTime(m, rr);
5267				}
5268
5269		// If we've seen multiple unanswered queries for this record,
5270		// then mark it to expire in five seconds if we don't get a response by then.
5271		if (rr->UnansweredQueries >= MaxUnansweredQueries)
5272			{
5273			// Only show debugging message if this record was not about to expire anyway
5274			if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
5275				debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5276					rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5277			mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
5278			}
5279		// Make a guess, based on the multi-packet query / known answer counts, whether we think we
5280		// should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
5281		// possible packet loss of up to 20% of the additional KA packets.)
5282		else if (rr->MPUnansweredQ * 4 > rr->MPUnansweredKA * 5 + 8)
5283			{
5284			// We want to do this conservatively.
5285			// If there are so many machines on the network that they have to use multi-packet known-answer lists,
5286			// then we don't want them to all hit the network simultaneously with their final expiration queries.
5287			// By setting the record to expire in four minutes, we achieve two things:
5288			// (a) the 90-95% final expiration queries will be less bunched together
5289			// (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
5290			mDNSu32 remain = (mDNSu32)(RRExpireTime(rr) - m->timenow) / 4;
5291			if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond)
5292				remain = 240 * (mDNSu32)mDNSPlatformOneSecond;
5293
5294			// Only show debugging message if this record was not about to expire anyway
5295			if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
5296				debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5297					rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5298
5299			if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
5300				rr->UnansweredQueries++;	// Treat this as equivalent to one definite unanswered query
5301			rr->MPUnansweredQ  = 0;			// Clear MPQ/MPKA statistics
5302			rr->MPUnansweredKA = 0;
5303			rr->MPExpectingKA  = mDNSfalse;
5304
5305			if (remain < kDefaultReconfirmTimeForNoAnswer)
5306				remain = kDefaultReconfirmTimeForNoAnswer;
5307			mDNS_Reconfirm_internal(m, rr, remain);
5308			}
5309		}
5310
5311	while (DupQuestions)
5312		{
5313		int i;
5314		DNSQuestion *q = DupQuestions;
5315		DupQuestions = q->NextInDQList;
5316		q->NextInDQList = mDNSNULL;
5317		i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type);
5318		debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID,
5319			srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i);
5320		}
5321
5322	return(responseptr);
5323	}
5324
5325mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
5326	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
5327	const mDNSInterfaceID InterfaceID)
5328	{
5329	mDNSu8    *responseend = mDNSNULL;
5330	mDNSBool   QueryWasLocalUnicast = !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
5331
5332	if (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr))
5333		{
5334		LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5335			"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
5336			srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
5337			msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
5338			msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
5339			msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
5340			msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
5341		return;
5342		}
5343
5344	verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5345		"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
5346		srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
5347		msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
5348		msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
5349		msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
5350		msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
5351
5352	responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
5353		(srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
5354
5355	if (responseend)	// If responseend is non-null, that means we built a unicast response packet
5356		{
5357		debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
5358			m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
5359			m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
5360			m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
5361			srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
5362		mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, -1, mDNSNULL);
5363		}
5364	}
5365
5366// NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
5367// the record list and/or question list.
5368// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
5369mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
5370	const DNSMessage *const response, const mDNSu8 *end,
5371	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
5372	const mDNSInterfaceID InterfaceID)
5373	{
5374	int i;
5375
5376	// We ignore questions (if any) in a DNS response packet
5377	const mDNSu8 *ptr = LocateAnswers(response, end);
5378
5379	// "(CacheRecord*)1" is a special (non-zero) end-of-list marker
5380	// We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
5381	// set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
5382	CacheRecord *CacheFlushRecords = (CacheRecord*)1;
5383	CacheRecord **cfp = &CacheFlushRecords;
5384
5385	// All records in a DNS response packet are treated as equally valid statements of truth. If we want
5386	// to guard against spoof responses, then the only credible protection against that is cryptographic
5387	// security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
5388	int totalrecords = response->h.numAnswers + response->h.numAuthorities + response->h.numAdditionals;
5389
5390	(void)srcaddr;	// Currently used only for display in debugging message
5391	(void)srcport;
5392	(void)dstport;
5393
5394	verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p with "
5395		"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
5396		srcaddr, dstaddr, InterfaceID,
5397		response->h.numQuestions,   response->h.numQuestions   == 1 ? ", " : "s,",
5398		response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
5399		response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
5400		response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
5401
5402	// If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us
5403	if (!mDNSAddrIsDNSMulticast(dstaddr))
5404		{
5405		if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2))
5406			return;
5407		// For now we don't put standard wide-area unicast responses in our main cache
5408		// (Later we should fix this and cache all known results in a unified manner.)
5409		if (response->h.id.NotAnInteger != 0 || srcport.NotAnInteger != MulticastDNSPort.NotAnInteger)
5410			return;
5411		}
5412
5413	for (i = 0; i < totalrecords && ptr && ptr < end; i++)
5414		{
5415		const mDNSu8 RecordType = (mDNSu8)((i < response->h.numAnswers) ? kDNSRecordTypePacketAns : kDNSRecordTypePacketAdd);
5416		ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
5417		if (!ptr) goto exit;		// Break out of the loop and clean up our CacheFlushRecords list before exiting
5418
5419		// 1. Check that this packet resource record does not conflict with any of ours
5420		if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set");
5421		m->CurrentRecord = m->ResourceRecords;
5422		while (m->CurrentRecord)
5423			{
5424			AuthRecord *rr = m->CurrentRecord;
5425			m->CurrentRecord = rr->next;
5426			if (PacketRRMatchesSignature(&m->rec.r, rr))		// If interface, name, type (if shared record) and class match...
5427				{
5428				// ... check to see if type and rdata are identical
5429				if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec))
5430					{
5431					// If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
5432					if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
5433						{
5434						// If we were planning to send on this -- and only this -- interface, then we don't need to any more
5435						if      (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
5436						}
5437					else
5438						{
5439						if      (rr->ImmedAnswer == mDNSNULL)    { rr->ImmedAnswer = InterfaceID;       m->NextScheduledResponse = m->timenow; }
5440						else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
5441						}
5442					}
5443				// else, the packet RR has different type or different rdata -- check to see if this is a conflict
5444				else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
5445					{
5446					debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr->     resrec.rdatahash, ARDisplayString(m, rr));
5447					debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
5448
5449					// If this record is marked DependentOn another record for conflict detection purposes,
5450					// then *that* record has to be bumped back to probing state to resolve the conflict
5451					while (rr->DependentOn) rr = rr->DependentOn;
5452
5453					// If we've just whacked this record's ProbeCount, don't need to do it again
5454					if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
5455						{
5456						// If we'd previously verified this record, put it back to probing state and try again
5457						if (rr->resrec.RecordType == kDNSRecordTypeVerified)
5458							{
5459							debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5460							rr->resrec.RecordType     = kDNSRecordTypeUnique;
5461							rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
5462							rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
5463							InitializeLastAPTime(m, rr);
5464							RecordProbeFailure(m, rr);	// Repeated late conflicts also cause us to back off to the slower probing rate
5465							}
5466						// If we're probing for this record, we just failed
5467						else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
5468							{
5469							debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5470							mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
5471							}
5472						// We assumed this record must be unique, but we were wrong.
5473						// (e.g. There are two mDNSResponders on the same machine giving
5474						// different answers for the reverse mapping record.)
5475						// This is simply a misconfiguration, and we don't try to recover from it.
5476						else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
5477							{
5478							debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
5479								rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5480							mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
5481							}
5482						else
5483							debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
5484								rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5485						}
5486					}
5487				// Else, matching signature, different type or rdata, but not a considered a conflict.
5488				// If the packet record has the cache-flush bit set, then we check to see if we
5489				// have any record(s) of the same type that we should re-assert to rescue them
5490				// (see note about "multi-homing and bridged networks" at the end of this function).
5491				else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
5492					if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
5493						{ rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
5494				}
5495			}
5496
5497		// 2. See if we want to add this packet resource record to our cache
5498		if (m->rrcache_size)	// Only try to cache answers if we have a cache to put them in
5499			{
5500			const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
5501			CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
5502			CacheRecord *rr;
5503			// 2a. Check if this packet resource record is already in our cache
5504			for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5505				{
5506				// If we found this exact resource record, refresh its TTL
5507				if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
5508					{
5509					if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
5510						verbosedebugf("Found record size %5d interface %p already in cache: %s",
5511							m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
5512					rr->TimeRcvd  = m->timenow;
5513
5514					if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
5515						{
5516						// If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
5517						if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList)
5518							{ *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
5519
5520						// If this packet record is marked unique, and our previous cached copy was not, then fix it
5521						if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
5522							{
5523							DNSQuestion *q;
5524							for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++;
5525							rr->resrec.RecordType = m->rec.r.resrec.RecordType;
5526							}
5527						}
5528
5529					if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength))
5530						{
5531						// If the rdata of the packet record differs in name capitalization from the record in our cache
5532						// then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
5533						// a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
5534						rr->resrec.rroriginalttl = 0;
5535						rr->UnansweredQueries = MaxUnansweredQueries;
5536						SetNextCacheCheckTime(m, rr);
5537						// DO NOT break out here -- we want to continue as if we never found it
5538						}
5539					else if (m->rec.r.resrec.rroriginalttl > 0)
5540						{
5541						rr->resrec.rroriginalttl = m->rec.r.resrec.rroriginalttl;
5542						rr->UnansweredQueries = 0;
5543						rr->MPUnansweredQ     = 0;
5544						rr->MPUnansweredKA    = 0;
5545						rr->MPExpectingKA     = mDNSfalse;
5546						SetNextCacheCheckTime(m, rr);
5547						break;
5548						}
5549					else
5550						{
5551						// If the packet TTL is zero, that means we're deleting this record.
5552						// To give other hosts on the network a chance to protest, we push the deletion
5553						// out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
5554						// Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
5555						// lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
5556						rr->resrec.rroriginalttl = 1;
5557						rr->UnansweredQueries = MaxUnansweredQueries;
5558						SetNextCacheCheckTime(m, rr);
5559						break;
5560						}
5561					}
5562				}
5563
5564			// If packet resource record not in our cache, add it now
5565			// (unless it is just a deletion of a record we never had, in which case we don't care)
5566			if (!rr && m->rec.r.resrec.rroriginalttl > 0)
5567				{
5568				// If we don't have a CacheGroup for this name, make one now
5569				if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec);
5570				if (cg) rr = GetCacheRecord(m, cg, m->rec.r.resrec.rdlength);	// Make a cache record, being careful not to recycle cg
5571				if (!rr) NoCacheAnswer(m, &m->rec.r);
5572				else
5573					{
5574					RData *saveptr = rr->resrec.rdata;		// Save the rr->resrec.rdata pointer
5575					*rr = m->rec.r;							// Block copy the CacheRecord object
5576					rr->resrec.rdata = saveptr;				// Restore rr->resrec.rdata after the structure assignment
5577					rr->resrec.name  = cg->name;			// And set rr->resrec.name to point into our CacheGroup header
5578					if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
5579						{ *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
5580					// If this is an oversized record with external storage allocated, copy rdata to external storage
5581					if (rr->resrec.rdata != (RData*)&rr->rdatastorage && !(m->rec.r.resrec.rdlength > InlineCacheRDSize))
5582						LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
5583					if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
5584						mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength);
5585					rr->next = mDNSNULL;					// Clear 'next' pointer
5586					*(cg->rrcache_tail) = rr;				// Append this record to tail of cache slot list
5587					cg->rrcache_tail = &(rr->next);			// Advance tail pointer
5588					if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)	// If marked unique, assume we may have
5589						rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond;	// to delay delivery of this 'add' event
5590					else
5591						rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
5592					CacheRecordAdd(m, rr);  // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
5593					}
5594				}
5595			}
5596		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5597		}
5598
5599exit:
5600	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5601
5602	// If we've just received one or more records with their cache flush bits set,
5603	// then scan that cache slot to see if there are any old stale records we need to flush
5604	while (CacheFlushRecords != (CacheRecord*)1)
5605		{
5606		CacheRecord *r1 = CacheFlushRecords, *r2;
5607		const mDNSu32 slot = HashSlot(r1->resrec.name);
5608		CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
5609		CacheFlushRecords = CacheFlushRecords->NextInCFList;
5610		r1->NextInCFList = mDNSNULL;
5611		for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
5612			if (SameResourceRecordSignature(&r1->resrec, &r2->resrec))
5613				{
5614				// If record was recently positively received
5615				// (i.e. not counting goodbye packets or cache flush events that set the TTL to 1)
5616				// then we need to ensure the whole RRSet has the same TTL (as required by DNS semantics)
5617				if (r2->resrec.rroriginalttl > 1 && m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
5618					{
5619					if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl)
5620						LogMsg("Correcting TTL from %4d to %4d for %s",
5621							r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
5622					r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
5623					r2->TimeRcvd = m->timenow;
5624					}
5625				else				// else, if record is old, mark it to be flushed
5626					{
5627					verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
5628					// We set stale records to expire in one second.
5629					// This gives the owner a chance to rescue it if necessary.
5630					// This is important in the case of multi-homing and bridged networks:
5631					//   Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
5632					//   bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
5633					//   set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
5634					//   will promptly delete their cached copies of the (still valid) Ethernet IP address record.
5635					//   By delaying the deletion by one second, we give X a change to notice that this bridging has
5636					//   happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
5637					// We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
5638					// final expiration queries for this record.
5639					r2->resrec.rroriginalttl = 1;
5640					r2->TimeRcvd          = m->timenow;
5641					r2->UnansweredQueries = MaxUnansweredQueries;
5642					}
5643				SetNextCacheCheckTime(m, r2);
5644				}
5645		if (r1->DelayDelivery)	// If we were planning to delay delivery of this record, see if we still need to
5646			{
5647			// Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
5648			r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
5649			if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
5650			}
5651		}
5652	}
5653
5654mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
5655	const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
5656	const mDNSInterfaceID InterfaceID)
5657	{
5658	DNSMessage  *msg  = (DNSMessage *)pkt;
5659	const mDNSu8 StdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
5660	const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
5661	mDNSu8 QR_OP;
5662	mDNSu8 *ptr = mDNSNULL;
5663	const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
5664
5665#ifndef UNICAST_DISABLED
5666	if (srcport.NotAnInteger == NATPMPPort.NotAnInteger)
5667		{
5668		mDNS_Lock(m);
5669		uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
5670		mDNS_Unlock(m);
5671		return;
5672		}
5673#endif
5674	if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
5675	QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
5676	// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
5677	ptr = (mDNSu8 *)&msg->h.numQuestions;
5678	msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
5679	msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
5680	msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
5681	msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
5682
5683	if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
5684
5685	// We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
5686	// If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
5687	if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
5688
5689	mDNS_Lock(m);
5690	m->PktNum++;
5691#ifndef UNICAST_DISABLED
5692	if (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdateR))
5693		uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5694		// Note: mDNSCore also needs to get access to received unicast responses
5695#endif
5696	if      (QR_OP == StdQ) mDNSCoreReceiveQuery   (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5697	else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5698	else if (QR_OP != UpdateR)
5699		LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)",
5700			msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID);
5701
5702	// Packet reception often causes a change to the task list:
5703	// 1. Inbound queries can cause us to need to send responses
5704	// 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
5705	// 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
5706	// 4. Response packets that answer questions may cause our client to issue new questions
5707	mDNS_Unlock(m);
5708	}
5709
5710// ***************************************************************************
5711#if COMPILER_LIKES_PRAGMA_MARK
5712#pragma mark -
5713#pragma mark -
5714#pragma mark - Searcher Functions
5715#endif
5716
5717#define SameQTarget(A,B) (mDNSSameAddress(&(A)->Target, &(B)->Target) && (A)->TargetPort.NotAnInteger == (B)->TargetPort.NotAnInteger)
5718
5719mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
5720	{
5721	DNSQuestion *q;
5722	// Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
5723	// This prevents circular references, where two questions are each marked as a duplicate of the other.
5724	// Accordingly, we break out of the loop when we get to 'question', because there's no point searching
5725	// further in the list.
5726	for (q = m->Questions; q && q != question; q=q->next)		// Scan our list of questions
5727		if (q->InterfaceID == question->InterfaceID &&			// for another question with the same InterfaceID,
5728			SameQTarget(q, question)                &&			// and same unicast/multicast target settings
5729			q->qtype       == question->qtype       &&			// type,
5730			q->qclass      == question->qclass      &&			// class,
5731			q->qnamehash   == question->qnamehash   &&
5732			SameDomainName(&q->qname, &question->qname))		// and name
5733			return(q);
5734	return(mDNSNULL);
5735	}
5736
5737// This is called after a question is deleted, in case other identical questions were being
5738// suppressed as duplicates
5739mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const question)
5740	{
5741	DNSQuestion *q;
5742	for (q = m->Questions; q; q=q->next)		// Scan our list of questions
5743		if (q->DuplicateOf == question)			// To see if any questions were referencing this as their duplicate
5744			{
5745			q->ThisQInterval    = question->ThisQInterval;
5746			q->RequestUnicast   = question->RequestUnicast;
5747			q->LastQTime        = question->LastQTime;
5748			q->RecentAnswerPkts = 0;
5749			q->DuplicateOf      = FindDuplicateQuestion(m, q);
5750			q->LastQTxTime      = question->LastQTxTime;
5751			SetNextQueryTime(m,q);
5752			}
5753	}
5754
5755#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
5756	((Q)->TargetPort.NotAnInteger == UnicastDNSPort.NotAnInteger || (Q)->TargetPort.NotAnInteger == MulticastDNSPort.NotAnInteger))
5757
5758mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
5759	{
5760	if (question->Target.type && !ValidQuestionTarget(question))
5761		{
5762		LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
5763			question->Target.type, mDNSVal16(question->TargetPort));
5764		question->Target.type = mDNSAddrType_None;
5765		}
5766
5767	if (!question->Target.type)		// No question->Target specified, so clear TargetPort and TargetQID
5768		{
5769		question->TargetPort = zeroIPPort;
5770		question->TargetQID  = zeroID;
5771		}
5772
5773#ifndef UNICAST_DISABLED
5774	// If the client has specified 'kDNSServiceFlagsForceMulticast'
5775	// then we do a multicast query on that interface, even for unicast domains.
5776    if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
5777    	question->uDNS_info.id = zeroID;
5778    else return uDNS_StartQuery(m, question);
5779#else
5780    question->uDNS_info.id = zeroID;
5781#endif // UNICAST_DISABLED
5782
5783	//LogOperation("mDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5784
5785	if (m->rrcache_size == 0)	// Can't do queries if we have no cache space allocated
5786		return(mStatus_NoCache);
5787	else
5788		{
5789		int i;
5790		// Note: It important that new questions are appended at the *end* of the list, not prepended at the start
5791		DNSQuestion **q = &m->Questions;
5792		if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
5793		while (*q && *q != question) q=&(*q)->next;
5794
5795		if (*q)
5796			{
5797			LogMsg("Error! Tried to add a question %##s (%s) that's already in the active list",
5798				question->qname.c, DNSTypeName(question->qtype));
5799			return(mStatus_AlreadyRegistered);
5800			}
5801
5802		// If this question is referencing a specific interface, verify it exists
5803		if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly)
5804			{
5805			NetworkInterfaceInfo *intf;
5806			for (intf = m->HostInterfaces; intf; intf = intf->next)
5807				if (intf->InterfaceID == question->InterfaceID) break;
5808			if (!intf)
5809				LogMsg("Note: InterfaceID %p for question %##s not currently found in active interface list",
5810					question->InterfaceID, question->qname.c);
5811			}
5812
5813		if (!ValidateDomainName(&question->qname))
5814			{
5815			LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5816			return(mStatus_Invalid);
5817			}
5818
5819		// Note: In the case where we already have the answer to this question in our cache, that may be all the client
5820		// wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
5821		// be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds
5822		// that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately.
5823		if (!m->RandomQueryDelay) m->RandomQueryDelay = 1 + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
5824
5825		question->next              = mDNSNULL;
5826		question->qnamehash         = DomainNameHashValue(&question->qname);	// MUST do this before FindDuplicateQuestion()
5827		question->DelayAnswering    = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
5828		question->ThisQInterval     = InitialQuestionInterval * 2;			// MUST be > zero for an active question
5829		question->RequestUnicast    = 2;										// Set to 2 because is decremented once *before* we check it
5830		question->LastQTime         = m->timenow - m->RandomQueryDelay;		// Avoid inter-machine synchronization
5831		question->LastAnswerPktNum  = m->PktNum;
5832		question->RecentAnswerPkts  = 0;
5833		question->CurrentAnswers    = 0;
5834		question->LargeAnswers      = 0;
5835		question->UniqueAnswers     = 0;
5836		question->FlappingInterface = mDNSNULL;
5837		question->DuplicateOf       = FindDuplicateQuestion(m, question);
5838		question->NextInDQList      = mDNSNULL;
5839		for (i=0; i<DupSuppressInfoSize; i++)
5840			question->DupSuppress[i].InterfaceID = mDNSNULL;
5841		// question->InterfaceID must be already set by caller
5842		question->SendQNow          = mDNSNULL;
5843		question->SendOnAll         = mDNSfalse;
5844		question->LastQTxTime       = m->timenow;
5845
5846		if (!question->DuplicateOf)
5847			verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) started",
5848				question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
5849				question->LastQTime + question->ThisQInterval - m->timenow, question);
5850		else
5851			verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) duplicate of (%p)",
5852				question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
5853				question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf);
5854
5855		*q = question;
5856		if (question->InterfaceID == mDNSInterface_LocalOnly)
5857			{
5858			if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
5859			}
5860		else
5861			{
5862			if (!m->NewQuestions) m->NewQuestions = question;
5863			SetNextQueryTime(m,question);
5864			}
5865
5866		return(mStatus_NoError);
5867		}
5868	}
5869
5870mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
5871	{
5872	const mDNSu32 slot = HashSlot(&question->qname);
5873	CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
5874	CacheRecord *rr;
5875	DNSQuestion **q = &m->Questions;
5876
5877    if (uDNS_IsActiveQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question);
5878
5879	if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
5880	while (*q && *q != question) q=&(*q)->next;
5881	if (*q) *q = (*q)->next;
5882	else
5883		{
5884		if (question->ThisQInterval >= 0)	// Only log error message if the query was supposed to be active
5885			LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
5886				question->qname.c, DNSTypeName(question->qtype));
5887		return(mStatus_BadReferenceErr);
5888		}
5889
5890	// Take care to cut question from list *before* calling UpdateQuestionDuplicates
5891	UpdateQuestionDuplicates(m, question);
5892	// But don't trash ThisQInterval until afterwards.
5893	question->ThisQInterval = -1;
5894
5895	// If there are any cache records referencing this as their active question, then see if any other
5896	// question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
5897	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5898		{
5899		if (rr->CRActiveQuestion == question)
5900			{
5901			DNSQuestion *q;
5902			for (q = m->Questions; q; q=q->next)		// Scan our list of questions
5903				if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
5904					break;
5905			verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p",
5906				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), q);
5907			rr->CRActiveQuestion = q;		// Question used to be active; new value may or may not be null
5908			if (!q) m->rrcache_active--;	// If no longer active, decrement rrcache_active count
5909			}
5910		}
5911
5912	// If we just deleted the question that CacheRecordAdd() or CacheRecordRmv()is about to look at,
5913	// bump its pointer forward one question.
5914	if (m->CurrentQuestion == question)
5915		{
5916		debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
5917			question->qname.c, DNSTypeName(question->qtype));
5918		m->CurrentQuestion = question->next;
5919		}
5920
5921	if (m->NewQuestions == question)
5922		{
5923		debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
5924			question->qname.c, DNSTypeName(question->qtype));
5925		m->NewQuestions = question->next;
5926		}
5927
5928	if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next;
5929
5930	// Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
5931	question->next = mDNSNULL;
5932	return(mStatus_NoError);
5933	}
5934
5935mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
5936	{
5937	mStatus status;
5938	mDNS_Lock(m);
5939	status = mDNS_StartQuery_internal(m, question);
5940	mDNS_Unlock(m);
5941	return(status);
5942	}
5943
5944mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
5945	{
5946	mStatus status;
5947	mDNS_Lock(m);
5948	status = mDNS_StopQuery_internal(m, question);
5949	mDNS_Unlock(m);
5950	return(status);
5951	}
5952
5953mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const rr)
5954	{
5955	mStatus status;
5956	mDNS_Lock(m);
5957	status = mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
5958	mDNS_Unlock(m);
5959	return(status);
5960	}
5961
5962mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr)
5963	{
5964	mStatus status = mStatus_BadReferenceErr;
5965	CacheRecord *cr;
5966	mDNS_Lock(m);
5967	cr = FindIdenticalRecordInCache(m, rr);
5968	if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
5969	mDNS_Unlock(m);
5970	return(status);
5971	}
5972
5973mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
5974	const domainname *const srv, const domainname *const domain,
5975	const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
5976	{
5977	question->InterfaceID      = InterfaceID;
5978	question->Target           = zeroAddr;
5979	question->qtype            = kDNSType_PTR;
5980	question->qclass           = kDNSClass_IN;
5981	question->LongLived        = mDNSfalse;
5982	question->ExpectUnique     = mDNSfalse;
5983	question->ForceMCast       = ForceMCast;
5984	question->QuestionCallback = Callback;
5985	question->QuestionContext  = Context;
5986	if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
5987
5988#ifndef UNICAST_DISABLED
5989    if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
5990    	{
5991		question->LongLived = mDNSfalse;
5992		question->uDNS_info.id = zeroID;
5993		return(mDNS_StartQuery(m, question));
5994		}
5995	else
5996		{
5997		mStatus status;
5998		// Need to explicitly lock here, because mDNS_StartQuery does locking but uDNS_StartQuery does not
5999		mDNS_Lock(m);
6000		question->LongLived = mDNStrue;
6001		status = uDNS_StartQuery(m, question);
6002		mDNS_Unlock(m);
6003		return(status);
6004		}
6005#else
6006	return(mDNS_StartQuery(m, question));
6007#endif // UNICAST_DISABLED
6008	}
6009
6010mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
6011	{
6012	NetworkInterfaceInfo *intf;
6013	for (intf = m->HostInterfaces; intf; intf = intf->next)
6014	if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue);
6015	return(mDNSfalse);
6016	}
6017
6018mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6019	{
6020	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6021	mDNSBool PortChanged = (mDNSBool)(query->info->port.NotAnInteger != answer->rdata->u.srv.port.NotAnInteger);
6022	if (!AddRecord) return;
6023	if (answer->rrtype != kDNSType_SRV) return;
6024
6025	query->info->port = answer->rdata->u.srv.port;
6026
6027	// If this is our first answer, then set the GotSRV flag and start the address query
6028	if (!query->GotSRV)
6029		{
6030		query->GotSRV             = mDNStrue;
6031		query->qAv4.InterfaceID   = answer->InterfaceID;
6032		AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
6033		query->qAv6.InterfaceID   = answer->InterfaceID;
6034		AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
6035		mDNS_StartQuery(m, &query->qAv4);
6036		// Only do the AAAA query if this machine actually has IPv6 active
6037		if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
6038		}
6039	// If this is not our first answer, only re-issue the address query if the target host name has changed
6040	else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) ||
6041		!SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target))
6042		{
6043		mDNS_StopQuery(m, &query->qAv4);
6044		if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6);
6045		if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged)
6046			{
6047			// If we get here, it means:
6048			// 1. This is not our first SRV answer
6049			// 2. The interface ID is different, but the target host and port are the same
6050			// This implies that we're seeing the exact same SRV record on more than one interface, so we should
6051			// make our address queries at least as broad as the original SRV query so that we catch all the answers.
6052			query->qAv4.InterfaceID = query->qSRV.InterfaceID;	// Will be mDNSInterface_Any, or a specific interface
6053			query->qAv6.InterfaceID = query->qSRV.InterfaceID;
6054			}
6055		else
6056			{
6057			query->qAv4.InterfaceID   = answer->InterfaceID;
6058			AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
6059			query->qAv6.InterfaceID   = answer->InterfaceID;
6060			AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
6061			}
6062		debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c);
6063		mDNS_StartQuery(m, &query->qAv4);
6064		// Only do the AAAA query if this machine actually has IPv6 active
6065		if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
6066		}
6067	else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged)
6068		{
6069		if (++query->Answers >= 100)
6070			debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
6071				query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c,
6072				mDNSVal16(answer->rdata->u.srv.port));
6073		query->ServiceInfoQueryCallback(m, query);
6074		}
6075	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6076	// callback function is allowed to do anything, including deleting this query and freeing its memory.
6077	}
6078
6079mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6080	{
6081	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6082	if (!AddRecord) return;
6083	if (answer->rrtype != kDNSType_TXT) return;
6084	if (answer->rdlength > sizeof(query->info->TXTinfo)) return;
6085
6086	query->GotTXT       = mDNStrue;
6087	query->info->TXTlen = answer->rdlength;
6088	query->info->TXTinfo[0] = 0;		// In case answer->rdlength is zero
6089	mDNSPlatformMemCopy(answer->rdata->u.txt.c, query->info->TXTinfo, answer->rdlength);
6090
6091	verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
6092
6093	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6094	// callback function is allowed to do anything, including deleting this query and freeing its memory.
6095	if (query->ServiceInfoQueryCallback && query->GotADD)
6096		{
6097		if (++query->Answers >= 100)
6098			debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
6099				query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c);
6100		query->ServiceInfoQueryCallback(m, query);
6101		}
6102	}
6103
6104mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6105	{
6106	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6107	//LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
6108	if (!AddRecord) return;
6109
6110	if (answer->rrtype == kDNSType_A)
6111		{
6112		query->info->ip.type = mDNSAddrType_IPv4;
6113		query->info->ip.ip.v4 = answer->rdata->u.ipv4;
6114		}
6115	else if (answer->rrtype == kDNSType_AAAA)
6116		{
6117		query->info->ip.type = mDNSAddrType_IPv6;
6118		query->info->ip.ip.v6 = answer->rdata->u.ipv6;
6119		}
6120	else
6121		{
6122		debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype));
6123		return;
6124		}
6125
6126	query->GotADD = mDNStrue;
6127	query->info->InterfaceID = answer->InterfaceID;
6128
6129	verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
6130
6131	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6132	// callback function is allowed to do anything, including deleting this query and freeing its memory.
6133	if (query->ServiceInfoQueryCallback && query->GotTXT)
6134		{
6135		if (++query->Answers >= 100)
6136			debugf(answer->rrtype == kDNSType_A ?
6137				"**** WARNING **** have given %lu answers for %##s (A) %.4a" :
6138				"**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
6139				query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
6140		query->ServiceInfoQueryCallback(m, query);
6141		}
6142	}
6143
6144// On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
6145// If the query is not interface-specific, then InterfaceID may be zero
6146// Each time the Callback is invoked, the remainder of the fields will have been filled in
6147// In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
6148mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
6149	ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context)
6150	{
6151	mStatus status;
6152	mDNS_Lock(m);
6153
6154	query->qSRV.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
6155	query->qSRV.InterfaceID         = info->InterfaceID;
6156	query->qSRV.Target              = zeroAddr;
6157	AssignDomainName(&query->qSRV.qname, &info->name);
6158	query->qSRV.qtype               = kDNSType_SRV;
6159	query->qSRV.qclass              = kDNSClass_IN;
6160	query->qSRV.LongLived           = mDNSfalse;
6161	query->qSRV.ExpectUnique        = mDNStrue;
6162	query->qSRV.ForceMCast          = mDNSfalse;
6163	query->qSRV.QuestionCallback    = FoundServiceInfoSRV;
6164	query->qSRV.QuestionContext     = query;
6165
6166	query->qTXT.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
6167	query->qTXT.InterfaceID         = info->InterfaceID;
6168	query->qTXT.Target              = zeroAddr;
6169	AssignDomainName(&query->qTXT.qname, &info->name);
6170	query->qTXT.qtype               = kDNSType_TXT;
6171	query->qTXT.qclass              = kDNSClass_IN;
6172	query->qTXT.LongLived           = mDNSfalse;
6173	query->qTXT.ExpectUnique        = mDNStrue;
6174	query->qTXT.ForceMCast          = mDNSfalse;
6175	query->qTXT.QuestionCallback    = FoundServiceInfoTXT;
6176	query->qTXT.QuestionContext     = query;
6177
6178	query->qAv4.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
6179	query->qAv4.InterfaceID         = info->InterfaceID;
6180	query->qAv4.Target              = zeroAddr;
6181	query->qAv4.qname.c[0]          = 0;
6182	query->qAv4.qtype               = kDNSType_A;
6183	query->qAv4.qclass              = kDNSClass_IN;
6184	query->qAv4.LongLived           = mDNSfalse;
6185	query->qAv4.ExpectUnique        = mDNStrue;
6186	query->qAv4.ForceMCast          = mDNSfalse;
6187	query->qAv4.QuestionCallback    = FoundServiceInfo;
6188	query->qAv4.QuestionContext     = query;
6189
6190	query->qAv6.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
6191	query->qAv6.InterfaceID         = info->InterfaceID;
6192	query->qAv6.Target              = zeroAddr;
6193	query->qAv6.qname.c[0]          = 0;
6194	query->qAv6.qtype               = kDNSType_AAAA;
6195	query->qAv6.qclass              = kDNSClass_IN;
6196	query->qAv6.LongLived           = mDNSfalse;
6197	query->qAv6.ExpectUnique        = mDNStrue;
6198	query->qAv6.ForceMCast          = mDNSfalse;
6199	query->qAv6.QuestionCallback    = FoundServiceInfo;
6200	query->qAv6.QuestionContext     = query;
6201
6202	query->GotSRV                   = mDNSfalse;
6203	query->GotTXT                   = mDNSfalse;
6204	query->GotADD                   = mDNSfalse;
6205	query->Answers                  = 0;
6206
6207	query->info                     = info;
6208	query->ServiceInfoQueryCallback = Callback;
6209	query->ServiceInfoQueryContext  = Context;
6210
6211//	info->name      = Must already be set up by client
6212//	info->interface = Must already be set up by client
6213	info->ip        = zeroAddr;
6214	info->port      = zeroIPPort;
6215	info->TXTlen    = 0;
6216
6217	// We use mDNS_StartQuery_internal here because we're already holding the lock
6218	status = mDNS_StartQuery_internal(m, &query->qSRV);
6219	if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT);
6220	if (status != mStatus_NoError) mDNS_StopResolveService(m, query);
6221
6222	mDNS_Unlock(m);
6223	return(status);
6224	}
6225
6226mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
6227	{
6228	mDNS_Lock(m);
6229	// We use mDNS_StopQuery_internal here because we're already holding the lock
6230	if (q->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qSRV, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qSRV);
6231	if (q->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qTXT, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qTXT);
6232	if (q->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv4, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv4);
6233	if (q->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv6, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv6);
6234	mDNS_Unlock(m);
6235	}
6236
6237mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
6238	const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
6239	{
6240	question->InterfaceID      = InterfaceID;
6241	question->Target           = zeroAddr;
6242	question->qtype            = kDNSType_PTR;
6243	question->qclass           = kDNSClass_IN;
6244	question->LongLived        = mDNSfalse;
6245	question->ExpectUnique     = mDNSfalse;
6246	question->ForceMCast       = mDNSfalse;
6247	question->QuestionCallback = Callback;
6248	question->QuestionContext  = Context;
6249	if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
6250	if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
6251	if (!dom) dom = &localdomain;
6252	if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
6253	return(mDNS_StartQuery(m, question));
6254	}
6255
6256// ***************************************************************************
6257#if COMPILER_LIKES_PRAGMA_MARK
6258#pragma mark -
6259#pragma mark - Responder Functions
6260#endif
6261
6262mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
6263	{
6264	mStatus status;
6265	mDNS_Lock(m);
6266	status = mDNS_Register_internal(m, rr);
6267	mDNS_Unlock(m);
6268	return(status);
6269	}
6270
6271mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
6272	const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
6273	{
6274#ifndef UNICAST_DISABLED
6275	mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
6276#else
6277	mDNSBool unicast = mDNSfalse;
6278#endif
6279
6280	if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
6281		{
6282		LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
6283		return(mStatus_Invalid);
6284		}
6285
6286	mDNS_Lock(m);
6287
6288	// If TTL is unspecified, leave TTL unchanged
6289	if (newttl == 0) newttl = rr->resrec.rroriginalttl;
6290
6291	// If we already have an update queued up which has not gone through yet,
6292	// give the client a chance to free that memory
6293	if (!unicast && rr->NewRData)
6294		{
6295		RData *n = rr->NewRData;
6296		rr->NewRData = mDNSNULL;			// Clear the NewRData pointer ...
6297		if (rr->UpdateCallback)
6298			rr->UpdateCallback(m, rr, n);	// ...and let the client free this memory, if necessary
6299		}
6300
6301	rr->NewRData             = newrdata;
6302	rr->newrdlength          = newrdlength;
6303	rr->UpdateCallback       = Callback;
6304
6305	if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
6306
6307	if (rr->resrec.rroriginalttl == newttl &&
6308		rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
6309		CompleteRDataUpdate(m, rr);
6310	else
6311		{
6312		domainlabel name;
6313		domainname type, domain;
6314		DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
6315		rr->AnnounceCount = InitialAnnounceCount;
6316		// iChat often does suprious record updates where no data has changed. For the _presence service type, using
6317		// name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
6318		// update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
6319		// even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
6320		// To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
6321		if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
6322		rr->ThisAPInterval       = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
6323		InitializeLastAPTime(m, rr);
6324		while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
6325		if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
6326		if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
6327		if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
6328		if (rr->UpdateCredits <= 5)
6329			{
6330			mDNSu32 delay = 6 - rr->UpdateCredits;		// Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
6331			if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
6332			rr->ThisAPInterval *= 4;
6333			rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
6334			LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
6335				rr->resrec.name->c, delay, delay > 1 ? "s" : "");
6336			}
6337		rr->resrec.rroriginalttl = newttl;
6338		}
6339
6340	mDNS_Unlock(m);
6341	return(mStatus_NoError);
6342	}
6343
6344// NOTE: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
6345// the record list and/or question list.
6346// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6347mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
6348	{
6349	mStatus status;
6350	mDNS_Lock(m);
6351	status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
6352	mDNS_Unlock(m);
6353	return(status);
6354	}
6355
6356mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
6357
6358mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
6359	{
6360	NetworkInterfaceInfo *intf;
6361	for (intf = m->HostInterfaces; intf; intf = intf->next)
6362		if (intf->Advertise) break;
6363	return(intf);
6364	}
6365
6366mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
6367	{
6368	char buffer[256];
6369	NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
6370	if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
6371
6372	// Send dynamic update for non-linklocal IPv4 Addresses
6373	mDNS_SetupResourceRecord(&set->RR_A,     mDNSNULL, set->InterfaceID, kDNSType_A,     kHostNameTTL, kDNSRecordTypeUnique,      mDNS_HostNameCallback, set);
6374	mDNS_SetupResourceRecord(&set->RR_PTR,   mDNSNULL, set->InterfaceID, kDNSType_PTR,   kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
6375	mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique,      mDNSNULL, mDNSNULL);
6376
6377#if ANSWER_REMOTE_HOSTNAME_QUERIES
6378	set->RR_A    .AllowRemoteQuery  = mDNStrue;
6379	set->RR_PTR  .AllowRemoteQuery  = mDNStrue;
6380	set->RR_HINFO.AllowRemoteQuery  = mDNStrue;
6381#endif
6382	// 1. Set up Address record to map from host name ("foo.local.") to IP address
6383	// 2. Set up reverse-lookup PTR record to map from our address back to our host name
6384	AssignDomainName(set->RR_A.resrec.name, &m->MulticastHostname);
6385	if (set->ip.type == mDNSAddrType_IPv4)
6386		{
6387		set->RR_A.resrec.rrtype = kDNSType_A;
6388		set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
6389		// Note: This is reverse order compared to a normal dotted-decimal IP address
6390		mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
6391			set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
6392		}
6393	else if (set->ip.type == mDNSAddrType_IPv6)
6394		{
6395		int i;
6396		set->RR_A.resrec.rrtype = kDNSType_AAAA;
6397		set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
6398		for (i = 0; i < 16; i++)
6399			{
6400			static const char hexValues[] = "0123456789ABCDEF";
6401			buffer[i * 4    ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F];
6402			buffer[i * 4 + 1] = '.';
6403			buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4];
6404			buffer[i * 4 + 3] = '.';
6405			}
6406		mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
6407		}
6408
6409	MakeDomainNameFromDNSNameString(set->RR_PTR.resrec.name, buffer);
6410	set->RR_PTR.HostTarget = mDNStrue;	// Tell mDNS that the target of this PTR is to be kept in sync with our host name
6411	set->RR_PTR.ForceMCast = mDNStrue;	// This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
6412
6413	set->RR_A.RRSet = &primary->RR_A;	// May refer to self
6414
6415	mDNS_Register_internal(m, &set->RR_A);
6416	mDNS_Register_internal(m, &set->RR_PTR);
6417
6418	if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
6419		{
6420		mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
6421		AssignDomainName(set->RR_HINFO.resrec.name, &m->MulticastHostname);
6422		set->RR_HINFO.DependentOn = &set->RR_A;
6423		mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]);
6424		p += 1 + (int)p[0];
6425		mDNSPlatformMemCopy(&m->HISoftware, p, 1 + (mDNSu32)m->HISoftware.c[0]);
6426		mDNS_Register_internal(m, &set->RR_HINFO);
6427		}
6428	else
6429		{
6430		debugf("Not creating HINFO record: platform support layer provided no information");
6431		set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
6432		}
6433	}
6434
6435mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
6436	{
6437	NetworkInterfaceInfo *intf;
6438
6439    // If we still have address records referring to this one, update them
6440	NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
6441	AuthRecord *A = primary ? &primary->RR_A : mDNSNULL;
6442	for (intf = m->HostInterfaces; intf; intf = intf->next)
6443		if (intf->RR_A.RRSet == &set->RR_A)
6444			intf->RR_A.RRSet = A;
6445
6446	// Unregister these records.
6447	// When doing the mDNS_Close processing, we first call DeadvertiseInterface for each interface, so by the time the platform
6448	// support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
6449	// Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
6450	// To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
6451	if (set->RR_A.    resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A,     mDNS_Dereg_normal);
6452	if (set->RR_PTR.  resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR,   mDNS_Dereg_normal);
6453	if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
6454	}
6455
6456mDNSexport void mDNS_SetFQDN(mDNS *const m)
6457	{
6458	domainname newmname;
6459	NetworkInterfaceInfo *intf;
6460	AuthRecord *rr;
6461	newmname.c[0] = 0;
6462
6463	if (!AppendDomainLabel(&newmname, &m->hostlabel))  { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6464	if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6465	if (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
6466
6467	mDNS_Lock(m);
6468	AssignDomainName(&m->MulticastHostname, &newmname);
6469
6470	// 1. Stop advertising our address records on all interfaces
6471	for (intf = m->HostInterfaces; intf; intf = intf->next)
6472		if (intf->Advertise) DeadvertiseInterface(m, intf);
6473
6474	// 2. Start advertising our address records using the new name
6475	for (intf = m->HostInterfaces; intf; intf = intf->next)
6476		if (intf->Advertise) AdvertiseInterface(m, intf);
6477
6478	// 3. Make sure that any SRV records (and the like) that reference our
6479	// host name in their rdata get updated to reference this new host name
6480	for (rr = m->ResourceRecords;  rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
6481	for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
6482
6483	mDNS_Unlock(m);
6484	}
6485
6486mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6487	{
6488	(void)rr;	// Unused parameter
6489
6490	#if MDNS_DEBUGMSGS
6491		{
6492		char *msg = "Unknown result";
6493		if      (result == mStatus_NoError)      msg = "Name registered";
6494		else if (result == mStatus_NameConflict) msg = "Name conflict";
6495		debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
6496		}
6497	#endif
6498
6499	if (result == mStatus_NoError)
6500		{
6501		// Notify the client that the host name is successfully registered
6502		if (m->MainCallback)
6503			{
6504			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
6505			m->MainCallback(m, result);
6506			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
6507			}
6508		}
6509	else if (result == mStatus_NameConflict)
6510		{
6511		domainlabel oldlabel = m->hostlabel;
6512
6513		// 1. First give the client callback a chance to pick a new name
6514		if (m->MainCallback)
6515			{
6516			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
6517			m->MainCallback(m, mStatus_NameConflict);
6518			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
6519			}
6520
6521		// 2. If the client callback didn't do it, add (or increment) an index ourselves
6522		if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
6523			IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
6524
6525		// 3. Generate the FQDNs from the hostlabel,
6526		// and make sure all SRV records, etc., are updated to reference our new hostname
6527		mDNS_SetFQDN(m);
6528		LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c);
6529		}
6530	else if (result == mStatus_MemFree)
6531		{
6532		// .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
6533		// mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
6534		debugf("mDNS_HostNameCallback: MemFree (ignored)");
6535		}
6536	else
6537		LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result,  rr->resrec.name->c);
6538	}
6539
6540mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
6541	{
6542	NetworkInterfaceInfo *intf;
6543	active->IPv4Available = mDNSfalse;
6544	active->IPv6Available = mDNSfalse;
6545	for (intf = m->HostInterfaces; intf; intf = intf->next)
6546		if (intf->InterfaceID == active->InterfaceID)
6547			{
6548			if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue;
6549			if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue;
6550			}
6551	}
6552
6553mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
6554	{
6555	mDNSBool FirstOfType = mDNStrue;
6556	NetworkInterfaceInfo **p = &m->HostInterfaces;
6557
6558	if (!set->InterfaceID)
6559		{ LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); }
6560
6561	if (!mDNSAddressIsValidNonZero(&set->mask))
6562		{ LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); }
6563
6564	mDNS_Lock(m);
6565
6566	// Assume this interface will be active now, unless we find a duplicate already in the list
6567	set->InterfaceActive = mDNStrue;
6568	set->IPv4Available   = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
6569	set->IPv6Available   = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
6570
6571	// Scan list to see if this InterfaceID is already represented
6572	while (*p)
6573		{
6574		if (*p == set)
6575			{
6576			LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
6577			mDNS_Unlock(m);
6578			return(mStatus_AlreadyRegistered);
6579			}
6580
6581		if ((*p)->InterfaceID == set->InterfaceID)
6582			{
6583			// This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
6584			set->InterfaceActive = mDNSfalse;
6585			if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
6586			if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
6587			if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue;
6588			}
6589
6590		p=&(*p)->next;
6591		}
6592
6593	set->next = mDNSNULL;
6594	*p = set;
6595
6596	if (set->Advertise)
6597		AdvertiseInterface(m, set);
6598
6599	LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
6600		set->InterfaceActive ?
6601			"not represented in list; marking active and retriggering queries" :
6602			"already represented in list; marking inactive for now");
6603
6604	// In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6605	// giving the false impression that there's an active representative of this interface when there really isn't.
6606	// Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
6607	// even if we believe that we previously had an active representative of this interface.
6608	if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
6609		{
6610		DNSQuestion *q;
6611		AuthRecord *rr;
6612		// If flapping, delay between first and second queries is eight seconds instead of one
6613		mDNSs32 delay    = flapping ? mDNSPlatformOneSecond   * 5 : 0;
6614		mDNSu8  announce = flapping ? (mDNSu8)1                   : InitialAnnounceCount;
6615
6616		// Use a small amount of randomness:
6617		// In the case of a network administrator turning on an Ethernet hub so that all the
6618		// connected machines establish link at exactly the same time, we don't want them all
6619		// to go and hit the network with identical queries at exactly the same moment.
6620		if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
6621
6622		if (flapping)
6623			{
6624			LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip);
6625			if (!m->SuppressProbes ||
6626				m->SuppressProbes - (m->timenow + delay) < 0)
6627				m->SuppressProbes = (m->timenow + delay);
6628			}
6629
6630		for (q = m->Questions; q; q=q->next)							// Scan our list of questions
6631			if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)	// If non-specific Q, or Q on this specific interface,
6632				{														// then reactivate this question
6633				mDNSs32 initial  = (flapping && q->FlappingInterface != set->InterfaceID) ? InitialQuestionInterval * 8 : InitialQuestionInterval;
6634				mDNSs32 qdelay   = (flapping && q->FlappingInterface != set->InterfaceID) ? mDNSPlatformOneSecond   * 5 : 0;
6635				if (flapping && q->FlappingInterface == set->InterfaceID)
6636					LogOperation("No cache records for %##s (%s) expired; no need for immediate question", q->qname.c, DNSTypeName(q->qtype));
6637
6638				if (!q->ThisQInterval || q->ThisQInterval > initial)
6639					{
6640					q->ThisQInterval = initial;
6641					q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
6642					}
6643				if (q->LastQTime - (m->timenow - q->ThisQInterval + qdelay) > 0)
6644					q->LastQTime = (m->timenow - q->ThisQInterval + qdelay);
6645				q->RecentAnswerPkts = 0;
6646				SetNextQueryTime(m,q);
6647				}
6648
6649		// For all our non-specific authoritative resource records (and any dormant records specific to this interface)
6650		// we now need them to re-probe if necessary, and then re-announce.
6651		for (rr = m->ResourceRecords; rr; rr=rr->next)
6652			if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
6653				{
6654				if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
6655				rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
6656				if (rr->AnnounceCount < announce) rr->AnnounceCount  = announce;
6657				rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
6658				InitializeLastAPTime(m, rr);
6659				}
6660		}
6661
6662	mDNS_Unlock(m);
6663	return(mStatus_NoError);
6664	}
6665
6666// NOTE: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
6667// the record list and/or question list.
6668// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6669mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
6670	{
6671	NetworkInterfaceInfo **p = &m->HostInterfaces;
6672
6673	mDNSBool revalidate = mDNSfalse;
6674	// If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
6675	// time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
6676	// still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
6677	if (m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) revalidate = mDNStrue;
6678
6679	mDNS_Lock(m);
6680
6681	// Find this record in our list
6682	while (*p && *p != set) p=&(*p)->next;
6683	if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; }
6684
6685	// Unlink this record from our list
6686	*p = (*p)->next;
6687	set->next = mDNSNULL;
6688
6689	if (!set->InterfaceActive)
6690		{
6691		// If this interface not the active member of its set, update the v4/v6Available flags for the active member
6692		NetworkInterfaceInfo *intf;
6693		for (intf = m->HostInterfaces; intf; intf = intf->next)
6694			if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID)
6695				UpdateInterfaceProtocols(m, intf);
6696		}
6697	else
6698		{
6699		NetworkInterfaceInfo *intf;
6700		for (intf = m->HostInterfaces; intf; intf = intf->next)
6701			if (intf->InterfaceID == set->InterfaceID)
6702				break;
6703		if (intf)
6704			{
6705			LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
6706				" making it active", set->InterfaceID, set->ifname, &set->ip);
6707			intf->InterfaceActive = mDNStrue;
6708			UpdateInterfaceProtocols(m, intf);
6709
6710			// See if another representative *of the same type* exists. If not, we mave have gone from
6711			// dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
6712			for (intf = m->HostInterfaces; intf; intf = intf->next)
6713				if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type)
6714					break;
6715			if (!intf) revalidate = mDNStrue;
6716			}
6717		else
6718			{
6719			mDNSu32 slot;
6720			CacheGroup *cg;
6721			CacheRecord *rr;
6722			DNSQuestion *q;
6723			LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
6724				" marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
6725
6726			if (flapping)
6727				LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
6728					set->ifname, &set->ip);
6729
6730			// 1. Deactivate any questions specific to this interface, and tag appropriate questions
6731			// so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
6732			for (q = m->Questions; q; q=q->next)
6733				{
6734				if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
6735				if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
6736					q->FlappingInterface = set->InterfaceID;
6737				}
6738
6739			// 2. Flush any cache records received on this interface
6740			revalidate = mDNSfalse;		// Don't revalidate if we're flushing the records
6741			FORALL_CACHERECORDS(slot, cg, rr)
6742				if (rr->resrec.InterfaceID == set->InterfaceID)
6743					{
6744					// If this interface is deemed flapping,
6745					// postpone deleting the cache records in case the interface comes back again
6746					if (!flapping) PurgeCacheResourceRecord(m, rr);
6747					else mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
6748					}
6749			}
6750		}
6751
6752	// If we were advertising on this interface, deregister those address and reverse-lookup records now
6753	if (set->Advertise) DeadvertiseInterface(m, set);
6754
6755	// If we have any cache records received on this interface that went away, then re-verify them.
6756	// In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6757	// giving the false impression that there's an active representative of this interface when there really isn't.
6758	// Don't need to do this when shutting down, because *all* interfaces are about to go away
6759	if (revalidate && !m->mDNS_shutdown)
6760		{
6761		mDNSu32 slot;
6762		CacheGroup *cg;
6763		CacheRecord *rr;
6764		m->NextCacheCheck = m->timenow;
6765		FORALL_CACHERECORDS(slot, cg, rr)
6766			if (rr->resrec.InterfaceID == set->InterfaceID)
6767				mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
6768		}
6769
6770	mDNS_Unlock(m);
6771	}
6772
6773mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6774	{
6775	ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
6776	(void)m;	// Unused parameter
6777
6778	#if MDNS_DEBUGMSGS
6779		{
6780		char *msg = "Unknown result";
6781		if      (result == mStatus_NoError)      msg = "Name Registered";
6782		else if (result == mStatus_NameConflict) msg = "Name Conflict";
6783		else if (result == mStatus_MemFree)      msg = "Memory Free";
6784		debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
6785		}
6786	#endif
6787
6788	// Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
6789	if (result == mStatus_NoError && rr != &sr->RR_SRV) return;
6790
6791	// If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
6792	if (result == mStatus_NameConflict)
6793		{
6794		sr->Conflict = mDNStrue;				// Record that this service set had a conflict
6795		mDNS_DeregisterService(m, sr);			// Unlink the records from our list
6796		return;
6797		}
6798
6799	if (result == mStatus_MemFree)
6800		{
6801		// If the PTR record or any of the subtype PTR records are still in the process of deregistering,
6802		// don't pass on the NameConflict/MemFree message until every record is finished cleaning up.
6803		mDNSu32 i;
6804		if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
6805		for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return;
6806
6807		// If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
6808		// then we can now report the NameConflict to the client
6809		if (sr->Conflict) result = mStatus_NameConflict;
6810		}
6811
6812	// CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
6813	// function is allowed to do anything, including deregistering this service and freeing its memory.
6814	if (sr->ServiceCallback)
6815		sr->ServiceCallback(m, sr, result);
6816	}
6817
6818mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6819	{
6820	ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
6821	if (sr->ServiceCallback)
6822		sr->ServiceCallback(m, sr, result);
6823	}
6824
6825// Note:
6826// Name is first label of domain name (any dots in the name are actual dots, not label separators)
6827// Type is service type (e.g. "_ipp._tcp.")
6828// Domain is fully qualified domain name (i.e. ending with a null label)
6829// We always register a TXT, even if it is empty (so that clients are not
6830// left waiting forever looking for a nonexistent record.)
6831// If the host parameter is mDNSNULL or the root domain (ASCII NUL),
6832// then the default host name (m->MulticastHostname) is automatically used
6833mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
6834	const domainlabel *const name, const domainname *const type, const domainname *const domain,
6835	const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
6836	AuthRecord *SubTypes, mDNSu32 NumSubTypes,
6837	const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context)
6838	{
6839	mStatus err;
6840	mDNSu32 i;
6841
6842	sr->ServiceCallback = Callback;
6843	sr->ServiceContext  = Context;
6844	sr->Extras          = mDNSNULL;
6845	sr->NumSubTypes     = NumSubTypes;
6846	sr->SubTypes        = SubTypes;
6847	sr->Conflict        = mDNSfalse;
6848	if (host && host->c[0]) sr->Host = *host;
6849	else sr->Host.c[0] = 0;
6850
6851	// If port number is zero, that means the client is really trying to do a RegisterNoSuchService
6852	if (!port.NotAnInteger)
6853		return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
6854
6855	// Initialize the AuthRecord objects to sane values
6856	mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
6857	mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared,   ServiceCallback, sr);
6858	mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
6859	mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
6860
6861	// If the client is registering an oversized TXT record,
6862	// it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
6863	if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
6864		sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen;
6865
6866	// Set up the record names
6867	// For now we only create an advisory record for the main type, not for subtypes
6868	// We need to gain some operational experience before we decide if there's a need to create them for subtypes too
6869	if (ConstructServiceName(sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
6870		return(mStatus_BadParamErr);
6871	if (ConstructServiceName(sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6872	if (ConstructServiceName(sr->RR_SRV.resrec.name, name,     type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6873	AssignDomainName(sr->RR_TXT.resrec.name, sr->RR_SRV.resrec.name);
6874
6875	// 1. Set up the ADV record rdata to advertise our service type
6876	AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
6877
6878	// 2. Set up the PTR record rdata to point to our service name
6879	// We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
6880	AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
6881	sr->RR_PTR.Additional1 = &sr->RR_SRV;
6882	sr->RR_PTR.Additional2 = &sr->RR_TXT;
6883
6884	// 2a. Set up any subtype PTRs to point to our service name
6885	// If the client is using subtypes, it is the client's responsibility to have
6886	// already set the first label of the record name to the subtype being registered
6887	for (i=0; i<NumSubTypes; i++)
6888		{
6889		domainname st;
6890		AssignDomainName(&st, sr->SubTypes[i].resrec.name);
6891		st.c[1+st.c[0]] = 0;			// Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
6892		AppendDomainName(&st, type);
6893		mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
6894		if (ConstructServiceName(sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
6895		AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
6896		sr->SubTypes[i].Additional1 = &sr->RR_SRV;
6897		sr->SubTypes[i].Additional2 = &sr->RR_TXT;
6898		}
6899
6900	// 3. Set up the SRV record rdata.
6901	sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
6902	sr->RR_SRV.resrec.rdata->u.srv.weight   = 0;
6903	sr->RR_SRV.resrec.rdata->u.srv.port     = port;
6904
6905	// Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
6906	if (sr->Host.c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, &sr->Host);
6907	else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
6908
6909	// 4. Set up the TXT record rdata,
6910	// and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
6911	if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0;
6912	else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c)
6913		{
6914		sr->RR_TXT.resrec.rdlength = txtlen;
6915		if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr);
6916		mDNSPlatformMemCopy(txtinfo, sr->RR_TXT.resrec.rdata->u.txt.c, txtlen);
6917		}
6918	sr->RR_TXT.DependentOn = &sr->RR_SRV;
6919
6920#ifndef UNICAST_DISABLED
6921	// If the client has specified an explicit InterfaceID,
6922	// then we do a multicast registration on that interface, even for unicast domains.
6923	if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
6924		{
6925		mStatus status;
6926		mDNS_Lock(m);
6927		// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
6928		// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
6929		// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
6930		// (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
6931		if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
6932		status = uDNS_RegisterService(m, sr);
6933		mDNS_Unlock(m);
6934		return(status);
6935		}
6936#endif
6937	mDNS_Lock(m);
6938	err = mDNS_Register_internal(m, &sr->RR_SRV);
6939	if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
6940	// We register the RR_PTR last, because we want to be sure that in the event of a forced call to
6941	// mDNS_Close, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
6942	// the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
6943	// the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
6944	// make sure we've deregistered all our records and done any other necessary cleanup before that happens.
6945	if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV);
6946	for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]);
6947	if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR);
6948
6949	mDNS_Unlock(m);
6950
6951	if (err) mDNS_DeregisterService(m, sr);
6952	return(err);
6953	}
6954
6955mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
6956	ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
6957	{
6958	ExtraResourceRecord **e;
6959	mStatus status;
6960
6961	extra->next = mDNSNULL;
6962	mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID,
6963		extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
6964	AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name);
6965
6966#ifndef UNICAST_DISABLED
6967	if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
6968		{
6969		mDNS_Lock(m);
6970		// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
6971		// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
6972		// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
6973		// (We have to duplicate this check here because uDNS_AddRecordToService() bypasses the usual mDNS_Register_internal() bottleneck)
6974		if (extra->r.resrec.rrtype == kDNSType_TXT && extra->r.resrec.rdlength == 0)
6975			{ extra->r.resrec.rdlength = 1; extra->r.resrec.rdata->u.txt.c[0] = 0; }
6976		status = uDNS_AddRecordToService(m, sr, extra);
6977		mDNS_Unlock(m);
6978		return status;
6979		}
6980#endif
6981
6982	mDNS_Lock(m);
6983	e = &sr->Extras;
6984	while (*e) e = &(*e)->next;
6985
6986	if (ttl == 0) ttl = kStandardTTL;
6987
6988	extra->r.DependentOn = &sr->RR_SRV;
6989
6990	debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name->c);
6991
6992	status = mDNS_Register_internal(m, &extra->r);
6993	if (status == mStatus_NoError) *e = extra;
6994	mDNS_Unlock(m);
6995	return(status);
6996	}
6997
6998mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra,
6999	mDNSRecordCallback MemFreeCallback, void *Context)
7000	{
7001	ExtraResourceRecord **e;
7002	mStatus status;
7003
7004	mDNS_Lock(m);
7005	e = &sr->Extras;
7006	while (*e && *e != extra) e = &(*e)->next;
7007	if (!*e)
7008		{
7009		debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c);
7010		status = mStatus_BadReferenceErr;
7011		}
7012	else
7013		{
7014		debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c);
7015		extra->r.RecordCallback = MemFreeCallback;
7016		extra->r.RecordContext  = Context;
7017		*e = (*e)->next;
7018#ifndef UNICAST_DISABLED
7019		if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
7020			status = uDNS_DeregisterRecord(m, &extra->r);
7021		else
7022#endif
7023		status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
7024		}
7025	mDNS_Unlock(m);
7026	return(status);
7027	}
7028
7029mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
7030	{
7031	// NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
7032	// mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
7033	domainlabel name1, name2;
7034	domainname type, domain;
7035	domainname *host = mDNSNULL;
7036	ExtraResourceRecord *extras = sr->Extras;
7037	mStatus err;
7038
7039	DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain);
7040	if (!newname)
7041		{
7042		name2 = name1;
7043		IncrementLabelSuffix(&name2, mDNStrue);
7044		newname = &name2;
7045		}
7046
7047	if (SameDomainName(&domain, &localdomain))
7048		LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
7049	else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
7050
7051	if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host;
7052
7053	err = mDNS_RegisterService(m, sr, newname, &type, &domain,
7054		host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength,
7055		sr->SubTypes, sr->NumSubTypes,
7056		sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext);
7057
7058	// mDNS_RegisterService() just reset sr->Extras to NULL.
7059	// Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
7060	// through the old list of extra records, and re-add them to our freshly created service registration
7061	while (!err && extras)
7062		{
7063		ExtraResourceRecord *e = extras;
7064		extras = extras->next;
7065		err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl);
7066		}
7067
7068	return(err);
7069	}
7070
7071// NOTE: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
7072// which may change the record list and/or question list.
7073// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
7074mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
7075	{
7076	// If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
7077	if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
7078
7079#ifndef UNICAST_DISABLED
7080	if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
7081		{
7082		mStatus status;
7083		mDNS_Lock(m);
7084		status = uDNS_DeregisterService(m, sr);
7085		mDNS_Unlock(m);
7086		return(status);
7087		}
7088#endif
7089	if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
7090		{
7091		debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
7092		return(mStatus_BadReferenceErr);
7093		}
7094	else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
7095		{
7096		debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
7097		return(mStatus_NoError);
7098		}
7099	else
7100		{
7101		mDNSu32 i;
7102		mStatus status;
7103		ExtraResourceRecord *e;
7104		mDNS_Lock(m);
7105		e = sr->Extras;
7106
7107		// We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
7108		// SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
7109		mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
7110		mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
7111
7112		mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal);
7113
7114		// We deregister all of the extra records, but we leave the sr->Extras list intact
7115		// in case the client wants to do a RenameAndReregister and reinstate the registration
7116		while (e)
7117			{
7118			mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat);
7119			e = e->next;
7120			}
7121
7122		for (i=0; i<sr->NumSubTypes; i++)
7123			mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
7124
7125		// Be sure to deregister the PTR last!
7126		// Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
7127		// which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
7128		// which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
7129		// we've deregistered all our records and done any other necessary cleanup before that happens.
7130		status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal);
7131		mDNS_Unlock(m);
7132		return(status);
7133		}
7134	}
7135
7136// Create a registration that asserts that no such service exists with this name.
7137// This can be useful where there is a given function is available through several protocols.
7138// For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
7139// protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
7140// "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
7141// could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
7142mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
7143	const domainlabel *const name, const domainname *const type, const domainname *const domain,
7144	const domainname *const host,
7145	const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
7146	{
7147	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
7148	if (ConstructServiceName(rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
7149	rr->resrec.rdata->u.srv.priority    = 0;
7150	rr->resrec.rdata->u.srv.weight      = 0;
7151	rr->resrec.rdata->u.srv.port        = zeroIPPort;
7152	if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
7153	else rr->HostTarget = mDNStrue;
7154	return(mDNS_Register(m, rr));
7155	}
7156
7157mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
7158	mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
7159	{
7160	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
7161	if (!MakeDomainNameFromDNSNameString(rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
7162	if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname))                 return(mStatus_BadParamErr);
7163	return(mDNS_Register(m, rr));
7164	}
7165
7166// ***************************************************************************
7167#if COMPILER_LIKES_PRAGMA_MARK
7168#pragma mark -
7169#pragma mark -
7170#pragma mark - Startup and Shutdown
7171#endif
7172
7173mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
7174	{
7175	if (storage && numrecords)
7176		{
7177		mDNSu32 i;
7178		debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity));
7179		for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1];
7180		storage[numrecords-1].next = m->rrcache_free;
7181		m->rrcache_free = storage;
7182		m->rrcache_size += numrecords;
7183		}
7184	}
7185
7186mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
7187	{
7188	mDNS_Lock(m);
7189	mDNS_GrowCache_internal(m, storage, numrecords);
7190	mDNS_Unlock(m);
7191	}
7192
7193mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
7194	CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
7195	mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
7196	{
7197	mDNSu32 slot;
7198	mDNSs32 timenow;
7199	mStatus result;
7200
7201	if (!rrcachestorage) rrcachesize = 0;
7202
7203	m->p                       = p;
7204	m->KnownBugs               = 0;
7205	m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
7206	m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
7207	m->mDNSPlatformStatus      = mStatus_Waiting;
7208	m->UnicastPort4            = zeroIPPort;
7209	m->UnicastPort6            = zeroIPPort;
7210	m->MainCallback            = Callback;
7211	m->MainContext             = Context;
7212	m->rec.r.resrec.RecordType = 0;
7213
7214	// For debugging: To catch and report locking failures
7215	m->mDNS_busy               = 0;
7216	m->mDNS_reentrancy         = 0;
7217	m->mDNS_shutdown           = mDNSfalse;
7218	m->lock_rrcache            = 0;
7219	m->lock_Questions          = 0;
7220	m->lock_Records            = 0;
7221
7222	// Task Scheduling variables
7223	result = mDNSPlatformTimeInit();
7224	if (result != mStatus_NoError) return(result);
7225	m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF);
7226	timenow = mDNS_TimeNow_NoLock(m);
7227
7228	m->timenow                 = 0;		// MUST only be set within mDNS_Lock/mDNS_Unlock section
7229	m->timenow_last            = timenow;
7230	m->NextScheduledEvent      = timenow;
7231	m->SuppressSending         = timenow;
7232	m->NextCacheCheck          = timenow + 0x78000000;
7233	m->NextScheduledQuery      = timenow + 0x78000000;
7234	m->NextScheduledProbe      = timenow + 0x78000000;
7235	m->NextScheduledResponse   = timenow + 0x78000000;
7236	m->ExpectUnicastResponse   = timenow + 0x78000000;
7237	m->RandomQueryDelay        = 0;
7238	m->RandomReconfirmDelay    = 0;
7239	m->PktNum                  = 0;
7240	m->SendDeregistrations     = mDNSfalse;
7241	m->SendImmediateAnswers    = mDNSfalse;
7242	m->SleepState              = mDNSfalse;
7243
7244	// These fields only required for mDNS Searcher...
7245	m->Questions               = mDNSNULL;
7246	m->NewQuestions            = mDNSNULL;
7247	m->CurrentQuestion         = mDNSNULL;
7248	m->LocalOnlyQuestions      = mDNSNULL;
7249	m->NewLocalOnlyQuestions   = mDNSNULL;
7250	m->rrcache_size            = 0;
7251	m->rrcache_totalused       = 0;
7252	m->rrcache_active          = 0;
7253	m->rrcache_report          = 10;
7254	m->rrcache_free            = mDNSNULL;
7255
7256	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL;
7257
7258	mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
7259
7260	// Fields below only required for mDNS Responder...
7261	m->hostlabel.c[0]          = 0;
7262	m->nicelabel.c[0]          = 0;
7263	m->MulticastHostname.c[0]  = 0;
7264	m->HIHardware.c[0]         = 0;
7265	m->HISoftware.c[0]         = 0;
7266	m->ResourceRecords         = mDNSNULL;
7267	m->DuplicateRecords        = mDNSNULL;
7268	m->NewLocalRecords         = mDNSNULL;
7269	m->CurrentRecord           = mDNSNULL;
7270	m->HostInterfaces          = mDNSNULL;
7271	m->ProbeFailTime           = 0;
7272	m->NumFailedProbes         = 0;
7273	m->SuppressProbes          = 0;
7274
7275#ifndef UNICAST_DISABLED
7276	uDNS_Init(m);
7277	m->SuppressStdPort53Queries = 0;
7278#endif
7279	result = mDNSPlatformInit(m);
7280
7281	return(result);
7282	}
7283
7284mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
7285	{
7286	m->mDNSPlatformStatus = result;
7287	if (m->MainCallback)
7288		{
7289		mDNS_Lock(m);
7290		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
7291		m->MainCallback(m, mStatus_NoError);
7292		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
7293		mDNS_Unlock(m);
7294		}
7295	}
7296
7297mDNSexport void mDNS_Close(mDNS *const m)
7298	{
7299	mDNSu32 rrcache_active = 0;
7300	mDNSu32 rrcache_totalused = 0;
7301	mDNSu32 slot;
7302	NetworkInterfaceInfo *intf;
7303	mDNS_Lock(m);
7304
7305	m->mDNS_shutdown = mDNStrue;
7306
7307#ifndef UNICAST_DISABLED
7308	uDNS_Close(m);
7309#endif
7310	rrcache_totalused = m->rrcache_totalused;
7311	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
7312		{
7313		while(m->rrcache_hash[slot])
7314			{
7315			CacheGroup *cg = m->rrcache_hash[slot];
7316			while (cg->members)
7317				{
7318				CacheRecord *rr = cg->members;
7319				cg->members = cg->members->next;
7320				if (rr->CRActiveQuestion) rrcache_active++;
7321				ReleaseCacheRecord(m, rr);
7322				}
7323			cg->rrcache_tail = &cg->members;
7324			ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
7325			}
7326		}
7327	debugf("mDNS_Close: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
7328	if (rrcache_active != m->rrcache_active)
7329		LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
7330
7331	for (intf = m->HostInterfaces; intf; intf = intf->next)
7332		if (intf->Advertise)
7333			DeadvertiseInterface(m, intf);
7334
7335	// Make sure there are nothing but deregistering records remaining in the list
7336	if (m->CurrentRecord) LogMsg("mDNS_Close ERROR m->CurrentRecord already set");
7337	m->CurrentRecord = m->ResourceRecords;
7338	while (m->CurrentRecord)
7339		{
7340		AuthRecord *rr = m->CurrentRecord;
7341		if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
7342			{
7343			debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name->c);
7344			mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
7345			}
7346		else
7347			m->CurrentRecord = rr->next;
7348		}
7349
7350	if (m->ResourceRecords) debugf("mDNS_Close: Sending final packets for deregistering records");
7351	else debugf("mDNS_Close: No deregistering records remain");
7352
7353	// If any deregistering records remain, send their deregistration announcements before we exit
7354	if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
7355	else if (m->ResourceRecords) SendResponses(m);
7356	if (m->ResourceRecords) LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, m->ResourceRecords));
7357
7358	mDNS_Unlock(m);
7359	debugf("mDNS_Close: mDNSPlatformClose");
7360	mDNSPlatformClose(m);
7361	debugf("mDNS_Close: done");
7362	}
7363